Bjørn Mork <bjorn@xxxxxxx> writes: > > Risking that I am trying to be too smart again. .. But I really think > we can fix this in a more generic way by making the probe behave more > like it did before. How about just letting it continue without erring > out until it has called usbnet_get_endpoints? That should work without > needing any quirks. I was thinking about something like this patch, dropping both the unnecessary verification of bNumEndpoints and of the CDC functional descriptors. If we find a CDC Union, then fine - we use it to locate the data interface. If we find a CDC Ether, then fine - we use it to set the MAC address. This should end up calling usbnet_get_endpoints (first thing qmi_wwan_register_subdriver does), and succeed if any data interface altsetting have the necessary endpoints. There really are few reasons to do any strict verification step in the probe in this driver, because there really are no usable markers on the functions. That's why the driver does explicit interface matching in the first place. So it makes sense to allow the probe to succeed if collecting the 3 required endpoints is at all possible. It will of course succeed on a number of unsupported interfaces if dynamical IDs are used. But with nothing to differentiate a QMI/wwan function from other functions, there is really nothing we can do to prevent that. If we are to support dynamic IDs, then there will be false positives. The user can manually unbind the driver from unwanted matches in this case. Only build tested for now. I will test on the devices I have before submitting, if this works for you: diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index efb5c7c..1cfa80c 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -139,18 +139,11 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct qmi_wwan_state))); - /* control and data is shared? */ - if (intf->cur_altsetting->desc.bNumEndpoints == 3) { - info->control = intf; - info->data = intf; - goto shared; - } - - /* else require a single interrupt status endpoint on control intf */ - if (intf->cur_altsetting->desc.bNumEndpoints != 1) - goto err; + /* set up initial state */ + info->control = intf; + info->data = intf; - /* and a number of CDC descriptors */ + /* some vendors add CDC descriptors */ while (len > 3) { struct usb_descriptor_header *h = (void *)buf; @@ -207,25 +200,17 @@ next_desc: buf += h->bLength; } - /* did we find all the required ones? */ - if (!(found & (1 << USB_CDC_HEADER_TYPE)) || - !(found & (1 << USB_CDC_UNION_TYPE))) { - dev_err(&intf->dev, "CDC functional descriptors missing\n"); - goto err; - } - - /* verify CDC Union */ - if (desc->bInterfaceNumber != cdc_union->bMasterInterface0) { - dev_err(&intf->dev, "bogus CDC Union: master=%u\n", cdc_union->bMasterInterface0); - goto err; - } - - /* need to save these for unbind */ - info->control = intf; - info->data = usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0); - if (!info->data) { - dev_err(&intf->dev, "bogus CDC Union: slave=%u\n", cdc_union->bSlaveInterface0); - goto err; + /* using two interfaces if we found a CDC Union */ + if (cdc_union) { + if (desc->bInterfaceNumber != cdc_union->bMasterInterface0) { + dev_err(&intf->dev, "bogus CDC Union: master=%u\n", cdc_union->bMasterInterface0); + goto err; + } + info->data = usb_ifnum_to_if(dev->udev, cdc_union->bSlaveInterface0); + if (!info->data) { + dev_err(&intf->dev, "bogus CDC Union: slave=%u\n", cdc_union->bSlaveInterface0); + goto err; + } } /* errors aren't fatal - we can live with the dynamic address */ @@ -234,12 +219,13 @@ next_desc: usbnet_get_ethernet_addr(dev, cdc_ether->iMACAddress); } - /* claim data interface and set it up */ - status = usb_driver_claim_interface(driver, info->data, dev); - if (status < 0) - goto err; + /* claim separate data interface? */ + if (info->control != info->data) { + status = usb_driver_claim_interface(driver, info->data, dev); + if (status < 0) + goto err; + } -shared: status = qmi_wwan_register_subdriver(dev); if (status < 0 && info->control != info->data) { usb_set_intfdata(info->data, NULL); -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html