The drm_get_edid() function skips EDID read when the connector is disabled through connector->force. drm_do_get_edid(), which is supposed to be used instead of drm_get_edid() for drivers that need to provide a custom DDC read method, is missing the connector force checks. This breaks the connector sysfs or command line force attribute. Fix this by moving the the connector checks to drm_do_get_edid(). For convenience, the existing drm_do_get_edid() function is renamed to __drm_do_get_edid() and used in drm_do_get_edid(). While at it, remove the incorrect statement from the drm_get_edid() documentation related to attaching the read EDID to the connector. Signed-off-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> --- drivers/gpu/drm/drm_edid.c | 80 +++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 541e50b858e3..4b28635f1050 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -5191,27 +5191,17 @@ int drm_add_override_edid_modes(struct drm_connector *connector) } EXPORT_SYMBOL(drm_add_override_edid_modes); -/** - * drm_do_get_edid - get EDID data using a custom EDID block read function - * @connector: connector we're probing - * @get_edid_block: EDID block read function - * @data: private data passed to the block read function - * - * When the I2C adapter connected to the DDC bus is hidden behind a device that - * exposes a different interface to read EDID blocks this function can be used - * to get EDID data using a custom block read function. - * - * As in the general case the DDC bus is accessible by the kernel at the I2C - * level, drivers must make all reasonable efforts to expose it as an I2C - * adapter and use drm_get_edid() instead of abusing this function. - * - * The EDID may be overridden using debugfs override_edid or firmware EDID - * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority - * order. Having either of them bypasses actual EDID reads. - * - * Return: Pointer to valid EDID or NULL if we couldn't find any. - */ -struct edid *drm_do_get_edid(struct drm_connector *connector, +static bool __drm_probe_ddc(int (*get_edid_block)(void *data, u8 *buf, + unsigned int block, + size_t len), + void *data) +{ + unsigned char out; + + return (get_edid_block(data, &out, 0, 1) == 0); +} + +static struct edid *__drm_do_get_edid(struct drm_connector *connector, int (*get_edid_block)(void *data, u8 *buf, unsigned int block, size_t len), void *data) @@ -5302,6 +5292,41 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, kfree(edid); return NULL; } + +/** + * drm_do_get_edid - get EDID data using a custom EDID block read function + * @connector: connector we're probing + * @get_edid_block: EDID block read function + * @data: private data passed to the block read function + * + * When the I2C adapter connected to the DDC bus is hidden behind a device that + * exposes a different interface to read EDID blocks this function can be used + * to get EDID data using a custom block read function. + * + * As in the general case the DDC bus is accessible by the kernel at the I2C + * level, drivers must make all reasonable efforts to expose it as an I2C + * adapter and use drm_get_edid() instead of abusing this function. + * + * The EDID may be overridden using debugfs override_edid or firmware EDID + * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority + * order. Having either of them bypasses actual EDID reads. + * + * Return: Pointer to valid EDID or NULL if we couldn't find any. + */ +struct edid *drm_do_get_edid(struct drm_connector *connector, + int (*get_edid_block)(void *data, u8 *buf, unsigned int block, + size_t len), + void *data) +{ + if (connector->force == DRM_FORCE_OFF) + return NULL; + + if (connector->force == DRM_FORCE_UNSPECIFIED && + !__drm_probe_ddc(get_edid_block, data)) + return NULL; + + return __drm_do_get_edid(connector, get_edid_block, data); +} EXPORT_SYMBOL_GPL(drm_do_get_edid); /** @@ -5313,9 +5338,7 @@ EXPORT_SYMBOL_GPL(drm_do_get_edid); bool drm_probe_ddc(struct i2c_adapter *adapter) { - unsigned char out; - - return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0); + return __drm_probe_ddc(drm_do_probe_ddc_edid, adapter); } EXPORT_SYMBOL(drm_probe_ddc); @@ -5324,20 +5347,13 @@ EXPORT_SYMBOL(drm_probe_ddc); * @connector: connector we're probing * @adapter: I2C adapter to use for DDC * - * Poke the given I2C channel to grab EDID data if possible. If found, - * attach it to the connector. + * Poke the given I2C channel to grab EDID data if possible. * * Return: Pointer to valid EDID or NULL if we couldn't find any. */ struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { - if (connector->force == DRM_FORCE_OFF) - return NULL; - - if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter)) - return NULL; - return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); } EXPORT_SYMBOL(drm_get_edid); -- Regards, Laurent Pinchart _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel