summaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@googlemail.com>2012-06-10 15:16:24 +0200
committerJiri Kosina <jkosina@suse.cz>2012-06-18 13:42:02 +0200
commit3b3baa82e4306b5160692643fab2fa322ceb94f9 (patch)
tree04885740c41ff3b9f85af8a641d942b4a9b9dd81 /drivers/hid
parentHID: uhid: forward output request to user-space (diff)
downloadlinux-3b3baa82e4306b5160692643fab2fa322ceb94f9.tar.xz
linux-3b3baa82e4306b5160692643fab2fa322ceb94f9.zip
HID: uhid: forward raw output reports to user-space
Some drivers that use non-standard HID features require raw output reports sent to the device. We now forward these requests directly to user-space so the transport-level driver can correctly send it to the device or handle it correspondingly. There is no way to signal back whether the transmission was successful, moreover, there might be lots of messages coming out from the driver flushing the output-queue. However, there is currently no driver that causes this so we are safe. If some drivers need to transmit lots of data this way, we need a method to synchronize this and can implement another UHID_OUTPUT_SYNC event. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/uhid.c34
1 files changed, 33 insertions, 1 deletions
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 4dd693e1c8b8..421c492dc824 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -149,7 +149,39 @@ static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
unsigned char report_type)
{
- return 0;
+ struct uhid_device *uhid = hid->driver_data;
+ __u8 rtype;
+ unsigned long flags;
+ struct uhid_event *ev;
+
+ switch (report_type) {
+ case HID_FEATURE_REPORT:
+ rtype = UHID_FEATURE_REPORT;
+ break;
+ case HID_OUTPUT_REPORT:
+ rtype = UHID_OUTPUT_REPORT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (count < 1 || count > UHID_DATA_MAX)
+ return -EINVAL;
+
+ ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+ if (!ev)
+ return -ENOMEM;
+
+ ev->type = UHID_OUTPUT;
+ ev->u.output.size = count;
+ ev->u.output.rtype = rtype;
+ memcpy(ev->u.output.data, buf, count);
+
+ spin_lock_irqsave(&uhid->qlock, flags);
+ uhid_queue(uhid, ev);
+ spin_unlock_irqrestore(&uhid->qlock, flags);
+
+ return count;
}
static struct hid_ll_driver uhid_hid_driver = {