diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
| -rw-r--r-- | drivers/usb/class/cdc-acm.c | 38 | 
1 files changed, 38 insertions, 0 deletions
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;  |