diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 54 | 
1 files changed, 44 insertions, 10 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 278bf5256a9..cb8ef3ef5c9 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)  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(tty, urb->transfer_buffer, urb->actual_length); -	tty_flip_buffer_push(tty); - -	tty_kref_put(tty); +	tty_insert_flip_string(&acm->port, urb->transfer_buffer, +			urb->actual_length); +	tty_flip_buffer_push(&acm->port);  }  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)  	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 +791,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 +832,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; @@ -1568,6 +1599,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 */  	},  |