mirror of
https://github.com/brl/mutter.git
synced 2024-11-21 23:50:41 -05:00
gpu-kms: Don't add outputs without modes
There seems to be a kernel race when one disconnects an external monitor connected to a DisplayPort via a USB-C adapter. The race results in a connector being reported as connected, but without any modes supported. This had the side effect that we tried to set a preferred mode to the first listed mode, but as no modes were available, we instead tried to dereference the first element of a NULL array, causing a segmentation fault. Mitigate this by skipping adding output if no supported modes are advertised and the output doesn't support scaling, while moving the fallback path for calculating a preferred output mode to after possibly adding the common modes, to avoid the unvolentary NULL dereference. https://bugzilla.gnome.org/show_bug.cgi?id=789501
This commit is contained in:
parent
6147be3dff
commit
d092e913d6
@ -675,11 +675,21 @@ init_outputs (MetaGpuKms *gpu_kms,
|
|||||||
{
|
{
|
||||||
MetaOutput *output;
|
MetaOutput *output;
|
||||||
MetaOutput *old_output;
|
MetaOutput *old_output;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
old_output = find_output_by_id (old_outputs, connector->connector_id);
|
old_output = find_output_by_id (old_outputs, connector->connector_id);
|
||||||
output = meta_create_kms_output (gpu_kms, connector, resources,
|
output = meta_create_kms_output (gpu_kms, connector, resources,
|
||||||
old_output);
|
old_output,
|
||||||
outputs = g_list_prepend (outputs, output);
|
&error);
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to create KMS output: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outputs = g_list_prepend (outputs, output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,9 +438,10 @@ compare_modes (const void *one,
|
|||||||
return g_strcmp0 (b->name, a->name);
|
return g_strcmp0 (b->name, a->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
init_output_modes (MetaOutput *output,
|
init_output_modes (MetaOutput *output,
|
||||||
MetaGpuKms *gpu_kms)
|
MetaGpuKms *gpu_kms,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
MetaOutputKms *output_kms = output->driver_private;
|
MetaOutputKms *output_kms = output->driver_private;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@ -460,15 +461,35 @@ init_output_modes (MetaOutput *output,
|
|||||||
output->preferred_mode = output->modes[i];
|
output->preferred_mode = output->modes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME: MSC feature bit? */
|
||||||
|
/* Presume that if the output supports scaling, then we have
|
||||||
|
* a panel fitter capable of adjusting any mode to suit.
|
||||||
|
*/
|
||||||
|
if (output_kms->has_scaling)
|
||||||
|
add_common_modes (output, gpu_kms);
|
||||||
|
|
||||||
|
if (!output->modes)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"No modes available");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort (output->modes, output->n_modes,
|
||||||
|
sizeof (MetaCrtcMode *), compare_modes);
|
||||||
|
|
||||||
if (!output->preferred_mode)
|
if (!output->preferred_mode)
|
||||||
output->preferred_mode = output->modes[0];
|
output->preferred_mode = output->modes[0];
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaOutput *
|
MetaOutput *
|
||||||
meta_create_kms_output (MetaGpuKms *gpu_kms,
|
meta_create_kms_output (MetaGpuKms *gpu_kms,
|
||||||
drmModeConnector *connector,
|
drmModeConnector *connector,
|
||||||
MetaKmsResources *resources,
|
MetaKmsResources *resources,
|
||||||
MetaOutput *old_output)
|
MetaOutput *old_output,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
MetaGpu *gpu = META_GPU (gpu_kms);
|
MetaGpu *gpu = META_GPU (gpu_kms);
|
||||||
MetaOutput *output;
|
MetaOutput *output;
|
||||||
@ -527,17 +548,11 @@ meta_create_kms_output (MetaGpuKms *gpu_kms,
|
|||||||
output->height_mm = connector->mmHeight;
|
output->height_mm = connector->mmHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_output_modes (output, gpu_kms);
|
if (!init_output_modes (output, gpu_kms, error))
|
||||||
|
{
|
||||||
/* FIXME: MSC feature bit? */
|
g_object_unref (output);
|
||||||
/* Presume that if the output supports scaling, then we have
|
return NULL;
|
||||||
* a panel fitter capable of adjusting any mode to suit.
|
}
|
||||||
*/
|
|
||||||
if (output_kms->has_scaling)
|
|
||||||
add_common_modes (output, gpu_kms);
|
|
||||||
|
|
||||||
qsort (output->modes, output->n_modes,
|
|
||||||
sizeof (MetaCrtcMode *), compare_modes);
|
|
||||||
|
|
||||||
output_kms->n_encoders = connector->count_encoders;
|
output_kms->n_encoders = connector->count_encoders;
|
||||||
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
|
output_kms->encoders = g_new0 (drmModeEncoderPtr, output_kms->n_encoders);
|
||||||
|
@ -35,9 +35,10 @@ gboolean meta_output_kms_can_clone (MetaOutput *output,
|
|||||||
|
|
||||||
GBytes * meta_output_kms_read_edid (MetaOutput *output);
|
GBytes * meta_output_kms_read_edid (MetaOutput *output);
|
||||||
|
|
||||||
MetaOutput * meta_create_kms_output (MetaGpuKms *gpu_kms,
|
MetaOutput * meta_create_kms_output (MetaGpuKms *gpu_kms,
|
||||||
drmModeConnector *connector,
|
drmModeConnector *connector,
|
||||||
MetaKmsResources *resources,
|
MetaKmsResources *resources,
|
||||||
MetaOutput *old_output);
|
MetaOutput *old_output,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
#endif /* META_OUTPUT_KMS_H */
|
#endif /* META_OUTPUT_KMS_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user