diff options
| author | Oliver Neukum <oneukum@suse.com> | 2016-07-14 09:41:31 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-07-18 11:46:57 -0400 |
| commit | eccf2a4e6b64d249929acc1f7aaa2ab0fb199d3d (patch) | |
| tree | d1beb391ff7e779b4591a3347a14e5bdf625e904 /drivers | |
| parent | e4c6fb779498243ec001c5547b3504fe6b1993ec (diff) | |
cdc-acm: use the common parser
This introduces the common parser for extra CDC headers now that it no longer
depends on usbnet.
Signed-off-by: Oliver Neukum <ONeukum@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 69 |
1 files changed, 10 insertions, 59 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index def5a54558b0..561baed7ba01 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -1147,6 +1147,7 @@ static int acm_probe(struct usb_interface *intf, | |||
| 1147 | { | 1147 | { |
| 1148 | struct usb_cdc_union_desc *union_header = NULL; | 1148 | struct usb_cdc_union_desc *union_header = NULL; |
| 1149 | struct usb_cdc_country_functional_desc *cfd = NULL; | 1149 | struct usb_cdc_country_functional_desc *cfd = NULL; |
| 1150 | struct usb_cdc_call_mgmt_descriptor *cmd = NULL; | ||
| 1150 | unsigned char *buffer = intf->altsetting->extra; | 1151 | unsigned char *buffer = intf->altsetting->extra; |
| 1151 | int buflen = intf->altsetting->extralen; | 1152 | int buflen = intf->altsetting->extralen; |
| 1152 | struct usb_interface *control_interface; | 1153 | struct usb_interface *control_interface; |
| @@ -1155,18 +1156,16 @@ static int acm_probe(struct usb_interface *intf, | |||
| 1155 | struct usb_endpoint_descriptor *epread = NULL; | 1156 | struct usb_endpoint_descriptor *epread = NULL; |
| 1156 | struct usb_endpoint_descriptor *epwrite = NULL; | 1157 | struct usb_endpoint_descriptor *epwrite = NULL; |
| 1157 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1158 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
| 1159 | struct usb_cdc_parsed_header hdr; | ||
| 1158 | struct acm *acm; | 1160 | struct acm *acm; |
| 1159 | int minor; | 1161 | int minor; |
| 1160 | int ctrlsize, readsize; | 1162 | int ctrlsize, readsize; |
| 1161 | u8 *buf; | 1163 | u8 *buf; |
| 1162 | u8 ac_management_function = 0; | ||
| 1163 | u8 call_management_function = 0; | ||
| 1164 | int call_interface_num = -1; | 1164 | int call_interface_num = -1; |
| 1165 | int data_interface_num = -1; | 1165 | int data_interface_num = -1; |
| 1166 | unsigned long quirks; | 1166 | unsigned long quirks; |
| 1167 | int num_rx_buf; | 1167 | int num_rx_buf; |
| 1168 | int i; | 1168 | int i; |
| 1169 | unsigned int elength = 0; | ||
| 1170 | int combined_interfaces = 0; | 1169 | int combined_interfaces = 0; |
| 1171 | struct device *tty_dev; | 1170 | struct device *tty_dev; |
| 1172 | int rv = -ENOMEM; | 1171 | int rv = -ENOMEM; |
| @@ -1210,61 +1209,11 @@ static int acm_probe(struct usb_interface *intf, | |||
| 1210 | } | 1209 | } |
| 1211 | } | 1210 | } |
| 1212 | 1211 | ||
| 1213 | while (buflen > 0) { | 1212 | cdc_parse_cdc_header(&hdr, intf, buffer, buflen); |
| 1214 | elength = buffer[0]; | 1213 | union_header = hdr.usb_cdc_union_desc; |
| 1215 | if (!elength) { | 1214 | cmd = hdr.usb_cdc_call_mgmt_descriptor; |
| 1216 | dev_err(&intf->dev, "skipping garbage byte\n"); | 1215 | if (cmd) |
| 1217 | elength = 1; | 1216 | call_interface_num = cmd->bDataInterface; |
| 1218 | goto next_desc; | ||
| 1219 | } | ||
| 1220 | if (buffer[1] != USB_DT_CS_INTERFACE) { | ||
| 1221 | dev_err(&intf->dev, "skipping garbage\n"); | ||
| 1222 | goto next_desc; | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | switch (buffer[2]) { | ||
| 1226 | case USB_CDC_UNION_TYPE: /* we've found it */ | ||
| 1227 | if (elength < sizeof(struct usb_cdc_union_desc)) | ||
| 1228 | goto next_desc; | ||
| 1229 | if (union_header) { | ||
| 1230 | dev_err(&intf->dev, "More than one " | ||
| 1231 | "union descriptor, skipping ...\n"); | ||
| 1232 | goto next_desc; | ||
| 1233 | } | ||
| 1234 | union_header = (struct usb_cdc_union_desc *)buffer; | ||
| 1235 | break; | ||
| 1236 | case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ | ||
| 1237 | if (elength < sizeof(struct usb_cdc_country_functional_desc)) | ||
| 1238 | goto next_desc; | ||
| 1239 | cfd = (struct usb_cdc_country_functional_desc *)buffer; | ||
| 1240 | break; | ||
| 1241 | case USB_CDC_HEADER_TYPE: /* maybe check version */ | ||
| 1242 | break; /* for now we ignore it */ | ||
| 1243 | case USB_CDC_ACM_TYPE: | ||
| 1244 | if (elength < 4) | ||
| 1245 | goto next_desc; | ||
| 1246 | ac_management_function = buffer[3]; | ||
| 1247 | break; | ||
| 1248 | case USB_CDC_CALL_MANAGEMENT_TYPE: | ||
| 1249 | if (elength < 5) | ||
| 1250 | goto next_desc; | ||
| 1251 | call_management_function = buffer[3]; | ||
| 1252 | call_interface_num = buffer[4]; | ||
| 1253 | break; | ||
| 1254 | default: | ||
| 1255 | /* | ||
| 1256 | * there are LOTS more CDC descriptors that | ||
| 1257 | * could legitimately be found here. | ||
| 1258 | */ | ||
| 1259 | dev_dbg(&intf->dev, "Ignoring descriptor: " | ||
| 1260 | "type %02x, length %ud\n", | ||
| 1261 | buffer[2], elength); | ||
| 1262 | break; | ||
| 1263 | } | ||
| 1264 | next_desc: | ||
| 1265 | buflen -= elength; | ||
| 1266 | buffer += elength; | ||
| 1267 | } | ||
| 1268 | 1217 | ||
| 1269 | if (!union_header) { | 1218 | if (!union_header) { |
| 1270 | if (call_interface_num > 0) { | 1219 | if (call_interface_num > 0) { |
| @@ -1394,7 +1343,8 @@ made_compressed_probe: | |||
| 1394 | acm->data = data_interface; | 1343 | acm->data = data_interface; |
| 1395 | acm->minor = minor; | 1344 | acm->minor = minor; |
| 1396 | acm->dev = usb_dev; | 1345 | acm->dev = usb_dev; |
| 1397 | acm->ctrl_caps = ac_management_function; | 1346 | if (hdr.usb_cdc_acm_descriptor) |
| 1347 | acm->ctrl_caps = hdr.usb_cdc_acm_descriptor->bmCapabilities; | ||
| 1398 | if (quirks & NO_CAP_LINE) | 1348 | if (quirks & NO_CAP_LINE) |
| 1399 | acm->ctrl_caps &= ~USB_CDC_CAP_LINE; | 1349 | acm->ctrl_caps &= ~USB_CDC_CAP_LINE; |
| 1400 | acm->ctrlsize = ctrlsize; | 1350 | acm->ctrlsize = ctrlsize; |
| @@ -1488,6 +1438,7 @@ made_compressed_probe: | |||
| 1488 | if (i < 0) | 1438 | if (i < 0) |
| 1489 | goto alloc_fail7; | 1439 | goto alloc_fail7; |
| 1490 | 1440 | ||
| 1441 | cfd = hdr.usb_cdc_country_functional_desc; | ||
| 1491 | if (cfd) { /* export the country data */ | 1442 | if (cfd) { /* export the country data */ |
| 1492 | acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); | 1443 | acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); |
| 1493 | if (!acm->country_codes) | 1444 | if (!acm->country_codes) |
