Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -187,19 +187,35 @@ 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);
	if (!urb)
		return -ENOMEM;

	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);