Commit 03304bcb authored by Bjørn Mork's avatar Bjørn Mork Committed by David S. Miller

net: qmi_wwan: use fixed interface number matching

This driver support many composite USB devices where the
interface class/subclass/protocol provides no information
about the interface function. Interfaces with different
functions may all use ff/ff/ff, like this example of
a device with three serial interfaces and three QMI/wwan
interfaces:

T:  Bus=02 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#=116 Spd=480  MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=1199 ProdID=68a2 Rev= 0.06
S:  Manufacturer=Sierra Wireless, Incorporated
S:  Product=MC7710
S:  SerialNumber=3581780xxxxxx
C:* #Ifs= 6 Cfg#= 1 Atr=e0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=qcserial
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=qcserial
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms
I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qcserial
E:  Ad=83(I) Atr=03(Int.) MxPS=  64 Ivl=2ms
E:  Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms
I:* If#= 8 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan
E:  Ad=85(I) Atr=03(Int.) MxPS=  64 Ivl=2ms
E:  Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms
I:* If#=19 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan
E:  Ad=87(I) Atr=03(Int.) MxPS=  64 Ivl=2ms
E:  Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms
I:* If#=20 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=89(I) Atr=03(Int.) MxPS=  64 Ivl=2ms
E:  Ad=8a(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=4ms

Instead of class/subclass/protocol the vendor use fixed
interface numbers for each function, and the Windows
drivers use these numbers to match driver and function.

The driver has had its own interface number whitelisting
code to simulate this functionality.  Replace this with
generic interface number matching now that the USB subsystem
support is there. This
 - removes the need for a driver_info structure per
   interface number,
 - avoids running the probe function for unsupported
   interfaces, and
 - simplifies the code.
Signed-off-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6556bfde
...@@ -247,30 +247,12 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -247,30 +247,12 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
*/ */
static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf) static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
{ {
int rv;
struct qmi_wwan_state *info = (void *)&dev->data; struct qmi_wwan_state *info = (void *)&dev->data;
/* ZTE makes devices where the interface descriptors and endpoint
* configurations of two or more interfaces are identical, even
* though the functions are completely different. If set, then
* driver_info->data is a bitmap of acceptable interface numbers
* allowing us to bind to one such interface without binding to
* all of them
*/
if (dev->driver_info->data &&
!test_bit(intf->cur_altsetting->desc.bInterfaceNumber, &dev->driver_info->data)) {
dev_info(&intf->dev, "not on our whitelist - ignored");
rv = -ENODEV;
goto err;
}
/* control and data is shared */ /* control and data is shared */
info->control = intf; info->control = intf;
info->data = intf; info->data = intf;
rv = qmi_wwan_register_subdriver(dev); return qmi_wwan_register_subdriver(dev);
err:
return rv;
} }
static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf) static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf)
...@@ -356,86 +338,23 @@ static const struct driver_info qmi_wwan_shared = { ...@@ -356,86 +338,23 @@ static const struct driver_info qmi_wwan_shared = {
.manage_power = qmi_wwan_manage_power, .manage_power = qmi_wwan_manage_power,
}; };
static const struct driver_info qmi_wwan_force_int0 = {
.description = "Qualcomm WWAN/QMI device",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind_shared,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
.data = BIT(0), /* interface whitelist bitmap */
};
static const struct driver_info qmi_wwan_force_int1 = {
.description = "Qualcomm WWAN/QMI device",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind_shared,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
.data = BIT(1), /* interface whitelist bitmap */
};
static const struct driver_info qmi_wwan_force_int2 = {
.description = "Qualcomm WWAN/QMI device",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind_shared,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
.data = BIT(2), /* interface whitelist bitmap */
};
static const struct driver_info qmi_wwan_force_int3 = {
.description = "Qualcomm WWAN/QMI device",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind_shared,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
.data = BIT(3), /* interface whitelist bitmap */
};
static const struct driver_info qmi_wwan_force_int4 = {
.description = "Qualcomm WWAN/QMI device",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind_shared,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
.data = BIT(4), /* interface whitelist bitmap */
};
/* Sierra Wireless provide equally useless interface descriptors
* Devices in QMI mode can be switched between two different
* configurations:
* a) USB interface #8 is QMI/wwan
* b) USB interfaces #8, #19 and #20 are QMI/wwan
*
* Both configurations provide a number of other interfaces (serial++),
* some of which have the same endpoint configuration as we expect, so
* a whitelist or blacklist is necessary.
*
* FIXME: The below whitelist should include BIT(20). It does not
* because I cannot get it to work...
*/
static const struct driver_info qmi_wwan_sierra = {
.description = "Sierra Wireless wwan/QMI device",
.flags = FLAG_WWAN,
.bind = qmi_wwan_bind_shared,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
.data = BIT(8) | BIT(19), /* interface whitelist bitmap */
};
#define HUAWEI_VENDOR_ID 0x12D1 #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
/* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */
#define QMI_GOBI1K_DEVICE(vend, prod) \ #define QMI_GOBI1K_DEVICE(vend, prod) \
USB_DEVICE(vend, prod), \ QMI_FIXED_INTF(vend, prod, 3)
.driver_info = (unsigned long)&qmi_wwan_force_int3
/* Gobi 2000 and Gobi 3000 QMI/wwan interface number is 0 according to qcserial */ /* Gobi 2000/3000 QMI/wwan interface number is 0 according to qcserial */
#define QMI_GOBI_DEVICE(vend, prod) \ #define QMI_GOBI_DEVICE(vend, prod) \
USB_DEVICE(vend, prod), \ QMI_FIXED_INTF(vend, prod, 0)
.driver_info = (unsigned long)&qmi_wwan_force_int0
static const struct usb_device_id products[] = { static const struct usb_device_id products[] = {
/* 1. CDC ECM like devices match on the control interface */
{ /* Huawei E392, E398 and possibly others sharing both device id and more... */ { /* Huawei E392, E398 and possibly others sharing both device id and more... */
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = HUAWEI_VENDOR_ID, .idVendor = HUAWEI_VENDOR_ID,
...@@ -452,10 +371,9 @@ static const struct usb_device_id products[] = { ...@@ -452,10 +371,9 @@ static const struct usb_device_id products[] = {
.bInterfaceProtocol = 57, /* CDC Ethernet *control* interface */ .bInterfaceProtocol = 57, /* CDC Ethernet *control* interface */
.driver_info = (unsigned long)&qmi_wwan_info, .driver_info = (unsigned long)&qmi_wwan_info,
}, },
{ /* Huawei E392, E398 and possibly others in "Windows mode"
* using a combined control and data interface without any CDC /* 2. Combined interface devices matching on class+protocol */
* functional descriptors { /* Huawei E392, E398 and possibly others in "Windows mode" */
*/
.match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = HUAWEI_VENDOR_ID, .idVendor = HUAWEI_VENDOR_ID,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
...@@ -472,98 +390,21 @@ static const struct usb_device_id products[] = { ...@@ -472,98 +390,21 @@ static const struct usb_device_id products[] = {
.bInterfaceProtocol = 0xff, .bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_shared, .driver_info = (unsigned long)&qmi_wwan_shared,
}, },
{ /* ZTE MF820D */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x0167,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
{ /* ZTE MF821D */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x0326,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
{ /* ZTE (Vodafone) K3520-Z */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x0055,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int1,
},
{ /* ZTE (Vodafone) K3565-Z */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x0063,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
{ /* ZTE (Vodafone) K3570-Z */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x1008,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
{ /* ZTE (Vodafone) K3571-Z */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x1010,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
{ /* ZTE (Vodafone) K3765-Z */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x2002,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
{ /* ZTE (Vodafone) K4505-Z */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x0104,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int4,
},
{ /* ZTE MF60 */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x19d2,
.idProduct = 0x1402,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_force_int2,
},
{ /* Sierra Wireless MC77xx in QMI mode */
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x1199,
.idProduct = 0x68a2,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0xff,
.bInterfaceProtocol = 0xff,
.driver_info = (unsigned long)&qmi_wwan_sierra,
},
/* Gobi 1000 devices */ /* 3. Combined interface devices matching on interface number */
{QMI_FIXED_INTF(0x19d2, 0x0055, 1)}, /* ZTE (Vodafone) K3520-Z */
{QMI_FIXED_INTF(0x19d2, 0x0063, 4)}, /* ZTE (Vodafone) K3565-Z */
{QMI_FIXED_INTF(0x19d2, 0x0104, 4)}, /* ZTE (Vodafone) K4505-Z */
{QMI_FIXED_INTF(0x19d2, 0x0167, 4)}, /* ZTE MF820D */
{QMI_FIXED_INTF(0x19d2, 0x0326, 4)}, /* ZTE MF821D */
{QMI_FIXED_INTF(0x19d2, 0x1008, 4)}, /* ZTE (Vodafone) K3570-Z */
{QMI_FIXED_INTF(0x19d2, 0x1010, 4)}, /* ZTE (Vodafone) K3571-Z */
{QMI_FIXED_INTF(0x19d2, 0x1402, 2)}, /* ZTE MF60 */
{QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */
{QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */
{QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
{QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */
{QMI_GOBI1K_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ {QMI_GOBI1K_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */
...@@ -579,7 +420,7 @@ static const struct usb_device_id products[] = { ...@@ -579,7 +420,7 @@ static const struct usb_device_id products[] = {
{QMI_GOBI1K_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */
/* Gobi 2000 and 3000 devices */ /* 5. Gobi 2000 and 3000 devices */
{QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ {QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */
{QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ {QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */
{QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ {QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment