Skip to contentSkip to conversation

USB: serial: ftdi_sio: type cleanup and HP/HA support

PATCH New Johan Hovold 1 participant 13 messages Sep 11, 2022

Subsystems (2)
lore
Share & tools
lore
author maintainer
#6 lore raw

PATCH 6/12 USB: serial: ftdi_sio: tighten device-type detection

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 118 ++++++++++++++++------------------
 1 file changed, 55 insertions(+), 63 deletions(-)
drivers/usb/serial/ftdi_sio.c +55 -63
index 707dc3d67a19..f372f55a1bdf 100644
@@ -1547,89 +1547,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;
 }
 
 
@@ -2256,7 +2240,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;
@@ -2271,6 +2258,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
Signature · 1 line
2.35.1
author maintainer
#5 lore raw

PATCH 5/12 USB: serial: ftdi_sio: rename channel index

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 40 +++++++++++++++++------------------
 drivers/usb/serial/ftdi_sio.h | 10 ++++-----
 2 files changed, 24 insertions(+), 26 deletions(-)
drivers/usb/serial/ftdi_sio.c +19 -21
index cd3cdecc5f90..707dc3d67a19 100644
@@ -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",
@@ -1413,7 +1412,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,
@@ -1444,7 +1443,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);
@@ -1460,7 +1459,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;
@@ -1581,15 +1580,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.  */
@@ -1730,7 +1728,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);
@@ -1804,7 +1802,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",
@@ -1868,7 +1866,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;
@@ -2404,7 +2402,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.
@@ -2427,7 +2425,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");
 		}
@@ -2620,7 +2618,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);
@@ -2756,7 +2754,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
 	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__);
@@ -2769,7 +2767,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
 		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__);
@@ -2803,7 +2801,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
 		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,
@@ -2857,7 +2855,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. */
drivers/usb/serial/ftdi_sio.h +5 -5
index 12bc3a82ac2c..55ea61264f91 100644
@@ -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
 
 
 /*
Signature · 1 line
2.35.1
author maintainer
#8 lore raw

PATCH 8/12 USB: serial: ftdi_sio: clean up attribute handling

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 47 ++++++++++++-----------------------
 1 file changed, 16 insertions(+), 31 deletions(-)
drivers/usb/serial/ftdi_sio.c +16 -31
index 58e0acb211df..835e12fc971a 100644
@@ -1726,46 +1726,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
Signature · 1 line
2.35.1
author maintainer
#11 lore raw

PATCH 11/12 USB: serial: ftdi_sio: simplify divisor handling

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/usb/serial/ftdi_sio.c +1 -3
index a43101000ee3..e9f508e31876 100644
@@ -1370,9 +1370,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) {
Signature · 1 line
2.35.1
author maintainer
#9 lore raw

PATCH 9/12 USB: serial: ftdi_sio: clean up baudrate request

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
drivers/usb/serial/ftdi_sio.c +3 -6
index 835e12fc971a..e772aacae562 100644
@@ -1407,13 +1407,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),
@@ -1596,10 +1591,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) {
Signature · 1 line
2.35.1
author maintainer
#1 lore raw

PATCH 1/12 USB: serial: ftdi_sio: clean up chip type enum

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 11 +++++++++++
 drivers/usb/serial/ftdi_sio.h | 12 ------------
 2 files changed, 11 insertions(+), 12 deletions(-)
drivers/usb/serial/ftdi_sio.c +11 -0
index 52d59be92034..3757931284cb 100644
@@ -47,6 +47,17 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <[email protected]>, Bill Ryder <[email protected]>, Kuba Ober <[email protected]>, Andreas Mohr, Johan Hovold <[email protected]>"
 #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;
drivers/usb/serial/ftdi_sio.h +0 -12
index be1641e0408b..12bc3a82ac2c 100644
@@ -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,
Signature · 1 line
2.35.1

Johan Hovold

author maintainer
#0 lore raw

cover USB: serial: ftdi_sio: type cleanup and HP/HA support

I finally got around to completing the clean up of the ftdi_sio device type handling which I started years ago but never to around to finishing.

A recent patch from FTDI adding support for further device types has been rebased on top.

Johan

Amireddy mallikarjuna reddy (1):
USB: serial: ftdi_sio: add support for HP and HA devices

Johan Hovold (11):
USB: serial: ftdi_sio: clean up chip type enum
USB: serial: ftdi_sio: drop redundant chip type comments
USB: serial: ftdi_sio: rename chip types
USB: serial: ftdi_sio: include FT2232D in type string
USB: serial: ftdi_sio: rename channel index
USB: serial: ftdi_sio: tighten device-type detection
USB: serial: ftdi_sio: clean up modem-status handling
USB: serial: ftdi_sio: clean up attribute handling
USB: serial: ftdi_sio: clean up baudrate request
USB: serial: ftdi_sio: assume hi-speed type
USB: serial: ftdi_sio: simplify divisor handling

 drivers/usb/serial/ftdi_sio.c     | 335 +++++++++++++++---------------
 drivers/usb/serial/ftdi_sio.h     |  22 +-
 drivers/usb/serial/ftdi_sio_ids.h |   7 +
 3 files changed, 184 insertions(+), 180 deletions(-)
Signature · 1 line
2.35.1
author maintainer
#4 lore raw

PATCH 4/12 USB: serial: ftdi_sio: include FT2232D in type string

Include the updated D-version in the type string for the FT2232C type.

---
 drivers/usb/serial/ftdi_sio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/serial/ftdi_sio.c +1 -1
index b4db6a4ea223..cd3cdecc5f90 100644
@@ -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",
Signature · 1 line
2.35.1
author maintainer
#2 lore raw

PATCH 2/12 USB: serial: ftdi_sio: drop redundant chip type comments

In reply to Johan Hovold

Drop redundant chip type comments.

---
 drivers/usb/serial/ftdi_sio.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)
drivers/usb/serial/ftdi_sio.c +10 -11
index 3757931284cb..4b432707d75b 100644
@@ -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;
@@ -1339,7 +1338,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 {
@@ -1349,10 +1348,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);
@@ -1372,9 +1371,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) {
@@ -1386,7 +1385,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",
Signature · 1 line
2.35.1
author maintainer
#3 lore raw

PATCH 3/12 USB: serial: ftdi_sio: rename chip types

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 60 +++++++++++++++++------------------
 1 file changed, 30 insertions(+), 30 deletions(-)
drivers/usb/serial/ftdi_sio.c +30 -30
index 4b432707d75b..b4db6a4ea223 100644
@@ -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",
 };
 
 
@@ -1338,7 +1338,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 {
@@ -1348,9 +1348,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(
@@ -1432,7 +1432,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)
@@ -1473,7 +1473,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);
@@ -1604,7 +1604,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,
@@ -1615,14 +1615,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;
@@ -1752,9 +1752,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 ||
@@ -1773,9 +1773,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 ||
@@ -2153,7 +2153,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:
@@ -2838,10 +2838,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:
Signature · 1 line
2.35.1
author maintainer
#7 lore raw

PATCH 7/12 USB: serial: ftdi_sio: clean up modem-status handling

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 22 ++++------------------
 1 file changed, 4 insertions(+), 18 deletions(-)
drivers/usb/serial/ftdi_sio.c +4 -18
index f372f55a1bdf..58e0acb211df 100644
@@ -2821,27 +2821,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),
Signature · 1 line
2.35.1
author maintainer
#10 lore raw

PATCH 10/12 USB: serial: ftdi_sio: assume hi-speed type

In reply to Johan Hovold

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.

---
 drivers/usb/serial/ftdi_sio.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/usb/serial/ftdi_sio.c +12 -11
index e772aacae562..a43101000ee3 100644
@@ -1552,13 +1552,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
@@ -1571,37 +1573,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;
Signature · 1 line
2.35.1
author maintainer
#12 lore raw

PATCH 12/12 USB: serial: ftdi_sio: add support for HP and HA devices

In reply to Johan Hovold

From: Amireddy mallikarjuna reddy <[email protected]>

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.

[ johan: rebase on type-handling rework, drop "Q" from automotive type
name ]

---
 drivers/usb/serial/ftdi_sio.c     | 42 +++++++++++++++++++++++++++++++
 drivers/usb/serial/ftdi_sio_ids.h |  7 ++++++
 2 files changed, 49 insertions(+)
drivers/usb/serial/ftdi_sio.c +42 -0
index e9f508e31876..c1e707555fe0 100644
@@ -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",
 };
 
@@ -1596,6 +1617,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;
drivers/usb/serial/ftdi_sio_ids.h +7 -0
index 31c8ccabbbb7..e2099445db70 100644
@@ -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 */
 
Signature · 1 line
2.35.1