Skip to content

Commit

Permalink
drm/sysfs: Send out uevent when connector->force changes
Browse files Browse the repository at this point in the history
To avoid even more code duplication punt this all to the probe worker,
which needs some slight adjustment to also generate a uevent when the
status has changed to due connector->force.

v2: Instead of running the output_poll_work (which is kinda the wrong
thing and a layering violation since it's an internal of the probe
helpers), or calling ->detect (which is again a layering violation
since it's used only by probe helpers) just call the official
->fill_modes function, like a GET_CONNECTOR ioctl call.

v3: Restore the accidentally removed forced-probe for echo "detect" >
force.

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reported-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1447951610-12622-22-git-send-email-daniel.vetter@ffwll.ch
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Daniel Vetter committed Nov 24, 2015
1 parent 9744bf4 commit ed293f7
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 48 deletions.
46 changes: 23 additions & 23 deletions drivers/gpu/drm/drm_probe_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
list_for_each_entry(mode, &connector->modes, head)
mode->status = MODE_UNVERIFIED;

old_status = connector->status;

if (connector->force) {
if (connector->force == DRM_FORCE_ON ||
connector->force == DRM_FORCE_ON_DIGITAL)
Expand All @@ -156,33 +158,31 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
if (connector->funcs->force)
connector->funcs->force(connector);
} else {
old_status = connector->status;

connector->status = connector->funcs->detect(connector, true);
}

/*
* Normally either the driver's hpd code or the poll loop should
* pick up any changes and fire the hotplug event. But if
* userspace sneaks in a probe, we might miss a change. Hence
* check here, and if anything changed start the hotplug code.
*/
if (old_status != connector->status) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
connector->base.id,
connector->name,
old_status, connector->status);

/*
* Normally either the driver's hpd code or the poll loop should
* pick up any changes and fire the hotplug event. But if
* userspace sneaks in a probe, we might miss a change. Hence
* check here, and if anything changed start the hotplug code.
* The hotplug event code might call into the fb
* helpers, and so expects that we do not hold any
* locks. Fire up the poll struct instead, it will
* disable itself again.
*/
if (old_status != connector->status) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
connector->base.id,
connector->name,
old_status, connector->status);

/*
* The hotplug event code might call into the fb
* helpers, and so expects that we do not hold any
* locks. Fire up the poll struct instead, it will
* disable itself again.
*/
dev->mode_config.delayed_event = true;
if (dev->mode_config.poll_enabled)
schedule_delayed_work(&dev->mode_config.output_poll_work,
0);
}
dev->mode_config.delayed_event = true;
if (dev->mode_config.poll_enabled)
schedule_delayed_work(&dev->mode_config.output_poll_work,
0);
}

/* Re-enable polling in case the global poll config changed. */
Expand Down
38 changes: 13 additions & 25 deletions drivers/gpu/drm/drm_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,47 +167,35 @@ static ssize_t status_store(struct device *device,
{
struct drm_connector *connector = to_drm_connector(device);
struct drm_device *dev = connector->dev;
enum drm_connector_status old_status;
enum drm_connector_force old_force;
int ret;

ret = mutex_lock_interruptible(&dev->mode_config.mutex);
if (ret)
return ret;

old_status = connector->status;
old_force = connector->force;

if (sysfs_streq(buf, "detect")) {
if (sysfs_streq(buf, "detect"))
connector->force = 0;
connector->status = connector->funcs->detect(connector, true);
} else if (sysfs_streq(buf, "on")) {
else if (sysfs_streq(buf, "on"))
connector->force = DRM_FORCE_ON;
} else if (sysfs_streq(buf, "on-digital")) {
else if (sysfs_streq(buf, "on-digital"))
connector->force = DRM_FORCE_ON_DIGITAL;
} else if (sysfs_streq(buf, "off")) {
else if (sysfs_streq(buf, "off"))
connector->force = DRM_FORCE_OFF;
} else
else
ret = -EINVAL;

if (ret == 0 && connector->force) {
if (connector->force == DRM_FORCE_ON ||
connector->force == DRM_FORCE_ON_DIGITAL)
connector->status = connector_status_connected;
else
connector->status = connector_status_disconnected;
if (connector->funcs->force)
connector->funcs->force(connector);
}

if (old_status != connector->status) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
if (old_force != connector->force || !connector->force) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n",
connector->base.id,
connector->name,
old_status, connector->status);
old_force, connector->force);

dev->mode_config.delayed_event = true;
if (dev->mode_config.poll_enabled)
schedule_delayed_work(&dev->mode_config.output_poll_work,
0);
connector->funcs->fill_modes(connector,
dev->mode_config.max_width,
dev->mode_config.max_height);
}

mutex_unlock(&dev->mode_config.mutex);
Expand Down

0 comments on commit ed293f7

Please sign in to comment.