diff options
author | Alan Ott <alan@signal11.us> | 2010-05-16 18:07:09 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-05-18 10:43:23 +0200 |
commit | a8ab5d58b0238b8199cc699b8dff7c5e1da24138 (patch) | |
tree | 9e737c8618433cb8a603a3f32c382ef08ef287ab /drivers/hid/usbhid | |
parent | 117ea33a18392685b92928bbaa4e84dbc5be8f93 (diff) |
HID: hidraw: Use Interrupt Endpoint for OUT Transfers if Available
This patch makes the hidraw driver use the first Interrupt OUT endpoint for
HID transfers to the device if such an endpoint exists. This is consistent
with the behavior of the hiddev driver, and the logic is similar.
From the USB HID specification:
The Interrupt Out pipe is optional. If a device declares an Interrupt Out
endpoint then Output reports are transmitted by the host to the device
through the Interrupt Out endpoint. If no Interrupt Out endpoint is
declared then Output reports are transmitted to a device through the
Control endpoint, using Set_Report(Output) requests.
Signed-off-by: Alan Ott <alan@signal11.us>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 245aef0de8f..f9640a362ca 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -807,16 +807,36 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co struct usb_host_interface *interface = intf->cur_altsetting; int ret; - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - HID_REQ_SET_REPORT, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - ((report_type + 1) << 8) | *buf, - interface->desc.bInterfaceNumber, buf + 1, count - 1, - USB_CTRL_SET_TIMEOUT); - - /* count also the report id */ - if (ret > 0) - ret++; + if (usbhid->urbout) { + int actual_length; + int skipped_report_id = 0; + if (buf[0] == 0x0) { + /* Don't send the Report ID */ + buf++; + count--; + skipped_report_id = 1; + } + ret = usb_interrupt_msg(dev, usbhid->urbout->pipe, + buf, count, &actual_length, + USB_CTRL_SET_TIMEOUT); + /* return the number of bytes transferred */ + if (ret == 0) { + ret = actual_length; + /* count also the report id */ + if (skipped_report_id) + ret++; + } + } else { + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + HID_REQ_SET_REPORT, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + ((report_type + 1) << 8) | *buf, + interface->desc.bInterfaceNumber, buf + 1, count - 1, + USB_CTRL_SET_TIMEOUT); + /* count also the report id */ + if (ret > 0) + ret++; + } return ret; } |