fix mceusb endpoint type identification/handling
PATCH v2 1/1 fix mceusb endpoint type identification/handling
From: Matt DeVillier <[email protected]>
Change the I/O endpoint handling of the mceusb driver to respect the endpoint type reported by device (bulk/interrupt), rather than treating all endpoints as type interrupt, which breaks devices using bulk endpoints when connected to a xhci controller. Accordingly, change the function calls to initialize an endpoint's transfer pipe and urb handlers to use the correct function based on the endpoint type.
---
This is a continuation of the work started in patch #21648
Patch compiled and tested against linux-media git master. Backported and tested against 3.14.1 stable as well.
v2 corrects some formatting issues (both with the patch itself and MUA), and removes a small bug fix not relevant to the core patch functionality.
---
mceusb.c renamed from mceusb.c.orig +0 -0
@@ -747,11 +747,19 @@ static void mce_request_packet(struct mc
} /* outbound data */
- pipe = usb_sndintpipe(ir->usbdev,
- ir->usb_ep_out->bEndpointAddress);
- usb_fill_int_urb(async_urb, ir->usbdev, pipe,
- async_buf, size, mce_async_callback,
- ir, ir->usb_ep_out->bInterval);
+ if ((ir->usb_ep_out->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT) {
+ pipe = usb_sndintpipe(ir->usbdev,
+ ir->usb_ep_out->bEndpointAddress);
+ usb_fill_int_urb(async_urb, ir->usbdev, pipe, async_buf,
+ size, mce_async_callback, ir,
+ ir->usb_ep_out->bInterval);
+ } else {
+ pipe = usb_sndbulkpipe(ir->usbdev,
+ ir->usb_ep_out->bEndpointAddress);
+ usb_fill_bulk_urb(async_urb, ir->usbdev, pipe, async_buf,
+ size, mce_async_callback, ir);
+ }
memcpy(async_buf, data, size);
} else if (urb_type == MCEUSB_RX) {@@ -1271,38 +1279,47 @@ static int mceusb_dev_probe(struct usb_i
if ((ep_in == NULL) && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN)
- && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)
- || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT))) {
-
- ep_in = ep;
- ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
- ep_in->bInterval = 1;
- dev_dbg(&intf->dev, "acceptable inbound endpoint found");
+ == USB_DIR_IN)) {
+
+ if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK) {
+
+ ep_in = ep;
+ mce_dbg(&intf->dev, "acceptable bulk inbound endpoint found\n");
+ } else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT) {
+
+ ep_in = ep;
+ ep_in->bInterval = 1;
+ mce_dbg(&intf->dev, "acceptable interrupt inbound endpoint found\n");
+ }
} if ((ep_out == NULL) && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_OUT)
- && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)
- || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT))) {
-
- ep_out = ep;
- ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
- ep_out->bInterval = 1;
- dev_dbg(&intf->dev, "acceptable outbound endpoint found");
+ == USB_DIR_OUT)) {
+ if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK) {
+ ep_out = ep;
+ mce_dbg(&intf->dev, "acceptable bulk outbound endpoint found\n");
+ } else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT) {
+ ep_out = ep;
+ ep_out->bInterval = 1;
+ mce_dbg(&intf->dev, "acceptable interrupt outbound endpoint found\n");
+ }
}
- }
if (ep_in == NULL) {
dev_dbg(&intf->dev, "inbound and/or endpoint not found");
return -ENODEV;
}- pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
+ if ((ep_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT) {
+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
+ } else {
+ pipe = usb_rcvbulkpipe(dev, ep_in->bEndpointAddress);
+ }
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL); @@ -1343,8 +1360,14 @@ static int mceusb_dev_probe(struct usb_i goto rc_dev_fail; /* wire up inbound data handler */
- usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
- mceusb_dev_recv, ir, ep_in->bInterval);
+ if ((ep_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT) {
+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+ mceusb_dev_recv, ir, ep_in->bInterval);
+ } else {
+ usb_fill_bulk_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+ mceusb_dev_recv, ir);
+ }
ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;