aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2014-07-29 17:14:25 +0200
committerJiri Kosina <jkosina@suse.cz>2014-08-25 03:28:08 -0500
commitc2b2f16c5c62583d4f8904e44c4b30c94a01eaf1 (patch)
tree72ff984b458a6ff721a67a062fc11fe6c9548a26
parentHID: uhid: implement SET_REPORT (diff)
downloadlinux-dev-c2b2f16c5c62583d4f8904e44c4b30c94a01eaf1.tar.xz
linux-dev-c2b2f16c5c62583d4f8904e44c4b30c94a01eaf1.zip
HID: uhid: report to user-space whether reports are numbered
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>
-rw-r--r--drivers/hid/uhid.c21
-rw-r--r--include/uapi/linux/uhid.h11
2 files changed, 31 insertions, 1 deletions
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 19511481a7d3..f6ec5eaf6b89 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -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)
diff --git a/include/uapi/linux/uhid.h b/include/uapi/linux/uhid.h
index 62aac0e4edf3..aaa86d6bd1dd 100644
--- a/include/uapi/linux/uhid.h
+++ b/include/uapi/linux/uhid.h
@@ -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__));