aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/keyspan_pda.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/keyspan_pda.c')
-rw-r--r--drivers/usb/serial/keyspan_pda.c548
1 files changed, 237 insertions, 311 deletions
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
};