Commit 4d53b801 authored by Henrik Rydberg's avatar Henrik Rydberg Committed by Jiri Kosina

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: default avatarHenrik Rydberg <rydberg@euromail.se>
Acked-by: default avatarBenjamin Tissoires <benjamin.tissoires@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent a7197c2e
...@@ -1222,6 +1222,7 @@ static bool hid_match_one_id(struct hid_device *hdev, ...@@ -1222,6 +1222,7 @@ static bool hid_match_one_id(struct hid_device *hdev,
const struct hid_device_id *id) const struct hid_device_id *id)
{ {
return id->bus == hdev->bus && return id->bus == hdev->bus &&
(id->group == HID_GROUP_ANY || id->group == hdev->group) &&
(id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) && (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
(id->product == HID_ANY_ID || id->product == hdev->product); (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, ...@@ -1694,6 +1695,7 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf,
return -ENOMEM; return -ENOMEM;
dynid->id.bus = bus; dynid->id.bus = bus;
dynid->id.group = HID_GROUP_ANY;
dynid->id.vendor = vendor; dynid->id.vendor = vendor;
dynid->id.product = product; dynid->id.product = product;
dynid->id.driver_data = driver_data; dynid->id.driver_data = driver_data;
...@@ -1817,6 +1819,23 @@ static int hid_device_remove(struct device *dev) ...@@ -1817,6 +1819,23 @@ static int hid_device_remove(struct device *dev)
return 0; 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) static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
{ {
struct hid_device *hdev = container_of(dev, struct hid_device, dev); 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,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)) if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
return -ENOMEM; return -ENOMEM;
if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X", if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
hdev->bus, hdev->vendor, hdev->product)) hdev->bus, hdev->group, hdev->vendor, hdev->product))
return -ENOMEM; return -ENOMEM;
return 0; return 0;
...@@ -1843,6 +1862,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env) ...@@ -1843,6 +1862,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
static struct bus_type hid_bus_type = { static struct bus_type hid_bus_type = {
.name = "hid", .name = "hid",
.dev_attrs = hid_dev_attrs,
.match = hid_bus_match, .match = hid_bus_match,
.probe = hid_device_probe, .probe = hid_device_probe,
.remove = hid_device_remove, .remove = hid_device_remove,
......
...@@ -476,6 +476,7 @@ struct hid_device { /* device report descriptor */ ...@@ -476,6 +476,7 @@ struct hid_device { /* device report descriptor */
unsigned maxcollection; /* Number of parsed collections */ unsigned maxcollection; /* Number of parsed collections */
unsigned maxapplication; /* Number of applications */ unsigned maxapplication; /* Number of applications */
__u16 bus; /* BUS ID */ __u16 bus; /* BUS ID */
__u16 group; /* Report group */
__u32 vendor; /* Vendor ID */ __u32 vendor; /* Vendor ID */
__u32 product; /* Product ID */ __u32 product; /* Product ID */
__u32 version; /* HID version */ __u32 version; /* HID version */
......
...@@ -132,10 +132,11 @@ struct usb_device_id { ...@@ -132,10 +132,11 @@ struct usb_device_id {
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#define HID_ANY_ID (~0) #define HID_ANY_ID (~0)
#define HID_GROUP_ANY 0x0000
struct hid_device_id { struct hid_device_id {
__u16 bus; __u16 bus;
__u16 pad1; __u16 group;
__u32 vendor; __u32 vendor;
__u32 product; __u32 product;
kernel_ulong_t driver_data kernel_ulong_t driver_data
......
...@@ -336,10 +336,12 @@ static int do_hid_entry(const char *filename, ...@@ -336,10 +336,12 @@ static int do_hid_entry(const char *filename,
struct hid_device_id *id, char *alias) struct hid_device_id *id, char *alias)
{ {
id->bus = TO_NATIVE(id->bus); id->bus = TO_NATIVE(id->bus);
id->group = TO_NATIVE(id->group);
id->vendor = TO_NATIVE(id->vendor); id->vendor = TO_NATIVE(id->vendor);
id->product = TO_NATIVE(id->product); id->product = TO_NATIVE(id->product);
sprintf(alias, "hid:b%04X", id->bus); 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, "v", id->vendor != HID_ANY_ID, id->vendor);
ADD(alias, "p", id->product != HID_ANY_ID, id->product); ADD(alias, "p", id->product != HID_ANY_ID, id->product);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment