mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 06:12:08 +00:00
[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: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> drivers/usb/core/message.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
This commit is contained in:
parent
b13296c661
commit
d09d36a91c
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user