]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/usb/class/cdc-acm.c
USB: cdc-acm: Add support for "PSC Scanning, Magellan 800i"
[karo-tx-linux.git] / drivers / usb / class / cdc-acm.c
index 6e49ec6f3adcaeae67898e53cc1c5eb6cd62b756..2d92cce260d7fd646d13d69e01f2152bbd43a487 100644 (file)
@@ -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;
@@ -1564,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 */
        },