@@ -347,6 +347,7 @@ EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
/**
* drm_kms_helper_hotplug_event - fire off KMS hotplug events
* @dev: drm_device whose connector state changed
+ * @connector: connector on which the status changed, if any
*
* This function fires off the uevent for userspace and also calls the
* output_poll_changed function, which is most commonly used to inform the fbdev
@@ -360,10 +361,11 @@ EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
* This function must be called from process context with no mode
* setting locks held.
*/
-void drm_kms_helper_hotplug_event(struct drm_device *dev)
+void drm_kms_helper_hotplug_event(struct drm_device *dev,
+ struct drm_connector *connector)
{
/* send a uevent + call fbdev */
- drm_sysfs_hotplug_event(dev);
+ drm_sysfs_hotplug_event(dev, connector);
if (dev->mode_config.funcs->output_poll_changed)
dev->mode_config.funcs->output_poll_changed(dev);
}
@@ -444,7 +446,7 @@ static void output_poll_execute(struct work_struct *work)
out:
if (changed)
- drm_kms_helper_hotplug_event(dev);
+ drm_kms_helper_hotplug_event(dev, NULL);
if (repoll)
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
@@ -578,7 +580,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
mutex_unlock(&dev->mode_config.mutex);
if (changed)
- drm_kms_helper_hotplug_event(dev);
+ drm_kms_helper_hotplug_event(dev, NULL);
return changed;
}
@@ -280,7 +280,7 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
}
/* Let userspace know we have a new connector */
- drm_sysfs_hotplug_event(dev);
+ drm_sysfs_hotplug_event(dev, connector);
return 0;
}
@@ -312,19 +312,30 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
/**
* drm_sysfs_hotplug_event - generate a DRM uevent
* @dev: DRM device
+ * @connector: the DRM connector, if any
*
* Send a uevent for the DRM device specified by @dev. Currently we only
* set HOTPLUG=1 in the uevent environment, but this could be expanded to
* deal with other types of events.
*/
-void drm_sysfs_hotplug_event(struct drm_device *dev)
+void drm_sysfs_hotplug_event(struct drm_device *dev,
+ struct drm_connector *connector)
{
- char *event_string = "HOTPLUG=1";
- char *envp[] = { event_string, NULL };
+ char *envp[3] = { "HOTPLUG=1" };
+ char *connector_event = NULL;
+
+ if (connector)
+ connector_event = kasprintf(GFP_KERNEL,
+ "CONNECTOR=%d",
+ connector->base.id);
+ if (connector_event)
+ envp[1] = connector_event;
DRM_DEBUG("generating hotplug event\n");
kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);
+
+ kfree(connector_event);
}
EXPORT_SYMBOL(drm_sysfs_hotplug_event);
@@ -617,7 +617,7 @@ static void tda998x_detect_work(struct work_struct *work)
struct drm_device *dev = priv->encoder.dev;
if (dev)
- drm_kms_helper_hotplug_event(dev);
+ drm_kms_helper_hotplug_event(dev, NULL);
}
/*
@@ -3981,7 +3981,8 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
intel_dp->is_mst = false;
drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
/* send a hotplug event */
- drm_kms_helper_hotplug_event(intel_dig_port->base.base.dev);
+ drm_kms_helper_hotplug_event(intel_dig_port->base.base.dev,
+ &intel_dp->attached_connector->base);
}
}
return -EINVAL;
@@ -493,7 +493,7 @@ static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
- drm_kms_helper_hotplug_event(dev);
+ drm_kms_helper_hotplug_event(dev, &intel_dp->attached_connector->base);
}
static const struct drm_dp_mst_topology_cbs mst_cbs = {
@@ -307,7 +307,6 @@ static void i915_hotplug_work_func(struct work_struct *work)
struct intel_connector *intel_connector;
struct intel_encoder *intel_encoder;
struct drm_connector *connector;
- bool changed = false;
u32 hpd_event_bits;
mutex_lock(&mode_config->mutex);
@@ -334,13 +333,10 @@ static void i915_hotplug_work_func(struct work_struct *work)
if (intel_encoder->hot_plug)
intel_encoder->hot_plug(intel_encoder);
if (intel_hpd_irq_event(dev, connector))
- changed = true;
+ drm_kms_helper_hotplug_event(dev, connector);
}
}
mutex_unlock(&mode_config->mutex);
-
- if (changed)
- drm_kms_helper_hotplug_event(dev);
}
@@ -135,7 +135,7 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
if (!drm_helper_hpd_irq_event(qdev->ddev)) {
/* notify that the monitor configuration changed, to
adjust at the arbitrary resolution */
- drm_kms_helper_hotplug_event(qdev->ddev);
+ drm_kms_helper_hotplug_event(qdev->ddev, NULL);
}
}
@@ -331,7 +331,7 @@ static void radeon_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
struct radeon_connector *master = container_of(mgr, struct radeon_connector, mst_mgr);
struct drm_device *dev = master->base.dev;
- drm_kms_helper_hotplug_event(dev);
+ drm_kms_helper_hotplug_event(dev, NULL);
}
const struct drm_dp_mst_topology_cbs mst_cbs = {
@@ -583,7 +583,7 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
wake_up(&vgdev->resp_wq);
if (!drm_helper_hpd_irq_event(vgdev->ddev))
- drm_kms_helper_hotplug_event(vgdev->ddev);
+ drm_kms_helper_hotplug_event(vgdev->ddev, NULL);
}
static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev,
@@ -1233,7 +1233,7 @@ static int vmw_master_set(struct drm_device *dev,
}
dev_priv->active_master = vmaster;
- drm_sysfs_hotplug_event(dev);
+ drm_sysfs_hotplug_event(dev, NULL);
return 0;
}
@@ -1407,7 +1407,7 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
}
mutex_unlock(&dev->mode_config.mutex);
- drm_sysfs_hotplug_event(dev);
+ drm_sysfs_hotplug_event(dev, con);
return 0;
}
@@ -1038,7 +1038,8 @@ extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size,
extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah);
/* sysfs support (drm_sysfs.c) */
-extern void drm_sysfs_hotplug_event(struct drm_device *dev);
+extern void drm_sysfs_hotplug_event(struct drm_device *dev,
+ struct drm_connector *connector);
struct drm_device *drm_dev_alloc(struct drm_driver *driver,
@@ -69,7 +69,8 @@ extern int drm_helper_probe_single_connector_modes(struct drm_connector
extern void drm_kms_helper_poll_init(struct drm_device *dev);
extern void drm_kms_helper_poll_fini(struct drm_device *dev);
extern bool drm_helper_hpd_irq_event(struct drm_device *dev);
-extern void drm_kms_helper_hotplug_event(struct drm_device *dev);
+extern void drm_kms_helper_hotplug_event(struct drm_device *dev,
+ struct drm_connector *connector);
extern void drm_kms_helper_poll_disable(struct drm_device *dev);
extern void drm_kms_helper_poll_enable(struct drm_device *dev);
If we know which connector was plugged/unplugged or connected/disconnected, we can pass that information along to userspace inside the uevent to reduce the amount of work userspace has to perform after the event (i.e. instead of looking over all connectors, it can just reprobe the affected one). Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Villle Syrjälä <ville.syrjala@linux.intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> --- drivers/gpu/drm/drm_probe_helper.c | 10 ++++++---- drivers/gpu/drm/drm_sysfs.c | 19 +++++++++++++++---- drivers/gpu/drm/i2c/tda998x_drv.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 3 ++- drivers/gpu/drm/i915/intel_dp_mst.c | 2 +- drivers/gpu/drm/i915/intel_hotplug.c | 6 +----- drivers/gpu/drm/qxl/qxl_display.c | 2 +- drivers/gpu/drm/radeon/radeon_dp_mst.c | 2 +- drivers/gpu/drm/virtio/virtgpu_vq.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- include/drm/drmP.h | 3 ++- include/drm/drm_crtc_helper.h | 3 ++- 13 files changed, 35 insertions(+), 23 deletions(-)