58,40 → 58,84 |
static bool drm_kms_helper_poll = true; |
module_param_named(poll, drm_kms_helper_poll, bool, 0600); |
|
static void drm_mode_validate_flag(struct drm_connector *connector, |
static enum drm_mode_status |
drm_mode_validate_flag(const struct drm_display_mode *mode, |
int flags) |
{ |
struct drm_display_mode *mode; |
|
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE | |
DRM_MODE_FLAG_3D_MASK)) |
return; |
|
list_for_each_entry(mode, &connector->modes, head) { |
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && |
!(flags & DRM_MODE_FLAG_INTERLACE)) |
mode->status = MODE_NO_INTERLACE; |
return MODE_NO_INTERLACE; |
|
if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && |
!(flags & DRM_MODE_FLAG_DBLSCAN)) |
mode->status = MODE_NO_DBLESCAN; |
return MODE_NO_DBLESCAN; |
|
if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && |
!(flags & DRM_MODE_FLAG_3D_MASK)) |
mode->status = MODE_NO_STEREO; |
return MODE_NO_STEREO; |
|
return MODE_OK; |
} |
|
static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector) |
{ |
struct drm_display_mode *mode; |
|
if (!connector->cmdline_mode.specified) |
return 0; |
|
mode = drm_mode_create_from_cmdline_mode(connector->dev, |
&connector->cmdline_mode); |
if (mode == NULL) |
return 0; |
|
drm_mode_probed_add(connector, mode); |
return 1; |
} |
|
#define DRM_OUTPUT_POLL_PERIOD (10*HZ) |
/** |
* drm_kms_helper_poll_enable_locked - re-enable output polling. |
* @dev: drm_device |
* |
* This function re-enables the output polling work without |
* locking the mode_config mutex. |
* |
* This is like drm_kms_helper_poll_enable() however it is to be |
* called from a context where the mode_config mutex is locked |
* already. |
*/ |
void drm_kms_helper_poll_enable_locked(struct drm_device *dev) |
{ |
bool poll = false; |
struct drm_connector *connector; |
|
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
|
if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) |
return; |
|
drm_for_each_connector(connector, dev) { |
if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | |
DRM_CONNECTOR_POLL_DISCONNECT)) |
poll = true; |
} |
|
} |
EXPORT_SYMBOL(drm_kms_helper_poll_enable_locked); |
|
|
static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, |
uint32_t maxX, uint32_t maxY, bool merge_type_bits) |
{ |
struct drm_device *dev = connector->dev; |
struct drm_display_mode *mode; |
struct drm_connector_helper_funcs *connector_funcs = |
const struct drm_connector_helper_funcs *connector_funcs = |
connector->helper_private; |
int count = 0; |
int mode_flags = 0; |
bool verbose_prune = true; |
enum drm_connector_status old_status; |
|
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); |
|
110,12 → 154,14 |
if (connector->funcs->force) |
connector->funcs->force(connector); |
} else { |
old_status = connector->status; |
|
connector->status = connector->funcs->detect(connector, true); |
} |
|
/* Re-enable polling in case the global poll config changed. */ |
if (drm_kms_helper_poll != dev->mode_config.poll_running) |
drm_kms_helper_poll_enable(dev); |
drm_kms_helper_poll_enable_locked(dev); |
|
dev->mode_config.poll_running = drm_kms_helper_poll; |
|
136,6 → 182,7 |
struct edid *edid = (struct edid *) connector->edid_blob_ptr->data; |
|
count = drm_add_edid_modes(connector, edid); |
drm_edid_to_eld(connector, edid); |
} else |
count = (*connector_funcs->get_modes)(connector); |
} |
147,9 → 194,6 |
|
drm_mode_connector_list_update(connector, merge_type_bits); |
|
if (maxX && maxY) |
drm_mode_validate_size(dev, &connector->modes, maxX, maxY); |
|
if (connector->interlace_allowed) |
mode_flags |= DRM_MODE_FLAG_INTERLACE; |
if (connector->doublescan_allowed) |
156,9 → 200,17 |
mode_flags |= DRM_MODE_FLAG_DBLSCAN; |
if (connector->stereo_allowed) |
mode_flags |= DRM_MODE_FLAG_3D_MASK; |
drm_mode_validate_flag(connector, mode_flags); |
|
list_for_each_entry(mode, &connector->modes, head) { |
if (mode->status == MODE_OK) |
mode->status = drm_mode_validate_basic(mode); |
|
if (mode->status == MODE_OK) |
mode->status = drm_mode_validate_size(mode, maxX, maxY); |
|
if (mode->status == MODE_OK) |
mode->status = drm_mode_validate_flag(mode, mode_flags); |
|
if (mode->status == MODE_OK && connector_funcs->mode_valid) |
mode->status = connector_funcs->mode_valid(connector, |
mode); |
251,7 → 303,6 |
} |
EXPORT_SYMBOL(drm_kms_helper_hotplug_event); |
|
#define DRM_OUTPUT_POLL_PERIOD (10*HZ) |
static void output_poll_execute(struct work_struct *work) |
{ |
struct delayed_work *delayed_work = to_delayed_work(work); |
258,13 → 309,17 |
struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); |
struct drm_connector *connector; |
enum drm_connector_status old_status; |
bool repoll = false, changed = false; |
bool repoll = false, changed; |
|
/* Pick up any changes detected by the probe functions. */ |
changed = dev->mode_config.delayed_event; |
dev->mode_config.delayed_event = false; |
|
if (!drm_kms_helper_poll) |
return; |
goto out; |
|
mutex_lock(&dev->mode_config.mutex); |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
drm_for_each_connector(connector, dev) { |
|
/* Ignore forced connectors. */ |
if (connector->force) |
275,8 → 330,6 |
if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) |
continue; |
|
repoll = true; |
|
old_status = connector->status; |
/* if we are connected and don't want to poll for disconnect |
skip it */ |
284,10 → 337,30 |
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) |
continue; |
|
repoll = true; |
|
connector->status = connector->funcs->detect(connector, false); |
if (old_status != connector->status) { |
const char *old, *new; |
|
/* |
* The poll work sets force=false when calling detect so |
* that drivers can avoid to do disruptive tests (e.g. |
* when load detect cycles could cause flickering on |
* other, running displays). This bears the risk that we |
* flip-flop between unknown here in the poll work and |
* the real state when userspace forces a full detect |
* call after receiving a hotplug event due to this |
* change. |
* |
* Hence clamp an unknown detect status to the old |
* value. |
*/ |
if (connector->status == connector_status_unknown) { |
connector->status = old_status; |
continue; |
} |
|
old = drm_get_connector_status_name(old_status); |
new = drm_get_connector_status_name(connector->status); |
|
303,6 → 376,8 |
|
mutex_unlock(&dev->mode_config.mutex); |
|
out: ; |
|
// if (changed) |
// drm_kms_helper_hotplug_event(dev); |
|
340,21 → 415,10 |
*/ |
void drm_kms_helper_poll_enable(struct drm_device *dev) |
{ |
bool poll = false; |
struct drm_connector *connector; |
|
if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) |
return; |
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | |
DRM_CONNECTOR_POLL_DISCONNECT)) |
poll = true; |
mutex_lock(&dev->mode_config.mutex); |
drm_kms_helper_poll_enable_locked(dev); |
mutex_unlock(&dev->mode_config.mutex); |
} |
|
// if (poll) |
// schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); |
} |
EXPORT_SYMBOL(drm_kms_helper_poll_enable); |
|
/** |
428,7 → 492,7 |
return false; |
|
mutex_lock(&dev->mode_config.mutex); |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
drm_for_each_connector(connector, dev) { |
|
/* Only handle HPD capable connectors. */ |
if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) |