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. -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQHbPq+cpGvN/peuzMLxc3C7H1lCAUCX9OIiQAKCRALxc3C7H1l CA1OAQCZVi5abi2R/+Rr3V9/iYOA/VJXJ6Mxg8xDbt3GWmp0lQD9G4z0Ws4f1RY1 ACEcOBNQedpoxXa/o3eb8tlAjObwAwg= =udri -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
007e337080
|
@ -89,7 +89,6 @@ CONFIG_USB_SERIAL_KEYSPAN=m
|
|||
CONFIG_USB_SERIAL_MCT_U232=m
|
||||
CONFIG_USB_SERIAL_PL2303=m
|
||||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_EXT2_FS=m
|
||||
CONFIG_EXT3_FS=m
|
||||
|
|
|
@ -191,7 +191,6 @@ CONFIG_USB_SERIAL_PL2303=m
|
|||
CONFIG_USB_SERIAL_SAFE=m
|
||||
CONFIG_USB_SERIAL_TI=m
|
||||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_EMI62=m
|
||||
CONFIG_USB_EMI26=m
|
||||
|
|
|
@ -574,7 +574,6 @@ CONFIG_USB_SERIAL_PL2303=m
|
|||
CONFIG_USB_SERIAL_SAFE=m
|
||||
CONFIG_USB_SERIAL_TI=m
|
||||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_EMI62=m
|
||||
CONFIG_USB_EMI26=m
|
||||
|
|
|
@ -185,7 +185,6 @@ CONFIG_USB_SERIAL_PL2303=m
|
|||
CONFIG_USB_SERIAL_SAFE=m
|
||||
CONFIG_USB_SERIAL_TI=m
|
||||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_EMI62=m
|
||||
CONFIG_USB_EMI26=m
|
||||
|
|
|
@ -565,7 +565,6 @@ CONFIG_USB_SERIAL_SAFE=m
|
|||
CONFIG_USB_SERIAL_SIERRAWIRELESS=m
|
||||
CONFIG_USB_SERIAL_TI=m
|
||||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OPTION=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_EMI62=m
|
||||
|
|
|
@ -311,7 +311,6 @@ CONFIG_USB_SERIAL_PL2303=m
|
|||
CONFIG_USB_SERIAL_SAFE=m
|
||||
CONFIG_USB_SERIAL_SAFE_PADDED=y
|
||||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_LEGOTOWER=m
|
||||
CONFIG_USB_LCD=m
|
||||
|
|
|
@ -194,7 +194,6 @@ CONFIG_USB_SERIAL_SAFE=m
|
|||
CONFIG_USB_SERIAL_SAFE_PADDED=y
|
||||
CONFIG_USB_SERIAL_TI=m
|
||||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_APPLEDISPLAY=m
|
||||
CONFIG_EXT2_FS=y
|
||||
|
|
|
@ -911,7 +911,6 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y
|
|||
CONFIG_USB_SERIAL_SIERRAWIRELESS=m
|
||||
CONFIG_USB_SERIAL_TI=m
|
||||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OPTION=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_SERIAL_DEBUG=m
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
@ -593,46 +577,6 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
@ -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;
|
||||
if (C_CSTOPB(tty))
|
||||
bits |= BITS_STOP_2;
|
||||
else
|
||||
bits |= BITS_STOP_1;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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__);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
room = kmalloc(1, GFP_KERNEL);
|
||||
if (!room)
|
||||
return -ENOMEM;
|
||||
|
||||
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,8 +137,19 @@ 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)
|
||||
{
|
||||
|
@ -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 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
|
|||
__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");
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
return 0;
|
||||
}
|
||||
clear_bit(0, &port->write_urbs_free);
|
||||
spin_unlock_bh(&port->lock);
|
||||
if (count > room)
|
||||
count = room;
|
||||
if (count > port->bulk_out_size)
|
||||
count = port->bulk_out_size;
|
||||
|
||||
/* 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. */
|
||||
urb = port->write_urb;
|
||||
count = kfifo_out(&port->write_fifo, urb->transfer_buffer, count);
|
||||
urb->transfer_buffer_length = count;
|
||||
|
||||
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
|
||||
port->tx_bytes += count;
|
||||
priv->tx_room -= 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;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
room = kmalloc(1, GFP_KERNEL);
|
||||
if (!room) {
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
dev_dbg(&port->dev, "%s - count = %d, txroom = %d\n", __func__, count, room);
|
||||
|
||||
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;
|
||||
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 (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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
set_bit(0, &port->write_urbs_free);
|
||||
priv = usb_get_serial_port_data(port);
|
||||
|
||||
/* queue up a wakeup at scheduler time */
|
||||
schedule_work(&priv->wakeup_work);
|
||||
}
|
||||
|
||||
|
||||
static int keyspan_pda_write_room(struct tty_struct *tty)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
priv = usb_get_serial_port_data(port);
|
||||
|
||||
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
|
||||
n_tty.c:normal_poll() ) that we're not writeable. */
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled)
|
||||
ret = 256;
|
||||
port->tx_bytes -= urb->transfer_buffer_length;
|
||||
__set_bit(0, &port->write_urbs_free);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
return ret;
|
||||
|
||||
keyspan_pda_write_start(port);
|
||||
|
||||
usb_serial_port_softint(port);
|
||||
}
|
||||
|
||||
static int keyspan_pda_write(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
const unsigned char *buf, int count)
|
||||
{
|
||||
int rc;
|
||||
|
||||
dev_dbg(&port->dev, "%s - count = %d\n", __func__, count);
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
|
||||
|
||||
rc = keyspan_pda_write_start(port);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
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;
|
||||
}
|
||||
static void keyspan_pda_close(struct usb_serial_port *port)
|
||||
{
|
||||
usb_kill_urb(port->write_urb);
|
||||
usb_kill_urb(port->interrupt_in_urb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void keyspan_pda_close(struct usb_serial_port *port)
|
||||
{
|
||||
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
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -62,7 +62,6 @@
|
|||
* @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this
|
||||
* port.
|
||||
* @flags: usb serial port flags
|
||||
* @write_wait: a wait_queue_head_t used by the port.
|
||||
* @work: work queue entry for the line discipline waking up.
|
||||
* @dev: pointer to the serial device
|
||||
*
|
||||
|
@ -108,7 +107,6 @@ struct usb_serial_port {
|
|||
int tx_bytes;
|
||||
|
||||
unsigned long flags;
|
||||
wait_queue_head_t write_wait;
|
||||
struct work_struct work;
|
||||
unsigned long sysrq; /* sysrq timeout */
|
||||
struct device dev;
|
||||
|
|
Loading…
Reference in New Issue