HID: Add device group to modalias
authorHenrik Rydberg <rydberg@euromail.se>
Mon, 23 Apr 2012 10:07:02 +0000 (12:07 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 1 May 2012 10:54:54 +0000 (12:54 +0200)
HID devices are only partially presented to userland.  Hotplugged
devices emit events containing a modalias based on the basic bus,
vendor and product entities. However, in practise a hid device can
depend on details such as a single usb interface or a particular item
in a report descriptor.

This patch adds a device group to the hid device id, and broadcasts it
using uevent and the device modalias.  The module alias generation is
modified to match. As a consequence, a device with a non-zero group
will be processed by the corresponding group driver instead of by the
generic hid driver.

Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Acked-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-core.c
include/linux/hid.h
include/linux/mod_devicetable.h
scripts/mod/file2alias.c

index 9ed4ff37dc2bf3797f8abfd6d33a90a428479cab..cfcb69eb17d6d67b3fdd9f42c25f5c1dfe1d8f55 100644 (file)
@@ -1222,6 +1222,7 @@ static bool hid_match_one_id(struct hid_device *hdev,
                const struct hid_device_id *id)
 {
        return id->bus == hdev->bus &&
+               (id->group == HID_GROUP_ANY || id->group == hdev->group) &&
                (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
                (id->product == HID_ANY_ID || id->product == hdev->product);
 }
@@ -1694,6 +1695,7 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf,
                return -ENOMEM;
 
        dynid->id.bus = bus;
+       dynid->id.group = HID_GROUP_ANY;
        dynid->id.vendor = vendor;
        dynid->id.product = product;
        dynid->id.driver_data = driver_data;
@@ -1817,6 +1819,23 @@ static int hid_device_remove(struct device *dev)
        return 0;
 }
 
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+                            char *buf)
+{
+       struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+       int len;
+
+       len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+                      hdev->bus, hdev->group, hdev->vendor, hdev->product);
+
+       return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute hid_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_NULL,
+};
+
 static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct hid_device *hdev = container_of(dev, struct hid_device, dev);
@@ -1834,8 +1853,8 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
        if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
                return -ENOMEM;
 
-       if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X",
-                       hdev->bus, hdev->vendor, hdev->product))
+       if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
+                          hdev->bus, hdev->group, hdev->vendor, hdev->product))
                return -ENOMEM;
 
        return 0;
@@ -1843,6 +1862,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 static struct bus_type hid_bus_type = {
        .name           = "hid",
+       .dev_attrs      = hid_dev_attrs,
        .match          = hid_bus_match,
        .probe          = hid_device_probe,
        .remove         = hid_device_remove,
index d8e7cc7f894fa69e9a1d43349ebfb955a6a9719b..a0e27ddb887d915670291de43819b574eab24886 100644 (file)
@@ -476,6 +476,7 @@ struct hid_device {                                                 /* device report descriptor */
        unsigned maxcollection;                                         /* Number of parsed collections */
        unsigned maxapplication;                                        /* Number of applications */
        __u16 bus;                                                      /* BUS ID */
+       __u16 group;                                                    /* Report group */
        __u32 vendor;                                                   /* Vendor ID */
        __u32 product;                                                  /* Product ID */
        __u32 version;                                                  /* HID version */
index 501da4cb8a6de02ecd0dbe8b6759c26b298d2c12..55ed0b0dc610b969c8c4bb533b55f3c54116782b 100644 (file)
@@ -132,10 +132,11 @@ struct usb_device_id {
 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL       0x0200
 
 #define HID_ANY_ID                             (~0)
+#define HID_GROUP_ANY                          0x0000
 
 struct hid_device_id {
        __u16 bus;
-       __u16 pad1;
+       __u16 group;
        __u32 vendor;
        __u32 product;
        kernel_ulong_t driver_data
index 8e730ccc3f2b22d55e7b716cf20298da4e9b7475..fe967cee73716f605fb69bb4f2f39a3d0bee63b7 100644 (file)
@@ -336,10 +336,12 @@ static int do_hid_entry(const char *filename,
                             struct hid_device_id *id, char *alias)
 {
        id->bus = TO_NATIVE(id->bus);
+       id->group = TO_NATIVE(id->group);
        id->vendor = TO_NATIVE(id->vendor);
        id->product = TO_NATIVE(id->product);
 
        sprintf(alias, "hid:b%04X", id->bus);
+       ADD(alias, "g", id->group != HID_GROUP_ANY, id->group);
        ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor);
        ADD(alias, "p", id->product != HID_ANY_ID, id->product);