diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-01-27 10:21:22 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-01-27 10:21:22 +0100 |
commit | eaa519983fd9e53c2a62a1e56777e1fb461865a9 (patch) | |
tree | ade6214da8b7b1732bfe56f5d13889ccf35b84f0 | |
parent | 880082666c8d08909bca0a3ea0d7162781f22786 (diff) | |
parent | 19c64e7354e50d19e7b5ddf94bfb5fa24d69594c (diff) | |
download | linux-eaa519983fd9e53c2a62a1e56777e1fb461865a9.tar.bz2 |
Merge tag 'usb-serial-5.6-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next
Johan writes:
Here are the USB-serial updates for 5.6-rc1, including:
- a missing ir-usb endpoint sanity check
- fixes for two long-standing regressions in ir-usb
- opticon chars_in_buffer support
Included are also various clean ups.
All have been in linux-next with no reported issues.
Signed-off-by: Johan Hovold <johan@kernel.org>
* tag 'usb-serial-5.6-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial:
USB: serial: cyberjack: fix spelling mistake "To" -> "Too"
USB: serial: ir-usb: simplify endpoint check
USB: serial: ir-usb: make set_termios synchronous
USB: serial: ir-usb: fix IrLAP framing
USB: serial: ir-usb: fix link-speed handling
USB: serial: ir-usb: add missing endpoint sanity check
USB: serial: garmin_gps: Use flexible-array member
USB: serial: opticon: stop all I/O on close()
USB: serial: opticon: add chars_in_buffer() implementation
-rw-r--r-- | drivers/usb/serial/cyberjack.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/garmin_gps.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/ir-usb.c | 185 | ||||
-rw-r--r-- | drivers/usb/serial/opticon.c | 61 | ||||
-rw-r--r-- | include/linux/usb/irda.h | 13 |
5 files changed, 172 insertions, 91 deletions
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index ebd76ab07b72..821970609695 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -276,7 +276,7 @@ static void cyberjack_read_int_callback(struct urb *urb) old_rdtodo = priv->rdtodo; if (old_rdtodo > SHRT_MAX - size) { - dev_dbg(dev, "To many bulk_in urbs to do.\n"); + dev_dbg(dev, "Too many bulk_in urbs to do.\n"); spin_unlock_irqrestore(&priv->lock, flags); goto resubmit; } diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 633550ec3025..ffd984142171 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -104,7 +104,7 @@ struct garmin_packet { int seq; /* the real size of the data array, always > 0 */ int size; - __u8 data[1]; + __u8 data[]; }; /* structure used to keep the current state of the driver */ diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 302eb9530859..79d0586e2b33 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -45,9 +45,10 @@ static int buffer_size; static int xbof = -1; static int ir_startup (struct usb_serial *serial); -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port); -static int ir_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); +static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +static int ir_write_room(struct tty_struct *tty); +static void ir_write_bulk_callback(struct urb *urb); static void ir_process_read_urb(struct urb *urb); static void ir_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); @@ -75,10 +76,13 @@ static struct usb_serial_driver ir_device = { .description = "IR Dongle", .id_table = ir_id_table, .num_ports = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, .set_termios = ir_set_termios, .attach = ir_startup, - .open = ir_open, - .prepare_write_buffer = ir_prepare_write_buffer, + .write = ir_write, + .write_room = ir_write_room, + .write_bulk_callback = ir_write_bulk_callback, .process_read_urb = ir_process_read_urb, }; @@ -251,35 +255,102 @@ static int ir_startup(struct usb_serial *serial) return 0; } -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) { - int i; + struct urb *urb = NULL; + unsigned long flags; + int ret; - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET; + if (port->bulk_out_size == 0) + return -EINVAL; - /* Start reading from the device */ - return usb_serial_generic_open(tty, port); -} + if (count == 0) + return 0; -static int ir_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - unsigned char *buf = dest; - int count; + count = min(count, port->bulk_out_size - 1); + + spin_lock_irqsave(&port->lock, flags); + if (__test_and_clear_bit(0, &port->write_urbs_free)) { + urb = port->write_urbs[0]; + port->tx_bytes += count; + } + spin_unlock_irqrestore(&port->lock, flags); + + if (!urb) + return 0; /* * The first byte of the packet we send to the device contains an - * inbound header which indicates an additional number of BOFs and + * outbound header which indicates an additional number of BOFs and * a baud rate change. * * See section 5.4.2.2 of the USB IrDA spec. */ - *buf = ir_xbof | ir_baud; + *(u8 *)urb->transfer_buffer = ir_xbof | ir_baud; + + memcpy(urb->transfer_buffer + 1, buf, count); + + urb->transfer_buffer_length = count + 1; + urb->transfer_flags = URB_ZERO_PACKET; + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + dev_err(&port->dev, "failed to submit write urb: %d\n", ret); + + spin_lock_irqsave(&port->lock, flags); + __set_bit(0, &port->write_urbs_free); + port->tx_bytes -= count; + spin_unlock_irqrestore(&port->lock, flags); + + return ret; + } + + return count; +} + +static void ir_write_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + int status = urb->status; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + __set_bit(0, &port->write_urbs_free); + port->tx_bytes -= urb->transfer_buffer_length - 1; + spin_unlock_irqrestore(&port->lock, flags); + + switch (status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + dev_dbg(&port->dev, "write urb stopped: %d\n", status); + return; + case -EPIPE: + dev_err(&port->dev, "write urb stopped: %d\n", status); + return; + default: + dev_err(&port->dev, "nonzero write-urb status: %d\n", status); + break; + } + + usb_serial_port_softint(port); +} - count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1, - &port->lock); - return count + 1; +static int ir_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + int count = 0; + + if (port->bulk_out_size == 0) + return 0; + + if (test_bit(0, &port->write_urbs_free)) + count = port->bulk_out_size - 1; + + return count; } static void ir_process_read_urb(struct urb *urb) @@ -304,23 +375,15 @@ static void ir_process_read_urb(struct urb *urb) tty_flip_buffer_push(&port->port); } -static void ir_set_termios_callback(struct urb *urb) -{ - kfree(urb->transfer_buffer); - - if (urb->status) - dev_dbg(&urb->dev->dev, "%s - non-zero urb status: %d\n", - __func__, urb->status); -} - static void ir_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - struct urb *urb; + struct usb_device *udev = port->serial->dev; unsigned char *transfer_buffer; - int result; + int actual_length; speed_t baud; int ir_baud; + int ret; baud = tty_get_baud_rate(tty); @@ -332,34 +395,34 @@ static void ir_set_termios(struct tty_struct *tty, switch (baud) { case 2400: - ir_baud = USB_IRDA_BR_2400; + ir_baud = USB_IRDA_LS_2400; break; case 9600: - ir_baud = USB_IRDA_BR_9600; + ir_baud = USB_IRDA_LS_9600; break; case 19200: - ir_baud = USB_IRDA_BR_19200; + ir_baud = USB_IRDA_LS_19200; break; case 38400: - ir_baud = USB_IRDA_BR_38400; + ir_baud = USB_IRDA_LS_38400; break; case 57600: - ir_baud = USB_IRDA_BR_57600; + ir_baud = USB_IRDA_LS_57600; break; case 115200: - ir_baud = USB_IRDA_BR_115200; + ir_baud = USB_IRDA_LS_115200; break; case 576000: - ir_baud = USB_IRDA_BR_576000; + ir_baud = USB_IRDA_LS_576000; break; case 1152000: - ir_baud = USB_IRDA_BR_1152000; + ir_baud = USB_IRDA_LS_1152000; break; case 4000000: - ir_baud = USB_IRDA_BR_4000000; + ir_baud = USB_IRDA_LS_4000000; break; default: - ir_baud = USB_IRDA_BR_9600; + ir_baud = USB_IRDA_LS_9600; baud = 9600; } @@ -375,42 +438,22 @@ static void ir_set_termios(struct tty_struct *tty, /* * send the baud change out on an "empty" data packet */ - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return; - transfer_buffer = kmalloc(1, GFP_KERNEL); if (!transfer_buffer) - goto err_buf; + return; *transfer_buffer = ir_xbof | ir_baud; - usb_fill_bulk_urb( - urb, - port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - transfer_buffer, - 1, - ir_set_termios_callback, - port); - - urb->transfer_flags = URB_ZERO_PACKET; - - result = usb_submit_urb(urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "%s - failed to submit urb: %d\n", - __func__, result); - goto err_subm; + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, port->bulk_out_endpointAddress), + transfer_buffer, 1, &actual_length, 5000); + if (ret || actual_length != 1) { + if (actual_length != 1) + ret = -EIO; + dev_err(&port->dev, "failed to change line speed: %d\n", ret); } - usb_free_urb(urb); - - return; -err_subm: kfree(transfer_buffer); -err_buf: - usb_free_urb(urb); } static int __init ir_init(void) diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index ed2b4e6dca38..0af76800bd78 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -41,6 +41,9 @@ struct opticon_private { bool rts; bool cts; int outstanding_urbs; + int outstanding_bytes; + + struct usb_anchor anchor; }; @@ -149,6 +152,15 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) return res; } +static void opticon_close(struct usb_serial_port *port) +{ + struct opticon_private *priv = usb_get_serial_port_data(port); + + usb_kill_anchored_urbs(&priv->anchor); + + usb_serial_generic_close(port); +} + static void opticon_write_control_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -169,6 +181,7 @@ static void opticon_write_control_callback(struct urb *urb) spin_lock_irqsave(&priv->lock, flags); --priv->outstanding_urbs; + priv->outstanding_bytes -= urb->transfer_buffer_length; spin_unlock_irqrestore(&priv->lock, flags); usb_serial_port_softint(port); @@ -182,8 +195,8 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, struct urb *urb; unsigned char *buffer; unsigned long flags; - int status; struct usb_ctrlrequest *dr; + int ret = -ENOMEM; spin_lock_irqsave(&priv->lock, flags); if (priv->outstanding_urbs > URB_UPPER_LIMIT) { @@ -192,19 +205,16 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, return 0; } priv->outstanding_urbs++; + priv->outstanding_bytes += count; spin_unlock_irqrestore(&priv->lock, flags); buffer = kmalloc(count, GFP_ATOMIC); - if (!buffer) { - count = -ENOMEM; + if (!buffer) goto error_no_buffer; - } urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - count = -ENOMEM; + if (!urb) goto error_no_urb; - } memcpy(buffer, buf, count); @@ -213,10 +223,8 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, /* The connected devices do not have a bulk write endpoint, * to transmit data to de barcode device the control endpoint is used */ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - if (!dr) { - count = -ENOMEM; + if (!dr) goto error_no_dr; - } dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; dr->bRequest = 0x01; @@ -229,13 +237,13 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, (unsigned char *)dr, buffer, count, opticon_write_control_callback, port); + usb_anchor_urb(urb, &priv->anchor); + /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_err(&port->dev, - "%s - usb_submit_urb(write endpoint) failed status = %d\n", - __func__, status); - count = status; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + dev_err(&port->dev, "failed to submit write urb: %d\n", ret); + usb_unanchor_urb(urb); goto error; } @@ -253,8 +261,10 @@ error_no_urb: error_no_buffer: spin_lock_irqsave(&priv->lock, flags); --priv->outstanding_urbs; + priv->outstanding_bytes -= count; spin_unlock_irqrestore(&priv->lock, flags); - return count; + + return ret; } static int opticon_write_room(struct tty_struct *tty) @@ -279,6 +289,20 @@ static int opticon_write_room(struct tty_struct *tty) return 2048; } +static int opticon_chars_in_buffer(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct opticon_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + int count; + + spin_lock_irqsave(&priv->lock, flags); + count = priv->outstanding_bytes; + spin_unlock_irqrestore(&priv->lock, flags); + + return count; +} + static int opticon_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; @@ -354,6 +378,7 @@ static int opticon_port_probe(struct usb_serial_port *port) return -ENOMEM; spin_lock_init(&priv->lock); + init_usb_anchor(&priv->anchor); usb_set_serial_port_data(port, priv); @@ -381,8 +406,10 @@ static struct usb_serial_driver opticon_device = { .port_probe = opticon_port_probe, .port_remove = opticon_port_remove, .open = opticon_open, + .close = opticon_close, .write = opticon_write, .write_room = opticon_write_room, + .chars_in_buffer = opticon_chars_in_buffer, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, .get_serial = get_serial_info, diff --git a/include/linux/usb/irda.h b/include/linux/usb/irda.h index 396d2b043e64..556a801efce3 100644 --- a/include/linux/usb/irda.h +++ b/include/linux/usb/irda.h @@ -119,11 +119,22 @@ struct usb_irda_cs_descriptor { * 6 - 115200 bps * 7 - 576000 bps * 8 - 1.152 Mbps - * 9 - 5 mbps + * 9 - 4 Mbps * 10..15 - Reserved */ #define USB_IRDA_STATUS_LINK_SPEED 0x0f +#define USB_IRDA_LS_NO_CHANGE 0 +#define USB_IRDA_LS_2400 1 +#define USB_IRDA_LS_9600 2 +#define USB_IRDA_LS_19200 3 +#define USB_IRDA_LS_38400 4 +#define USB_IRDA_LS_57600 5 +#define USB_IRDA_LS_115200 6 +#define USB_IRDA_LS_576000 7 +#define USB_IRDA_LS_1152000 8 +#define USB_IRDA_LS_4000000 9 + /* The following is a 4-bit value used only for * outbound header: * |