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 special interface tag to the hid device id, and broadcasts it using both uevent and modalias. Matching ids are introduced for the hid-multitouch driver. As a consequence, generic hid will no longer match multitouch devices, and udev will automatically load hid-multitouch instead. Signed-off-by: Henrik Rydberg <rydberg@xxxxxxxxxxx> --- drivers/hid/hid-core.c | 28 +++++++++++++++++++++++++--- drivers/hid/hid-multitouch.c | 7 ++++++- include/linux/hid.h | 7 +++++++ include/linux/mod_devicetable.h | 2 +- scripts/mod/file2alias.c | 2 ++ 5 files changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8a7b59e..1cf6cb5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -205,6 +205,10 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage) parser->collection_stack_ptr ? parser->collection_stack[parser->collection_stack_ptr - 1] : 0; parser->local.usage_index++; + + if (usage == HID_DG_CONTACTID) + parser->device->idtags |= HID_IDTAG_MULTITOUCH; + return 0; } @@ -1154,7 +1158,7 @@ EXPORT_SYMBOL_GPL(hid_input_report); static bool hid_match_one_id(struct hid_device *hdev, const struct hid_device_id *id) { - return id->bus == hdev->bus && + return id->bus == hdev->bus && id->idtags == hdev->idtags && (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) && (id->product == HID_ANY_ID || id->product == hdev->product); } @@ -1723,6 +1727,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%04Xi%04Xv%08Xp%08X\n", + hdev->bus, hdev->idtags, 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); @@ -1740,8 +1761,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%04Xi%04Xv%08Xp%08X", + hdev->bus, hdev->idtags, hdev->vendor, hdev->product)) return -ENOMEM; return 0; @@ -1749,6 +1770,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, diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 421b16c..80ceab5 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -104,7 +104,7 @@ struct mt_device { #define MT_DEFAULT_MAXCONTACT 10 #define HID_USB_MT_DEVICE(v, p) \ - HID_USB_DEVICE(v, p) + .idtags = HID_IDTAG_MULTITOUCH, HID_USB_DEVICE(v, p) /* * these device-dependent functions determine what slot corresponds @@ -886,6 +886,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_MT_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, + /* Generic MT device */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_MT_DEVICE(HID_ANY_ID, + HID_ANY_ID) }, + { } }; MODULE_DEVICE_TABLE(hid, mt_devices); diff --git a/include/linux/hid.h b/include/linux/hid.h index 5b3be43..1e68543 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -62,6 +62,12 @@ #define HID_MAX_DESCRIPTOR_SIZE 4096 +/* + * HID identifying tags extracted from reports + */ +#define HID_IDTAG_MULTITOUCH 0x0001 + + #ifdef __KERNEL__ #include <linux/types.h> @@ -473,6 +479,7 @@ struct hid_device { /* device report descriptor */ unsigned maxcollection; /* Number of parsed collections */ unsigned maxapplication; /* Number of applications */ __u16 bus; /* BUS ID */ + __u16 idtags; /* Identifying tags extracted from reports */ __u32 vendor; /* Vendor ID */ __u32 product; /* Product ID */ __u32 version; /* HID version */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 83ac071..25446f0 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -135,7 +135,7 @@ struct usb_device_id { struct hid_device_id { __u16 bus; - __u16 pad1; + __u16 idtags; __u32 vendor; __u32 product; kernel_ulong_t driver_data diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index b89efe6..d0c3a2b 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -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->idtags = TO_NATIVE(id->idtags); id->vendor = TO_NATIVE(id->vendor); id->product = TO_NATIVE(id->product); sprintf(alias, "hid:b%04X", id->bus); + ADD(alias, "i", true, id->idtags); ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); ADD(alias, "p", id->product != HID_ANY_ID, id->product); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html