|
@@ -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 */
|