diff options
| author | Henrik Rydberg <rydberg@euromail.se> | 2012-04-23 06:07:02 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2012-05-01 06:54:54 -0400 |
| commit | 4d53b8012f1f01ddb3f24db2031b042bb4cbd0d0 (patch) | |
| tree | 4536bb9fefb51c212f28dee84e810ab0d6854a6e | |
| parent | a7197c2e4120ce40e7e3f5580336b9a1dc791220 (diff) | |
HID: Add device group to modalias
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>
| -rw-r--r-- | drivers/hid/hid-core.c | 24 | ||||
| -rw-r--r-- | include/linux/hid.h | 1 | ||||
| -rw-r--r-- | include/linux/mod_devicetable.h | 3 | ||||
| -rw-r--r-- | scripts/mod/file2alias.c | 2 |
4 files changed, 27 insertions, 3 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9ed4ff37dc2b..cfcb69eb17d6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
| @@ -1222,6 +1222,7 @@ static bool hid_match_one_id(struct hid_device *hdev, | |||
| 1222 | const struct hid_device_id *id) | 1222 | const struct hid_device_id *id) |
| 1223 | { | 1223 | { |
| 1224 | return id->bus == hdev->bus && | 1224 | return id->bus == hdev->bus && |
| 1225 | (id->group == HID_GROUP_ANY || id->group == hdev->group) && | ||
| 1225 | (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) && | 1226 | (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) && |
| 1226 | (id->product == HID_ANY_ID || id->product == hdev->product); | 1227 | (id->product == HID_ANY_ID || id->product == hdev->product); |
| 1227 | } | 1228 | } |
| @@ -1694,6 +1695,7 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf, | |||
| 1694 | return -ENOMEM; | 1695 | return -ENOMEM; |
| 1695 | 1696 | ||
| 1696 | dynid->id.bus = bus; | 1697 | dynid->id.bus = bus; |
| 1698 | dynid->id.group = HID_GROUP_ANY; | ||
| 1697 | dynid->id.vendor = vendor; | 1699 | dynid->id.vendor = vendor; |
| 1698 | dynid->id.product = product; | 1700 | dynid->id.product = product; |
| 1699 | dynid->id.driver_data = driver_data; | 1701 | dynid->id.driver_data = driver_data; |
| @@ -1817,6 +1819,23 @@ static int hid_device_remove(struct device *dev) | |||
| 1817 | return 0; | 1819 | return 0; |
| 1818 | } | 1820 | } |
| 1819 | 1821 | ||
| 1822 | static ssize_t modalias_show(struct device *dev, struct device_attribute *a, | ||
| 1823 | char *buf) | ||
| 1824 | { | ||
| 1825 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
| 1826 | int len; | ||
| 1827 | |||
| 1828 | len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n", | ||
| 1829 | hdev->bus, hdev->group, hdev->vendor, hdev->product); | ||
| 1830 | |||
| 1831 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; | ||
| 1832 | } | ||
| 1833 | |||
| 1834 | static struct device_attribute hid_dev_attrs[] = { | ||
| 1835 | __ATTR_RO(modalias), | ||
| 1836 | __ATTR_NULL, | ||
| 1837 | }; | ||
| 1838 | |||
| 1820 | static int hid_uevent(struct device *dev, struct kobj_uevent_env *env) | 1839 | static int hid_uevent(struct device *dev, struct kobj_uevent_env *env) |
| 1821 | { | 1840 | { |
| 1822 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | 1841 | 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) | |||
| 1834 | if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq)) | 1853 | if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq)) |
| 1835 | return -ENOMEM; | 1854 | return -ENOMEM; |
| 1836 | 1855 | ||
| 1837 | if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X", | 1856 | if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X", |
| 1838 | hdev->bus, hdev->vendor, hdev->product)) | 1857 | hdev->bus, hdev->group, hdev->vendor, hdev->product)) |
| 1839 | return -ENOMEM; | 1858 | return -ENOMEM; |
| 1840 | 1859 | ||
| 1841 | return 0; | 1860 | return 0; |
| @@ -1843,6 +1862,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
| 1843 | 1862 | ||
| 1844 | static struct bus_type hid_bus_type = { | 1863 | static struct bus_type hid_bus_type = { |
| 1845 | .name = "hid", | 1864 | .name = "hid", |
| 1865 | .dev_attrs = hid_dev_attrs, | ||
| 1846 | .match = hid_bus_match, | 1866 | .match = hid_bus_match, |
| 1847 | .probe = hid_device_probe, | 1867 | .probe = hid_device_probe, |
| 1848 | .remove = hid_device_remove, | 1868 | .remove = hid_device_remove, |
diff --git a/include/linux/hid.h b/include/linux/hid.h index d8e7cc7f894f..a0e27ddb887d 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
| @@ -476,6 +476,7 @@ struct hid_device { /* device report descriptor */ | |||
| 476 | unsigned maxcollection; /* Number of parsed collections */ | 476 | unsigned maxcollection; /* Number of parsed collections */ |
| 477 | unsigned maxapplication; /* Number of applications */ | 477 | unsigned maxapplication; /* Number of applications */ |
| 478 | __u16 bus; /* BUS ID */ | 478 | __u16 bus; /* BUS ID */ |
| 479 | __u16 group; /* Report group */ | ||
| 479 | __u32 vendor; /* Vendor ID */ | 480 | __u32 vendor; /* Vendor ID */ |
| 480 | __u32 product; /* Product ID */ | 481 | __u32 product; /* Product ID */ |
| 481 | __u32 version; /* HID version */ | 482 | __u32 version; /* HID version */ |
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 501da4cb8a6d..55ed0b0dc610 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h | |||
| @@ -132,10 +132,11 @@ struct usb_device_id { | |||
| 132 | #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 | 132 | #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 |
| 133 | 133 | ||
| 134 | #define HID_ANY_ID (~0) | 134 | #define HID_ANY_ID (~0) |
| 135 | #define HID_GROUP_ANY 0x0000 | ||
| 135 | 136 | ||
| 136 | struct hid_device_id { | 137 | struct hid_device_id { |
| 137 | __u16 bus; | 138 | __u16 bus; |
| 138 | __u16 pad1; | 139 | __u16 group; |
| 139 | __u32 vendor; | 140 | __u32 vendor; |
| 140 | __u32 product; | 141 | __u32 product; |
| 141 | kernel_ulong_t driver_data | 142 | kernel_ulong_t driver_data |
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 8e730ccc3f2b..fe967cee7371 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c | |||
| @@ -336,10 +336,12 @@ static int do_hid_entry(const char *filename, | |||
| 336 | struct hid_device_id *id, char *alias) | 336 | struct hid_device_id *id, char *alias) |
| 337 | { | 337 | { |
| 338 | id->bus = TO_NATIVE(id->bus); | 338 | id->bus = TO_NATIVE(id->bus); |
| 339 | id->group = TO_NATIVE(id->group); | ||
| 339 | id->vendor = TO_NATIVE(id->vendor); | 340 | id->vendor = TO_NATIVE(id->vendor); |
| 340 | id->product = TO_NATIVE(id->product); | 341 | id->product = TO_NATIVE(id->product); |
| 341 | 342 | ||
| 342 | sprintf(alias, "hid:b%04X", id->bus); | 343 | sprintf(alias, "hid:b%04X", id->bus); |
| 344 | ADD(alias, "g", id->group != HID_GROUP_ANY, id->group); | ||
| 343 | ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); | 345 | ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); |
| 344 | ADD(alias, "p", id->product != HID_ANY_ID, id->product); | 346 | ADD(alias, "p", id->product != HID_ANY_ID, id->product); |
| 345 | 347 | ||
