From a8ab5d58b0238b8199cc699b8dff7c5e1da24138 Mon Sep 17 00:00:00 2001 From: Alan Ott Date: Sun, 16 May 2010 18:07:09 -0400 Subject: [PATCH] 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 Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 40 ++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 245aef0de8f2..f9640a362caa 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; } -- 2.34.1