USB serial updates for 7.3-rc1

Here are the USB serial updates for 7.3-rc1, including:
 
  - fix digi_acceleport port registration order
  - stop digi_acceleport I/O when ports are closed
  - fix digi_acceleport OOB port dev_printk()
  - fix metro-usb unthrottle race
  - fix option slab OOB read with malicious devices
  - add support for a new class of Prolific PL256X devices
 
 Included are also various clean ups.
 
 All have been in linux-next with no reported issues.
 -----BEGIN PGP SIGNATURE-----
 
 iJEEABYKADkWIQQHbPq+cpGvN/peuzMLxc3C7H1lCAUCanx8jhsUgAAAAAAEAA5t
 YW51MiwyLjUrMS4xMiwyLDIACgkQC8XNwux9ZQgLawD/c6N+U30HtX8XToVPvdur
 +QJeRlxiRjJR34ObmZMmDOgBAIm03twNNY3lGj1oagSGYkJ7HaB00lU4AEn+RlAU
 3WEK
 =CRDf
 -----END PGP SIGNATURE-----

Merge tag 'usb-serial-7.3-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next

Johan writes:

USB serial updates for 7.3-rc1

Here are the USB serial updates for 7.3-rc1, including:

 - fix digi_acceleport port registration order
 - stop digi_acceleport I/O when ports are closed
 - fix digi_acceleport OOB port dev_printk()
 - fix metro-usb unthrottle race
 - fix option slab OOB read with malicious devices
 - add support for a new class of Prolific PL256X devices

Included are also various clean ups.

All have been in linux-next with no reported issues.

* tag 'usb-serial-7.3-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial:
  USB: serial: pl2303: add support for PL256X multi-port devices
  USB: serial: option: fix slab OOB read in interrupt URB callback
  USB: serial: keyspan_pda: drop unused driver data usb-serial pointer
  USB: serial: metro-usb: drop redundant initialisations
  USB: serial: metro-usb: fix unthrottle race
  USB: serial: metro-usb: replace unnecessary atomic allocation
  USB: serial: digi_acceleport: fix oob port dev_printk()
  USB: serial: digi_acceleport: clean up inb command submission
  USB: serial: digi_acceleport: clean up write completion
  USB: serial: digi_acceleport: clean up xfer buf length expression
  USB: serial: digi_acceleport: drop unused in-buf define
  USB: serial: digi_acceleport: stop OOB I/O when not in use
  USB: serial: digi_acceleport: drop redundant driver data sanity checks
  USB: serial: digi_acceleport: clean up declarations and whitespace
  USB: serial: digi_acceleport: add oob port helper
  USB: serial: digi_acceleport: always stop write urb on close
  USB: serial: digi_acceleport: drop unused wait queue
  USB: serial: digi_acceleport: fix port registration order
  USB: serial: digi_acceleport: do not log stopping of urbs as errors
This commit is contained in:
Greg Kroah-Hartman 2026-08-14 10:25:23 +09:00
commit 05abeffcc2
6 changed files with 269 additions and 218 deletions

View File

@ -32,10 +32,6 @@
/* so we can be sure to send the full buffer in one urb */
#define DIGI_OUT_BUF_SIZE 8
/* port input buffer length -- must be >= transfer buffer length - 3 */
/* so we can be sure to hold at least one full buffer from one urb */
#define DIGI_IN_BUF_SIZE 64
/* retry timeout while sleeping */
#define DIGI_RETRY_TIMEOUT (HZ/10)
@ -176,10 +172,10 @@
/* Structures */
struct digi_serial {
spinlock_t ds_serial_lock;
struct mutex open_mutex;
struct usb_serial_port *ds_oob_port; /* out-of-band port */
int ds_oob_port_num; /* index of out-of-band port */
int ds_device_started;
int open_count;
};
struct digi_port {
@ -194,7 +190,6 @@ struct digi_port {
int dp_throttled;
int dp_throttle_restart;
wait_queue_head_t dp_flush_wait;
wait_queue_head_t dp_close_wait; /* wait queue for close */
wait_queue_head_t write_wait;
struct usb_serial_port *dp_port;
};
@ -227,9 +222,7 @@ static unsigned int digi_chars_in_buffer(struct tty_struct *tty);
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port);
static void digi_close(struct usb_serial_port *port);
static void digi_dtr_rts(struct usb_serial_port *port, int on);
static int digi_startup_device(struct usb_serial *serial);
static int digi_startup(struct usb_serial *serial);
static void digi_disconnect(struct usb_serial *serial);
static void digi_release(struct usb_serial *serial);
static int digi_port_probe(struct usb_serial_port *port);
static void digi_port_remove(struct usb_serial_port *port);
@ -272,7 +265,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.dtr_rts = digi_dtr_rts,
.write = digi_write,
.write_room = digi_write_room,
.write_bulk_callback = digi_write_bulk_callback,
.write_bulk_callback = digi_write_bulk_callback,
.read_bulk_callback = digi_read_bulk_callback,
.chars_in_buffer = digi_chars_in_buffer,
.throttle = digi_rx_throttle,
@ -282,7 +275,6 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.tiocmget = digi_tiocmget,
.tiocmset = digi_tiocmset,
.attach = digi_startup,
.disconnect = digi_disconnect,
.release = digi_release,
.port_probe = digi_port_probe,
.port_remove = digi_port_remove,
@ -301,7 +293,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.close = digi_close,
.write = digi_write,
.write_room = digi_write_room,
.write_bulk_callback = digi_write_bulk_callback,
.write_bulk_callback = digi_write_bulk_callback,
.read_bulk_callback = digi_read_bulk_callback,
.chars_in_buffer = digi_chars_in_buffer,
.throttle = digi_rx_throttle,
@ -311,7 +303,6 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.tiocmget = digi_tiocmget,
.tiocmset = digi_tiocmset,
.attach = digi_startup,
.disconnect = digi_disconnect,
.release = digi_release,
.port_probe = digi_port_probe,
.port_remove = digi_port_remove,
@ -335,7 +326,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
* interruptible_sleep_on_timeout is deprecated and has been replaced
* with the equivalent code.
*/
static long cond_wait_interruptible_timeout_irqrestore(
wait_queue_head_t *q, long timeout,
spinlock_t *lock, unsigned long flags)
@ -351,6 +341,13 @@ __releases(lock)
return timeout;
}
static struct usb_serial_port *digi_get_oob_port(struct usb_serial *serial)
{
struct digi_serial *serial_priv = usb_get_serial_data(serial);
return serial_priv->ds_oob_port;
}
/*
* Digi Write OOB Command
*
@ -361,15 +358,14 @@ __releases(lock)
* the interruptible flag is true, or a negative error
* returned by usb_submit_urb.
*/
static int digi_write_oob_command(struct usb_serial_port *port,
unsigned char *buf, int count, int interruptible)
{
int ret = 0;
int len;
struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
struct usb_serial_port *oob_port = digi_get_oob_port(port->serial);
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
unsigned long flags;
int ret = 0;
int len;
dev_dbg(&port->dev,
"digi_write_oob_command: TOP: port=%d, count=%d\n",
@ -406,10 +402,8 @@ static int digi_write_oob_command(struct usb_serial_port *port,
dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n",
__func__, ret);
return ret;
}
/*
* Digi Write In Band Command
*
@ -421,16 +415,15 @@ static int digi_write_oob_command(struct usb_serial_port *port,
* timeout ticks. Returns 0 if successful, or a negative
* error returned by digi_write.
*/
static int digi_write_inb_command(struct usb_serial_port *port,
unsigned char *buf, int count, unsigned long timeout)
{
int ret = 0;
int len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
unsigned long expire;
unsigned long flags;
int ret = 0;
int len;
dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n",
priv->dp_port_num, count);
@ -459,7 +452,7 @@ static int digi_write_inb_command(struct usb_serial_port *port,
/* len must be a multiple of 4 and small enough to */
/* guarantee the write will send buffered data first, */
/* so commands are in order with data and not split */
len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
len = min(count, port->bulk_out_size - 2 - priv->dp_out_buf_len);
if (len > 4)
len &= ~3;
@ -467,11 +460,10 @@ static int digi_write_inb_command(struct usb_serial_port *port,
if (priv->dp_out_buf_len > 0) {
data[0] = DIGI_CMD_SEND_DATA;
data[1] = priv->dp_out_buf_len;
memcpy(data + 2, priv->dp_out_buf,
priv->dp_out_buf_len);
memcpy(data + 2, priv->dp_out_buf, priv->dp_out_buf_len);
memcpy(data + 2 + priv->dp_out_buf_len, buf, len);
port->write_urb->transfer_buffer_length
= priv->dp_out_buf_len + 2 + len;
port->write_urb->transfer_buffer_length =
priv->dp_out_buf_len + 2 + len;
} else {
memcpy(data, buf, len);
port->write_urb->transfer_buffer_length = len;
@ -484,7 +476,6 @@ static int digi_write_inb_command(struct usb_serial_port *port,
count -= len;
buf += len;
}
}
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
@ -495,7 +486,6 @@ static int digi_write_inb_command(struct usb_serial_port *port,
return ret;
}
/*
* Digi Set Modem Signals
*
@ -505,17 +495,15 @@ static int digi_write_inb_command(struct usb_serial_port *port,
* -EINTR if interrupted while sleeping, or a non-zero error
* returned by usb_submit_urb.
*/
static int digi_set_modem_signals(struct usb_serial_port *port,
unsigned int modem_signals, int interruptible)
{
int ret;
struct digi_port *port_priv = usb_get_serial_port_data(port);
struct usb_serial_port *oob_port = (struct usb_serial_port *) ((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;
struct usb_serial_port *oob_port = digi_get_oob_port(port->serial);
struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
unsigned char *data = oob_port->write_urb->transfer_buffer;
unsigned long flags;
int ret;
dev_dbg(&port->dev,
"digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n",
@ -573,14 +561,13 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
* is only called from close, and only one process can be in close on a
* port at a time, so its ok.
*/
static int digi_transmit_idle(struct usb_serial_port *port,
unsigned long timeout)
{
int ret;
unsigned char buf[2];
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char buf[2];
unsigned long flags;
int ret;
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_transmit_idle = 0;
@ -607,16 +594,15 @@ static int digi_transmit_idle(struct usb_serial_port *port,
}
priv->dp_transmit_idle = 0;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
return 0;
}
static void digi_rx_throttle(struct tty_struct *tty)
{
unsigned long flags;
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned long flags;
/* stop receiving characters by not resubmitting the read urb */
spin_lock_irqsave(&priv->dp_port_lock, flags);
@ -625,13 +611,12 @@ static void digi_rx_throttle(struct tty_struct *tty)
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
}
static void digi_rx_unthrottle(struct tty_struct *tty)
{
int ret = 0;
unsigned long flags;
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&priv->dp_port_lock, flags);
@ -651,7 +636,6 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
__func__, ret, priv->dp_port_num);
}
static void digi_set_termios(struct tty_struct *tty,
struct usb_serial_port *port,
const struct ktermios *old_termios)
@ -762,7 +746,6 @@ static void digi_set_termios(struct tty_struct *tty,
/* set stop bits */
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
if ((cflag & CSTOPB))
arg = DIGI_STOP_BITS_2;
else
@ -772,7 +755,6 @@ static void digi_set_termios(struct tty_struct *tty,
buf[i++] = priv->dp_port_num;
buf[i++] = arg;
buf[i++] = 0;
}
/* set input flow control */
@ -841,7 +823,6 @@ static void digi_set_termios(struct tty_struct *tty,
tty_encode_baud_rate(tty, baud, baud);
}
static int digi_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
@ -855,50 +836,48 @@ static int digi_break_ctl(struct tty_struct *tty, int break_state)
return digi_write_inb_command(port, buf, 4, 0);
}
static int digi_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned int val;
unsigned long flags;
unsigned int val;
spin_lock_irqsave(&priv->dp_port_lock, flags);
val = priv->dp_modem_signals;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
return val;
}
static int digi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned int val;
unsigned long flags;
unsigned int val;
spin_lock_irqsave(&priv->dp_port_lock, flags);
val = (priv->dp_modem_signals & ~clear) | set;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
return digi_set_modem_signals(port, val, 1);
}
static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
int ret, data_len, new_len;
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = port->write_urb->transfer_buffer;
int ret, data_len, new_len;
unsigned long flags;
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);
count = min(count, port->bulk_out_size - 2);
count = min(64, count);
/* be sure only one write proceeds at a time */
@ -920,7 +899,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
/* allow space for any buffered data and for new data, up to */
/* transfer buffer size - 2 (for command and length bytes) */
new_len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
new_len = min(count, port->bulk_out_size - 2 - priv->dp_out_buf_len);
data_len = new_len + priv->dp_out_buf_len;
if (data_len == 0) {
@ -928,7 +907,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
return 0;
}
port->write_urb->transfer_buffer_length = data_len+2;
port->write_urb->transfer_buffer_length = data_len + 2;
*data++ = DIGI_CMD_SEND_DATA;
*data++ = data_len;
@ -954,39 +933,22 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
dev_dbg(&port->dev, "digi_write: returning %d\n", ret);
return ret;
return ret;
}
static void digi_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct usb_serial *serial;
struct digi_port *priv;
struct digi_serial *serial_priv;
struct digi_serial *serial_priv = usb_get_serial_data(port->serial);
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
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) {
pr_err("%s: port or port->private is NULL, status=%d\n",
__func__, status);
return;
}
serial = port->serial;
if (serial == NULL || (serial_priv = usb_get_serial_data(serial)) == NULL) {
dev_err(&port->dev,
"%s: serial or serial->private is NULL, status=%d\n",
__func__, status);
return;
}
int ret = 0;
/* handle oob callback */
if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
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(&priv->write_wait);
@ -999,15 +961,13 @@ static void digi_write_bulk_callback(struct urb *urb)
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_write_urb_in_use = 0;
if (priv->dp_out_buf_len > 0) {
*((unsigned char *)(port->write_urb->transfer_buffer))
= (unsigned char)DIGI_CMD_SEND_DATA;
*((unsigned char *)(port->write_urb->transfer_buffer) + 1)
= (unsigned char)priv->dp_out_buf_len;
port->write_urb->transfer_buffer_length =
priv->dp_out_buf_len + 2;
memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf,
priv->dp_out_buf_len);
ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
data[0] = DIGI_CMD_SEND_DATA;
data[1] = priv->dp_out_buf_len;
memcpy(data + 2, priv->dp_out_buf, priv->dp_out_buf_len);
urb->transfer_buffer_length = priv->dp_out_buf_len + 2;
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret == 0) {
priv->dp_write_urb_in_use = 1;
priv->dp_out_buf_len = 0;
@ -1041,8 +1001,8 @@ static unsigned int digi_write_room(struct tty_struct *tty)
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
dev_dbg(&port->dev, "digi_write_room: port=%d, room=%u\n", priv->dp_port_num, room);
return room;
return room;
}
static unsigned int digi_chars_in_buffer(struct tty_struct *tty)
@ -1070,17 +1030,53 @@ static void digi_dtr_rts(struct usb_serial_port *port, int on)
digi_set_modem_signals(port, on * (TIOCM_DTR | TIOCM_RTS), 1);
}
static int digi_open_oob_port(struct usb_serial *serial)
{
struct digi_serial *serial_priv = usb_get_serial_data(serial);
struct usb_serial_port *oob_port = serial_priv->ds_oob_port;
int ret = 0;
mutex_lock(&serial_priv->open_mutex);
if (serial_priv->open_count++ == 0) {
ret = usb_submit_urb(oob_port->read_urb, GFP_KERNEL);
if (ret) {
dev_err(&serial->interface->dev, "failed to submit OOB read urb: %d\n",
ret);
serial_priv->open_count--;
}
}
mutex_unlock(&serial_priv->open_mutex);
return ret;
}
static void digi_close_oob_port(struct usb_serial *serial)
{
struct digi_serial *serial_priv = usb_get_serial_data(serial);
struct usb_serial_port *oob_port = serial_priv->ds_oob_port;
mutex_lock(&serial_priv->open_mutex);
if (serial_priv->open_count-- == 1) {
usb_kill_urb(oob_port->read_urb);
usb_kill_urb(oob_port->write_urb);
}
mutex_unlock(&serial_priv->open_mutex);
}
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int ret;
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
int throttled;
unsigned char buf[32];
int ret;
/* be sure the device is started up */
if (digi_startup_device(port->serial) != 0)
return -ENXIO;
ret = digi_open_oob_port(port->serial);
if (ret)
return ret;
/* read modem signals automatically whenever they change */
buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;
@ -1106,32 +1102,34 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
}
spin_lock_irq(&priv->dp_port_lock);
throttled = priv->dp_throttle_restart;
priv->dp_throttled = 0;
priv->dp_throttle_restart = 0;
spin_unlock_irq(&priv->dp_port_lock);
if (throttled) {
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (ret) {
dev_err(&port->dev, "failed to submit read urb: %d\n", ret);
return ret;
}
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (ret) {
dev_err(&port->dev, "failed to submit read urb: %d\n", ret);
goto err_close_oob;
}
return 0;
}
err_close_oob:
digi_close_oob_port(port->serial);
return ret;
}
static void digi_close(struct usb_serial_port *port)
{
struct digi_port *priv = usb_get_serial_port_data(port);
unsigned char buf[32];
DEFINE_WAIT(wait);
int ret;
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
usb_kill_urb(port->read_urb);
mutex_lock(&port->serial->disc_mutex);
/* if disconnected, just clear flags */
if (port->serial->disconnected)
goto exit;
@ -1177,53 +1175,13 @@ static void digi_close(struct usb_serial_port *port)
TASK_INTERRUPTIBLE);
schedule_timeout(DIGI_CLOSE_TIMEOUT);
finish_wait(&priv->dp_flush_wait, &wait);
exit:
mutex_unlock(&port->serial->disc_mutex);
/* shutdown any outstanding bulk writes */
usb_kill_urb(port->write_urb);
exit:
spin_lock_irq(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
wake_up_interruptible(&priv->dp_close_wait);
spin_unlock_irq(&priv->dp_port_lock);
mutex_unlock(&port->serial->disc_mutex);
}
/*
* Digi Startup Device
*
* Starts reads on all ports. Must be called AFTER startup, with
* urbs initialized. Returns 0 if successful, non-zero error otherwise.
*/
static int digi_startup_device(struct usb_serial *serial)
{
int i, ret = 0;
struct digi_serial *serial_priv = usb_get_serial_data(serial);
struct usb_serial_port *port;
/* be sure this happens exactly once */
spin_lock(&serial_priv->ds_serial_lock);
if (serial_priv->ds_device_started) {
spin_unlock(&serial_priv->ds_serial_lock);
return 0;
}
serial_priv->ds_device_started = 1;
spin_unlock(&serial_priv->ds_serial_lock);
/* start reading from each bulk in endpoint for the device */
/* set USB_DISABLE_SPD flag for write bulk urbs */
for (i = 0; i < serial->type->num_ports + 1; i++) {
port = serial->port[i];
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (ret != 0) {
dev_err(&port->dev,
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, i);
break;
}
}
return ret;
digi_close_oob_port(port->serial);
}
static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
@ -1243,7 +1201,6 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
priv->dp_port_num = 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_waitqueue_head(&priv->write_wait);
priv->dp_port = port;
@ -1280,7 +1237,8 @@ static int digi_startup(struct usb_serial *serial)
if (!serial_priv)
return -ENOMEM;
spin_lock_init(&serial_priv->ds_serial_lock);
mutex_init(&serial_priv->open_mutex);
serial_priv->ds_oob_port_num = oob_port_num;
serial_priv->ds_oob_port = serial->port[oob_port_num];
@ -1296,19 +1254,6 @@ static int digi_startup(struct usb_serial *serial)
return 0;
}
static void digi_disconnect(struct usb_serial *serial)
{
int i;
/* stop reads and writes on all ports */
for (i = 0; i < serial->type->num_ports + 1; i++) {
usb_kill_urb(serial->port[i]->read_urb);
usb_kill_urb(serial->port[i]->write_urb);
}
}
static void digi_release(struct usb_serial *serial)
{
struct digi_serial *serial_priv;
@ -1338,30 +1283,25 @@ static void digi_port_remove(struct usb_serial_port *port)
static void digi_read_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct digi_port *priv;
struct digi_serial *serial_priv;
int ret;
struct usb_serial *serial = port->serial;
struct digi_serial *serial_priv = usb_get_serial_data(serial);
struct digi_port *priv = usb_get_serial_port_data(port);
int status = urb->status;
/* port sanity check, do not resubmit if port is not valid */
if (port == NULL)
return;
priv = usb_get_serial_port_data(port);
if (priv == NULL) {
dev_err(&port->dev, "%s: port->private is NULL, status=%d\n",
__func__, status);
return;
}
if (port->serial == NULL ||
(serial_priv = usb_get_serial_data(port->serial)) == NULL) {
dev_err(&port->dev, "%s: serial is bad or serial->private "
"is NULL, status=%d\n", __func__, status);
return;
}
int ret;
/* do not resubmit urb if it has any status error */
if (status) {
dev_err(&port->dev,
switch (status) {
case 0:
break;
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
dev_err(&serial->interface->dev,
"%s: nonzero read bulk status: status=%d, port=%d\n",
__func__, status, priv->dp_port_num);
return;
default:
dev_err(&serial->interface->dev,
"%s: nonzero read bulk status: status=%d, port=%d\n",
__func__, status, priv->dp_port_num);
return;
@ -1379,11 +1319,10 @@ static void digi_read_bulk_callback(struct urb *urb)
/* continue read */
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret != 0 && ret != -EPERM) {
dev_err(&port->dev,
dev_err(&serial->interface->dev,
"%s: failed resubmitting urb, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
}
}
/*
@ -1395,7 +1334,6 @@ static void digi_read_bulk_callback(struct urb *urb)
* It returns 0 if successful, 1 if successful but the port is
* throttled, and -1 if the sanity checks failed.
*/
static int digi_read_inb_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@ -1473,10 +1411,8 @@ static int digi_read_inb_callback(struct urb *urb)
dev_dbg(&port->dev, "%s: unknown opcode: %d\n", __func__, opcode);
return throttled ? 1 : 0;
}
/*
* Digi Read OOB Callback
*
@ -1485,10 +1421,8 @@ static int digi_read_inb_callback(struct urb *urb)
* the port->serial is valid. It returns 0 if successful, and
* -1 if the sanity checks failed.
*/
static int digi_read_oob_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct usb_serial *serial = port->serial;
struct tty_struct *tty;
@ -1496,8 +1430,8 @@ static int digi_read_oob_callback(struct urb *urb)
unsigned char *buf = urb->transfer_buffer;
int opcode, line, status, val;
unsigned long flags;
int i;
unsigned int rts;
int i;
if (urb->actual_length < 4)
return -1;
@ -1509,7 +1443,8 @@ static int digi_read_oob_callback(struct urb *urb)
status = buf[i + 2];
val = buf[i + 3];
dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
dev_dbg(&serial->interface->dev,
"digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
opcode, line, status, val);
if (status != 0 || line >= serial->type->num_ports)
@ -1567,8 +1502,8 @@ static int digi_read_oob_callback(struct urb *urb)
}
tty_kref_put(tty);
}
return 0;
return 0;
}
module_usb_serial_driver(serial_drivers, id_table_combined);

View File

@ -31,7 +31,6 @@
struct keyspan_pda_private {
int tx_room;
struct work_struct unthrottle_work;
struct usb_serial *serial;
struct usb_serial_port *port;
bool throttled;
bool throttle_req;

View File

@ -36,6 +36,7 @@
struct metrousb_private {
spinlock_t lock;
int throttled;
int throttle_req;
unsigned long control_state;
};
@ -108,7 +109,7 @@ static void metrousb_read_int_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
int throttled = 0;
int result = 0;
int result;
dev_dbg(&port->dev, "%s\n", __func__);
@ -143,7 +144,10 @@ static void metrousb_read_int_callback(struct urb *urb)
/* Set any port variables. */
spin_lock_irqsave(&metro_priv->lock, flags);
throttled = metro_priv->throttled;
if (metro_priv->throttle_req) {
metro_priv->throttled = 1;
throttled = 1;
}
spin_unlock_irqrestore(&metro_priv->lock, flags);
if (throttled)
@ -169,12 +173,13 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
struct usb_serial *serial = port->serial;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
unsigned long flags;
int result = 0;
int result;
/* Set the private data information for the port. */
spin_lock_irqsave(&metro_priv->lock, flags);
metro_priv->control_state = 0;
metro_priv->throttled = 0;
metro_priv->throttle_req = 0;
spin_unlock_irqrestore(&metro_priv->lock, flags);
/* Clear the urb pipe. */
@ -269,7 +274,7 @@ static void metrousb_throttle(struct tty_struct *tty)
/* Set the private information for the port to stop reading data. */
spin_lock_irqsave(&metro_priv->lock, flags);
metro_priv->throttled = 1;
metro_priv->throttle_req = 1;
spin_unlock_irqrestore(&metro_priv->lock, flags);
}
@ -321,19 +326,23 @@ static void metrousb_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
unsigned long flags;
int result = 0;
int throttled;
int result;
/* Set the private information for the port to resume reading data. */
spin_lock_irqsave(&metro_priv->lock, flags);
throttled = metro_priv->throttled;
metro_priv->throttled = 0;
metro_priv->throttle_req = 0;
spin_unlock_irqrestore(&metro_priv->lock, flags);
/* Submit the urb to read from the port. */
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev,
"failed submitting interrupt in urb error code=%d\n",
result);
if (throttled) {
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "failed to submit interrupt in urb: %d\n",
result);
}
}
}
static struct usb_serial_driver metrousb_device = {

View File

@ -2689,12 +2689,26 @@ static void option_instat_callback(struct urb *urb)
dev_dbg(dev, "%s: NULL req_pkt\n", __func__);
return;
}
if (urb->actual_length < sizeof(*req_pkt)) {
dev_err(dev, "%s: short packet: %u bytes\n", __func__,
urb->actual_length);
return;
}
if ((req_pkt->bRequestType == 0xA1) &&
(req_pkt->bRequest == 0x20)) {
unsigned char signals;
int old_dcd_state;
unsigned char signals = *((unsigned char *)
urb->transfer_buffer +
sizeof(struct usb_ctrlrequest));
if (urb->actual_length < sizeof(*req_pkt) + 1) {
dev_err(dev, "%s: short interrupt transfer: %u bytes\n",
__func__, urb->actual_length);
return;
}
signals = *((unsigned char *)urb->transfer_buffer +
sizeof(*req_pkt));
dev_dbg(dev, "%s: signal x%x\n", __func__, signals);

View File

@ -51,6 +51,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GL) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GE) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GS) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL256X_PRODUCT_ID_4P) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID),
@ -141,10 +142,15 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define VENDOR_WRITE_REQUEST_TYPE 0x40
#define VENDOR_WRITE_REQUEST 0x01
#define VENDOR_WRITE_NREQUEST 0x80
#define VENDOR_WRITE_MPREQUEST 0x80
#define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01
#define VENDOR_READ_NREQUEST 0x81
#define VENDOR_READ_MPREQUEST 0x80
#define PL256X_RESET_REQUEST_TYPE 0x40
#define PL256X_RESET_REQUEST 0x96
#define UART_STATE_INDEX 8
#define UART_STATE_MSR_MASK 0x8b
@ -172,6 +178,16 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18
#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c
#define PL256X_PORT_A_FLOWCTRL_REG 0xc005
#define PL256X_PORT_B_FLOWCTRL_REG 0xd005
#define PL256X_PORT_C_FLOWCTRL_REG 0xe005
#define PL256X_PORT_D_FLOWCTRL_REG 0xf005
#define PL256X_FLOWCTRL_MASK 0x43
#define PL256X_FLOWCTRL_XON_XOFF 0x40
#define PL256X_FLOWCTRL_RTS_CTS 0x03
#define PL256X_FLOWCTRL_NONE 0x00
static int pl2303_set_break(struct usb_serial_port *port, bool enable);
enum pl2303_type {
@ -181,6 +197,7 @@ enum pl2303_type {
TYPE_TB,
TYPE_HXD,
TYPE_HXN,
TYPE_MP,
TYPE_COUNT
};
@ -196,6 +213,8 @@ struct pl2303_type_data {
struct pl2303_serial_private {
const struct pl2303_type_data *type;
unsigned long quirks;
u16 interface_num;
u16 flowctrl_reg;
};
struct pl2303_private {
@ -236,8 +255,30 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
.max_baud_rate = 12000000,
.no_divisors = true,
},
[TYPE_MP] = {
.name = "MP",
.max_baud_rate = 24000000,
.no_divisors = true,
},
};
static int pl256x_uart_reset(struct usb_serial *serial)
{
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
struct device *dev = &serial->interface->dev;
int res;
res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
PL256X_RESET_REQUEST, PL256X_RESET_REQUEST_TYPE,
0, spriv->interface_num, NULL, 0, 100);
if (res) {
dev_err(dev, "failed to reset device: %d\n", res);
return res;
}
return 0;
}
static int pl2303_vendor_read(struct usb_serial *serial, u16 value,
unsigned char buf[1])
{
@ -248,6 +289,8 @@ static int pl2303_vendor_read(struct usb_serial *serial, u16 value,
if (spriv->type == &pl2303_type_data[TYPE_HXN])
request = VENDOR_READ_NREQUEST;
else if (spriv->type == &pl2303_type_data[TYPE_MP])
request = VENDOR_READ_MPREQUEST;
else
request = VENDOR_READ_REQUEST;
@ -279,6 +322,8 @@ static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
if (spriv->type == &pl2303_type_data[TYPE_HXN])
request = VENDOR_WRITE_NREQUEST;
else if (spriv->type == &pl2303_type_data[TYPE_MP])
request = VENDOR_WRITE_MPREQUEST;
else
request = VENDOR_WRITE_REQUEST;
@ -304,10 +349,12 @@ static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val)
if (!buf)
return -ENOMEM;
if (spriv->type == &pl2303_type_data[TYPE_HXN])
if (spriv->type == &pl2303_type_data[TYPE_HXN] ||
spriv->type == &pl2303_type_data[TYPE_MP]) {
ret = pl2303_vendor_read(serial, reg, buf);
else
} else {
ret = pl2303_vendor_read(serial, reg | 0x80, buf);
}
if (ret)
goto out_free;
@ -458,6 +505,14 @@ static int pl2303_detect_type(struct usb_serial *serial)
case 0x905: /* GT-2AB */
case 0x1005: /* GC-Q20 */
return TYPE_HXN;
case 0x3302: /* PL2533 VC 2 Port */
case 0x3304: /* PL2533 VC 4 Port */
case 0x4302: /* PL2543 VC 2 Port */
case 0x4304: /* PL2543 VC 4 Port */
case 0x6502: /* PL2565 VC 2 Port */
case 0x6504: /* PL2565 VC 4 Port */
case 0x6506: /* PL2565 VC 4 Port QFN64 package */
return TYPE_MP;
}
break;
}
@ -491,6 +546,7 @@ static int pl2303_startup(struct usb_serial *serial)
struct pl2303_serial_private *spriv;
enum pl2303_type type;
unsigned char *buf;
unsigned int ifnum;
int ret;
ret = pl2303_detect_type(serial);
@ -500,20 +556,43 @@ static int pl2303_startup(struct usb_serial *serial)
type = ret;
dev_dbg(&serial->interface->dev, "device type: %s\n", pl2303_type_data[type].name);
ifnum = serial->interface->altsetting->desc.bInterfaceNumber;
spriv = kzalloc_obj(*spriv);
if (!spriv)
return -ENOMEM;
if (type == TYPE_MP) {
switch (ifnum) {
case 0:
spriv->flowctrl_reg = PL256X_PORT_A_FLOWCTRL_REG;
break;
case 1:
spriv->flowctrl_reg = PL256X_PORT_B_FLOWCTRL_REG;
break;
case 2:
spriv->flowctrl_reg = PL256X_PORT_C_FLOWCTRL_REG;
break;
case 3:
spriv->flowctrl_reg = PL256X_PORT_D_FLOWCTRL_REG;
break;
default:
kfree(spriv);
return -ENODEV;
}
}
spriv->type = &pl2303_type_data[type];
spriv->quirks = (unsigned long)usb_get_serial_data(serial);
spriv->quirks |= spriv->type->quirks;
spriv->interface_num = ifnum;
if (type == TYPE_HXD && pl2303_is_hxd_clone(serial))
spriv->quirks |= PL2303_QUIRK_NO_BREAK_GETLINE;
usb_set_serial_data(serial, spriv);
if (type != TYPE_HXN) {
if (type != TYPE_HXN && type != TYPE_MP) {
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
kfree(spriv);
@ -575,13 +654,15 @@ static void pl2303_port_remove(struct usb_serial_port *port)
static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
{
struct usb_device *dev = port->serial->dev;
struct usb_serial *serial = port->serial;
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
int retval;
dev_dbg(&port->dev, "%s - %02x\n", __func__, value);
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
value, spriv->interface_num, NULL, 0, 100);
if (retval)
dev_err(&port->dev, "%s - failed: %d\n", __func__, retval);
@ -761,7 +842,7 @@ static int pl2303_get_line_request(struct usb_serial_port *port,
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
0, spriv->interface_num, buf, 7, 100);
if (ret != 7) {
dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
@ -780,11 +861,13 @@ static int pl2303_set_line_request(struct usb_serial_port *port,
unsigned char buf[7])
{
struct usb_device *udev = port->serial->dev;
struct usb_serial *serial = port->serial;
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
int ret;
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
0, spriv->interface_num, buf, 7, 100);
if (ret < 0) {
dev_err(&port->dev, "%s - failed: %d\n", __func__, ret);
return ret;
@ -939,6 +1022,9 @@ static void pl2303_set_termios(struct tty_struct *tty,
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
PL2303_HXN_FLOWCTRL_MASK,
PL2303_HXN_FLOWCTRL_RTS_CTS);
} else if (spriv->type == &pl2303_type_data[TYPE_MP]) {
pl2303_vendor_write(serial, spriv->flowctrl_reg,
PL256X_FLOWCTRL_RTS_CTS);
} else {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60);
}
@ -947,6 +1033,9 @@ static void pl2303_set_termios(struct tty_struct *tty,
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
PL2303_HXN_FLOWCTRL_MASK,
PL2303_HXN_FLOWCTRL_XON_XOFF);
} else if (spriv->type == &pl2303_type_data[TYPE_MP]) {
pl2303_vendor_write(serial, spriv->flowctrl_reg,
PL256X_FLOWCTRL_XON_XOFF);
} else {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0);
}
@ -955,6 +1044,9 @@ static void pl2303_set_termios(struct tty_struct *tty,
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
PL2303_HXN_FLOWCTRL_MASK,
PL2303_HXN_FLOWCTRL_NONE);
} else if (spriv->type == &pl2303_type_data[TYPE_MP]) {
pl2303_vendor_write(serial, spriv->flowctrl_reg,
PL256X_FLOWCTRL_NONE);
} else {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
}
@ -1002,6 +1094,8 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
pl2303_vendor_write(serial, PL2303_HXN_RESET_REG,
PL2303_HXN_RESET_UPSTREAM_PIPE |
PL2303_HXN_RESET_DOWNSTREAM_PIPE);
} else if (spriv->type == &pl2303_type_data[TYPE_MP]) {
pl256x_uart_reset(serial);
} else {
pl2303_vendor_write(serial, 8, 0);
pl2303_vendor_write(serial, 9, 0);
@ -1112,7 +1206,7 @@ static int pl2303_set_break(struct usb_serial_port *port, bool enable)
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
0, NULL, 0, 100);
spriv->interface_num, NULL, 0, 100);
if (result) {
dev_err(&port->dev, "error sending break = %d\n", result);
return result;

View File

@ -26,7 +26,7 @@
#define PL2303_PRODUCT_ID_HCR331 0x331a
#define PL2303_PRODUCT_ID_MOTOROLA 0x0307
#define PL2303_PRODUCT_ID_ZTEK 0xe1f1
#define PL256X_PRODUCT_ID_4P 0x2533
#define ATEN_VENDOR_ID 0x0557
#define ATEN_VENDOR_ID2 0x0547