diff options
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 6e49ec6f3adc..2d92cce260d7 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) | |||
787 | tmp.flags = ASYNC_LOW_LATENCY; | 787 | tmp.flags = ASYNC_LOW_LATENCY; |
788 | tmp.xmit_fifo_size = acm->writesize; | 788 | tmp.xmit_fifo_size = acm->writesize; |
789 | tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); | 789 | tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); |
790 | tmp.close_delay = acm->port.close_delay / 10; | ||
791 | tmp.closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? | ||
792 | ASYNC_CLOSING_WAIT_NONE : | ||
793 | acm->port.closing_wait / 10; | ||
790 | 794 | ||
791 | if (copy_to_user(info, &tmp, sizeof(tmp))) | 795 | if (copy_to_user(info, &tmp, sizeof(tmp))) |
792 | return -EFAULT; | 796 | return -EFAULT; |
@@ -794,6 +798,37 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) | |||
794 | return 0; | 798 | return 0; |
795 | } | 799 | } |
796 | 800 | ||
801 | static int set_serial_info(struct acm *acm, | ||
802 | struct serial_struct __user *newinfo) | ||
803 | { | ||
804 | struct serial_struct new_serial; | ||
805 | unsigned int closing_wait, close_delay; | ||
806 | int retval = 0; | ||
807 | |||
808 | if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) | ||
809 | return -EFAULT; | ||
810 | |||
811 | close_delay = new_serial.close_delay * 10; | ||
812 | closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? | ||
813 | ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; | ||
814 | |||
815 | mutex_lock(&acm->port.mutex); | ||
816 | |||
817 | if (!capable(CAP_SYS_ADMIN)) { | ||
818 | if ((close_delay != acm->port.close_delay) || | ||
819 | (closing_wait != acm->port.closing_wait)) | ||
820 | retval = -EPERM; | ||
821 | else | ||
822 | retval = -EOPNOTSUPP; | ||
823 | } else { | ||
824 | acm->port.close_delay = close_delay; | ||
825 | acm->port.closing_wait = closing_wait; | ||
826 | } | ||
827 | |||
828 | mutex_unlock(&acm->port.mutex); | ||
829 | return retval; | ||
830 | } | ||
831 | |||
797 | static int acm_tty_ioctl(struct tty_struct *tty, | 832 | static int acm_tty_ioctl(struct tty_struct *tty, |
798 | unsigned int cmd, unsigned long arg) | 833 | unsigned int cmd, unsigned long arg) |
799 | { | 834 | { |
@@ -804,6 +839,9 @@ static int acm_tty_ioctl(struct tty_struct *tty, | |||
804 | case TIOCGSERIAL: /* gets serial port data */ | 839 | case TIOCGSERIAL: /* gets serial port data */ |
805 | rv = get_serial_info(acm, (struct serial_struct __user *) arg); | 840 | rv = get_serial_info(acm, (struct serial_struct __user *) arg); |
806 | break; | 841 | break; |
842 | case TIOCSSERIAL: | ||
843 | rv = set_serial_info(acm, (struct serial_struct __user *) arg); | ||
844 | break; | ||
807 | } | 845 | } |
808 | 846 | ||
809 | return rv; | 847 | return rv; |
@@ -1564,6 +1602,9 @@ static const struct usb_device_id acm_ids[] = { | |||
1564 | { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ | 1602 | { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */ |
1565 | .driver_info = NO_UNION_NORMAL, | 1603 | .driver_info = NO_UNION_NORMAL, |
1566 | }, | 1604 | }, |
1605 | { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */ | ||
1606 | .driver_info = NO_UNION_NORMAL, | ||
1607 | }, | ||
1567 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ | 1608 | { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */ |
1568 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ | 1609 | .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ |
1569 | }, | 1610 | }, |