summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/ftdi_sio.c27
-rw-r--r--drivers/usb/serial/option.c2
-rw-r--r--drivers/usb/serial/oti6858.c5
-rw-r--r--drivers/usb/serial/ssu100.c56
-rw-r--r--drivers/usb/serial/usb-wwan.h2
-rw-r--r--drivers/usb/serial/usb_wwan.c79
6 files changed, 119 insertions, 52 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 2dec5001352..a2668d08926 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -75,6 +75,7 @@ struct ftdi_private {
unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
+ char transmit_empty; /* If transmitter is empty or not */
struct usb_serial_port *port;
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
(0 for FT232/245) */
@@ -1323,6 +1324,23 @@ check_and_exit:
return 0;
}
+static int get_lsr_info(struct usb_serial_port *port,
+ struct serial_struct __user *retinfo)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ unsigned int result = 0;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ if (priv->transmit_empty)
+ result = TIOCSER_TEMT;
+
+ if (copy_to_user(retinfo, &result, sizeof(unsigned int)))
+ return -EFAULT;
+ return 0;
+}
+
/* Determine type of FTDI chip based on USB config and descriptor. */
static void ftdi_determine_type(struct usb_serial_port *port)
@@ -1872,6 +1890,12 @@ static int ftdi_process_packet(struct tty_struct *tty,
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
+ /* save if the transmitter is empty or not */
+ if (packet[1] & FTDI_RS_TEMT)
+ priv->transmit_empty = 1;
+ else
+ priv->transmit_empty = 0;
+
len -= 2;
if (!len)
return 0; /* status only */
@@ -2235,6 +2259,9 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file,
}
}
return 0;
+ case TIOCSERGETLSR:
+ return get_lsr_info(port, (struct serial_struct __user *)arg);
+ break;
default:
break;
}
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index ef2977d3a61..748778288d9 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -615,7 +615,6 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0007, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) },
@@ -989,6 +988,7 @@ static struct usb_serial_driver option_1port_device = {
.set_termios = usb_wwan_set_termios,
.tiocmget = usb_wwan_tiocmget,
.tiocmset = usb_wwan_tiocmset,
+ .ioctl = usb_wwan_ioctl,
.attach = usb_wwan_startup,
.disconnect = usb_wwan_disconnect,
.release = usb_wwan_release,
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index e199b0f4f99..5be866bb7a4 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -613,9 +613,8 @@ static void oti6858_close(struct usb_serial_port *port)
dbg("%s(): after buf_clear()", __func__);
/* cancel scheduled setup */
- cancel_delayed_work(&priv->delayed_setup_work);
- cancel_delayed_work(&priv->delayed_write_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&priv->delayed_setup_work);
+ cancel_delayed_work_sync(&priv->delayed_write_work);
/* shutdown our urbs */
dbg("%s(): shutting down urbs", __func__);
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index f5312dd3331..8359ec79895 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -79,7 +79,6 @@ struct ssu100_port_private {
u8 shadowLSR;
u8 shadowMSR;
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
- unsigned short max_packet_size;
struct async_icount icount;
};
@@ -464,36 +463,6 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
-static void ssu100_set_max_packet_size(struct usb_serial_port *port)
-{
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- struct usb_serial *serial = port->serial;
- struct usb_device *udev = serial->dev;
-
- struct usb_interface *interface = serial->interface;
- struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
-
- unsigned num_endpoints;
- int i;
- unsigned long flags;
-
- num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
- dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
-
- for (i = 0; i < num_endpoints; i++) {
- dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
- interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
- ep_desc = &interface->cur_altsetting->endpoint[i].desc;
- }
-
- /* set max packet size based on descriptor */
- spin_lock_irqsave(&priv->status_lock, flags);
- priv->max_packet_size = ep_desc->wMaxPacketSize;
- spin_unlock_irqrestore(&priv->status_lock, flags);
-
- dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
-}
-
static int ssu100_attach(struct usb_serial *serial)
{
struct ssu100_port_private *priv;
@@ -511,7 +480,6 @@ static int ssu100_attach(struct usb_serial *serial)
spin_lock_init(&priv->status_lock);
init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
- ssu100_set_max_packet_size(port);
return ssu100_initdevice(serial->dev);
}
@@ -641,13 +609,14 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
}
-static int ssu100_process_packet(struct tty_struct *tty,
- struct usb_serial_port *port,
- struct ssu100_port_private *priv,
- char *packet, int len)
+static int ssu100_process_packet(struct urb *urb,
+ struct tty_struct *tty)
{
- int i;
+ struct usb_serial_port *port = urb->context;
+ char *packet = (char *)urb->transfer_buffer;
char flag = TTY_NORMAL;
+ u32 len = urb->actual_length;
+ int i;
char *ch;
dbg("%s - port %d", __func__, port->number);
@@ -685,12 +654,8 @@ static int ssu100_process_packet(struct tty_struct *tty,
static void ssu100_process_read_urb(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- char *data = (char *)urb->transfer_buffer;
struct tty_struct *tty;
- int count = 0;
- int i;
- int len;
+ int count;
dbg("%s", __func__);
@@ -698,10 +663,7 @@ static void ssu100_process_read_urb(struct urb *urb)
if (!tty)
return;
- for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
- len = min_t(int, urb->actual_length - i, priv->max_packet_size);
- count += ssu100_process_packet(tty, port, priv, &data[i], len);
- }
+ count = ssu100_process_packet(urb, tty);
if (count)
tty_flip_buffer_push(tty);
@@ -717,8 +679,6 @@ static struct usb_serial_driver ssu100_device = {
.id_table = id_table,
.usb_driver = &ssu100_driver,
.num_ports = 1,
- .bulk_in_size = 256,
- .bulk_out_size = 256,
.open = ssu100_open,
.close = ssu100_close,
.attach = ssu100_attach,
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index 2be298a1305..3ab77c5d981 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,
extern int usb_wwan_tiocmget(struct tty_struct *tty, struct file *file);
extern int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
+extern int usb_wwan_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg);
extern int usb_wwan_send_setup(struct usb_serial_port *port);
extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index fbc94679780..b004b2a485c 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -31,8 +31,10 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/bitops.h>
+#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <linux/serial.h>
#include "usb-wwan.h"
static int debug;
@@ -123,6 +125,83 @@ int usb_wwan_tiocmset(struct tty_struct *tty, struct file *file,
}
EXPORT_SYMBOL(usb_wwan_tiocmset);
+static int get_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.line = port->serial->minor;
+ tmp.port = port->number;
+ tmp.baud_base = tty_get_baud_rate(port->port.tty);
+ tmp.close_delay = port->port.close_delay / 10;
+ tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+ ASYNC_CLOSING_WAIT_NONE :
+ port->port.closing_wait / 10;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_serial_info(struct usb_serial_port *port,
+ 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(&port->port.mutex);
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((close_delay != port->port.close_delay) ||
+ (closing_wait != port->port.closing_wait))
+ retval = -EPERM;
+ else
+ retval = -EOPNOTSUPP;
+ } else {
+ port->port.close_delay = close_delay;
+ port->port.closing_wait = closing_wait;
+ }
+
+ mutex_unlock(&port->port.mutex);
+ return retval;
+}
+
+int usb_wwan_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ dbg("%s cmd 0x%04x", __func__, cmd);
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return get_serial_info(port,
+ (struct serial_struct __user *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(port,
+ (struct serial_struct __user *) arg);
+ default:
+ break;
+ }
+
+ dbg("%s arg not supported", __func__);
+
+ return -ENOIOCTLCMD;
+}
+EXPORT_SYMBOL(usb_wwan_ioctl);
+
/* Write */
int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)