diff options
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 27 | ||||
-rw-r--r-- | drivers/usb/serial/option.c | 1 | ||||
-rw-r--r-- | drivers/usb/serial/ssu100.c | 56 | ||||
-rw-r--r-- | drivers/usb/serial/usb-wwan.h | 2 | ||||
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 79 |
5 files changed, 117 insertions, 48 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 2dec50013528..a2668d089260 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -75,6 +75,7 @@ struct ftdi_private { | |||
75 | unsigned long last_dtr_rts; /* saved modem control outputs */ | 75 | unsigned long last_dtr_rts; /* saved modem control outputs */ |
76 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ | 76 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ |
77 | char prev_status, diff_status; /* Used for TIOCMIWAIT */ | 77 | char prev_status, diff_status; /* Used for TIOCMIWAIT */ |
78 | char transmit_empty; /* If transmitter is empty or not */ | ||
78 | struct usb_serial_port *port; | 79 | struct usb_serial_port *port; |
79 | __u16 interface; /* FT2232C, FT2232H or FT4232H port interface | 80 | __u16 interface; /* FT2232C, FT2232H or FT4232H port interface |
80 | (0 for FT232/245) */ | 81 | (0 for FT232/245) */ |
@@ -1323,6 +1324,23 @@ check_and_exit: | |||
1323 | return 0; | 1324 | return 0; |
1324 | } | 1325 | } |
1325 | 1326 | ||
1327 | static int get_lsr_info(struct usb_serial_port *port, | ||
1328 | struct serial_struct __user *retinfo) | ||
1329 | { | ||
1330 | struct ftdi_private *priv = usb_get_serial_port_data(port); | ||
1331 | unsigned int result = 0; | ||
1332 | |||
1333 | if (!retinfo) | ||
1334 | return -EFAULT; | ||
1335 | |||
1336 | if (priv->transmit_empty) | ||
1337 | result = TIOCSER_TEMT; | ||
1338 | |||
1339 | if (copy_to_user(retinfo, &result, sizeof(unsigned int))) | ||
1340 | return -EFAULT; | ||
1341 | return 0; | ||
1342 | } | ||
1343 | |||
1326 | 1344 | ||
1327 | /* Determine type of FTDI chip based on USB config and descriptor. */ | 1345 | /* Determine type of FTDI chip based on USB config and descriptor. */ |
1328 | static void ftdi_determine_type(struct usb_serial_port *port) | 1346 | static void ftdi_determine_type(struct usb_serial_port *port) |
@@ -1872,6 +1890,12 @@ static int ftdi_process_packet(struct tty_struct *tty, | |||
1872 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | 1890 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); |
1873 | } | 1891 | } |
1874 | 1892 | ||
1893 | /* save if the transmitter is empty or not */ | ||
1894 | if (packet[1] & FTDI_RS_TEMT) | ||
1895 | priv->transmit_empty = 1; | ||
1896 | else | ||
1897 | priv->transmit_empty = 0; | ||
1898 | |||
1875 | len -= 2; | 1899 | len -= 2; |
1876 | if (!len) | 1900 | if (!len) |
1877 | return 0; /* status only */ | 1901 | return 0; /* status only */ |
@@ -2235,6 +2259,9 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file, | |||
2235 | } | 2259 | } |
2236 | } | 2260 | } |
2237 | return 0; | 2261 | return 0; |
2262 | case TIOCSERGETLSR: | ||
2263 | return get_lsr_info(port, (struct serial_struct __user *)arg); | ||
2264 | break; | ||
2238 | default: | 2265 | default: |
2239 | break; | 2266 | break; |
2240 | } | 2267 | } |
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index ef2977d3a613..cdfb1868caef 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -989,6 +989,7 @@ static struct usb_serial_driver option_1port_device = { | |||
989 | .set_termios = usb_wwan_set_termios, | 989 | .set_termios = usb_wwan_set_termios, |
990 | .tiocmget = usb_wwan_tiocmget, | 990 | .tiocmget = usb_wwan_tiocmget, |
991 | .tiocmset = usb_wwan_tiocmset, | 991 | .tiocmset = usb_wwan_tiocmset, |
992 | .ioctl = usb_wwan_ioctl, | ||
992 | .attach = usb_wwan_startup, | 993 | .attach = usb_wwan_startup, |
993 | .disconnect = usb_wwan_disconnect, | 994 | .disconnect = usb_wwan_disconnect, |
994 | .release = usb_wwan_release, | 995 | .release = usb_wwan_release, |
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index f5312dd3331b..8359ec798959 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c | |||
@@ -79,7 +79,6 @@ struct ssu100_port_private { | |||
79 | u8 shadowLSR; | 79 | u8 shadowLSR; |
80 | u8 shadowMSR; | 80 | u8 shadowMSR; |
81 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ | 81 | wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ |
82 | unsigned short max_packet_size; | ||
83 | struct async_icount icount; | 82 | struct async_icount icount; |
84 | }; | 83 | }; |
85 | 84 | ||
@@ -464,36 +463,6 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file, | |||
464 | return -ENOIOCTLCMD; | 463 | return -ENOIOCTLCMD; |
465 | } | 464 | } |
466 | 465 | ||
467 | static void ssu100_set_max_packet_size(struct usb_serial_port *port) | ||
468 | { | ||
469 | struct ssu100_port_private *priv = usb_get_serial_port_data(port); | ||
470 | struct usb_serial *serial = port->serial; | ||
471 | struct usb_device *udev = serial->dev; | ||
472 | |||
473 | struct usb_interface *interface = serial->interface; | ||
474 | struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc; | ||
475 | |||
476 | unsigned num_endpoints; | ||
477 | int i; | ||
478 | unsigned long flags; | ||
479 | |||
480 | num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; | ||
481 | dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); | ||
482 | |||
483 | for (i = 0; i < num_endpoints; i++) { | ||
484 | dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1, | ||
485 | interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize); | ||
486 | ep_desc = &interface->cur_altsetting->endpoint[i].desc; | ||
487 | } | ||
488 | |||
489 | /* set max packet size based on descriptor */ | ||
490 | spin_lock_irqsave(&priv->status_lock, flags); | ||
491 | priv->max_packet_size = ep_desc->wMaxPacketSize; | ||
492 | spin_unlock_irqrestore(&priv->status_lock, flags); | ||
493 | |||
494 | dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); | ||
495 | } | ||
496 | |||
497 | static int ssu100_attach(struct usb_serial *serial) | 466 | static int ssu100_attach(struct usb_serial *serial) |
498 | { | 467 | { |
499 | struct ssu100_port_private *priv; | 468 | struct ssu100_port_private *priv; |
@@ -511,7 +480,6 @@ static int ssu100_attach(struct usb_serial *serial) | |||
511 | spin_lock_init(&priv->status_lock); | 480 | spin_lock_init(&priv->status_lock); |
512 | init_waitqueue_head(&priv->delta_msr_wait); | 481 | init_waitqueue_head(&priv->delta_msr_wait); |
513 | usb_set_serial_port_data(port, priv); | 482 | usb_set_serial_port_data(port, priv); |
514 | ssu100_set_max_packet_size(port); | ||
515 | 483 | ||
516 | return ssu100_initdevice(serial->dev); | 484 | return ssu100_initdevice(serial->dev); |
517 | } | 485 | } |
@@ -641,13 +609,14 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, | |||
641 | 609 | ||
642 | } | 610 | } |
643 | 611 | ||
644 | static int ssu100_process_packet(struct tty_struct *tty, | 612 | static int ssu100_process_packet(struct urb *urb, |
645 | struct usb_serial_port *port, | 613 | struct tty_struct *tty) |
646 | struct ssu100_port_private *priv, | ||
647 | char *packet, int len) | ||
648 | { | 614 | { |
649 | int i; | 615 | struct usb_serial_port *port = urb->context; |
616 | char *packet = (char *)urb->transfer_buffer; | ||
650 | char flag = TTY_NORMAL; | 617 | char flag = TTY_NORMAL; |
618 | u32 len = urb->actual_length; | ||
619 | int i; | ||
651 | char *ch; | 620 | char *ch; |
652 | 621 | ||
653 | dbg("%s - port %d", __func__, port->number); | 622 | dbg("%s - port %d", __func__, port->number); |
@@ -685,12 +654,8 @@ static int ssu100_process_packet(struct tty_struct *tty, | |||
685 | static void ssu100_process_read_urb(struct urb *urb) | 654 | static void ssu100_process_read_urb(struct urb *urb) |
686 | { | 655 | { |
687 | struct usb_serial_port *port = urb->context; | 656 | struct usb_serial_port *port = urb->context; |
688 | struct ssu100_port_private *priv = usb_get_serial_port_data(port); | ||
689 | char *data = (char *)urb->transfer_buffer; | ||
690 | struct tty_struct *tty; | 657 | struct tty_struct *tty; |
691 | int count = 0; | 658 | int count; |
692 | int i; | ||
693 | int len; | ||
694 | 659 | ||
695 | dbg("%s", __func__); | 660 | dbg("%s", __func__); |
696 | 661 | ||
@@ -698,10 +663,7 @@ static void ssu100_process_read_urb(struct urb *urb) | |||
698 | if (!tty) | 663 | if (!tty) |
699 | return; | 664 | return; |
700 | 665 | ||
701 | for (i = 0; i < urb->actual_length; i += priv->max_packet_size) { | 666 | count = ssu100_process_packet(urb, tty); |
702 | len = min_t(int, urb->actual_length - i, priv->max_packet_size); | ||
703 | count += ssu100_process_packet(tty, port, priv, &data[i], len); | ||
704 | } | ||
705 | 667 | ||
706 | if (count) | 668 | if (count) |
707 | tty_flip_buffer_push(tty); | 669 | tty_flip_buffer_push(tty); |
@@ -717,8 +679,6 @@ static struct usb_serial_driver ssu100_device = { | |||
717 | .id_table = id_table, | 679 | .id_table = id_table, |
718 | .usb_driver = &ssu100_driver, | 680 | .usb_driver = &ssu100_driver, |
719 | .num_ports = 1, | 681 | .num_ports = 1, |
720 | .bulk_in_size = 256, | ||
721 | .bulk_out_size = 256, | ||
722 | .open = ssu100_open, | 682 | .open = ssu100_open, |
723 | .close = ssu100_close, | 683 | .close = ssu100_close, |
724 | .attach = ssu100_attach, | 684 | .attach = ssu100_attach, |
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index 2be298a1305b..3ab77c5d9819 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h | |||
@@ -18,6 +18,8 @@ extern void usb_wwan_set_termios(struct tty_struct *tty, | |||
18 | extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file); | 18 | extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file); |
19 | extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, | 19 | extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, |
20 | unsigned int set, unsigned int clear); | 20 | unsigned int set, unsigned int clear); |
21 | extern int usb_wwan_ioctl(struct tty_struct *tty, struct file *file, | ||
22 | unsigned int cmd, unsigned long arg); | ||
21 | extern int usb_wwan_send_setup(struct usb_serial_port *port); | 23 | extern int usb_wwan_send_setup(struct usb_serial_port *port); |
22 | extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | 24 | extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, |
23 | const unsigned char *buf, int count); | 25 | const unsigned char *buf, int count); |
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index fbc946797801..b004b2a485c3 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c | |||
@@ -31,8 +31,10 @@ | |||
31 | #include <linux/tty_flip.h> | 31 | #include <linux/tty_flip.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/bitops.h> | 33 | #include <linux/bitops.h> |
34 | #include <linux/uaccess.h> | ||
34 | #include <linux/usb.h> | 35 | #include <linux/usb.h> |
35 | #include <linux/usb/serial.h> | 36 | #include <linux/usb/serial.h> |
37 | #include <linux/serial.h> | ||
36 | #include "usb-wwan.h" | 38 | #include "usb-wwan.h" |
37 | 39 | ||
38 | static int debug; | 40 | static int debug; |
@@ -123,6 +125,83 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file, | |||
123 | } | 125 | } |
124 | EXPORT_SYMBOL(usb_wwan_tiocmset); | 126 | EXPORT_SYMBOL(usb_wwan_tiocmset); |
125 | 127 | ||
128 | static int get_serial_info(struct usb_serial_port *port, | ||
129 | struct serial_struct __user *retinfo) | ||
130 | { | ||
131 | struct serial_struct tmp; | ||
132 | |||
133 | if (!retinfo) | ||
134 | return -EFAULT; | ||
135 | |||
136 | memset(&tmp, 0, sizeof(tmp)); | ||
137 | tmp.line = port->serial->minor; | ||
138 | tmp.port = port->number; | ||
139 | tmp.baud_base = tty_get_baud_rate(port->port.tty); | ||
140 | tmp.close_delay = port->port.close_delay / 10; | ||
141 | tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? | ||
142 | ASYNC_CLOSING_WAIT_NONE : | ||
143 | port->port.closing_wait / 10; | ||
144 | |||
145 | if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) | ||
146 | return -EFAULT; | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int set_serial_info(struct usb_serial_port *port, | ||
151 | struct serial_struct __user *newinfo) | ||
152 | { | ||
153 | struct serial_struct new_serial; | ||
154 | unsigned int closing_wait, close_delay; | ||
155 | int retval = 0; | ||
156 | |||
157 | if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) | ||
158 | return -EFAULT; | ||
159 | |||
160 | close_delay = new_serial.close_delay * 10; | ||
161 | closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? | ||
162 | ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; | ||
163 | |||
164 | mutex_lock(&port->port.mutex); | ||
165 | |||
166 | if (!capable(CAP_SYS_ADMIN)) { | ||
167 | if ((close_delay != port->port.close_delay) || | ||
168 | (closing_wait != port->port.closing_wait)) | ||
169 | retval = -EPERM; | ||
170 | else | ||
171 | retval = -EOPNOTSUPP; | ||
172 | } else { | ||
173 | port->port.close_delay = close_delay; | ||
174 | port->port.closing_wait = closing_wait; | ||
175 | } | ||
176 | |||
177 | mutex_unlock(&port->port.mutex); | ||
178 | return retval; | ||
179 | } | ||
180 | |||
181 | int usb_wwan_ioctl(struct tty_struct *tty, struct file *file, | ||
182 | unsigned int cmd, unsigned long arg) | ||
183 | { | ||
184 | struct usb_serial_port *port = tty->driver_data; | ||
185 | |||
186 | dbg("%s cmd 0x%04x", __func__, cmd); | ||
187 | |||
188 | switch (cmd) { | ||
189 | case TIOCGSERIAL: | ||
190 | return get_serial_info(port, | ||
191 | (struct serial_struct __user *) arg); | ||
192 | case TIOCSSERIAL: | ||
193 | return set_serial_info(port, | ||
194 | (struct serial_struct __user *) arg); | ||
195 | default: | ||
196 | break; | ||
197 | } | ||
198 | |||
199 | dbg("%s arg not supported", __func__); | ||
200 | |||
201 | return -ENOIOCTLCMD; | ||
202 | } | ||
203 | EXPORT_SYMBOL(usb_wwan_ioctl); | ||
204 | |||
126 | /* Write */ | 205 | /* Write */ |
127 | int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, | 206 | int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, |
128 | const unsigned char *buf, int count) | 207 | const unsigned char *buf, int count) |