thunderbolt: Read vendor and device name from DROM
authorMika Westerberg <mika.westerberg@linux.intel.com>
Tue, 6 Jun 2017 12:25:05 +0000 (15:25 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 9 Jun 2017 09:42:42 +0000 (11:42 +0200)
The device DROM contains name of the vendor and device among other
things. Extract this information and expose it to the userspace via two
new attributes.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com>
Reviewed-by: Michael Jamet <michael.jamet@intel.com>
Signed-off-by: Andreas Noever <andreas.noever@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-bus-thunderbolt
drivers/thunderbolt/eeprom.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/tb.h

index 9f1bd008693898d423744286f7d7d8b4a1f86fa9..29a516f53d2c83ce0731268030c9d8468a9e5930 100644 (file)
@@ -5,6 +5,13 @@ Contact:       thunderbolt-software@lists.01.org
 Description:   This attribute contains id of this device extracted from
                the device DROM.
 
+What:          /sys/bus/thunderbolt/devices/.../device_name
+Date:          Sep 2017
+KernelVersion: 4.13
+Contact:       thunderbolt-software@lists.01.org
+Description:   This attribute contains name of this device extracted from
+               the device DROM.
+
 What:          /sys/bus/thunderbolt/devices/.../vendor
 Date:          Sep 2017
 KernelVersion: 4.13
@@ -12,6 +19,13 @@ Contact:     thunderbolt-software@lists.01.org
 Description:   This attribute contains vendor id of this device extracted
                from the device DROM.
 
+What:          /sys/bus/thunderbolt/devices/.../vendor_name
+Date:          Sep 2017
+KernelVersion: 4.13
+Contact:       thunderbolt-software@lists.01.org
+Description:   This attribute contains vendor name of this device extracted
+               from the device DROM.
+
 What:          /sys/bus/thunderbolt/devices/.../unique_id
 Date:          Sep 2017
 KernelVersion: 4.13
index 5c7d80a109b152a9e4224857daf2d6baedc69a07..d40a5f07fc4ccd2e99aaf3e31bb0eaa032e67906 100644 (file)
@@ -204,6 +204,11 @@ struct tb_drom_entry_header {
        enum tb_drom_entry_type type:1;
 } __packed;
 
+struct tb_drom_entry_generic {
+       struct tb_drom_entry_header header;
+       u8 data[0];
+} __packed;
+
 struct tb_drom_entry_port {
        /* BYTES 0-1 */
        struct tb_drom_entry_header header;
@@ -295,6 +300,32 @@ int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid)
        return 0;
 }
 
+static int tb_drom_parse_entry_generic(struct tb_switch *sw,
+               struct tb_drom_entry_header *header)
+{
+       const struct tb_drom_entry_generic *entry =
+               (const struct tb_drom_entry_generic *)header;
+
+       switch (header->index) {
+       case 1:
+               /* Length includes 2 bytes header so remove it before copy */
+               sw->vendor_name = kstrndup(entry->data,
+                       header->len - sizeof(*header), GFP_KERNEL);
+               if (!sw->vendor_name)
+                       return -ENOMEM;
+               break;
+
+       case 2:
+               sw->device_name = kstrndup(entry->data,
+                       header->len - sizeof(*header), GFP_KERNEL);
+               if (!sw->device_name)
+                       return -ENOMEM;
+               break;
+       }
+
+       return 0;
+}
+
 static int tb_drom_parse_entry_port(struct tb_switch *sw,
                                    struct tb_drom_entry_header *header)
 {
@@ -350,6 +381,7 @@ static int tb_drom_parse_entries(struct tb_switch *sw)
 
                switch (entry->type) {
                case TB_DROM_ENTRY_GENERIC:
+                       res = tb_drom_parse_entry_generic(sw, entry);
                        break;
                case TB_DROM_ENTRY_PORT:
                        res = tb_drom_parse_entry_port(sw, entry);
index 2390f08b94da697e3190b8461ef28ce5552b397c..11f16a141686acdde2489bce5aec59ece6b7f4c1 100644 (file)
@@ -319,6 +319,15 @@ static ssize_t device_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(device);
 
+static ssize_t
+device_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct tb_switch *sw = tb_to_switch(dev);
+
+       return sprintf(buf, "%s\n", sw->device_name ? sw->device_name : "");
+}
+static DEVICE_ATTR_RO(device_name);
+
 static ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
@@ -328,6 +337,15 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(vendor);
 
+static ssize_t
+vendor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct tb_switch *sw = tb_to_switch(dev);
+
+       return sprintf(buf, "%s\n", sw->vendor_name ? sw->vendor_name : "");
+}
+static DEVICE_ATTR_RO(vendor_name);
+
 static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr,
                              char *buf)
 {
@@ -339,7 +357,9 @@ static DEVICE_ATTR_RO(unique_id);
 
 static struct attribute *switch_attrs[] = {
        &dev_attr_device.attr,
+       &dev_attr_device_name.attr,
        &dev_attr_vendor.attr,
+       &dev_attr_vendor_name.attr,
        &dev_attr_unique_id.attr,
        NULL,
 };
@@ -358,6 +378,8 @@ static void tb_switch_release(struct device *dev)
        struct tb_switch *sw = tb_to_switch(dev);
 
        kfree(sw->uuid);
+       kfree(sw->device_name);
+       kfree(sw->vendor_name);
        kfree(sw->ports);
        kfree(sw->drom);
        kfree(sw);
index f7dfe733d71af5084c085009b895b463d71961d0..6d4910ef2eb9d58f37007cafcbe1804d32e871e7 100644 (file)
@@ -23,6 +23,8 @@
  * @uuid: UUID of the switch (or %NULL if not supported)
  * @vendor: Vendor ID of the switch
  * @device: Device ID of the switch
+ * @vendor_name: Name of the vendor (or %NULL if not known)
+ * @device_name: Name of the device (or %NULL if not known)
  * @cap_plug_events: Offset to the plug events capability (%0 if not found)
  * @is_unplugged: The switch is going away
  * @drom: DROM of the switch (%NULL if not found)
@@ -36,6 +38,8 @@ struct tb_switch {
        uuid_be *uuid;
        u16 vendor;
        u16 device;
+       const char *vendor_name;
+       const char *device_name;
        int cap_plug_events;
        bool is_unplugged;
        u8 *drom;