aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/usb/cdc_ether.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 04ee044dde51..4393f1483126 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -215,6 +215,10 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
215 goto bad_desc; 215 goto bad_desc;
216 } 216 }
217 217
218 /* some devices merge these - skip class check */
219 if (info->control == info->data)
220 goto next_desc;
221
218 /* a data interface altsetting does the real i/o */ 222 /* a data interface altsetting does the real i/o */
219 d = &info->data->cur_altsetting->desc; 223 d = &info->data->cur_altsetting->desc;
220 if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { 224 if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
@@ -304,19 +308,23 @@ next_desc:
304 /* claim data interface and set it up ... with side effects. 308 /* claim data interface and set it up ... with side effects.
305 * network traffic can't flow until an altsetting is enabled. 309 * network traffic can't flow until an altsetting is enabled.
306 */ 310 */
307 status = usb_driver_claim_interface(driver, info->data, dev); 311 if (info->data != info->control) {
308 if (status < 0) 312 status = usb_driver_claim_interface(driver, info->data, dev);
309 return status; 313 if (status < 0)
314 return status;
315 }
310 status = usbnet_get_endpoints(dev, info->data); 316 status = usbnet_get_endpoints(dev, info->data);
311 if (status < 0) { 317 if (status < 0) {
312 /* ensure immediate exit from usbnet_disconnect */ 318 /* ensure immediate exit from usbnet_disconnect */
313 usb_set_intfdata(info->data, NULL); 319 usb_set_intfdata(info->data, NULL);
314 usb_driver_release_interface(driver, info->data); 320 if (info->data != info->control)
321 usb_driver_release_interface(driver, info->data);
315 return status; 322 return status;
316 } 323 }
317 324
318 /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */ 325 /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */
319 dev->status = NULL; 326 if (info->data != info->control)
327 dev->status = NULL;
320 if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { 328 if (info->control->cur_altsetting->desc.bNumEndpoints == 1) {
321 struct usb_endpoint_descriptor *desc; 329 struct usb_endpoint_descriptor *desc;
322 330
@@ -349,6 +357,10 @@ void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
349 struct cdc_state *info = (void *) &dev->data; 357 struct cdc_state *info = (void *) &dev->data;
350 struct usb_driver *driver = driver_of(intf); 358 struct usb_driver *driver = driver_of(intf);
351 359
360 /* combined interface - nothing to do */
361 if (info->data == info->control)
362 return;
363
352 /* disconnect master --> disconnect slave */ 364 /* disconnect master --> disconnect slave */
353 if (intf == info->control && info->data) { 365 if (intf == info->control && info->data) {
354 /* ensure immediate exit from usbnet_disconnect */ 366 /* ensure immediate exit from usbnet_disconnect */