--- zzzz-none-000/linux-4.4.271/drivers/usb/class/cdc-acm.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/drivers/usb/class/cdc-acm.c 2023-04-19 10:22:29.000000000 +0000 @@ -1097,6 +1097,7 @@ { struct usb_cdc_union_desc *union_header = NULL; struct usb_cdc_country_functional_desc *cfd = NULL; + struct usb_cdc_call_mgmt_descriptor *cmd = NULL; unsigned char *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; struct usb_interface *control_interface; @@ -1105,18 +1106,16 @@ struct usb_endpoint_descriptor *epread = NULL; struct usb_endpoint_descriptor *epwrite = NULL; struct usb_device *usb_dev = interface_to_usbdev(intf); + struct usb_cdc_parsed_header hdr; struct acm *acm; int minor; int ctrlsize, readsize; u8 *buf; - u8 ac_management_function = 0; - u8 call_management_function = 0; int call_interface_num = -1; int data_interface_num = -1; unsigned long quirks; int num_rx_buf; int i; - unsigned int elength = 0; int combined_interfaces = 0; struct device *tty_dev; int rv = -ENOMEM; @@ -1160,61 +1159,11 @@ } } - while (buflen > 0) { - elength = buffer[0]; - if (!elength) { - dev_err(&intf->dev, "skipping garbage byte\n"); - elength = 1; - goto next_desc; - } - if (buffer[1] != USB_DT_CS_INTERFACE) { - dev_err(&intf->dev, "skipping garbage\n"); - goto next_desc; - } - - switch (buffer[2]) { - case USB_CDC_UNION_TYPE: /* we've found it */ - if (elength < sizeof(struct usb_cdc_union_desc)) - goto next_desc; - if (union_header) { - dev_err(&intf->dev, "More than one " - "union descriptor, skipping ...\n"); - goto next_desc; - } - union_header = (struct usb_cdc_union_desc *)buffer; - break; - case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ - if (elength < sizeof(struct usb_cdc_country_functional_desc)) - goto next_desc; - cfd = (struct usb_cdc_country_functional_desc *)buffer; - break; - case USB_CDC_HEADER_TYPE: /* maybe check version */ - break; /* for now we ignore it */ - case USB_CDC_ACM_TYPE: - if (elength < 4) - goto next_desc; - ac_management_function = buffer[3]; - break; - case USB_CDC_CALL_MANAGEMENT_TYPE: - if (elength < 5) - goto next_desc; - call_management_function = buffer[3]; - call_interface_num = buffer[4]; - break; - default: - /* - * there are LOTS more CDC descriptors that - * could legitimately be found here. - */ - dev_dbg(&intf->dev, "Ignoring descriptor: " - "type %02x, length %ud\n", - buffer[2], elength); - break; - } -next_desc: - buflen -= elength; - buffer += elength; - } + cdc_parse_cdc_header(&hdr, intf, buffer, buflen); + union_header = hdr.usb_cdc_union_desc; + cmd = hdr.usb_cdc_call_mgmt_descriptor; + if (cmd) + call_interface_num = cmd->bDataInterface; if (!union_header) { if (call_interface_num > 0) { @@ -1347,7 +1296,8 @@ acm->minor = minor; acm->dev = usb_dev; - acm->ctrl_caps = ac_management_function; + if (hdr.usb_cdc_acm_descriptor) + acm->ctrl_caps = hdr.usb_cdc_acm_descriptor->bmCapabilities; if (quirks & NO_CAP_LINE) acm->ctrl_caps &= ~USB_CDC_CAP_LINE; acm->ctrlsize = ctrlsize; @@ -1440,6 +1390,7 @@ if (i < 0) goto alloc_fail7; + cfd = hdr.usb_cdc_country_functional_desc; if (cfd) { /* export the country data */ acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); if (!acm->country_codes)