From ba2d8ce9db0a61505362bb17b8899df3d3326146 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 8 Nov 2012 12:47:41 -0600 Subject: cdc-acm: implement TIOCSSERIAL to avoid blocking close(2) Some devices (ex Nokia C7) simply don't respond at all when data is sent to some of their USB interfaces. The data gets stuck in the TTYs queue and sits there until close(2), which them blocks because closing_wait defaults to 30 seconds (even though the fd is O_NONBLOCK). This is rarely desired. Implement the standard mechanism to adjust closing_wait and let applications handle it how they want to. See also 02303f73373aa1da19dbec510ec5a4e2576f9610 for usb_wwan.c. Signed-off-by: Dan Williams Cc: stable Acked-by: Oliver Neukum Tested-by: Aleksander Morgado Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers/usb/class/cdc-acm.c') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 6e49ec6f3ad..8d809a811e1 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -787,6 +787,10 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) tmp.flags = ASYNC_LOW_LATENCY; tmp.xmit_fifo_size = acm->writesize; tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); + tmp.close_delay = acm->port.close_delay / 10; + tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : + acm->port.closing_wait / 10; if (copy_to_user(info, &tmp, sizeof(tmp))) return -EFAULT; @@ -794,6 +798,37 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) return 0; } +static int set_serial_info(struct acm *acm, + struct serial_struct __user *newinfo) +{ + struct serial_struct new_serial; + unsigned int closing_wait, close_delay; + int retval = 0; + + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) + return -EFAULT; + + close_delay = new_serial.close_delay * 10; + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; + + mutex_lock(&acm->port.mutex); + + if (!capable(CAP_SYS_ADMIN)) { + if ((close_delay != acm->port.close_delay) || + (closing_wait != acm->port.closing_wait)) + retval = -EPERM; + else + retval = -EOPNOTSUPP; + } else { + acm->port.close_delay = close_delay; + acm->port.closing_wait = closing_wait; + } + + mutex_unlock(&acm->port.mutex); + return retval; +} + static int acm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -804,6 +839,9 @@ static int acm_tty_ioctl(struct tty_struct *tty, case TIOCGSERIAL: /* gets serial port data */ rv = get_serial_info(acm, (struct serial_struct __user *) arg); break; + case TIOCSSERIAL: + rv = set_serial_info(acm, (struct serial_struct __user *) arg); + break; } return rv; -- cgit v1.2.3 From 036915a7a402753c05b8d0529f5fd08805ab46d0 Mon Sep 17 00:00:00 2001 From: Denis N Ladin Date: Wed, 26 Dec 2012 18:29:44 +0500 Subject: USB: cdc-acm: Add support for "PSC Scanning, Magellan 800i" Adding support "PSC Scanning, Magellan 800i" in cdc-acm Very simple, but very necessary. Suitable for all versions of the kernel > 2.6 Signed-off-by: Denis N Ladin Cc: stable Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb/class/cdc-acm.c') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 8d809a811e1..2d92cce260d 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1602,6 +1602,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ .driver_info = NO_UNION_NORMAL, }, + { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */ + .driver_info = NO_UNION_NORMAL, + }, { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ }, -- cgit v1.2.3 From 05c7cd39907184328f48d3e7899f9cdd653ad336 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 3 Jan 2013 15:53:04 +0100 Subject: TTY: switch tty_insert_flip_string Now, we start converting tty buffer functions to actually use tty_port. This will allow us to get rid of the need of tty in many call sites. Only tty_port will needed and hence no more tty_port_tty_get in those paths. tty_insert_flip_string this time. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb/class/cdc-acm.c') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 8d809a811e1..20dc2add27b 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -419,7 +419,8 @@ static void acm_process_read_urb(struct acm *acm, struct urb *urb) if (!tty) return; - tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); + tty_insert_flip_string(&acm->port, urb->transfer_buffer, + urb->actual_length); tty_flip_buffer_push(tty); tty_kref_put(tty); -- cgit v1.2.3 From 2e124b4a390ca85325fae75764bef92f0547fa25 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 3 Jan 2013 15:53:06 +0100 Subject: TTY: switch tty_flip_buffer_push Now, we start converting tty buffer functions to actually use tty_port. This will allow us to get rid of the need of tty in many call sites. Only tty_port will needed and hence no more tty_port_tty_get in those paths. Now, the one where most of tty_port_tty_get gets removed: tty_flip_buffer_push. IOW we also closed all the races in drivers not using tty_port_tty_get at all yet. Also we move tty_flip_buffer_push declaration from include/linux/tty.h to include/linux/tty_flip.h to all others while we are changing it anyway. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/usb/class/cdc-acm.c') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 20dc2add27b..15b36e2efa8 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -410,20 +410,12 @@ static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags) static void acm_process_read_urb(struct acm *acm, struct urb *urb) { - struct tty_struct *tty; - if (!urb->actual_length) return; - tty = tty_port_tty_get(&acm->port); - if (!tty) - return; - tty_insert_flip_string(&acm->port, urb->transfer_buffer, urb->actual_length); - tty_flip_buffer_push(tty); - - tty_kref_put(tty); + tty_flip_buffer_push(&acm->port); } static void acm_read_bulk_callback(struct urb *urb) -- cgit v1.2.3