Commit 3b3baa82 authored by David Herrmann's avatar David Herrmann Committed by Jiri Kosina

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: default avatarDavid Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent f80e1360
...@@ -149,7 +149,39 @@ static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum, ...@@ -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, static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
unsigned char report_type) 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 = { static struct hid_ll_driver uhid_hid_driver = {
......
...@@ -29,6 +29,7 @@ enum uhid_event_type { ...@@ -29,6 +29,7 @@ enum uhid_event_type {
UHID_STOP, UHID_STOP,
UHID_OPEN, UHID_OPEN,
UHID_CLOSE, UHID_CLOSE,
UHID_OUTPUT,
UHID_OUTPUT_EV, UHID_OUTPUT_EV,
UHID_INPUT, UHID_INPUT,
}; };
...@@ -49,11 +50,23 @@ struct uhid_create_req { ...@@ -49,11 +50,23 @@ struct uhid_create_req {
#define UHID_DATA_MAX 4096 #define UHID_DATA_MAX 4096
enum uhid_report_type {
UHID_FEATURE_REPORT,
UHID_OUTPUT_REPORT,
UHID_INPUT_REPORT,
};
struct uhid_input_req { struct uhid_input_req {
__u8 data[UHID_DATA_MAX]; __u8 data[UHID_DATA_MAX];
__u16 size; __u16 size;
} __attribute__((__packed__)); } __attribute__((__packed__));
struct uhid_output_req {
__u8 data[UHID_DATA_MAX];
__u16 size;
__u8 rtype;
} __attribute__((__packed__));
struct uhid_output_ev_req { struct uhid_output_ev_req {
__u16 type; __u16 type;
__u16 code; __u16 code;
...@@ -66,6 +79,7 @@ struct uhid_event { ...@@ -66,6 +79,7 @@ struct uhid_event {
union { union {
struct uhid_create_req create; struct uhid_create_req create;
struct uhid_input_req input; struct uhid_input_req input;
struct uhid_output_req output;
struct uhid_output_ev_req output_ev; struct uhid_output_ev_req output_ev;
} u; } u;
} __attribute__((__packed__)); } __attribute__((__packed__));
......
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