From 7bd7ad3c310cd6766f170927381eea0aa6f46c69 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 13 Sep 2022 16:53:12 +0200 Subject: USB: serial: ftdi_sio: fix 300 bps rate for SIO The 300 bps rate of SIO devices has been mapped to 9600 bps since 2003... Let's fix the regression. Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 52d59be92034..787e63fd7f99 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1319,8 +1319,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, case 38400: div_value = ftdi_sio_b38400; break; case 57600: div_value = ftdi_sio_b57600; break; case 115200: div_value = ftdi_sio_b115200; break; - } /* baud */ - if (div_value == 0) { + default: dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n", __func__, baud); div_value = ftdi_sio_b9600; -- cgit v1.2.3 From 366e89aafe200d654d6fca788cb837906c82159d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:05 +0200 Subject: USB: serial: ftdi_sio: clean up chip type enum Clean up the chip type enum by dropping the explicit values and moving the definition to the implementation to make it easier to add further types. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 11 +++++++++++ drivers/usb/serial/ftdi_sio.h | 12 ------------ 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 787e63fd7f99..54a79284ffd7 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -47,6 +47,17 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober , Andreas Mohr, Johan Hovold " #define DRIVER_DESC "USB FTDI Serial Converters Driver" +enum ftdi_chip_type { + SIO, + FT8U232AM, + FT232BM, + FT2232C, + FT232RL, + FT2232H, + FT4232H, + FT232H, + FTX, +}; struct ftdi_private { enum ftdi_chip_type chip_type; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index be1641e0408b..12bc3a82ac2c 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -153,18 +153,6 @@ * not supported by the FT8U232AM). */ -enum ftdi_chip_type { - SIO = 1, - FT8U232AM = 2, - FT232BM = 3, - FT2232C = 4, - FT232RL = 5, - FT2232H = 6, - FT4232H = 7, - FT232H = 8, - FTX = 9, -}; - enum ftdi_sio_baudrate { ftdi_sio_b300 = 0, ftdi_sio_b600 = 1, -- cgit v1.2.3 From 25eb948601dfd7128d136a8c191f6bb7a253880c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:06 +0200 Subject: USB: serial: ftdi_sio: drop redundant chip type comments Drop redundant chip type comments. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 54a79284ffd7..8355bfc6ab01 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -61,7 +61,6 @@ enum ftdi_chip_type { struct ftdi_private { enum ftdi_chip_type chip_type; - /* type of device, either SIO or FT8U232AM */ int baud_base; /* baud base clock for divisor setting */ int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the @@ -1318,7 +1317,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, if (!baud) baud = 9600; switch (priv->chip_type) { - case SIO: /* SIO chip */ + case SIO: switch (baud) { case 300: div_value = ftdi_sio_b300; break; case 600: div_value = ftdi_sio_b600; break; @@ -1338,7 +1337,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_okay = 0; } break; - case FT8U232AM: /* 8U232AM chip */ + case FT8U232AM: if (baud <= 3000000) { div_value = ftdi_232am_baud_to_divisor(baud); } else { @@ -1348,10 +1347,10 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_okay = 0; } break; - case FT232BM: /* FT232BM chip */ - case FT2232C: /* FT2232C chip */ - case FT232RL: /* FT232RL chip */ - case FTX: /* FT-X series */ + case FT232BM: + case FT2232C: + case FT232RL: + case FTX: if (baud <= 3000000) { u16 product_id = le16_to_cpu( port->serial->dev->descriptor.idProduct); @@ -1371,9 +1370,9 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, baud = 9600; } break; - case FT2232H: /* FT2232H chip */ - case FT4232H: /* FT4232H chip */ - case FT232H: /* FT232H chip */ + case FT2232H: + case FT4232H: + case FT232H: if ((baud <= 12000000) && (baud >= 1200)) { div_value = ftdi_2232h_baud_to_divisor(baud); } else if (baud < 1200) { @@ -1385,7 +1384,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, baud = 9600; } break; - } /* priv->chip_type */ + } if (div_okay) { dev_dbg(dev, "%s - Baud rate set to %d (divisor 0x%lX) on chip %s\n", -- cgit v1.2.3 From 01aeb31f3cdaa90d4827edf0b20069c5c368b371 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:07 +0200 Subject: USB: serial: ftdi_sio: rename chip types Shorten the chip type enum and string representation for A, B and R chip types so that they don't include the IC package type in the name. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 60 +++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 8355bfc6ab01..6c279d4f37bc 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -49,13 +49,13 @@ enum ftdi_chip_type { SIO, - FT8U232AM, - FT232BM, + FT232A, + FT232B, FT2232C, - FT232RL, + FT232R, + FT232H, FT2232H, FT4232H, - FT232H, FTX, }; @@ -1071,15 +1071,15 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); static const char *ftdi_chip_name[] = { - [SIO] = "SIO", /* the serial part of FT8U100AX */ - [FT8U232AM] = "FT8U232AM", - [FT232BM] = "FT232BM", - [FT2232C] = "FT2232C", - [FT232RL] = "FT232RL", - [FT2232H] = "FT2232H", - [FT4232H] = "FT4232H", - [FT232H] = "FT232H", - [FTX] = "FT-X" + [SIO] = "SIO", /* the serial part of FT8U100AX */ + [FT232A] = "FT232A", + [FT232B] = "FT232B", + [FT2232C] = "FT2232C", + [FT232R] = "FT232R", + [FT232H] = "FT232H", + [FT2232H] = "FT2232H", + [FT4232H] = "FT4232H", + [FTX] = "FT-X", }; @@ -1337,7 +1337,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_okay = 0; } break; - case FT8U232AM: + case FT232A: if (baud <= 3000000) { div_value = ftdi_232am_baud_to_divisor(baud); } else { @@ -1347,9 +1347,9 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, div_okay = 0; } break; - case FT232BM: + case FT232B: case FT2232C: - case FT232RL: + case FT232R: case FTX: if (baud <= 3000000) { u16 product_id = le16_to_cpu( @@ -1431,7 +1431,7 @@ static int write_latency_timer(struct usb_serial_port *port) int rv; int l = priv->latency; - if (priv->chip_type == SIO || priv->chip_type == FT8U232AM) + if (priv->chip_type == SIO || priv->chip_type == FT232A) return -EINVAL; if (priv->flags & ASYNC_LOW_LATENCY) @@ -1472,7 +1472,7 @@ static int read_latency_timer(struct usb_serial_port *port) struct ftdi_private *priv = usb_get_serial_port_data(port); int rv; - if (priv->chip_type == SIO || priv->chip_type == FT8U232AM) + if (priv->chip_type == SIO || priv->chip_type == FT232A) return -EINVAL; rv = _read_latency_timer(port); @@ -1603,7 +1603,7 @@ static void ftdi_determine_type(struct usb_serial_port *port) priv->baud_base = 12000000 / 16; } else if (version < 0x400) { /* Assume it's an FT8U232AM (or FT8U245AM) */ - priv->chip_type = FT8U232AM; + priv->chip_type = FT232A; /* * It might be a BM type because of the iSerialNumber bug. * If iSerialNumber==0 and the latency timer is readable, @@ -1614,14 +1614,14 @@ static void ftdi_determine_type(struct usb_serial_port *port) dev_dbg(&port->dev, "%s: has latency timer so not an AM type\n", __func__); - priv->chip_type = FT232BM; + priv->chip_type = FT232B; } } else if (version < 0x600) { /* Assume it's an FT232BM (or FT245BM) */ - priv->chip_type = FT232BM; + priv->chip_type = FT232B; } else if (version < 0x900) { /* Assume it's an FT232RL */ - priv->chip_type = FT232RL; + priv->chip_type = FT232R; } else if (version < 0x1000) { /* Assume it's an FT232H */ priv->chip_type = FT232H; @@ -1751,9 +1751,9 @@ static int create_sysfs_attrs(struct usb_serial_port *port) dev_dbg(&port->dev, "sysfs attributes for %s\n", ftdi_chip_name[priv->chip_type]); retval = device_create_file(&port->dev, &dev_attr_event_char); if ((!retval) && - (priv->chip_type == FT232BM || + (priv->chip_type == FT232B || priv->chip_type == FT2232C || - priv->chip_type == FT232RL || + priv->chip_type == FT232R || priv->chip_type == FT2232H || priv->chip_type == FT4232H || priv->chip_type == FT232H || @@ -1772,9 +1772,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232BM || + if (priv->chip_type == FT232B || priv->chip_type == FT2232C || - priv->chip_type == FT232RL || + priv->chip_type == FT232R || priv->chip_type == FT2232H || priv->chip_type == FT4232H || priv->chip_type == FT232H || @@ -2152,7 +2152,7 @@ static int ftdi_gpio_init(struct usb_serial_port *port) case FT232H: result = ftdi_gpio_init_ft232h(port); break; - case FT232RL: + case FT232R: result = ftdi_gpio_init_ft232r(port); break; case FTX: @@ -2837,10 +2837,10 @@ static int ftdi_get_modem_status(struct usb_serial_port *port, case SIO: len = 1; break; - case FT8U232AM: - case FT232BM: + case FT232A: + case FT232B: case FT2232C: - case FT232RL: + case FT232R: case FT2232H: case FT4232H: case FT232H: -- cgit v1.2.3 From 64b12fdac0ed4e3bfadef39c8f8795417bb13d9f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:08 +0200 Subject: USB: serial: ftdi_sio: include FT2232D in type string Include the updated D-version in the type string for the FT2232C type. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6c279d4f37bc..853e036bdef2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1074,7 +1074,7 @@ static const char *ftdi_chip_name[] = { [SIO] = "SIO", /* the serial part of FT8U100AX */ [FT232A] = "FT232A", [FT232B] = "FT232B", - [FT2232C] = "FT2232C", + [FT2232C] = "FT2232C/D", [FT232R] = "FT232R", [FT232H] = "FT232H", [FT2232H] = "FT2232H", -- cgit v1.2.3 From 027bf37dbe82bb6ce8aa7845f5c7653a869695cd Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:09 +0200 Subject: USB: serial: ftdi_sio: rename channel index Multi-channel devices require a channel selector to be included in control requests. Replace "interface" with the less ambiguous "channel", which is the terminology used for newer devices, in the corresponding defines and variables. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 40 +++++++++++++++++++--------------------- drivers/usb/serial/ftdi_sio.h | 10 +++++----- 2 files changed, 24 insertions(+), 26 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 853e036bdef2..0b8133d04023 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -72,8 +72,7 @@ struct ftdi_private { unsigned long last_dtr_rts; /* saved modem control outputs */ char prev_status; /* Used for TIOCMIWAIT */ char transmit_empty; /* If transmitter is empty or not */ - u16 interface; /* FT2232C, FT2232H or FT4232H port interface - (0 for FT232/245) */ + u16 channel; /* channel index, or 0 for legacy types */ speed_t force_baud; /* if non-zero, force the baud rate to this value */ @@ -1271,7 +1270,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - value, priv->interface, + value, priv->channel, NULL, 0, WDR_TIMEOUT); if (rv < 0) { dev_dbg(dev, "%s Error from MODEM_CTRL urb: DTR %s, RTS %s\n", @@ -1412,7 +1411,7 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) priv->chip_type == FTX) { /* Probably the BM type needs the MSB of the encoded fractional * divider also moved like for the chips above. Any infos? */ - index = (u16)((index << 8) | priv->interface); + index = (u16)((index << 8) | priv->channel); } rv = usb_control_msg(port->serial->dev, @@ -1443,7 +1442,7 @@ static int write_latency_timer(struct usb_serial_port *port) usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - l, priv->interface, + l, priv->channel, NULL, 0, WDR_TIMEOUT); if (rv < 0) dev_err(&port->dev, "Unable to write latency timer: %i\n", rv); @@ -1459,7 +1458,7 @@ static int _read_latency_timer(struct usb_serial_port *port) rv = usb_control_msg_recv(udev, 0, FTDI_SIO_GET_LATENCY_TIMER_REQUEST, FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0, - priv->interface, &buf, 1, WDR_TIMEOUT, + priv->channel, &buf, 1, WDR_TIMEOUT, GFP_KERNEL); if (rv == 0) rv = buf; @@ -1580,15 +1579,14 @@ static void ftdi_determine_type(struct usb_serial_port *port) } else priv->chip_type = FT2232C; - /* Determine interface code. */ if (ifnum == 0) - priv->interface = INTERFACE_A; + priv->channel = CHANNEL_A; else if (ifnum == 1) - priv->interface = INTERFACE_B; + priv->channel = CHANNEL_B; else if (ifnum == 2) - priv->interface = INTERFACE_C; + priv->channel = CHANNEL_C; else if (ifnum == 3) - priv->interface = INTERFACE_D; + priv->channel = CHANNEL_D; /* BM-type devices have a bug where bcdDevice gets set * to 0x200 when iSerialNumber is 0. */ @@ -1729,7 +1727,7 @@ static ssize_t event_char_store(struct device *dev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_EVENT_CHAR_REQUEST, FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, - v, priv->interface, + v, priv->channel, NULL, 0, WDR_TIMEOUT); if (rv < 0) { dev_dbg(&port->dev, "Unable to write event character: %i\n", rv); @@ -1803,7 +1801,7 @@ static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode) usb_sndctrlpipe(serial->dev, 0), FTDI_SIO_SET_BITMODE_REQUEST, FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val, - priv->interface, NULL, 0, WDR_TIMEOUT); + priv->channel, NULL, 0, WDR_TIMEOUT); if (result < 0) { dev_err(&serial->interface->dev, "bitmode request failed for value 0x%04x: %d\n", @@ -1867,7 +1865,7 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port) result = usb_control_msg_recv(serial->dev, 0, FTDI_SIO_READ_PINS_REQUEST, FTDI_SIO_READ_PINS_REQUEST_TYPE, 0, - priv->interface, &buf, 1, WDR_TIMEOUT, + priv->channel, &buf, 1, WDR_TIMEOUT, GFP_KERNEL); if (result == 0) result = buf; @@ -2403,7 +2401,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, - priv->interface, NULL, 0, WDR_TIMEOUT); + priv->channel, NULL, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change port->tty->termios - this would lose speed settings, etc. @@ -2426,7 +2424,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on) usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, NULL, 0, + 0, priv->channel, NULL, 0, WDR_TIMEOUT) < 0) { dev_err(&port->dev, "error from flowcontrol urb\n"); } @@ -2619,7 +2617,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state) usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - value , priv->interface, + value, priv->channel, NULL, 0, WDR_TIMEOUT) < 0) { dev_err(&port->dev, "%s FAILED to enable/disable break state (state was %d)\n", __func__, break_state); @@ -2755,7 +2753,7 @@ no_skip: if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - value , priv->interface, + value, priv->channel, NULL, 0, WDR_SHORT_TIMEOUT) < 0) { dev_err(ddev, "%s FAILED to set databits/stopbits/parity\n", __func__); @@ -2768,7 +2766,7 @@ no_data_parity_stop_changes: if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, + 0, priv->channel, NULL, 0, WDR_TIMEOUT) < 0) { dev_err(ddev, "%s error from disable flowcontrol urb\n", __func__); @@ -2802,7 +2800,7 @@ no_c_cflag_changes: index = FTDI_SIO_DISABLE_FLOW_CTRL; } - index |= priv->interface; + index |= priv->channel; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, @@ -2856,7 +2854,7 @@ static int ftdi_get_modem_status(struct usb_serial_port *port, usb_rcvctrlpipe(port->serial->dev, 0), FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, priv->interface, + 0, priv->channel, buf, len, WDR_TIMEOUT); /* NOTE: We allow short responses and handle that below. */ diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 12bc3a82ac2c..55ea61264f91 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -40,11 +40,11 @@ #define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */ #define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */ -/* Interface indices for FT2232, FT2232H and FT4232H devices */ -#define INTERFACE_A 1 -#define INTERFACE_B 2 -#define INTERFACE_C 3 -#define INTERFACE_D 4 +/* Channel indices for FT2232, FT2232H and FT4232H devices */ +#define CHANNEL_A 1 +#define CHANNEL_B 2 +#define CHANNEL_C 3 +#define CHANNEL_D 4 /* -- cgit v1.2.3 From f353c0d43006a485b999035b7cb387f76bdd7291 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:10 +0200 Subject: USB: serial: ftdi_sio: tighten device-type detection Clean up and tighten the device-type detection, which is based on bcdDevice. Don't make assumptions about unknown (future) types (currently assumed to be either FT2232C or FT-X depending on bNumInterfaces) and instead log an error and refuse to bind so that we can add proper support when needed. Note that the bcdDevice values have been provided by FTDI. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 118 ++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 63 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0b8133d04023..4d85cc7fadcb 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1546,89 +1546,73 @@ static int get_lsr_info(struct usb_serial_port *port, return 0; } - -/* Determine type of FTDI chip based on USB config and descriptor. */ -static void ftdi_determine_type(struct usb_serial_port *port) +static int ftdi_determine_type(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; struct usb_device *udev = serial->dev; - unsigned version; - unsigned interfaces; + unsigned int version, ifnum; + + version = le16_to_cpu(udev->descriptor.bcdDevice); + ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - /* Assume it is not the original SIO device for now. */ priv->baud_base = 48000000 / 2; + priv->channel = 0; - version = le16_to_cpu(udev->descriptor.bcdDevice); - interfaces = udev->actconfig->desc.bNumInterfaces; - dev_dbg(&port->dev, "%s: bcdDevice = 0x%x, bNumInterfaces = %u\n", __func__, - version, interfaces); - if (interfaces > 1) { - struct usb_interface *intf = serial->interface; - int ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - - /* Multiple interfaces.*/ - if (version == 0x0800) { - priv->chip_type = FT4232H; - /* Hi-speed - baud clock runs at 120MHz */ - priv->baud_base = 120000000 / 2; - } else if (version == 0x0700) { - priv->chip_type = FT2232H; - /* Hi-speed - baud clock runs at 120MHz */ - priv->baud_base = 120000000 / 2; - } else - priv->chip_type = FT2232C; - - if (ifnum == 0) - priv->channel = CHANNEL_A; - else if (ifnum == 1) - priv->channel = CHANNEL_B; - else if (ifnum == 2) - priv->channel = CHANNEL_C; - else if (ifnum == 3) - priv->channel = CHANNEL_D; - - /* BM-type devices have a bug where bcdDevice gets set - * to 0x200 when iSerialNumber is 0. */ - if (version < 0x500) { - dev_dbg(&port->dev, - "%s: something fishy - bcdDevice too low for multi-interface device\n", - __func__); - } - } else if (version < 0x200) { - /* Old device. Assume it's the original SIO. */ - priv->chip_type = SIO; - priv->baud_base = 12000000 / 16; - } else if (version < 0x400) { - /* Assume it's an FT8U232AM (or FT8U245AM) */ + switch (version) { + case 0x200: priv->chip_type = FT232A; + /* - * It might be a BM type because of the iSerialNumber bug. - * If iSerialNumber==0 and the latency timer is readable, - * assume it is BM type. + * FT232B devices have a bug where bcdDevice gets set to 0x200 + * when iSerialNumber is 0. Assume it is an FT232B in case the + * latency timer is readable. */ if (udev->descriptor.iSerialNumber == 0 && _read_latency_timer(port) >= 0) { - dev_dbg(&port->dev, - "%s: has latency timer so not an AM type\n", - __func__); priv->chip_type = FT232B; } - } else if (version < 0x600) { - /* Assume it's an FT232BM (or FT245BM) */ + break; + case 0x400: priv->chip_type = FT232B; - } else if (version < 0x900) { - /* Assume it's an FT232RL */ + break; + case 0x500: + priv->chip_type = FT2232C; + priv->channel = CHANNEL_A + ifnum; + break; + case 0x600: priv->chip_type = FT232R; - } else if (version < 0x1000) { - /* Assume it's an FT232H */ + break; + case 0x700: + priv->chip_type = FT2232H; + priv->channel = CHANNEL_A + ifnum; + priv->baud_base = 120000000 / 2; + break; + case 0x800: + priv->chip_type = FT4232H; + priv->channel = CHANNEL_A + ifnum; + priv->baud_base = 120000000 / 2; + break; + case 0x900: priv->chip_type = FT232H; - } else { - /* Assume it's an FT-X series device */ + priv->baud_base = 120000000 / 2; + break; + case 0x1000: priv->chip_type = FTX; + break; + default: + if (version < 0x200) { + priv->chip_type = SIO; + priv->baud_base = 12000000 / 16; + } else { + dev_err(&port->dev, "unknown device type: 0x%02x\n", version); + return -ENODEV; + } } dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]); + + return 0; } @@ -2255,7 +2239,10 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) usb_set_serial_port_data(port, priv); - ftdi_determine_type(port); + result = ftdi_determine_type(port); + if (result) + goto err_free; + ftdi_set_max_packet_size(port); if (read_latency_timer(port) < 0) priv->latency = 16; @@ -2270,6 +2257,11 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) } return 0; + +err_free: + kfree(priv); + + return result; } /* Setup for the USB-UIRT device, which requires hardwired -- cgit v1.2.3 From 6fbd91425746f1df97145da31fb2177f7915479b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:11 +0200 Subject: USB: serial: ftdi_sio: clean up modem-status handling All chip types but the original SIO (FT8U100AX) return a two-byte modem status and there's no need to explicitly list every other type in the handler. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 4d85cc7fadcb..eecd4b13a5ec 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2820,27 +2820,13 @@ static int ftdi_get_modem_status(struct usb_serial_port *port, if (!buf) return -ENOMEM; /* - * The 8U232AM returns a two byte value (the SIO a 1 byte value) in - * the same format as the data returned from the in point. + * The device returns a two byte value (the SIO a 1 byte value) in the + * same format as the data returned from the IN endpoint. */ - switch (priv->chip_type) { - case SIO: + if (priv->chip_type == SIO) len = 1; - break; - case FT232A: - case FT232B: - case FT2232C: - case FT232R: - case FT2232H: - case FT4232H: - case FT232H: - case FTX: + else len = 2; - break; - default: - ret = -EFAULT; - goto out; - } ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), -- cgit v1.2.3 From 4d045b98fb7460026ac7aefe5418fff3b9d04f14 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:12 +0200 Subject: USB: serial: ftdi_sio: clean up attribute handling The driver exposes two attributes for all chip types but FT232A, which doesn't have a configurable latency timer, and SIO, which (probably) doesn't support the event-char mechanism either. Explicitly test for the exceptions rather than list each and every supported device type in the attribute helpers. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 47 +++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index eecd4b13a5ec..05c635e3cb30 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1725,46 +1725,31 @@ static DEVICE_ATTR_WO(event_char); static int create_sysfs_attrs(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - int retval = 0; - - /* XXX I've no idea if the original SIO supports the event_char - * sysfs parameter, so I'm playing it safe. */ - if (priv->chip_type != SIO) { - dev_dbg(&port->dev, "sysfs attributes for %s\n", ftdi_chip_name[priv->chip_type]); - retval = device_create_file(&port->dev, &dev_attr_event_char); - if ((!retval) && - (priv->chip_type == FT232B || - priv->chip_type == FT2232C || - priv->chip_type == FT232R || - priv->chip_type == FT2232H || - priv->chip_type == FT4232H || - priv->chip_type == FT232H || - priv->chip_type == FTX)) { - retval = device_create_file(&port->dev, - &dev_attr_latency_timer); - } + enum ftdi_chip_type type = priv->chip_type; + int ret = 0; + + if (type != SIO) { + ret = device_create_file(&port->dev, &dev_attr_event_char); + if (ret) + return ret; } - return retval; + + if (type != SIO && type != FT232A) + ret = device_create_file(&port->dev, &dev_attr_latency_timer); + + return ret; } static void remove_sysfs_attrs(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); + enum ftdi_chip_type type = priv->chip_type; - /* XXX see create_sysfs_attrs */ - if (priv->chip_type != SIO) { + if (type != SIO) device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232B || - priv->chip_type == FT2232C || - priv->chip_type == FT232R || - priv->chip_type == FT2232H || - priv->chip_type == FT4232H || - priv->chip_type == FT232H || - priv->chip_type == FTX) { - device_remove_file(&port->dev, &dev_attr_latency_timer); - } - } + if (type != SIO && type != FT232A) + device_remove_file(&port->dev, &dev_attr_latency_timer); } #ifdef CONFIG_GPIOLIB -- cgit v1.2.3 From a146cc4d4671e938bbfee414c29f589d4a148cbe Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:13 +0200 Subject: USB: serial: ftdi_sio: clean up baudrate request Multi-channel devices need to encode the channel selector in their control requests and newer single-channel chip types use the same request format. Set the channel index also for these single-channel types so that the index can be used to determine the baudrate request format instead of listing types explicitly. Note that FT232H and FTX accept either 0 or 1 as selector for their single channel, presumably for backward compatibility reasons. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 05c635e3cb30..af0ed7f954ec 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1406,13 +1406,8 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) index_value = get_ftdi_divisor(tty, port); value = (u16)index_value; index = (u16)(index_value >> 16); - if (priv->chip_type == FT2232C || priv->chip_type == FT2232H || - priv->chip_type == FT4232H || priv->chip_type == FT232H || - priv->chip_type == FTX) { - /* Probably the BM type needs the MSB of the encoded fractional - * divider also moved like for the chips above. Any infos? */ + if (priv->channel) index = (u16)((index << 8) | priv->channel); - } rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), @@ -1595,10 +1590,12 @@ static int ftdi_determine_type(struct usb_serial_port *port) break; case 0x900: priv->chip_type = FT232H; + priv->channel = CHANNEL_A + ifnum; priv->baud_base = 120000000 / 2; break; case 0x1000: priv->chip_type = FTX; + priv->channel = CHANNEL_A + ifnum; break; default: if (version < 0x200) { -- cgit v1.2.3 From 4d50f4fc67d6e903266ff3769d655729a070d490 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:14 +0200 Subject: USB: serial: ftdi_sio: assume hi-speed type In preparation for adding further Hi-Speed types, assume a 120 MHz clock and set the channel index by default and instead override these values as needed for legacy types. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index af0ed7f954ec..40343ab0ef03 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1551,13 +1551,15 @@ static int ftdi_determine_type(struct usb_serial_port *port) version = le16_to_cpu(udev->descriptor.bcdDevice); ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - priv->baud_base = 48000000 / 2; - priv->channel = 0; + /* Assume Hi-Speed type */ + priv->baud_base = 120000000 / 2; + priv->channel = CHANNEL_A + ifnum; switch (version) { case 0x200: priv->chip_type = FT232A; - + priv->baud_base = 48000000 / 2; + priv->channel = 0; /* * FT232B devices have a bug where bcdDevice gets set to 0x200 * when iSerialNumber is 0. Assume it is an FT232B in case the @@ -1570,37 +1572,36 @@ static int ftdi_determine_type(struct usb_serial_port *port) break; case 0x400: priv->chip_type = FT232B; + priv->baud_base = 48000000 / 2; + priv->channel = 0; break; case 0x500: priv->chip_type = FT2232C; - priv->channel = CHANNEL_A + ifnum; + priv->baud_base = 48000000 / 2; break; case 0x600: priv->chip_type = FT232R; + priv->baud_base = 48000000 / 2; + priv->channel = 0; break; case 0x700: priv->chip_type = FT2232H; - priv->channel = CHANNEL_A + ifnum; - priv->baud_base = 120000000 / 2; break; case 0x800: priv->chip_type = FT4232H; - priv->channel = CHANNEL_A + ifnum; - priv->baud_base = 120000000 / 2; break; case 0x900: priv->chip_type = FT232H; - priv->channel = CHANNEL_A + ifnum; - priv->baud_base = 120000000 / 2; break; case 0x1000: priv->chip_type = FTX; - priv->channel = CHANNEL_A + ifnum; + priv->baud_base = 48000000 / 2; break; default: if (version < 0x200) { priv->chip_type = SIO; priv->baud_base = 12000000 / 16; + priv->channel = 0; } else { dev_err(&port->dev, "unknown device type: 0x%02x\n", version); return -ENODEV; -- cgit v1.2.3 From 1a0398915d2243fc14be6506a6d226e0593a1c33 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 11 Sep 2022 16:02:15 +0200 Subject: USB: serial: ftdi_sio: simplify divisor handling In preparation for adding further Hi-Speed types, assume the device type is Hi-Speed unless it's an explicitly listed legacy type when determining divisors. Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 40343ab0ef03..79069c0fb587 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1369,9 +1369,7 @@ static u32 get_ftdi_divisor(struct tty_struct *tty, baud = 9600; } break; - case FT2232H: - case FT4232H: - case FT232H: + default: if ((baud <= 12000000) && (baud >= 1200)) { div_value = ftdi_2232h_baud_to_divisor(baud); } else if (baud < 1200) { -- cgit v1.2.3 From cfebcd53e65ec6f932f202fc9769da9e13fa0792 Mon Sep 17 00:00:00 2001 From: Amireddy mallikarjuna reddy Date: Sun, 11 Sep 2022 16:02:16 +0200 Subject: USB: serial: ftdi_sio: add support for HP and HA devices Add the product IDs for the USB-to-Serial devices FT2233HP, FT2232HP, FT4233HP, FT4232HP, FT233HP, FT232HP, and FT4232HA. Also include BCD values so that the chip type can be determined. Signed-off-by: Amireddy mallikarjuna reddy Link: https://lore.kernel.org/r/ac28f2c5eba23a645b3b9299c224f2755a233eef.1658385786.git.mallikarjuna.reddy@ftdichip.com [ johan: rebase on type-handling rework, drop "Q" from automotive type name ] Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 42 +++++++++++++++++++++++++++++++++++++++ drivers/usb/serial/ftdi_sio_ids.h | 7 +++++++ 2 files changed, 49 insertions(+) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 79069c0fb587..1d6190504d89 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -56,6 +56,13 @@ enum ftdi_chip_type { FT232H, FT2232H, FT4232H, + FT4232HA, + FT232HP, + FT233HP, + FT2232HP, + FT2233HP, + FT4232HP, + FT4233HP, FTX, }; @@ -189,6 +196,13 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT2233HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT4233HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT2232HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT4232HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT233HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT232HP_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FT4232HA_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, @@ -1078,6 +1092,13 @@ static const char *ftdi_chip_name[] = { [FT232H] = "FT232H", [FT2232H] = "FT2232H", [FT4232H] = "FT4232H", + [FT4232HA] = "FT4232HA", + [FT232HP] = "FT232HP", + [FT233HP] = "FT233HP", + [FT2232HP] = "FT2232HP", + [FT2233HP] = "FT2233HP", + [FT4232HP] = "FT4232HP", + [FT4233HP] = "FT4233HP", [FTX] = "FT-X", }; @@ -1595,6 +1616,27 @@ static int ftdi_determine_type(struct usb_serial_port *port) priv->chip_type = FTX; priv->baud_base = 48000000 / 2; break; + case 0x2800: + priv->chip_type = FT2233HP; + break; + case 0x2900: + priv->chip_type = FT4233HP; + break; + case 0x3000: + priv->chip_type = FT2232HP; + break; + case 0x3100: + priv->chip_type = FT4232HP; + break; + case 0x3200: + priv->chip_type = FT233HP; + break; + case 0x3300: + priv->chip_type = FT232HP; + break; + case 0x3600: + priv->chip_type = FT4232HA; + break; default: if (version < 0x200) { priv->chip_type = SIO; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 31c8ccabbbb7..e2099445db70 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -25,6 +25,13 @@ #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ #define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ #define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */ +#define FTDI_FT2233HP_PID 0x6040 /* Dual channel hi-speed device with PD */ +#define FTDI_FT4233HP_PID 0x6041 /* Quad channel hi-speed device with PD */ +#define FTDI_FT2232HP_PID 0x6042 /* Dual channel hi-speed device with PD */ +#define FTDI_FT4232HP_PID 0x6043 /* Quad channel hi-speed device with PD */ +#define FTDI_FT233HP_PID 0x6044 /* Dual channel hi-speed device with PD */ +#define FTDI_FT232HP_PID 0x6045 /* Dual channel hi-speed device with PD */ +#define FTDI_FT4232HA_PID 0x6048 /* Quad channel automotive grade hi-speed device */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ -- cgit v1.2.3 From 0f6632e2e8beb6a1e0895c1309dd0b84b805c202 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Wed, 14 Sep 2022 15:13:34 +0800 Subject: USB: serial: ftdi_sio: convert to use dev_groups The driver core supports the ability to handle the creation and removal of device-specific sysfs files in a race-free manner. Signed-off-by: Jiasheng Jiang [ johan: rebase on type rework, make groups static, clean up, amend commit message ] Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 49 ++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1d6190504d89..147b5e80595a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1140,10 +1140,13 @@ static u32 ftdi_232bm_baud_to_divisor(int baud); static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base); static u32 ftdi_2232h_baud_to_divisor(int baud); +static const struct attribute_group *ftdi_groups[]; + static struct usb_serial_driver ftdi_sio_device = { .driver = { .owner = THIS_MODULE, .name = "ftdi_sio", + .dev_groups = ftdi_groups, }, .description = "FTDI USB Serial Device", .id_table = id_table_combined, @@ -1760,35 +1763,42 @@ static ssize_t event_char_store(struct device *dev, } static DEVICE_ATTR_WO(event_char); -static int create_sysfs_attrs(struct usb_serial_port *port) +static struct attribute *ftdi_attrs[] = { + &dev_attr_event_char.attr, + &dev_attr_latency_timer.attr, + NULL +}; + +static umode_t ftdi_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { + struct device *dev = kobj_to_dev(kobj); + struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); enum ftdi_chip_type type = priv->chip_type; - int ret = 0; + umode_t mode = attr->mode; if (type != SIO) { - ret = device_create_file(&port->dev, &dev_attr_event_char); - if (ret) - return ret; + if (attr == &dev_attr_event_char.attr) + return mode; } - if (type != SIO && type != FT232A) - ret = device_create_file(&port->dev, &dev_attr_latency_timer); + if (type != SIO && type != FT232A) { + if (attr == &dev_attr_latency_timer.attr) + return mode; + } - return ret; + return 0; } -static void remove_sysfs_attrs(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - enum ftdi_chip_type type = priv->chip_type; - - if (type != SIO) - device_remove_file(&port->dev, &dev_attr_event_char); +static const struct attribute_group ftdi_group = { + .attrs = ftdi_attrs, + .is_visible = ftdi_is_visible, +}; - if (type != SIO && type != FT232A) - device_remove_file(&port->dev, &dev_attr_latency_timer); -} +static const struct attribute_group *ftdi_groups[] = { + &ftdi_group, + NULL +}; #ifdef CONFIG_GPIOLIB @@ -2270,7 +2280,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) if (read_latency_timer(port) < 0) priv->latency = 16; write_latency_timer(port); - create_sysfs_attrs(port); result = ftdi_gpio_init(port); if (result < 0) { @@ -2401,8 +2410,6 @@ static void ftdi_sio_port_remove(struct usb_serial_port *port) ftdi_gpio_remove(port); - remove_sysfs_attrs(port); - kfree(priv); } -- cgit v1.2.3 From 61dfa797c731754642d1ac500a6ac42f9b47f920 Mon Sep 17 00:00:00 2001 From: Liang He Date: Mon, 19 Sep 2022 18:48:24 +0800 Subject: USB: serial: console: move mutex_unlock() before usb_serial_put() While in current version there is no use-after-free as USB serial core holds another reference when the console is registered, we should better unlock before dropping the reference in usb_console_setup(). Fixes: 7bd032dc2793 ("USB serial: update the console driver") Signed-off-by: Liang He Signed-off-by: Johan Hovold --- drivers/usb/serial/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index b97aa40ca4d1..da19a5fa414f 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -189,8 +189,8 @@ static int usb_console_setup(struct console *co, char *options) info->port = NULL; usb_autopm_put_interface(serial->interface); error_get_interface: - usb_serial_put(serial); mutex_unlock(&serial->disc_mutex); + usb_serial_put(serial); return retval; } -- cgit v1.2.3 From c142bdc5c7207018efa1928317b1e708eda05e09 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 19 Sep 2022 15:24:54 +0200 Subject: USB: serial: ftdi_sio: clean up attribute visibility logic Clean up the attribute visibility logic by defaulting to attributes being visible and explicitly listing the exceptions. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 147b5e80595a..a5fc199cde0b 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1775,19 +1775,18 @@ static umode_t ftdi_is_visible(struct kobject *kobj, struct attribute *attr, int struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); enum ftdi_chip_type type = priv->chip_type; - umode_t mode = attr->mode; - if (type != SIO) { - if (attr == &dev_attr_event_char.attr) - return mode; + if (attr == &dev_attr_event_char.attr) { + if (type == SIO) + return 0; } - if (type != SIO && type != FT232A) { - if (attr == &dev_attr_latency_timer.attr) - return mode; + if (attr == &dev_attr_latency_timer.attr) { + if (type == SIO || type == FT232A) + return 0; } - return 0; + return attr->mode; } static const struct attribute_group ftdi_group = { -- cgit v1.2.3 From a8619505a7780e30db259e01a643eca621e963d3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 19 Sep 2022 15:24:55 +0200 Subject: USB: serial: ftdi_sio: move driver structure Move the definition of the USB serial driver structure to the end of the file where it is used and drop the now redundant forward declarations. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 101 +++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 66 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a5fc199cde0b..dbca7ae354dd 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1108,77 +1108,11 @@ static const char *ftdi_chip_name[] = { #define FTDI_STATUS_B1_MASK (FTDI_RS_BI) /* End TIOCMIWAIT */ -/* function prototypes for a FTDI serial converter */ -static int ftdi_sio_probe(struct usb_serial *serial, - const struct usb_device_id *id); -static int ftdi_sio_port_probe(struct usb_serial_port *port); -static void ftdi_sio_port_remove(struct usb_serial_port *port); -static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ftdi_dtr_rts(struct usb_serial_port *port, int on); -static void ftdi_process_read_urb(struct urb *urb); -static int ftdi_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); static void ftdi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); -static int ftdi_tiocmget(struct tty_struct *tty); -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 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); -static bool ftdi_tx_empty(struct usb_serial_port *port); static int ftdi_get_modem_status(struct usb_serial_port *port, unsigned char status[2]); -static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); -static unsigned short int ftdi_232am_baud_to_divisor(int baud); -static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base); -static u32 ftdi_232bm_baud_to_divisor(int baud); -static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base); -static u32 ftdi_2232h_baud_to_divisor(int baud); - -static const struct attribute_group *ftdi_groups[]; - -static struct usb_serial_driver ftdi_sio_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ftdi_sio", - .dev_groups = ftdi_groups, - }, - .description = "FTDI USB Serial Device", - .id_table = id_table_combined, - .num_ports = 1, - .bulk_in_size = 512, - .bulk_out_size = 256, - .probe = ftdi_sio_probe, - .port_probe = ftdi_sio_port_probe, - .port_remove = ftdi_sio_port_remove, - .open = ftdi_open, - .dtr_rts = ftdi_dtr_rts, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .process_read_urb = ftdi_process_read_urb, - .prepare_write_buffer = ftdi_prepare_write_buffer, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .ioctl = ftdi_ioctl, - .get_serial = get_serial_info, - .set_serial = set_serial_info, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, - .tx_empty = ftdi_tx_empty, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ftdi_sio_device, NULL -}; - - #define WDR_TIMEOUT 5000 /* default urb timeout */ #define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ @@ -2931,6 +2865,41 @@ static int ftdi_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +static struct usb_serial_driver ftdi_sio_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ftdi_sio", + .dev_groups = ftdi_groups, + }, + .description = "FTDI USB Serial Device", + .id_table = id_table_combined, + .num_ports = 1, + .bulk_in_size = 512, + .bulk_out_size = 256, + .probe = ftdi_sio_probe, + .port_probe = ftdi_sio_port_probe, + .port_remove = ftdi_sio_port_remove, + .open = ftdi_open, + .dtr_rts = ftdi_dtr_rts, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, + .process_read_urb = ftdi_process_read_urb, + .prepare_write_buffer = ftdi_prepare_write_buffer, + .tiocmget = ftdi_tiocmget, + .tiocmset = ftdi_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .ioctl = ftdi_ioctl, + .get_serial = get_serial_info, + .set_serial = set_serial_info, + .set_termios = ftdi_set_termios, + .break_ctl = ftdi_break_ctl, + .tx_empty = ftdi_tx_empty, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &ftdi_sio_device, NULL +}; module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); -- cgit v1.2.3 From 6b2fe3df7c0ca3cf9ee9cea4470462fa708baf87 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 19 Sep 2022 15:24:56 +0200 Subject: USB: serial: ftdi_sio: clean up driver prefix Drop the "sio" infix from the few remaining definitions and symbol names that still had it. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index dbca7ae354dd..31b9b36f3a1c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -100,8 +100,7 @@ struct ftdi_private { #endif }; -/* struct ftdi_sio_quirk is used by devices requiring special attention. */ -struct ftdi_sio_quirk { +struct ftdi_quirk { int (*probe)(struct usb_serial *); /* Special settings for probed ports. */ void (*port_probe)(struct ftdi_private *); @@ -114,27 +113,27 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial); static void ftdi_USB_UIRT_setup(struct ftdi_private *priv); static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv); -static const struct ftdi_sio_quirk ftdi_jtag_quirk = { +static const struct ftdi_quirk ftdi_jtag_quirk = { .probe = ftdi_jtag_probe, }; -static const struct ftdi_sio_quirk ftdi_NDI_device_quirk = { +static const struct ftdi_quirk ftdi_NDI_device_quirk = { .probe = ftdi_NDI_device_setup, }; -static const struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { +static const struct ftdi_quirk ftdi_USB_UIRT_quirk = { .port_probe = ftdi_USB_UIRT_setup, }; -static const struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { +static const struct ftdi_quirk ftdi_HE_TIRA1_quirk = { .port_probe = ftdi_HE_TIRA1_setup, }; -static const struct ftdi_sio_quirk ftdi_stmclite_quirk = { +static const struct ftdi_quirk ftdi_stmclite_quirk = { .probe = ftdi_stmclite_probe, }; -static const struct ftdi_sio_quirk ftdi_8u2232c_quirk = { +static const struct ftdi_quirk ftdi_8u2232c_quirk = { .probe = ftdi_8u2232c_probe, }; @@ -2170,12 +2169,9 @@ static void ftdi_gpio_remove(struct usb_serial_port *port) { } * *************************************************************************** */ -/* Probe function to check for special devices */ -static int ftdi_sio_probe(struct usb_serial *serial, - const struct usb_device_id *id) +static int ftdi_probe(struct usb_serial *serial, const struct usb_device_id *id) { - const struct ftdi_sio_quirk *quirk = - (struct ftdi_sio_quirk *)id->driver_info; + const struct ftdi_quirk *quirk = (struct ftdi_quirk *)id->driver_info; if (quirk && quirk->probe) { int ret = quirk->probe(serial); @@ -2188,10 +2184,10 @@ static int ftdi_sio_probe(struct usb_serial *serial, return 0; } -static int ftdi_sio_port_probe(struct usb_serial_port *port) +static int ftdi_port_probe(struct usb_serial_port *port) { + const struct ftdi_quirk *quirk = usb_get_serial_data(port->serial); struct ftdi_private *priv; - const struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); int result; priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); @@ -2337,7 +2333,7 @@ static int ftdi_stmclite_probe(struct usb_serial *serial) return 0; } -static void ftdi_sio_port_remove(struct usb_serial_port *port) +static void ftdi_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); @@ -2865,7 +2861,7 @@ static int ftdi_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } -static struct usb_serial_driver ftdi_sio_device = { +static struct usb_serial_driver ftdi_device = { .driver = { .owner = THIS_MODULE, .name = "ftdi_sio", @@ -2876,9 +2872,9 @@ static struct usb_serial_driver ftdi_sio_device = { .num_ports = 1, .bulk_in_size = 512, .bulk_out_size = 256, - .probe = ftdi_sio_probe, - .port_probe = ftdi_sio_port_probe, - .port_remove = ftdi_sio_port_remove, + .probe = ftdi_probe, + .port_probe = ftdi_port_probe, + .port_remove = ftdi_port_remove, .open = ftdi_open, .dtr_rts = ftdi_dtr_rts, .throttle = usb_serial_generic_throttle, @@ -2898,7 +2894,7 @@ static struct usb_serial_driver ftdi_sio_device = { }; static struct usb_serial_driver * const serial_drivers[] = { - &ftdi_sio_device, NULL + &ftdi_device, NULL }; module_usb_serial_driver(serial_drivers, id_table_combined); -- cgit v1.2.3 From eee48781ea199e32c1d0c4732641c494833788ca Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Mon, 26 Sep 2022 17:07:39 +0200 Subject: USB: serial: qcserial: add new usb-id for Dell branded EM7455 Add support for Dell 5811e (EM7455) with USB-id 0x413c:0x81c2. Signed-off-by: Frank Wunderlich Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/qcserial.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/serial') diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 586ef5551e76..b1e844bf31f8 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -177,6 +177,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x413c, 0x81b3)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */ {DEVICE_SWI(0x413c, 0x81b5)}, /* Dell Wireless 5811e QDL */ {DEVICE_SWI(0x413c, 0x81b6)}, /* Dell Wireless 5811e QDL */ + {DEVICE_SWI(0x413c, 0x81c2)}, /* Dell Wireless 5811e */ {DEVICE_SWI(0x413c, 0x81cb)}, /* Dell Wireless 5816e QDL */ {DEVICE_SWI(0x413c, 0x81cc)}, /* Dell Wireless 5816e */ {DEVICE_SWI(0x413c, 0x81cf)}, /* Dell Wireless 5819 */ -- cgit v1.2.3