diff options
Diffstat (limited to 'drivers/usb/serial/quatech2.c')
| -rw-r--r-- | drivers/usb/serial/quatech2.c | 219 |
1 files changed, 77 insertions, 142 deletions
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index d99743290fc1..72fe83a6c978 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -1,21 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* * usb-serial driver for Quatech USB 2 devices * * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * * These devices all have only 1 bulk in and 1 bulk out that is shared * for all serial ports. * */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -62,6 +57,7 @@ #define MAX_BAUD_RATE 921600 #define DEFAULT_BAUD_RATE 9600 +#define QT2_READ_BUFFER_SIZE 512 /* size of read buffer */ #define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */ #define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */ @@ -112,7 +108,7 @@ struct qt2_serial_private { unsigned char current_port; /* current port for incoming data */ struct urb *read_urb; /* shared among all ports */ - char read_buffer[512]; + char *read_buffer; }; struct qt2_port_private { @@ -121,7 +117,7 @@ struct qt2_port_private { spinlock_t urb_lock; bool urb_in_use; struct urb *write_urb; - char write_buffer[QT2_WRITE_BUFFER_SIZE]; + char *write_buffer; spinlock_t lock; u8 shadowLSR; @@ -141,7 +137,9 @@ static void qt2_release(struct usb_serial *serial) serial_priv = usb_get_serial_data(serial); + usb_kill_urb(serial_priv->read_urb); usb_free_urb(serial_priv->read_urb); + kfree(serial_priv->read_buffer); kfree(serial_priv); } @@ -178,30 +176,22 @@ static inline int qt2_control_msg(struct usb_device *dev, NULL, 0, QT2_USB_TIMEOUT); } -static inline int qt2_setdevice(struct usb_device *dev, u8 *data) -{ - u16 x = ((u16) (data[1] << 8) | (u16) (data[0])); - - return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0); -} - - -static inline int qt2_getdevice(struct usb_device *dev, u8 *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_DEVICE, 0xc0, 0, 0, - data, 3, QT2_USB_TIMEOUT); -} - static inline int qt2_getregister(struct usb_device *dev, u8 uart, u8 reg, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_REGISTER, 0xc0, reg, - uart, data, sizeof(*data), QT2_USB_TIMEOUT); + int ret; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), QT2_USB_TIMEOUT); + if (ret < (int)sizeof(*data)) { + if (ret >= 0) + ret = -EIO; + } + + return ret; } static inline int qt2_setregister(struct usb_device *dev, @@ -244,7 +234,8 @@ static inline int update_mctrl(struct qt2_port_private *port_priv, return status; } -static int qt2_calc_num_ports(struct usb_serial *serial) +static int qt2_calc_num_ports(struct usb_serial *serial, + struct usb_serial_endpoints *epds) { struct qt2_device_detail d; int i; @@ -262,8 +253,8 @@ static int qt2_calc_num_ports(struct usb_serial *serial) } static void qt2_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) + struct usb_serial_port *port, + const struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; struct qt2_port_private *port_priv; @@ -282,21 +273,7 @@ static void qt2_set_termios(struct tty_struct *tty, new_lcr |= SERIAL_EVEN_PARITY; } - switch (cflag & CSIZE) { - case CS5: - new_lcr |= UART_LCR_WLEN5; - break; - case CS6: - new_lcr |= UART_LCR_WLEN6; - break; - case CS7: - new_lcr |= UART_LCR_WLEN7; - break; - default: - case CS8: - new_lcr |= UART_LCR_WLEN8; - break; - } + new_lcr |= UART_LCR_WLEN(tty_get_char_size(cflag)); baud = tty_get_baud_rate(tty); if (!baud) @@ -370,9 +347,11 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) 0xc0, 0, device_port, data, 2, QT2_USB_TIMEOUT); - if (status < 0) { - dev_err(&port->dev, "%s - open port failed %i", __func__, + if (status < 2) { + dev_err(&port->dev, "%s - open port failed %i\n", __func__, status); + if (status >= 0) + status = -EIO; kfree(data); return status; } @@ -406,20 +385,16 @@ static void qt2_close(struct usb_serial_port *port) { struct usb_serial *serial; struct qt2_port_private *port_priv; - unsigned long flags; int i; serial = port->serial; port_priv = usb_get_serial_port_data(port); - spin_lock_irqsave(&port_priv->urb_lock, flags); usb_kill_urb(port_priv->write_urb); - port_priv->urb_in_use = false; - spin_unlock_irqrestore(&port_priv->urb_lock, flags); /* flush the port transmit buffer */ i = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), + usb_sndctrlpipe(serial->dev, 0), QT2_FLUSH_DEVICE, 0x40, 1, port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); @@ -429,7 +404,7 @@ static void qt2_close(struct usb_serial_port *port) /* flush the port receive buffer */ i = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), + usb_sndctrlpipe(serial->dev, 0), QT2_FLUSH_DEVICE, 0x40, 0, port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); @@ -456,45 +431,6 @@ 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; - - if (!retinfo) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - 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) -{ - 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; -} - static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) { switch (*ch) { @@ -507,27 +443,11 @@ static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) } } -/* not needed, kept to document functionality */ -static void qt2_process_xmit_empty(struct usb_serial_port *port, - unsigned char *ch) -{ - int bytes_written; - - bytes_written = (int)(*ch) + (int)(*(ch + 1) << 4); -} - -/* not needed, kept to document functionality */ -static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch) -{ - return; -} - static void qt2_process_read_urb(struct urb *urb) { struct usb_serial *serial; struct qt2_serial_private *serial_priv; struct usb_serial_port *port; - struct qt2_port_private *port_priv; bool escapeflag; unsigned char *ch; int i; @@ -541,7 +461,6 @@ static void qt2_process_read_urb(struct urb *urb) serial = urb->context; serial_priv = usb_get_serial_data(serial); port = serial->port[serial_priv->current_port]; - port_priv = usb_get_serial_port_data(port); for (i = 0; i < urb->actual_length; i++) { ch = (unsigned char *)urb->transfer_buffer + i; @@ -569,7 +488,7 @@ static void qt2_process_read_urb(struct urb *urb) __func__); break; } - qt2_process_xmit_empty(port, ch + 3); + /* bytes_written = (ch[1] << 4) + ch[0]; */ i += 4; escapeflag = true; break; @@ -584,7 +503,7 @@ static void qt2_process_read_urb(struct urb *urb) newport = *(ch + 3); - if (newport > serial->num_ports) { + if (newport >= serial->num_ports) { dev_err(&port->dev, "%s - port change to invalid port: %i\n", __func__, newport); @@ -593,18 +512,15 @@ static void qt2_process_read_urb(struct urb *urb) serial_priv->current_port = newport; port = serial->port[serial_priv->current_port]; - port_priv = usb_get_serial_port_data(port); i += 3; escapeflag = true; break; case QT2_REC_FLUSH: case QT2_XMIT_FLUSH: - qt2_process_flush(port, ch + 2); i += 2; escapeflag = true; break; case QT2_CONTROL_ESCAPE: - tty_buffer_request_room(&port->port, 2); tty_insert_flip_string(&port->port, ch, 2); i += 2; escapeflag = true; @@ -619,8 +535,7 @@ static void qt2_process_read_urb(struct urb *urb) continue; } - tty_buffer_request_room(&port->port, 1); - tty_insert_flip_string(&port->port, ch, 1); + tty_insert_flip_char(&port->port, *ch, TTY_NORMAL); } tty_flip_buffer_push(&port->port); @@ -630,16 +545,17 @@ static void qt2_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port; struct qt2_port_private *port_priv; + unsigned long flags; port = urb->context; port_priv = usb_get_serial_port_data(port); - spin_lock(&port_priv->urb_lock); + spin_lock_irqsave(&port_priv->urb_lock, flags); port_priv->urb_in_use = false; usb_serial_port_softint(port); - spin_unlock(&port_priv->urb_lock); + spin_unlock_irqrestore(&port_priv->urb_lock, flags); } @@ -674,16 +590,14 @@ static int qt2_setup_urbs(struct usb_serial *serial) serial_priv = usb_get_serial_data(serial); serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!serial_priv->read_urb) { - dev_err(&serial->dev->dev, "No free urbs available\n"); + if (!serial_priv->read_urb) return -ENOMEM; - } usb_fill_bulk_urb(serial_priv->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress), serial_priv->read_buffer, - sizeof(serial_priv->read_buffer), + QT2_READ_BUFFER_SIZE, qt2_read_bulk_callback, serial); status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL); @@ -703,7 +617,7 @@ static int qt2_attach(struct usb_serial *serial) int status; /* power on unit */ - status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + status = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0xc2, 0x40, 0x8000, 0, NULL, 0, QT2_USB_TIMEOUT); if (status < 0) { @@ -713,9 +627,13 @@ static int qt2_attach(struct usb_serial *serial) } serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); - if (!serial_priv) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); + if (!serial_priv) return -ENOMEM; + + serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL); + if (!serial_priv->read_buffer) { + status = -ENOMEM; + goto err_buf; } usb_set_serial_data(serial, serial_priv); @@ -727,6 +645,8 @@ static int qt2_attach(struct usb_serial *serial) return 0; attach_failed: + kfree(serial_priv->read_buffer); +err_buf: kfree(serial_priv); return status; } @@ -745,32 +665,39 @@ static int qt2_port_probe(struct usb_serial_port *port) spin_lock_init(&port_priv->urb_lock); port_priv->port = port; + port_priv->write_buffer = kmalloc(QT2_WRITE_BUFFER_SIZE, GFP_KERNEL); + if (!port_priv->write_buffer) + goto err_buf; + port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port_priv->write_urb) { - kfree(port_priv); - return -ENOMEM; - } + if (!port_priv->write_urb) + goto err_urb; + bEndpointAddress = serial->port[0]->bulk_out_endpointAddress; usb_fill_bulk_urb(port_priv->write_urb, serial->dev, usb_sndbulkpipe(serial->dev, bEndpointAddress), port_priv->write_buffer, - sizeof(port_priv->write_buffer), + QT2_WRITE_BUFFER_SIZE, qt2_write_bulk_callback, port); usb_set_serial_port_data(port, port_priv); return 0; +err_urb: + kfree(port_priv->write_buffer); +err_buf: + kfree(port_priv); + return -ENOMEM; } -static int qt2_port_remove(struct usb_serial_port *port) +static void qt2_port_remove(struct usb_serial_port *port) { struct qt2_port_private *port_priv; port_priv = usb_get_serial_port_data(port); usb_free_urb(port_priv->write_urb); + kfree(port_priv->write_buffer); kfree(port_priv); - - return 0; } static int qt2_tiocmget(struct tty_struct *tty) @@ -814,7 +741,7 @@ static int qt2_tiocmset(struct tty_struct *tty, return update_mctrl(port_priv, set, clear); } -static void qt2_break_ctl(struct tty_struct *tty, int break_state) +static int qt2_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; struct qt2_port_private *port_priv; @@ -827,10 +754,14 @@ static void qt2_break_ctl(struct tty_struct *tty, int break_state) status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL, val, port_priv->device_port); - if (status < 0) + if (status < 0) { dev_warn(&port->dev, "%s - failed to send control message: %i\n", __func__, status); + return status; + } + + return 0; } @@ -859,7 +790,10 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch) u8 newMSR = (u8) *ch; unsigned long flags; + /* May be called from qt2_process_read_urb() for an unbound port. */ port_priv = usb_get_serial_port_data(port); + if (!port_priv) + return; spin_lock_irqsave(&port_priv->lock, flags); port_priv->shadowMSR = newMSR; @@ -887,7 +821,10 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) unsigned long flags; u8 newLSR = (u8) *ch; + /* May be called from qt2_process_read_urb() for an unbound port. */ port_priv = usb_get_serial_port_data(port); + if (!port_priv) + return; if (newLSR & UART_LSR_BI) newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI); @@ -915,12 +852,12 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) } -static int qt2_write_room(struct tty_struct *tty) +static unsigned int qt2_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct qt2_port_private *port_priv; - unsigned long flags = 0; - int r; + unsigned long flags; + unsigned int r; port_priv = usb_get_serial_port_data(port); @@ -959,7 +896,7 @@ static int qt2_write(struct tty_struct *tty, data = write_urb->transfer_buffer; spin_lock_irqsave(&port_priv->urb_lock, flags); - if (port_priv->urb_in_use == true) { + if (port_priv->urb_in_use) { dev_err(&port->dev, "qt2_write - urb is in use\n"); goto write_out; } @@ -987,7 +924,6 @@ write_out: static struct usb_serial_driver qt2_device = { .driver = { - .owner = THIS_MODULE, .name = "quatech-serial", }, .description = DRIVER_DESC, @@ -1008,7 +944,6 @@ 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, .set_termios = qt2_set_termios, }; @@ -1019,4 +954,4 @@ static struct usb_serial_driver *const serial_drivers[] = { module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); |
