]> Pileus Git - ~andy/linux/blobdiff - drivers/usb/class/cdc-wdm.c
USB: cdc-wdm: Avoid hanging on interface with no USB_CDC_DMM_TYPE
[~andy/linux] / drivers / usb / class / cdc-wdm.c
index 1c50baff7725ec2d8e368b3c34f50925a76f3804..c0197af22fd85b1d6828311cdb820d42877a84c4 100644 (file)
@@ -57,6 +57,8 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
 
 #define WDM_MAX                        16
 
+/* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */
+#define WDM_DEFAULT_BUFSIZE    256
 
 static DEFINE_MUTEX(wdm_mutex);
 
@@ -80,7 +82,6 @@ struct wdm_device {
        u16                     bufsize;
        u16                     wMaxCommand;
        u16                     wMaxPacketSize;
-       u16                     bMaxPacketSize0;
        __le16                  inum;
        int                     reslength;
        int                     length;
@@ -159,11 +160,9 @@ static void wdm_int_callback(struct urb *urb)
        int rv = 0;
        int status = urb->status;
        struct wdm_device *desc;
-       struct usb_ctrlrequest *req;
        struct usb_cdc_notification *dr;
 
        desc = urb->context;
-       req = desc->irq;
        dr = (struct usb_cdc_notification *)desc->sbuf;
 
        if (status) {
@@ -210,24 +209,6 @@ static void wdm_int_callback(struct urb *urb)
                goto exit;
        }
 
-       req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
-       req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
-       req->wValue = 0;
-       req->wIndex = desc->inum;
-       req->wLength = cpu_to_le16(desc->wMaxCommand);
-
-       usb_fill_control_urb(
-               desc->response,
-               interface_to_usbdev(desc->intf),
-               /* using common endpoint 0 */
-               usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
-               (unsigned char *)req,
-               desc->inbuf,
-               desc->wMaxCommand,
-               wdm_in_callback,
-               desc
-       );
-       desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        spin_lock(&desc->iuspin);
        clear_bit(WDM_READ, &desc->flags);
        set_bit(WDM_RESPONDING, &desc->flags);
@@ -276,14 +257,8 @@ static void free_urbs(struct wdm_device *desc)
 
 static void cleanup(struct wdm_device *desc)
 {
-       usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->wMaxPacketSize,
-                         desc->sbuf,
-                         desc->validity->transfer_dma);
-       usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->bMaxPacketSize0,
-                         desc->inbuf,
-                         desc->response->transfer_dma);
+       kfree(desc->sbuf);
+       kfree(desc->inbuf);
        kfree(desc->orq);
        kfree(desc->irq);
        kfree(desc->ubuf);
@@ -623,14 +598,13 @@ static void wdm_rxwork(struct work_struct *work)
 static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        int rv = -EINVAL;
-       struct usb_device *udev = interface_to_usbdev(intf);
        struct wdm_device *desc;
        struct usb_host_interface *iface;
        struct usb_endpoint_descriptor *ep;
        struct usb_cdc_dmm_desc *dmhd;
        u8 *buffer = intf->altsetting->extra;
        int buflen = intf->altsetting->extralen;
-       u16 maxcom = 0;
+       u16 maxcom = WDM_DEFAULT_BUFSIZE;
 
        if (!buffer)
                goto out;
@@ -683,7 +657,6 @@ next_desc:
                goto err;
 
        desc->wMaxPacketSize = usb_endpoint_maxp(ep);
-       desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
 
        desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
        if (!desc->orq)
@@ -708,19 +681,13 @@ next_desc:
        if (!desc->ubuf)
                goto err;
 
-       desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf),
-                                       desc->wMaxPacketSize,
-                                       GFP_KERNEL,
-                                       &desc->validity->transfer_dma);
+       desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL);
        if (!desc->sbuf)
                goto err;
 
-       desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
-                                        desc->bMaxPacketSize0,
-                                        GFP_KERNEL,
-                                        &desc->response->transfer_dma);
+       desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
        if (!desc->inbuf)
-               goto err2;
+               goto err;
 
        usb_fill_int_urb(
                desc->validity,
@@ -732,30 +699,40 @@ next_desc:
                desc,
                ep->bInterval
        );
-       desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+       desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+       desc->irq->wValue = 0;
+       desc->irq->wIndex = desc->inum;
+       desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
+
+       usb_fill_control_urb(
+               desc->response,
+               interface_to_usbdev(intf),
+               /* using common endpoint 0 */
+               usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
+               (unsigned char *)desc->irq,
+               desc->inbuf,
+               desc->wMaxCommand,
+               wdm_in_callback,
+               desc
+       );
 
        usb_set_intfdata(intf, desc);
        rv = usb_register_dev(intf, &wdm_class);
        if (rv < 0)
-               goto err3;
+               goto err2;
        else
                dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n",
                        intf->minor - WDM_MINOR_BASE);
 out:
        return rv;
-err3:
-       usb_set_intfdata(intf, NULL);
-       usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->bMaxPacketSize0,
-                       desc->inbuf,
-                       desc->response->transfer_dma);
 err2:
-       usb_free_coherent(interface_to_usbdev(desc->intf),
-                         desc->wMaxPacketSize,
-                         desc->sbuf,
-                         desc->validity->transfer_dma);
+       usb_set_intfdata(intf, NULL);
 err:
        free_urbs(desc);
+       kfree(desc->inbuf);
+       kfree(desc->sbuf);
        kfree(desc->ubuf);
        kfree(desc->orq);
        kfree(desc->irq);