diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 85 |
1 files changed, 65 insertions, 20 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 38f85b0e32ab..c653635ce5c2 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -160,17 +160,29 @@ static inline int acm_set_control(struct acm *acm, int control) | |||
160 | #define acm_send_break(acm, ms) \ | 160 | #define acm_send_break(acm, ms) \ |
161 | acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) | 161 | acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) |
162 | 162 | ||
163 | static void acm_kill_urbs(struct acm *acm) | 163 | static void acm_poison_urbs(struct acm *acm) |
164 | { | 164 | { |
165 | int i; | 165 | int i; |
166 | 166 | ||
167 | usb_kill_urb(acm->ctrlurb); | 167 | usb_poison_urb(acm->ctrlurb); |
168 | for (i = 0; i < ACM_NW; i++) | 168 | for (i = 0; i < ACM_NW; i++) |
169 | usb_kill_urb(acm->wb[i].urb); | 169 | usb_poison_urb(acm->wb[i].urb); |
170 | for (i = 0; i < acm->rx_buflimit; i++) | 170 | for (i = 0; i < acm->rx_buflimit; i++) |
171 | usb_kill_urb(acm->read_urbs[i]); | 171 | usb_poison_urb(acm->read_urbs[i]); |
172 | } | ||
173 | |||
174 | static void acm_unpoison_urbs(struct acm *acm) | ||
175 | { | ||
176 | int i; | ||
177 | |||
178 | for (i = 0; i < acm->rx_buflimit; i++) | ||
179 | usb_unpoison_urb(acm->read_urbs[i]); | ||
180 | for (i = 0; i < ACM_NW; i++) | ||
181 | usb_unpoison_urb(acm->wb[i].urb); | ||
182 | usb_unpoison_urb(acm->ctrlurb); | ||
172 | } | 183 | } |
173 | 184 | ||
185 | |||
174 | /* | 186 | /* |
175 | * Write buffer management. | 187 | * Write buffer management. |
176 | * All of these assume proper locks taken by the caller. | 188 | * All of these assume proper locks taken by the caller. |
@@ -238,9 +250,10 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb) | |||
238 | 250 | ||
239 | rc = usb_submit_urb(wb->urb, GFP_ATOMIC); | 251 | rc = usb_submit_urb(wb->urb, GFP_ATOMIC); |
240 | if (rc < 0) { | 252 | if (rc < 0) { |
241 | dev_err(&acm->data->dev, | 253 | if (rc != -EPERM) |
242 | "%s - usb_submit_urb(write bulk) failed: %d\n", | 254 | dev_err(&acm->data->dev, |
243 | __func__, rc); | 255 | "%s - usb_submit_urb(write bulk) failed: %d\n", |
256 | __func__, rc); | ||
244 | acm_write_done(acm, wb); | 257 | acm_write_done(acm, wb); |
245 | } | 258 | } |
246 | return rc; | 259 | return rc; |
@@ -324,8 +337,10 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) | |||
324 | acm->iocount.dsr++; | 337 | acm->iocount.dsr++; |
325 | if (difference & ACM_CTRL_DCD) | 338 | if (difference & ACM_CTRL_DCD) |
326 | acm->iocount.dcd++; | 339 | acm->iocount.dcd++; |
327 | if (newctrl & ACM_CTRL_BRK) | 340 | if (newctrl & ACM_CTRL_BRK) { |
328 | acm->iocount.brk++; | 341 | acm->iocount.brk++; |
342 | tty_insert_flip_char(&acm->port, 0, TTY_BREAK); | ||
343 | } | ||
329 | if (newctrl & ACM_CTRL_RI) | 344 | if (newctrl & ACM_CTRL_RI) |
330 | acm->iocount.rng++; | 345 | acm->iocount.rng++; |
331 | if (newctrl & ACM_CTRL_FRAMING) | 346 | if (newctrl & ACM_CTRL_FRAMING) |
@@ -336,6 +351,9 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) | |||
336 | acm->iocount.overrun++; | 351 | acm->iocount.overrun++; |
337 | spin_unlock(&acm->read_lock); | 352 | spin_unlock(&acm->read_lock); |
338 | 353 | ||
354 | if (newctrl & ACM_CTRL_BRK) | ||
355 | tty_flip_buffer_push(&acm->port); | ||
356 | |||
339 | if (difference) | 357 | if (difference) |
340 | wake_up_all(&acm->wioctl); | 358 | wake_up_all(&acm->wioctl); |
341 | 359 | ||
@@ -471,11 +489,16 @@ static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags) | |||
471 | 489 | ||
472 | static void acm_process_read_urb(struct acm *acm, struct urb *urb) | 490 | static void acm_process_read_urb(struct acm *acm, struct urb *urb) |
473 | { | 491 | { |
492 | unsigned long flags; | ||
493 | |||
474 | if (!urb->actual_length) | 494 | if (!urb->actual_length) |
475 | return; | 495 | return; |
476 | 496 | ||
497 | spin_lock_irqsave(&acm->read_lock, flags); | ||
477 | tty_insert_flip_string(&acm->port, urb->transfer_buffer, | 498 | tty_insert_flip_string(&acm->port, urb->transfer_buffer, |
478 | urb->actual_length); | 499 | urb->actual_length); |
500 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
501 | |||
479 | tty_flip_buffer_push(&acm->port); | 502 | tty_flip_buffer_push(&acm->port); |
480 | } | 503 | } |
481 | 504 | ||
@@ -492,11 +515,6 @@ static void acm_read_bulk_callback(struct urb *urb) | |||
492 | dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n", | 515 | dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n", |
493 | rb->index, urb->actual_length, status); | 516 | rb->index, urb->actual_length, status); |
494 | 517 | ||
495 | if (!acm->dev) { | ||
496 | dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); | ||
497 | return; | ||
498 | } | ||
499 | |||
500 | switch (status) { | 518 | switch (status) { |
501 | case 0: | 519 | case 0: |
502 | usb_mark_last_busy(acm->dev); | 520 | usb_mark_last_busy(acm->dev); |
@@ -666,7 +684,8 @@ static void acm_port_dtr_rts(struct tty_port *port, int raise) | |||
666 | 684 | ||
667 | res = acm_set_control(acm, val); | 685 | res = acm_set_control(acm, val); |
668 | if (res && (acm->ctrl_caps & USB_CDC_CAP_LINE)) | 686 | if (res && (acm->ctrl_caps & USB_CDC_CAP_LINE)) |
669 | dev_err(&acm->control->dev, "failed to set dtr/rts\n"); | 687 | /* This is broken in too many devices to spam the logs */ |
688 | dev_dbg(&acm->control->dev, "failed to set dtr/rts\n"); | ||
670 | } | 689 | } |
671 | 690 | ||
672 | static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) | 691 | static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) |
@@ -751,6 +770,7 @@ static void acm_port_shutdown(struct tty_port *port) | |||
751 | * Need to grab write_lock to prevent race with resume, but no need to | 770 | * Need to grab write_lock to prevent race with resume, but no need to |
752 | * hold it due to the tty-port initialised flag. | 771 | * hold it due to the tty-port initialised flag. |
753 | */ | 772 | */ |
773 | acm_poison_urbs(acm); | ||
754 | spin_lock_irq(&acm->write_lock); | 774 | spin_lock_irq(&acm->write_lock); |
755 | spin_unlock_irq(&acm->write_lock); | 775 | spin_unlock_irq(&acm->write_lock); |
756 | 776 | ||
@@ -767,7 +787,8 @@ static void acm_port_shutdown(struct tty_port *port) | |||
767 | usb_autopm_put_interface_async(acm->control); | 787 | usb_autopm_put_interface_async(acm->control); |
768 | } | 788 | } |
769 | 789 | ||
770 | acm_kill_urbs(acm); | 790 | acm_unpoison_urbs(acm); |
791 | |||
771 | } | 792 | } |
772 | 793 | ||
773 | static void acm_tty_cleanup(struct tty_struct *tty) | 794 | static void acm_tty_cleanup(struct tty_struct *tty) |
@@ -986,8 +1007,6 @@ static int set_serial_info(struct acm *acm, | |||
986 | if ((new_serial.close_delay != old_close_delay) || | 1007 | if ((new_serial.close_delay != old_close_delay) || |
987 | (new_serial.closing_wait != old_closing_wait)) | 1008 | (new_serial.closing_wait != old_closing_wait)) |
988 | retval = -EPERM; | 1009 | retval = -EPERM; |
989 | else | ||
990 | retval = -EOPNOTSUPP; | ||
991 | } else { | 1010 | } else { |
992 | acm->port.close_delay = close_delay; | 1011 | acm->port.close_delay = close_delay; |
993 | acm->port.closing_wait = closing_wait; | 1012 | acm->port.closing_wait = closing_wait; |
@@ -1559,6 +1578,11 @@ skip_countries: | |||
1559 | 1578 | ||
1560 | return 0; | 1579 | return 0; |
1561 | alloc_fail8: | 1580 | alloc_fail8: |
1581 | if (!acm->combined_interfaces) { | ||
1582 | /* Clear driver data so that disconnect() returns early. */ | ||
1583 | usb_set_intfdata(data_interface, NULL); | ||
1584 | usb_driver_release_interface(&acm_driver, data_interface); | ||
1585 | } | ||
1562 | if (acm->country_codes) { | 1586 | if (acm->country_codes) { |
1563 | device_remove_file(&acm->control->dev, | 1587 | device_remove_file(&acm->control->dev, |
1564 | &dev_attr_wCountryCodes); | 1588 | &dev_attr_wCountryCodes); |
@@ -1598,8 +1622,14 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1598 | if (!acm) | 1622 | if (!acm) |
1599 | return; | 1623 | return; |
1600 | 1624 | ||
1601 | mutex_lock(&acm->mutex); | ||
1602 | acm->disconnected = true; | 1625 | acm->disconnected = true; |
1626 | /* | ||
1627 | * there is a circular dependency. acm_softint() can resubmit | ||
1628 | * the URBs in error handling so we need to block any | ||
1629 | * submission right away | ||
1630 | */ | ||
1631 | acm_poison_urbs(acm); | ||
1632 | mutex_lock(&acm->mutex); | ||
1603 | if (acm->country_codes) { | 1633 | if (acm->country_codes) { |
1604 | device_remove_file(&acm->control->dev, | 1634 | device_remove_file(&acm->control->dev, |
1605 | &dev_attr_wCountryCodes); | 1635 | &dev_attr_wCountryCodes); |
@@ -1618,7 +1648,6 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1618 | tty_kref_put(tty); | 1648 | tty_kref_put(tty); |
1619 | } | 1649 | } |
1620 | 1650 | ||
1621 | acm_kill_urbs(acm); | ||
1622 | cancel_delayed_work_sync(&acm->dwork); | 1651 | cancel_delayed_work_sync(&acm->dwork); |
1623 | 1652 | ||
1624 | tty_unregister_device(acm_tty_driver, acm->minor); | 1653 | tty_unregister_device(acm_tty_driver, acm->minor); |
@@ -1660,7 +1689,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) | |||
1660 | if (cnt) | 1689 | if (cnt) |
1661 | return 0; | 1690 | return 0; |
1662 | 1691 | ||
1663 | acm_kill_urbs(acm); | 1692 | acm_poison_urbs(acm); |
1664 | cancel_delayed_work_sync(&acm->dwork); | 1693 | cancel_delayed_work_sync(&acm->dwork); |
1665 | acm->urbs_in_error_delay = 0; | 1694 | acm->urbs_in_error_delay = 0; |
1666 | 1695 | ||
@@ -1678,6 +1707,8 @@ static int acm_resume(struct usb_interface *intf) | |||
1678 | if (--acm->susp_count) | 1707 | if (--acm->susp_count) |
1679 | goto out; | 1708 | goto out; |
1680 | 1709 | ||
1710 | acm_unpoison_urbs(acm); | ||
1711 | |||
1681 | if (tty_port_initialized(&acm->port)) { | 1712 | if (tty_port_initialized(&acm->port)) { |
1682 | rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); | 1713 | rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); |
1683 | 1714 | ||
@@ -1952,6 +1983,10 @@ static const struct usb_device_id acm_ids[] = { | |||
1952 | { USB_DEVICE(0x04d8, 0x0083), /* Bootloader mode */ | 1983 | { USB_DEVICE(0x04d8, 0x0083), /* Bootloader mode */ |
1953 | .driver_info = IGNORE_DEVICE, | 1984 | .driver_info = IGNORE_DEVICE, |
1954 | }, | 1985 | }, |
1986 | |||
1987 | { USB_DEVICE(0x04d8, 0xf58b), | ||
1988 | .driver_info = IGNORE_DEVICE, | ||
1989 | }, | ||
1955 | #endif | 1990 | #endif |
1956 | 1991 | ||
1957 | /*Samsung phone in firmware update mode */ | 1992 | /*Samsung phone in firmware update mode */ |
@@ -1982,6 +2017,16 @@ static const struct usb_device_id acm_ids[] = { | |||
1982 | .driver_info = SEND_ZERO_PACKET, | 2017 | .driver_info = SEND_ZERO_PACKET, |
1983 | }, | 2018 | }, |
1984 | 2019 | ||
2020 | /* Exclude Goodix Fingerprint Reader */ | ||
2021 | { USB_DEVICE(0x27c6, 0x5395), | ||
2022 | .driver_info = IGNORE_DEVICE, | ||
2023 | }, | ||
2024 | |||
2025 | /* Exclude Heimann Sensor GmbH USB appset demo */ | ||
2026 | { USB_DEVICE(0x32a7, 0x0000), | ||
2027 | .driver_info = IGNORE_DEVICE, | ||
2028 | }, | ||
2029 | |||
1985 | /* control interfaces without any protocol set */ | 2030 | /* control interfaces without any protocol set */ |
1986 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 2031 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1987 | USB_CDC_PROTO_NONE) }, | 2032 | USB_CDC_PROTO_NONE) }, |