[PATCH/RFC 4/5] drm/edid: Honour connector->force in drm_do_get_edid()

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Aug 21 18:50:04 UTC 2019


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 at ideasonboard.com>
---
 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



More information about the dri-devel mailing list