diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-11-02 17:42:47 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-11-02 17:42:47 +0100 |
commit | 29ce32ecca842d73cd1c82f540a6fbde5d1ad44b (patch) | |
tree | fef1707d4ff01247d0dd969aba2a8844cfbe04db /drivers/usb | |
parent | dc586a60a11d0260308db1bebe788ad8973e2729 (diff) | |
parent | 7c36e6e14da53a0a9c0893c363163afe629b2ee5 (diff) |
Merge tag 'usb-serial-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next
Johan writes:
USB-serial updates for v4.15-rc1
Here are the USB-serial updates for 4.15-rc1, including:
- three fixes for longstanding issues in garmin_gps and metro-usb which
could lead to NULL-pointer dereferences and memory leaks
- a workaround for broken f81534 firmware-handling of overruns
- f81534 break support, and
- conversion to timer_setup()
Included are also various clean ups and a new qcserial device id.
All have been in linux-next with no reported issues.
Signed-off-by: Johan Hovold <johan@kernel.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/serial/f81534.c | 90 | ||||
-rw-r--r-- | drivers/usb/serial/garmin_gps.c | 67 | ||||
-rw-r--r-- | drivers/usb/serial/kobil_sct.c | 1 | ||||
-rw-r--r-- | drivers/usb/serial/metro-usb.c | 41 | ||||
-rw-r--r-- | drivers/usb/serial/qcserial.c | 1 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 22 |
6 files changed, 147 insertions, 75 deletions
diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 3d616a2a9f96..cb8214860192 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -39,9 +39,11 @@ #define F81534_UART_OFFSET 0x10 #define F81534_DIVISOR_LSB_REG (0x00 + F81534_UART_BASE_ADDRESS) #define F81534_DIVISOR_MSB_REG (0x01 + F81534_UART_BASE_ADDRESS) +#define F81534_INTERRUPT_ENABLE_REG (0x01 + F81534_UART_BASE_ADDRESS) #define F81534_FIFO_CONTROL_REG (0x02 + F81534_UART_BASE_ADDRESS) #define F81534_LINE_CONTROL_REG (0x03 + F81534_UART_BASE_ADDRESS) #define F81534_MODEM_CONTROL_REG (0x04 + F81534_UART_BASE_ADDRESS) +#define F81534_LINE_STATUS_REG (0x05 + F81534_UART_BASE_ADDRESS) #define F81534_MODEM_STATUS_REG (0x06 + F81534_UART_BASE_ADDRESS) #define F81534_CONFIG1_REG (0x09 + F81534_UART_BASE_ADDRESS) @@ -126,9 +128,13 @@ struct f81534_serial_private { struct f81534_port_private { struct mutex mcr_mutex; + struct mutex lcr_mutex; + struct work_struct lsr_work; + struct usb_serial_port *port; unsigned long tx_empty; spinlock_t msr_lock; u8 shadow_mcr; + u8 shadow_lcr; u8 shadow_msr; u8 phy_num; }; @@ -461,6 +467,7 @@ static u32 f81534_calc_baud_divisor(u32 baudrate, u32 clockrate) static int f81534_set_port_config(struct usb_serial_port *port, u32 baudrate, u8 lcr) { + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); u32 divisor; int status; u8 value; @@ -489,35 +496,65 @@ static int f81534_set_port_config(struct usb_serial_port *port, u32 baudrate, } divisor = f81534_calc_baud_divisor(baudrate, F81534_MAX_BAUDRATE); + + mutex_lock(&port_priv->lcr_mutex); + value = UART_LCR_DLAB; status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG, value); if (status) { dev_err(&port->dev, "%s: set LCR failed\n", __func__); - return status; + goto out_unlock; } value = divisor & 0xff; status = f81534_set_port_register(port, F81534_DIVISOR_LSB_REG, value); if (status) { dev_err(&port->dev, "%s: set DLAB LSB failed\n", __func__); - return status; + goto out_unlock; } value = (divisor >> 8) & 0xff; status = f81534_set_port_register(port, F81534_DIVISOR_MSB_REG, value); if (status) { dev_err(&port->dev, "%s: set DLAB MSB failed\n", __func__); - return status; + goto out_unlock; } - status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG, lcr); + value = lcr | (port_priv->shadow_lcr & UART_LCR_SBC); + status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG, + value); if (status) { dev_err(&port->dev, "%s: set LCR failed\n", __func__); - return status; + goto out_unlock; } - return 0; + port_priv->shadow_lcr = value; +out_unlock: + mutex_unlock(&port_priv->lcr_mutex); + + return status; +} + +static void f81534_break_ctl(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = tty->driver_data; + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + int status; + + mutex_lock(&port_priv->lcr_mutex); + + if (break_state) + port_priv->shadow_lcr |= UART_LCR_SBC; + else + port_priv->shadow_lcr &= ~UART_LCR_SBC; + + status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG, + port_priv->shadow_lcr); + if (status) + dev_err(&port->dev, "set break failed: %d\n", status); + + mutex_unlock(&port_priv->lcr_mutex); } static int f81534_update_mctrl(struct usb_serial_port *port, unsigned int set, @@ -1015,6 +1052,8 @@ static void f81534_process_per_serial_block(struct usb_serial_port *port, tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); } + + schedule_work(&port_priv->lsr_work); } if (port->port.console && port->sysrq) { @@ -1162,6 +1201,21 @@ static int f81534_attach(struct usb_serial *serial) return 0; } +static void f81534_lsr_worker(struct work_struct *work) +{ + struct f81534_port_private *port_priv; + struct usb_serial_port *port; + int status; + u8 tmp; + + port_priv = container_of(work, struct f81534_port_private, lsr_work); + port = port_priv->port; + + status = f81534_get_port_register(port, F81534_LINE_STATUS_REG, &tmp); + if (status) + dev_warn(&port->dev, "read LSR failed: %d\n", status); +} + static int f81534_port_probe(struct usb_serial_port *port) { struct f81534_port_private *port_priv; @@ -1173,6 +1227,8 @@ static int f81534_port_probe(struct usb_serial_port *port) spin_lock_init(&port_priv->msr_lock); mutex_init(&port_priv->mcr_mutex); + mutex_init(&port_priv->lcr_mutex); + INIT_WORK(&port_priv->lsr_work, f81534_lsr_worker); /* Assign logic-to-phy mapping */ ret = f81534_logic_to_phy_port(port->serial, port); @@ -1180,10 +1236,30 @@ static int f81534_port_probe(struct usb_serial_port *port) return ret; port_priv->phy_num = ret; + port_priv->port = port; usb_set_serial_port_data(port, port_priv); dev_dbg(&port->dev, "%s: port_number: %d, phy_num: %d\n", __func__, port->port_number, port_priv->phy_num); + /* + * The F81532/534 will hang-up when enable LSR interrupt in IER and + * occur data overrun. So we'll disable the LSR interrupt in probe() + * and submit the LSR worker to clear LSR state when reported LSR error + * bit with bulk-in data in f81534_process_per_serial_block(). + */ + ret = f81534_set_port_register(port, F81534_INTERRUPT_ENABLE_REG, + UART_IER_RDI | UART_IER_THRI | UART_IER_MSI); + if (ret) + return ret; + + return 0; +} + +static int f81534_port_remove(struct usb_serial_port *port) +{ + struct f81534_port_private *port_priv = usb_get_serial_port_data(port); + + flush_work(&port_priv->lsr_work); return 0; } @@ -1317,6 +1393,8 @@ static struct usb_serial_driver f81534_device = { .calc_num_ports = f81534_calc_num_ports, .attach = f81534_attach, .port_probe = f81534_port_probe, + .port_remove = f81534_port_remove, + .break_ctl = f81534_break_ctl, .dtr_rts = f81534_dtr_rts, .process_read_urb = f81534_process_read_urb, .ioctl = f81534_ioctl, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index b2f2e87aed94..4f793c86978e 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -138,6 +138,7 @@ struct garmin_data { __u8 privpkt[4*6]; spinlock_t lock; struct list_head pktlist; + struct usb_anchor write_urbs; }; @@ -875,42 +876,38 @@ static int garmin_clear(struct garmin_data *garmin_data_p) static int garmin_init_session(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - int status = 0; - int i = 0; + int status; + int i; - if (status == 0) { - usb_kill_urb(port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); - dev_dbg(&serial->dev->dev, "%s - adding interrupt input\n", __func__); - status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (status) - dev_err(&serial->dev->dev, - "%s - failed submitting interrupt urb, error %d\n", - __func__, status); + status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (status) { + dev_err(&port->dev, "failed to submit interrupt urb: %d\n", + status); + return status; } /* * using the initialization method from gpsbabel. See comments in * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles() */ - if (status == 0) { - dev_dbg(&serial->dev->dev, "%s - starting session ...\n", __func__); - garmin_data_p->state = STATE_ACTIVE; + dev_dbg(&port->dev, "%s - starting session ...\n", __func__); + garmin_data_p->state = STATE_ACTIVE; - for (i = 0; i < 3; i++) { - status = garmin_write_bulk(port, - GARMIN_START_SESSION_REQ, - sizeof(GARMIN_START_SESSION_REQ), 0); + for (i = 0; i < 3; i++) { + status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ, + sizeof(GARMIN_START_SESSION_REQ), 0); + if (status < 0) + goto err_kill_urbs; + } - if (status < 0) - break; - } + return 0; - if (status > 0) - status = 0; - } +err_kill_urbs: + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); + usb_kill_urb(port->interrupt_in_urb); return status; } @@ -930,7 +927,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) spin_unlock_irqrestore(&garmin_data_p->lock, flags); /* shutdown any bulk reads that might be going on */ - usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); if (garmin_data_p->state == STATE_RESET) @@ -953,7 +949,7 @@ static void garmin_close(struct usb_serial_port *port) /* shutdown our urbs */ usb_kill_urb(port->read_urb); - usb_kill_urb(port->write_urb); + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); /* keep reset state so we know that we must start a new session */ if (garmin_data_p->state != STATE_RESET) @@ -1037,12 +1033,14 @@ static int garmin_write_bulk(struct usb_serial_port *port, } /* send it down the pipe */ + usb_anchor_urb(urb, &garmin_data_p->write_urbs); status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status); count = status; + usb_unanchor_urb(urb); kfree(buffer); } @@ -1370,9 +1368,9 @@ static void garmin_unthrottle(struct tty_struct *tty) * the tty in cases where the protocol provides no own handshaking * to initiate the transfer. */ -static void timeout_handler(unsigned long data) +static void timeout_handler(struct timer_list *t) { - struct garmin_data *garmin_data_p = (struct garmin_data *) data; + struct garmin_data *garmin_data_p = from_timer(garmin_data_p, t, timer); /* send the next queued packet to the tty port */ if (garmin_data_p->mode == MODE_NATIVE) @@ -1391,19 +1389,23 @@ static int garmin_port_probe(struct usb_serial_port *port) if (!garmin_data_p) return -ENOMEM; - init_timer(&garmin_data_p->timer); + timer_setup(&garmin_data_p->timer, timeout_handler, 0); spin_lock_init(&garmin_data_p->lock); INIT_LIST_HEAD(&garmin_data_p->pktlist); - /* garmin_data_p->timer.expires = jiffies + session_timeout; */ - garmin_data_p->timer.data = (unsigned long)garmin_data_p; - garmin_data_p->timer.function = timeout_handler; garmin_data_p->port = port; garmin_data_p->state = 0; garmin_data_p->flags = 0; garmin_data_p->count = 0; + init_usb_anchor(&garmin_data_p->write_urbs); usb_set_serial_port_data(port, garmin_data_p); status = garmin_init_session(port); + if (status) + goto err_free; + + return 0; +err_free: + kfree(garmin_data_p); return status; } @@ -1413,6 +1415,7 @@ static int garmin_port_remove(struct usb_serial_port *port) { struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); usb_kill_urb(port->interrupt_in_urb); del_timer_sync(&garmin_data_p->timer); kfree(garmin_data_p); diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 3024b9b25360..2f8fa3589b20 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -491,6 +491,7 @@ static void kobil_set_termios(struct tty_struct *tty, break; default: speed = 9600; + /* fall through */ case 9600: urb_val = SUSBCR_SBR_9600; break; diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 14511d6a7d44..36f65df41721 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -54,21 +54,33 @@ MODULE_DEVICE_TABLE(usb, id_table); #define UNI_CMD_OPEN 0x80 #define UNI_CMD_CLOSE 0xFF -static inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port) +static int metrousb_is_unidirectional_mode(struct usb_serial *serial) { - __u16 product_id = le16_to_cpu( - port->serial->dev->descriptor.idProduct); + u16 product_id = le16_to_cpu(serial->dev->descriptor.idProduct); return product_id == FOCUS_PRODUCT_ID_UNI; } +static int metrousb_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) +{ + if (metrousb_is_unidirectional_mode(serial)) { + if (epds->num_interrupt_out == 0) { + dev_err(&serial->interface->dev, "interrupt-out endpoint missing\n"); + return -ENODEV; + } + } + + return 1; +} + static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port) { int ret; int actual_len; u8 *buffer_cmd = NULL; - if (!metrousb_is_unidirectional_mode(port)) + if (!metrousb_is_unidirectional_mode(port->serial)) return 0; buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL); @@ -161,13 +173,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags = 0; int result = 0; - /* Make sure the urb is initialized. */ - if (!port->interrupt_in_urb) { - dev_err(&port->dev, "%s - interrupt urb not initialized\n", - __func__); - return -ENODEV; - } - /* Set the private data information for the port. */ spin_lock_irqsave(&metro_priv->lock, flags); metro_priv->control_state = 0; @@ -189,7 +194,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "%s - failed submitting interrupt in urb, error code=%d\n", __func__, result); - goto exit; + return result; } /* Send activate cmd to device */ @@ -198,9 +203,14 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "%s - failed to configure device, error code=%d\n", __func__, result); - goto exit; + goto err_kill_urb; } -exit: + + return 0; + +err_kill_urb: + usb_kill_urb(port->interrupt_in_urb); + return result; } @@ -337,7 +347,8 @@ static struct usb_serial_driver metrousb_device = { }, .description = "Metrologic USB to Serial", .id_table = id_table, - .num_ports = 1, + .num_interrupt_in = 1, + .calc_num_ports = metrousb_calc_num_ports, .open = metrousb_open, .close = metrousb_cleanup, .read_int_callback = metrousb_read_int_callback, diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index eb9928963a53..9f9d3a904464 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -148,6 +148,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x1199, 0x68a2)}, /* Sierra Wireless MC7710 */ {DEVICE_SWI(0x1199, 0x68c0)}, /* Sierra Wireless MC7304/MC7354 */ {DEVICE_SWI(0x1199, 0x901c)}, /* Sierra Wireless EM7700 */ + {DEVICE_SWI(0x1199, 0x901e)}, /* Sierra Wireless EM7355 QDL */ {DEVICE_SWI(0x1199, 0x901f)}, /* Sierra Wireless EM7355 */ {DEVICE_SWI(0x1199, 0x9040)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9041)}, /* Sierra Wireless MC7305/MC7355 */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index bb34f9f7eaf4..20639d5b8886 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1201,17 +1201,6 @@ static const struct tty_operations serial_ops = { struct tty_driver *usb_serial_tty_driver; -/* Driver structure we register with the USB core */ -static struct usb_driver usb_serial_driver = { - .name = "usbserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - static int __init usb_serial_init(void) { int result; @@ -1247,13 +1236,6 @@ static int __init usb_serial_init(void) goto exit_reg_driver; } - /* register the USB driver */ - result = usb_register(&usb_serial_driver); - if (result < 0) { - pr_err("%s - usb_register failed\n", __func__); - goto exit_tty; - } - /* register the generic driver, if we should */ result = usb_serial_generic_register(); if (result < 0) { @@ -1264,9 +1246,6 @@ static int __init usb_serial_init(void) return result; exit_generic: - usb_deregister(&usb_serial_driver); - -exit_tty: tty_unregister_driver(usb_serial_tty_driver); exit_reg_driver: @@ -1285,7 +1264,6 @@ static void __exit usb_serial_exit(void) usb_serial_generic_deregister(); - usb_deregister(&usb_serial_driver); tty_unregister_driver(usb_serial_tty_driver); put_tty_driver(usb_serial_tty_driver); bus_unregister(&usb_serial_bus_type); |