net: qmi_wwan: use a single bind function for all device types
authorBjørn Mork <bjorn@mork.no>
Fri, 7 Sep 2012 07:36:07 +0000 (07:36 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 7 Sep 2012 18:50:06 +0000 (14:50 -0400)
Refactoring the bind code lets us use a common driver_info struct
for all supported devices, simplifying the code a bit.  The
real advantage is that devices using the CDC ECM interface
layout now also can be added dynamically using the new_id sysfs
interface.  This simplifies testing of new devices.

Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/usb/qmi_wwan.c

index 516653f..8492333 100644 (file)
@@ -139,10 +139,18 @@ 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)));
 
-       /* require a single interrupt status endpoint for subdriver */
+       /* 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;
 
+       /* and a number of CDC descriptors */
        while (len > 3) {
                struct usb_descriptor_header *h = (void *)buf;
 
@@ -231,8 +239,9 @@ next_desc:
        if (status < 0)
                goto err;
 
+shared:
        status = qmi_wwan_register_subdriver(dev);
-       if (status < 0) {
+       if (status < 0 && info->control != info->data) {
                usb_set_intfdata(info->data, NULL);
                usb_driver_release_interface(driver, info->data);
        }
@@ -241,20 +250,6 @@ err:
        return status;
 }
 
-/* Some devices combine the "control" and "data" functions into a
- * single interface with all three endpoints: interrupt + bulk in and
- * out
- */
-static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
-{
-       struct qmi_wwan_state *info = (void *)&dev->data;
-
-       /*  control and data is shared */
-       info->control = intf;
-       info->data = intf;
-       return qmi_wwan_register_subdriver(dev);
-}
-
 static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf)
 {
        struct qmi_wwan_state *info = (void *)&dev->data;
@@ -330,20 +325,12 @@ static const struct driver_info   qmi_wwan_info = {
        .manage_power   = qmi_wwan_manage_power,
 };
 
-static const struct driver_info        qmi_wwan_shared = {
-       .description    = "WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-};
-
 #define HUAWEI_VENDOR_ID       0x12D1
 
 /* map QMI/wwan function by a fixed interface number */
 #define QMI_FIXED_INTF(vend, prod, num) \
        USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \
-       .driver_info = (unsigned long)&qmi_wwan_shared
+       .driver_info = (unsigned long)&qmi_wwan_info
 
 /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */
 #define QMI_GOBI1K_DEVICE(vend, prod) \
@@ -367,15 +354,15 @@ static const struct usb_device_id products[] = {
        /* 2. Combined interface devices matching on class+protocol */
        {       /* Huawei E392, E398 and possibly others in "Windows mode" */
                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17),
-               .driver_info        = (unsigned long)&qmi_wwan_shared,
+               .driver_info        = (unsigned long)&qmi_wwan_info,
        },
        {       /* Pantech UML290 */
                USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff),
-               .driver_info        = (unsigned long)&qmi_wwan_shared,
+               .driver_info        = (unsigned long)&qmi_wwan_info,
        },
        {       /* Pantech UML290 - newer firmware */
                USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff),
-               .driver_info        = (unsigned long)&qmi_wwan_shared,
+               .driver_info        = (unsigned long)&qmi_wwan_info,
        },
 
        /* 3. Combined interface devices matching on interface number */
@@ -457,7 +444,7 @@ static int qmi_wwan_probe(struct usb_interface *intf, const struct usb_device_id
         */
        if (!id->driver_info) {
                dev_dbg(&intf->dev, "setting defaults for dynamic device id\n");
-               id->driver_info = (unsigned long)&qmi_wwan_shared;
+               id->driver_info = (unsigned long)&qmi_wwan_info;
        }
 
        return usbnet_probe(intf, id);