Commit d09d36a9 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: usb_bulk_message() handles interrupts endpoints

Because there is no bulk_interrupt_message() routine and no
USBDEVFS_INTERRUPT ioctl, people have been forced to abuse the
usb_bulk_message() routine and USBDEVFS_BULK by using them for interrupt
transfers as well as bulk transfers.

This patch (as567) formalizes this practice and adds code to
usb_bulk_message() for detecting when the target is really an interrupt
endpoint.  If it is, the routine submits an interrupt URB (using the
default interval) instead of a bulk URB.  In theory this should help HCDs
that don't like it when people try to mix transfer types, queuing both
periodic and non-periodic types for the same endpoint.

Not fully tested -- I don't have any programs that use USBDEVFS_BULK for
interrupt transfers -- but it compiles okay and normal bulk messages work
as well as before.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>

 drivers/usb/core/message.c |   24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)
parent b13296c6
......@@ -187,21 +187,37 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
* If a thread in your driver uses this call, make sure your disconnect()
* method can wait for it to complete. Since you don't have a handle on
* the URB used, you can't cancel the request.
*
* Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT
* ioctl, users are forced to abuse this routine by using it to submit
* URBs for interrupt endpoints. We will take the liberty of creating
* an interrupt URB (with the default interval) if the target is an
* interrupt endpoint.
*/
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;
struct usb_host_endpoint *ep;
if (len < 0)
ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)
[usb_pipeendpoint(pipe)];
if (!ep || len < 0)
return -EINVAL;
urb=usb_alloc_urb(0, GFP_KERNEL);
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT) {
pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
usb_fill_int_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL,
ep->desc.bInterval);
} else
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
return usb_start_wait_urb(urb, timeout, actual_length);
}
......
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