diff options
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/ark3116.c | 38 | ||||
-rw-r--r-- | drivers/usb/serial/cypress_m8.c | 7 | ||||
-rw-r--r-- | drivers/usb/serial/f81232.c | 36 | ||||
-rw-r--r-- | drivers/usb/serial/f81534.c | 38 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 439 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.h | 28 | ||||
-rw-r--r-- | drivers/usb/serial/io_edgeport.c | 37 | ||||
-rw-r--r-- | drivers/usb/serial/io_ti.c | 47 | ||||
-rw-r--r-- | drivers/usb/serial/mos7720.c | 86 | ||||
-rw-r--r-- | drivers/usb/serial/mos7840.c | 39 | ||||
-rw-r--r-- | drivers/usb/serial/opticon.c | 43 | ||||
-rw-r--r-- | drivers/usb/serial/option.c | 3 | ||||
-rw-r--r-- | drivers/usb/serial/pl2303.c | 29 | ||||
-rw-r--r-- | drivers/usb/serial/quatech2.c | 42 | ||||
-rw-r--r-- | drivers/usb/serial/ssu100.c | 42 | ||||
-rw-r--r-- | drivers/usb/serial/ti_usb_3410_5052.c | 74 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 20 | ||||
-rw-r--r-- | drivers/usb/serial/usb-wwan.h | 6 | ||||
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 63 | ||||
-rw-r--r-- | drivers/usb/serial/whiteheat.c | 42 |
20 files changed, 645 insertions, 514 deletions
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 7796ad8e33c6..ff38aa8963cf 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -397,38 +397,16 @@ err_free: return result; } -static int ark3116_get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16654; - tmp.line = port->minor; - tmp.port = port->port_number; - tmp.baud_base = 460800; - - if (copy_to_user(retinfo, &tmp, sizeof(tmp))) - return -EFAULT; - - return 0; -} - -static int ark3116_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int ark3116_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - void __user *user_arg = (void __user *)arg; - - switch (cmd) { - case TIOCGSERIAL: - return ark3116_get_serial_info(port, user_arg); - default: - break; - } - return -ENOIOCTLCMD; + ss->type = PORT_16654; + ss->line = port->minor; + ss->port = port->port_number; + ss->baud_base = 460800; + return 0; } static int ark3116_tiocmget(struct tty_struct *tty) @@ -668,7 +646,7 @@ static struct usb_serial_driver ark3116_device = { .port_remove = ark3116_port_remove, .set_termios = ark3116_set_termios, .init_termios = ark3116_init_termios, - .ioctl = ark3116_ioctl, + .get_serial = ark3116_get_serial_info, .tiocmget = ark3116_tiocmget, .tiocmset = ark3116_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index e0035c023120..ed51bc48eea6 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -378,7 +378,7 @@ static int cypress_serial_control(struct tty_struct *tty, retval = -ENOTTY; goto out; } - dev_dbg(dev, "%s - retreiving serial line settings\n", __func__); + dev_dbg(dev, "%s - retrieving serial line settings\n", __func__); do { retval = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), @@ -769,7 +769,7 @@ send: usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), - port->interrupt_out_buffer, port->interrupt_out_size, + port->interrupt_out_buffer, actual_size, cypress_write_int_callback, port, priv->write_urb_interval); result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); if (result) { @@ -863,7 +863,7 @@ static void cypress_set_termios(struct tty_struct *tty, struct cypress_private *priv = usb_get_serial_port_data(port); struct device *dev = &port->dev; int data_bits, stop_bits, parity_type, parity_enable; - unsigned cflag, iflag; + unsigned int cflag; unsigned long flags; __u8 oldlines; int linechange = 0; @@ -899,7 +899,6 @@ static void cypress_set_termios(struct tty_struct *tty, tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); cflag = tty->termios.c_cflag; - iflag = tty->termios.c_iflag; /* check if there are new settings */ if (old_termios) { diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 96036f87b1de..0dcdcb4b2cde 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -583,36 +583,16 @@ static int f81232_carrier_raised(struct usb_serial_port *port) return 0; } -static int f81232_get_serial_info(struct usb_serial_port *port, - unsigned long arg) -{ - struct serial_struct ser; - - memset(&ser, 0, sizeof(ser)); - - ser.type = PORT_16550A; - ser.line = port->minor; - ser.port = port->port_number; - ser.baud_base = F81232_MAX_BAUDRATE; - - if (copy_to_user((void __user *)arg, &ser, sizeof(ser))) - return -EFAULT; - - return 0; -} - -static int f81232_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int f81232_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - switch (cmd) { - case TIOCGSERIAL: - return f81232_get_serial_info(port, arg); - default: - break; - } - return -ENOIOCTLCMD; + ss->type = PORT_16550A; + ss->line = port->minor; + ss->port = port->port_number; + ss->baud_base = F81232_MAX_BAUDRATE; + return 0; } static void f81232_interrupt_work(struct work_struct *work) @@ -665,7 +645,7 @@ static struct usb_serial_driver f81232_device = { .close = f81232_close, .dtr_rts = f81232_dtr_rts, .carrier_raised = f81232_carrier_raised, - .ioctl = f81232_ioctl, + .get_serial = f81232_get_serial_info, .break_ctl = f81232_break_ctl, .set_termios = f81232_set_termios, .tiocmget = f81232_tiocmget, diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 4dfbff20bda4..380933db34dd 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1139,43 +1139,21 @@ static void f81534_close(struct usb_serial_port *port) mutex_unlock(&serial_priv->urb_mutex); } -static int f81534_get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) +static int f81534_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { + struct usb_serial_port *port = tty->driver_data; struct f81534_port_private *port_priv; - struct serial_struct tmp; port_priv = usb_get_serial_port_data(port); - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.port = port->port_number; - tmp.line = port->minor; - tmp.baud_base = port_priv->baud_base; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - + ss->type = PORT_16550A; + ss->port = port->port_number; + ss->line = port->minor; + ss->baud_base = port_priv->baud_base; return 0; } -static int f81534_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct serial_struct __user *buf = (struct serial_struct __user *)arg; - - switch (cmd) { - case TIOCGSERIAL: - return f81534_get_serial_info(port, buf); - default: - break; - } - - return -ENOIOCTLCMD; -} - static void f81534_process_per_serial_block(struct usb_serial_port *port, u8 *data) { @@ -1581,7 +1559,7 @@ static struct usb_serial_driver f81534_device = { .break_ctl = f81534_break_ctl, .dtr_rts = f81534_dtr_rts, .process_read_urb = f81534_process_read_urb, - .ioctl = f81534_ioctl, + .get_serial = f81534_get_serial_info, .tiocmget = f81534_tiocmget, .tiocmset = f81534_tiocmset, .write_bulk_callback = f81534_write_usb_callback, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b5cef322826f..609198d9594c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -39,6 +39,7 @@ #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/serial.h> +#include <linux/gpio/driver.h> #include <linux/usb/serial.h> #include "ftdi_sio.h" #include "ftdi_sio_ids.h" @@ -72,6 +73,15 @@ struct ftdi_private { unsigned int latency; /* latency setting in use */ unsigned short max_packet_size; struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */ +#ifdef CONFIG_GPIOLIB + struct gpio_chip gc; + struct mutex gpio_lock; /* protects GPIO state */ + bool gpio_registered; /* is the gpiochip in kernel registered */ + bool gpio_used; /* true if the user requested a gpio */ + u8 gpio_altfunc; /* which pins are in gpio mode */ + u8 gpio_output; /* pin directions cache */ + u8 gpio_value; /* pin value for outputs */ +#endif }; /* struct ftdi_sio_quirk is used by devices requiring special attention. */ @@ -1055,6 +1065,10 @@ static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss); +static int set_serial_info(struct tty_struct *tty, + struct serial_struct *ss); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); static bool ftdi_tx_empty(struct usb_serial_port *port); static int ftdi_get_modem_status(struct usb_serial_port *port, @@ -1091,6 +1105,8 @@ static struct usb_serial_driver ftdi_sio_device = { .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .ioctl = ftdi_ioctl, + .get_serial = get_serial_info, + .set_serial = set_serial_info, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, .tx_empty = ftdi_tx_empty, @@ -1443,48 +1459,42 @@ static int read_latency_timer(struct usb_serial_port *port) return 0; } -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { + struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); - struct serial_struct tmp; - memset(&tmp, 0, sizeof(tmp)); - tmp.flags = priv->flags; - tmp.baud_base = priv->baud_base; - tmp.custom_divisor = priv->custom_divisor; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->flags = priv->flags; + ss->baud_base = priv->baud_base; + ss->custom_divisor = priv->custom_divisor; return 0; } static int set_serial_info(struct tty_struct *tty, - struct usb_serial_port *port, struct serial_struct __user *newinfo) + struct serial_struct *ss) { + struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); - struct serial_struct new_serial; struct ftdi_private old_priv; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - mutex_lock(&priv->cfg_lock); old_priv = *priv; /* Do error checking and permission checking */ if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.flags ^ priv->flags) & ~ASYNC_USR_MASK) { + if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) { mutex_unlock(&priv->cfg_lock); return -EPERM; } priv->flags = ((priv->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - priv->custom_divisor = new_serial.custom_divisor; + (ss->flags & ASYNC_USR_MASK)); + priv->custom_divisor = ss->custom_divisor; goto check_and_exit; } - if (new_serial.baud_base != priv->baud_base) { + if (ss->baud_base != priv->baud_base) { mutex_unlock(&priv->cfg_lock); return -EINVAL; } @@ -1492,8 +1502,8 @@ static int set_serial_info(struct tty_struct *tty, /* Make the changes - these are privileged changes! */ priv->flags = ((priv->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - priv->custom_divisor = new_serial.custom_divisor; + (ss->flags & ASYNC_FLAGS)); + priv->custom_divisor = ss->custom_divisor; check_and_exit: write_latency_timer(port); @@ -1507,10 +1517,8 @@ check_and_exit: dev_warn_ratelimited(&port->dev, "use of SPD flags is deprecated\n"); change_speed(tty, port); - mutex_unlock(&priv->cfg_lock); } - else - mutex_unlock(&priv->cfg_lock); + mutex_unlock(&priv->cfg_lock); return 0; } @@ -1766,6 +1774,375 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) } +#ifdef CONFIG_GPIOLIB + +static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + int result; + u16 val; + + val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value; + result = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + FTDI_SIO_SET_BITMODE_REQUEST, + FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val, + priv->interface, NULL, 0, WDR_TIMEOUT); + if (result < 0) { + dev_err(&serial->interface->dev, + "bitmode request failed for value 0x%04x: %d\n", + val, result); + } + + return result; +} + +static int ftdi_set_cbus_pins(struct usb_serial_port *port) +{ + return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_CBUS); +} + +static int ftdi_exit_cbus_mode(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + + priv->gpio_output = 0; + priv->gpio_value = 0; + return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_RESET); +} + +static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + int result; + + if (priv->gpio_altfunc & BIT(offset)) + return -ENODEV; + + mutex_lock(&priv->gpio_lock); + if (!priv->gpio_used) { + /* Set default pin states, as we cannot get them from device */ + priv->gpio_output = 0x00; + priv->gpio_value = 0x00; + result = ftdi_set_cbus_pins(port); + if (result) { + mutex_unlock(&priv->gpio_lock); + return result; + } + + priv->gpio_used = true; + } + mutex_unlock(&priv->gpio_lock); + + return 0; +} + +static int ftdi_read_cbus_pins(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + unsigned char *buf; + int result; + + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + FTDI_SIO_READ_PINS_REQUEST, + FTDI_SIO_READ_PINS_REQUEST_TYPE, 0, + priv->interface, buf, 1, WDR_TIMEOUT); + if (result < 1) { + if (result >= 0) + result = -EIO; + } else { + result = buf[0]; + } + + kfree(buf); + + return result; +} + +static int ftdi_gpio_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + int result; + + result = ftdi_read_cbus_pins(port); + if (result < 0) + return result; + + return !!(result & BIT(gpio)); +} + +static void ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + + mutex_lock(&priv->gpio_lock); + + if (value) + priv->gpio_value |= BIT(gpio); + else + priv->gpio_value &= ~BIT(gpio); + + ftdi_set_cbus_pins(port); + + mutex_unlock(&priv->gpio_lock); +} + +static int ftdi_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + int result; + + result = ftdi_read_cbus_pins(port); + if (result < 0) + return result; + + *bits = result & *mask; + + return 0; +} + +static void ftdi_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + + mutex_lock(&priv->gpio_lock); + + priv->gpio_value &= ~(*mask); + priv->gpio_value |= *bits & *mask; + ftdi_set_cbus_pins(port); + + mutex_unlock(&priv->gpio_lock); +} + +static int ftdi_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + + return !(priv->gpio_output & BIT(gpio)); +} + +static int ftdi_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + int result; + + mutex_lock(&priv->gpio_lock); + + priv->gpio_output &= ~BIT(gpio); + result = ftdi_set_cbus_pins(port); + + mutex_unlock(&priv->gpio_lock); + + return result; +} + +static int ftdi_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, + int value) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + int result; + + mutex_lock(&priv->gpio_lock); + + priv->gpio_output |= BIT(gpio); + if (value) + priv->gpio_value |= BIT(gpio); + else + priv->gpio_value &= ~BIT(gpio); + + result = ftdi_set_cbus_pins(port); + + mutex_unlock(&priv->gpio_lock); + + return result; +} + +static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr, + u16 nbytes) +{ + int read = 0; + + if (addr % 2 != 0) + return -EINVAL; + if (nbytes % 2 != 0) + return -EINVAL; + + /* Read EEPROM two bytes at a time */ + while (read < nbytes) { + int rv; + + rv = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + FTDI_SIO_READ_EEPROM_REQUEST, + FTDI_SIO_READ_EEPROM_REQUEST_TYPE, + 0, (addr + read) / 2, dst + read, 2, + WDR_TIMEOUT); + if (rv < 2) { + if (rv >= 0) + return -EIO; + else + return rv; + } + + read += rv; + } + + return 0; +} + +static int ftdi_gpio_init_ft232r(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + u16 cbus_config; + u8 *buf; + int ret; + int i; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = ftdi_read_eeprom(port->serial, buf, 0x14, 2); + if (ret < 0) + goto out_free; + + cbus_config = le16_to_cpup((__le16 *)buf); + dev_dbg(&port->dev, "cbus_config = 0x%04x\n", cbus_config); + + priv->gc.ngpio = 4; + + priv->gpio_altfunc = 0xff; + for (i = 0; i < priv->gc.ngpio; ++i) { + if ((cbus_config & 0xf) == FTDI_FT232R_CBUS_MUX_GPIO) + priv->gpio_altfunc &= ~BIT(i); + cbus_config >>= 4; + } +out_free: + kfree(buf); + + return ret; +} + +static int ftdi_gpio_init_ftx(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + const u16 cbus_cfg_addr = 0x1a; + const u16 cbus_cfg_size = 4; + u8 *cbus_cfg_buf; + int result; + u8 i; + + cbus_cfg_buf = kmalloc(cbus_cfg_size, GFP_KERNEL); + if (!cbus_cfg_buf) + return -ENOMEM; + + result = ftdi_read_eeprom(serial, cbus_cfg_buf, + cbus_cfg_addr, cbus_cfg_size); + if (result < 0) + goto out_free; + + /* FIXME: FT234XD alone has 1 GPIO, but how to recognize this IC? */ + priv->gc.ngpio = 4; + + /* Determine which pins are configured for CBUS bitbanging */ + priv->gpio_altfunc = 0xff; + for (i = 0; i < priv->gc.ngpio; ++i) { + if (cbus_cfg_buf[i] == FTDI_FTX_CBUS_MUX_GPIO) + priv->gpio_altfunc &= ~BIT(i); + } + +out_free: + kfree(cbus_cfg_buf); + + return result; +} + +static int ftdi_gpio_init(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + int result; + + switch (priv->chip_type) { + case FT232RL: + result = ftdi_gpio_init_ft232r(port); + break; + case FTX: + result = ftdi_gpio_init_ftx(port); + break; + default: + return 0; + } + + if (result < 0) + return result; + + mutex_init(&priv->gpio_lock); + + priv->gc.label = "ftdi-cbus"; + priv->gc.request = ftdi_gpio_request; + priv->gc.get_direction = ftdi_gpio_direction_get; + priv->gc.direction_input = ftdi_gpio_direction_input; + priv->gc.direction_output = ftdi_gpio_direction_output; + priv->gc.get = ftdi_gpio_get; + priv->gc.set = ftdi_gpio_set; + priv->gc.get_multiple = ftdi_gpio_get_multiple; + priv->gc.set_multiple = ftdi_gpio_set_multiple; + priv->gc.owner = THIS_MODULE; + priv->gc.parent = &serial->interface->dev; + priv->gc.base = -1; + priv->gc.can_sleep = true; + + result = gpiochip_add_data(&priv->gc, port); + if (!result) + priv->gpio_registered = true; + + return result; +} + +static void ftdi_gpio_remove(struct usb_serial_port *port) +{ + struct ftdi_private *priv = usb_get_serial_port_data(port); + + if (priv->gpio_registered) { + gpiochip_remove(&priv->gc); + priv->gpio_registered = false; + } + + if (priv->gpio_used) { + /* Exiting CBUS-mode does not reset pin states. */ + ftdi_exit_cbus_mode(port); + priv->gpio_used = false; + } +} + +#else + +static int ftdi_gpio_init(struct usb_serial_port *port) +{ + return 0; +} + +static void ftdi_gpio_remove(struct usb_serial_port *port) { } + +#endif /* CONFIG_GPIOLIB */ + /* * *************************************************************************** * FTDI driver specific functions @@ -1794,7 +2171,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) { struct ftdi_private *priv; const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); - + int result; priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv) @@ -1813,6 +2190,14 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) priv->latency = 16; write_latency_timer(port); create_sysfs_attrs(port); + + result = ftdi_gpio_init(port); + if (result < 0) { + dev_err(&port->serial->interface->dev, + "GPIO initialisation failed: %d\n", + result); + } + return 0; } @@ -1930,6 +2315,8 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); + ftdi_gpio_remove(port); + remove_sysfs_attrs(port); kfree(priv); @@ -2452,10 +2839,6 @@ static int ftdi_ioctl(struct tty_struct *tty, void __user *argp = (void __user *)arg; switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, argp); - case TIOCSSERIAL: - return set_serial_info(tty, port, argp); case TIOCSERGETLSR: return get_lsr_info(port, argp); default: diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index dcd0b6e05baf..a79a1325b4d9 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -35,7 +35,10 @@ #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ #define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ -#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ +#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */ +#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */ +#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */ +#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */ /* Interface indices for FT2232, FT2232H and FT4232H devices */ #define INTERFACE_A 1 @@ -433,6 +436,29 @@ enum ftdi_sio_baudrate { * 1 = active */ +/* FTDI_SIO_SET_BITMODE */ +#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE + +/* Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST */ +#define FTDI_SIO_BITMODE_RESET 0x00 +#define FTDI_SIO_BITMODE_CBUS 0x20 + +/* FTDI_SIO_READ_PINS */ +#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS + +/* + * FTDI_SIO_READ_EEPROM + * + * EEPROM format found in FTDI AN_201, "FT-X MTP memory Configuration", + * http://www.ftdichip.com/Support/Documents/AppNotes/AN_201_FT-X%20MTP%20Memory%20Configuration.pdf + */ +#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM + +#define FTDI_FTX_CBUS_MUX_GPIO 0x8 +#define FTDI_FT232R_CBUS_MUX_GPIO 0xa /* Descriptors returned by the device diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 97c69d373ca6..4ca31c0e4174 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1637,24 +1637,20 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct edgeport_port *edge_port, - struct serial_struct __user *retinfo) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = edge_port->port->minor; - tmp.port = edge_port->port->port_number; - tmp.irq = 0; - tmp.xmit_fifo_size = edge_port->maxTxCredits; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; + struct usb_serial_port *port = tty->driver_data; + struct edgeport_port *edge_port = usb_get_serial_port_data(port); - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = edge_port->port->minor; + ss->port = edge_port->port->port_number; + ss->irq = 0; + ss->xmit_fifo_size = edge_port->maxTxCredits; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; return 0; } @@ -1667,17 +1663,12 @@ static int edge_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - DEFINE_WAIT(wait); struct edgeport_port *edge_port = usb_get_serial_port_data(port); switch (cmd) { case TIOCSERGETLSR: dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return get_lsr_info(edge_port, (unsigned int __user *) arg); - - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); - return get_serial_info(edge_port, (struct serial_struct __user *) arg); } return -ENOIOCTLCMD; } @@ -3126,6 +3117,7 @@ static struct usb_serial_driver edgeport_2port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3161,6 +3153,7 @@ static struct usb_serial_driver edgeport_4port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3196,6 +3189,7 @@ static struct usb_serial_driver edgeport_8port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3231,6 +3225,7 @@ static struct usb_serial_driver epic_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, + .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 6d1d6efa3055..c327d4cf7928 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2437,47 +2437,28 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct edgeport_port *edge_port, - struct serial_struct __user *retinfo) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; + struct usb_serial_port *port = tty->driver_data; + struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned cwait; cwait = edge_port->port->port.closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) cwait = jiffies_to_msecs(cwait) / 10; - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = edge_port->port->minor; - tmp.port = edge_port->port->port_number; - tmp.irq = 0; - tmp.xmit_fifo_size = edge_port->port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = cwait; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = edge_port->port->minor; + ss->port = edge_port->port->port_number; + ss->irq = 0; + ss->xmit_fifo_size = edge_port->port->bulk_out_size; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = cwait; return 0; } -static int edge_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - - switch (cmd) { - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); - return get_serial_info(edge_port, - (struct serial_struct __user *) arg); - } - return -ENOIOCTLCMD; -} - static void edge_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; @@ -2738,7 +2719,7 @@ static struct usb_serial_driver edgeport_1port_device = { .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .ioctl = edge_ioctl, + .get_serial = get_serial_info, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, @@ -2777,7 +2758,7 @@ static struct usb_serial_driver edgeport_2port_device = { .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .ioctl = edge_ioctl, + .get_serial = get_serial_info, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 27109522fd8b..fc52ac75fbf6 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1786,69 +1786,20 @@ static int mos7720_tiocmset(struct tty_struct *tty, return 0; } -static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, - unsigned int __user *value) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - unsigned int mcr; - unsigned int arg; - - struct usb_serial_port *port; - - if (mos7720_port == NULL) - return -1; - - port = (struct usb_serial_port *)mos7720_port->port; - mcr = mos7720_port->shadowMCR; - - if (copy_from_user(&arg, value, sizeof(int))) - return -EFAULT; - - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (arg & TIOCM_DTR) - mcr |= UART_MCR_RTS; - if (arg & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) - mcr &= ~UART_MCR_RTS; - if (arg & TIOCM_DTR) - mcr &= ~UART_MCR_RTS; - if (arg & TIOCM_LOOP) - mcr &= ~UART_MCR_LOOP; - break; - - } - - mos7720_port->shadowMCR = mcr; - write_mos_reg(port->serial, port->port_number, MOS7720_MCR, - mos7720_port->shadowMCR); - - return 0; -} - -static int get_serial_info(struct moschip_port *mos7720_port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = mos7720_port->port->minor; - tmp.port = mos7720_port->port->port_number; - tmp.irq = 0; - tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; + struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7720_port = usb_get_serial_port_data(port); - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = mos7720_port->port->minor; + ss->port = mos7720_port->port->port_number; + ss->irq = 0; + ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; return 0; } @@ -1867,18 +1818,6 @@ static int mos7720_ioctl(struct tty_struct *tty, dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return get_lsr_info(tty, mos7720_port, (unsigned int __user *)arg); - - /* FIXME: These should be using the mode methods */ - case TIOCMBIS: - case TIOCMBIC: - dev_dbg(&port->dev, "%s TIOCMSET/TIOCMBIC/TIOCMSET\n", __func__); - return set_modem_info(mos7720_port, cmd, - (unsigned int __user *)arg); - - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); - return get_serial_info(mos7720_port, - (struct serial_struct __user *)arg); } return -ENOIOCTLCMD; @@ -2015,6 +1954,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { .ioctl = mos7720_ioctl, .tiocmget = mos7720_tiocmget, .tiocmset = mos7720_tiocmset, + .get_serial = get_serial_info, .set_termios = mos7720_set_termios, .write = mos7720_write, .write_room = mos7720_write_room, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index b42bad85097a..88828b4b8c44 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1931,27 +1931,20 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, * function to get information about serial port *****************************************************************************/ -static int mos7840_get_serial_info(struct moschip_port *mos7840_port, - struct serial_struct __user *retinfo) +static int mos7840_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - if (mos7840_port == NULL) - return -1; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = mos7840_port->port->minor; - tmp.port = mos7840_port->port->port_number; - tmp.irq = 0; - tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - tmp.baud_base = 9600; - tmp.close_delay = 5 * HZ; - tmp.closing_wait = 30 * HZ; + struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7840_port = mos7840_get_port_private(port); - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = mos7840_port->port->minor; + ss->port = mos7840_port->port->port_number; + ss->irq = 0; + ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; + ss->baud_base = 9600; + ss->close_delay = 5 * HZ; + ss->closing_wait = 30 * HZ; return 0; } @@ -1982,13 +1975,6 @@ static int mos7840_ioctl(struct tty_struct *tty, dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); return mos7840_get_lsr_info(tty, argp); - case TIOCGSERIAL: - dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); - return mos7840_get_serial_info(mos7840_port, argp); - - case TIOCSSERIAL: - dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__); - break; default: break; } @@ -2376,6 +2362,7 @@ static struct usb_serial_driver moschip7840_4port_device = { .calc_num_ports = mos7840_calc_num_ports, .probe = mos7840_probe, .ioctl = mos7840_ioctl, + .get_serial = mos7840_get_serial_info, .set_termios = mos7840_set_termios, .break_ctl = mos7840_break, .tiocmget = mos7840_tiocmget, diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index caa0746326fd..cb7aac9cd9e7 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -328,42 +328,23 @@ static int opticon_tiocmset(struct tty_struct *tty, return 0; } -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *serial) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0x00, sizeof(tmp)); + struct usb_serial_port *port = tty->driver_data; /* fake emulate a 16550 uart to make userspace code happy */ - tmp.type = PORT_16550A; - tmp.line = port->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.xmit_fifo_size = 1024; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(serial, &tmp, sizeof(*serial))) - return -EFAULT; + ss->type = PORT_16550A; + ss->line = port->minor; + ss->port = 0; + ss->irq = 0; + ss->xmit_fifo_size = 1024; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; return 0; } -static int opticon_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *)arg); - } - - return -ENOIOCTLCMD; -} - static int opticon_port_probe(struct usb_serial_port *port) { struct opticon_private *priv; @@ -404,7 +385,7 @@ static struct usb_serial_driver opticon_device = { .write_room = opticon_write_room, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, - .ioctl = opticon_ioctl, + .get_serial = get_serial_info, .tiocmget = opticon_tiocmget, .tiocmset = opticon_tiocmset, .process_read_urb = opticon_process_read_urb, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e72ad9f81c73..e24ff16d4147 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1966,7 +1966,8 @@ static struct usb_serial_driver option_1port_device = { .chars_in_buffer = usb_wwan_chars_in_buffer, .tiocmget = usb_wwan_tiocmget, .tiocmset = usb_wwan_tiocmset, - .ioctl = usb_wwan_ioctl, + .get_serial = usb_wwan_get_serial_info, + .set_serial = usb_wwan_set_serial_info, .attach = option_attach, .release = option_release, .port_probe = usb_wwan_port_probe, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index e41f725ac7aa..a4e0d13fc121 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -808,29 +808,16 @@ static int pl2303_carrier_raised(struct usb_serial_port *port) return 0; } -static int pl2303_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int pl2303_get_serial(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct ser; struct usb_serial_port *port = tty->driver_data; - switch (cmd) { - case TIOCGSERIAL: - memset(&ser, 0, sizeof ser); - ser.type = PORT_16654; - ser.line = port->minor; - ser.port = port->port_number; - ser.baud_base = 460800; - - if (copy_to_user((void __user *)arg, &ser, sizeof ser)) - return -EFAULT; - - return 0; - default: - break; - } - - return -ENOIOCTLCMD; + ss->type = PORT_16654; + ss->line = port->minor; + ss->port = port->port_number; + ss->baud_base = 460800; + return 0; } static void pl2303_set_break(struct usb_serial_port *port, bool enable) @@ -1016,7 +1003,7 @@ static struct usb_serial_driver pl2303_device = { .close = pl2303_close, .dtr_rts = pl2303_dtr_rts, .carrier_raised = pl2303_carrier_raised, - .ioctl = pl2303_ioctl, + .get_serial = pl2303_get_serial, .break_ctl = pl2303_break_ctl, .set_termios = pl2303_set_termios, .tiocmget = pl2303_tiocmget, diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index b61c2a9b6b11..f2fbe1ec9701 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -453,39 +453,19 @@ static void qt2_disconnect(struct usb_serial *serial) usb_kill_urb(serial_priv->read_urb); } -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.xmit_fifo_size = port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int qt2_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *)arg); - default: - break; - } - - return -ENOIOCTLCMD; + ss->line = port->minor; + ss->port = 0; + ss->irq = 0; + ss->xmit_fifo_size = port->bulk_out_size; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; + return 0; } static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) @@ -1013,7 +993,7 @@ static struct usb_serial_driver qt2_device = { .tiocmset = qt2_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .ioctl = qt2_ioctl, + .get_serial = get_serial_info, .set_termios = qt2_set_termios, }; diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 0900b47b5f57..f6aea9f1be1a 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -331,39 +331,19 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) return usb_serial_generic_open(tty, port); } -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.xmit_fifo_size = port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int ssu100_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *) arg); - default: - break; - } - - return -ENOIOCTLCMD; + ss->line = port->minor; + ss->port = 0; + ss->irq = 0; + ss->xmit_fifo_size = port->bulk_out_size; + ss->baud_base = 9600; + ss->close_delay = 5*HZ; + ss->closing_wait = 30*HZ; + return 0; } static int ssu100_attach(struct usb_serial *serial) @@ -566,7 +546,7 @@ static struct usb_serial_driver ssu100_device = { .tiocmset = ssu100_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .ioctl = ssu100_ioctl, + .get_serial = get_serial_info, .set_termios = ssu100_set_termios, }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index e3c5832337e0..dd0ad67aa71e 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -313,8 +313,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty); static bool ti_tx_empty(struct usb_serial_port *port); static void ti_throttle(struct tty_struct *tty); static void ti_unthrottle(struct tty_struct *tty); -static int ti_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); static void ti_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); static int ti_tiocmget(struct tty_struct *tty); @@ -330,10 +328,10 @@ static void ti_recv(struct usb_serial_port *port, unsigned char *data, static void ti_send(struct ti_port *tport); static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); static int ti_get_lsr(struct ti_port *tport, u8 *lsr); -static int ti_get_serial_info(struct ti_port *tport, - struct serial_struct __user *ret_arg); -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, - struct serial_struct __user *new_arg); +static int ti_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss); +static int ti_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss); static void ti_handle_new_msr(struct ti_port *tport, u8 msr); static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); @@ -436,7 +434,8 @@ static struct usb_serial_driver ti_1port_device = { .tx_empty = ti_tx_empty, .throttle = ti_throttle, .unthrottle = ti_unthrottle, - .ioctl = ti_ioctl, + .get_serial = ti_get_serial_info, + .set_serial = ti_set_serial_info, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, @@ -469,7 +468,8 @@ static struct usb_serial_driver ti_2port_device = { .tx_empty = ti_tx_empty, .throttle = ti_throttle, .unthrottle = ti_unthrottle, - .ioctl = ti_ioctl, + .get_serial = ti_get_serial_info, + .set_serial = ti_set_serial_info, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, @@ -902,24 +902,6 @@ static void ti_unthrottle(struct tty_struct *tty) } } -static int ti_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - - switch (cmd) { - case TIOCGSERIAL: - return ti_get_serial_info(tport, - (struct serial_struct __user *)arg); - case TIOCSSERIAL: - return ti_set_serial_info(tty, tport, - (struct serial_struct __user *)arg); - } - return -ENOIOCTLCMD; -} - - static void ti_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -1417,45 +1399,37 @@ free_data: } -static int ti_get_serial_info(struct ti_port *tport, - struct serial_struct __user *ret_arg) +static int ti_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct usb_serial_port *port = tport->tp_port; - struct serial_struct ret_serial; + struct usb_serial_port *port = tty->driver_data; + struct ti_port *tport = usb_get_serial_port_data(port); unsigned cwait; cwait = port->port.closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) cwait = jiffies_to_msecs(cwait) / 10; - memset(&ret_serial, 0, sizeof(ret_serial)); - - ret_serial.type = PORT_16550A; - ret_serial.line = port->minor; - ret_serial.port = port->port_number; - ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo); - ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; - ret_serial.closing_wait = cwait; - - if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg))) - return -EFAULT; - + ss->type = PORT_16550A; + ss->line = port->minor; + ss->port = port->port_number; + ss->xmit_fifo_size = kfifo_size(&port->write_fifo); + ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; + ss->closing_wait = cwait; return 0; } -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, - struct serial_struct __user *new_arg) +static int ti_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct usb_serial_port *port = tty->driver_data; + struct ti_port *tport = usb_get_serial_port_data(port); unsigned cwait; - if (copy_from_user(&new_serial, new_arg, sizeof(new_serial))) - return -EFAULT; - - cwait = new_serial.closing_wait; + cwait = ss->closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = msecs_to_jiffies(10 * new_serial.closing_wait); + cwait = msecs_to_jiffies(10 * ss->closing_wait); tport->tp_port->port.closing_wait = cwait; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index f7aaa7f079e1..7e89efbf2c28 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -396,6 +396,24 @@ static void serial_unthrottle(struct tty_struct *tty) port->serial->type->unthrottle(tty); } +static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) +{ + struct usb_serial_port *port = tty->driver_data; + + if (port->serial->type->get_serial) + return port->serial->type->get_serial(tty, ss); + return -ENOTTY; +} + +static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) +{ + struct usb_serial_port *port = tty->driver_data; + + if (port->serial->type->set_serial) + return port->serial->type->set_serial(tty, ss); + return -ENOTTY; +} + static int serial_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -1177,6 +1195,8 @@ static const struct tty_operations serial_ops = { .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, .get_icount = serial_get_icount, + .set_serial = serial_set_serial, + .get_serial = serial_get_serial, .cleanup = serial_cleanup, .install = serial_install, .proc_show = serial_proc_show, diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index d28dab4b9eff..1c120eaf4091 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -15,8 +15,10 @@ extern int usb_wwan_write_room(struct tty_struct *tty); extern int usb_wwan_tiocmget(struct tty_struct *tty); extern int usb_wwan_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -extern int usb_wwan_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); +extern int usb_wwan_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss); +extern int usb_wwan_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss); extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 912472f26e4f..7e855c87e4f7 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -132,38 +132,32 @@ int usb_wwan_tiocmset(struct tty_struct *tty, } EXPORT_SYMBOL(usb_wwan_tiocmset); -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) +int usb_wwan_get_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->minor; - tmp.port = 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 ? + struct usb_serial_port *port = tty->driver_data; + + ss->line = port->minor; + ss->port = port->port_number; + ss->baud_base = tty_get_baud_rate(port->port.tty); + ss->close_delay = port->port.close_delay / 10; + ss->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; } +EXPORT_SYMBOL(usb_wwan_get_serial_info); -static int set_serial_info(struct usb_serial_port *port, - struct serial_struct __user *newinfo) +int usb_wwan_set_serial_info(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct new_serial; + struct usb_serial_port *port = tty->driver_data; 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; + close_delay = ss->close_delay * 10; + closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10; mutex_lock(&port->port.mutex); @@ -181,30 +175,7 @@ static int set_serial_info(struct usb_serial_port *port, mutex_unlock(&port->port.mutex); return retval; } - -int usb_wwan_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dev_dbg(&port->dev, "%s cmd 0x%04x\n", __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; - } - - dev_dbg(&port->dev, "%s arg not supported\n", __func__); - - return -ENOIOCTLCMD; -} -EXPORT_SYMBOL(usb_wwan_ioctl); +EXPORT_SYMBOL(usb_wwan_set_serial_info); 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/whiteheat.c b/drivers/usb/serial/whiteheat.c index 1c7b46a8620c..aefd84f88b59 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -83,8 +83,8 @@ static int whiteheat_port_remove(struct usb_serial_port *port); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port); static void whiteheat_close(struct usb_serial_port *port); -static int whiteheat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); +static int whiteheat_get_serial(struct tty_struct *tty, + struct serial_struct *ss); static void whiteheat_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int whiteheat_tiocmget(struct tty_struct *tty); @@ -120,7 +120,7 @@ static struct usb_serial_driver whiteheat_device = { .port_remove = whiteheat_port_remove, .open = whiteheat_open, .close = whiteheat_close, - .ioctl = whiteheat_ioctl, + .get_serial = whiteheat_get_serial, .set_termios = whiteheat_set_termios, .break_ctl = whiteheat_break_ctl, .tiocmget = whiteheat_tiocmget, @@ -442,33 +442,21 @@ static int whiteheat_tiocmset(struct tty_struct *tty, } -static int whiteheat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int whiteheat_get_serial(struct tty_struct *tty, + struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - struct serial_struct serstruct; - void __user *user_arg = (void __user *)arg; - - switch (cmd) { - case TIOCGSERIAL: - memset(&serstruct, 0, sizeof(serstruct)); - serstruct.type = PORT_16654; - serstruct.line = port->minor; - serstruct.port = port->port_number; - serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo); - serstruct.custom_divisor = 0; - serstruct.baud_base = 460800; - serstruct.close_delay = CLOSING_DELAY; - serstruct.closing_wait = CLOSING_DELAY; - - if (copy_to_user(user_arg, &serstruct, sizeof(serstruct))) - return -EFAULT; - break; - default: - break; - } - return -ENOIOCTLCMD; + ss->type = PORT_16654; + ss->line = port->minor; + ss->port = port->port_number; + ss->xmit_fifo_size = kfifo_size(&port->write_fifo); + ss->custom_divisor = 0; + ss->baud_base = 460800; + ss->close_delay = CLOSING_DELAY; + ss->closing_wait = CLOSING_DELAY; + + return 0; } |