diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 138 |
1 files changed, 125 insertions, 13 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index dac7676ce21..a06f2cdc610 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -155,7 +155,6 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb) | |||
155 | wb->urb->transfer_dma = wb->dmah; | 155 | wb->urb->transfer_dma = wb->dmah; |
156 | wb->urb->transfer_buffer_length = wb->len; | 156 | wb->urb->transfer_buffer_length = wb->len; |
157 | wb->urb->dev = acm->dev; | 157 | wb->urb->dev = acm->dev; |
158 | |||
159 | rc = usb_submit_urb(wb->urb, GFP_ATOMIC); | 158 | rc = usb_submit_urb(wb->urb, GFP_ATOMIC); |
160 | if (rc < 0) { | 159 | if (rc < 0) { |
161 | dev_err(&acm->data->dev, | 160 | dev_err(&acm->data->dev, |
@@ -171,6 +170,9 @@ static int acm_write_start(struct acm *acm, int wbn) | |||
171 | unsigned long flags; | 170 | unsigned long flags; |
172 | struct acm_wb *wb = &acm->wb[wbn]; | 171 | struct acm_wb *wb = &acm->wb[wbn]; |
173 | int rc; | 172 | int rc; |
173 | #ifdef CONFIG_PM | ||
174 | struct urb *res; | ||
175 | #endif | ||
174 | 176 | ||
175 | spin_lock_irqsave(&acm->write_lock, flags); | 177 | spin_lock_irqsave(&acm->write_lock, flags); |
176 | if (!acm->dev) { | 178 | if (!acm->dev) { |
@@ -183,15 +185,33 @@ static int acm_write_start(struct acm *acm, int wbn) | |||
183 | acm->susp_count); | 185 | acm->susp_count); |
184 | usb_autopm_get_interface_async(acm->control); | 186 | usb_autopm_get_interface_async(acm->control); |
185 | if (acm->susp_count) { | 187 | if (acm->susp_count) { |
188 | #ifdef CONFIG_PM | ||
189 | acm->transmitting++; | ||
190 | wb->urb->transfer_buffer = wb->buf; | ||
191 | wb->urb->transfer_dma = wb->dmah; | ||
192 | wb->urb->transfer_buffer_length = wb->len; | ||
193 | wb->urb->dev = acm->dev; | ||
194 | usb_anchor_urb(wb->urb, &acm->deferred); | ||
195 | #else | ||
186 | if (!acm->delayed_wb) | 196 | if (!acm->delayed_wb) |
187 | acm->delayed_wb = wb; | 197 | acm->delayed_wb = wb; |
188 | else | 198 | else |
189 | usb_autopm_put_interface_async(acm->control); | 199 | usb_autopm_put_interface_async(acm->control); |
200 | #endif | ||
190 | spin_unlock_irqrestore(&acm->write_lock, flags); | 201 | spin_unlock_irqrestore(&acm->write_lock, flags); |
191 | return 0; /* A white lie */ | 202 | return 0; /* A white lie */ |
192 | } | 203 | } |
193 | usb_mark_last_busy(acm->dev); | 204 | usb_mark_last_busy(acm->dev); |
194 | 205 | #ifdef CONFIG_PM | |
206 | while ((res = usb_get_from_anchor(&acm->deferred))) { | ||
207 | rc = usb_submit_urb(res, GFP_ATOMIC); | ||
208 | if (rc < 0) { | ||
209 | dbg("usb_submit_urb(pending request) failed: %d", rc); | ||
210 | usb_unanchor_urb(res); | ||
211 | acm_write_done(acm, res->context); | ||
212 | } | ||
213 | } | ||
214 | #endif | ||
195 | rc = acm_start_wb(acm, wb); | 215 | rc = acm_start_wb(acm, wb); |
196 | spin_unlock_irqrestore(&acm->write_lock, flags); | 216 | spin_unlock_irqrestore(&acm->write_lock, flags); |
197 | 217 | ||
@@ -476,7 +496,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
476 | if (usb_autopm_get_interface(acm->control) < 0) | 496 | if (usb_autopm_get_interface(acm->control) < 0) |
477 | goto early_bail; | 497 | goto early_bail; |
478 | else | 498 | else |
479 | acm->control->needs_remote_wakeup = 1; | 499 | acm->control->needs_remote_wakeup = 0; |
480 | 500 | ||
481 | mutex_lock(&acm->mutex); | 501 | mutex_lock(&acm->mutex); |
482 | if (acm->port.count++) { | 502 | if (acm->port.count++) { |
@@ -539,7 +559,6 @@ static void acm_port_down(struct acm *acm) | |||
539 | { | 559 | { |
540 | int i; | 560 | int i; |
541 | 561 | ||
542 | mutex_lock(&open_mutex); | ||
543 | if (acm->dev) { | 562 | if (acm->dev) { |
544 | usb_autopm_get_interface(acm->control); | 563 | usb_autopm_get_interface(acm->control); |
545 | acm_set_control(acm, acm->ctrlout = 0); | 564 | acm_set_control(acm, acm->ctrlout = 0); |
@@ -551,14 +570,23 @@ static void acm_port_down(struct acm *acm) | |||
551 | acm->control->needs_remote_wakeup = 0; | 570 | acm->control->needs_remote_wakeup = 0; |
552 | usb_autopm_put_interface(acm->control); | 571 | usb_autopm_put_interface(acm->control); |
553 | } | 572 | } |
554 | mutex_unlock(&open_mutex); | ||
555 | } | 573 | } |
556 | 574 | ||
557 | static void acm_tty_hangup(struct tty_struct *tty) | 575 | static void acm_tty_hangup(struct tty_struct *tty) |
558 | { | 576 | { |
559 | struct acm *acm = tty->driver_data; | 577 | struct acm *acm; |
578 | |||
579 | mutex_lock(&open_mutex); | ||
580 | acm = tty->driver_data; | ||
581 | |||
582 | if (!acm) | ||
583 | goto out; | ||
584 | |||
560 | tty_port_hangup(&acm->port); | 585 | tty_port_hangup(&acm->port); |
561 | acm_port_down(acm); | 586 | acm_port_down(acm); |
587 | |||
588 | out: | ||
589 | mutex_unlock(&open_mutex); | ||
562 | } | 590 | } |
563 | 591 | ||
564 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 592 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
@@ -569,8 +597,9 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) | |||
569 | shutdown */ | 597 | shutdown */ |
570 | if (!acm) | 598 | if (!acm) |
571 | return; | 599 | return; |
600 | |||
601 | mutex_lock(&open_mutex); | ||
572 | if (tty_port_close_start(&acm->port, tty, filp) == 0) { | 602 | if (tty_port_close_start(&acm->port, tty, filp) == 0) { |
573 | mutex_lock(&open_mutex); | ||
574 | if (!acm->dev) { | 603 | if (!acm->dev) { |
575 | tty_port_tty_set(&acm->port, NULL); | 604 | tty_port_tty_set(&acm->port, NULL); |
576 | acm_tty_unregister(acm); | 605 | acm_tty_unregister(acm); |
@@ -582,6 +611,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) | |||
582 | acm_port_down(acm); | 611 | acm_port_down(acm); |
583 | tty_port_close_end(&acm->port, tty); | 612 | tty_port_close_end(&acm->port, tty); |
584 | tty_port_tty_set(&acm->port, NULL); | 613 | tty_port_tty_set(&acm->port, NULL); |
614 | mutex_unlock(&open_mutex); | ||
585 | } | 615 | } |
586 | 616 | ||
587 | static int acm_tty_write(struct tty_struct *tty, | 617 | static int acm_tty_write(struct tty_struct *tty, |
@@ -863,8 +893,12 @@ static int acm_probe(struct usb_interface *intf, | |||
863 | quirks = (unsigned long)id->driver_info; | 893 | quirks = (unsigned long)id->driver_info; |
864 | num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; | 894 | num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; |
865 | 895 | ||
896 | /* not a real CDC ACM device */ | ||
897 | if (quirks & NOT_REAL_ACM) | ||
898 | return -ENODEV; | ||
899 | |||
866 | /* handle quirks deadly to normal probing*/ | 900 | /* handle quirks deadly to normal probing*/ |
867 | if (quirks == NO_UNION_NORMAL) { | 901 | if (quirks & NO_UNION_NORMAL) { |
868 | data_interface = usb_ifnum_to_if(usb_dev, 1); | 902 | data_interface = usb_ifnum_to_if(usb_dev, 1); |
869 | control_interface = usb_ifnum_to_if(usb_dev, 0); | 903 | control_interface = usb_ifnum_to_if(usb_dev, 0); |
870 | goto skip_normal_probe; | 904 | goto skip_normal_probe; |
@@ -1074,6 +1108,7 @@ made_compressed_probe: | |||
1074 | acm->readsize = readsize; | 1108 | acm->readsize = readsize; |
1075 | acm->rx_buflimit = num_rx_buf; | 1109 | acm->rx_buflimit = num_rx_buf; |
1076 | INIT_WORK(&acm->work, acm_softint); | 1110 | INIT_WORK(&acm->work, acm_softint); |
1111 | init_usb_anchor(&acm->deferred); | ||
1077 | spin_lock_init(&acm->write_lock); | 1112 | spin_lock_init(&acm->write_lock); |
1078 | spin_lock_init(&acm->read_lock); | 1113 | spin_lock_init(&acm->read_lock); |
1079 | mutex_init(&acm->mutex); | 1114 | mutex_init(&acm->mutex); |
@@ -1081,6 +1116,8 @@ made_compressed_probe: | |||
1081 | acm->is_int_ep = usb_endpoint_xfer_int(epread); | 1116 | acm->is_int_ep = usb_endpoint_xfer_int(epread); |
1082 | if (acm->is_int_ep) | 1117 | if (acm->is_int_ep) |
1083 | acm->bInterval = epread->bInterval; | 1118 | acm->bInterval = epread->bInterval; |
1119 | if (quirks & NO_HANGUP_IN_RESET_RESUME) | ||
1120 | acm->no_hangup_in_reset_resume = 1; | ||
1084 | tty_port_init(&acm->port); | 1121 | tty_port_init(&acm->port); |
1085 | acm->port.ops = &acm_port_ops; | 1122 | acm->port.ops = &acm_port_ops; |
1086 | 1123 | ||
@@ -1181,6 +1218,8 @@ made_compressed_probe: | |||
1181 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); | 1218 | i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); |
1182 | if (i < 0) { | 1219 | if (i < 0) { |
1183 | kfree(acm->country_codes); | 1220 | kfree(acm->country_codes); |
1221 | acm->country_codes = NULL; | ||
1222 | acm->country_code_size = 0; | ||
1184 | goto skip_countries; | 1223 | goto skip_countries; |
1185 | } | 1224 | } |
1186 | 1225 | ||
@@ -1189,6 +1228,8 @@ made_compressed_probe: | |||
1189 | if (i < 0) { | 1228 | if (i < 0) { |
1190 | device_remove_file(&intf->dev, &dev_attr_wCountryCodes); | 1229 | device_remove_file(&intf->dev, &dev_attr_wCountryCodes); |
1191 | kfree(acm->country_codes); | 1230 | kfree(acm->country_codes); |
1231 | acm->country_codes = NULL; | ||
1232 | acm->country_code_size = 0; | ||
1192 | goto skip_countries; | 1233 | goto skip_countries; |
1193 | } | 1234 | } |
1194 | } | 1235 | } |
@@ -1241,6 +1282,11 @@ static void stop_data_traffic(struct acm *acm) | |||
1241 | { | 1282 | { |
1242 | int i; | 1283 | int i; |
1243 | 1284 | ||
1285 | if (!acm) { | ||
1286 | pr_err("%s: !acm\n", __func__); | ||
1287 | return; | ||
1288 | } | ||
1289 | |||
1244 | dev_dbg(&acm->control->dev, "%s\n", __func__); | 1290 | dev_dbg(&acm->control->dev, "%s\n", __func__); |
1245 | 1291 | ||
1246 | usb_kill_urb(acm->ctrlurb); | 1292 | usb_kill_urb(acm->ctrlurb); |
@@ -1276,6 +1322,7 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1276 | 1322 | ||
1277 | stop_data_traffic(acm); | 1323 | stop_data_traffic(acm); |
1278 | 1324 | ||
1325 | usb_kill_anchored_urbs(&acm->deferred); | ||
1279 | acm_write_buffers_free(acm); | 1326 | acm_write_buffers_free(acm); |
1280 | usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, | 1327 | usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, |
1281 | acm->ctrl_dma); | 1328 | acm->ctrl_dma); |
@@ -1305,6 +1352,11 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) | |||
1305 | struct acm *acm = usb_get_intfdata(intf); | 1352 | struct acm *acm = usb_get_intfdata(intf); |
1306 | int cnt; | 1353 | int cnt; |
1307 | 1354 | ||
1355 | if (!acm) { | ||
1356 | pr_err("%s: !acm\n", __func__); | ||
1357 | return -ENODEV; | ||
1358 | } | ||
1359 | |||
1308 | if (message.event & PM_EVENT_AUTO) { | 1360 | if (message.event & PM_EVENT_AUTO) { |
1309 | int b; | 1361 | int b; |
1310 | 1362 | ||
@@ -1339,23 +1391,50 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) | |||
1339 | static int acm_resume(struct usb_interface *intf) | 1391 | static int acm_resume(struct usb_interface *intf) |
1340 | { | 1392 | { |
1341 | struct acm *acm = usb_get_intfdata(intf); | 1393 | struct acm *acm = usb_get_intfdata(intf); |
1342 | struct acm_wb *wb; | ||
1343 | int rv = 0; | 1394 | int rv = 0; |
1344 | int cnt; | 1395 | int cnt; |
1396 | #ifdef CONFIG_PM | ||
1397 | struct urb *res; | ||
1398 | #else | ||
1399 | struct acm_wb *wb; | ||
1400 | #endif | ||
1401 | |||
1402 | if (!acm) { | ||
1403 | pr_err("%s: !acm\n", __func__); | ||
1404 | return -ENODEV; | ||
1405 | } | ||
1345 | 1406 | ||
1346 | spin_lock_irq(&acm->read_lock); | 1407 | spin_lock_irq(&acm->read_lock); |
1347 | acm->susp_count -= 1; | 1408 | if (acm->susp_count > 0) { |
1348 | cnt = acm->susp_count; | 1409 | acm->susp_count -= 1; |
1410 | cnt = acm->susp_count; | ||
1411 | } else { | ||
1412 | spin_unlock_irq(&acm->read_lock); | ||
1413 | return 0; | ||
1414 | } | ||
1349 | spin_unlock_irq(&acm->read_lock); | 1415 | spin_unlock_irq(&acm->read_lock); |
1350 | 1416 | ||
1351 | if (cnt) | 1417 | if (cnt) |
1352 | return 0; | 1418 | return 0; |
1353 | 1419 | ||
1420 | |||
1354 | mutex_lock(&acm->mutex); | 1421 | mutex_lock(&acm->mutex); |
1422 | |||
1355 | if (acm->port.count) { | 1423 | if (acm->port.count) { |
1356 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); | 1424 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); |
1357 | |||
1358 | spin_lock_irq(&acm->write_lock); | 1425 | spin_lock_irq(&acm->write_lock); |
1426 | #ifdef CONFIG_PM | ||
1427 | while ((res = usb_get_from_anchor(&acm->deferred))) { | ||
1428 | rv = usb_submit_urb(res, GFP_ATOMIC); | ||
1429 | if (rv < 0) { | ||
1430 | dbg("usb_submit_urb(pending request)" | ||
1431 | " failed: %d", rv); | ||
1432 | usb_unanchor_urb(res); | ||
1433 | acm_write_done(acm, res->context); | ||
1434 | } | ||
1435 | } | ||
1436 | spin_unlock_irq(&acm->write_lock); | ||
1437 | #else | ||
1359 | if (acm->delayed_wb) { | 1438 | if (acm->delayed_wb) { |
1360 | wb = acm->delayed_wb; | 1439 | wb = acm->delayed_wb; |
1361 | acm->delayed_wb = NULL; | 1440 | acm->delayed_wb = NULL; |
@@ -1364,6 +1443,7 @@ static int acm_resume(struct usb_interface *intf) | |||
1364 | } else { | 1443 | } else { |
1365 | spin_unlock_irq(&acm->write_lock); | 1444 | spin_unlock_irq(&acm->write_lock); |
1366 | } | 1445 | } |
1446 | #endif | ||
1367 | 1447 | ||
1368 | /* | 1448 | /* |
1369 | * delayed error checking because we must | 1449 | * delayed error checking because we must |
@@ -1385,11 +1465,17 @@ static int acm_reset_resume(struct usb_interface *intf) | |||
1385 | struct acm *acm = usb_get_intfdata(intf); | 1465 | struct acm *acm = usb_get_intfdata(intf); |
1386 | struct tty_struct *tty; | 1466 | struct tty_struct *tty; |
1387 | 1467 | ||
1468 | if (!acm) { | ||
1469 | pr_err("%s: !acm\n", __func__); | ||
1470 | return -ENODEV; | ||
1471 | } | ||
1472 | |||
1388 | mutex_lock(&acm->mutex); | 1473 | mutex_lock(&acm->mutex); |
1389 | if (acm->port.count) { | 1474 | if (acm->port.count) { |
1390 | tty = tty_port_tty_get(&acm->port); | 1475 | tty = tty_port_tty_get(&acm->port); |
1391 | if (tty) { | 1476 | if (tty) { |
1392 | tty_hangup(tty); | 1477 | if (!acm->no_hangup_in_reset_resume) |
1478 | tty_hangup(tty); | ||
1393 | tty_kref_put(tty); | 1479 | tty_kref_put(tty); |
1394 | } | 1480 | } |
1395 | } | 1481 | } |
@@ -1456,6 +1542,16 @@ static const struct usb_device_id acm_ids[] = { | |||
1456 | }, | 1542 | }, |
1457 | { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ | 1543 | { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ |
1458 | }, | 1544 | }, |
1545 | /* Motorola H24 HSPA module: */ | ||
1546 | { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ | ||
1547 | { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ | ||
1548 | { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ | ||
1549 | { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ | ||
1550 | { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ | ||
1551 | { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ | ||
1552 | { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ | ||
1553 | { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ | ||
1554 | |||
1459 | { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ | 1555 | { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ |
1460 | .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on | 1556 | .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on |
1461 | data interface instead of | 1557 | data interface instead of |
@@ -1469,6 +1565,9 @@ static const struct usb_device_id acm_ids[] = { | |||
1469 | { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */ | 1565 | { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */ |
1470 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ | 1566 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ |
1471 | }, | 1567 | }, |
1568 | { USB_DEVICE(0x1519, 0x0020), | ||
1569 | .driver_info = NO_UNION_NORMAL | NO_HANGUP_IN_RESET_RESUME, /* has no union descriptor */ | ||
1570 | }, | ||
1472 | 1571 | ||
1473 | /* Nokia S60 phones expose two ACM channels. The first is | 1572 | /* Nokia S60 phones expose two ACM channels. The first is |
1474 | * a modem and is picked up by the standard AT-command | 1573 | * a modem and is picked up by the standard AT-command |
@@ -1534,6 +1633,9 @@ static const struct usb_device_id acm_ids[] = { | |||
1534 | { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */ | 1633 | { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */ |
1535 | { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ | 1634 | { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ |
1536 | 1635 | ||
1636 | /* Support for Owen devices */ | ||
1637 | { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */ | ||
1638 | |||
1537 | /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ | 1639 | /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ |
1538 | 1640 | ||
1539 | /* Support Lego NXT using pbLua firmware */ | 1641 | /* Support Lego NXT using pbLua firmware */ |
@@ -1546,6 +1648,16 @@ static const struct usb_device_id acm_ids[] = { | |||
1546 | .driver_info = NO_DATA_INTERFACE, | 1648 | .driver_info = NO_DATA_INTERFACE, |
1547 | }, | 1649 | }, |
1548 | 1650 | ||
1651 | /* Exclude XMM6260 boot rom (not running modem software yet) */ | ||
1652 | { USB_DEVICE(0x058b, 0x0041), | ||
1653 | .driver_info = NOT_REAL_ACM, | ||
1654 | }, | ||
1655 | |||
1656 | /* Icera 450 */ | ||
1657 | { USB_DEVICE(0x1983, 0x0321), | ||
1658 | .driver_info = NO_HANGUP_IN_RESET_RESUME, | ||
1659 | }, | ||
1660 | |||
1549 | /* control interfaces without any protocol set */ | 1661 | /* control interfaces without any protocol set */ |
1550 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1662 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1551 | USB_CDC_PROTO_NONE) }, | 1663 | USB_CDC_PROTO_NONE) }, |