aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/cdc_ether.c
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2013-06-29 06:03:06 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-02 04:47:41 -0400
commit1fc4c84d49558ceca04761abd3f7eb5224af75b2 (patch)
treead2c98f91e1ce5c97e55932ec56b33ec2402b7c4 /drivers/net/usb/cdc_ether.c
parent06efce71166b222b6715c73700f5e9b228d68999 (diff)
net: cdc_ether: allow combined control and data interface
Some Icera based Huawei modems handled by this driver are not completely CDC ECM compliant, using the same USB interface for both control and data. The CDC functional descriptors include a Union naming this interface as both master and slave, so it is supportable by relaxing the descriptor parsing in case these interfaces are identical. This has been tested on a Huawei K3806 and verified to add support for that device. Reported-and-tested-by: Enrico Mioso <mrkiko.rs@gmail.com> Signed-off-by: Bjørn Mork <bjorn@mork.no> Acked-by: Oliver Neukum <oliver@neukum.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/cdc_ether.c')
-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 */