]> Pileus Git - ~andy/linux/blobdiff - drivers/net/usb/cdc_ether.c
net: cdc_ether: allow combined control and data interface
[~andy/linux] / drivers / net / usb / cdc_ether.c
index 04ee044dde511badbe8117f45faed74ee92b93be..4393f148312629ba5b93426d4e4e55d7ddd221a0 100644 (file)
@@ -215,6 +215,10 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                                        goto bad_desc;
                        }
 
+                       /* some devices merge these - skip class check */
+                       if (info->control == info->data)
+                               goto next_desc;
+
                        /* a data interface altsetting does the real i/o */
                        d = &info->data->cur_altsetting->desc;
                        if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
@@ -304,19 +308,23 @@ next_desc:
        /* claim data interface and set it up ... with side effects.
         * network traffic can't flow until an altsetting is enabled.
         */
-       status = usb_driver_claim_interface(driver, info->data, dev);
-       if (status < 0)
-               return status;
+       if (info->data != info->control) {
+               status = usb_driver_claim_interface(driver, info->data, dev);
+               if (status < 0)
+                       return status;
+       }
        status = usbnet_get_endpoints(dev, info->data);
        if (status < 0) {
                /* ensure immediate exit from usbnet_disconnect */
                usb_set_intfdata(info->data, NULL);
-               usb_driver_release_interface(driver, info->data);
+               if (info->data != info->control)
+                       usb_driver_release_interface(driver, info->data);
                return status;
        }
 
        /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
-       dev->status = NULL;
+       if (info->data != info->control)
+               dev->status = NULL;
        if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
                struct usb_endpoint_descriptor  *desc;
 
@@ -349,6 +357,10 @@ void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
        struct cdc_state                *info = (void *) &dev->data;
        struct usb_driver               *driver = driver_of(intf);
 
+       /* combined interface - nothing  to do */
+       if (info->data == info->control)
+               return;
+
        /* disconnect master --> disconnect slave */
        if (intf == info->control && info->data) {
                /* ensure immediate exit from usbnet_disconnect */