[PATCH v2 1/2] drm/sysfs: Provide per connector control of DRM KMS polling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



DRM KMS polling of connections providing errant EDID responses, or
polling of "connectors" that have chips responding on DDC I2C bus
address 0xA0/0xA1 with no actual physical connector nor EDID EEPROM,
will create perpetual noise in dmesg and the system log every 10
seconds.  Currently the user has apparently little recourse to silence
these messages aside from replacing the offending cable, monitor, or
graphics adapter.  That recourse is impossible for an unused DVI-D
"connector" of an internal graphics processor on a motherboard that
provides no physical DVI-D connector.

This change allows the root user to disable (and re-enable) DRM KMS
connector polling on a per connector basis via sysfs, like so:

        # cat /sys/class/drm/card0/card0-DVI-D-1/polled
        [hotplug_detectable] connect disconnect
        
        # echo > /sys/class/drm/card0/card0-DVI-D-1/polled
        # cat /sys/class/drm/card0/card0-DVI-D-1/polled
        hotplug_detectable connect disconnect
        
        # echo " connect  hotplug_detectable " > \
                /sys/class/drm/card0/card0-DVI-D-1/polled
        # cat /sys/class/drm/card0/card0-DVI-D-1/polled
        [hotplug_detectable] [connect] disconnect
        
        # echo > /sys/class/drm/card0/card0-DVI-D-1/polled
        # cat /sys/class/drm/card0/card0-DVI-D-1/polled
        hotplug_detectable connect disconnect

with the enabled poll types for the connector denoted in brackets: [].
This allows the root user to silence DRM KMS log spam for locally known
uncorrectable conditions.

Signed-off-by Andy Walls <awalls@xxxxxxxxxxxxxxxx>

diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 86118a7..8e0807d 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -318,11 +318,80 @@ static ssize_t select_subconnector_show(struct device *device,
                        drm_get_dvi_i_select_name((int)subconnector));
 }
 
+static const struct {
+       uint8_t mask;
+       const char *name;
+} polled_bit_names[] = {
+       { DRM_CONNECTOR_POLL_HPD,        "hotplug_detectable" },
+       { DRM_CONNECTOR_POLL_CONNECT,    "connect"            },
+       { DRM_CONNECTOR_POLL_DISCONNECT, "disconnect"         },
+};
+
+/*
+ * Return the decoded contents of connector->polled, using the names of the
+ * all the bit masks.  Bits that are set, have their names enclosed in brackets.
+ */
+static ssize_t polled_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct drm_connector *connector = to_drm_connector(dev);
+       char *tmp;
+       int i;
+
+       tmp = buf;
+       for (i = 0; i < ARRAY_SIZE(polled_bit_names); i++) {
+               if (connector->polled & polled_bit_names[i].mask)
+                       tmp += sprintf(tmp, "[%s] ", polled_bit_names[i].name);
+               else
+                       tmp += sprintf(tmp, "%s ", polled_bit_names[i].name);
+       }
+
+       if (tmp != buf)
+               *(tmp - 1) = '\n';
+       return tmp - buf;
+}
+
+/*
+ * Change the state of connector->polled, given input bit-mask name-strings
+ * that are separated by space or newline.
+ */
+static ssize_t polled_store(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct drm_connector *connector = to_drm_connector(dev);
+       const char *tmp;
+       int i;
+       uint8_t polled;
+
+       /* Polling of this connector will cease, if no match is made below */
+       polled = 0;
+
+       /* Incrementally split and parse the input */
+       while ((tmp = strsep((char **) &buf, " \n")) != NULL) {
+
+               /* Don't waste effort on multiple adjacent separators */
+               if (*tmp == '\0')
+                       continue;
+
+               /* Check for a match with a connector poll type name */
+               for (i = 0; i < ARRAY_SIZE(polled_bit_names); i++) {
+                       if (!strncasecmp(tmp, polled_bit_names[i].name,
+                                        strlen(polled_bit_names[i].name))) {
+                               polled |= polled_bit_names[i].mask;
+                               break;
+                       }
+               }
+       }
+       connector->polled = polled;
+       return count;
+}
+
 static struct device_attribute connector_attrs[] = {
        __ATTR_RO(status),
        __ATTR_RO(enabled),
        __ATTR_RO(dpms),
        __ATTR_RO(modes),
+       __ATTR(polled, 0644, polled_show, polled_store),
 };
 
 /* These attributes are for both DVI-I connectors and all types of tv-out. */




_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/dri-devel


[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux