|
@@ -229,11 +229,11 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
|
|
|
u8 *buf = intf->cur_altsetting->extra;
|
|
|
int len = intf->cur_altsetting->extralen;
|
|
|
struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
|
|
|
- struct usb_cdc_union_desc *cdc_union = NULL;
|
|
|
- struct usb_cdc_ether_desc *cdc_ether = NULL;
|
|
|
- u32 found = 0;
|
|
|
+ struct usb_cdc_union_desc *cdc_union;
|
|
|
+ struct usb_cdc_ether_desc *cdc_ether;
|
|
|
struct usb_driver *driver = driver_of(intf);
|
|
|
struct qmi_wwan_state *info = (void *)&dev->data;
|
|
|
+ struct usb_cdc_parsed_header hdr;
|
|
|
|
|
|
BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) <
|
|
|
sizeof(struct qmi_wwan_state)));
|
|
@@ -243,63 +243,9 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
|
|
|
info->data = intf;
|
|
|
|
|
|
/* and a number of CDC descriptors */
|
|
|
- while (len > 3) {
|
|
|
- struct usb_descriptor_header *h = (void *)buf;
|
|
|
-
|
|
|
- /* ignore any misplaced descriptors */
|
|
|
- if (h->bDescriptorType != USB_DT_CS_INTERFACE)
|
|
|
- goto next_desc;
|
|
|
-
|
|
|
- /* buf[2] is CDC descriptor subtype */
|
|
|
- switch (buf[2]) {
|
|
|
- case USB_CDC_HEADER_TYPE:
|
|
|
- if (found & 1 << USB_CDC_HEADER_TYPE) {
|
|
|
- dev_dbg(&intf->dev, "extra CDC header\n");
|
|
|
- goto err;
|
|
|
- }
|
|
|
- if (h->bLength != sizeof(struct usb_cdc_header_desc)) {
|
|
|
- dev_dbg(&intf->dev, "CDC header len %u\n",
|
|
|
- h->bLength);
|
|
|
- goto err;
|
|
|
- }
|
|
|
- break;
|
|
|
- case USB_CDC_UNION_TYPE:
|
|
|
- if (found & 1 << USB_CDC_UNION_TYPE) {
|
|
|
- dev_dbg(&intf->dev, "extra CDC union\n");
|
|
|
- goto err;
|
|
|
- }
|
|
|
- if (h->bLength != sizeof(struct usb_cdc_union_desc)) {
|
|
|
- dev_dbg(&intf->dev, "CDC union len %u\n",
|
|
|
- h->bLength);
|
|
|
- goto err;
|
|
|
- }
|
|
|
- cdc_union = (struct usb_cdc_union_desc *)buf;
|
|
|
- break;
|
|
|
- case USB_CDC_ETHERNET_TYPE:
|
|
|
- if (found & 1 << USB_CDC_ETHERNET_TYPE) {
|
|
|
- dev_dbg(&intf->dev, "extra CDC ether\n");
|
|
|
- goto err;
|
|
|
- }
|
|
|
- if (h->bLength != sizeof(struct usb_cdc_ether_desc)) {
|
|
|
- dev_dbg(&intf->dev, "CDC ether len %u\n",
|
|
|
- h->bLength);
|
|
|
- goto err;
|
|
|
- }
|
|
|
- cdc_ether = (struct usb_cdc_ether_desc *)buf;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- /* Remember which CDC functional descriptors we've seen. Works
|
|
|
- * for all types we care about, of which USB_CDC_ETHERNET_TYPE
|
|
|
- * (0x0f) is the highest numbered
|
|
|
- */
|
|
|
- if (buf[2] < 32)
|
|
|
- found |= 1 << buf[2];
|
|
|
-
|
|
|
-next_desc:
|
|
|
- len -= h->bLength;
|
|
|
- buf += h->bLength;
|
|
|
- }
|
|
|
+ cdc_parse_cdc_header(&hdr, intf, buf, len);
|
|
|
+ cdc_union = hdr.usb_cdc_union_desc;
|
|
|
+ cdc_ether = hdr.usb_cdc_ether_desc;
|
|
|
|
|
|
/* Use separate control and data interfaces if we found a CDC Union */
|
|
|
if (cdc_union) {
|