diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-05-01 11:47:44 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-05-01 11:47:44 -0400 |
commit | bf61c8840efe60fd8f91446860b63338fb424158 (patch) | |
tree | 7a71832407a4f0d6346db773343f4c3ae2257b19 /drivers/usb/class | |
parent | 5846115b30f3a881e542c8bfde59a699c1c13740 (diff) | |
parent | 0c6a61657da78098472fd0eb71cc01f2387fa1bb (diff) |
Merge branch 'next' into for-linus
Prepare first set of updates for 3.10 merge window.
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 67 | ||||
-rw-r--r-- | drivers/usb/class/cdc-acm.h | 1 | ||||
-rw-r--r-- | drivers/usb/class/cdc-wdm.c | 23 |
4 files changed, 79 insertions, 14 deletions
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index 2519e320098f..316aac8e4ca1 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig | |||
@@ -6,7 +6,7 @@ comment "USB Device Class drivers" | |||
6 | 6 | ||
7 | config USB_ACM | 7 | config USB_ACM |
8 | tristate "USB Modem (CDC ACM) support" | 8 | tristate "USB Modem (CDC ACM) support" |
9 | depends on USB | 9 | depends on USB && TTY |
10 | ---help--- | 10 | ---help--- |
11 | This driver supports USB modems and ISDN adapters which support the | 11 | This driver supports USB modems and ISDN adapters which support the |
12 | Communication Device Class Abstract Control Model interface. | 12 | Communication Device Class Abstract Control Model interface. |
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 6e49ec6f3adc..cb8ef3ef5c94 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -410,19 +410,12 @@ static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags) | |||
410 | 410 | ||
411 | static void acm_process_read_urb(struct acm *acm, struct urb *urb) | 411 | static void acm_process_read_urb(struct acm *acm, struct urb *urb) |
412 | { | 412 | { |
413 | struct tty_struct *tty; | ||
414 | |||
415 | if (!urb->actual_length) | 413 | if (!urb->actual_length) |
416 | return; | 414 | return; |
417 | 415 | ||
418 | tty = tty_port_tty_get(&acm->port); | 416 | tty_insert_flip_string(&acm->port, urb->transfer_buffer, |
419 | if (!tty) | 417 | urb->actual_length); |
420 | return; | 418 | tty_flip_buffer_push(&acm->port); |
421 | |||
422 | tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); | ||
423 | tty_flip_buffer_push(tty); | ||
424 | |||
425 | tty_kref_put(tty); | ||
426 | } | 419 | } |
427 | 420 | ||
428 | static void acm_read_bulk_callback(struct urb *urb) | 421 | static void acm_read_bulk_callback(struct urb *urb) |
@@ -787,6 +780,10 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) | |||
787 | tmp.flags = ASYNC_LOW_LATENCY; | 780 | tmp.flags = ASYNC_LOW_LATENCY; |
788 | tmp.xmit_fifo_size = acm->writesize; | 781 | tmp.xmit_fifo_size = acm->writesize; |
789 | tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); | 782 | tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); |
783 | tmp.close_delay = acm->port.close_delay / 10; | ||
784 | tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? | ||
785 | ASYNC_CLOSING_WAIT_NONE : | ||
786 | acm->port.closing_wait / 10; | ||
790 | 787 | ||
791 | if (copy_to_user(info, &tmp, sizeof(tmp))) | 788 | if (copy_to_user(info, &tmp, sizeof(tmp))) |
792 | return -EFAULT; | 789 | return -EFAULT; |
@@ -794,6 +791,37 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) | |||
794 | return 0; | 791 | return 0; |
795 | } | 792 | } |
796 | 793 | ||
794 | static int set_serial_info(struct acm *acm, | ||
795 | struct serial_struct __user *newinfo) | ||
796 | { | ||
797 | struct serial_struct new_serial; | ||
798 | unsigned int closing_wait, close_delay; | ||
799 | int retval = 0; | ||
800 | |||
801 | if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) | ||
802 | return -EFAULT; | ||
803 | |||
804 | close_delay = new_serial.close_delay * 10; | ||
805 | closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? | ||
806 | ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; | ||
807 | |||
808 | mutex_lock(&acm->port.mutex); | ||
809 | |||
810 | if (!capable(CAP_SYS_ADMIN)) { | ||
811 | if ((close_delay != acm->port.close_delay) || | ||
812 | (closing_wait != acm->port.closing_wait)) | ||
813 | retval = -EPERM; | ||
814 | else | ||
815 | retval = -EOPNOTSUPP; | ||
816 | } else { | ||
817 | acm->port.close_delay = close_delay; | ||
818 | acm->port.closing_wait = closing_wait; | ||
819 | } | ||
820 | |||
821 | mutex_unlock(&acm->port.mutex); | ||
822 | return retval; | ||
823 | } | ||
824 | |||
797 | static int acm_tty_ioctl(struct tty_struct *tty, | 825 | static int acm_tty_ioctl(struct tty_struct *tty, |
798 | unsigned int cmd, unsigned long arg) | 826 | unsigned int cmd, unsigned long arg) |
799 | { | 827 | { |
@@ -804,6 +832,9 @@ static int acm_tty_ioctl(struct tty_struct *tty, | |||
804 | case TIOCGSERIAL: /* gets serial port data */ | 832 | case TIOCGSERIAL: /* gets serial port data */ |
805 | rv = get_serial_info(acm, (struct serial_struct __user *) arg); | 833 | rv = get_serial_info(acm, (struct serial_struct __user *) arg); |
806 | break; | 834 | break; |
835 | case TIOCSSERIAL: | ||
836 | rv = set_serial_info(acm, (struct serial_struct __user *) arg); | ||
837 | break; | ||
807 | } | 838 | } |
808 | 839 | ||
809 | return rv; | 840 | return rv; |
@@ -949,6 +980,10 @@ static int acm_probe(struct usb_interface *intf, | |||
949 | 980 | ||
950 | /* normal quirks */ | 981 | /* normal quirks */ |
951 | quirks = (unsigned long)id->driver_info; | 982 | quirks = (unsigned long)id->driver_info; |
983 | |||
984 | if (quirks == IGNORE_DEVICE) | ||
985 | return -ENODEV; | ||
986 | |||
952 | num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; | 987 | num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; |
953 | 988 | ||
954 | /* handle quirks deadly to normal probing*/ | 989 | /* handle quirks deadly to normal probing*/ |
@@ -1564,6 +1599,9 @@ static const struct usb_device_id acm_ids[] = { | |||
1564 | { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ | 1599 | { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ |
1565 | .driver_info = NO_UNION_NORMAL, | 1600 | .driver_info = NO_UNION_NORMAL, |
1566 | }, | 1601 | }, |
1602 | { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */ | ||
1603 | .driver_info = NO_UNION_NORMAL, | ||
1604 | }, | ||
1567 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ | 1605 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ |
1568 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ | 1606 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ |
1569 | }, | 1607 | }, |
@@ -1650,6 +1688,15 @@ static const struct usb_device_id acm_ids[] = { | |||
1650 | .driver_info = NO_DATA_INTERFACE, | 1688 | .driver_info = NO_DATA_INTERFACE, |
1651 | }, | 1689 | }, |
1652 | 1690 | ||
1691 | #if IS_ENABLED(CONFIG_INPUT_IMS_PCU) | ||
1692 | { USB_DEVICE(0x04d8, 0x0082), /* Application mode */ | ||
1693 | .driver_info = IGNORE_DEVICE, | ||
1694 | }, | ||
1695 | { USB_DEVICE(0x04d8, 0x0083), /* Bootloader mode */ | ||
1696 | .driver_info = IGNORE_DEVICE, | ||
1697 | }, | ||
1698 | #endif | ||
1699 | |||
1653 | /* control interfaces without any protocol set */ | 1700 | /* control interfaces without any protocol set */ |
1654 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1701 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
1655 | USB_CDC_PROTO_NONE) }, | 1702 | USB_CDC_PROTO_NONE) }, |
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 35ef887b7417..0f76e4af600e 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h | |||
@@ -128,3 +128,4 @@ struct acm { | |||
128 | #define NO_CAP_LINE 4 | 128 | #define NO_CAP_LINE 4 |
129 | #define NOT_A_MODEM 8 | 129 | #define NOT_A_MODEM 8 |
130 | #define NO_DATA_INTERFACE 16 | 130 | #define NO_DATA_INTERFACE 16 |
131 | #define IGNORE_DEVICE 32 | ||
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 5f0cb417b736..122d056d96d5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
@@ -56,6 +56,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); | |||
56 | #define WDM_RESPONDING 7 | 56 | #define WDM_RESPONDING 7 |
57 | #define WDM_SUSPENDING 8 | 57 | #define WDM_SUSPENDING 8 |
58 | #define WDM_RESETTING 9 | 58 | #define WDM_RESETTING 9 |
59 | #define WDM_OVERFLOW 10 | ||
59 | 60 | ||
60 | #define WDM_MAX 16 | 61 | #define WDM_MAX 16 |
61 | 62 | ||
@@ -155,6 +156,7 @@ static void wdm_in_callback(struct urb *urb) | |||
155 | { | 156 | { |
156 | struct wdm_device *desc = urb->context; | 157 | struct wdm_device *desc = urb->context; |
157 | int status = urb->status; | 158 | int status = urb->status; |
159 | int length = urb->actual_length; | ||
158 | 160 | ||
159 | spin_lock(&desc->iuspin); | 161 | spin_lock(&desc->iuspin); |
160 | clear_bit(WDM_RESPONDING, &desc->flags); | 162 | clear_bit(WDM_RESPONDING, &desc->flags); |
@@ -185,9 +187,17 @@ static void wdm_in_callback(struct urb *urb) | |||
185 | } | 187 | } |
186 | 188 | ||
187 | desc->rerr = status; | 189 | desc->rerr = status; |
188 | desc->reslength = urb->actual_length; | 190 | if (length + desc->length > desc->wMaxCommand) { |
189 | memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); | 191 | /* The buffer would overflow */ |
190 | desc->length += desc->reslength; | 192 | set_bit(WDM_OVERFLOW, &desc->flags); |
193 | } else { | ||
194 | /* we may already be in overflow */ | ||
195 | if (!test_bit(WDM_OVERFLOW, &desc->flags)) { | ||
196 | memmove(desc->ubuf + desc->length, desc->inbuf, length); | ||
197 | desc->length += length; | ||
198 | desc->reslength = length; | ||
199 | } | ||
200 | } | ||
191 | skip_error: | 201 | skip_error: |
192 | wake_up(&desc->wait); | 202 | wake_up(&desc->wait); |
193 | 203 | ||
@@ -435,6 +445,11 @@ retry: | |||
435 | rv = -ENODEV; | 445 | rv = -ENODEV; |
436 | goto err; | 446 | goto err; |
437 | } | 447 | } |
448 | if (test_bit(WDM_OVERFLOW, &desc->flags)) { | ||
449 | clear_bit(WDM_OVERFLOW, &desc->flags); | ||
450 | rv = -ENOBUFS; | ||
451 | goto err; | ||
452 | } | ||
438 | i++; | 453 | i++; |
439 | if (file->f_flags & O_NONBLOCK) { | 454 | if (file->f_flags & O_NONBLOCK) { |
440 | if (!test_bit(WDM_READ, &desc->flags)) { | 455 | if (!test_bit(WDM_READ, &desc->flags)) { |
@@ -478,6 +493,7 @@ retry: | |||
478 | spin_unlock_irq(&desc->iuspin); | 493 | spin_unlock_irq(&desc->iuspin); |
479 | goto retry; | 494 | goto retry; |
480 | } | 495 | } |
496 | |||
481 | if (!desc->reslength) { /* zero length read */ | 497 | if (!desc->reslength) { /* zero length read */ |
482 | dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); | 498 | dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); |
483 | clear_bit(WDM_READ, &desc->flags); | 499 | clear_bit(WDM_READ, &desc->flags); |
@@ -1004,6 +1020,7 @@ static int wdm_post_reset(struct usb_interface *intf) | |||
1004 | struct wdm_device *desc = wdm_find_device(intf); | 1020 | struct wdm_device *desc = wdm_find_device(intf); |
1005 | int rv; | 1021 | int rv; |
1006 | 1022 | ||
1023 | clear_bit(WDM_OVERFLOW, &desc->flags); | ||
1007 | clear_bit(WDM_RESETTING, &desc->flags); | 1024 | clear_bit(WDM_RESETTING, &desc->flags); |
1008 | rv = recover_from_urb_loss(desc); | 1025 | rv = recover_from_urb_loss(desc); |
1009 | mutex_unlock(&desc->wlock); | 1026 | mutex_unlock(&desc->wlock); |