From bf260466c89f4a447c53dc704238cfc3685e05d2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 2 Mar 2021 07:22:07 +0100 Subject: USB: serial: keyspan: drop unneeded forward declarations Forward declarations make the code larger, harder to follow and rewrite. Harder as the declarations are often omitted from global changes. Remove forward declarations which are not really needed, i.e. when the definition of the function is before its first use. Signed-off-by: Jiri Slaby Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/keyspan.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 622077dcc344..b04a029e3657 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -41,27 +41,7 @@ #define DRIVER_AUTHOR "Hugh Blemings Date: Tue, 2 Mar 2021 07:22:08 +0100 Subject: USB: serial: io_edgeport: drop unneeded forward declarations Forward declarations make the code larger and rewrites harder. Harder as they are often omitted from global changes. Remove forward declarations which are not really needed, i.e. the definition of the function is before its first use. Signed-off-by: Jiri Slaby Reviewed-by: Greg Kroah-Hartman [ johan: update the prototype comments ] Signed-off-by: Johan Hovold --- drivers/usb/serial/io_edgeport.c | 45 +--------------------------------------- 1 file changed, 1 insertion(+), 44 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 68401adcffde..a296078d20c2 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -263,39 +263,9 @@ static const struct divisor_table_entry divisor_table[] = { static atomic_t CmdUrbs = ATOMIC_INIT(0); -/* local function prototypes */ +/* function prototypes */ -/* function prototypes for all URB callbacks */ -static void edge_interrupt_callback(struct urb *urb); -static void edge_bulk_in_callback(struct urb *urb); -static void edge_bulk_out_data_callback(struct urb *urb); -static void edge_bulk_out_cmd_callback(struct urb *urb); - -/* function prototypes for the usbserial callbacks */ -static int edge_open(struct tty_struct *tty, struct usb_serial_port *port); static void edge_close(struct usb_serial_port *port); -static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int edge_write_room(struct tty_struct *tty); -static int edge_chars_in_buffer(struct tty_struct *tty); -static void edge_throttle(struct tty_struct *tty); -static void edge_unthrottle(struct tty_struct *tty); -static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios); -static int edge_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static void edge_break(struct tty_struct *tty, int break_state); -static int edge_tiocmget(struct tty_struct *tty); -static int edge_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int edge_startup(struct usb_serial *serial); -static void edge_disconnect(struct usb_serial *serial); -static void edge_release(struct usb_serial *serial); -static int edge_port_probe(struct usb_serial_port *port); -static void edge_port_remove(struct usb_serial_port *port); - -/* function prototypes for all of our local functions */ static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); @@ -309,8 +279,6 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command, __u8 param); static int calc_baud_rate_divisor(struct device *dev, int baud_rate, int *divisor); -static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, - int baudRate); static void change_port_settings(struct tty_struct *tty, struct edgeport_port *edge_port, struct ktermios *old_termios); @@ -321,19 +289,8 @@ static int write_cmd_usb(struct edgeport_port *edge_port, static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port); -static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, const __u8 *data); -static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, __u8 *data); static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, const __u8 *data); -static void get_manufacturing_desc(struct edgeport_serial *edge_serial); -static void get_boot_desc(struct edgeport_serial *edge_serial); -static void load_application_firmware(struct edgeport_serial *edge_serial); - -static void unicode_to_ascii(char *string, int buflen, - __le16 *unicode, int unicode_size); - /* ************************************************************************ */ /* ************************************************************************ */ -- cgit 1.4.1 From e5f48c812679ff46c8fe5e0c4a9f2881cb56ea1a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 11 Mar 2021 17:14:47 +0100 Subject: USB: serial: pl2303: clean up type detection Clean up the type detection somewhat in preparation for adding support for more types. Note this also fixes the type debug printk for the new HXN type. Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 68 ++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 26 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index eed9acd1ae08..db840b471adb 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -362,42 +362,52 @@ static int pl2303_calc_num_ports(struct usb_serial *serial, return 1; } +static enum pl2303_type pl2303_detect_type(struct usb_serial *serial) +{ + struct usb_device_descriptor *desc = &serial->dev->descriptor; + int ret; + u8 buf; + + /* + * Legacy types 0 and 1, difference unknown. + */ + if (desc->bDeviceClass == 0x02) + return TYPE_01; /* type 0 */ + + if (desc->bMaxPacketSize0 != 0x40) { + if (desc->bDeviceClass == 0x00 || desc->bDeviceClass == 0xff) + return TYPE_01; /* type 1 */ + + return TYPE_01; /* type 0 */ + } + + /* + * Assume it's an HXN-type if the device doesn't support the old read + * request value. + */ + ret = usb_control_msg_recv(serial->dev, 0, VENDOR_READ_REQUEST, + VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, + 0, &buf, 1, 100, GFP_KERNEL); + if (ret) + return TYPE_HXN; + + return TYPE_HX; +} + static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; - enum pl2303_type type = TYPE_01; + enum pl2303_type type; unsigned char *buf; - int res; spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) return -ENOMEM; - buf = kmalloc(1, GFP_KERNEL); - if (!buf) { - kfree(spriv); - return -ENOMEM; - } + type = pl2303_detect_type(serial); - if (serial->dev->descriptor.bDeviceClass == 0x02) - type = TYPE_01; /* type 0 */ - else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) - type = TYPE_HX; - else if (serial->dev->descriptor.bDeviceClass == 0x00) - type = TYPE_01; /* type 1 */ - else if (serial->dev->descriptor.bDeviceClass == 0xFF) - type = TYPE_01; /* type 1 */ dev_dbg(&serial->interface->dev, "device type: %d\n", type); - if (type == TYPE_HX) { - res = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, - PL2303_READ_TYPE_HX_STATUS, 0, buf, 1, 100); - if (res != 1) - type = TYPE_HXN; - } - spriv->type = &pl2303_type_data[type]; spriv->quirks = (unsigned long)usb_get_serial_data(serial); spriv->quirks |= spriv->type->quirks; @@ -405,6 +415,12 @@ static int pl2303_startup(struct usb_serial *serial) usb_set_serial_data(serial, spriv); if (type != TYPE_HXN) { + buf = kmalloc(1, GFP_KERNEL); + if (!buf) { + kfree(spriv); + return -ENOMEM; + } + pl2303_vendor_read(serial, 0x8484, buf); pl2303_vendor_write(serial, 0x0404, 0); pl2303_vendor_read(serial, 0x8484, buf); @@ -419,9 +435,9 @@ static int pl2303_startup(struct usb_serial *serial) pl2303_vendor_write(serial, 2, 0x24); else pl2303_vendor_write(serial, 2, 0x44); - } - kfree(buf); + kfree(buf); + } return 0; } -- cgit 1.4.1 From 8a7bf7510d1f43994b39a677e561af4ee6a1a0ae Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 11 Mar 2021 17:14:48 +0100 Subject: USB: serial: pl2303: amend and tighten type detection Add support for detecting the HX, TA, TB and HXD device types and refuse to bind to any unknown types. Note that the HX type includes the XA variant, while the HXD type includes the EA, RA and SA variants. Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 50 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index db840b471adb..42dcc3cfb449 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -174,8 +174,11 @@ static void pl2303_set_break(struct usb_serial_port *port, bool enable); enum pl2303_type { TYPE_01, /* Type 0 and 1 (difference unknown) */ - TYPE_HX, /* HX version of the pl2303 chip */ - TYPE_HXN, /* HXN version of the pl2303 chip */ + TYPE_HX, + TYPE_TA, + TYPE_TB, + TYPE_HXD, + TYPE_HXN, TYPE_COUNT }; @@ -206,6 +209,15 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { .no_autoxonxoff = true, }, [TYPE_HX] = { + .max_baud_rate = 6000000, + }, + [TYPE_TA] = { + .max_baud_rate = 6000000, + }, + [TYPE_TB] = { + .max_baud_rate = 12000000, + }, + [TYPE_HXD] = { .max_baud_rate = 12000000, }, [TYPE_HXN] = { @@ -362,9 +374,10 @@ static int pl2303_calc_num_ports(struct usb_serial *serial, return 1; } -static enum pl2303_type pl2303_detect_type(struct usb_serial *serial) +static int pl2303_detect_type(struct usb_serial *serial) { struct usb_device_descriptor *desc = &serial->dev->descriptor; + u16 bcdDevice, bcdUSB; int ret; u8 buf; @@ -391,7 +404,24 @@ static enum pl2303_type pl2303_detect_type(struct usb_serial *serial) if (ret) return TYPE_HXN; - return TYPE_HX; + bcdDevice = le16_to_cpu(desc->bcdDevice); + bcdUSB = le16_to_cpu(desc->bcdUSB); + + switch (bcdDevice) { + case 0x300: + if (bcdUSB == 0x200) + return TYPE_TA; + + return TYPE_HX; + case 0x400: + return TYPE_HXD; + case 0x500: + return TYPE_TB; + } + + dev_err(&serial->interface->dev, + "unknown device type, please report to linux-usb@vger.kernel.org\n"); + return -ENODEV; } static int pl2303_startup(struct usb_serial *serial) @@ -399,15 +429,19 @@ static int pl2303_startup(struct usb_serial *serial) struct pl2303_serial_private *spriv; enum pl2303_type type; unsigned char *buf; + int ret; + + ret = pl2303_detect_type(serial); + if (ret < 0) + return ret; + + type = ret; + dev_dbg(&serial->interface->dev, "device type: %d\n", type); spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) return -ENOMEM; - type = pl2303_detect_type(serial); - - dev_dbg(&serial->interface->dev, "device type: %d\n", type); - spriv->type = &pl2303_type_data[type]; spriv->quirks = (unsigned long)usb_get_serial_data(serial); spriv->quirks |= spriv->type->quirks; -- cgit 1.4.1 From ca82f648d6d4f5cb21717d250bb08aa6b0bce660 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 11 Mar 2021 17:14:49 +0100 Subject: USB: serial: pl2303: rename legacy PL2303H type Rename the legacy type which is supposedly a PL2303H which came in two variants (and which we handle the same way). Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 42dcc3cfb449..cd2acd8c5246 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -173,7 +173,7 @@ MODULE_DEVICE_TABLE(usb, id_table); static void pl2303_set_break(struct usb_serial_port *port, bool enable); enum pl2303_type { - TYPE_01, /* Type 0 and 1 (difference unknown) */ + TYPE_H, TYPE_HX, TYPE_TA, TYPE_TB, @@ -203,7 +203,7 @@ struct pl2303_private { }; static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { - [TYPE_01] = { + [TYPE_H] = { .max_baud_rate = 1228800, .quirks = PL2303_QUIRK_LEGACY, .no_autoxonxoff = true, @@ -382,16 +382,16 @@ static int pl2303_detect_type(struct usb_serial *serial) u8 buf; /* - * Legacy types 0 and 1, difference unknown. + * Legacy PL2303H, variants 0 and 1 (difference unknown). */ if (desc->bDeviceClass == 0x02) - return TYPE_01; /* type 0 */ + return TYPE_H; /* variant 0 */ if (desc->bMaxPacketSize0 != 0x40) { if (desc->bDeviceClass == 0x00 || desc->bDeviceClass == 0xff) - return TYPE_01; /* type 1 */ + return TYPE_H; /* variant 1 */ - return TYPE_01; /* type 0 */ + return TYPE_H; /* variant 0 */ } /* -- cgit 1.4.1 From 894758d0571de4675520540c9e093d7e0ed9aae6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 11 Mar 2021 17:14:50 +0100 Subject: USB: serial: pl2303: tighten type HXN (G) detection Tighten the detection of the new HXN (G) type instead of assuming that every device which doesn't support the old read request is an HXN. Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index cd2acd8c5246..e742187c8a7f 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -374,12 +374,22 @@ static int pl2303_calc_num_ports(struct usb_serial *serial, return 1; } +static bool pl2303_supports_hx_status(struct usb_serial *serial) +{ + int ret; + u8 buf; + + ret = usb_control_msg_recv(serial->dev, 0, VENDOR_READ_REQUEST, + VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, + 0, &buf, 1, 100, GFP_KERNEL); + + return ret == 0; +} + static int pl2303_detect_type(struct usb_serial *serial) { struct usb_device_descriptor *desc = &serial->dev->descriptor; u16 bcdDevice, bcdUSB; - int ret; - u8 buf; /* * Legacy PL2303H, variants 0 and 1 (difference unknown). @@ -394,20 +404,18 @@ static int pl2303_detect_type(struct usb_serial *serial) return TYPE_H; /* variant 0 */ } - /* - * Assume it's an HXN-type if the device doesn't support the old read - * request value. - */ - ret = usb_control_msg_recv(serial->dev, 0, VENDOR_READ_REQUEST, - VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, - 0, &buf, 1, 100, GFP_KERNEL); - if (ret) - return TYPE_HXN; - bcdDevice = le16_to_cpu(desc->bcdDevice); bcdUSB = le16_to_cpu(desc->bcdUSB); switch (bcdDevice) { + case 0x100: + /* + * Assume it's an HXN-type if the device doesn't support the old read + * request value. + */ + if (bcdUSB == 0x200 && !pl2303_supports_hx_status(serial)) + return TYPE_HXN; + break; case 0x300: if (bcdUSB == 0x200) return TYPE_TA; -- cgit 1.4.1 From 8cbc753961e3afc71da527ec7f68ffdfc1f16a93 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 11 Mar 2021 17:14:51 +0100 Subject: USB: serial: pl2303: add device-type names Add names for the device types to be printed at probe when debugging is enabled. Note that the HXN type is referred to as G for now as that is the name the vendor uses. Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index e742187c8a7f..7208966891d0 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -183,6 +183,7 @@ enum pl2303_type { }; struct pl2303_type_data { + const char *name; speed_t max_baud_rate; unsigned long quirks; unsigned int no_autoxonxoff:1; @@ -204,23 +205,29 @@ struct pl2303_private { static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { [TYPE_H] = { + .name = "H", .max_baud_rate = 1228800, .quirks = PL2303_QUIRK_LEGACY, .no_autoxonxoff = true, }, [TYPE_HX] = { + .name = "HX", .max_baud_rate = 6000000, }, [TYPE_TA] = { + .name = "TA", .max_baud_rate = 6000000, }, [TYPE_TB] = { + .name = "TB", .max_baud_rate = 12000000, }, [TYPE_HXD] = { + .name = "HXD", .max_baud_rate = 12000000, }, [TYPE_HXN] = { + .name = "G", .max_baud_rate = 12000000, .no_divisors = true, }, @@ -444,7 +451,7 @@ static int pl2303_startup(struct usb_serial *serial) return ret; type = ret; - dev_dbg(&serial->interface->dev, "device type: %d\n", type); + dev_dbg(&serial->interface->dev, "device type: %s\n", pl2303_type_data[type].name); spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) -- cgit 1.4.1 From 764de1059b97ca1fe8fe023bb10e736772945c87 Mon Sep 17 00:00:00 2001 From: "Michael G. Katzmann" Date: Tue, 16 Mar 2021 13:17:00 -0400 Subject: USB: serial: pl2303: TA & TB alternate divider with non-standard baud rates Use an alternate clock divider algorithm and bit ordering for the TA and TB versions of the pl2303. It was discovered that these variants do not produce the correct baud rates with the existing scheme. see https://lore.kernel.org/r/3aee5708-7961-f464-8c5f-6685d96920d6@IEEE.org Signed-off-by: Michael G. Katzmann Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 7208966891d0..9c0bb59688fa 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -188,6 +188,7 @@ struct pl2303_type_data { unsigned long quirks; unsigned int no_autoxonxoff:1; unsigned int no_divisors:1; + unsigned int alt_divisors:1; }; struct pl2303_serial_private { @@ -217,10 +218,12 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { [TYPE_TA] = { .name = "TA", .max_baud_rate = 6000000, + .alt_divisors = true, }, [TYPE_TB] = { .name = "TB", .max_baud_rate = 12000000, + .alt_divisors = true, }, [TYPE_HXD] = { .name = "HXD", @@ -618,6 +621,45 @@ static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4], return baud; } +static speed_t pl2303_encode_baud_rate_divisor_alt(unsigned char buf[4], + speed_t baud) +{ + unsigned int baseline, mantissa, exponent; + + /* + * Apparently, for the TA version the formula is: + * baudrate = 12M * 32 / (mantissa * 2^exponent) + * where + * mantissa = buf[10:0] + * exponent = buf[15:13 16] + */ + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) + mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */ + exponent = 0; + while (mantissa >= 2048) { + if (exponent < 15) { + mantissa >>= 1; /* divide by 2 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 2047; + break; + } + } + + buf[3] = 0x80; + buf[2] = exponent & 0x01; + buf[1] = (exponent & ~0x01) << 4 | mantissa >> 8; + buf[0] = mantissa & 0xff; + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> exponent; + + return baud; +} + static void pl2303_encode_baud_rate(struct tty_struct *tty, struct usb_serial_port *port, u8 buf[4]) @@ -645,6 +687,8 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty, if (baud == baud_sup) baud = pl2303_encode_baud_rate_direct(buf, baud); + else if (spriv->type->alt_divisors) + baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); else baud = pl2303_encode_baud_rate_divisor(buf, baud); -- cgit 1.4.1 From 315e2811f58b807e6e76b7385e3d7b970f4562d2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 27 Mar 2021 23:27:44 +0000 Subject: USB: serial: iuu_phoenix: remove redundant variable 'error' The variable error is initialized to 0 and is set to 1 this value is never read as it is on an immediate return path. The only read of error is to check it is 0 and this check is always true at that point of the code. The variable is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Johan Hovold --- drivers/usb/serial/iuu_phoenix.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 093afd67a664..19753611e7b0 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -643,7 +643,6 @@ static void iuu_uart_read_callback(struct urb *urb) struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long flags; int status = urb->status; - int error = 0; int len = 0; unsigned char *data = urb->transfer_buffer; priv->poll++; @@ -660,12 +659,11 @@ static void iuu_uart_read_callback(struct urb *urb) if (urb->actual_length > 1) { dev_dbg(&port->dev, "%s - urb->actual_length = %i\n", __func__, urb->actual_length); - error = 1; return; } /* if len > 0 call readbuf */ - if (len > 0 && error == 0) { + if (len > 0) { dev_dbg(&port->dev, "%s - call read buf - len to read is %i\n", __func__, len); status = iuu_read_buf(port, len); -- cgit 1.4.1 From ea7ada4de2f7406150dd35ecd0302842587a464e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 30 Mar 2021 16:37:16 +0200 Subject: USB: serial: xr: fix CSIZE handling The XR21V141X does not have a 5- or 6-bit mode, but the current implementation failed to properly restore the old setting when CS5 or CS6 was requested. Instead an invalid request would be sent to the device. Fixes: c2d405aa86b4 ("USB: serial: add MaxLinear/Exar USB to Serial driver") Reviewed-by: Manivannan Sadhasivam Cc: stable@vger.kernel.org # 5.12 Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 0ca04906da4b..c59c8b47a120 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -467,6 +467,11 @@ static void xr_set_termios(struct tty_struct *tty, termios->c_cflag &= ~CSIZE; if (old_termios) termios->c_cflag |= old_termios->c_cflag & CSIZE; + else + termios->c_cflag |= CS8; + + if (C_CSIZE(tty) == CS7) + bits |= XR21V141X_UART_DATA_7; else bits |= XR21V141X_UART_DATA_8; break; -- cgit 1.4.1 From 53366a9f917a8601dcad0fd9768d5956cd2f99a6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 30 Mar 2021 16:38:17 +0200 Subject: USB: serial: drop unused suspending flag The suspending flag was added back in 2009 but no users ever followed. Remove it. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 8 +------- include/linux/usb/serial.h | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 27e3bb58c872..2a38810a3979 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1114,8 +1114,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) struct usb_serial *serial = usb_get_intfdata(intf); int i, r = 0; - serial->suspending = 1; - /* * serial->type->suspend() MUST return 0 in system sleep context, * otherwise, the resume callback has to recover device from @@ -1123,10 +1121,8 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) */ if (serial->type->suspend) { r = serial->type->suspend(serial, message); - if (r < 0) { - serial->suspending = 0; + if (r < 0) goto err_out; - } } for (i = 0; i < serial->num_ports; ++i) @@ -1151,7 +1147,6 @@ int usb_serial_resume(struct usb_interface *intf) usb_serial_unpoison_port_urbs(serial); - serial->suspending = 0; if (serial->type->resume) rv = serial->type->resume(serial); else @@ -1168,7 +1163,6 @@ static int usb_serial_reset_resume(struct usb_interface *intf) usb_serial_unpoison_port_urbs(serial); - serial->suspending = 0; if (serial->type->reset_resume) { rv = serial->type->reset_resume(serial); } else { diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 952272002e48..7efba6caaadc 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -146,7 +146,6 @@ struct usb_serial { struct usb_serial_driver *type; struct usb_interface *interface; unsigned char disconnected:1; - unsigned char suspending:1; unsigned char attached:1; unsigned char minors_reserved:1; unsigned char num_ports; -- cgit 1.4.1 From b3431093ad05c5242d87fcf94bddc7a84a2134f5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 30 Mar 2021 16:38:18 +0200 Subject: USB: serial: refactor endpoint classification Refactor endpoint classification and replace the build-time endpoint-array sanity checks with runtime checks in preparation for handling endpoints from a sibling interface. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 51 +++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 20 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 2a38810a3979..d981809c4ed3 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -711,36 +711,47 @@ static const struct tty_port_operations serial_port_ops = { .shutdown = serial_port_shutdown, }; +static void store_endpoint(struct usb_serial *serial, + struct usb_serial_endpoints *epds, + struct usb_endpoint_descriptor *epd) +{ + struct device *dev = &serial->interface->dev; + u8 addr = epd->bEndpointAddress; + + if (usb_endpoint_is_bulk_in(epd)) { + if (epds->num_bulk_in == ARRAY_SIZE(epds->bulk_in)) + return; + dev_dbg(dev, "found bulk in endpoint %02x\n", addr); + epds->bulk_in[epds->num_bulk_in++] = epd; + } else if (usb_endpoint_is_bulk_out(epd)) { + if (epds->num_bulk_out == ARRAY_SIZE(epds->bulk_out)) + return; + dev_dbg(dev, "found bulk out endpoint %02x\n", addr); + epds->bulk_out[epds->num_bulk_out++] = epd; + } else if (usb_endpoint_is_int_in(epd)) { + if (epds->num_interrupt_in == ARRAY_SIZE(epds->interrupt_in)) + return; + dev_dbg(dev, "found interrupt in endpoint %02x\n", addr); + epds->interrupt_in[epds->num_interrupt_in++] = epd; + } else if (usb_endpoint_is_int_out(epd)) { + if (epds->num_interrupt_out == ARRAY_SIZE(epds->interrupt_out)) + return; + dev_dbg(dev, "found interrupt out endpoint %02x\n", addr); + epds->interrupt_out[epds->num_interrupt_out++] = epd; + } +} + static void find_endpoints(struct usb_serial *serial, struct usb_serial_endpoints *epds) { - struct device *dev = &serial->interface->dev; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *epd; unsigned int i; - BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_in) < USB_MAXENDPOINTS / 2); - BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < USB_MAXENDPOINTS / 2); - BUILD_BUG_ON(ARRAY_SIZE(epds->interrupt_in) < USB_MAXENDPOINTS / 2); - BUILD_BUG_ON(ARRAY_SIZE(epds->interrupt_out) < USB_MAXENDPOINTS / 2); - iface_desc = serial->interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { epd = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(epd)) { - dev_dbg(dev, "found bulk in on endpoint %u\n", i); - epds->bulk_in[epds->num_bulk_in++] = epd; - } else if (usb_endpoint_is_bulk_out(epd)) { - dev_dbg(dev, "found bulk out on endpoint %u\n", i); - epds->bulk_out[epds->num_bulk_out++] = epd; - } else if (usb_endpoint_is_int_in(epd)) { - dev_dbg(dev, "found interrupt in on endpoint %u\n", i); - epds->interrupt_in[epds->num_interrupt_in++] = epd; - } else if (usb_endpoint_is_int_out(epd)) { - dev_dbg(dev, "found interrupt out on endpoint %u\n", i); - epds->interrupt_out[epds->num_interrupt_out++] = epd; - } + store_endpoint(serial, epds, epd); } } -- cgit 1.4.1 From 5de03c99691d5b0b6253fda1d1d3bbc8239aadb8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 30 Mar 2021 16:38:19 +0200 Subject: USB: serial: add support for multi-interface functions A single USB function can be implemented using a group of interfaces and this is for example commonly used for Communication Class devices. Add support for multi-interface functions to USB serial core and export an interface that allows drivers to claim a second sibling interface. The interface could easily be extended to allow claiming further interfaces if ever needed. When a driver claims a sibling interface in probe(), core allocates resources for any bulk in, bulk out, interrupt in and interrupt out endpoints found also on the sibling interface. Disconnect is implemented so that unbinding either interface will release the other interface while disconnect() is called precisely once. Similarly, suspend() is called when the first sibling interface is suspended and resume() is called when the last sibling interface is resumed by USB core. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 84 +++++++++++++++++++++++++++++++++++------ include/linux/usb/serial.h | 7 ++++ 2 files changed, 80 insertions(+), 11 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index d981809c4ed3..aaae71a0bbff 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -121,6 +121,44 @@ static void release_minors(struct usb_serial *serial) serial->minors_reserved = 0; } +int usb_serial_claim_interface(struct usb_serial *serial, struct usb_interface *intf) +{ + struct usb_driver *driver = serial->type->usb_driver; + int ret; + + if (serial->sibling) + return -EBUSY; + + ret = usb_driver_claim_interface(driver, intf, serial); + if (ret) { + dev_err(&serial->interface->dev, + "failed to claim sibling interface: %d\n", ret); + return ret; + } + + serial->sibling = intf; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_serial_claim_interface); + +static void release_sibling(struct usb_serial *serial, struct usb_interface *intf) +{ + struct usb_driver *driver = serial->type->usb_driver; + struct usb_interface *sibling; + + if (!serial->sibling) + return; + + if (intf == serial->sibling) + sibling = serial->interface; + else + sibling = serial->sibling; + + usb_set_intfdata(sibling, NULL); + usb_driver_release_interface(driver, sibling); +} + static void destroy_serial(struct kref *kref) { struct usb_serial *serial; @@ -742,13 +780,14 @@ static void store_endpoint(struct usb_serial *serial, } static void find_endpoints(struct usb_serial *serial, - struct usb_serial_endpoints *epds) + struct usb_serial_endpoints *epds, + struct usb_interface *intf) { struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *epd; unsigned int i; - iface_desc = serial->interface->cur_altsetting; + iface_desc = intf->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { epd = &iface_desc->endpoint[i].desc; store_endpoint(serial, epds, epd); @@ -917,7 +956,7 @@ static int usb_serial_probe(struct usb_interface *interface, if (retval) { dev_dbg(ddev, "sub driver rejected device\n"); - goto err_put_serial; + goto err_release_sibling; } } @@ -925,10 +964,12 @@ static int usb_serial_probe(struct usb_interface *interface, epds = kzalloc(sizeof(*epds), GFP_KERNEL); if (!epds) { retval = -ENOMEM; - goto err_put_serial; + goto err_release_sibling; } - find_endpoints(serial, epds); + find_endpoints(serial, epds, interface); + if (serial->sibling) + find_endpoints(serial, epds, serial->sibling); if (epds->num_bulk_in < type->num_bulk_in || epds->num_bulk_out < type->num_bulk_out || @@ -1076,7 +1117,8 @@ exit: err_free_epds: kfree(epds); -err_put_serial: +err_release_sibling: + release_sibling(serial, interface); usb_serial_put(serial); err_put_module: module_put(type->driver.owner); @@ -1092,6 +1134,10 @@ static void usb_serial_disconnect(struct usb_interface *interface) struct usb_serial_port *port; struct tty_struct *tty; + /* sibling interface is cleaning up */ + if (!serial) + return; + usb_serial_console_disconnect(serial); mutex_lock(&serial->disc_mutex); @@ -1115,6 +1161,8 @@ static void usb_serial_disconnect(struct usb_interface *interface) if (serial->type->disconnect) serial->type->disconnect(serial); + release_sibling(serial, interface); + /* let the last holder of this object cause it to be cleaned up */ usb_serial_put(serial); dev_info(dev, "device disconnected\n"); @@ -1123,7 +1171,11 @@ static void usb_serial_disconnect(struct usb_interface *interface) int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) { struct usb_serial *serial = usb_get_intfdata(intf); - int i, r = 0; + int i, r; + + /* suspend when called for first sibling interface */ + if (serial->suspend_count++) + return 0; /* * serial->type->suspend() MUST return 0 in system sleep context, @@ -1132,14 +1184,16 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) */ if (serial->type->suspend) { r = serial->type->suspend(serial, message); - if (r < 0) - goto err_out; + if (r < 0) { + serial->suspend_count--; + return r; + } } for (i = 0; i < serial->num_ports; ++i) usb_serial_port_poison_urbs(serial->port[i]); -err_out: - return r; + + return 0; } EXPORT_SYMBOL(usb_serial_suspend); @@ -1156,6 +1210,10 @@ int usb_serial_resume(struct usb_interface *intf) struct usb_serial *serial = usb_get_intfdata(intf); int rv; + /* resume when called for last sibling interface */ + if (--serial->suspend_count) + return 0; + usb_serial_unpoison_port_urbs(serial); if (serial->type->resume) @@ -1172,6 +1230,10 @@ static int usb_serial_reset_resume(struct usb_interface *intf) struct usb_serial *serial = usb_get_intfdata(intf); int rv; + /* resume when called for last sibling interface */ + if (--serial->suspend_count) + return 0; + usb_serial_unpoison_port_urbs(serial); if (serial->type->reset_resume) { diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 7efba6caaadc..e9b90577f50b 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -130,6 +130,8 @@ static inline void usb_set_serial_port_data(struct usb_serial_port *port, * @dev: pointer to the struct usb_device for this device * @type: pointer to the struct usb_serial_driver for this device * @interface: pointer to the struct usb_interface for this device + * @sibling: pointer to the struct usb_interface of any sibling interface + * @suspend_count: number of suspended (sibling) interfaces * @num_ports: the number of ports this device has * @num_interrupt_in: number of interrupt in endpoints we have * @num_interrupt_out: number of interrupt out endpoints we have @@ -145,6 +147,8 @@ struct usb_serial { struct usb_device *dev; struct usb_serial_driver *type; struct usb_interface *interface; + struct usb_interface *sibling; + unsigned int suspend_count; unsigned char disconnected:1; unsigned char attached:1; unsigned char minors_reserved:1; @@ -334,6 +338,9 @@ static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} /* Functions needed by other parts of the usbserial core */ struct usb_serial_port *usb_serial_port_get_by_minor(unsigned int minor); void usb_serial_put(struct usb_serial *serial); + +int usb_serial_claim_interface(struct usb_serial *serial, struct usb_interface *intf); + int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port); int usb_serial_generic_write_start(struct usb_serial_port *port, gfp_t mem_flags); int usb_serial_generic_write(struct tty_struct *tty, struct usb_serial_port *port, -- cgit 1.4.1 From 5fec21e74bfc1db764fdab013162d839cc889290 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 30 Mar 2021 16:38:20 +0200 Subject: USB: serial: xr: claim both interfaces Use the new multi-interface support in USB serial core to properly claim also the control interface during probe. This prevents having another driver claim the control interface and makes core allocate resources also for the interrupt endpoint (currently unused). Switch to probing only Communication Class interfaces and use the Union functional descriptor to determine the corresponding data interface. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index c59c8b47a120..88c73f88cb26 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -16,6 +16,7 @@ #include #include #include +#include #include struct xr_txrx_clk_mask { @@ -550,15 +551,34 @@ static void xr_close(struct usb_serial_port *port) static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id) { - /* Don't bind to control interface */ - if (serial->interface->cur_altsetting->desc.bInterfaceNumber == 0) + struct usb_interface *control = serial->interface; + struct usb_host_interface *alt = control->cur_altsetting; + struct usb_cdc_parsed_header hdrs; + struct usb_cdc_union_desc *desc; + struct usb_interface *data; + int ret; + + ret = cdc_parse_cdc_header(&hdrs, control, alt->extra, alt->extralen); + if (ret < 0) return -ENODEV; + desc = hdrs.usb_cdc_union_desc; + if (!desc) + return -ENODEV; + + data = usb_ifnum_to_if(serial->dev, desc->bSlaveInterface0); + if (!data) + return -ENODEV; + + ret = usb_serial_claim_interface(serial, data); + if (ret) + return ret; + return 0; } static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x04e2, 0x1410) }, /* XR21V141X */ + { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1410, USB_CLASS_COMM) }, /* XR21V141X */ { } }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit 1.4.1 From 9d76b10ac643f1115121d2054f0d47f2e295f743 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:02 +0200 Subject: USB: serial: ark3116: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The baud_base parameter could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds. The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Fixes: 2f430b4bbae7 ("USB: ark3116: Add TIOCGSERIAL and TIOCSSERIAL ioctl calls.") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ark3116.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index b9bedfe9bd09..957cdd694b1f 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -392,8 +392,9 @@ static int ark3116_get_serial_info(struct tty_struct *tty, ss->type = PORT_16654; ss->line = port->minor; - ss->port = port->port_number; - ss->baud_base = 460800; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From 5486a9dd37f424750b540633d809f1dfef605788 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:03 +0200 Subject: USB: serial: f81232: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds. The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Fixes: aac1fc386fa1 ("USB: serial: add Fintek F81232 usb to serial driver") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/f81232.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 6a8f39147d8e..af0fe2a82eb2 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -828,8 +828,10 @@ static int f81232_get_serial_info(struct tty_struct *tty, ss->type = PORT_16550A; ss->line = port->minor; - ss->port = port->port_number; ss->baud_base = priv->baud_base; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From 5c1426df9bb4363ed06bfbb35aaa7cf6076e9953 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:04 +0200 Subject: USB: serial: f81534: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds. The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Fixes: aac1fc386fa1 ("USB: serial: add Fintek F81232 usb to serial driver") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/f81534.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index a763b362f081..c9f90d437e3a 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1149,9 +1149,11 @@ static int f81534_get_serial_info(struct tty_struct *tty, port_priv = usb_get_serial_port_data(port); ss->type = PORT_16550A; - ss->port = port->port_number; ss->line = port->minor; ss->baud_base = port_priv->baud_base; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From 2ab5836101f8e06877917458aed1e13020a43e43 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:05 +0200 Subject: USB: serial: ftdi_sio: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The FTDI driver is the only USB serial driver supporting the deprecated ASYNC_SPD flags, which are reported back as they should by TIOCGSERIAL, but the returned parameters did not include the line number. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds. The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c867592477c9..f8a0911f90ea 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1483,9 +1483,13 @@ static int get_serial_info(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); + ss->line = port->minor; ss->flags = priv->flags; ss->baud_base = priv->baud_base; ss->custom_divisor = priv->custom_divisor; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From e54fbdbf0763b04e8f27b6db31fd07c8952d4c4b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:06 +0200 Subject: USB: serial: io_edgeport: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. Similarly, baud_base could be used to set the uart base clock when it could not be detected, but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds (not jiffies). The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_edgeport.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index a296078d20c2..3b4809875a71 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1598,16 +1598,12 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); ss->type = PORT_16550A; - ss->line = edge_port->port->minor; - ss->port = edge_port->port->port_number; - ss->irq = 0; - ss->xmit_fifo_size = edge_port->maxTxCredits; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; + ss->line = port->minor; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From c2f58d2457fb08ed045923fc6114c8d1c46f1884 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:07 +0200 Subject: USB: serial: io_ti: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. Similarly, baud_base could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds (not jiffies). The driver does not yet support changing close_delay, but let's report back the default value actually used (0.5 seconds). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index e800547be9e0..f5aab570fd05 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2437,21 +2437,17 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned cwait; - cwait = edge_port->port->port.closing_wait; + cwait = port->port.closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) cwait = jiffies_to_msecs(cwait) / 10; ss->type = PORT_16550A; - ss->line = edge_port->port->minor; - ss->port = edge_port->port->port_number; - ss->irq = 0; - ss->xmit_fifo_size = edge_port->port->bulk_out_size; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; + ss->line = port->minor; + ss->close_delay = 50; ss->closing_wait = cwait; + return 0; } -- cgit 1.4.1 From 8458e35443d30ec97ecc4b969eca77f2990d0d32 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:08 +0200 Subject: USB: serial: mos7720: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. Similarly, baud_base could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds (not jiffies). The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Fixes: 0f64478cbc7a ("USB: add USB serial mos7720 driver") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/mos7720.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 701dfb32b129..7289d46c3164 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1638,16 +1638,12 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port = usb_get_serial_port_data(port); ss->type = PORT_16550A; - ss->line = mos7720_port->port->minor; - ss->port = mos7720_port->port->port_number; - ss->irq = 0; - ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; + ss->line = port->minor; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From a804834bdf5e6be93fa7a0557e9bb80fd6d92664 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:09 +0200 Subject: USB: serial: mos7840: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. Similarly, baud_base could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds (not jiffies). The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Fixes: 3f5429746d91 ("USB: Moschip 7840 USB-Serial Driver") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/mos7840.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 1bf0d066f55a..77cbe18a1629 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1392,16 +1392,12 @@ static int mos7840_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port = usb_get_serial_port_data(port); ss->type = PORT_16550A; - ss->line = mos7840_port->port->minor; - ss->port = mos7840_port->port->port_number; - ss->irq = 0; - ss->xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - ss->baud_base = 9600; - ss->close_delay = 5 * HZ; - ss->closing_wait = 30 * HZ; + ss->line = port->minor; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From aa6a45850224fc19dbc6058598a9dc57db45b530 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:10 +0200 Subject: USB: serial: opticon: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. Similarly, baud_base could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds (not jiffies). The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Fixes: faac64ad9c7b ("USB: serial: opticon: add serial line ioctls") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/opticon.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index eecb72aef83e..1c7e5dc2c272 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -360,12 +360,9 @@ static int get_serial_info(struct tty_struct *tty, /* fake emulate a 16550 uart to make userspace code happy */ ss->type = PORT_16550A; ss->line = port->minor; - ss->port = 0; - ss->irq = 0; - ss->xmit_fifo_size = 1024; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From 5b489012e9a4965c5dbefe88aa59676152b607f0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:11 +0200 Subject: USB: serial: pl2303: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The baud_base parameter could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds. The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 9c0bb59688fa..1bb870ca7044 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1055,8 +1055,9 @@ static int pl2303_get_serial(struct tty_struct *tty, ss->type = PORT_16654; ss->line = port->minor; - ss->port = port->port_number; - ss->baud_base = 460800; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From 4065158c4897533abc430c02f5071d2e3ddbb191 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:12 +0200 Subject: USB: serial: quatech2: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. Similarly, baud_base could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds (not jiffies). The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Fixes: f7a33e608d9a ("USB: serial: add quatech2 usb to serial driver") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/quatech2.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 599dcb2e374d..0d23e565e0d2 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -459,12 +459,9 @@ static int get_serial_info(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; ss->line = port->minor; - ss->port = 0; - ss->irq = 0; - ss->xmit_fifo_size = port->bulk_out_size; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From 67a948779067f5b2e4e0c5aa67d010c525c8a0ad Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:13 +0200 Subject: USB: serial: ssu100: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. Similarly, baud_base could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds (not jiffies). The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Fixes: 52af95459939 ("USB: add USB serial ssu100 driver") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ssu100.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 89fdc5c19285..c4616c37f33f 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -337,12 +337,9 @@ static int get_serial_info(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; ss->line = port->minor; - ss->port = 0; - ss->irq = 0; - ss->xmit_fifo_size = port->bulk_out_size; - ss->baud_base = 9600; - ss->close_delay = 5*HZ; - ss->closing_wait = 30*HZ; + ss->close_delay = 50; + ss->closing_wait = 3000; + return 0; } -- cgit 1.4.1 From 4c47dc2a3a00cb288fc4888691227927430e2683 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:14 +0200 Subject: USB: serial: ti_usb_3410_5052: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds. The driver does not yet support changing close_delay, but let's report back the default value actually used (0.5 seconds). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 7252b0ce75a6..4b497c1e850b 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1406,10 +1406,10 @@ static int ti_get_serial_info(struct tty_struct *tty, ss->type = PORT_16550A; ss->line = port->minor; - ss->port = port->port_number; - ss->xmit_fifo_size = kfifo_size(&port->write_fifo); ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; + ss->close_delay = 50; ss->closing_wait = cwait; + return 0; } -- cgit 1.4.1 From d370c90dcd64e427a79a093a070117a1571d4cd8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:15 +0200 Subject: USB: serial: ti_usb_3410_5052: fix TIOCSSERIAL permission check Changing the port closing-wait parameter is a privileged operation so make sure to return -EPERM if a regular user tries to change it. Cc: stable@vger.kernel.org Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 4b497c1e850b..bb50098a0ce6 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1418,14 +1418,19 @@ static int ti_set_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); + struct tty_port *tport = &port->port; unsigned cwait; cwait = ss->closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) cwait = msecs_to_jiffies(10 * ss->closing_wait); - tport->tp_port->port.closing_wait = cwait; + if (!capable(CAP_SYS_ADMIN)) { + if (cwait != tport->closing_wait) + return -EPERM; + } + + tport->closing_wait = cwait; return 0; } -- cgit 1.4.1 From 3d732690d2267f4d0e19077b178dffbedafdf0c9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:16 +0200 Subject: USB: serial: usb_wwan: fix TIOCSSERIAL jiffies conversions The port close_delay and closing_wait parameters set by TIOCSSERIAL are specified in jiffies and not milliseconds. Add the missing conversions so that the TIOCSSERIAL works as expected also when HZ is not 1000. Fixes: 02303f73373a ("usb-wwan: implement TIOCGSERIAL and TIOCSSERIAL to avoid blocking close(2)") Cc: stable@vger.kernel.org # 2.6.38 Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/usb_wwan.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 46d46a4f99c9..4e9c994a972a 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -140,10 +140,10 @@ int usb_wwan_get_serial_info(struct tty_struct *tty, ss->line = port->minor; ss->port = port->port_number; ss->baud_base = tty_get_baud_rate(port->port.tty); - ss->close_delay = port->port.close_delay / 10; + ss->close_delay = jiffies_to_msecs(port->port.close_delay) / 10; ss->closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - port->port.closing_wait / 10; + jiffies_to_msecs(port->port.closing_wait) / 10; return 0; } EXPORT_SYMBOL(usb_wwan_get_serial_info); @@ -155,9 +155,10 @@ int usb_wwan_set_serial_info(struct tty_struct *tty, unsigned int closing_wait, close_delay; int retval = 0; - close_delay = ss->close_delay * 10; + close_delay = msecs_to_jiffies(ss->close_delay * 10); closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10; + ASYNC_CLOSING_WAIT_NONE : + msecs_to_jiffies(ss->closing_wait * 10); mutex_lock(&port->port.mutex); -- cgit 1.4.1 From a3cb01e2fe3793b8ffcb9cc7f7c7f2ca55793e62 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:17 +0200 Subject: USB: serial: usb_wwan: fix unprivileged TIOCCSERIAL TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. A non-privileged user has only ever been able to set the since long deprecated ASYNC_SPD flags and trying to change any other *supported* feature should result in -EPERM being returned. Setting the current values for any supported features should return success. Fix the usb_wwan implementation which instead indicated that the TIOCSSERIAL ioctl was not even implemented when a non-privileged user set the current values. Fixes: 02303f73373a ("usb-wwan: implement TIOCGSERIAL and TIOCSSERIAL to avoid blocking close(2)") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/usb_wwan.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 4e9c994a972a..e71c828682f5 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -166,8 +166,6 @@ int usb_wwan_set_serial_info(struct tty_struct *tty, if ((close_delay != port->port.close_delay) || (closing_wait != port->port.closing_wait)) retval = -EPERM; - else - retval = -EOPNOTSUPP; } else { port->port.close_delay = close_delay; port->port.closing_wait = closing_wait; -- cgit 1.4.1 From b6be55625138c07627d7559ecdd11333545436ae Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:18 +0200 Subject: USB: serial: usb_wwan: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The baud_base parameter could be used to set the UART base clock when it could not be detected but might as well be left unset when it is not known. Fix the usb_wwan TIOCGSERIAL implementation by dropping its custom interpretation of the unused port and baud_base fields, which were set to the port index and current line speed, respectively. Fixes: 02303f73373a ("usb-wwan: implement TIOCGSERIAL and TIOCSSERIAL to avoid blocking close(2)") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/usb_wwan.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index e71c828682f5..4ea315e5e69b 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -138,8 +138,6 @@ int usb_wwan_get_serial_info(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; ss->line = port->minor; - ss->port = port->port_number; - ss->baud_base = tty_get_baud_rate(port->port.tty); ss->close_delay = jiffies_to_msecs(port->port.close_delay) / 10; ss->closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : -- cgit 1.4.1 From 6f9f8aeab7fd5cc9a54096f5053fa3c79154756e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:19 +0200 Subject: USB: serial: whiteheat: fix TIOCGSERIAL implementation TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The port parameter is used to set the I/O port and does not make any sense to use for USB serial devices. The xmit_fifo_size parameter could be used to set the hardware transmit fifo size of a legacy UART when it could not be detected, but the interface is limited to eight bits and should be left unset when not used. The close_delay and closing_wait parameters returned by TIOCGSERIAL are specified in centiseconds (not jiffies). The driver does not yet support changing these, but let's report back the default values actually used (0.5 and 30 seconds, respectively). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/whiteheat.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index ccfd5ed652cd..c8b10faa2ff8 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -170,7 +170,6 @@ static int firm_report_tx_done(struct usb_serial_port *port); #define COMMAND_PORT 4 #define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */ #define COMMAND_TIMEOUT_MS 2000 -#define CLOSING_DELAY (30 * HZ) /***************************************************************************** @@ -447,12 +446,9 @@ static int whiteheat_get_serial(struct tty_struct *tty, ss->type = PORT_16654; ss->line = port->minor; - ss->port = port->port_number; - ss->xmit_fifo_size = kfifo_size(&port->write_fifo); - ss->custom_divisor = 0; ss->baud_base = 460800; - ss->close_delay = CLOSING_DELAY; - ss->closing_wait = CLOSING_DELAY; + ss->close_delay = 50; + ss->closing_wait = 3000; return 0; } -- cgit 1.4.1 From 5f92aee93a68c3f3b13dc28a7e220adbdc3433b0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:20 +0200 Subject: USB: serial: fix return value for unsupported ioctls Drivers should return -ENOTTY ("Inappropriate I/O control operation") when an ioctl isn't supported, while -EINVAL is used for invalid arguments. Fix up the TIOCMGET, TIOCMSET and TIOCGICOUNT helpers which returned -EINVAL when a USB serial driver did not implement the corresponding methods. Note that the TIOCMGET and TIOCMSET helpers predate git and do not get a corresponding Fixes tag below. Fixes: d281da7ff6f7 ("tty: Make tiocgicount a handler") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/usb-serial.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index aaae71a0bbff..f53a830f4094 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -540,7 +540,7 @@ static int serial_tiocmget(struct tty_struct *tty) if (port->serial->type->tiocmget) return port->serial->type->tiocmget(tty); - return -EINVAL; + return -ENOTTY; } static int serial_tiocmset(struct tty_struct *tty, @@ -552,7 +552,7 @@ static int serial_tiocmset(struct tty_struct *tty, if (port->serial->type->tiocmset) return port->serial->type->tiocmset(tty, set, clear); - return -EINVAL; + return -ENOTTY; } static int serial_get_icount(struct tty_struct *tty, @@ -564,7 +564,7 @@ static int serial_get_icount(struct tty_struct *tty, if (port->serial->type->get_icount) return port->serial->type->get_icount(tty, icount); - return -EINVAL; + return -ENOTTY; } /* -- cgit 1.4.1 From 01fd45f676f1b3785b7cdd5d815f9c31ddcd9dd1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:21 +0200 Subject: USB: serial: add generic support for TIOCSSERIAL TIOCSSERIAL is a horrid, underspecified, legacy interface which for most serial devices is only useful for setting the close_delay and closing_wait parameters. The closing_wait parameter determines how long to wait for the transfer buffers to drain during close and the default timeout of 30 seconds may not be sufficient at low line speeds. In other cases, when for example flow is stopped, the default timeout may instead be too long. Add generic support for TIOCSSERIAL and TIOCGSERIAL with handling of the three common parameters close_delay, closing_wait and line for the benefit of all USB serial drivers while still allowing drivers to implement further functionality through the existing callbacks. This currently includes a few drivers that report their base baud clock rate even if that is really only of interest when setting custom divisors through the deprecated ASYNC_SPD_CUST interface; an interface which only the FTDI driver actually implements. Some drivers have also been reporting back a fake UART type, something which should no longer be needed and will be dropped by a follow-on patch. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ark3116.c | 9 +----- drivers/usb/serial/f81232.c | 12 ++------ drivers/usb/serial/f81534.c | 8 +----- drivers/usb/serial/ftdi_sio.c | 11 ++------ drivers/usb/serial/io_edgeport.c | 12 ++------ drivers/usb/serial/io_ti.c | 17 ++--------- drivers/usb/serial/mos7720.c | 12 ++------ drivers/usb/serial/mos7840.c | 10 +------ drivers/usb/serial/opticon.c | 12 ++------ drivers/usb/serial/option.c | 2 -- drivers/usb/serial/pl2303.c | 10 +------ drivers/usb/serial/quatech2.c | 13 --------- drivers/usb/serial/ssu100.c | 13 --------- drivers/usb/serial/ti_usb_3410_5052.c | 42 ++------------------------- drivers/usb/serial/usb-serial.c | 53 +++++++++++++++++++++++++++++++---- drivers/usb/serial/usb-wwan.h | 4 --- drivers/usb/serial/usb_wwan.c | 42 --------------------------- drivers/usb/serial/whiteheat.c | 12 ++------ include/linux/usb/serial.h | 2 +- 19 files changed, 70 insertions(+), 226 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 957cdd694b1f..c0cf60e9273d 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -385,17 +385,10 @@ err_free: return result; } -static int ark3116_get_serial_info(struct tty_struct *tty, +static void ark3116_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - ss->type = PORT_16654; - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; } static int ark3116_tiocmget(struct tty_struct *tty) diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index af0fe2a82eb2..5e34b364d94d 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -820,19 +820,13 @@ static int f81232_carrier_raised(struct usb_serial_port *port) return 0; } -static int f81232_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void f81232_get_serial(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; struct f81232_private *priv = usb_get_serial_port_data(port); ss->type = PORT_16550A; - ss->line = port->minor; ss->baud_base = priv->baud_base; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; } static void f81232_interrupt_work(struct work_struct *work) @@ -1023,7 +1017,7 @@ static struct usb_serial_driver f81232_device = { .close = f81232_close, .dtr_rts = f81232_dtr_rts, .carrier_raised = f81232_carrier_raised, - .get_serial = f81232_get_serial_info, + .get_serial = f81232_get_serial, .break_ctl = f81232_break_ctl, .set_termios = f81232_set_termios, .tiocmget = f81232_tiocmget, @@ -1048,7 +1042,7 @@ static struct usb_serial_driver f81534a_device = { .close = f81232_close, .dtr_rts = f81232_dtr_rts, .carrier_raised = f81232_carrier_raised, - .get_serial = f81232_get_serial_info, + .get_serial = f81232_get_serial, .break_ctl = f81232_break_ctl, .set_termios = f81232_set_termios, .tiocmget = f81232_tiocmget, diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index c9f90d437e3a..633de52feaad 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1140,8 +1140,7 @@ static void f81534_close(struct usb_serial_port *port) mutex_unlock(&serial_priv->urb_mutex); } -static int f81534_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void f81534_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; struct f81534_port_private *port_priv; @@ -1149,12 +1148,7 @@ static int f81534_get_serial_info(struct tty_struct *tty, port_priv = usb_get_serial_port_data(port); ss->type = PORT_16550A; - ss->line = port->minor; ss->baud_base = port_priv->baud_base; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; } static void f81534_process_per_serial_block(struct usb_serial_port *port, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f8a0911f90ea..16d3e50487e6 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1082,8 +1082,7 @@ static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss); +static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss); static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); @@ -1477,20 +1476,14 @@ static int read_latency_timer(struct usb_serial_port *port) return 0; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); - ss->line = port->minor; ss->flags = priv->flags; ss->baud_base = priv->baud_base; ss->custom_divisor = priv->custom_divisor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; } static int set_serial_info(struct tty_struct *tty, diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 3b4809875a71..6b86e68ee2e8 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1594,17 +1594,9 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - - ss->type = PORT_16550A; - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; + ss->type = PORT_16550A; } diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index f5aab570fd05..dce994c29afe 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2433,22 +2433,9 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - unsigned cwait; - - cwait = port->port.closing_wait; - if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = jiffies_to_msecs(cwait) / 10; - - ss->type = PORT_16550A; - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = cwait; - - return 0; + ss->type = PORT_16550A; } static void edge_break(struct tty_struct *tty, int break_state) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 7289d46c3164..4012b448388a 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1634,17 +1634,9 @@ static int mos7720_tiocmset(struct tty_struct *tty, return 0; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - - ss->type = PORT_16550A; - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; + ss->type = PORT_16550A; } static int mos7720_ioctl(struct tty_struct *tty, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 77cbe18a1629..d20fb0a678dc 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1388,17 +1388,9 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, * function to get information about serial port *****************************************************************************/ -static int mos7840_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void mos7840_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - ss->type = PORT_16550A; - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; } /***************************************************************************** diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 1c7e5dc2c272..db84afcf7f1a 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -352,18 +352,10 @@ static int opticon_tiocmset(struct tty_struct *tty, return 0; } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - /* fake emulate a 16550 uart to make userspace code happy */ - ss->type = PORT_16550A; - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; + ss->type = PORT_16550A; } static int opticon_port_probe(struct usb_serial_port *port) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index c6969ca72839..3e79a543d3e7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2095,8 +2095,6 @@ static struct usb_serial_driver option_1port_device = { .chars_in_buffer = usb_wwan_chars_in_buffer, .tiocmget = usb_wwan_tiocmget, .tiocmset = usb_wwan_tiocmset, - .get_serial = usb_wwan_get_serial_info, - .set_serial = usb_wwan_set_serial_info, .attach = option_attach, .release = option_release, .port_probe = usb_wwan_port_probe, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1bb870ca7044..64f08a45eb46 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1048,17 +1048,9 @@ static int pl2303_carrier_raised(struct usb_serial_port *port) return 0; } -static int pl2303_get_serial(struct tty_struct *tty, - struct serial_struct *ss) +static void pl2303_get_serial(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - ss->type = PORT_16654; - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; } static void pl2303_set_break(struct usb_serial_port *port, bool enable) diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 0d23e565e0d2..5f2e7f668e68 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -453,18 +453,6 @@ static void qt2_disconnect(struct usb_serial *serial) usb_kill_urb(serial_priv->read_urb); } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; -} - static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) { switch (*ch) { @@ -975,7 +963,6 @@ static struct usb_serial_driver qt2_device = { .tiocmset = qt2_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .get_serial = get_serial_info, .set_termios = qt2_set_termios, }; diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index c4616c37f33f..3baf7c0f5a98 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -331,18 +331,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) return usb_serial_generic_open(tty, port); } -static int get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - ss->line = port->minor; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; -} - static int ssu100_attach(struct usb_serial *serial) { return ssu100_initdevice(serial->dev); @@ -542,7 +530,6 @@ static struct usb_serial_driver ssu100_device = { .tiocmset = ssu100_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, - .get_serial = get_serial_info, .set_termios = ssu100_set_termios, }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index bb50098a0ce6..6df316bdb40f 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -328,10 +328,7 @@ static void ti_recv(struct usb_serial_port *port, unsigned char *data, static void ti_send(struct ti_port *tport); static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); static int ti_get_lsr(struct ti_port *tport, u8 *lsr); -static int ti_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss); -static int ti_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss); +static void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss); static void ti_handle_new_msr(struct ti_port *tport, u8 msr); static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); @@ -435,7 +432,6 @@ static struct usb_serial_driver ti_1port_device = { .throttle = ti_throttle, .unthrottle = ti_unthrottle, .get_serial = ti_get_serial_info, - .set_serial = ti_set_serial_info, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, @@ -469,7 +465,6 @@ static struct usb_serial_driver ti_2port_device = { .throttle = ti_throttle, .unthrottle = ti_unthrottle, .get_serial = ti_get_serial_info, - .set_serial = ti_set_serial_info, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, @@ -1393,46 +1388,13 @@ free_data: } -static int ti_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - unsigned cwait; - - cwait = port->port.closing_wait; - if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = jiffies_to_msecs(cwait) / 10; ss->type = PORT_16550A; - ss->line = port->minor; ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; - ss->close_delay = 50; - ss->closing_wait = cwait; - - return 0; -} - - -static int ti_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - struct tty_port *tport = &port->port; - unsigned cwait; - - cwait = ss->closing_wait; - if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = msecs_to_jiffies(10 * ss->closing_wait); - - if (!capable(CAP_SYS_ADMIN)) { - if (cwait != tport->closing_wait) - return -EPERM; - } - - tport->closing_wait = cwait; - - return 0; } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index f53a830f4094..255f562ef1a0 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -437,19 +437,62 @@ static void serial_unthrottle(struct tty_struct *tty) static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; + unsigned int close_delay, closing_wait; + + mutex_lock(&tport->mutex); + + close_delay = jiffies_to_msecs(tport->close_delay) / 10; + closing_wait = tport->closing_wait; + if (closing_wait != ASYNC_CLOSING_WAIT_NONE) + closing_wait = jiffies_to_msecs(closing_wait) / 10; + + ss->line = port->minor; + ss->close_delay = close_delay; + ss->closing_wait = closing_wait; if (port->serial->type->get_serial) - return port->serial->type->get_serial(tty, ss); - return -ENOTTY; + port->serial->type->get_serial(tty, ss); + + mutex_unlock(&tport->mutex); + + return 0; } static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; + unsigned int close_delay, closing_wait; + int ret = 0; + + close_delay = msecs_to_jiffies(ss->close_delay * 10); + closing_wait = ss->closing_wait; + if (closing_wait != ASYNC_CLOSING_WAIT_NONE) + closing_wait = msecs_to_jiffies(closing_wait * 10); + + mutex_lock(&tport->mutex); + + if (!capable(CAP_SYS_ADMIN)) { + if (close_delay != tport->close_delay || + closing_wait != tport->closing_wait) { + ret = -EPERM; + goto out_unlock; + } + } - if (port->serial->type->set_serial) - return port->serial->type->set_serial(tty, ss); - return -ENOTTY; + if (port->serial->type->set_serial) { + ret = port->serial->type->set_serial(tty, ss); + if (ret) + goto out_unlock; + } + + tport->close_delay = close_delay; + tport->closing_wait = closing_wait; +out_unlock: + mutex_unlock(&tport->mutex); + + return ret; } static int serial_ioctl(struct tty_struct *tty, diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index 79dafd98e0a1..b5331d03092f 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -15,10 +15,6 @@ extern int usb_wwan_write_room(struct tty_struct *tty); extern int usb_wwan_tiocmget(struct tty_struct *tty); extern int usb_wwan_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -extern int usb_wwan_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss); -extern int usb_wwan_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss); extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 4ea315e5e69b..3eb72c59ede6 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -132,48 +132,6 @@ int usb_wwan_tiocmset(struct tty_struct *tty, } EXPORT_SYMBOL(usb_wwan_tiocmset); -int usb_wwan_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - - ss->line = port->minor; - ss->close_delay = jiffies_to_msecs(port->port.close_delay) / 10; - ss->closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : - jiffies_to_msecs(port->port.closing_wait) / 10; - return 0; -} -EXPORT_SYMBOL(usb_wwan_get_serial_info); - -int usb_wwan_set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int closing_wait, close_delay; - int retval = 0; - - close_delay = msecs_to_jiffies(ss->close_delay * 10); - closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : - msecs_to_jiffies(ss->closing_wait * 10); - - mutex_lock(&port->port.mutex); - - if (!capable(CAP_SYS_ADMIN)) { - if ((close_delay != port->port.close_delay) || - (closing_wait != port->port.closing_wait)) - retval = -EPERM; - } else { - port->port.close_delay = close_delay; - port->port.closing_wait = closing_wait; - } - - mutex_unlock(&port->port.mutex); - return retval; -} -EXPORT_SYMBOL(usb_wwan_set_serial_info); - int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index c8b10faa2ff8..6a95c5a0056f 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -83,7 +83,7 @@ static void whiteheat_port_remove(struct usb_serial_port *port); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port); static void whiteheat_close(struct usb_serial_port *port); -static int whiteheat_get_serial(struct tty_struct *tty, +static void whiteheat_get_serial(struct tty_struct *tty, struct serial_struct *ss); static void whiteheat_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); @@ -439,18 +439,10 @@ static int whiteheat_tiocmset(struct tty_struct *tty, } -static int whiteheat_get_serial(struct tty_struct *tty, - struct serial_struct *ss) +static void whiteheat_get_serial(struct tty_struct *tty, struct serial_struct *ss) { - struct usb_serial_port *port = tty->driver_data; - ss->type = PORT_16654; - ss->line = port->minor; ss->baud_base = 460800; - ss->close_delay = 50; - ss->closing_wait = 3000; - - return 0; } diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index e9b90577f50b..8c63fa9bfc74 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -279,7 +279,7 @@ struct usb_serial_driver { int (*write_room)(struct tty_struct *tty); int (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); - int (*get_serial)(struct tty_struct *tty, struct serial_struct *ss); + void (*get_serial)(struct tty_struct *tty, struct serial_struct *ss); int (*set_serial)(struct tty_struct *tty, struct serial_struct *ss); void (*set_termios)(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -- cgit 1.4.1 From f64d74a59c476df7d5abbddc23011f0d8475c7cc Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:22 +0200 Subject: USB: serial: stop reporting legacy UART types The TIOCGSERIAL ioctl can be used to set and retrieve the UART type for legacy UARTs, but some USB serial drivers have been reporting back random types in order to "make user-space happy". Some applications have historically expected TIOCGSERIAL to be implemented, but judging from the Debian sources, the port type not being PORT_UNKNOWN is only used to check for the existence of legacy serial ports (ttySn). Drivers like ftdi_sio have been using PORT_UNKNOWN for twenty years (and option for 10 years) without anyone complaining so let's stop reporting back anything else. In the unlikely event that this do cause problems, this should be fixed tree-wide anyway (e.g. for all USB serial drivers and also CDC-ACM). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ark3116.c | 7 ------- drivers/usb/serial/f81232.c | 1 - drivers/usb/serial/f81534.c | 1 - drivers/usb/serial/io_edgeport.c | 10 ---------- drivers/usb/serial/io_ti.c | 7 ------- drivers/usb/serial/mos7720.c | 6 ------ drivers/usb/serial/mos7840.c | 11 ----------- drivers/usb/serial/opticon.c | 7 ------- drivers/usb/serial/pl2303.c | 6 ------ drivers/usb/serial/ti_usb_3410_5052.c | 1 - drivers/usb/serial/whiteheat.c | 1 - 11 files changed, 58 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index c0cf60e9273d..5dd710e9fe7d 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -385,12 +385,6 @@ err_free: return result; } -static void ark3116_get_serial_info(struct tty_struct *tty, - struct serial_struct *ss) -{ - ss->type = PORT_16654; -} - static int ark3116_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; @@ -627,7 +621,6 @@ static struct usb_serial_driver ark3116_device = { .port_probe = ark3116_port_probe, .port_remove = ark3116_port_remove, .set_termios = ark3116_set_termios, - .get_serial = ark3116_get_serial_info, .tiocmget = ark3116_tiocmget, .tiocmset = ark3116_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 5e34b364d94d..b4b847dce4bc 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -825,7 +825,6 @@ static void f81232_get_serial(struct tty_struct *tty, struct serial_struct *ss) struct usb_serial_port *port = tty->driver_data; struct f81232_private *priv = usb_get_serial_port_data(port); - ss->type = PORT_16550A; ss->baud_base = priv->baud_base; } diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 633de52feaad..c0bca52ef92a 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1147,7 +1147,6 @@ static void f81534_get_serial_info(struct tty_struct *tty, struct serial_struct port_priv = usb_get_serial_port_data(port); - ss->type = PORT_16550A; ss->baud_base = port_priv->baud_base; } diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 6b86e68ee2e8..e6fe3882bf69 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1594,12 +1594,6 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) -{ - ss->type = PORT_16550A; -} - - /***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver @@ -3061,7 +3055,6 @@ static struct usb_serial_driver edgeport_2port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3097,7 +3090,6 @@ static struct usb_serial_driver edgeport_4port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3133,7 +3125,6 @@ static struct usb_serial_driver edgeport_8port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, @@ -3169,7 +3160,6 @@ static struct usb_serial_driver epic_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_serial = get_serial_info, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .write = edge_write, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index dce994c29afe..f548cdbf0a51 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2433,11 +2433,6 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) -{ - ss->type = PORT_16550A; -} - static void edge_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; @@ -2696,7 +2691,6 @@ static struct usb_serial_driver edgeport_1port_device = { .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .get_serial = get_serial_info, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, @@ -2735,7 +2729,6 @@ static struct usb_serial_driver edgeport_2port_device = { .release = edge_release, .port_probe = edge_port_probe, .port_remove = edge_port_remove, - .get_serial = get_serial_info, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 4012b448388a..d3f1bdb26fd4 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1634,11 +1634,6 @@ static int mos7720_tiocmset(struct tty_struct *tty, return 0; } -static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) -{ - ss->type = PORT_16550A; -} - static int mos7720_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -1778,7 +1773,6 @@ static struct usb_serial_driver moschip7720_2port_driver = { .ioctl = mos7720_ioctl, .tiocmget = mos7720_tiocmget, .tiocmset = mos7720_tiocmset, - .get_serial = get_serial_info, .set_termios = mos7720_set_termios, .write = mos7720_write, .write_room = mos7720_write_room, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index d20fb0a678dc..28e4093794e0 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1383,16 +1383,6 @@ static int mos7840_get_lsr_info(struct tty_struct *tty, return 0; } -/***************************************************************************** - * mos7840_get_serial_info - * function to get information about serial port - *****************************************************************************/ - -static void mos7840_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) -{ - ss->type = PORT_16550A; -} - /***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver @@ -1771,7 +1761,6 @@ static struct usb_serial_driver moschip7840_4port_device = { .probe = mos7840_probe, .attach = mos7840_attach, .ioctl = mos7840_ioctl, - .get_serial = mos7840_get_serial_info, .set_termios = mos7840_set_termios, .break_ctl = mos7840_break, .tiocmget = mos7840_tiocmget, diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index db84afcf7f1a..40c713fae0c3 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -352,12 +352,6 @@ static int opticon_tiocmset(struct tty_struct *tty, return 0; } -static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) -{ - /* fake emulate a 16550 uart to make userspace code happy */ - ss->type = PORT_16550A; -} - static int opticon_port_probe(struct usb_serial_port *port) { struct opticon_private *priv; @@ -399,7 +393,6 @@ static struct usb_serial_driver opticon_device = { .chars_in_buffer = opticon_chars_in_buffer, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, - .get_serial = get_serial_info, .tiocmget = opticon_tiocmget, .tiocmset = opticon_tiocmset, .process_read_urb = opticon_process_read_urb, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 64f08a45eb46..fd773d252691 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1048,11 +1048,6 @@ static int pl2303_carrier_raised(struct usb_serial_port *port) return 0; } -static void pl2303_get_serial(struct tty_struct *tty, struct serial_struct *ss) -{ - ss->type = PORT_16654; -} - static void pl2303_set_break(struct usb_serial_port *port, bool enable) { struct usb_serial *serial = port->serial; @@ -1236,7 +1231,6 @@ static struct usb_serial_driver pl2303_device = { .close = pl2303_close, .dtr_rts = pl2303_dtr_rts, .carrier_raised = pl2303_carrier_raised, - .get_serial = pl2303_get_serial, .break_ctl = pl2303_break_ctl, .set_termios = pl2303_set_termios, .tiocmget = pl2303_tiocmget, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 6df316bdb40f..c312d0cce5fb 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1393,7 +1393,6 @@ static void ti_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - ss->type = PORT_16550A; ss->baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 6a95c5a0056f..5116ed9db3eb 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -441,7 +441,6 @@ static int whiteheat_tiocmset(struct tty_struct *tty, static void whiteheat_get_serial(struct tty_struct *tty, struct serial_struct *ss) { - ss->type = PORT_16654; ss->baud_base = 460800; } -- cgit 1.4.1 From 9378379b15e3bab6915193874e1ac4464f36d869 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:23 +0200 Subject: USB: serial: ftdi_sio: ignore baud_base changes The TIOCSSERIAL error handling is inconsistent at best, but drivers tend to ignore requests to change parameters which cannot be changed rather than return an error. The FTDI driver ignores change requests for all immutable parameters but baud_base so return success also in this case for consistency. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 16d3e50487e6..3fd7875200b9 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1509,10 +1509,6 @@ static int set_serial_info(struct tty_struct *tty, goto check_and_exit; } - if (ss->baud_base != priv->baud_base) { - mutex_unlock(&priv->cfg_lock); - return -EINVAL; - } /* Make the changes - these are privileged changes! */ -- cgit 1.4.1 From c12860c0f6e6b6b0301760a2b0e3e6b3f83eace8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:24 +0200 Subject: USB: serial: ftdi_sio: simplify TIOCGSERIAL permission check Changing the deprecated custom_divisor field is an unprivileged operation so after verifying that flag field does not contain any privileged changes both updates can be carried out by any user. Combine the two branches and drop the erroneous comment. Note that private flags field is only used for ASYNC flags so there's no need to try to retain any other bits when updating the flags. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 3fd7875200b9..9228e56a91c0 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1496,27 +1496,16 @@ static int set_serial_info(struct tty_struct *tty, mutex_lock(&priv->cfg_lock); old_priv = *priv; - /* Do error checking and permission checking */ - if (!capable(CAP_SYS_ADMIN)) { if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) { mutex_unlock(&priv->cfg_lock); return -EPERM; } - priv->flags = ((priv->flags & ~ASYNC_USR_MASK) | - (ss->flags & ASYNC_USR_MASK)); - priv->custom_divisor = ss->custom_divisor; - goto check_and_exit; } - - /* Make the changes - these are privileged changes! */ - - priv->flags = ((priv->flags & ~ASYNC_FLAGS) | - (ss->flags & ASYNC_FLAGS)); + priv->flags = ss->flags & ASYNC_FLAGS; priv->custom_divisor = ss->custom_divisor; -check_and_exit: write_latency_timer(port); if ((priv->flags ^ old_priv.flags) & ASYNC_SPD_MASK || -- cgit 1.4.1 From 0428bf6807fe77e6d97c8e78538a594119d4aab2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:39:25 +0200 Subject: USB: serial: ftdi_sio: clean up TIOCSSERIAL The TIOCSSERIAL implementation needs to compare the old flag and divisor settings with the new to detect ASYNC_SPD changes, but there's no need to copy all driver state to the stack for that. While at it, unbreak the function parameter list. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9228e56a91c0..6f2659e59b2e 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1486,15 +1486,13 @@ static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) ss->custom_divisor = priv->custom_divisor; } -static int set_serial_info(struct tty_struct *tty, - struct serial_struct *ss) +static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); - struct ftdi_private old_priv; + int old_flags, old_divisor; mutex_lock(&priv->cfg_lock); - old_priv = *priv; if (!capable(CAP_SYS_ADMIN)) { if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) { @@ -1503,14 +1501,17 @@ static int set_serial_info(struct tty_struct *tty, } } + old_flags = priv->flags; + old_divisor = priv->custom_divisor; + priv->flags = ss->flags & ASYNC_FLAGS; priv->custom_divisor = ss->custom_divisor; write_latency_timer(port); - if ((priv->flags ^ old_priv.flags) & ASYNC_SPD_MASK || + if ((priv->flags ^ old_flags) & ASYNC_SPD_MASK || ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && - priv->custom_divisor != old_priv.custom_divisor)) { + priv->custom_divisor != old_divisor)) { /* warn about deprecation unless clearing */ if (priv->flags & ASYNC_SPD_MASK) -- cgit 1.4.1 From d669a51d572742acc8749cf1f25aa6db0055352c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:45:26 +0200 Subject: USB: serial: io_ti: drop closing_wait module parameter Now that all USB serial drivers supports setting the closing_wait parameter through TIOCSSERIAL (setserial) it's time to drop the corresponding io_ti module parameter. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index f548cdbf0a51..6eff0e5a7545 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -211,7 +211,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static int closing_wait = EDGE_CLOSING_WAIT; static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ @@ -2593,7 +2592,7 @@ static int edge_port_probe(struct usb_serial_port *port) if (ret) goto err; - port->port.closing_wait = msecs_to_jiffies(closing_wait * 10); + port->port.closing_wait = msecs_to_jiffies(EDGE_CLOSING_WAIT * 10); port->port.drain_delay = 1; return 0; @@ -2759,9 +2758,6 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_FIRMWARE("edgeport/down3.bin"); -module_param(closing_wait, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs"); - module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device"); -- cgit 1.4.1 From 2813b16533408129bb34ee243520fc6fb87a5d8d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:45:27 +0200 Subject: USB: serial: io_ti: switch to 30-second closing wait Switch to using the system-wide default 30-second closing-wait timeout instead of the driver specific 40-second timeout. The timeout can be changed per port using TIOCSSERIAL (setserial) if needed. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 6eff0e5a7545..75325c2b295e 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -60,8 +60,6 @@ #define EDGE_READ_URB_STOPPING 1 #define EDGE_READ_URB_STOPPED 2 -#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */ - /* Product information read from the Edgeport */ struct product_info { @@ -2592,7 +2590,6 @@ static int edge_port_probe(struct usb_serial_port *port) if (ret) goto err; - port->port.closing_wait = msecs_to_jiffies(EDGE_CLOSING_WAIT * 10); port->port.drain_delay = 1; return 0; -- cgit 1.4.1 From 9b31f8cd9174c835e76b63bd71f82dca4b3d7e4f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:45:28 +0200 Subject: USB: serial: ti_usb_3410_5052: drop closing_wait module parameter The ti_usb_3410_5052 has supported changing the closing_wait parameter through TIOCSSERIAL (setserial) for about a decade and commit f1175daa5312 ("USB: ti_usb_3410_5052: kill custom closing_wait"). It's time to drop the corresponding driver-specific module parameter. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index c312d0cce5fb..35cc1be738ef 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -344,8 +344,6 @@ static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, static int ti_download_firmware(struct ti_device *tdev); -static int closing_wait = TI_DEFAULT_CLOSING_WAIT; - static const struct usb_device_id ti_id_table_3410[] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, @@ -497,10 +495,6 @@ MODULE_FIRMWARE("moxa/moxa-1131.fw"); MODULE_FIRMWARE("moxa/moxa-1150.fw"); MODULE_FIRMWARE("moxa/moxa-1151.fw"); -module_param(closing_wait, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(closing_wait, - "Maximum wait for data to drain in close, in .01 secs, default is 4000"); - MODULE_DEVICE_TABLE(usb, ti_id_table_combined); module_usb_serial_driver(serial_drivers, ti_id_table_combined); @@ -608,7 +602,7 @@ static int ti_port_probe(struct usb_serial_port *port) tport->tp_uart_base_addr = TI_UART1_BASE_ADDR; else tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; - port->port.closing_wait = msecs_to_jiffies(10 * closing_wait); + port->port.closing_wait = msecs_to_jiffies(10 * TI_DEFAULT_CLOSING_WAIT); tport->tp_port = port; tport->tp_tdev = usb_get_serial_data(port->serial); -- cgit 1.4.1 From 8665444b80e62c3a3d95be24a284dc7332537e42 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:45:29 +0200 Subject: USB: serial: ti_usb_3410_5052: switch to 30-second closing wait Switch to using the system-wide default 30-second closing-wait timeout instead of the driver specific 40-second timeout. The timeout can be changed per port using TIOCSSERIAL (setserial) if needed. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 35cc1be738ef..03839289d6c0 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -270,8 +270,6 @@ struct ti_firmware_header { #define TI_TRANSFER_TIMEOUT 2 -#define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */ - /* read urb states */ #define TI_READ_URB_RUNNING 0 #define TI_READ_URB_STOPPING 1 @@ -602,7 +600,6 @@ static int ti_port_probe(struct usb_serial_port *port) tport->tp_uart_base_addr = TI_UART1_BASE_ADDR; else tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; - port->port.closing_wait = msecs_to_jiffies(10 * TI_DEFAULT_CLOSING_WAIT); tport->tp_port = port; tport->tp_tdev = usb_get_serial_data(port->serial); -- cgit 1.4.1 From f8edbd5186548e670bfb583cd2ad90f3e203a010 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 7 Apr 2021 12:46:29 +0200 Subject: USB: serial: io_edgeport: drop unused definitions Drop unused definitions relating to a never mainlined custom proc-interface and some likewise unused string descriptor definitions. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_edgeport.h | 68 ---------------------------------------- 1 file changed, 68 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index 43ba53a3a6fa..7c9f62af5ed6 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -10,7 +10,6 @@ #if !defined(_IO_EDGEPORT_H_) #define _IO_EDGEPORT_H_ - #define MAX_RS232_PORTS 8 /* Max # of RS-232 ports per device */ /* typedefs that the insideout headers need */ @@ -21,57 +20,8 @@ #define HIGH8(a) ((unsigned char)((a & 0xff00) >> 8)) #endif -#ifndef __KERNEL__ -#define __KERNEL__ -#endif - #include "io_usbvend.h" - - -/* The following table is used to map the USBx port number to - * the device serial number (or physical USB path), */ -#define MAX_EDGEPORTS 64 - -struct comMapper { - char SerialNumber[MAX_SERIALNUMBER_LEN+1]; /* Serial number/usb path */ - int numPorts; /* Number of ports */ - int Original[MAX_RS232_PORTS]; /* Port numbers set by IOCTL */ - int Port[MAX_RS232_PORTS]; /* Actual used port numbers */ -}; - - -#define EDGEPORT_CONFIG_DEVICE "/proc/edgeport" - -/* /proc/edgeport Interface - * This interface uses read/write/lseek interface to talk to the edgeport driver - * the following read functions are supported: */ -#define PROC_GET_MAPPING_TO_PATH 1 -#define PROC_GET_COM_ENTRY 2 -#define PROC_GET_EDGE_MANUF_DESCRIPTOR 3 -#define PROC_GET_BOOT_DESCRIPTOR 4 -#define PROC_GET_PRODUCT_INFO 5 -#define PROC_GET_STRINGS 6 -#define PROC_GET_CURRENT_COM_MAPPING 7 - -/* The parameters to the lseek() for the read is: */ -#define PROC_READ_SETUP(Command, Argument) ((Command) + ((Argument)<<8)) - - -/* the following write functions are supported: */ -#define PROC_SET_COM_MAPPING 1 -#define PROC_SET_COM_ENTRY 2 - - -/* The following structure is passed to the write */ -struct procWrite { - int Command; - union { - struct comMapper Entry; - int ComMappingBasedOnUSBPort; /* Boolean value */ - } u; -}; - /* * Product information read from the Edgeport */ @@ -108,22 +58,4 @@ struct edgeport_product_info { struct edge_compatibility_bits Epic; }; -/* - * Edgeport Stringblock String locations - */ -#define EDGESTRING_MANUFNAME 1 /* Manufacture Name */ -#define EDGESTRING_PRODNAME 2 /* Product Name */ -#define EDGESTRING_SERIALNUM 3 /* Serial Number */ -#define EDGESTRING_ASSEMNUM 4 /* Assembly Number */ -#define EDGESTRING_OEMASSEMNUM 5 /* OEM Assembly Number */ -#define EDGESTRING_MANUFDATE 6 /* Manufacture Date */ -#define EDGESTRING_ORIGSERIALNUM 7 /* Serial Number */ - -struct string_block { - __u16 NumStrings; /* Number of strings in block */ - __u16 Strings[1]; /* Start of string block */ -}; - - - #endif -- cgit 1.4.1 From 07125072b0a08a13331b46990ea48997fa0c64b4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 8 Apr 2021 17:08:59 +0200 Subject: USB: serial: do not use tty class device for debugging Use the port struct device rather than tty class device for debugging. Note that while USB serial doesn't support serdev yet (due to serdev not handling hotplugging), serdev ttys do not have a corresponding class device and would have been logged using a "(NULL device *):" prefix. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/metro-usb.c | 4 ++-- drivers/usb/serial/upd78f0730.c | 7 +++---- drivers/usb/serial/usb-serial.c | 32 ++++++++++++++++---------------- 3 files changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 0bfe4459c37f..f9ce9e7b9b80 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -299,7 +299,7 @@ static int metrousb_tiocmset(struct tty_struct *tty, unsigned long flags = 0; unsigned long control_state = 0; - dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear); + dev_dbg(&port->dev, "%s - set=%d, clear=%d\n", __func__, set, clear); spin_lock_irqsave(&metro_priv->lock, flags); control_state = metro_priv->control_state; @@ -334,7 +334,7 @@ static void metrousb_unthrottle(struct tty_struct *tty) /* Submit the urb to read from the port. */ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) - dev_err(tty->dev, + dev_err(&port->dev, "failed submitting interrupt in urb error code=%d\n", result); } diff --git a/drivers/usb/serial/upd78f0730.c b/drivers/usb/serial/upd78f0730.c index 26d7b003b7e3..63d4a784ae45 100644 --- a/drivers/usb/serial/upd78f0730.c +++ b/drivers/usb/serial/upd78f0730.c @@ -182,7 +182,6 @@ static void upd78f0730_port_remove(struct usb_serial_port *port) static int upd78f0730_tiocmget(struct tty_struct *tty) { - struct device *dev = tty->dev; struct upd78f0730_port_private *private; struct usb_serial_port *port = tty->driver_data; int signals; @@ -197,7 +196,7 @@ static int upd78f0730_tiocmget(struct tty_struct *tty) res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) | ((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0); - dev_dbg(dev, "%s - res = %x\n", __func__, res); + dev_dbg(&port->dev, "%s - res = %x\n", __func__, res); return res; } @@ -205,10 +204,10 @@ static int upd78f0730_tiocmget(struct tty_struct *tty) static int upd78f0730_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { - struct device *dev = tty->dev; struct usb_serial_port *port = tty->driver_data; struct upd78f0730_port_private *private; struct upd78f0730_set_dtr_rts request; + struct device *dev = &port->dev; int res; private = usb_get_serial_port_data(port); @@ -241,10 +240,10 @@ static int upd78f0730_tiocmset(struct tty_struct *tty, static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state) { - struct device *dev = tty->dev; struct upd78f0730_port_private *private; struct usb_serial_port *port = tty->driver_data; struct upd78f0730_set_dtr_rts request; + struct device *dev = &port->dev; private = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 255f562ef1a0..98b33b1b5357 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -281,7 +281,7 @@ static int serial_open(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); return tty_port_open(&port->port, tty, filp); } @@ -310,7 +310,7 @@ static void serial_hangup(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); tty_port_hangup(&port->port); } @@ -319,7 +319,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); tty_port_close(&port->port, tty, filp); } @@ -339,7 +339,7 @@ static void serial_cleanup(struct tty_struct *tty) struct usb_serial *serial; struct module *owner; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); /* The console is magical. Do not hang up the console hardware * or there will be tears. @@ -367,7 +367,7 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf, if (port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; - dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count); + dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count); retval = port->serial->type->write(tty, port, buf, count); if (retval < 0) @@ -380,7 +380,7 @@ static int serial_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); return port->serial->type->write_room(tty); } @@ -390,7 +390,7 @@ static int serial_chars_in_buffer(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (serial->disconnected) return 0; @@ -403,7 +403,7 @@ static void serial_wait_until_sent(struct tty_struct *tty, int timeout) struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = port->serial; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (!port->serial->type->wait_until_sent) return; @@ -418,7 +418,7 @@ static void serial_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->throttle) port->serial->type->throttle(tty); @@ -428,7 +428,7 @@ static void serial_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->unthrottle) port->serial->type->unthrottle(tty); @@ -501,7 +501,7 @@ static int serial_ioctl(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; int retval = -ENOIOCTLCMD; - dev_dbg(tty->dev, "%s - cmd 0x%04x\n", __func__, cmd); + dev_dbg(&port->dev, "%s - cmd 0x%04x\n", __func__, cmd); switch (cmd) { case TIOCMIWAIT: @@ -520,7 +520,7 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->set_termios) port->serial->type->set_termios(tty, port, old); @@ -532,7 +532,7 @@ static int serial_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->break_ctl) port->serial->type->break_ctl(tty, break_state); @@ -579,7 +579,7 @@ static int serial_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->tiocmget) return port->serial->type->tiocmget(tty); @@ -591,7 +591,7 @@ static int serial_tiocmset(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->tiocmset) return port->serial->type->tiocmset(tty, set, clear); @@ -603,7 +603,7 @@ static int serial_get_icount(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); + dev_dbg(&port->dev, "%s\n", __func__); if (port->serial->type->get_icount) return port->serial->type->get_icount(tty, icount); -- cgit 1.4.1 From b979248d16d12b913501dacd61bddc7a36aac886 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 9 Apr 2021 17:52:15 +0200 Subject: USB: serial: cp210x: provide gpio valid mask Use the new GPIO valid-mask feature to inform gpiolib which pins are available for use instead of handling that in a request callback. This also allows user space to figure out which pins are available through the chardev interface without having to request each pin in turn. Note that the return value when requesting an unavailable pin will now be -EINVAL instead of -ENODEV. Reviewed-by: Andy Shevchenko Signed-off-by: Johan Hovold --- drivers/usb/serial/cp210x.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index a373cd63b3a4..ceb3a656a075 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -1410,17 +1410,6 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state) } #ifdef CONFIG_GPIOLIB -static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset) -{ - struct usb_serial *serial = gpiochip_get_data(gc); - struct cp210x_serial_private *priv = usb_get_serial_data(serial); - - if (priv->gpio_altfunc & BIT(offset)) - return -ENODEV; - - return 0; -} - static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio) { struct usb_serial *serial = gpiochip_get_data(gc); @@ -1549,6 +1538,18 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio, return -ENOTSUPP; } +static int cp210x_gpio_init_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, unsigned int ngpios) +{ + struct usb_serial *serial = gpiochip_get_data(gc); + struct cp210x_serial_private *priv = usb_get_serial_data(serial); + unsigned long altfunc_mask = priv->gpio_altfunc; + + bitmap_complement(valid_mask, &altfunc_mask, ngpios); + + return 0; +} + /* * This function is for configuring GPIO using shared pins, where other signals * are made unavailable by configuring the use of GPIO. This is believed to be @@ -1786,13 +1787,13 @@ static int cp210x_gpio_init(struct usb_serial *serial) return result; priv->gc.label = "cp210x"; - priv->gc.request = cp210x_gpio_request; priv->gc.get_direction = cp210x_gpio_direction_get; priv->gc.direction_input = cp210x_gpio_direction_input; priv->gc.direction_output = cp210x_gpio_direction_output; priv->gc.get = cp210x_gpio_get; priv->gc.set = cp210x_gpio_set; priv->gc.set_config = cp210x_gpio_set_config; + priv->gc.init_valid_mask = cp210x_gpio_init_valid_mask; priv->gc.owner = THIS_MODULE; priv->gc.parent = &serial->interface->dev; priv->gc.base = -1; -- cgit 1.4.1 From d07082277f55cb395be00c813c62f3c956d1edb6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 9 Apr 2021 17:52:16 +0200 Subject: USB: serial: cp210x: add gpio-configuration debug printk Add a debug printk to dump the GPIO configuration stored in EEPROM during probe. Reviewed-by: Andy Shevchenko Signed-off-by: Johan Hovold --- drivers/usb/serial/cp210x.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index ceb3a656a075..ee595d1bea0a 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -1543,10 +1543,16 @@ static int cp210x_gpio_init_valid_mask(struct gpio_chip *gc, { struct usb_serial *serial = gpiochip_get_data(gc); struct cp210x_serial_private *priv = usb_get_serial_data(serial); + struct device *dev = &serial->interface->dev; unsigned long altfunc_mask = priv->gpio_altfunc; bitmap_complement(valid_mask, &altfunc_mask, ngpios); + if (bitmap_empty(valid_mask, ngpios)) + dev_dbg(dev, "no pin configured for GPIO\n"); + else + dev_dbg(dev, "GPIO.%*pbl configured for GPIO\n", ngpios, + valid_mask); return 0; } -- cgit 1.4.1 From 8674cabe052b9ce23f72abb83058fc1d545e257a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:38:12 +0200 Subject: USB: serial: f81232: drop time-based drain delay The f81232 driver now waits for the transmit FIFO to drain during close so there is no need to keep the time-based drain delay, which would add up to two seconds on every close for low line speeds. Fixes: 98405f81036d ("USB: serial: f81232: add tx_empty function") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/f81232.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index b4b847dce4bc..a7a7af8d05bf 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -948,7 +948,6 @@ static int f81232_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); - port->port.drain_delay = 256; priv->port = port; return 0; -- cgit 1.4.1 From 4b8e07951ff53e702bd5d6d21450b17152d124d7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:38:13 +0200 Subject: USB: serial: io_ti: document reason for drain delay Document that the device line-status register doesn't tell when the transmitter shift register has emptied and that this is why the one-character drain delay is needed. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 75325c2b295e..17720670e06c 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2590,6 +2590,10 @@ static int edge_port_probe(struct usb_serial_port *port) if (ret) goto err; + /* + * The LSR does not tell when the transmitter shift register has + * emptied so add a one-character drain delay. + */ port->port.drain_delay = 1; return 0; -- cgit 1.4.1 From c505b8b2ef274ce60a79f18a33bf23efd17a04de Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:38:14 +0200 Subject: USB: serial: ti_usb_3410_5052: reduce drain delay to one char The three-character drain delay was added by commit f1175daa5312 ("USB: ti_usb_3410_5052: kill custom closing_wait") when removing the custom closing-wait implementation, which used a fixed 20 ms poll period and drain delay. This was likely a bit too conservative as a one-character timeout (e.g. 33 ms at 300 bps) should be enough to compensate for the lack of a transmitter empty bit in the TUSB5052 line-status register. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 03839289d6c0..8ed64115987f 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -610,7 +610,11 @@ static int ti_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, tport); - port->port.drain_delay = 3; + /* + * The TUSB5052 LSR does not tell when the transmitter shift register + * has emptied so add a one-character drain delay. + */ + port->port.drain_delay = 1; return 0; } -- cgit 1.4.1 From bd49224a2ecf19bf5ce9128d8175fa69eeb952b5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:38:15 +0200 Subject: USB: serial: ti_usb_3410_5052: drop drain delay for 3410 Unlike the TUSB5052, the TUSB3410 has an LSR TEMT bit to tell if both the transmitter data and shift registers are empty. Make sure to check also the shift register on TUSB3410 when waiting for the transmit buffer to drain during close and drop the time-based one-char delay which is otherwise needed (e.g. 90 ms at 110 bps). Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 8ed64115987f..d9bffb2de8bf 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -121,6 +121,7 @@ #define TI_LSR_ERROR 0x0F #define TI_LSR_RX_FULL 0x10 #define TI_LSR_TX_EMPTY 0x20 +#define TI_LSR_TX_EMPTY_BOTH 0x40 /* Line control */ #define TI_LCR_BREAK 0x40 @@ -614,7 +615,8 @@ static int ti_port_probe(struct usb_serial_port *port) * The TUSB5052 LSR does not tell when the transmitter shift register * has emptied so add a one-character drain delay. */ - port->port.drain_delay = 1; + if (!tport->tp_tdev->td_is_3410) + port->port.drain_delay = 1; return 0; } @@ -851,11 +853,20 @@ static int ti_chars_in_buffer(struct tty_struct *tty) static bool ti_tx_empty(struct usb_serial_port *port) { struct ti_port *tport = usb_get_serial_port_data(port); + u8 lsr, mask; int ret; - u8 lsr; + + /* + * TUSB5052 does not have the TEMT bit to tell if the shift register + * is empty. + */ + if (tport->tp_tdev->td_is_3410) + mask = TI_LSR_TX_EMPTY_BOTH; + else + mask = TI_LSR_TX_EMPTY; ret = ti_get_lsr(tport, &lsr); - if (!ret && !(lsr & TI_LSR_TX_EMPTY)) + if (!ret && !(lsr & mask)) return false; return true; -- cgit 1.4.1 From e8d89db01a97be04050fb2bc74ed6b6f01ed9169 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:29 +0200 Subject: USB: serial: io_ti: clean up vendor-request helpers Clean up the vendor-request helpers by using kernel-types consistently and using void pointers for the data arguments, which allows removing a cast from one caller. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 17720670e06c..5d99e6d25c11 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -252,8 +252,8 @@ static int edge_remove_sysfs_attrs(struct usb_serial_port *port); #define TI_VSEND_TIMEOUT_DEFAULT 1000 #define TI_VSEND_TIMEOUT_FW_DOWNLOAD 10000 -static int ti_vread_sync(struct usb_device *dev, __u8 request, - __u16 value, __u16 index, u8 *data, int size) +static int ti_vread_sync(struct usb_device *dev, u8 request, u16 value, + u16 index, void *data, int size) { int status; @@ -271,7 +271,7 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request, } static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, - u16 index, u8 *data, int size, int timeout) + u16 index, void *data, int size, int timeout) { int status; @@ -284,9 +284,8 @@ static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, return 0; } -static int send_cmd(struct usb_device *dev, __u8 command, - __u8 moduleid, __u16 value, u8 *data, - int size) +static int send_cmd(struct usb_device *dev, u8 command, u8 moduleid, + u16 value, void *data, int size) { return ti_vsend_sync(dev, command, value, moduleid, data, size, TI_VSEND_TIMEOUT_DEFAULT); @@ -2354,7 +2353,7 @@ static void change_port_settings(struct tty_struct *tty, status = send_cmd(edge_port->port->serial->dev, UMPC_SET_CONFIG, (__u8)(UMPM_UART1_PORT + port_number), - 0, (__u8 *)config, sizeof(*config)); + 0, config, sizeof(*config)); if (status) dev_dbg(dev, "%s - error %d when trying to write config to device\n", __func__, status); -- cgit 1.4.1 From 7a14fac0c94472ad2d11ac14cefbeab5bf98e303 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:30 +0200 Subject: USB: serial: io_ti: add send-port-command helper Add a send-port-command helper which takes care of determining the UART module id when sending commands instead of doing so at every call site. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 5d99e6d25c11..f65a712078ab 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -284,11 +284,12 @@ static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, return 0; } -static int send_cmd(struct usb_device *dev, u8 command, u8 moduleid, - u16 value, void *data, int size) +static int send_port_cmd(struct usb_serial_port *port, u8 command, u16 value, + void *data, int size) { - return ti_vsend_sync(dev, command, value, moduleid, data, size, - TI_VSEND_TIMEOUT_DEFAULT); + return ti_vsend_sync(port->serial->dev, command, value, + UMPM_UART1_PORT + port->port_number, + data, size, TI_VSEND_TIMEOUT_DEFAULT); } /* clear tx/rx buffers and fifo in TI UMP */ @@ -298,12 +299,7 @@ static int purge_port(struct usb_serial_port *port, __u16 mask) dev_dbg(&port->dev, "%s - port %d, mask %x\n", __func__, port_number, mask); - return send_cmd(port->serial->dev, - UMPC_PURGE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), - mask, - NULL, - 0); + return send_port_cmd(port, UMPC_PURGE_PORT, mask, NULL, 0); } /** @@ -1500,12 +1496,9 @@ stayinbootmode: static int ti_do_config(struct edgeport_port *port, int feature, int on) { - int port_number = port->port->port_number; - on = !!on; /* 1 or 0 not bitmask */ - return send_cmd(port->port->serial->dev, - feature, (__u8)(UMPM_UART1_PORT + port_number), - on, NULL, 0); + + return send_port_cmd(port->port, feature, on, NULL, 0); } static int restore_mcr(struct edgeport_port *port, __u8 mcr) @@ -1874,8 +1867,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) dev_dbg(&port->dev, "%s - Sending UMPC_OPEN_PORT\n", __func__); /* Tell TI to open and start the port */ - status = send_cmd(dev, UMPC_OPEN_PORT, - (u8)(UMPM_UART1_PORT + port_number), open_settings, NULL, 0); + status = send_port_cmd(port, UMPC_OPEN_PORT, open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command, %d\n", __func__, status); @@ -1883,8 +1875,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) } /* Start the DMA? */ - status = send_cmd(dev, UMPC_START_PORT, - (u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); + status = send_port_cmd(port, UMPC_START_PORT, 0, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send start DMA command, %d\n", __func__, status); @@ -1967,9 +1958,7 @@ static void edge_close(struct usb_serial_port *port) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; - struct usb_serial *serial = port->serial; unsigned long flags; - int port_number; edge_serial = usb_get_serial_data(port->serial); edge_port = usb_get_serial_port_data(port); @@ -1990,9 +1979,7 @@ static void edge_close(struct usb_serial_port *port) spin_unlock_irqrestore(&edge_port->ep_lock, flags); dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__); - port_number = port->port_number; - send_cmd(serial->dev, UMPC_CLOSE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); + send_port_cmd(port, UMPC_CLOSE_PORT, 0, NULL, 0); mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; @@ -2225,7 +2212,6 @@ static void change_port_settings(struct tty_struct *tty, int baud; unsigned cflag; int status; - int port_number = edge_port->port->port_number; config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { @@ -2351,9 +2337,8 @@ static void change_port_settings(struct tty_struct *tty, cpu_to_be16s(&config->wFlags); cpu_to_be16s(&config->wBaudRate); - status = send_cmd(edge_port->port->serial->dev, UMPC_SET_CONFIG, - (__u8)(UMPM_UART1_PORT + port_number), - 0, config, sizeof(*config)); + status = send_port_cmd(edge_port->port, UMPC_SET_CONFIG, 0, config, + sizeof(*config)); if (status) dev_dbg(dev, "%s - error %d when trying to write config to device\n", __func__, status); -- cgit 1.4.1 From 13c613393cee59a6f6fd4627f7003606392690d1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:31 +0200 Subject: USB: serial: io_ti: add read-port-command helper Add a read-port-command helper analogous to the send-port-command helper to take care of the UART module id instead of open coding. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index f65a712078ab..480a73aff78f 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -284,6 +284,14 @@ static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, return 0; } +static int read_port_cmd(struct usb_serial_port *port, u8 command, u16 value, + void *data, int size) +{ + return ti_vread_sync(port->serial->dev, command, value, + UMPM_UART1_PORT + port->port_number, + data, size); +} + static int send_port_cmd(struct usb_serial_port *port, u8 command, u16 value, void *data, int size) { @@ -1826,7 +1834,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) struct edgeport_serial *edge_serial; struct usb_device *dev; struct urb *urb; - int port_number; int status; u16 open_settings; u8 transaction_timeout; @@ -1834,8 +1841,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) if (edge_port == NULL) return -ENODEV; - port_number = port->port_number; - dev = port->serial->dev; /* turn off loopback */ @@ -1892,9 +1897,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) } /* Read Initial MSR */ - status = ti_vread_sync(dev, UMPC_READ_MSR, 0, - (__u16)(UMPM_UART1_PORT + port_number), - &edge_port->shadow_msr, 1); + status = read_port_cmd(port, UMPC_READ_MSR, 0, &edge_port->shadow_msr, 1); if (status) { dev_err(&port->dev, "%s - cannot send read MSR command, %d\n", __func__, status); -- cgit 1.4.1 From 35aeb1b31b73359902d8c8031c8dae5d390fd14f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:32 +0200 Subject: USB: serial: io_ti: use kernel types consistently Use kernel types consistently by replacing the remaining __uXX types. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 110 ++++++++++++++++++++++----------------------- drivers/usb/serial/io_ti.h | 32 ++++++------- 2 files changed, 71 insertions(+), 71 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 480a73aff78f..b2e41ddd757e 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -64,7 +64,7 @@ /* Product information read from the Edgeport */ struct product_info { int TiMode; /* Current TI Mode */ - __u8 hardware_type; /* Type of hardware */ + u8 hardware_type; /* Type of hardware */ } __attribute__((packed)); /* @@ -87,13 +87,13 @@ struct edgeport_fw_hdr { } __packed; struct edgeport_port { - __u16 uart_base; - __u16 dma_address; - __u8 shadow_msr; - __u8 shadow_mcr; - __u8 shadow_lsr; - __u8 lsr_mask; - __u32 ump_read_timeout; /* + u16 uart_base; + u16 dma_address; + u8 shadow_msr; + u8 shadow_mcr; + u8 shadow_lsr; + u8 lsr_mask; + u32 ump_read_timeout; /* * Number of milliseconds the UMP will * wait without data before completing * a read short @@ -104,7 +104,7 @@ struct edgeport_port { struct edgeport_serial *edge_serial; struct usb_serial_port *port; - __u8 bUartMode; /* Port type, 0: RS232, etc. */ + u8 bUartMode; /* Port type, 0: RS232, etc. */ spinlock_t ep_lock; int ep_read_urb_state; int ep_write_urb_in_use; @@ -301,7 +301,7 @@ static int send_port_cmd(struct usb_serial_port *port, u8 command, u16 value, } /* clear tx/rx buffers and fifo in TI UMP */ -static int purge_port(struct usb_serial_port *port, __u16 mask) +static int purge_port(struct usb_serial_port *port, u16 mask) { int port_number = port->port_number; @@ -319,10 +319,10 @@ static int purge_port(struct usb_serial_port *port, __u16 mask) * @buffer: pointer to input data buffer */ static int read_download_mem(struct usb_device *dev, int start_address, - int length, __u8 address_type, __u8 *buffer) + int length, u8 address_type, u8 *buffer) { int status = 0; - __u8 read_length; + u8 read_length; u16 be_start_address; dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); @@ -335,7 +335,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, if (length > 64) read_length = 64; else - read_length = (__u8)length; + read_length = (u8)length; if (read_length > 1) { dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length); @@ -346,7 +346,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, */ be_start_address = swab16((u16)start_address); status = ti_vread_sync(dev, UMPC_MEMORY_READ, - (__u16)address_type, + (u16)address_type, be_start_address, buffer, read_length); @@ -368,7 +368,7 @@ static int read_download_mem(struct usb_device *dev, int start_address, } static int read_ram(struct usb_device *dev, int start_address, - int length, __u8 *buffer) + int length, u8 *buffer) { return read_download_mem(dev, start_address, length, DTK_ADDR_SPACE_XDATA, buffer); @@ -376,7 +376,7 @@ static int read_ram(struct usb_device *dev, int start_address, /* Read edgeport memory to a given block */ static int read_boot_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status = 0; int i; @@ -384,7 +384,7 @@ static int read_boot_mem(struct edgeport_serial *serial, for (i = 0; i < length; i++) { status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, serial->TI_I2C_Type, - (__u16)(start_address+i), &buffer[i], 0x01); + (u16)(start_address+i), &buffer[i], 0x01); if (status) { dev_dbg(&serial->serial->dev->dev, "%s - ERROR %x\n", __func__, status); return status; @@ -402,7 +402,7 @@ static int read_boot_mem(struct edgeport_serial *serial, /* Write given block to TI EPROM memory */ static int write_boot_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status = 0; int i; @@ -436,7 +436,7 @@ static int write_boot_mem(struct edgeport_serial *serial, /* Write edgeport I2C memory to TI chip */ static int write_i2c_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 address_type, __u8 *buffer) + int start_address, int length, u8 address_type, u8 *buffer) { struct device *dev = &serial->serial->dev->dev; int status = 0; @@ -522,7 +522,7 @@ static int tx_active(struct edgeport_port *port) { int status; struct out_endpoint_desc_block *oedb; - __u8 *lsr; + u8 *lsr; int bytes_left = 0; oedb = kmalloc(sizeof(*oedb), GFP_KERNEL); @@ -593,7 +593,7 @@ static int choose_config(struct usb_device *dev) } static int read_rom(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) + int start_address, int length, u8 *buffer) { int status; @@ -611,7 +611,7 @@ static int read_rom(struct edgeport_serial *serial, } static int write_rom(struct edgeport_serial *serial, int start_address, - int length, __u8 *buffer) + int length, u8 *buffer) { if (serial->product_info.TiMode == TI_MODE_BOOT) return write_boot_mem(serial, start_address, length, @@ -636,7 +636,7 @@ static int get_descriptor_addr(struct edgeport_serial *serial, status = read_rom(serial, start_address, sizeof(struct ti_i2c_desc), - (__u8 *)rom_desc); + (u8 *)rom_desc); if (status) return 0; @@ -652,13 +652,13 @@ static int get_descriptor_addr(struct edgeport_serial *serial, } /* Validate descriptor checksum */ -static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer) +static int valid_csum(struct ti_i2c_desc *rom_desc, u8 *buffer) { - __u16 i; - __u8 cs = 0; + u16 i; + u8 cs = 0; for (i = 0; i < le16_to_cpu(rom_desc->Size); i++) - cs = (__u8)(cs + buffer[i]); + cs = (u8)(cs + buffer[i]); if (cs != rom_desc->CheckSum) { pr_debug("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs); @@ -674,8 +674,8 @@ static int check_i2c_image(struct edgeport_serial *serial) int status = 0; struct ti_i2c_desc *rom_desc; int start_address = 2; - __u8 *buffer; - __u16 ttype; + u8 *buffer; + u16 ttype; rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); if (!rom_desc) @@ -703,7 +703,7 @@ static int check_i2c_image(struct edgeport_serial *serial) status = read_rom(serial, start_address, sizeof(struct ti_i2c_desc), - (__u8 *)rom_desc); + (u8 *)rom_desc); if (status) break; @@ -748,7 +748,7 @@ out: return status; } -static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) +static int get_manuf_info(struct edgeport_serial *serial, u8 *buffer) { int status; int start_address; @@ -793,10 +793,10 @@ exit: /* Build firmware header used for firmware update */ static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw) { - __u8 *buffer; + u8 *buffer; int buffer_size; int i; - __u8 cs = 0; + u8 cs = 0; struct ti_i2c_desc *i2c_header; struct ti_i2c_image_header *img_header; struct ti_i2c_firmware_rec *firmware_rec; @@ -840,7 +840,7 @@ static int build_i2c_fw_hdr(u8 *header, const struct firmware *fw) le16_to_cpu(img_header->Length)); for (i=0; i < buffer_size; i++) { - cs = (__u8)(cs + buffer[i]); + cs = (u8)(cs + buffer[i]); } kfree(buffer); @@ -916,7 +916,7 @@ static int bulk_xfer(struct usb_serial *serial, void *buffer, } /* Download given firmware image to the device (IN BOOT MODE) */ -static int download_code(struct edgeport_serial *serial, __u8 *image, +static int download_code(struct edgeport_serial *serial, u8 *image, int image_length) { int status = 0; @@ -1090,7 +1090,7 @@ static int do_download_mode(struct edgeport_serial *serial, if (!ti_manuf_desc) return -ENOMEM; - status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); + status = get_manuf_info(serial, (u8 *)ti_manuf_desc); if (status) { kfree(ti_manuf_desc); return status; @@ -1135,7 +1135,7 @@ static int do_download_mode(struct edgeport_serial *serial, status = read_rom(serial, start_address + sizeof(struct ti_i2c_desc), sizeof(struct ti_i2c_firmware_rec), - (__u8 *)firmware_version); + (u8 *)firmware_version); if (status) { kfree(firmware_version); kfree(rom_desc); @@ -1261,8 +1261,8 @@ static int do_download_mode(struct edgeport_serial *serial, if (start_address != 0) { #define HEADER_SIZE (sizeof(struct ti_i2c_desc) + \ sizeof(struct ti_i2c_firmware_rec)) - __u8 *header; - __u8 *vheader; + u8 *header; + u8 *vheader; header = kmalloc(HEADER_SIZE, GFP_KERNEL); if (!header) { @@ -1408,8 +1408,8 @@ static int do_boot_mode(struct edgeport_serial *serial, if (!check_i2c_image(serial)) { struct ti_i2c_image_header *header; int i; - __u8 cs = 0; - __u8 *buffer; + u8 cs = 0; + u8 *buffer; int buffer_size; /* @@ -1420,7 +1420,7 @@ static int do_boot_mode(struct edgeport_serial *serial, if (!ti_manuf_desc) return -ENOMEM; - status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); + status = get_manuf_info(serial, (u8 *)ti_manuf_desc); if (status) { kfree(ti_manuf_desc); goto stayinbootmode; @@ -1463,13 +1463,13 @@ static int do_boot_mode(struct edgeport_serial *serial, for (i = sizeof(struct ti_i2c_image_header); i < buffer_size; i++) { - cs = (__u8)(cs + buffer[i]); + cs = (u8)(cs + buffer[i]); } header = (struct ti_i2c_image_header *)buffer; /* update length and checksum after padding */ - header->Length = cpu_to_le16((__u16)(buffer_size - + header->Length = cpu_to_le16((u16)(buffer_size - sizeof(struct ti_i2c_image_header))); header->CheckSum = cs; @@ -1509,7 +1509,7 @@ static int ti_do_config(struct edgeport_port *port, int feature, int on) return send_port_cmd(port->port, feature, on, NULL, 0); } -static int restore_mcr(struct edgeport_port *port, __u8 mcr) +static int restore_mcr(struct edgeport_port *port, u8 mcr) { int status = 0; @@ -1525,9 +1525,9 @@ static int restore_mcr(struct edgeport_port *port, __u8 mcr) } /* Convert TI LSR to standard UART flags */ -static __u8 map_line_status(__u8 ti_lsr) +static u8 map_line_status(u8 ti_lsr) { - __u8 lsr = 0; + u8 lsr = 0; #define MAP_FLAG(flagUmp, flagUart) \ if (ti_lsr & flagUmp) \ @@ -1545,7 +1545,7 @@ static __u8 map_line_status(__u8 ti_lsr) return lsr; } -static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) +static void handle_new_msr(struct edgeport_port *edge_port, u8 msr) { struct async_icount *icount; struct tty_struct *tty; @@ -1581,10 +1581,10 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) } static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, - __u8 lsr, __u8 data) + u8 lsr, u8 data) { struct async_icount *icount; - __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | + u8 new_lsr = (u8)(lsr & (u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); dev_dbg(&edge_port->port->dev, "%s - %02x\n", __func__, new_lsr); @@ -1596,7 +1596,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, * Parity and Framing errors only count if they * occur exclusive of a break being received. */ - new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); + new_lsr &= (u8)(LSR_OVER_ERR | LSR_BREAK); /* Place LSR data byte into Rx buffer */ if (lsr_data) @@ -1625,8 +1625,8 @@ static void edge_interrupt_callback(struct urb *urb) int port_number; int function; int retval; - __u8 lsr; - __u8 msr; + u8 lsr; + u8 msr; int status = urb->status; switch (status) { @@ -2229,7 +2229,7 @@ static void change_port_settings(struct tty_struct *tty, /* These flags must be set */ config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT; config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR; - config->bUartMode = (__u8)(edge_port->bUartMode); + config->bUartMode = (u8)(edge_port->bUartMode); switch (cflag & CSIZE) { case CS5: @@ -2321,7 +2321,7 @@ static void change_port_settings(struct tty_struct *tty, } edge_port->baud_rate = baud; - config->wBaudRate = (__u16)((461550L + baud/2) / baud); + config->wBaudRate = (u16)((461550L + baud/2) / baud); /* FIXME: Recompute actual baud from divisor here */ diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h index 50b899d55ed0..e31406c252dd 100644 --- a/drivers/usb/serial/io_ti.h +++ b/drivers/usb/serial/io_ti.h @@ -133,14 +133,14 @@ #define UMPD_OEDB2_ADDRESS 0xFF10 struct out_endpoint_desc_block { - __u8 Configuration; - __u8 XBufAddr; - __u8 XByteCount; - __u8 Unused1; - __u8 Unused2; - __u8 YBufAddr; - __u8 YByteCount; - __u8 BufferSize; + u8 Configuration; + u8 XBufAddr; + u8 XByteCount; + u8 Unused1; + u8 Unused2; + u8 YBufAddr; + u8 YByteCount; + u8 BufferSize; } __attribute__((packed)); @@ -150,14 +150,14 @@ struct out_endpoint_desc_block { */ /* UART settings */ struct ump_uart_config { - __u16 wBaudRate; /* Baud rate */ - __u16 wFlags; /* Bitmap mask of flags */ - __u8 bDataBits; /* 5..8 - data bits per character */ - __u8 bParity; /* Parity settings */ - __u8 bStopBits; /* Stop bits settings */ + u16 wBaudRate; /* Baud rate */ + u16 wFlags; /* Bitmap mask of flags */ + u8 bDataBits; /* 5..8 - data bits per character */ + u8 bParity; /* Parity settings */ + u8 bStopBits; /* Stop bits settings */ char cXon; /* XON character */ char cXoff; /* XOFF character */ - __u8 bUartMode; /* Will be updated when a user */ + u8 bUartMode; /* Will be updated when a user */ /* interface is defined */ } __attribute__((packed)); @@ -168,8 +168,8 @@ struct ump_uart_config { */ /* Interrupt packet structure */ struct ump_interrupt { - __u8 bICode; /* Interrupt code (interrupt num) */ - __u8 bIInfo; /* Interrupt information */ + u8 bICode; /* Interrupt code (interrupt num) */ + u8 bIInfo; /* Interrupt information */ } __attribute__((packed)); -- cgit 1.4.1 From 46388e865273bc67dc29fee9772e1b8b59eaafd3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:33 +0200 Subject: USB: serial: io_ti: drop unnecessary packed attributes Drop unnecessary packed attributes from structures that don't need it and use the __packed macro consistently. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 2 +- drivers/usb/serial/io_ti.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index b2e41ddd757e..39503fdccebf 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -65,7 +65,7 @@ struct product_info { int TiMode; /* Current TI Mode */ u8 hardware_type; /* Type of hardware */ -} __attribute__((packed)); +} __packed; /* * Edgeport firmware header diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h index e31406c252dd..24fe1312c84d 100644 --- a/drivers/usb/serial/io_ti.h +++ b/drivers/usb/serial/io_ti.h @@ -141,7 +141,7 @@ struct out_endpoint_desc_block { u8 YBufAddr; u8 YByteCount; u8 BufferSize; -} __attribute__((packed)); +}; /* @@ -159,7 +159,7 @@ struct ump_uart_config { char cXoff; /* XOFF character */ u8 bUartMode; /* Will be updated when a user */ /* interface is defined */ -} __attribute__((packed)); +}; /* @@ -170,7 +170,7 @@ struct ump_uart_config { struct ump_interrupt { u8 bICode; /* Interrupt code (interrupt num) */ u8 bIInfo; /* Interrupt information */ -} __attribute__((packed)); +}; #define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 6) & 0x01) -- cgit 1.4.1 From a1db84f6cab79780954ffd55bb114c52b867d81d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:34 +0200 Subject: USB: serial: ti_usb_3410_5052: drop unnecessary packed attributes Drop unnecessary packed attributes from structures that don't need it. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index d9bffb2de8bf..11e6792981b7 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -184,7 +184,7 @@ struct ti_uart_config { char cXon; char cXoff; u8 bUartMode; -} __packed; +}; /* Get port status */ struct ti_port_status { @@ -193,7 +193,7 @@ struct ti_port_status { u8 bErrorCode; u8 bMSR; u8 bLSR; -} __packed; +}; /* Purge modes */ #define TI_PURGE_OUTPUT 0x00 @@ -236,13 +236,13 @@ struct ti_read_data_bytes { __u8 bModuleId; __u8 bErrorCode; __u8 bData[]; -} __packed; +}; /* Interrupt struct */ struct ti_interrupt { __u8 bICode; __u8 bIInfo; -} __packed; +}; /* Interrupt codes */ #define TI_CODE_HARDWARE_ERROR 0xFF -- cgit 1.4.1 From d24223367d21240c1985456859daddb5e7d227b8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:35 +0200 Subject: USB: serial: ti_usb_3410_5052: clean up vendor-request helpers Make the vendor-request helpers data parameters be void pointers and drop the caller casts. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 11e6792981b7..25d5a6e83009 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -334,9 +334,9 @@ static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); static int ti_command_out_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size); + __u16 moduleid, __u16 value, void *data, int size); static int ti_command_in_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size); + __u16 moduleid, __u16 value, void *data, int size); static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, unsigned long addr, u8 mask, u8 byte); @@ -999,7 +999,7 @@ static void ti_set_termios(struct tty_struct *tty, config->wFlags = cpu_to_be16(wflags); status = ti_command_out_sync(tport->tp_tdev, TI_SET_CONFIG, - (__u8)(TI_UART1_PORT + port_number), 0, (__u8 *)config, + (__u8)(TI_UART1_PORT + port_number), 0, config, sizeof(*config)); if (status) dev_err(&port->dev, "%s - cannot set config on port %d, %d\n", @@ -1376,7 +1376,7 @@ static int ti_get_lsr(struct ti_port *tport, u8 *lsr) return -ENOMEM; status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS, - (__u8)(TI_UART1_PORT+port_number), 0, (__u8 *)data, size); + (__u8)(TI_UART1_PORT+port_number), 0, data, size); if (status) { dev_err(&port->dev, "%s - get port status command failed, %d\n", @@ -1475,7 +1475,7 @@ static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty) static int ti_command_out_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size) + __u16 moduleid, __u16 value, void *data, int size) { int status; @@ -1492,7 +1492,7 @@ static int ti_command_out_sync(struct ti_device *tdev, __u8 command, static int ti_command_in_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size) + __u16 moduleid, __u16 value, void *data, int size) { int status; @@ -1535,8 +1535,7 @@ static int ti_write_byte(struct usb_serial_port *port, data->bData[1] = byte; status = ti_command_out_sync(tdev, TI_WRITE_DATA, TI_RAM_PORT, 0, - (__u8 *)data, size); - + data, size); if (status < 0) dev_err(&port->dev, "%s - failed, %d\n", __func__, status); -- cgit 1.4.1 From 3bfe43988c93ada8c8fc8fb16c95271381606289 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:36 +0200 Subject: USB: serial: ti_usb_3410_5052: add port-command helpers Add two port-command helpers to handle the UART module-id parameter instead of open coding. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 94 ++++++++++++++++------------------- 1 file changed, 44 insertions(+), 50 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 25d5a6e83009..d4e4aa6d1f1f 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -333,10 +333,14 @@ static void ti_handle_new_msr(struct ti_port *tport, u8 msr); static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); -static int ti_command_out_sync(struct ti_device *tdev, __u8 command, +static int ti_command_out_sync(struct usb_device *udev, __u8 command, __u16 moduleid, __u16 value, void *data, int size); -static int ti_command_in_sync(struct ti_device *tdev, __u8 command, +static int ti_command_in_sync(struct usb_device *udev, __u8 command, __u16 moduleid, __u16 value, void *data, int size); +static int ti_port_cmd_out(struct usb_serial_port *port, u8 command, + u16 value, void *data, int size); +static int ti_port_cmd_in(struct usb_serial_port *port, u8 command, + u16 value, void *data, int size); static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, unsigned long addr, u8 mask, u8 byte); @@ -635,7 +639,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) struct ti_device *tdev; struct usb_device *dev; struct urb *urb; - int port_number; int status; u16 open_settings; @@ -650,8 +653,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (mutex_lock_interruptible(&tdev->td_open_close_lock)) return -ERESTARTSYS; - port_number = port->port_number; - tport->tp_msr = 0; tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR); @@ -675,31 +676,27 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ti_set_termios(tty, port, &tty->termios); - status = ti_command_out_sync(tdev, TI_OPEN_PORT, - (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); + status = ti_port_cmd_out(port, TI_OPEN_PORT, open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command, %d\n", __func__, status); goto unlink_int_urb; } - status = ti_command_out_sync(tdev, TI_START_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); + status = ti_port_cmd_out(port, TI_START_PORT, 0, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send start command, %d\n", __func__, status); goto unlink_int_urb; } - status = ti_command_out_sync(tdev, TI_PURGE_PORT, - (__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0); + status = ti_port_cmd_out(port, TI_PURGE_PORT, TI_PURGE_INPUT, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot clear input buffers, %d\n", __func__, status); goto unlink_int_urb; } - status = ti_command_out_sync(tdev, TI_PURGE_PORT, - (__u8)(TI_UART1_PORT + port_number), TI_PURGE_OUTPUT, NULL, 0); + status = ti_port_cmd_out(port, TI_PURGE_PORT, TI_PURGE_OUTPUT, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot clear output buffers, %d\n", __func__, status); @@ -714,16 +711,14 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ti_set_termios(tty, port, &tty->termios); - status = ti_command_out_sync(tdev, TI_OPEN_PORT, - (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); + status = ti_port_cmd_out(port, TI_OPEN_PORT, open_settings, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send open command (2), %d\n", __func__, status); goto unlink_int_urb; } - status = ti_command_out_sync(tdev, TI_START_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); + status = ti_port_cmd_out(port, TI_START_PORT, 0, NULL, 0); if (status) { dev_err(&port->dev, "%s - cannot send start command (2), %d\n", __func__, status); @@ -764,7 +759,6 @@ static void ti_close(struct usb_serial_port *port) { struct ti_device *tdev; struct ti_port *tport; - int port_number; int status; unsigned long flags; @@ -780,10 +774,7 @@ static void ti_close(struct usb_serial_port *port) kfifo_reset_out(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); - port_number = port->port_number; - - status = ti_command_out_sync(tdev, TI_CLOSE_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); + status = ti_port_cmd_out(port, TI_CLOSE_PORT, 0, NULL, 0); if (status) dev_err(&port->dev, "%s - cannot send close port command, %d\n" @@ -904,7 +895,6 @@ static void ti_set_termios(struct tty_struct *tty, struct ti_uart_config *config; int baud; int status; - int port_number = port->port_number; unsigned int mcr; u16 wbaudrate; u16 wflags = 0; @@ -998,12 +988,11 @@ static void ti_set_termios(struct tty_struct *tty, config->wBaudRate = cpu_to_be16(wbaudrate); config->wFlags = cpu_to_be16(wflags); - status = ti_command_out_sync(tport->tp_tdev, TI_SET_CONFIG, - (__u8)(TI_UART1_PORT + port_number), 0, config, - sizeof(*config)); + status = ti_port_cmd_out(port, TI_SET_CONFIG, 0, config, + sizeof(*config)); if (status) dev_err(&port->dev, "%s - cannot set config on port %d, %d\n", - __func__, port_number, status); + __func__, port->port_number, status); /* SET_CONFIG asserts RTS and DTR, reset them correctly */ mcr = tport->tp_shadow_mcr; @@ -1012,9 +1001,8 @@ static void ti_set_termios(struct tty_struct *tty, mcr &= ~(TI_MCR_DTR | TI_MCR_RTS); status = ti_set_mcr(tport, mcr); if (status) - dev_err(&port->dev, - "%s - cannot set modem control on port %d, %d\n", - __func__, port_number, status); + dev_err(&port->dev, "%s - cannot set modem control on port %d, %d\n", + __func__, port->port_number, status); kfree(config); } @@ -1365,9 +1353,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr) static int ti_get_lsr(struct ti_port *tport, u8 *lsr) { int size, status; - struct ti_device *tdev = tport->tp_tdev; struct usb_serial_port *port = tport->tp_port; - int port_number = port->port_number; struct ti_port_status *data; size = sizeof(struct ti_port_status); @@ -1375,8 +1361,7 @@ static int ti_get_lsr(struct ti_port *tport, u8 *lsr) if (!data) return -ENOMEM; - status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS, - (__u8)(TI_UART1_PORT+port_number), 0, data, size); + status = ti_port_cmd_in(port, TI_GET_PORT_STATUS, 0, data, size); if (status) { dev_err(&port->dev, "%s - get port status command failed, %d\n", @@ -1473,34 +1458,28 @@ static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty) return status; } - -static int ti_command_out_sync(struct ti_device *tdev, __u8 command, +static int ti_command_out_sync(struct usb_device *udev, __u8 command, __u16 moduleid, __u16 value, void *data, int size) { int status; - status = usb_control_msg(tdev->td_serial->dev, - usb_sndctrlpipe(tdev->td_serial->dev, 0), command, - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), - value, moduleid, data, size, 1000); - + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), command, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + value, moduleid, data, size, 1000); if (status < 0) return status; return 0; } - -static int ti_command_in_sync(struct ti_device *tdev, __u8 command, +static int ti_command_in_sync(struct usb_device *udev, __u8 command, __u16 moduleid, __u16 value, void *data, int size) { int status; - status = usb_control_msg(tdev->td_serial->dev, - usb_rcvctrlpipe(tdev->td_serial->dev, 0), command, - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN), - value, moduleid, data, size, 1000); - + status = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), command, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, + value, moduleid, data, size, 1000); if (status == size) status = 0; else if (status >= 0) @@ -1509,6 +1488,21 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, return status; } +static int ti_port_cmd_out(struct usb_serial_port *port, u8 command, + u16 value, void *data, int size) +{ + return ti_command_out_sync(port->serial->dev, command, + TI_UART1_PORT + port->port_number, + value, data, size); +} + +static int ti_port_cmd_in(struct usb_serial_port *port, u8 command, + u16 value, void *data, int size) +{ + return ti_command_in_sync(port->serial->dev, command, + TI_UART1_PORT + port->port_number, + value, data, size); +} static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, unsigned long addr, @@ -1534,8 +1528,8 @@ static int ti_write_byte(struct usb_serial_port *port, data->bData[0] = mask; data->bData[1] = byte; - status = ti_command_out_sync(tdev, TI_WRITE_DATA, TI_RAM_PORT, 0, - data, size); + status = ti_command_out_sync(port->serial->dev, TI_WRITE_DATA, + TI_RAM_PORT, 0, data, size); if (status < 0) dev_err(&port->dev, "%s - failed, %d\n", __func__, status); -- cgit 1.4.1 From b7cff0c412dcb31961e4b536cddd9ffa7a76c225 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:37 +0200 Subject: USB: serial: ti_usb_3410_5052: use kernel types consistently Replace the remaining uses of user-space __XX types. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index d4e4aa6d1f1f..7e335162c1aa 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -224,24 +224,24 @@ struct ti_write_data_bytes { } __packed; struct ti_read_data_request { - __u8 bAddrType; - __u8 bDataType; - __u8 bDataCounter; + u8 bAddrType; + u8 bDataType; + u8 bDataCounter; __be16 wBaseAddrHi; __be16 wBaseAddrLo; } __packed; struct ti_read_data_bytes { - __u8 bCmdCode; - __u8 bModuleId; - __u8 bErrorCode; - __u8 bData[]; + u8 bCmdCode; + u8 bModuleId; + u8 bErrorCode; + u8 bData[]; }; /* Interrupt struct */ struct ti_interrupt { - __u8 bICode; - __u8 bIInfo; + u8 bICode; + u8 bIInfo; }; /* Interrupt codes */ @@ -333,10 +333,10 @@ static void ti_handle_new_msr(struct ti_port *tport, u8 msr); static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); -static int ti_command_out_sync(struct usb_device *udev, __u8 command, - __u16 moduleid, __u16 value, void *data, int size); -static int ti_command_in_sync(struct usb_device *udev, __u8 command, - __u16 moduleid, __u16 value, void *data, int size); +static int ti_command_out_sync(struct usb_device *udev, u8 command, + u16 moduleid, u16 value, void *data, int size); +static int ti_command_in_sync(struct usb_device *udev, u8 command, + u16 moduleid, u16 value, void *data, int size); static int ti_port_cmd_out(struct usb_serial_port *port, u8 command, u16 value, void *data, int size); static int ti_port_cmd_in(struct usb_serial_port *port, u8 command, @@ -1458,8 +1458,8 @@ static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty) return status; } -static int ti_command_out_sync(struct usb_device *udev, __u8 command, - __u16 moduleid, __u16 value, void *data, int size) +static int ti_command_out_sync(struct usb_device *udev, u8 command, + u16 moduleid, u16 value, void *data, int size) { int status; @@ -1472,8 +1472,8 @@ static int ti_command_out_sync(struct usb_device *udev, __u8 command, return 0; } -static int ti_command_in_sync(struct usb_device *udev, __u8 command, - __u16 moduleid, __u16 value, void *data, int size) +static int ti_command_in_sync(struct usb_device *udev, u8 command, + u16 moduleid, u16 value, void *data, int size) { int status; -- cgit 1.4.1 From 4ef8f235778716476528a0ca270a4783ef6a40bb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:47:38 +0200 Subject: USB: serial: ti_usb_3410_5052: clean up termios CSIZE handling Remove the random white space from the CSIZE switch. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 7e335162c1aa..caa46ac23db9 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -910,18 +910,18 @@ static void ti_set_termios(struct tty_struct *tty, switch (C_CSIZE(tty)) { case CS5: - config->bDataBits = TI_UART_5_DATA_BITS; - break; + config->bDataBits = TI_UART_5_DATA_BITS; + break; case CS6: - config->bDataBits = TI_UART_6_DATA_BITS; - break; + config->bDataBits = TI_UART_6_DATA_BITS; + break; case CS7: - config->bDataBits = TI_UART_7_DATA_BITS; - break; + config->bDataBits = TI_UART_7_DATA_BITS; + break; default: case CS8: - config->bDataBits = TI_UART_8_DATA_BITS; - break; + config->bDataBits = TI_UART_8_DATA_BITS; + break; } /* CMSPAR isn't supported by this driver */ -- cgit 1.4.1 From 23b7998e81aa37d97897aa236bdcfba3f6edeb66 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:46 +0200 Subject: USB: serial: xr: add support for XR21V1412 and XR21V1414 Add support for the two- and four-port variants of XR21V1410. Use the interface number of each control interface (e.g. 0, 2, 4, 6) to derive the zero-based channel index: XR21V1410 0 XR21V1412 0, 1 XR21V1414 0, 1, 2, 3 Note that the UART registers reside in separate blocks per channel, while the UART Manager functionality is implemented using per-channel registers. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 55 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 88c73f88cb26..64bc9d7b948b 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -109,6 +109,10 @@ struct xr_txrx_clk_mask { #define XR21V141X_REG_GPIO_CLR 0x1e #define XR21V141X_REG_GPIO_STATUS 0x1f +struct xr_data { + u8 channel; /* zero-based index */ +}; + static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val) { struct usb_serial *serial = port->serial; @@ -160,16 +164,31 @@ static int xr_get_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 *val) static int xr_set_reg_uart(struct usb_serial_port *port, u8 reg, u8 val) { - return xr_set_reg(port, XR21V141X_UART_REG_BLOCK, reg, val); + struct xr_data *data = usb_get_serial_port_data(port); + u8 block; + + block = XR21V141X_UART_REG_BLOCK + data->channel; + + return xr_set_reg(port, block, reg, val); } static int xr_get_reg_uart(struct usb_serial_port *port, u8 reg, u8 *val) { - return xr_get_reg(port, XR21V141X_UART_REG_BLOCK, reg, val); + struct xr_data *data = usb_get_serial_port_data(port); + u8 block; + + block = XR21V141X_UART_REG_BLOCK + data->channel; + + return xr_get_reg(port, block, reg, val); } -static int xr_set_reg_um(struct usb_serial_port *port, u8 reg, u8 val) +static int xr_set_reg_um(struct usb_serial_port *port, u8 reg_base, u8 val) { + struct xr_data *data = usb_get_serial_port_data(port); + u8 reg; + + reg = reg_base + data->channel; + return xr_set_reg(port, XR21V141X_UM_REG_BLOCK, reg, val); } @@ -577,8 +596,34 @@ static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id) return 0; } +static int xr_port_probe(struct usb_serial_port *port) +{ + struct usb_interface_descriptor *desc; + struct xr_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + desc = &port->serial->interface->cur_altsetting->desc; + data->channel = desc->bInterfaceNumber / 2; + + usb_set_serial_port_data(port, data); + + return 0; +} + +static void xr_port_remove(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + kfree(data); +} + static const struct usb_device_id id_table[] = { - { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1410, USB_CLASS_COMM) }, /* XR21V141X */ + { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1410, USB_CLASS_COMM) }, /* XR21V1410 */ + { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1412, USB_CLASS_COMM) }, /* XR21V1412 */ + { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1414, USB_CLASS_COMM) }, /* XR21V1414 */ { } }; MODULE_DEVICE_TABLE(usb, id_table); @@ -591,6 +636,8 @@ static struct usb_serial_driver xr_device = { .id_table = id_table, .num_ports = 1, .probe = xr_probe, + .port_probe = xr_port_probe, + .port_remove = xr_port_remove, .open = xr_open, .close = xr_close, .break_ctl = xr_break_ctl, -- cgit 1.4.1 From 3c369a850d3f30ff258ed9b9982b6d06a6232985 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:47 +0200 Subject: USB: serial: xr: rename GPIO-mode defines Rename the GPIO mode defines so that they reflect the datasheet and how they are used. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 64bc9d7b948b..a600448c6016 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -88,11 +88,11 @@ struct xr_txrx_clk_mask { #define XR21V141X_UART_FLOW_MODE_HW 0x1 #define XR21V141X_UART_FLOW_MODE_SW 0x2 -#define XR21V141X_UART_MODE_GPIO_MASK GENMASK(2, 0) -#define XR21V141X_UART_MODE_RTS_CTS 0x1 -#define XR21V141X_UART_MODE_DTR_DSR 0x2 -#define XR21V141X_UART_MODE_RS485 0x3 -#define XR21V141X_UART_MODE_RS485_ADDR 0x4 +#define XR21V141X_GPIO_MODE_MASK GENMASK(2, 0) +#define XR21V141X_GPIO_MODE_RTS_CTS 0x1 +#define XR21V141X_GPIO_MODE_DTR_DSR 0x2 +#define XR21V141X_GPIO_MODE_RS485 0x3 +#define XR21V141X_GPIO_MODE_RS485_ADDR 0x4 #define XR21V141X_REG_ENABLE 0x03 #define XR21V141X_REG_FORMAT 0x0b @@ -433,11 +433,11 @@ static void xr_set_flow_mode(struct tty_struct *tty, return; /* Set GPIO mode for controlling the pins manually by default. */ - gpio_mode &= ~XR21V141X_UART_MODE_GPIO_MASK; + gpio_mode &= ~XR21V141X_GPIO_MODE_MASK; if (C_CRTSCTS(tty) && C_BAUD(tty) != B0) { dev_dbg(&port->dev, "Enabling hardware flow ctrl\n"); - gpio_mode |= XR21V141X_UART_MODE_RTS_CTS; + gpio_mode |= XR21V141X_GPIO_MODE_RTS_CTS; flow = XR21V141X_UART_FLOW_MODE_HW; } else if (I_IXON(tty)) { u8 start_char = START_CHAR(tty); -- cgit 1.4.1 From 5f70fe320e47de0611150dd4628c86eb9212eb00 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:48 +0200 Subject: USB: serial: xr: rename GPIO-pin defines Rename the GPIO-pin defines so that they reflect how they are used. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index a600448c6016..f5087a8b6c86 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -57,12 +57,12 @@ struct xr_txrx_clk_mask { #define XR21V141X_UART_ENABLE_TX 0x1 #define XR21V141X_UART_ENABLE_RX 0x2 -#define XR21V141X_UART_MODE_RI BIT(0) -#define XR21V141X_UART_MODE_CD BIT(1) -#define XR21V141X_UART_MODE_DSR BIT(2) -#define XR21V141X_UART_MODE_DTR BIT(3) -#define XR21V141X_UART_MODE_CTS BIT(4) -#define XR21V141X_UART_MODE_RTS BIT(5) +#define XR21V141X_GPIO_RI BIT(0) +#define XR21V141X_GPIO_CD BIT(1) +#define XR21V141X_GPIO_DSR BIT(2) +#define XR21V141X_GPIO_DTR BIT(3) +#define XR21V141X_GPIO_CTS BIT(4) +#define XR21V141X_GPIO_RTS BIT(5) #define XR21V141X_UART_BREAK_ON 0xff #define XR21V141X_UART_BREAK_OFF 0 @@ -250,12 +250,12 @@ static int xr_tiocmget(struct tty_struct *tty) * Modem control pins are active low, so reading '0' means it is active * and '1' means not active. */ - ret = ((status & XR21V141X_UART_MODE_DTR) ? 0 : TIOCM_DTR) | - ((status & XR21V141X_UART_MODE_RTS) ? 0 : TIOCM_RTS) | - ((status & XR21V141X_UART_MODE_CTS) ? 0 : TIOCM_CTS) | - ((status & XR21V141X_UART_MODE_DSR) ? 0 : TIOCM_DSR) | - ((status & XR21V141X_UART_MODE_RI) ? 0 : TIOCM_RI) | - ((status & XR21V141X_UART_MODE_CD) ? 0 : TIOCM_CD); + ret = ((status & XR21V141X_GPIO_DTR) ? 0 : TIOCM_DTR) | + ((status & XR21V141X_GPIO_RTS) ? 0 : TIOCM_RTS) | + ((status & XR21V141X_GPIO_CTS) ? 0 : TIOCM_CTS) | + ((status & XR21V141X_GPIO_DSR) ? 0 : TIOCM_DSR) | + ((status & XR21V141X_GPIO_RI) ? 0 : TIOCM_RI) | + ((status & XR21V141X_GPIO_CD) ? 0 : TIOCM_CD); return ret; } @@ -269,13 +269,13 @@ static int xr_tiocmset_port(struct usb_serial_port *port, /* Modem control pins are active low, so set & clr are swapped */ if (set & TIOCM_RTS) - gpio_clr |= XR21V141X_UART_MODE_RTS; + gpio_clr |= XR21V141X_GPIO_RTS; if (set & TIOCM_DTR) - gpio_clr |= XR21V141X_UART_MODE_DTR; + gpio_clr |= XR21V141X_GPIO_DTR; if (clear & TIOCM_RTS) - gpio_set |= XR21V141X_UART_MODE_RTS; + gpio_set |= XR21V141X_GPIO_RTS; if (clear & TIOCM_DTR) - gpio_set |= XR21V141X_UART_MODE_DTR; + gpio_set |= XR21V141X_GPIO_DTR; /* Writing '0' to gpio_{set/clr} bits has no effect, so no need to do */ if (gpio_clr) @@ -545,7 +545,7 @@ static int xr_open(struct tty_struct *tty, struct usb_serial_port *port) * Configure DTR and RTS as outputs and RI, CD, DSR and CTS as * inputs. */ - gpio_dir = XR21V141X_UART_MODE_DTR | XR21V141X_UART_MODE_RTS; + gpio_dir = XR21V141X_GPIO_DTR | XR21V141X_GPIO_RTS; xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, gpio_dir); /* Setup termios */ -- cgit 1.4.1 From 49036fd021ce77764bc8059166f646c9768a1b26 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:49 +0200 Subject: USB: serial: xr: move pin configuration to probe There's no need to configure the pins on every open and judging from the vendor driver and datasheet it can be done before enabling the UART. Move pin configuration from open() to port probe and make sure to deassert DTR and RTS after configuring all pins as GPIO. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 45 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index f5087a8b6c86..542c1dc060cc 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -532,7 +532,6 @@ static void xr_set_termios(struct tty_struct *tty, static int xr_open(struct tty_struct *tty, struct usb_serial_port *port) { - u8 gpio_dir; int ret; ret = xr_uart_enable(port); @@ -541,13 +540,6 @@ static int xr_open(struct tty_struct *tty, struct usb_serial_port *port) return ret; } - /* - * Configure DTR and RTS as outputs and RI, CD, DSR and CTS as - * inputs. - */ - gpio_dir = XR21V141X_GPIO_DTR | XR21V141X_GPIO_RTS; - xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, gpio_dir); - /* Setup termios */ if (tty) xr_set_termios(tty, port, NULL); @@ -596,10 +588,38 @@ static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id) return 0; } +static int xr_gpio_init(struct usb_serial_port *port) +{ + u8 mask, mode; + int ret; + + /* Configure all pins as GPIO. */ + mode = 0; + ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_MODE, mode); + if (ret) + return ret; + + /* + * Configure DTR and RTS as outputs and make sure they are deasserted + * (active low), and configure RI, CD, DSR and CTS as inputs. + */ + mask = XR21V141X_GPIO_DTR | XR21V141X_GPIO_RTS; + ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, mask); + if (ret) + return ret; + + ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_SET, mask); + if (ret) + return ret; + + return 0; +} + static int xr_port_probe(struct usb_serial_port *port) { struct usb_interface_descriptor *desc; struct xr_data *data; + int ret; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) @@ -610,7 +630,16 @@ static int xr_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, data); + ret = xr_gpio_init(port); + if (ret) + goto err_free; + return 0; + +err_free: + kfree(data); + + return ret; } static void xr_port_remove(struct usb_serial_port *port) -- cgit 1.4.1 From 958d6b958574a7b609982f1499bf3d792284ce7b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:50 +0200 Subject: USB: serial: xr: drop type prefix from shared defines In preparation for adding support for further types, drop the type prefix from defines that are not specific to XR21V141X. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 122 ++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 61 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 542c1dc060cc..bbfe92fcabc0 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -54,45 +54,45 @@ struct xr_txrx_clk_mask { #define XR21V141X_UM_RX_FIFO_RESET 0x18 #define XR21V141X_UM_TX_FIFO_RESET 0x1c -#define XR21V141X_UART_ENABLE_TX 0x1 -#define XR21V141X_UART_ENABLE_RX 0x2 +#define XR_UART_ENABLE_TX 0x1 +#define XR_UART_ENABLE_RX 0x2 -#define XR21V141X_GPIO_RI BIT(0) -#define XR21V141X_GPIO_CD BIT(1) -#define XR21V141X_GPIO_DSR BIT(2) -#define XR21V141X_GPIO_DTR BIT(3) -#define XR21V141X_GPIO_CTS BIT(4) -#define XR21V141X_GPIO_RTS BIT(5) +#define XR_GPIO_RI BIT(0) +#define XR_GPIO_CD BIT(1) +#define XR_GPIO_DSR BIT(2) +#define XR_GPIO_DTR BIT(3) +#define XR_GPIO_CTS BIT(4) +#define XR_GPIO_RTS BIT(5) #define XR21V141X_UART_BREAK_ON 0xff #define XR21V141X_UART_BREAK_OFF 0 -#define XR21V141X_UART_DATA_MASK GENMASK(3, 0) -#define XR21V141X_UART_DATA_7 0x7 -#define XR21V141X_UART_DATA_8 0x8 - -#define XR21V141X_UART_PARITY_MASK GENMASK(6, 4) -#define XR21V141X_UART_PARITY_SHIFT 4 -#define XR21V141X_UART_PARITY_NONE (0x0 << XR21V141X_UART_PARITY_SHIFT) -#define XR21V141X_UART_PARITY_ODD (0x1 << XR21V141X_UART_PARITY_SHIFT) -#define XR21V141X_UART_PARITY_EVEN (0x2 << XR21V141X_UART_PARITY_SHIFT) -#define XR21V141X_UART_PARITY_MARK (0x3 << XR21V141X_UART_PARITY_SHIFT) -#define XR21V141X_UART_PARITY_SPACE (0x4 << XR21V141X_UART_PARITY_SHIFT) - -#define XR21V141X_UART_STOP_MASK BIT(7) -#define XR21V141X_UART_STOP_SHIFT 7 -#define XR21V141X_UART_STOP_1 (0x0 << XR21V141X_UART_STOP_SHIFT) -#define XR21V141X_UART_STOP_2 (0x1 << XR21V141X_UART_STOP_SHIFT) - -#define XR21V141X_UART_FLOW_MODE_NONE 0x0 -#define XR21V141X_UART_FLOW_MODE_HW 0x1 -#define XR21V141X_UART_FLOW_MODE_SW 0x2 - -#define XR21V141X_GPIO_MODE_MASK GENMASK(2, 0) -#define XR21V141X_GPIO_MODE_RTS_CTS 0x1 -#define XR21V141X_GPIO_MODE_DTR_DSR 0x2 -#define XR21V141X_GPIO_MODE_RS485 0x3 -#define XR21V141X_GPIO_MODE_RS485_ADDR 0x4 +#define XR_UART_DATA_MASK GENMASK(3, 0) +#define XR_UART_DATA_7 0x7 +#define XR_UART_DATA_8 0x8 + +#define XR_UART_PARITY_MASK GENMASK(6, 4) +#define XR_UART_PARITY_SHIFT 4 +#define XR_UART_PARITY_NONE (0x0 << XR_UART_PARITY_SHIFT) +#define XR_UART_PARITY_ODD (0x1 << XR_UART_PARITY_SHIFT) +#define XR_UART_PARITY_EVEN (0x2 << XR_UART_PARITY_SHIFT) +#define XR_UART_PARITY_MARK (0x3 << XR_UART_PARITY_SHIFT) +#define XR_UART_PARITY_SPACE (0x4 << XR_UART_PARITY_SHIFT) + +#define XR_UART_STOP_MASK BIT(7) +#define XR_UART_STOP_SHIFT 7 +#define XR_UART_STOP_1 (0x0 << XR_UART_STOP_SHIFT) +#define XR_UART_STOP_2 (0x1 << XR_UART_STOP_SHIFT) + +#define XR_UART_FLOW_MODE_NONE 0x0 +#define XR_UART_FLOW_MODE_HW 0x1 +#define XR_UART_FLOW_MODE_SW 0x2 + +#define XR_GPIO_MODE_MASK GENMASK(2, 0) +#define XR_GPIO_MODE_RTS_CTS 0x1 +#define XR_GPIO_MODE_DTR_DSR 0x2 +#define XR_GPIO_MODE_RS485 0x3 +#define XR_GPIO_MODE_RS485_ADDR 0x4 #define XR21V141X_REG_ENABLE 0x03 #define XR21V141X_REG_FORMAT 0x0b @@ -210,7 +210,7 @@ static int xr_uart_enable(struct usb_serial_port *port) return ret; ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE, - XR21V141X_UART_ENABLE_TX | XR21V141X_UART_ENABLE_RX); + XR_UART_ENABLE_TX | XR_UART_ENABLE_RX); if (ret) return ret; @@ -250,12 +250,12 @@ static int xr_tiocmget(struct tty_struct *tty) * Modem control pins are active low, so reading '0' means it is active * and '1' means not active. */ - ret = ((status & XR21V141X_GPIO_DTR) ? 0 : TIOCM_DTR) | - ((status & XR21V141X_GPIO_RTS) ? 0 : TIOCM_RTS) | - ((status & XR21V141X_GPIO_CTS) ? 0 : TIOCM_CTS) | - ((status & XR21V141X_GPIO_DSR) ? 0 : TIOCM_DSR) | - ((status & XR21V141X_GPIO_RI) ? 0 : TIOCM_RI) | - ((status & XR21V141X_GPIO_CD) ? 0 : TIOCM_CD); + ret = ((status & XR_GPIO_DTR) ? 0 : TIOCM_DTR) | + ((status & XR_GPIO_RTS) ? 0 : TIOCM_RTS) | + ((status & XR_GPIO_CTS) ? 0 : TIOCM_CTS) | + ((status & XR_GPIO_DSR) ? 0 : TIOCM_DSR) | + ((status & XR_GPIO_RI) ? 0 : TIOCM_RI) | + ((status & XR_GPIO_CD) ? 0 : TIOCM_CD); return ret; } @@ -269,13 +269,13 @@ static int xr_tiocmset_port(struct usb_serial_port *port, /* Modem control pins are active low, so set & clr are swapped */ if (set & TIOCM_RTS) - gpio_clr |= XR21V141X_GPIO_RTS; + gpio_clr |= XR_GPIO_RTS; if (set & TIOCM_DTR) - gpio_clr |= XR21V141X_GPIO_DTR; + gpio_clr |= XR_GPIO_DTR; if (clear & TIOCM_RTS) - gpio_set |= XR21V141X_GPIO_RTS; + gpio_set |= XR_GPIO_RTS; if (clear & TIOCM_DTR) - gpio_set |= XR21V141X_GPIO_DTR; + gpio_set |= XR_GPIO_DTR; /* Writing '0' to gpio_{set/clr} bits has no effect, so no need to do */ if (gpio_clr) @@ -433,24 +433,24 @@ static void xr_set_flow_mode(struct tty_struct *tty, return; /* Set GPIO mode for controlling the pins manually by default. */ - gpio_mode &= ~XR21V141X_GPIO_MODE_MASK; + gpio_mode &= ~XR_GPIO_MODE_MASK; if (C_CRTSCTS(tty) && C_BAUD(tty) != B0) { dev_dbg(&port->dev, "Enabling hardware flow ctrl\n"); - gpio_mode |= XR21V141X_GPIO_MODE_RTS_CTS; - flow = XR21V141X_UART_FLOW_MODE_HW; + gpio_mode |= XR_GPIO_MODE_RTS_CTS; + flow = XR_UART_FLOW_MODE_HW; } else if (I_IXON(tty)) { u8 start_char = START_CHAR(tty); u8 stop_char = STOP_CHAR(tty); dev_dbg(&port->dev, "Enabling sw flow ctrl\n"); - flow = XR21V141X_UART_FLOW_MODE_SW; + flow = XR_UART_FLOW_MODE_SW; xr_set_reg_uart(port, XR21V141X_REG_XON_CHAR, start_char); xr_set_reg_uart(port, XR21V141X_REG_XOFF_CHAR, stop_char); } else { dev_dbg(&port->dev, "Disabling flow ctrl\n"); - flow = XR21V141X_UART_FLOW_MODE_NONE; + flow = XR_UART_FLOW_MODE_NONE; } /* @@ -491,37 +491,37 @@ static void xr_set_termios(struct tty_struct *tty, termios->c_cflag |= CS8; if (C_CSIZE(tty) == CS7) - bits |= XR21V141X_UART_DATA_7; + bits |= XR_UART_DATA_7; else - bits |= XR21V141X_UART_DATA_8; + bits |= XR_UART_DATA_8; break; case CS7: - bits |= XR21V141X_UART_DATA_7; + bits |= XR_UART_DATA_7; break; case CS8: default: - bits |= XR21V141X_UART_DATA_8; + bits |= XR_UART_DATA_8; break; } if (C_PARENB(tty)) { if (C_CMSPAR(tty)) { if (C_PARODD(tty)) - bits |= XR21V141X_UART_PARITY_MARK; + bits |= XR_UART_PARITY_MARK; else - bits |= XR21V141X_UART_PARITY_SPACE; + bits |= XR_UART_PARITY_SPACE; } else { if (C_PARODD(tty)) - bits |= XR21V141X_UART_PARITY_ODD; + bits |= XR_UART_PARITY_ODD; else - bits |= XR21V141X_UART_PARITY_EVEN; + bits |= XR_UART_PARITY_EVEN; } } if (C_CSTOPB(tty)) - bits |= XR21V141X_UART_STOP_2; + bits |= XR_UART_STOP_2; else - bits |= XR21V141X_UART_STOP_1; + bits |= XR_UART_STOP_1; ret = xr_set_reg_uart(port, XR21V141X_REG_FORMAT, bits); if (ret) @@ -603,7 +603,7 @@ static int xr_gpio_init(struct usb_serial_port *port) * Configure DTR and RTS as outputs and make sure they are deasserted * (active low), and configure RI, CD, DSR and CTS as inputs. */ - mask = XR21V141X_GPIO_DTR | XR21V141X_GPIO_RTS; + mask = XR_GPIO_DTR | XR_GPIO_RTS; ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, mask); if (ret) return ret; -- cgit 1.4.1 From f865e614604cb6b5ea76462ad314c90a62b918c4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:51 +0200 Subject: USB: serial: xr: add type abstraction There are at least four types of Maxlinear/Exar USB UARTs which differ in various ways such as in their register layouts: XR21V141X XR21B142X XR21B1411 XR22804 It is not clear whether the device type can be inferred from the descriptors so encode it in the device-id table for now. Add a type structure that can be used to abstract the register layout and other features, and use it when accessing the XR21V141X UART registers that are shared by all types. Note that the currently supported XR21V141X type is the only type that has a set of UART Manager registers and that these will need to be handled specifically. Similarly, XR21V141X is the only type which has the divisor registers and that needs to use the format register when configuring the line settings. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 128 +++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 43 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index bbfe92fcabc0..003aa1e04c85 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -29,10 +29,16 @@ struct xr_txrx_clk_mask { #define XR21V141X_MIN_SPEED 46U #define XR21V141X_MAX_SPEED XR_INT_OSC_HZ -/* USB Requests */ +/* USB requests */ #define XR21V141X_SET_REQ 0 #define XR21V141X_GET_REQ 1 +/* XR21V141X register blocks */ +#define XR21V141X_UART_REG_BLOCK 0 +#define XR21V141X_UM_REG_BLOCK 4 +#define XR21V141X_UART_CUSTOM_BLOCK 0x66 + +/* XR21V141X UART registers */ #define XR21V141X_CLOCK_DIVISOR_0 0x04 #define XR21V141X_CLOCK_DIVISOR_1 0x05 #define XR21V141X_CLOCK_DIVISOR_2 0x06 @@ -40,13 +46,9 @@ struct xr_txrx_clk_mask { #define XR21V141X_TX_CLOCK_MASK_1 0x08 #define XR21V141X_RX_CLOCK_MASK_0 0x09 #define XR21V141X_RX_CLOCK_MASK_1 0x0a +#define XR21V141X_REG_FORMAT 0x0b -/* XR21V141X register blocks */ -#define XR21V141X_UART_REG_BLOCK 0 -#define XR21V141X_UM_REG_BLOCK 4 -#define XR21V141X_UART_CUSTOM_BLOCK 0x66 - -/* XR21V141X UART Manager Registers */ +/* XR21V141X UART Manager registers */ #define XR21V141X_UM_FIFO_ENABLE_REG 0x10 #define XR21V141X_UM_ENABLE_TX_FIFO 0x01 #define XR21V141X_UM_ENABLE_RX_FIFO 0x02 @@ -94,23 +96,42 @@ struct xr_txrx_clk_mask { #define XR_GPIO_MODE_RS485 0x3 #define XR_GPIO_MODE_RS485_ADDR 0x4 -#define XR21V141X_REG_ENABLE 0x03 -#define XR21V141X_REG_FORMAT 0x0b -#define XR21V141X_REG_FLOW_CTRL 0x0c -#define XR21V141X_REG_XON_CHAR 0x10 -#define XR21V141X_REG_XOFF_CHAR 0x11 -#define XR21V141X_REG_LOOPBACK 0x12 -#define XR21V141X_REG_TX_BREAK 0x14 -#define XR21V141X_REG_RS845_DELAY 0x15 -#define XR21V141X_REG_GPIO_MODE 0x1a -#define XR21V141X_REG_GPIO_DIR 0x1b -#define XR21V141X_REG_GPIO_INT_MASK 0x1c -#define XR21V141X_REG_GPIO_SET 0x1d -#define XR21V141X_REG_GPIO_CLR 0x1e -#define XR21V141X_REG_GPIO_STATUS 0x1f +struct xr_type { + u8 uart_enable; + u8 flow_control; + u8 xon_char; + u8 xoff_char; + u8 tx_break; + u8 gpio_mode; + u8 gpio_direction; + u8 gpio_set; + u8 gpio_clear; + u8 gpio_status; +}; + +enum xr_type_id { + XR21V141X, + XR_TYPE_COUNT, +}; + +static const struct xr_type xr_types[] = { + [XR21V141X] = { + .uart_enable = 0x03, + .flow_control = 0x0c, + .xon_char = 0x10, + .xoff_char = 0x11, + .tx_break = 0x14, + .gpio_mode = 0x1a, + .gpio_direction = 0x1b, + .gpio_set = 0x1d, + .gpio_clear = 0x1e, + .gpio_status = 0x1f, + }, +}; struct xr_data { - u8 channel; /* zero-based index */ + const struct xr_type *type; + u8 channel; /* zero-based index */ }; static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val) @@ -202,6 +223,7 @@ static int xr_set_reg_um(struct usb_serial_port *port, u8 reg_base, u8 val) */ static int xr_uart_enable(struct usb_serial_port *port) { + struct xr_data *data = usb_get_serial_port_data(port); int ret; ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, @@ -209,25 +231,25 @@ static int xr_uart_enable(struct usb_serial_port *port) if (ret) return ret; - ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE, + ret = xr_set_reg_uart(port, data->type->uart_enable, XR_UART_ENABLE_TX | XR_UART_ENABLE_RX); if (ret) return ret; ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, XR21V141X_UM_ENABLE_TX_FIFO | XR21V141X_UM_ENABLE_RX_FIFO); - if (ret) - xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0); + xr_set_reg_uart(port, data->type->uart_enable, 0); return ret; } static int xr_uart_disable(struct usb_serial_port *port) { + struct xr_data *data = usb_get_serial_port_data(port); int ret; - ret = xr_set_reg_uart(port, XR21V141X_REG_ENABLE, 0); + ret = xr_set_reg_uart(port, data->type->uart_enable, 0); if (ret) return ret; @@ -239,10 +261,11 @@ static int xr_uart_disable(struct usb_serial_port *port) static int xr_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; + struct xr_data *data = usb_get_serial_port_data(port); u8 status; int ret; - ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_STATUS, &status); + ret = xr_get_reg_uart(port, data->type->gpio_status, &status); if (ret) return ret; @@ -263,6 +286,8 @@ static int xr_tiocmget(struct tty_struct *tty) static int xr_tiocmset_port(struct usb_serial_port *port, unsigned int set, unsigned int clear) { + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; u8 gpio_set = 0; u8 gpio_clr = 0; int ret = 0; @@ -279,10 +304,10 @@ static int xr_tiocmset_port(struct usb_serial_port *port, /* Writing '0' to gpio_{set/clr} bits has no effect, so no need to do */ if (gpio_clr) - ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_CLR, gpio_clr); + ret = xr_set_reg_uart(port, type->gpio_clear, gpio_clr); if (gpio_set) - ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_SET, gpio_set); + ret = xr_set_reg_uart(port, type->gpio_set, gpio_set); return ret; } @@ -306,6 +331,8 @@ static void xr_dtr_rts(struct usb_serial_port *port, int on) static void xr_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; u8 state; if (break_state == 0) @@ -315,7 +342,7 @@ static void xr_break_ctl(struct tty_struct *tty, int break_state) dev_dbg(&port->dev, "Turning break %s\n", state == XR21V141X_UART_BREAK_OFF ? "off" : "on"); - xr_set_reg_uart(port, XR21V141X_REG_TX_BREAK, state); + xr_set_reg_uart(port, type->tx_break, state); } /* Tx and Rx clock mask values obtained from section 3.3.4 of datasheet */ @@ -425,10 +452,12 @@ static void xr_set_flow_mode(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; u8 flow, gpio_mode; int ret; - ret = xr_get_reg_uart(port, XR21V141X_REG_GPIO_MODE, &gpio_mode); + ret = xr_get_reg_uart(port, type->gpio_mode, &gpio_mode); if (ret) return; @@ -446,8 +475,8 @@ static void xr_set_flow_mode(struct tty_struct *tty, dev_dbg(&port->dev, "Enabling sw flow ctrl\n"); flow = XR_UART_FLOW_MODE_SW; - xr_set_reg_uart(port, XR21V141X_REG_XON_CHAR, start_char); - xr_set_reg_uart(port, XR21V141X_REG_XOFF_CHAR, stop_char); + xr_set_reg_uart(port, type->xon_char, start_char); + xr_set_reg_uart(port, type->xoff_char, stop_char); } else { dev_dbg(&port->dev, "Disabling flow ctrl\n"); flow = XR_UART_FLOW_MODE_NONE; @@ -458,10 +487,10 @@ static void xr_set_flow_mode(struct tty_struct *tty, * FLOW_CONTROL register. */ xr_uart_disable(port); - xr_set_reg_uart(port, XR21V141X_REG_FLOW_CTRL, flow); + xr_set_reg_uart(port, type->flow_control, flow); xr_uart_enable(port); - xr_set_reg_uart(port, XR21V141X_REG_GPIO_MODE, gpio_mode); + xr_set_reg_uart(port, type->gpio_mode, gpio_mode); if (C_BAUD(tty) == B0) xr_dtr_rts(port, 0); @@ -585,17 +614,19 @@ static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id) if (ret) return ret; + usb_set_serial_data(serial, (void *)id->driver_info); + return 0; } -static int xr_gpio_init(struct usb_serial_port *port) +static int xr_gpio_init(struct usb_serial_port *port, const struct xr_type *type) { u8 mask, mode; int ret; /* Configure all pins as GPIO. */ mode = 0; - ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_MODE, mode); + ret = xr_set_reg_uart(port, type->gpio_mode, mode); if (ret) return ret; @@ -604,11 +635,11 @@ static int xr_gpio_init(struct usb_serial_port *port) * (active low), and configure RI, CD, DSR and CTS as inputs. */ mask = XR_GPIO_DTR | XR_GPIO_RTS; - ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_DIR, mask); + ret = xr_set_reg_uart(port, type->gpio_direction, mask); if (ret) return ret; - ret = xr_set_reg_uart(port, XR21V141X_REG_GPIO_SET, mask); + ret = xr_set_reg_uart(port, type->gpio_set, mask); if (ret) return ret; @@ -618,19 +649,26 @@ static int xr_gpio_init(struct usb_serial_port *port) static int xr_port_probe(struct usb_serial_port *port) { struct usb_interface_descriptor *desc; + const struct xr_type *type; struct xr_data *data; + enum xr_type_id type_id; int ret; + type_id = (int)(unsigned long)usb_get_serial_data(port->serial); + type = &xr_types[type_id]; + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + data->type = type; + desc = &port->serial->interface->cur_altsetting->desc; data->channel = desc->bInterfaceNumber / 2; usb_set_serial_port_data(port, data); - ret = xr_gpio_init(port); + ret = xr_gpio_init(port, type); if (ret) goto err_free; @@ -649,10 +687,14 @@ static void xr_port_remove(struct usb_serial_port *port) kfree(data); } +#define XR_DEVICE(vid, pid, type) \ + USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_COMM), \ + .driver_info = (type) + static const struct usb_device_id id_table[] = { - { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1410, USB_CLASS_COMM) }, /* XR21V1410 */ - { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1412, USB_CLASS_COMM) }, /* XR21V1412 */ - { USB_DEVICE_INTERFACE_CLASS(0x04e2, 0x1414, USB_CLASS_COMM) }, /* XR21V1414 */ + { XR_DEVICE(0x04e2, 0x1410, XR21V141X) }, + { XR_DEVICE(0x04e2, 0x1412, XR21V141X) }, + { XR_DEVICE(0x04e2, 0x1414, XR21V141X) }, { } }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit 1.4.1 From 607f67183742eeb45e316e89dc7fec64d6288308 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:52 +0200 Subject: USB: serial: xr: add support for XR21B1421, XR21B1422 and XR21B1424 The XR21B1421, XR21B1422 and XR21B1424 are the one-, two- and four-port models of a second XR21B142X type of the Maxlinear/Exar USB UARTs. The XR21B142X type differs from XR21V141X in several ways, including: - register layout - register width (16-bit instead of 8-bit) - vendor register requests - UART enable/disable sequence - custom-driver mode flag - three additional GPIOs (9 instead of 6) As for XR21V141X, the XR21B142X vendor requests encode the channel index in the MSB of wIndex, but it lacks the UART Manager registers which have been replaced by regular UART registers. The new type also uses the interface number of the control interface (0, 2, 4, 6) as channel index instead of the channel number (0, 1, 2, 3). The XR21B142X lacks the divisor and format registers used by XR21V141X and instead uses the CDC SET_LINE_CONTROL request to configure the line settings. Note that the currently supported XR21V141X type lacks the custom-driver mode flag that prevents the device from entering CDC-ACM mode when a CDC requests is received. This specifically means that the SET_LINE_CONTROL request cannot be used with XR21V141X even though it is otherwise supported. The UART enable sequence for XR21B142X does not involve explicitly enabling the FIFOs, but according to datasheet the UART must be disabled when writing any register but GPIO_SET, GPIO_CLEAR, TX_BREAK and ERROR_STATUS. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 338 ++++++++++++++++++++++++++++++++--------- 1 file changed, 262 insertions(+), 76 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 003aa1e04c85..32055c763147 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -29,10 +29,6 @@ struct xr_txrx_clk_mask { #define XR21V141X_MIN_SPEED 46U #define XR21V141X_MAX_SPEED XR_INT_OSC_HZ -/* USB requests */ -#define XR21V141X_SET_REQ 0 -#define XR21V141X_GET_REQ 1 - /* XR21V141X register blocks */ #define XR21V141X_UART_REG_BLOCK 0 #define XR21V141X_UM_REG_BLOCK 4 @@ -65,9 +61,10 @@ struct xr_txrx_clk_mask { #define XR_GPIO_DTR BIT(3) #define XR_GPIO_CTS BIT(4) #define XR_GPIO_RTS BIT(5) - -#define XR21V141X_UART_BREAK_ON 0xff -#define XR21V141X_UART_BREAK_OFF 0 +#define XR_GPIO_CLK BIT(6) +#define XR_GPIO_XEN BIT(7) +#define XR_GPIO_TXT BIT(8) +#define XR_GPIO_RXT BIT(9) #define XR_UART_DATA_MASK GENMASK(3, 0) #define XR_UART_DATA_7 0x7 @@ -90,13 +87,27 @@ struct xr_txrx_clk_mask { #define XR_UART_FLOW_MODE_HW 0x1 #define XR_UART_FLOW_MODE_SW 0x2 -#define XR_GPIO_MODE_MASK GENMASK(2, 0) -#define XR_GPIO_MODE_RTS_CTS 0x1 -#define XR_GPIO_MODE_DTR_DSR 0x2 -#define XR_GPIO_MODE_RS485 0x3 -#define XR_GPIO_MODE_RS485_ADDR 0x4 +#define XR_GPIO_MODE_SEL_MASK GENMASK(2, 0) +#define XR_GPIO_MODE_SEL_RTS_CTS 0x1 +#define XR_GPIO_MODE_SEL_DTR_DSR 0x2 +#define XR_GPIO_MODE_SEL_RS485 0x3 +#define XR_GPIO_MODE_SEL_RS485_ADDR 0x4 +#define XR_GPIO_MODE_TX_TOGGLE 0x100 +#define XR_GPIO_MODE_RX_TOGGLE 0x200 + +#define XR_CUSTOM_DRIVER_ACTIVE 0x1 + +static int xr21v141x_uart_enable(struct usb_serial_port *port); +static int xr21v141x_uart_disable(struct usb_serial_port *port); +static void xr21v141x_set_line_settings(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios); struct xr_type { + int reg_width; + u8 reg_recipient; + u8 set_reg; + u8 get_reg; + u8 uart_enable; u8 flow_control; u8 xon_char; @@ -107,15 +118,30 @@ struct xr_type { u8 gpio_set; u8 gpio_clear; u8 gpio_status; + u8 custom_driver; + + bool have_xmit_toggle; + + int (*enable)(struct usb_serial_port *port); + int (*disable)(struct usb_serial_port *port); + void (*set_line_settings)(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios); }; enum xr_type_id { XR21V141X, + XR21B142X, XR_TYPE_COUNT, }; static const struct xr_type xr_types[] = { [XR21V141X] = { + .reg_width = 8, + .reg_recipient = USB_RECIP_DEVICE, + .set_reg = 0x00, + .get_reg = 0x01, + .uart_enable = 0x03, .flow_control = 0x0c, .xon_char = 0x10, @@ -126,25 +152,50 @@ static const struct xr_type xr_types[] = { .gpio_set = 0x1d, .gpio_clear = 0x1e, .gpio_status = 0x1f, + + .enable = xr21v141x_uart_enable, + .disable = xr21v141x_uart_disable, + .set_line_settings = xr21v141x_set_line_settings, + }, + [XR21B142X] = { + .reg_width = 16, + .reg_recipient = USB_RECIP_INTERFACE, + .set_reg = 0x00, + .get_reg = 0x00, + + .uart_enable = 0x00, + .flow_control = 0x06, + .xon_char = 0x07, + .xoff_char = 0x08, + .tx_break = 0x0a, + .gpio_mode = 0x0c, + .gpio_direction = 0x0d, + .gpio_set = 0x0e, + .gpio_clear = 0x0f, + .gpio_status = 0x10, + .custom_driver = 0x60, + + .have_xmit_toggle = true, }, }; struct xr_data { const struct xr_type *type; - u8 channel; /* zero-based index */ + u8 channel; /* zero-based index or interface number */ }; -static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val) +static int xr_set_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 val) { + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; struct usb_serial *serial = port->serial; int ret; - ret = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - XR21V141X_SET_REQ, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - val, reg | (block << 8), NULL, 0, - USB_CTRL_SET_TIMEOUT); + ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + type->set_reg, + USB_DIR_OUT | USB_TYPE_VENDOR | type->reg_recipient, + val, (channel << 8) | reg, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (ret < 0) { dev_err(&port->dev, "Failed to set reg 0x%02x: %d\n", reg, ret); return ret; @@ -153,24 +204,33 @@ static int xr_set_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 val) return 0; } -static int xr_get_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 *val) +static int xr_get_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 *val) { + struct xr_data *data = usb_get_serial_port_data(port); + const struct xr_type *type = data->type; struct usb_serial *serial = port->serial; u8 *dmabuf; - int ret; + int ret, len; - dmabuf = kmalloc(1, GFP_KERNEL); + if (type->reg_width == 8) + len = 1; + else + len = 2; + + dmabuf = kmalloc(len, GFP_KERNEL); if (!dmabuf) return -ENOMEM; - ret = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - XR21V141X_GET_REQ, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, reg | (block << 8), dmabuf, 1, - USB_CTRL_GET_TIMEOUT); - if (ret == 1) { - *val = *dmabuf; + ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + type->get_reg, + USB_DIR_IN | USB_TYPE_VENDOR | type->reg_recipient, + 0, (channel << 8) | reg, dmabuf, len, + USB_CTRL_GET_TIMEOUT); + if (ret == len) { + if (len == 2) + *val = le16_to_cpup((__le16 *)dmabuf); + else + *val = *dmabuf; ret = 0; } else { dev_err(&port->dev, "Failed to get reg 0x%02x: %d\n", reg, ret); @@ -183,24 +243,18 @@ static int xr_get_reg(struct usb_serial_port *port, u8 block, u8 reg, u8 *val) return ret; } -static int xr_set_reg_uart(struct usb_serial_port *port, u8 reg, u8 val) +static int xr_set_reg_uart(struct usb_serial_port *port, u8 reg, u16 val) { struct xr_data *data = usb_get_serial_port_data(port); - u8 block; - - block = XR21V141X_UART_REG_BLOCK + data->channel; - return xr_set_reg(port, block, reg, val); + return xr_set_reg(port, data->channel, reg, val); } -static int xr_get_reg_uart(struct usb_serial_port *port, u8 reg, u8 *val) +static int xr_get_reg_uart(struct usb_serial_port *port, u8 reg, u16 *val) { struct xr_data *data = usb_get_serial_port_data(port); - u8 block; - block = XR21V141X_UART_REG_BLOCK + data->channel; - - return xr_get_reg(port, block, reg, val); + return xr_get_reg(port, data->channel, reg, val); } static int xr_set_reg_um(struct usb_serial_port *port, u8 reg_base, u8 val) @@ -213,6 +267,21 @@ static int xr_set_reg_um(struct usb_serial_port *port, u8 reg_base, u8 val) return xr_set_reg(port, XR21V141X_UM_REG_BLOCK, reg, val); } +static int __xr_uart_enable(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + return xr_set_reg_uart(port, data->type->uart_enable, + XR_UART_ENABLE_TX | XR_UART_ENABLE_RX); +} + +static int __xr_uart_disable(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + return xr_set_reg_uart(port, data->type->uart_enable, 0); +} + /* * According to datasheet, below is the recommended sequence for enabling UART * module in XR21V141X: @@ -221,9 +290,8 @@ static int xr_set_reg_um(struct usb_serial_port *port, u8 reg_base, u8 val) * Enable Tx and Rx * Enable Rx FIFO */ -static int xr_uart_enable(struct usb_serial_port *port) +static int xr21v141x_uart_enable(struct usb_serial_port *port) { - struct xr_data *data = usb_get_serial_port_data(port); int ret; ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, @@ -231,25 +299,23 @@ static int xr_uart_enable(struct usb_serial_port *port) if (ret) return ret; - ret = xr_set_reg_uart(port, data->type->uart_enable, - XR_UART_ENABLE_TX | XR_UART_ENABLE_RX); + ret = __xr_uart_enable(port); if (ret) return ret; ret = xr_set_reg_um(port, XR21V141X_UM_FIFO_ENABLE_REG, XR21V141X_UM_ENABLE_TX_FIFO | XR21V141X_UM_ENABLE_RX_FIFO); if (ret) - xr_set_reg_uart(port, data->type->uart_enable, 0); + __xr_uart_disable(port); return ret; } -static int xr_uart_disable(struct usb_serial_port *port) +static int xr21v141x_uart_disable(struct usb_serial_port *port) { - struct xr_data *data = usb_get_serial_port_data(port); int ret; - ret = xr_set_reg_uart(port, data->type->uart_enable, 0); + ret = __xr_uart_disable(port); if (ret) return ret; @@ -258,11 +324,31 @@ static int xr_uart_disable(struct usb_serial_port *port) return ret; } +static int xr_uart_enable(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + if (data->type->enable) + return data->type->enable(port); + + return __xr_uart_enable(port); +} + +static int xr_uart_disable(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + if (data->type->disable) + return data->type->disable(port); + + return __xr_uart_disable(port); +} + static int xr_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct xr_data *data = usb_get_serial_port_data(port); - u8 status; + u16 status; int ret; ret = xr_get_reg_uart(port, data->type->gpio_status, &status); @@ -288,8 +374,8 @@ static int xr_tiocmset_port(struct usb_serial_port *port, { struct xr_data *data = usb_get_serial_port_data(port); const struct xr_type *type = data->type; - u8 gpio_set = 0; - u8 gpio_clr = 0; + u16 gpio_set = 0; + u16 gpio_clr = 0; int ret = 0; /* Modem control pins are active low, so set & clr are swapped */ @@ -333,15 +419,15 @@ static void xr_break_ctl(struct tty_struct *tty, int break_state) struct usb_serial_port *port = tty->driver_data; struct xr_data *data = usb_get_serial_port_data(port); const struct xr_type *type = data->type; - u8 state; + u16 state; if (break_state == 0) - state = XR21V141X_UART_BREAK_OFF; + state = 0; else - state = XR21V141X_UART_BREAK_ON; + state = GENMASK(type->reg_width - 1, 0); + + dev_dbg(&port->dev, "Turning break %s\n", state == 0 ? "off" : "on"); - dev_dbg(&port->dev, "Turning break %s\n", - state == XR21V141X_UART_BREAK_OFF ? "off" : "on"); xr_set_reg_uart(port, type->tx_break, state); } @@ -381,8 +467,7 @@ static const struct xr_txrx_clk_mask xr21v141x_txrx_clk_masks[] = { { 0xfff, 0xffe, 0xffd }, }; -static int xr_set_baudrate(struct tty_struct *tty, - struct usb_serial_port *port) +static int xr21v141x_set_baudrate(struct tty_struct *tty, struct usb_serial_port *port) { u32 divisor, baud, idx; u16 tx_mask, rx_mask; @@ -454,19 +539,26 @@ static void xr_set_flow_mode(struct tty_struct *tty, { struct xr_data *data = usb_get_serial_port_data(port); const struct xr_type *type = data->type; - u8 flow, gpio_mode; + u16 flow, gpio_mode; int ret; ret = xr_get_reg_uart(port, type->gpio_mode, &gpio_mode); if (ret) return; + /* + * According to the datasheets, the UART needs to be disabled while + * writing to the FLOW_CONTROL register (XR21V141X), or any register + * but GPIO_SET, GPIO_CLEAR, TX_BREAK and ERROR_STATUS (XR21B142X). + */ + xr_uart_disable(port); + /* Set GPIO mode for controlling the pins manually by default. */ - gpio_mode &= ~XR_GPIO_MODE_MASK; + gpio_mode &= ~XR_GPIO_MODE_SEL_MASK; if (C_CRTSCTS(tty) && C_BAUD(tty) != B0) { dev_dbg(&port->dev, "Enabling hardware flow ctrl\n"); - gpio_mode |= XR_GPIO_MODE_RTS_CTS; + gpio_mode |= XR_GPIO_MODE_SEL_RTS_CTS; flow = XR_UART_FLOW_MODE_HW; } else if (I_IXON(tty)) { u8 start_char = START_CHAR(tty); @@ -482,32 +574,26 @@ static void xr_set_flow_mode(struct tty_struct *tty, flow = XR_UART_FLOW_MODE_NONE; } - /* - * As per the datasheet, UART needs to be disabled while writing to - * FLOW_CONTROL register. - */ - xr_uart_disable(port); xr_set_reg_uart(port, type->flow_control, flow); - xr_uart_enable(port); - xr_set_reg_uart(port, type->gpio_mode, gpio_mode); + xr_uart_enable(port); + if (C_BAUD(tty) == B0) xr_dtr_rts(port, 0); else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) xr_dtr_rts(port, 1); } -static void xr_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) +static void xr21v141x_set_line_settings(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) { struct ktermios *termios = &tty->termios; u8 bits = 0; int ret; if (!old_termios || (tty->termios.c_ospeed != old_termios->c_ospeed)) - xr_set_baudrate(tty, port); + xr21v141x_set_baudrate(tty, port); switch (C_CSIZE(tty)) { case CS5: @@ -555,6 +641,88 @@ static void xr_set_termios(struct tty_struct *tty, ret = xr_set_reg_uart(port, XR21V141X_REG_FORMAT, bits); if (ret) return; +} + +static void xr_cdc_set_line_coding(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) +{ + struct usb_host_interface *alt = port->serial->interface->cur_altsetting; + struct usb_device *udev = port->serial->dev; + struct usb_cdc_line_coding *lc; + int ret; + + lc = kzalloc(sizeof(*lc), GFP_KERNEL); + if (!lc) + return; + + if (tty->termios.c_ospeed) + lc->dwDTERate = cpu_to_le32(tty->termios.c_ospeed); + else if (old_termios) + lc->dwDTERate = cpu_to_le32(old_termios->c_ospeed); + else + lc->dwDTERate = cpu_to_le32(9600); + + if (C_CSTOPB(tty)) + lc->bCharFormat = USB_CDC_2_STOP_BITS; + else + lc->bCharFormat = USB_CDC_1_STOP_BITS; + + if (C_PARENB(tty)) { + if (C_CMSPAR(tty)) { + if (C_PARODD(tty)) + lc->bParityType = USB_CDC_MARK_PARITY; + else + lc->bParityType = USB_CDC_SPACE_PARITY; + } else { + if (C_PARODD(tty)) + lc->bParityType = USB_CDC_ODD_PARITY; + else + lc->bParityType = USB_CDC_EVEN_PARITY; + } + } else { + lc->bParityType = USB_CDC_NO_PARITY; + } + + switch (C_CSIZE(tty)) { + case CS5: + lc->bDataBits = 5; + break; + case CS6: + lc->bDataBits = 6; + break; + case CS7: + lc->bDataBits = 7; + break; + case CS8: + default: + lc->bDataBits = 8; + break; + } + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_CDC_REQ_SET_LINE_CODING, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, alt->desc.bInterfaceNumber, + lc, sizeof(*lc), USB_CTRL_SET_TIMEOUT); + if (ret < 0) + dev_err(&port->dev, "Failed to set line coding: %d\n", ret); + + kfree(lc); +} + +static void xr_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) +{ + struct xr_data *data = usb_get_serial_port_data(port); + + /* + * XR21V141X does not have a CUSTOM_DRIVER flag and always enters CDC + * mode upon receiving CDC requests. + */ + if (data->type->set_line_settings) + data->type->set_line_settings(tty, port, old_termios); + else + xr_cdc_set_line_coding(tty, port, old_termios); xr_set_flow_mode(tty, port, old_termios); } @@ -621,11 +789,16 @@ static int xr_probe(struct usb_serial *serial, const struct usb_device_id *id) static int xr_gpio_init(struct usb_serial_port *port, const struct xr_type *type) { - u8 mask, mode; + u16 mask, mode; int ret; - /* Configure all pins as GPIO. */ + /* + * Configure all pins as GPIO except for Receive and Transmit Toggle. + */ mode = 0; + if (type->have_xmit_toggle) + mode |= XR_GPIO_MODE_RX_TOGGLE | XR_GPIO_MODE_TX_TOGGLE; + ret = xr_set_reg_uart(port, type->gpio_mode, mode); if (ret) return ret; @@ -664,10 +837,20 @@ static int xr_port_probe(struct usb_serial_port *port) data->type = type; desc = &port->serial->interface->cur_altsetting->desc; - data->channel = desc->bInterfaceNumber / 2; + if (type_id == XR21V141X) + data->channel = desc->bInterfaceNumber / 2; + else + data->channel = desc->bInterfaceNumber; usb_set_serial_port_data(port, data); + if (type->custom_driver) { + ret = xr_set_reg_uart(port, type->custom_driver, + XR_CUSTOM_DRIVER_ACTIVE); + if (ret) + goto err_free; + } + ret = xr_gpio_init(port, type); if (ret) goto err_free; @@ -695,6 +878,9 @@ static const struct usb_device_id id_table[] = { { XR_DEVICE(0x04e2, 0x1410, XR21V141X) }, { XR_DEVICE(0x04e2, 0x1412, XR21V141X) }, { XR_DEVICE(0x04e2, 0x1414, XR21V141X) }, + { XR_DEVICE(0x04e2, 0x1420, XR21B142X) }, + { XR_DEVICE(0x04e2, 0x1422, XR21B142X) }, + { XR_DEVICE(0x04e2, 0x1424, XR21B142X) }, { } }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit 1.4.1 From 4099d4ba476325100fcafb139fc6c49d0441bc7c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:53 +0200 Subject: USB: serial: xr: add support for XR21B1411 The single-port XR21B1411 is similar to the XR21B142X type but uses 12-bit registers and 16-bit register addresses, the register requests are different and are directed at the device rather than interface, and 5 and 6-bit words are not supported. The register layout is very similar to XR21B142X except that most registers are offset by 0xc00 (corresponding to a channel index of 12 in the MSB of wIndex). As the device is single-port so that the derived channel index is 0, the current register accessors can be reused after simply changing the address width. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 64 +++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 16 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 32055c763147..46e5e1b2f3c0 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -108,18 +108,19 @@ struct xr_type { u8 set_reg; u8 get_reg; - u8 uart_enable; - u8 flow_control; - u8 xon_char; - u8 xoff_char; - u8 tx_break; - u8 gpio_mode; - u8 gpio_direction; - u8 gpio_set; - u8 gpio_clear; - u8 gpio_status; - u8 custom_driver; - + u16 uart_enable; + u16 flow_control; + u16 xon_char; + u16 xoff_char; + u16 tx_break; + u16 gpio_mode; + u16 gpio_direction; + u16 gpio_set; + u16 gpio_clear; + u16 gpio_status; + u16 custom_driver; + + bool have_5_6_bit_mode; bool have_xmit_toggle; int (*enable)(struct usb_serial_port *port); @@ -132,6 +133,7 @@ struct xr_type { enum xr_type_id { XR21V141X, XR21B142X, + XR21B1411, XR_TYPE_COUNT, }; @@ -175,8 +177,27 @@ static const struct xr_type xr_types[] = { .gpio_status = 0x10, .custom_driver = 0x60, + .have_5_6_bit_mode = true, .have_xmit_toggle = true, }, + [XR21B1411] = { + .reg_width = 12, + .reg_recipient = USB_RECIP_DEVICE, + .set_reg = 0x00, + .get_reg = 0x01, + + .uart_enable = 0xc00, + .flow_control = 0xc06, + .xon_char = 0xc07, + .xoff_char = 0xc08, + .tx_break = 0xc0a, + .gpio_mode = 0xc0c, + .gpio_direction = 0xc0d, + .gpio_set = 0xc0e, + .gpio_clear = 0xc0f, + .gpio_status = 0xc10, + .custom_driver = 0x20d, + }, }; struct xr_data { @@ -184,7 +205,7 @@ struct xr_data { u8 channel; /* zero-based index or interface number */ }; -static int xr_set_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 val) +static int xr_set_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 val) { struct xr_data *data = usb_get_serial_port_data(port); const struct xr_type *type = data->type; @@ -204,7 +225,7 @@ static int xr_set_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 val) return 0; } -static int xr_get_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 *val) +static int xr_get_reg(struct usb_serial_port *port, u8 channel, u16 reg, u16 *val) { struct xr_data *data = usb_get_serial_port_data(port); const struct xr_type *type = data->type; @@ -243,14 +264,14 @@ static int xr_get_reg(struct usb_serial_port *port, u8 channel, u8 reg, u16 *val return ret; } -static int xr_set_reg_uart(struct usb_serial_port *port, u8 reg, u16 val) +static int xr_set_reg_uart(struct usb_serial_port *port, u16 reg, u16 val) { struct xr_data *data = usb_get_serial_port_data(port); return xr_set_reg(port, data->channel, reg, val); } -static int xr_get_reg_uart(struct usb_serial_port *port, u8 reg, u16 *val) +static int xr_get_reg_uart(struct usb_serial_port *port, u16 reg, u16 *val) { struct xr_data *data = usb_get_serial_port_data(port); @@ -646,6 +667,7 @@ static void xr21v141x_set_line_settings(struct tty_struct *tty, static void xr_cdc_set_line_coding(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { + struct xr_data *data = usb_get_serial_port_data(port); struct usb_host_interface *alt = port->serial->interface->cur_altsetting; struct usb_device *udev = port->serial->dev; struct usb_cdc_line_coding *lc; @@ -683,6 +705,15 @@ static void xr_cdc_set_line_coding(struct tty_struct *tty, lc->bParityType = USB_CDC_NO_PARITY; } + if (!data->type->have_5_6_bit_mode && + (C_CSIZE(tty) == CS5 || C_CSIZE(tty) == CS6)) { + tty->termios.c_cflag &= ~CSIZE; + if (old_termios) + tty->termios.c_cflag |= old_termios->c_cflag & CSIZE; + else + tty->termios.c_cflag |= CS8; + } + switch (C_CSIZE(tty)) { case CS5: lc->bDataBits = 5; @@ -876,6 +907,7 @@ static void xr_port_remove(struct usb_serial_port *port) static const struct usb_device_id id_table[] = { { XR_DEVICE(0x04e2, 0x1410, XR21V141X) }, + { XR_DEVICE(0x04e2, 0x1411, XR21B1411) }, { XR_DEVICE(0x04e2, 0x1412, XR21V141X) }, { XR_DEVICE(0x04e2, 0x1414, XR21V141X) }, { XR_DEVICE(0x04e2, 0x1420, XR21B142X) }, -- cgit 1.4.1 From 6da99f9de5feb25b01cbe37fdb15f26a2d7d64a9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:54 +0200 Subject: USB: serial: xr: add support for XR22801, XR22802, XR22804 The XR22801, XR22802 and XR22804 are compound devices with an embedded hub and up to seven downstream USB devices including one, two or four UARTs respectively. The UART function is similar to XR21B142X but most registers are offset by 0x40, the register requests are different and are directed at the device rather than interface, and 5 and 6-bit words are not supported. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 46e5e1b2f3c0..14dbda13ab4d 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -134,6 +134,7 @@ enum xr_type_id { XR21V141X, XR21B142X, XR21B1411, + XR2280X, XR_TYPE_COUNT, }; @@ -198,6 +199,24 @@ static const struct xr_type xr_types[] = { .gpio_status = 0xc10, .custom_driver = 0x20d, }, + [XR2280X] = { + .reg_width = 16, + .reg_recipient = USB_RECIP_DEVICE, + .set_reg = 0x05, + .get_reg = 0x05, + + .uart_enable = 0x40, + .flow_control = 0x46, + .xon_char = 0x47, + .xoff_char = 0x48, + .tx_break = 0x4a, + .gpio_mode = 0x4c, + .gpio_direction = 0x4d, + .gpio_set = 0x4e, + .gpio_clear = 0x4f, + .gpio_status = 0x50, + .custom_driver = 0x81, + }, }; struct xr_data { @@ -906,6 +925,10 @@ static void xr_port_remove(struct usb_serial_port *port) .driver_info = (type) static const struct usb_device_id id_table[] = { + { XR_DEVICE(0x04e2, 0x1400, XR2280X) }, + { XR_DEVICE(0x04e2, 0x1401, XR2280X) }, + { XR_DEVICE(0x04e2, 0x1402, XR2280X) }, + { XR_DEVICE(0x04e2, 0x1403, XR2280X) }, { XR_DEVICE(0x04e2, 0x1410, XR21V141X) }, { XR_DEVICE(0x04e2, 0x1411, XR21B1411) }, { XR_DEVICE(0x04e2, 0x1412, XR21V141X) }, -- cgit 1.4.1 From 06f79d57f4f572395082da07d663fef91c9bb891 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:55 +0200 Subject: USB: serial: xr: reset FIFOs on open Reset the transmit and receive FIFOs before enabling the UARTs as part of open() in order to flush any stale data. Note that the XR21V141X needs a type-specific implementation due to its UART Manager registers. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 14dbda13ab4d..1b7b3c70a9b3 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -95,10 +95,13 @@ struct xr_txrx_clk_mask { #define XR_GPIO_MODE_TX_TOGGLE 0x100 #define XR_GPIO_MODE_RX_TOGGLE 0x200 +#define XR_FIFO_RESET 0x1 + #define XR_CUSTOM_DRIVER_ACTIVE 0x1 static int xr21v141x_uart_enable(struct usb_serial_port *port); static int xr21v141x_uart_disable(struct usb_serial_port *port); +static int xr21v141x_fifo_reset(struct usb_serial_port *port); static void xr21v141x_set_line_settings(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); @@ -118,6 +121,8 @@ struct xr_type { u16 gpio_set; u16 gpio_clear; u16 gpio_status; + u16 tx_fifo_reset; + u16 rx_fifo_reset; u16 custom_driver; bool have_5_6_bit_mode; @@ -125,6 +130,7 @@ struct xr_type { int (*enable)(struct usb_serial_port *port); int (*disable)(struct usb_serial_port *port); + int (*fifo_reset)(struct usb_serial_port *port); void (*set_line_settings)(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); @@ -158,6 +164,7 @@ static const struct xr_type xr_types[] = { .enable = xr21v141x_uart_enable, .disable = xr21v141x_uart_disable, + .fifo_reset = xr21v141x_fifo_reset, .set_line_settings = xr21v141x_set_line_settings, }, [XR21B142X] = { @@ -176,6 +183,8 @@ static const struct xr_type xr_types[] = { .gpio_set = 0x0e, .gpio_clear = 0x0f, .gpio_status = 0x10, + .tx_fifo_reset = 0x40, + .rx_fifo_reset = 0x43, .custom_driver = 0x60, .have_5_6_bit_mode = true, @@ -197,6 +206,8 @@ static const struct xr_type xr_types[] = { .gpio_set = 0xc0e, .gpio_clear = 0xc0f, .gpio_status = 0xc10, + .tx_fifo_reset = 0xc80, + .rx_fifo_reset = 0xcc0, .custom_driver = 0x20d, }, [XR2280X] = { @@ -215,6 +226,8 @@ static const struct xr_type xr_types[] = { .gpio_set = 0x4e, .gpio_clear = 0x4f, .gpio_status = 0x50, + .tx_fifo_reset = 0x60, + .rx_fifo_reset = 0x63, .custom_driver = 0x81, }, }; @@ -384,6 +397,40 @@ static int xr_uart_disable(struct usb_serial_port *port) return __xr_uart_disable(port); } +static int xr21v141x_fifo_reset(struct usb_serial_port *port) +{ + int ret; + + ret = xr_set_reg_um(port, XR21V141X_UM_TX_FIFO_RESET, XR_FIFO_RESET); + if (ret) + return ret; + + ret = xr_set_reg_um(port, XR21V141X_UM_RX_FIFO_RESET, XR_FIFO_RESET); + if (ret) + return ret; + + return 0; +} + +static int xr_fifo_reset(struct usb_serial_port *port) +{ + struct xr_data *data = usb_get_serial_port_data(port); + int ret; + + if (data->type->fifo_reset) + return data->type->fifo_reset(port); + + ret = xr_set_reg_uart(port, data->type->tx_fifo_reset, XR_FIFO_RESET); + if (ret) + return ret; + + ret = xr_set_reg_uart(port, data->type->rx_fifo_reset, XR_FIFO_RESET); + if (ret) + return ret; + + return 0; +} + static int xr_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; @@ -781,6 +828,10 @@ static int xr_open(struct tty_struct *tty, struct usb_serial_port *port) { int ret; + ret = xr_fifo_reset(port); + if (ret) + return ret; + ret = xr_uart_enable(port); if (ret) { dev_err(&port->dev, "Failed to enable UART\n"); -- cgit 1.4.1 From d801c8d438b3e8f2b6d2f79e3c75b8e0c5dd86df Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 12 Apr 2021 11:55:56 +0200 Subject: USB: serial: xr: add copyright notice Add another copyright notice for the work done in 2021. Signed-off-by: Johan Hovold --- drivers/usb/serial/xr_serial.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 1b7b3c70a9b3..6853cd56d8dc 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -3,6 +3,7 @@ * MaxLinear/Exar USB to Serial driver * * Copyright (c) 2020 Manivannan Sadhasivam + * Copyright (c) 2021 Johan Hovold * * Based on the initial driver written by Patong Yang: * -- cgit 1.4.1 From 039b81d50a4822edfc07a7c2e6963823e993b2f0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 12 Apr 2021 11:55:57 +0200 Subject: USB: cdc-acm: add more Maxlinear/Exar models to ignore list Now that the xr_serial got support for other models, add their USB IDs as well. The Maxlinear/Exar USB UARTs can be used in either ACM mode using the cdc-acm driver or in "custom driver" mode in which further features such as hardware and software flow control, GPIO control and in-band line-status reporting are available. In ACM mode the device always enables RTS/CTS flow control, something which could prevent transmission in case the CTS input isn't wired up correctly. Ensure that cdc_acm will not bind to these devices if the custom USB-serial driver is enabled. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/5155887a764cbc11f8da0217fe08a24a77d120b4.1616571453.git.mchehab+huawei@kernel.org [ johan: rewrite commit message, clean up entries ] Cc: Oliver Neukum Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/class/cdc-acm.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 39ddb5585ded..2e43a03aca46 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1902,9 +1902,17 @@ static const struct usb_device_id acm_ids[] = { #endif #if IS_ENABLED(CONFIG_USB_SERIAL_XR) - { USB_DEVICE(0x04e2, 0x1410), /* Ignore XR21V141X USB to Serial converter */ - .driver_info = IGNORE_DEVICE, - }, + { USB_DEVICE(0x04e2, 0x1400), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1401), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1402), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1403), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1410), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1411), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1412), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1414), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1420), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1422), .driver_info = IGNORE_DEVICE }, + { USB_DEVICE(0x04e2, 0x1424), .driver_info = IGNORE_DEVICE }, #endif /*Samsung phone in firmware update mode */ -- cgit 1.4.1