|
@@ -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;
|