aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-core.c
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2012-04-23 06:07:03 -0400
committerJiri Kosina <jkosina@suse.cz>2012-05-01 06:54:54 -0400
commit734c660931095ae165c0db6ff60558fc4173bfd0 (patch)
treee56f9e51a034c4fb0c9b89a903b64c41b050d1d3 /drivers/hid/hid-core.c
parent4d53b8012f1f01ddb3f24db2031b042bb4cbd0d0 (diff)
HID: Scan the device for group info before adding it
In order to allow the report descriptor to influence the hid device properties, one needs to parse the descriptor early, without reference to any driver. Scan the descriptor for group information during device add, before the device has been broadcast to userland. The device modalias will contain group information which can be used to differentiate between modules. For starters, just handle the generic group. Signed-off-by: Henrik Rydberg <rydberg@euromail.se> Acked-by: Benjamin Tissoires <benjamin.tissoires@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-core.c')
-rw-r--r--drivers/hid/hid-core.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index cfcb69eb17d..f932cd533d4 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -658,6 +658,58 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
658 return NULL; 658 return NULL;
659} 659}
660 660
661static void hid_scan_usage(struct hid_device *hid, u32 usage)
662{
663}
664
665/*
666 * Scan a report descriptor before the device is added to the bus.
667 * Sets device groups and other properties that determine what driver
668 * to load.
669 */
670static int hid_scan_report(struct hid_device *hid)
671{
672 unsigned int page = 0, delim = 0;
673 __u8 *start = hid->dev_rdesc;
674 __u8 *end = start + hid->dev_rsize;
675 unsigned int u, u_min = 0, u_max = 0;
676 struct hid_item item;
677
678 hid->group = HID_GROUP_GENERIC;
679 while ((start = fetch_item(start, end, &item)) != NULL) {
680 if (item.format != HID_ITEM_FORMAT_SHORT)
681 return -EINVAL;
682 if (item.type == HID_ITEM_TYPE_GLOBAL) {
683 if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
684 page = item_udata(&item) << 16;
685 } else if (item.type == HID_ITEM_TYPE_LOCAL) {
686 if (delim > 1)
687 break;
688 u = item_udata(&item);
689 if (item.size <= 2)
690 u += page;
691 switch (item.tag) {
692 case HID_LOCAL_ITEM_TAG_DELIMITER:
693 delim += !!u;
694 break;
695 case HID_LOCAL_ITEM_TAG_USAGE:
696 hid_scan_usage(hid, u);
697 break;
698 case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
699 u_min = u;
700 break;
701 case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
702 u_max = u;
703 for (u = u_min; u <= u_max; u++)
704 hid_scan_usage(hid, u);
705 break;
706 }
707 }
708 }
709
710 return 0;
711}
712
661/** 713/**
662 * hid_parse_report - parse device report 714 * hid_parse_report - parse device report
663 * 715 *
@@ -2171,6 +2223,16 @@ int hid_add_device(struct hid_device *hdev)
2171 if (!hdev->dev_rdesc) 2223 if (!hdev->dev_rdesc)
2172 return -ENODEV; 2224 return -ENODEV;
2173 2225
2226 /*
2227 * Scan generic devices for group information
2228 */
2229 if (hid_ignore_special_drivers ||
2230 !hid_match_id(hdev, hid_have_special_driver)) {
2231 ret = hid_scan_report(hdev);
2232 if (ret)
2233 hid_warn(hdev, "bad device descriptor (%d)\n", ret);
2234 }
2235
2174 /* XXX hack, any other cleaner solution after the driver core 2236 /* XXX hack, any other cleaner solution after the driver core
2175 * is converted to allow more than 20 bytes as the device name? */ 2237 * is converted to allow more than 20 bytes as the device name? */
2176 dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, 2238 dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,