HID: uhid: report to user-space whether reports are numbered
authorDavid Herrmann <dh.herrmann@gmail.com>
Tue, 29 Jul 2014 15:14:25 +0000 (17:14 +0200)
committerJiri Kosina <jkosina@suse.cz>
Mon, 25 Aug 2014 08:28:08 +0000 (03:28 -0500)
This makes UHID_START include a "dev_flags" field that describes details
of the hid-device in the kernel. The first flags we introduce describe
whether a given report-type uses numbered reports. This is useful for
transport layers that force report-numbers and therefore might have to
prefix kernel-provided HID-messages with the report-number.

Currently, only HoG needs this and the spec only talks about "global
report numbers". That is, it's a global boolean not a per-type boolean.
However, given the quirks we already have in kernel-space, a per-type
value seems much more appropriate.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/uhid.c
include/uapi/linux/uhid.h

index 19511481a7d3a932e3306497d50616832ade72e6..f6ec5eaf6b89353203440bbd1a70aeaa2aaa8d3d 100644 (file)
@@ -92,8 +92,27 @@ static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
 static int uhid_hid_start(struct hid_device *hid)
 {
        struct uhid_device *uhid = hid->driver_data;
+       struct uhid_event *ev;
+       unsigned long flags;
+
+       ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+       if (!ev)
+               return -ENOMEM;
+
+       ev->type = UHID_START;
 
-       return uhid_queue_event(uhid, UHID_START);
+       if (hid->report_enum[HID_FEATURE_REPORT].numbered)
+               ev->u.start.dev_flags |= UHID_DEV_NUMBERED_FEATURE_REPORTS;
+       if (hid->report_enum[HID_OUTPUT_REPORT].numbered)
+               ev->u.start.dev_flags |= UHID_DEV_NUMBERED_OUTPUT_REPORTS;
+       if (hid->report_enum[HID_INPUT_REPORT].numbered)
+               ev->u.start.dev_flags |= UHID_DEV_NUMBERED_INPUT_REPORTS;
+
+       spin_lock_irqsave(&uhid->qlock, flags);
+       uhid_queue(uhid, ev);
+       spin_unlock_irqrestore(&uhid->qlock, flags);
+
+       return 0;
 }
 
 static void uhid_hid_stop(struct hid_device *hid)
index 62aac0e4edf34a98c231b4d3248ef1a2b7854da3..aaa86d6bd1dd921ab0637f232ced8678c60e8849 100644 (file)
@@ -54,6 +54,16 @@ struct uhid_create2_req {
        __u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
 } __attribute__((__packed__));
 
+enum uhid_dev_flag {
+       UHID_DEV_NUMBERED_FEATURE_REPORTS                       = (1ULL << 0),
+       UHID_DEV_NUMBERED_OUTPUT_REPORTS                        = (1ULL << 1),
+       UHID_DEV_NUMBERED_INPUT_REPORTS                         = (1ULL << 2),
+};
+
+struct uhid_start_req {
+       __u64 dev_flags;
+};
+
 #define UHID_DATA_MAX 4096
 
 enum uhid_report_type {
@@ -182,6 +192,7 @@ struct uhid_event {
                struct uhid_input2_req input2;
                struct uhid_set_report_req set_report;
                struct uhid_set_report_reply_req set_report_reply;
+               struct uhid_start_req start;
        } u;
 } __attribute__((__packed__));