diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 911d74f20f0e..12db0589ee27 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -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); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index dd4cfd17f7ad..4ee0bdf98c0e 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -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; diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 35473544f1c8..22c5f071f116 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -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 = { diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 580f06f5ce5e..e4ad14375d6a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -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); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 0bcbdcea52af..bf42a545c20f 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -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; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index d60eda7f6eda..8eb1e7b5d3ec 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -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