diff options
author | Greg Kroah-Hartman | 2020-12-11 16:16:52 +0100 |
---|---|---|
committer | Greg Kroah-Hartman | 2020-12-11 16:16:52 +0100 |
commit | 007e3370806da1bbe83d0b43a04f420ae2e19dbb (patch) | |
tree | ac64737e4307f6ce1756b28ce8416580300b7942 /drivers/usb | |
parent | b5206275b46c30a8236feb34a1dc247fa3683d83 (diff) | |
parent | fddd408ad448efc49c67f8dfdc4e86b31c683a0c (diff) |
Merge tag 'usb-serial-5.11-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next
Johan writes:
USB-serial updates for 5.11-rc1
Here are the USB-serial updates for 5.11-rc1, including:
- keyspan_pda write-implementation fixes
- digi_acceleport write-wakeup fix
- mos7720 parport-restore fix
- mos7720 parport-tasklet removal
- cp210x termios-handling cleanups
- option device-flag fix
- ftdi_sio GPIO CBUS-configuration improvements
- removal of in_interrupt() uses
Included are also various clean ups.
All have been in linux-next with no reported issues.
* tag 'usb-serial-5.11-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial: (30 commits)
USB: serial: ftdi_sio: log the CBUS GPIO validity
USB: serial: ftdi_sio: drop GPIO line checking dead code
USB: serial: ftdi_sio: report the valid GPIO lines to gpiolib
USB: serial: option: add interface-number sanity check to flag handling
USB: serial: cp210x: clean up dtr_rts()
USB: serial: cp210x: refactor flow-control handling
USB: serial: cp210x: drop flow-control debugging
USB: serial: cp210x: set terminal settings on open
USB: serial: cp210x: clean up line-control handling
USB: serial: cp210x: return early on unchanged termios
USB: serial: mos7720: defer state restore to a workqueue
USB: serial: mos7720: fix parallel-port state restore
USB: serial: remove write wait queue
USB: serial: digi_acceleport: fix write-wakeup deadlocks
USB: serial: keyspan_pda: drop redundant usb-serial pointer
USB: serial: keyspan_pda: use BIT() macro
USB: serial: keyspan_pda: clean up comments and whitespace
USB: serial: keyspan_pda: clean up xircom/entrega support
USB: serial: keyspan_pda: add write-fifo support
USB: serial: keyspan_pda: increase transmitter threshold
...
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/serial/Kconfig | 19 | ||||
-rw-r--r-- | drivers/usb/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/serial/cp210x.c | 499 | ||||
-rw-r--r-- | drivers/usb/serial/digi_acceleport.c | 62 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 23 | ||||
-rw-r--r-- | drivers/usb/serial/iuu_phoenix.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_pda.c | 548 | ||||
-rw-r--r-- | drivers/usb/serial/mos7720.c | 236 | ||||
-rw-r--r-- | drivers/usb/serial/option.c | 23 |
9 files changed, 444 insertions, 969 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 4007fa25a8ff..a21ff5ab6df9 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -298,12 +298,12 @@ config USB_SERIAL_IUU module will be called iuu_phoenix.o config USB_SERIAL_KEYSPAN_PDA - tristate "USB Keyspan PDA Single Port Serial Driver" + tristate "USB Keyspan PDA / Xircom Single Port Serial Driver" select USB_EZUSB_FX2 help - Say Y here if you want to use a Keyspan PDA single port USB to - serial converter device. This driver makes use of firmware - developed from scratch by Brian Warner. + Say Y here if you want to use a Keyspan PDA, Xircom or Entrega single + port USB to serial converter device. This driver makes use of + firmware developed from scratch by Brian Warner. To compile this driver as a module, choose M here: the module will be called keyspan_pda. @@ -538,17 +538,6 @@ config USB_SERIAL_CYBERJACK If unsure, say N. -config USB_SERIAL_XIRCOM - tristate "USB Xircom / Entrega Single Port Serial Driver" - select USB_EZUSB_FX2 - help - Say Y here if you want to use a Xircom or Entrega single port USB to - serial converter device. This driver makes use of firmware - developed from scratch by Brian Warner. - - To compile this driver as a module, choose M here: the - module will be called keyspan_pda. - config USB_SERIAL_WWAN tristate diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 2d491e434f11..50c53aed787a 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -61,5 +61,4 @@ obj-$(CONFIG_USB_SERIAL_UPD78F0730) += upd78f0730.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o -obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_XSENS_MT) += xsens_mt.o diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index d0c05aa8a0d6..fbb10dfc56e3 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -31,9 +31,6 @@ */ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); static void cp210x_close(struct usb_serial_port *); -static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *); -static void cp210x_get_termios_port(struct usb_serial_port *port, - tcflag_t *cflagp, unsigned int *baudp); static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, struct ktermios *); static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, @@ -49,7 +46,7 @@ static void cp210x_disconnect(struct usb_serial *); static void cp210x_release(struct usb_serial *); static int cp210x_port_probe(struct usb_serial_port *); static int cp210x_port_remove(struct usb_serial_port *); -static void cp210x_dtr_rts(struct usb_serial_port *p, int on); +static void cp210x_dtr_rts(struct usb_serial_port *port, int on); static void cp210x_process_read_urb(struct urb *urb); static void cp210x_enable_event_mode(struct usb_serial_port *port); static void cp210x_disable_event_mode(struct usb_serial_port *port); @@ -267,7 +264,6 @@ enum cp210x_event_state { struct cp210x_port_private { u8 bInterfaceNumber; - bool has_swapped_line_ctl; bool event_mode; enum cp210x_event_state event_state; u8 lsr; @@ -559,14 +555,8 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req, int result; dmabuf = kmalloc(bufsize, GFP_KERNEL); - if (!dmabuf) { - /* - * FIXME Some callers don't bother to check for error, - * at least give them consistent junk until they are fixed - */ - memset(buf, 0, bufsize); + if (!dmabuf) return -ENOMEM; - } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), req, REQTYPE_INTERFACE_TO_HOST, 0, @@ -580,12 +570,6 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req, req, bufsize, result); if (result >= 0) result = -EIO; - - /* - * FIXME Some callers don't bother to check for error, - * at least give them consistent junk until they are fixed - */ - memset(buf, 0, bufsize); } kfree(dmabuf); @@ -594,46 +578,6 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req, } /* - * Reads any 32-bit CP210X_ register identified by req. - */ -static int cp210x_read_u32_reg(struct usb_serial_port *port, u8 req, u32 *val) -{ - __le32 le32_val; - int err; - - err = cp210x_read_reg_block(port, req, &le32_val, sizeof(le32_val)); - if (err) { - /* - * FIXME Some callers don't bother to check for error, - * at least give them consistent junk until they are fixed - */ - *val = 0; - return err; - } - - *val = le32_to_cpu(le32_val); - - return 0; -} - -/* - * Reads any 16-bit CP210X_ register identified by req. - */ -static int cp210x_read_u16_reg(struct usb_serial_port *port, u8 req, u16 *val) -{ - __le16 le16_val; - int err; - - err = cp210x_read_reg_block(port, req, &le16_val, sizeof(le16_val)); - if (err) - return err; - - *val = le16_to_cpu(le16_val); - - return 0; -} - -/* * Reads any 8-bit CP210X_ register identified by req. */ static int cp210x_read_u8_reg(struct usb_serial_port *port, u8 req, u8 *val) @@ -780,59 +724,6 @@ static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type, } #endif -/* - * Detect CP2108 GET_LINE_CTL bug and activate workaround. - * Write a known good value 0x800, read it back. - * If it comes back swapped the bug is detected. - * Preserve the original register value. - */ -static int cp210x_detect_swapped_line_ctl(struct usb_serial_port *port) -{ - struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); - u16 line_ctl_save; - u16 line_ctl_test; - int err; - - err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_save); - if (err) - return err; - - err = cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, 0x800); - if (err) - return err; - - err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, &line_ctl_test); - if (err) - return err; - - if (line_ctl_test == 8) { - port_priv->has_swapped_line_ctl = true; - line_ctl_save = swab16(line_ctl_save); - } - - return cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, line_ctl_save); -} - -/* - * Must always be called instead of cp210x_read_u16_reg(CP210X_GET_LINE_CTL) - * to workaround cp2108 bug and get correct value. - */ -static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl) -{ - struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); - int err; - - err = cp210x_read_u16_reg(port, CP210X_GET_LINE_CTL, ctl); - if (err) - return err; - - /* Workaround swapped bytes in 16-bit value from CP210X_GET_LINE_CTL */ - if (port_priv->has_swapped_line_ctl) - *ctl = swab16(*ctl); - - return 0; -} - static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) { struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); @@ -844,16 +735,8 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) return result; } - /* Configure the termios structure */ - cp210x_get_termios(tty, port); - - if (tty) { - /* The baud rate must be initialised on cp2104 */ - cp210x_change_speed(tty, port, NULL); - - if (I_INPCK(tty)) - cp210x_enable_event_mode(port); - } + if (tty) + cp210x_set_termios(tty, port, NULL); result = usb_serial_generic_open(tty, port); if (result) @@ -1032,167 +915,6 @@ static bool cp210x_tx_empty(struct usb_serial_port *port) return !count; } -/* - * cp210x_get_termios - * Reads the baud rate, data bits, parity, stop bits and flow control mode - * from the device, corrects any unsupported values, and configures the - * termios structure to reflect the state of the device - */ -static void cp210x_get_termios(struct tty_struct *tty, - struct usb_serial_port *port) -{ - unsigned int baud; - - if (tty) { - cp210x_get_termios_port(tty->driver_data, - &tty->termios.c_cflag, &baud); - tty_encode_baud_rate(tty, baud, baud); - } else { - tcflag_t cflag; - cflag = 0; - cp210x_get_termios_port(port, &cflag, &baud); - } -} - -/* - * cp210x_get_termios_port - * This is the heart of cp210x_get_termios which always uses a &usb_serial_port. - */ -static void cp210x_get_termios_port(struct usb_serial_port *port, - tcflag_t *cflagp, unsigned int *baudp) -{ - struct device *dev = &port->dev; - tcflag_t cflag; - struct cp210x_flow_ctl flow_ctl; - u32 baud; - u16 bits; - u32 ctl_hs; - u32 flow_repl; - - cp210x_read_u32_reg(port, CP210X_GET_BAUDRATE, &baud); - - dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud); - *baudp = baud; - - cflag = *cflagp; - - cp210x_get_line_ctl(port, &bits); - cflag &= ~CSIZE; - switch (bits & BITS_DATA_MASK) { - case BITS_DATA_5: - dev_dbg(dev, "%s - data bits = 5\n", __func__); - cflag |= CS5; - break; - case BITS_DATA_6: - dev_dbg(dev, "%s - data bits = 6\n", __func__); - cflag |= CS6; - break; - case BITS_DATA_7: - dev_dbg(dev, "%s - data bits = 7\n", __func__); - cflag |= CS7; - break; - case BITS_DATA_8: - dev_dbg(dev, "%s - data bits = 8\n", __func__); - cflag |= CS8; - break; - case BITS_DATA_9: - dev_dbg(dev, "%s - data bits = 9 (not supported, using 8 data bits)\n", __func__); - cflag |= CS8; - bits &= ~BITS_DATA_MASK; - bits |= BITS_DATA_8; - cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits); - break; - default: - dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__); - cflag |= CS8; - bits &= ~BITS_DATA_MASK; - bits |= BITS_DATA_8; - cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits); - break; - } - - switch (bits & BITS_PARITY_MASK) { - case BITS_PARITY_NONE: - dev_dbg(dev, "%s - parity = NONE\n", __func__); - cflag &= ~PARENB; - break; - case BITS_PARITY_ODD: - dev_dbg(dev, "%s - parity = ODD\n", __func__); - cflag |= (PARENB|PARODD); - break; - case BITS_PARITY_EVEN: - dev_dbg(dev, "%s - parity = EVEN\n", __func__); - cflag &= ~PARODD; - cflag |= PARENB; - break; - case BITS_PARITY_MARK: - dev_dbg(dev, "%s - parity = MARK\n", __func__); - cflag |= (PARENB|PARODD|CMSPAR); - break; - case BITS_PARITY_SPACE: - dev_dbg(dev, "%s - parity = SPACE\n", __func__); - cflag &= ~PARODD; - cflag |= (PARENB|CMSPAR); - break; - default: - dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__); - cflag &= ~PARENB; - bits &= ~BITS_PARITY_MASK; - cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits); - break; - } - - cflag &= ~CSTOPB; - switch (bits & BITS_STOP_MASK) { - case BITS_STOP_1: - dev_dbg(dev, "%s - stop bits = 1\n", __func__); - break; - case BITS_STOP_1_5: - dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__); - bits &= ~BITS_STOP_MASK; - cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits); - break; - case BITS_STOP_2: - dev_dbg(dev, "%s - stop bits = 2\n", __func__); - cflag |= CSTOPB; - break; - default: - dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__); - bits &= ~BITS_STOP_MASK; - cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits); - break; - } - - cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl, - sizeof(flow_ctl)); - ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake); - if (ctl_hs & CP210X_SERIAL_CTS_HANDSHAKE) { - dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); - /* - * When the port is closed, the CP210x hardware disables - * auto-RTS and RTS is deasserted but it leaves auto-CTS when - * in hardware flow control mode. When re-opening the port, if - * auto-CTS is enabled on the cp210x, then auto-RTS must be - * re-enabled in the driver. - */ - flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace); - flow_repl &= ~CP210X_SERIAL_RTS_MASK; - flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL); - flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl); - cp210x_write_reg_block(port, - CP210X_SET_FLOW, - &flow_ctl, - sizeof(flow_ctl)); - - cflag |= CRTSCTS; - } else { - dev_dbg(dev, "%s - flow control = NONE\n", __func__); - cflag &= ~CRTSCTS; - } - - *cflagp = cflag; -} - struct cp210x_rate { speed_t rate; speed_t high; @@ -1352,127 +1074,121 @@ static void cp210x_disable_event_mode(struct usb_serial_port *port) port_priv->event_mode = false; } +static bool cp210x_termios_change(const struct ktermios *a, const struct ktermios *b) +{ + bool iflag_change; + + iflag_change = ((a->c_iflag ^ b->c_iflag) & INPCK); + + return tty_termios_hw_change(a, b) || iflag_change; +} + +static void cp210x_set_flow_control(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) +{ + struct cp210x_flow_ctl flow_ctl; + u32 flow_repl; + u32 ctl_hs; + int ret; + + if (old_termios && C_CRTSCTS(tty) == (old_termios->c_cflag & CRTSCTS)) + return; + + ret = cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl, + sizeof(flow_ctl)); + if (ret) + return; + + ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake); + flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace); + + ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE; + ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE; + ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY; + ctl_hs &= ~CP210X_SERIAL_DTR_MASK; + ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE); + + if (C_CRTSCTS(tty)) { + ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE; + flow_repl &= ~CP210X_SERIAL_RTS_MASK; + flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL); + } else { + ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE; + flow_repl &= ~CP210X_SERIAL_RTS_MASK; + flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE); + } + + dev_dbg(&port->dev, "%s - ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n", + __func__, ctl_hs, flow_repl); + + flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs); + flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl); + + cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl, + sizeof(flow_ctl)); +} + static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - struct device *dev = &port->dev; - unsigned int cflag, old_cflag; + struct cp210x_serial_private *priv = usb_get_serial_data(port->serial); u16 bits; + int ret; - cflag = tty->termios.c_cflag; - old_cflag = old_termios->c_cflag; + if (old_termios && !cp210x_termios_change(&tty->termios, old_termios)) + return; - if (tty->termios.c_ospeed != old_termios->c_ospeed) + if (!old_termios || tty->termios.c_ospeed != old_termios->c_ospeed) cp210x_change_speed(tty, port, old_termios); - /* If the number of data bits is to be updated */ - if ((cflag & CSIZE) != (old_cflag & CSIZE)) { - cp210x_get_line_ctl(port, &bits); - bits &= ~BITS_DATA_MASK; - switch (cflag & CSIZE) { - case CS5: - bits |= BITS_DATA_5; - dev_dbg(dev, "%s - data bits = 5\n", __func__); - break; - case CS6: - bits |= BITS_DATA_6; - dev_dbg(dev, "%s - data bits = 6\n", __func__); - break; - case CS7: - bits |= BITS_DATA_7; - dev_dbg(dev, "%s - data bits = 7\n", __func__); - break; - case CS8: - default: - bits |= BITS_DATA_8; - dev_dbg(dev, "%s - data bits = 8\n", __func__); - break; - } - if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits)) - dev_dbg(dev, "Number of data bits requested not supported by device\n"); + /* CP2101 only supports CS8, 1 stop bit and non-stick parity. */ + if (priv->partnum == CP210X_PARTNUM_CP2101) { + tty->termios.c_cflag &= ~(CSIZE | CSTOPB | CMSPAR); + tty->termios.c_cflag |= CS8; } - if ((cflag & (PARENB|PARODD|CMSPAR)) != - (old_cflag & (PARENB|PARODD|CMSPAR))) { - cp210x_get_line_ctl(port, &bits); - bits &= ~BITS_PARITY_MASK; - if (cflag & PARENB) { - if (cflag & CMSPAR) { - if (cflag & PARODD) { - bits |= BITS_PARITY_MARK; - dev_dbg(dev, "%s - parity = MARK\n", __func__); - } else { - bits |= BITS_PARITY_SPACE; - dev_dbg(dev, "%s - parity = SPACE\n", __func__); - } - } else { - if (cflag & PARODD) { - bits |= BITS_PARITY_ODD; - dev_dbg(dev, "%s - parity = ODD\n", __func__); - } else { - bits |= BITS_PARITY_EVEN; - dev_dbg(dev, "%s - parity = EVEN\n", __func__); - } - } - } - if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits)) - dev_dbg(dev, "Parity mode not supported by device\n"); + bits = 0; + + switch (C_CSIZE(tty)) { + case CS5: + bits |= BITS_DATA_5; + break; + case CS6: + bits |= BITS_DATA_6; + break; + case CS7: + bits |= BITS_DATA_7; + break; + case CS8: + default: + bits |= BITS_DATA_8; + break; } - if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { - cp210x_get_line_ctl(port, &bits); - bits &= ~BITS_STOP_MASK; - if (cflag & CSTOPB) { - bits |= BITS_STOP_2; - dev_dbg(dev, "%s - stop bits = 2\n", __func__); + if (C_PARENB(tty)) { + if (C_CMSPAR(tty)) { + if (C_PARODD(tty)) + bits |= BITS_PARITY_MARK; + else + bits |= BITS_PARITY_SPACE; } else { - bits |= BITS_STOP_1; - dev_dbg(dev, "%s - stop bits = 1\n", __func__); + if (C_PARODD(tty)) + bits |= BITS_PARITY_ODD; + else + bits |= BITS_PARITY_EVEN; } - if (cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits)) - dev_dbg(dev, "Number of stop bits requested not supported by device\n"); } - if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { - struct cp210x_flow_ctl flow_ctl; - u32 ctl_hs; - u32 flow_repl; - - cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl, - sizeof(flow_ctl)); - ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake); - flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace); - dev_dbg(dev, "%s - read ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n", - __func__, ctl_hs, flow_repl); - - ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE; - ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE; - ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY; - ctl_hs &= ~CP210X_SERIAL_DTR_MASK; - ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE); - if (cflag & CRTSCTS) { - ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE; - - flow_repl &= ~CP210X_SERIAL_RTS_MASK; - flow_repl |= CP210X_SERIAL_RTS_SHIFT( - CP210X_SERIAL_RTS_FLOW_CTL); - dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__); - } else { - ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE; + if (C_CSTOPB(tty)) + bits |= BITS_STOP_2; + else + bits |= BITS_STOP_1; - flow_repl &= ~CP210X_SERIAL_RTS_MASK; - flow_repl |= CP210X_SERIAL_RTS_SHIFT( - CP210X_SERIAL_RTS_ACTIVE); - dev_dbg(dev, "%s - flow control = NONE\n", __func__); - } + ret = cp210x_write_u16_reg(port, CP210X_SET_LINE_CTL, bits); + if (ret) + dev_err(&port->dev, "failed to set line control: %d\n", ret); - dev_dbg(dev, "%s - write ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n", - __func__, ctl_hs, flow_repl); - flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs); - flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl); - cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl, - sizeof(flow_ctl)); - } + cp210x_set_flow_control(tty, port, old_termios); /* * Enable event-insertion mode only if input parity checking is @@ -1518,12 +1234,12 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, return cp210x_write_u16_reg(port, CP210X_SET_MHS, control); } -static void cp210x_dtr_rts(struct usb_serial_port *p, int on) +static void cp210x_dtr_rts(struct usb_serial_port *port, int on) { if (on) - cp210x_tiocmset_port(p, TIOCM_DTR|TIOCM_RTS, 0); + cp210x_tiocmset_port(port, TIOCM_DTR | TIOCM_RTS, 0); else - cp210x_tiocmset_port(p, 0, TIOCM_DTR|TIOCM_RTS); + cp210x_tiocmset_port(port, 0, TIOCM_DTR | TIOCM_RTS); } static int cp210x_tiocmget(struct tty_struct *tty) @@ -1986,7 +1702,6 @@ static int cp210x_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct cp210x_port_private *port_priv; - int ret; port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); if (!port_priv) @@ -1996,12 +1711,6 @@ static int cp210x_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, port_priv); - ret = cp210x_detect_swapped_line_ctl(port); - if (ret) { - kfree(port_priv); - return ret; - } - return 0; } diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 91055a191995..0ecd5316d85f 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -19,7 +19,6 @@ #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> -#include <linux/workqueue.h> #include <linux/uaccess.h> #include <linux/usb.h> #include <linux/wait.h> @@ -198,14 +197,13 @@ struct digi_port { int dp_throttle_restart; wait_queue_head_t dp_flush_wait; wait_queue_head_t dp_close_wait; /* wait queue for close */ - struct work_struct dp_wakeup_work; + wait_queue_head_t write_wait; struct usb_serial_port *dp_port; }; /* Local Function Declarations */ -static void digi_wakeup_write_lock(struct work_struct *work); static int digi_write_oob_command(struct usb_serial_port *port, unsigned char *buf, int count, int interruptible); static int digi_write_inb_command(struct usb_serial_port *port, @@ -356,26 +354,6 @@ __releases(lock) return timeout; } - -/* - * Digi Wakeup Write - * - * Wake up port, line discipline, and tty processes sleeping - * on writes. - */ - -static void digi_wakeup_write_lock(struct work_struct *work) -{ - struct digi_port *priv = - container_of(work, struct digi_port, dp_wakeup_work); - struct usb_serial_port *port = priv->dp_port; - unsigned long flags; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - tty_port_tty_wakeup(&port->port); - spin_unlock_irqrestore(&priv->dp_port_lock, flags); -} - /* * Digi Write OOB Command * @@ -404,7 +382,7 @@ static int digi_write_oob_command(struct usb_serial_port *port, while (count > 0) { while (oob_priv->dp_write_urb_in_use) { cond_wait_interruptible_timeout_irqrestore( - &oob_port->write_wait, DIGI_RETRY_TIMEOUT, + &oob_priv->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags); if (interruptible && signal_pending(current)) return -EINTR; @@ -467,7 +445,7 @@ static int digi_write_inb_command(struct usb_serial_port *port, while (priv->dp_write_urb_in_use && time_before(jiffies, timeout)) { cond_wait_interruptible_timeout_irqrestore( - &port->write_wait, DIGI_RETRY_TIMEOUT, + &priv->write_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags); if (signal_pending(current)) return -EINTR; @@ -546,7 +524,7 @@ static int digi_set_modem_signals(struct usb_serial_port *port, while (oob_priv->dp_write_urb_in_use) { spin_unlock(&port_priv->dp_port_lock); cond_wait_interruptible_timeout_irqrestore( - &oob_port->write_wait, DIGI_RETRY_TIMEOUT, + &oob_priv->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags); if (interruptible && signal_pending(current)) return -EINTR; @@ -911,9 +889,8 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; - dev_dbg(&port->dev, - "digi_write: TOP: port=%d, count=%d, in_interrupt=%ld\n", - priv->dp_port_num, count, in_interrupt()); + dev_dbg(&port->dev, "digi_write: TOP: port=%d, count=%d\n", + priv->dp_port_num, count); /* copy user data (which can sleep) before getting spin lock */ count = min(count, port->bulk_out_size-2); @@ -986,6 +963,7 @@ static void digi_write_bulk_callback(struct urb *urb) unsigned long flags; int ret = 0; int status = urb->status; + bool wakeup; /* port and serial sanity check */ if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { @@ -1006,12 +984,13 @@ static void digi_write_bulk_callback(struct urb *urb) dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n"); spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_write_urb_in_use = 0; - wake_up_interruptible(&port->write_wait); + wake_up_interruptible(&priv->write_wait); spin_unlock_irqrestore(&priv->dp_port_lock, flags); return; } /* try to send any buffered data on this port */ + wakeup = true; spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_write_urb_in_use = 0; if (priv->dp_out_buf_len > 0) { @@ -1027,19 +1006,18 @@ static void digi_write_bulk_callback(struct urb *urb) if (ret == 0) { priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; + wakeup = false; } } - /* wake up processes sleeping on writes immediately */ - tty_port_tty_wakeup(&port->port); - /* also queue up a wakeup at scheduler time, in case we */ - /* lost the race in write_chan(). */ - schedule_work(&priv->dp_wakeup_work); - spin_unlock_irqrestore(&priv->dp_port_lock, flags); + if (ret && ret != -EPERM) dev_err_console(port, "%s: usb_submit_urb failed, ret=%d, port=%d\n", __func__, ret, priv->dp_port_num); + + if (wakeup) + tty_port_tty_wakeup(&port->port); } static int digi_write_room(struct tty_struct *tty) @@ -1239,11 +1217,9 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num) init_waitqueue_head(&priv->dp_transmit_idle_wait); init_waitqueue_head(&priv->dp_flush_wait); init_waitqueue_head(&priv->dp_close_wait); - INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); + init_waitqueue_head(&priv->write_wait); priv->dp_port = port; - init_waitqueue_head(&port->write_wait); - usb_set_serial_port_data(port, priv); return 0; @@ -1508,13 +1484,14 @@ static int digi_read_oob_callback(struct urb *urb) rts = C_CRTSCTS(tty); if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) { + bool wakeup = false; + spin_lock_irqsave(&priv->dp_port_lock, flags); /* convert from digi flags to termiox flags */ if (val & DIGI_READ_INPUT_SIGNALS_CTS) { priv->dp_modem_signals |= TIOCM_CTS; - /* port must be open to use tty struct */ if (rts) - tty_port_tty_wakeup(&port->port); + wakeup = true; } else { priv->dp_modem_signals &= ~TIOCM_CTS; /* port must be open to use tty struct */ @@ -1533,6 +1510,9 @@ static int digi_read_oob_callback(struct urb *urb) priv->dp_modem_signals &= ~TIOCM_CD; spin_unlock_irqrestore(&priv->dp_port_lock, flags); + + if (wakeup) + tty_port_tty_wakeup(&port->port); } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) { spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_transmit_idle = 1; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index e0f4c3d9649c..94398f89e600 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1841,9 +1841,6 @@ static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset) 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 */ @@ -2002,6 +1999,25 @@ static int ftdi_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, return result; } +static int ftdi_gpio_init_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct usb_serial_port *port = gpiochip_get_data(gc); + struct ftdi_private *priv = usb_get_serial_port_data(port); + unsigned long map = priv->gpio_altfunc; + + bitmap_complement(valid_mask, &map, ngpios); + + if (bitmap_empty(valid_mask, ngpios)) + dev_dbg(&port->dev, "no CBUS pin configured for GPIO\n"); + else + dev_dbg(&port->dev, "CBUS%*pbl configured for GPIO\n", ngpios, + valid_mask); + + return 0; +} + static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr, u16 nbytes) { @@ -2173,6 +2189,7 @@ static int ftdi_gpio_init(struct usb_serial_port *port) 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.init_valid_mask = ftdi_gpio_init_valid_mask; priv->gc.get = ftdi_gpio_get; priv->gc.set = ftdi_gpio_set; priv->gc.get_multiple = ftdi_gpio_get_multiple; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index b4ba79123d9d..f1201d4de297 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -850,7 +850,6 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, default: kfree(dataout); return IUU_INVALID_PARAMETER; - break; } switch (parity & 0xF0) { @@ -864,7 +863,6 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, default: kfree(dataout); return IUU_INVALID_PARAMETER; - break; } status = bulk_immediate(port, dataout, DataCount); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index c1333919716b..e6f933e8d25f 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -5,12 +5,12 @@ * Copyright (C) 1999 - 2001 Greg Kroah-Hartman <greg@kroah.com> * Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com> * Copyright (C) 2000 Al Borchers <borchers@steinerpoint.com> + * Copyright (C) 2020 Johan Hovold <johan@kernel.org> * * See Documentation/usb/usb-serial.rst for more information on using this * driver */ - #include <linux/kernel.h> #include <linux/errno.h> #include <linux/slab.h> @@ -25,30 +25,19 @@ #include <linux/usb/serial.h> #include <linux/usb/ezusb.h> -/* make a simple define to handle if we are compiling keyspan_pda or xircom support */ -#if IS_ENABLED(CONFIG_USB_SERIAL_KEYSPAN_PDA) - #define KEYSPAN -#else - #undef KEYSPAN -#endif -#if IS_ENABLED(CONFIG_USB_SERIAL_XIRCOM) - #define XIRCOM -#else - #undef XIRCOM -#endif - -#define DRIVER_AUTHOR "Brian Warner <warner@lothar.com>" +#define DRIVER_AUTHOR "Brian Warner <warner@lothar.com>, Johan Hovold <johan@kernel.org>" #define DRIVER_DESC "USB Keyspan PDA Converter driver" +#define KEYSPAN_TX_THRESHOLD 128 + struct keyspan_pda_private { int tx_room; - int tx_throttled; - struct work_struct wakeup_work; - struct work_struct unthrottle_work; + struct work_struct unthrottle_work; struct usb_serial *serial; struct usb_serial_port *port; }; +static int keyspan_pda_write_start(struct usb_serial_port *port); #define KEYSPAN_VENDOR_ID 0x06cd #define KEYSPAN_PDA_FAKE_ID 0x0103 @@ -62,18 +51,13 @@ struct keyspan_pda_private { #define ENTREGA_FAKE_ID 0x8093 static const struct usb_device_id id_table_combined[] = { -#ifdef KEYSPAN { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) }, -#endif -#ifdef XIRCOM { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) }, { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, -#endif { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table_combined); static const struct usb_device_id id_table_std[] = { @@ -81,46 +65,71 @@ static const struct usb_device_id id_table_std[] = { { } /* Terminating entry */ }; -#ifdef KEYSPAN static const struct usb_device_id id_table_fake[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) }, - { } /* Terminating entry */ -}; -#endif - -#ifdef XIRCOM -static const struct usb_device_id id_table_fake_xircom[] = { { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) }, { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, - { } + { } /* Terminating entry */ }; -#endif -static void keyspan_pda_wakeup_write(struct work_struct *work) +static int keyspan_pda_get_write_room(struct keyspan_pda_private *priv) { - struct keyspan_pda_private *priv = - container_of(work, struct keyspan_pda_private, wakeup_work); struct usb_serial_port *port = priv->port; + struct usb_serial *serial = port->serial; + u8 *room; + int rc; + + room = kmalloc(1, GFP_KERNEL); + if (!room) + return -ENOMEM; - tty_port_tty_wakeup(&port->port); + rc = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 6, /* write_room */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_IN, + 0, /* value: 0 means "remaining room" */ + 0, /* index */ + room, + 1, + 2000); + if (rc != 1) { + if (rc >= 0) + rc = -EIO; + dev_dbg(&port->dev, "roomquery failed: %d\n", rc); + goto out_free; + } + + dev_dbg(&port->dev, "roomquery says %d\n", *room); + rc = *room; +out_free: + kfree(room); + + return rc; } static void keyspan_pda_request_unthrottle(struct work_struct *work) { struct keyspan_pda_private *priv = container_of(work, struct keyspan_pda_private, unthrottle_work); - struct usb_serial *serial = priv->serial; + struct usb_serial_port *port = priv->port; + struct usb_serial *serial = port->serial; + unsigned long flags; int result; - /* ask the device to tell us when the tx buffer becomes - sufficiently empty */ + dev_dbg(&port->dev, "%s\n", __func__); + + /* + * Ask the device to tell us when the tx buffer becomes + * sufficiently empty. + */ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 7, /* request_unthrottle */ USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - 16, /* value: threshold */ + KEYSPAN_TX_THRESHOLD, 0, /* index */ NULL, 0, @@ -128,9 +137,20 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work) if (result < 0) dev_dbg(&serial->dev->dev, "%s - error %d from usb_control_msg\n", __func__, result); + /* + * Need to check available space after requesting notification in case + * buffer is already empty so that no notification is sent. + */ + result = keyspan_pda_get_write_room(priv); + if (result > KEYSPAN_TX_THRESHOLD) { + spin_lock_irqsave(&port->lock, flags); + priv->tx_room = max(priv->tx_room, result); + spin_unlock_irqrestore(&port->lock, flags); + + usb_serial_port_softint(port); + } } - static void keyspan_pda_rx_interrupt(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -139,6 +159,8 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) int retval; int status = urb->status; struct keyspan_pda_private *priv; + unsigned long flags; + priv = usb_get_serial_port_data(port); switch (status) { @@ -172,18 +194,22 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) break; case 1: /* status interrupt */ - if (len < 3) { + if (len < 2) { dev_warn(&port->dev, "short interrupt message received\n"); break; } - dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]); + dev_dbg(&port->dev, "rx int, d1=%d\n", data[1]); switch (data[1]) { case 1: /* modemline change */ break; case 2: /* tx unthrottle interrupt */ - priv->tx_throttled = 0; - /* queue up a wakeup at scheduler time */ - schedule_work(&priv->wakeup_work); + spin_lock_irqsave(&port->lock, flags); + priv->tx_room = max(priv->tx_room, KEYSPAN_TX_THRESHOLD); + spin_unlock_irqrestore(&port->lock, flags); + + keyspan_pda_write_start(port); + + usb_serial_port_softint(port); break; default: break; @@ -201,31 +227,30 @@ exit: __func__, retval); } - static void keyspan_pda_rx_throttle(struct tty_struct *tty) { - /* stop receiving characters. We just turn off the URB request, and - let chars pile up in the device. If we're doing hardware - flowcontrol, the device will signal the other end when its buffer - fills up. If we're doing XON/XOFF, this would be a good time to - send an XOFF, although it might make sense to foist that off - upon the device too. */ struct usb_serial_port *port = tty->driver_data; + /* + * Stop receiving characters. We just turn off the URB request, and + * let chars pile up in the device. If we're doing hardware + * flowcontrol, the device will signal the other end when its buffer + * fills up. If we're doing XON/XOFF, this would be a good time to + * send an XOFF, although it might make sense to foist that off upon + * the device too. + */ usb_kill_urb(port->interrupt_in_urb); } - static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - /* just restart the receive interrupt URB */ + /* just restart the receive interrupt URB */ if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n"); } - static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud) { int rc; @@ -267,8 +292,6 @@ static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud) baud = 9600; } - /* rather than figure out how to sleep while waiting for this - to complete, I just use the "legacy" API. */ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0, /* set baud */ USB_TYPE_VENDOR @@ -281,10 +304,10 @@ static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud) 2000); /* timeout */ if (rc < 0) return 0; + return baud; } - static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; @@ -296,6 +319,7 @@ static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state) value = 1; /* start break */ else value = 0; /* clear break */ + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 4, /* set break */ USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, @@ -303,39 +327,35 @@ static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state) if (result < 0) dev_dbg(&port->dev, "%s - error %d from usb_control_msg\n", __func__, result); - /* there is something funky about this.. the TCSBRK that 'cu' performs - ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4 - seconds apart, but it feels like the break sent isn't as long as it - is on /dev/ttyS0 */ } - static void keyspan_pda_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; speed_t speed; - /* cflag specifies lots of stuff: number of stop bits, parity, number - of data bits, baud. What can the device actually handle?: - CSTOPB (1 stop bit or 2) - PARENB (parity) - CSIZE (5bit .. 8bit) - There is minimal hw support for parity (a PSW bit seems to hold the - parity of whatever is in the accumulator). The UART either deals - with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data, - 1 special, stop). So, with firmware changes, we could do: - 8N1: 10 bit - 8N2: 11 bit, extra bit always (mark?) - 8[EOMS]1: 11 bit, extra bit is parity - 7[EOMS]1: 10 bit, b0/b7 is parity - 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?) - - HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS - bit. - - For now, just do baud. */ - + /* + * cflag specifies lots of stuff: number of stop bits, parity, number + * of data bits, baud. What can the device actually handle?: + * CSTOPB (1 stop bit or 2) + * PARENB (parity) + * CSIZE (5bit .. 8bit) + * There is minimal hw support for parity (a PSW bit seems to hold the + * parity of whatever is in the accumulator). The UART either deals + * with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data, + * 1 special, stop). So, with firmware changes, we could do: + * 8N1: 10 bit + * 8N2: 11 bit, extra bit always (mark?) + * 8[EOMS]1: 11 bit, extra bit is parity + * 7[EOMS]1: 10 bit, b0/b7 is parity + * 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?) + * + * HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS + * bit. + * + * For now, just do baud. + */ speed = tty_get_baud_rate(tty); speed = keyspan_pda_setbaud(serial, speed); @@ -344,17 +364,19 @@ static void keyspan_pda_set_termios(struct tty_struct *tty, /* It hasn't changed so.. */ speed = tty_termios_baud_rate(old_termios); } - /* Only speed can change so copy the old h/w parameters - then encode the new speed */ + /* + * Only speed can change so copy the old h/w parameters then encode + * the new speed. + */ tty_termios_copy_hw(&tty->termios, old_termios); tty_encode_baud_rate(tty, speed, speed); } - -/* modem control pins: DTR and RTS are outputs and can be controlled. - DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be - read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */ - +/* + * Modem control pins: DTR and RTS are outputs and can be controlled. + * DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be + * read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused. + */ static int keyspan_pda_get_modem_info(struct usb_serial *serial, unsigned char *value) { @@ -378,7 +400,6 @@ static int keyspan_pda_get_modem_info(struct usb_serial *serial, return rc; } - static int keyspan_pda_set_modem_info(struct usb_serial *serial, unsigned char value) { @@ -401,13 +422,14 @@ static int keyspan_pda_tiocmget(struct tty_struct *tty) rc = keyspan_pda_get_modem_info(serial, &status); if (rc < 0) return rc; - value = - ((status & (1<<7)) ? TIOCM_DTR : 0) | - ((status & (1<<6)) ? TIOCM_CAR : 0) | - ((status & (1<<5)) ? TIOCM_RNG : 0) | - ((status & (1<<4)) ? TIOCM_DSR : 0) | - ((status & (1<<3)) ? TIOCM_CTS : 0) | - ((status & (1<<2)) ? TIOCM_RTS : 0); + + value = ((status & BIT(7)) ? TIOCM_DTR : 0) | + ((status & BIT(6)) ? TIOCM_CAR : 0) | + ((status & BIT(5)) ? TIOCM_RNG : 0) | + ((status & BIT(4)) ? TIOCM_DSR : 0) | + ((status & BIT(3)) ? TIOCM_CTS : 0) | + ((status & BIT(2)) ? TIOCM_RTS : 0); + return value; } @@ -424,186 +446,127 @@ static int keyspan_pda_tiocmset(struct tty_struct *tty, return rc; if (set & TIOCM_RTS) - status |= (1<<2); + status |= BIT(2); if (set & TIOCM_DTR) - status |= (1<<7); + status |= BIT(7); if (clear & TIOCM_RTS) - status &= ~(1<<2); + status &= ~BIT(2); if (clear & TIOCM_DTR) - status &= ~(1<<7); + status &= ~BIT(7); rc = keyspan_pda_set_modem_info(serial, status); return rc; } -static int keyspan_pda_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) +static int keyspan_pda_write_start(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; - int request_unthrottle = 0; - int rc = 0; - struct keyspan_pda_private *priv; + struct keyspan_pda_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + struct urb *urb; + int count; + int room; + int rc; - priv = usb_get_serial_port_data(port); - /* guess how much room is left in the device's ring buffer, and if we - want to send more than that, check first, updating our notion of - what is left. If our write will result in no room left, ask the - device to give us an interrupt when the room available rises above - a threshold, and hold off all writers (eventually, those using - select() or poll() too) until we receive that unthrottle interrupt. - Block if we can't write anything at all, otherwise write as much as - we can. */ - if (count == 0) { - dev_dbg(&port->dev, "write request of 0 bytes\n"); - return 0; - } + /* + * Guess how much room is left in the device's ring buffer. If our + * write will result in no room left, ask the device to give us an + * interrupt when the room available rises above a threshold but also + * query how much room is currently available (in case our guess was + * too conservative and the buffer is already empty when the + * unthrottle work is scheduled). + */ + + /* + * We might block because of: + * the TX urb is in-flight (wait until it completes) + * the device is full (wait until it says there is room) + */ + spin_lock_irqsave(&port->lock, flags); + + room = priv->tx_room; + count = kfifo_len(&port->write_fifo); - /* we might block because of: - the TX urb is in-flight (wait until it completes) - the device is full (wait until it says there is room) - */ - spin_lock_bh(&port->lock); - if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) { - spin_unlock_bh(&port->lock); + if (!test_bit(0, &port->write_urbs_free) || count == 0 || room == 0) { + spin_unlock_irqrestore(&port->lock, flags); return 0; } - clear_bit(0, &port->write_urbs_free); - spin_unlock_bh(&port->lock); - - /* At this point the URB is in our control, nobody else can submit it - again (the only sudden transition was the one from EINPROGRESS to - finished). Also, the tx process is not throttled. So we are - ready to write. */ - - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - - /* Check if we might overrun the Tx buffer. If so, ask the - device how much room it really has. This is done only on - scheduler time, since usb_control_msg() sleeps. */ - if (count > priv->tx_room && !in_interrupt()) { - u8 *room; - - room = kmalloc(1, GFP_KERNEL); - if (!room) { - rc = -ENOMEM; - goto exit; - } + __clear_bit(0, &port->write_urbs_free); - rc = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 6, /* write_room */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_IN, - 0, /* value: 0 means "remaining room" */ - 0, /* index */ - room, - 1, - 2000); - if (rc > 0) { - dev_dbg(&port->dev, "roomquery says %d\n", *room); - priv->tx_room = *room; - } - kfree(room); - if (rc < 0) { - dev_dbg(&port->dev, "roomquery failed\n"); - goto exit; - } - if (rc == 0) { - dev_dbg(&port->dev, "roomquery returned 0 bytes\n"); - rc = -EIO; /* device didn't return any data */ - goto exit; - } - } - if (count > priv->tx_room) { - /* we're about to completely fill the Tx buffer, so - we'll be throttled afterwards. */ - count = priv->tx_room; - request_unthrottle = 1; - } + if (count > room) + count = room; + if (count > port->bulk_out_size) + count = port->bulk_out_size; - if (count) { - /* now transfer data */ - memcpy(port->write_urb->transfer_buffer, buf, count); - /* send the data out the bulk port */ - port->write_urb->transfer_buffer_length = count; + urb = port->write_urb; + count = kfifo_out(&port->write_fifo, urb->transfer_buffer, count); + urb->transfer_buffer_length = count; - priv->tx_room -= count; + port->tx_bytes += count; + priv->tx_room -= count; - rc = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (rc) { - dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n"); - goto exit; - } - } else { - /* There wasn't any room left, so we are throttled until - the buffer empties a bit */ - request_unthrottle = 1; + spin_unlock_irqrestore(&port->lock, flags); + + dev_dbg(&port->dev, "%s - count = %d, txroom = %d\n", __func__, count, room); + + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc) { + dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n"); + + spin_lock_irqsave(&port->lock, flags); + port->tx_bytes -= count; + priv->tx_room = max(priv->tx_room, room + count); + __set_bit(0, &port->write_urbs_free); + spin_unlock_irqrestore(&port->lock, flags); + + return rc; } - if (request_unthrottle) { - priv->tx_throttled = 1; /* block writers */ + if (count == room) schedule_work(&priv->unthrottle_work); - } - rc = count; -exit: - if (rc < 0) - set_bit(0, &port->write_urbs_free); - return rc; + return count; } - static void keyspan_pda_write_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; - struct keyspan_pda_private *priv; + unsigned long flags; - set_bit(0, &port->write_urbs_free); - priv = usb_get_serial_port_data(port); + spin_lock_irqsave(&port->lock, flags); + port->tx_bytes -= urb->transfer_buffer_length; + __set_bit(0, &port->write_urbs_free); + spin_unlock_irqrestore(&port->lock, flags); - /* queue up a wakeup at scheduler time */ - schedule_work(&priv->wakeup_work); -} + keyspan_pda_write_start(port); + usb_serial_port_softint(port); +} -static int keyspan_pda_write_room(struct tty_struct *tty) +static int keyspan_pda_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) { - struct usb_serial_port *port = tty->driver_data; - struct keyspan_pda_private *priv; - priv = usb_get_serial_port_data(port); - /* used by n_tty.c for processing of tabs and such. Giving it our - conservative guess is probably good enough, but needs testing by - running a console through the device. */ - return priv->tx_room; -} + int rc; + dev_dbg(&port->dev, "%s - count = %d\n", __func__, count); -static int keyspan_pda_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct keyspan_pda_private *priv; - unsigned long flags; - int ret = 0; + if (!count) + return 0; - priv = usb_get_serial_port_data(port); + count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); - /* when throttled, return at least WAKEUP_CHARS to tell select() (via - n_tty.c:normal_poll() ) that we're not writeable. */ + rc = keyspan_pda_write_start(port); + if (rc) + return rc; - spin_lock_irqsave(&port->lock, flags); - if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) - ret = 256; - spin_unlock_irqrestore(&port->lock, flags); - return ret; + return count; } - static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on) { struct usb_serial *serial = port->serial; if (on) - keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2)); + keyspan_pda_set_modem_info(serial, BIT(7) | BIT(2)); else keyspan_pda_set_modem_info(serial, 0); } @@ -612,74 +575,63 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on) static int keyspan_pda_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; - u8 *room; - int rc = 0; - struct keyspan_pda_private *priv; + struct keyspan_pda_private *priv = usb_get_serial_port_data(port); + int rc; /* find out how much room is in the Tx ring */ - room = kmalloc(1, GFP_KERNEL); - if (!room) - return -ENOMEM; + rc = keyspan_pda_get_write_room(priv); + if (rc < 0) + return rc; - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 6, /* write_room */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_IN, - 0, /* value */ - 0, /* index */ - room, - 1, - 2000); - if (rc < 0) { - dev_dbg(&port->dev, "%s - roomquery failed\n", __func__); - goto error; - } - if (rc == 0) { - dev_dbg(&port->dev, "%s - roomquery returned 0 bytes\n", __func__); - rc = -EIO; - goto error; - } - priv = usb_get_serial_port_data(port); - priv->tx_room = *room; - priv->tx_throttled = *room ? 0 : 1; + spin_lock_irq(&port->lock); + priv->tx_room = rc; + spin_unlock_irq(&port->lock); - /*Start reading from the device*/ rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (rc) { dev_dbg(&port->dev, "%s - usb_submit_urb(read int) failed\n", __func__); - goto error; + return rc; } -error: - kfree(room); - return rc; + + return 0; } + static void keyspan_pda_close(struct usb_serial_port *port) { - usb_kill_urb(port->write_urb); + struct keyspan_pda_private *priv = usb_get_serial_port_data(port); + + /* + * Stop the interrupt URB first as its completion handler may submit + * the write URB. + */ usb_kill_urb(port->interrupt_in_urb); -} + usb_kill_urb(port->write_urb); + + cancel_work_sync(&priv->unthrottle_work); + spin_lock_irq(&port->lock); + kfifo_reset(&port->write_fifo); + spin_unlock_irq(&port->lock); +} /* download the firmware to a "fake" device (pre-renumeration) */ static int keyspan_pda_fake_startup(struct usb_serial *serial) { + unsigned int vid = le16_to_cpu(serial->dev->descriptor.idVendor); const char *fw_name; /* download the firmware here ... */ ezusb_fx1_set_reset(serial->dev, 1); - if (0) { ; } -#ifdef KEYSPAN - else if (le16_to_cpu(serial->dev->descriptor.idVendor) == KEYSPAN_VENDOR_ID) + switch (vid) { + case KEYSPAN_VENDOR_ID: fw_name = "keyspan_pda/keyspan_pda.fw"; -#endif -#ifdef XIRCOM - else if ((le16_to_cpu(serial->dev->descriptor.idVendor) == XIRCOM_VENDOR_ID) || - (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGA_VENDOR_ID)) + break; + case XIRCOM_VENDOR_ID: + case ENTREGA_VENDOR_ID: fw_name = "keyspan_pda/xircom_pgs.fw"; -#endif - else { + break; + default: dev_err(&serial->dev->dev, "%s: unknown vendor, aborting.\n", __func__); return -ENODEV; @@ -691,19 +643,17 @@ static int keyspan_pda_fake_startup(struct usb_serial *serial) return -ENOENT; } - /* after downloading firmware Renumeration will occur in a - moment and the new device will bind to the real driver */ + /* + * After downloading firmware renumeration will occur in a moment and + * the new device will bind to the real driver. + */ - /* we want this device to fail to have a driver assigned to it. */ + /* We want this device to fail to have a driver assigned to it. */ return 1; } -#ifdef KEYSPAN MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw"); -#endif -#ifdef XIRCOM MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); -#endif static int keyspan_pda_port_probe(struct usb_serial_port *port) { @@ -714,9 +664,7 @@ static int keyspan_pda_port_probe(struct usb_serial_port *port) if (!priv) return -ENOMEM; - INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write); INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle); - priv->serial = port->serial; priv->port = port; usb_set_serial_port_data(port, priv); @@ -734,7 +682,6 @@ static int keyspan_pda_port_remove(struct usb_serial_port *port) return 0; } -#ifdef KEYSPAN static struct usb_serial_driver keyspan_pda_fake_device = { .driver = { .owner = THIS_MODULE, @@ -745,20 +692,6 @@ static struct usb_serial_driver keyspan_pda_fake_device = { .num_ports = 1, .attach = keyspan_pda_fake_startup, }; -#endif - -#ifdef XIRCOM -static struct usb_serial_driver xircom_pgs_fake_device = { - .driver = { - .owner = THIS_MODULE, - .name = "xircom_no_firm", - }, - .description = "Xircom / Entrega PGS - (prerenumeration)", - .id_table = id_table_fake_xircom, - .num_ports = 1, - .attach = keyspan_pda_fake_startup, -}; -#endif static struct usb_serial_driver keyspan_pda_device = { .driver = { @@ -774,10 +707,8 @@ static struct usb_serial_driver keyspan_pda_device = { .open = keyspan_pda_open, .close = keyspan_pda_close, .write = keyspan_pda_write, - .write_room = keyspan_pda_write_room, - .write_bulk_callback = keyspan_pda_write_bulk_callback, + .write_bulk_callback = keyspan_pda_write_bulk_callback, .read_int_callback = keyspan_pda_rx_interrupt, - .chars_in_buffer = keyspan_pda_chars_in_buffer, .throttle = keyspan_pda_rx_throttle, .unthrottle = keyspan_pda_rx_unthrottle, .set_termios = keyspan_pda_set_termios, @@ -790,12 +721,7 @@ static struct usb_serial_driver keyspan_pda_device = { static struct usb_serial_driver * const serial_drivers[] = { &keyspan_pda_device, -#ifdef KEYSPAN &keyspan_pda_fake_device, -#endif -#ifdef XIRCOM - &xircom_pgs_fake_device, -#endif NULL }; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 5eed1078fac8..41ee2984a0df 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -79,14 +79,6 @@ MODULE_DEVICE_TABLE(usb, id_table); #define DCR_INIT_VAL 0x0c /* SLCTIN, nINIT */ #define ECR_INIT_VAL 0x00 /* SPP mode */ -struct urbtracker { - struct mos7715_parport *mos_parport; - struct list_head urblist_entry; - struct kref ref_count; - struct urb *urb; - struct usb_ctrlrequest *setup; -}; - enum mos7715_pp_modes { SPP = 0<<5, PS2 = 1<<5, /* moschip calls this 'NIBBLE' mode */ @@ -96,12 +88,9 @@ enum mos7715_pp_modes { struct mos7715_parport { struct parport *pp; /* back to containing struct */ struct kref ref_count; /* to instance of this struct */ - struct list_head deferred_urbs; /* list deferred async urbs */ - struct list_head active_urbs; /* list async urbs in flight */ - spinlock_t listlock; /* protects list access */ bool msg_pending; /* usb sync call pending */ struct completion syncmsg_compl; /* usb sync call completed */ - struct tasklet_struct urb_tasklet; /* for sending deferred urbs */ + struct work_struct work; /* restore deferred writes */ struct usb_serial *serial; /* back to containing struct */ __u8 shadowECR; /* parallel port regs... */ __u8 shadowDCR; @@ -265,174 +254,8 @@ static void destroy_mos_parport(struct kref *kref) kfree(mos_parport); } -static void destroy_urbtracker(struct kref *kref) -{ - struct urbtracker *urbtrack = - container_of(kref, struct urbtracker, ref_count); - struct mos7715_parport *mos_parport = urbtrack->mos_parport; - - usb_free_urb(urbtrack->urb); - kfree(urbtrack->setup); - kfree(urbtrack); - kref_put(&mos_parport->ref_count, destroy_mos_parport); -} - /* - * This runs as a tasklet when sending an urb in a non-blocking parallel - * port callback had to be deferred because the disconnect mutex could not be - * obtained at the time. - */ -static void send_deferred_urbs(struct tasklet_struct *t) -{ - int ret_val; - unsigned long flags; - struct mos7715_parport *mos_parport = from_tasklet(mos_parport, t, - urb_tasklet); - struct urbtracker *urbtrack, *tmp; - struct list_head *cursor, *next; - struct device *dev; - - /* if release function ran, game over */ - if (unlikely(mos_parport->serial == NULL)) - return; - - dev = &mos_parport->serial->dev->dev; - - /* try again to get the mutex */ - if (!mutex_trylock(&mos_parport->serial->disc_mutex)) { - dev_dbg(dev, "%s: rescheduling tasklet\n", __func__); - tasklet_schedule(&mos_parport->urb_tasklet); - return; - } - - /* if device disconnected, game over */ - if (unlikely(mos_parport->serial->disconnected)) { - mutex_unlock(&mos_parport->serial->disc_mutex); - return; - } - - spin_lock_irqsave(&mos_parport->listlock, flags); - if (list_empty(&mos_parport->deferred_urbs)) { - spin_unlock_irqrestore(&mos_parport->listlock, flags); - mutex_unlock(&mos_parport->serial->disc_mutex); - dev_dbg(dev, "%s: deferred_urbs list empty\n", __func__); - return; - } - - /* move contents of deferred_urbs list to active_urbs list and submit */ - list_for_each_safe(cursor, next, &mos_parport->deferred_urbs) - list_move_tail(cursor, &mos_parport->active_urbs); - list_for_each_entry_safe(urbtrack, tmp, &mos_parport->active_urbs, - urblist_entry) { - ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); - dev_dbg(dev, "%s: urb submitted\n", __func__); - if (ret_val) { - dev_err(dev, "usb_submit_urb() failed: %d\n", ret_val); - list_del(&urbtrack->urblist_entry); - kref_put(&urbtrack->ref_count, destroy_urbtracker); - } - } - spin_unlock_irqrestore(&mos_parport->listlock, flags); - mutex_unlock(&mos_parport->serial->disc_mutex); -} - -/* callback for parallel port control urbs submitted asynchronously */ -static void async_complete(struct urb *urb) -{ - struct urbtracker *urbtrack = urb->context; - int status = urb->status; - unsigned long flags; - - if (unlikely(status)) - dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); - - /* remove the urbtracker from the active_urbs list */ - spin_lock_irqsave(&urbtrack->mos_parport->listlock, flags); - list_del(&urbtrack->urblist_entry); - spin_unlock_irqrestore(&urbtrack->mos_parport->listlock, flags); - kref_put(&urbtrack->ref_count, destroy_urbtracker); -} - -static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, - enum mos_regs reg, __u8 data) -{ - struct urbtracker *urbtrack; - int ret_val; - unsigned long flags; - struct usb_serial *serial = mos_parport->serial; - struct usb_device *usbdev = serial->dev; - - /* create and initialize the control urb and containing urbtracker */ - urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC); - if (!urbtrack) - return -ENOMEM; - - urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urbtrack->urb) { - kfree(urbtrack); - return -ENOMEM; - } - urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_ATOMIC); - if (!urbtrack->setup) { - usb_free_urb(urbtrack->urb); - kfree(urbtrack); - return -ENOMEM; - } - urbtrack->setup->bRequestType = (__u8)0x40; - urbtrack->setup->bRequest = (__u8)0x0e; - urbtrack->setup->wValue = cpu_to_le16(get_reg_value(reg, dummy)); - urbtrack->setup->wIndex = cpu_to_le16(get_reg_index(reg)); - urbtrack->setup->wLength = 0; - usb_fill_control_urb(urbtrack->urb, usbdev, - usb_sndctrlpipe(usbdev, 0), - (unsigned char *)urbtrack->setup, - NULL, 0, async_complete, urbtrack); - kref_get(&mos_parport->ref_count); - urbtrack->mos_parport = mos_parport; - kref_init(&urbtrack->ref_count); - INIT_LIST_HEAD(&urbtrack->urblist_entry); - - /* - * get the disconnect mutex, or add tracker to the deferred_urbs list - * and schedule a tasklet to try again later - */ - if (!mutex_trylock(&serial->disc_mutex)) { - spin_lock_irqsave(&mos_parport->listlock, flags); - list_add_tail(&urbtrack->urblist_entry, - &mos_parport->deferred_urbs); - spin_unlock_irqrestore(&mos_parport->listlock, flags); - tasklet_schedule(&mos_parport->urb_tasklet); - dev_dbg(&usbdev->dev, "tasklet scheduled\n"); - return 0; - } - - /* bail if device disconnected */ - if (serial->disconnected) { - kref_put(&urbtrack->ref_count, destroy_urbtracker); - mutex_unlock(&serial->disc_mutex); - return -ENODEV; - } - - /* add the tracker to the active_urbs list and submit */ - spin_lock_irqsave(&mos_parport->listlock, flags); - list_add_tail(&urbtrack->urblist_entry, &mos_parport->active_urbs); - spin_unlock_irqrestore(&mos_parport->listlock, flags); - ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); - mutex_unlock(&serial->disc_mutex); - if (ret_val) { - dev_err(&usbdev->dev, - "%s: submit_urb() failed: %d\n", __func__, ret_val); - spin_lock_irqsave(&mos_parport->listlock, flags); - list_del(&urbtrack->urblist_entry); - spin_unlock_irqrestore(&mos_parport->listlock, flags); - kref_put(&urbtrack->ref_count, destroy_urbtracker); - return ret_val; - } - return 0; -} - -/* - * This is the the common top part of all parallel port callback operations that + * This is the common top part of all parallel port callback operations that * send synchronous messages to the device. This implements convoluted locking * that avoids two scenarios: (1) a port operation is called after usbserial * has called our release function, at which point struct mos7715_parport has @@ -458,6 +281,10 @@ static int parport_prologue(struct parport *pp) reinit_completion(&mos_parport->syncmsg_compl); spin_unlock(&release_lock); + /* ensure writes from restore are submitted before new requests */ + if (work_pending(&mos_parport->work)) + flush_work(&mos_parport->work); + mutex_lock(&mos_parport->serial->disc_mutex); if (mos_parport->serial->disconnected) { /* device disconnected */ @@ -482,6 +309,26 @@ static inline void parport_epilogue(struct parport *pp) complete(&mos_parport->syncmsg_compl); } +static void deferred_restore_writes(struct work_struct *work) +{ + struct mos7715_parport *mos_parport; + + mos_parport = container_of(work, struct mos7715_parport, work); + + mutex_lock(&mos_parport->serial->disc_mutex); + + /* if device disconnected, game over */ + if (mos_parport->serial->disconnected) + goto done; + + write_mos_reg(mos_parport->serial, dummy, MOS7720_DCR, + mos_parport->shadowDCR); + write_mos_reg(mos_parport->serial, dummy, MOS7720_ECR, + mos_parport->shadowECR); +done: + mutex_unlock(&mos_parport->serial->disc_mutex); +} + static void parport_mos7715_write_data(struct parport *pp, unsigned char d) { struct mos7715_parport *mos_parport = pp->private_data; @@ -639,10 +486,10 @@ static void parport_mos7715_restore_state(struct parport *pp, spin_unlock(&release_lock); return; } - write_parport_reg_nonblock(mos_parport, MOS7720_DCR, - mos_parport->shadowDCR); - write_parport_reg_nonblock(mos_parport, MOS7720_ECR, - mos_parport->shadowECR); + mos_parport->shadowDCR = s->u.pc.ctr; + mos_parport->shadowECR = s->u.pc.ecr; + + schedule_work(&mos_parport->work); spin_unlock(&release_lock); } @@ -712,12 +559,9 @@ static int mos7715_parport_init(struct usb_serial *serial) mos_parport->msg_pending = false; kref_init(&mos_parport->ref_count); - spin_lock_init(&mos_parport->listlock); - INIT_LIST_HEAD(&mos_parport->active_urbs); - INIT_LIST_HEAD(&mos_parport->deferred_urbs); usb_set_serial_data(serial, mos_parport); /* hijack private pointer */ mos_parport->serial = serial; - tasklet_setup(&mos_parport->urb_tasklet, send_deferred_urbs); + INIT_WORK(&mos_parport->work, deferred_restore_writes); init_completion(&mos_parport->syncmsg_compl); /* cycle parallel port reset bit */ @@ -1867,8 +1711,6 @@ static void mos7720_release(struct usb_serial *serial) if (le16_to_cpu(serial->dev->descriptor.idProduct) == MOSCHIP_DEVICE_ID_7715) { - struct urbtracker *urbtrack; - unsigned long flags; struct mos7715_parport *mos_parport = usb_get_serial_data(serial); @@ -1881,21 +1723,17 @@ static void mos7720_release(struct usb_serial *serial) if (mos_parport->msg_pending) wait_for_completion_timeout(&mos_parport->syncmsg_compl, msecs_to_jiffies(MOS_WDR_TIMEOUT)); + /* + * If delayed work is currently scheduled, wait for it to + * complete. This also implies barriers that ensure the + * below serial clearing is not hoisted above the ->work. + */ + cancel_work_sync(&mos_parport->work); parport_remove_port(mos_parport->pp); usb_set_serial_data(serial, NULL); mos_parport->serial = NULL; - /* if tasklet currently scheduled, wait for it to complete */ - tasklet_kill(&mos_parport->urb_tasklet); - - /* unlink any urbs sent by the tasklet */ - spin_lock_irqsave(&mos_parport->listlock, flags); - list_for_each_entry(urbtrack, - &mos_parport->active_urbs, - urblist_entry) - usb_unlink_urb(urbtrack->urb); - spin_unlock_irqrestore(&mos_parport->listlock, flags); parport_del_port(mos_parport->pp); kref_put(&mos_parport->ref_count, destroy_mos_parport); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 56d6f6d83bd7..2c21e34235bb 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -563,6 +563,9 @@ static void option_instat_callback(struct urb *urb); /* Device flags */ +/* Highest interface number which can be used with NCTRL() and RSVD() */ +#define FLAG_IFNUM_MAX 7 + /* Interface does not support modem-control requests */ #define NCTRL(ifnum) ((BIT(ifnum) & 0xff) << 8) @@ -2101,6 +2104,14 @@ static struct usb_serial_driver * const serial_drivers[] = { module_usb_serial_driver(serial_drivers, option_ids); +static bool iface_is_reserved(unsigned long device_flags, u8 ifnum) +{ + if (ifnum > FLAG_IFNUM_MAX) + return false; + + return device_flags & RSVD(ifnum); +} + static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) { @@ -2117,7 +2128,7 @@ static int option_probe(struct usb_serial *serial, * the same class/subclass/protocol as the serial interfaces. Look at * the Windows driver .INF files for reserved interface numbers. */ - if (device_flags & RSVD(iface_desc->bInterfaceNumber)) + if (iface_is_reserved(device_flags, iface_desc->bInterfaceNumber)) return -ENODEV; /* @@ -2133,6 +2144,14 @@ static int option_probe(struct usb_serial *serial, return 0; } +static bool iface_no_modem_control(unsigned long device_flags, u8 ifnum) +{ + if (ifnum > FLAG_IFNUM_MAX) + return false; + + return device_flags & NCTRL(ifnum); +} + static int option_attach(struct usb_serial *serial) { struct usb_interface_descriptor *iface_desc; @@ -2148,7 +2167,7 @@ static int option_attach(struct usb_serial *serial) iface_desc = &serial->interface->cur_altsetting->desc; - if (!(device_flags & NCTRL(iface_desc->bInterfaceNumber))) + if (!iface_no_modem_control(device_flags, iface_desc->bInterfaceNumber)) data->use_send_setup = 1; if (device_flags & ZLP) |