changeset 0:713fe1e8df41

initial import of formal patches from freecalypso-hwlab repo
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 11 Dec 2023 05:55:17 +0000
parents
children f7a2cd285016
files 4.4.14/0001-USB-serial-ftdi_sio-add-support-for-FreeCalypso-JTAG.patch 4.4.14/0002-USB-serial-ftdi_sio-pass-port-to-quirk-port_probe-fu.patch 4.4.14/0003-USB-serial-ftdi_sio-add-support-for-FreeCalypso-DUAR.patch 4.4.240/0002-USB-serial-ftdi_sio-pass-port-to-quirk-port_probe-fu.patch 4.4.240/0003-USB-serial-ftdi_sio-add-support-for-FreeCalypso-DUAR.patch 4.9.240/0002-USB-serial-ftdi_sio-pass-port-to-quirk-port_probe-fu.patch 4.9.240/0003-USB-serial-ftdi_sio-add-support-for-FreeCalypso-DUAR.patch
diffstat 7 files changed, 822 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4.4.14/0001-USB-serial-ftdi_sio-add-support-for-FreeCalypso-JTAG.patch	Mon Dec 11 05:55:17 2023 +0000
@@ -0,0 +1,78 @@
+From 5af8e2ad7d0295d90cb2bc566f3d935668fb0535 Mon Sep 17 00:00:00 2001
+From: "Mychaela N. Falconia" <falcon@freecalypso.org>
+Date: Wed, 16 Sep 2020 01:56:29 +0000
+Subject: [PATCH 1/3] USB: serial: ftdi_sio: add support for FreeCalypso
+ JTAG+UART adapters
+
+commit 6cf87e5edd9944e1d3b6efd966ea401effc304ee upstream.
+
+There exist many FT2232-based JTAG+UART adapter designs in which
+FT2232 Channel A is used for JTAG and Channel B is used for UART.
+The best way to handle them in Linux is to have the ftdi_sio driver
+create a ttyUSB device only for Channel B and not for Channel A:
+a ttyUSB device for Channel A would be bogus and will disappear as
+soon as the user runs OpenOCD or other applications that access
+Channel A for JTAG from userspace, causing undesirable noise for
+users.  The ftdi_sio driver already has a dedicated quirk for such
+JTAG+UART FT2232 adapters, and it requires assigning custom USB IDs
+to such adapters and adding these IDs to the driver with the
+ftdi_jtag_quirk applied.
+
+Boutique hardware manufacturer Falconia Partners LLC has created a
+couple of JTAG+UART adapter designs (one buffered, one unbuffered)
+as part of FreeCalypso project, and this hardware is specifically made
+to be used with Linux hosts, with the intent that Channel A will be
+accessed only from userspace via appropriate applications, and that
+Channel B will be supported by the ftdi_sio kernel driver, presenting
+a standard ttyUSB device to userspace.  Toward this end the hardware
+manufacturer will be programming FT2232 EEPROMs with custom USB IDs,
+specifically with the intent that these IDs will be recognized by
+the ftdi_sio driver with the ftdi_jtag_quirk applied.
+
+Signed-off-by: Mychaela N. Falconia <falcon@freecalypso.org>
+[johan: insert in PID order and drop unused define]
+Cc: stable@vger.kernel.org
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/ftdi_sio.c     | 5 +++++
+ drivers/usb/serial/ftdi_sio_ids.h | 7 +++++++
+ 2 files changed, 12 insertions(+)
+
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index b61f12160d37..984a93c38365 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -1008,6 +1008,11 @@ static const struct usb_device_id id_table_combined[] = {
+ 	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7560U_PID) },
+ 	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
+ 	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7563U_PID) },
++	/* FreeCalypso USB adapters */
++	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_BUF_PID),
++		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
++	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID),
++		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ 	{ }					/* Terminating entry */
+ };
+ 
+diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
+index c5d6c1e73e8e..6218f9c45016 100644
+--- a/drivers/usb/serial/ftdi_sio_ids.h
++++ b/drivers/usb/serial/ftdi_sio_ids.h
+@@ -38,6 +38,13 @@
+ 
+ #define FTDI_LUMEL_PD12_PID	0x6002
+ 
++/*
++ * Custom USB adapters made by Falconia Partners LLC
++ * for FreeCalypso project, ID codes allocated to Falconia by FTDI.
++ */
++#define FTDI_FALCONIA_JTAG_BUF_PID	0x7150
++#define FTDI_FALCONIA_JTAG_UNBUF_PID	0x7151
++
+ /* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
+ #define CYBER_CORTEX_AV_PID	0x8698
+ 
+-- 
+2.9.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4.4.14/0002-USB-serial-ftdi_sio-pass-port-to-quirk-port_probe-fu.patch	Mon Dec 11 05:55:17 2023 +0000
@@ -0,0 +1,85 @@
+From 13701049a8f24450d69b6eeac6cfab5951abc604 Mon Sep 17 00:00:00 2001
+From: "Mychaela N. Falconia" <falcon@freecalypso.org>
+Date: Fri, 2 Oct 2020 17:38:56 +0000
+Subject: [PATCH 2/3] USB: serial: ftdi_sio: pass port to quirk port_probe
+ functions
+
+The original code passed only the pointer to the ftdi_private struct
+to quirk port_probe functions.  However, some quirks may need to be
+applied conditionally only to some channels of a multichannel FT2232x
+or FT4232H device, and if a given quirk's port_probe function needs
+to figure out which channel of a multichannel device is currently
+being considered, it needs access to the port pointer passed to the
+ftdi_sio_port_probe() function, so it can traverse USB data structures
+from there.
+
+Signed-off-by: Mychaela N. Falconia <falcon@freecalypso.org>
+---
+ drivers/usb/serial/ftdi_sio.c | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index 984a93c38365..60d1831ee8c3 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -83,15 +83,15 @@ struct ftdi_private {
+ struct ftdi_sio_quirk {
+ 	int (*probe)(struct usb_serial *);
+ 	/* Special settings for probed ports. */
+-	void (*port_probe)(struct ftdi_private *);
++	void (*port_probe)(struct usb_serial_port *);
+ };
+ 
+ static int   ftdi_jtag_probe(struct usb_serial *serial);
+ static int   ftdi_NDI_device_setup(struct usb_serial *serial);
+ static int   ftdi_stmclite_probe(struct usb_serial *serial);
+ 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 void  ftdi_USB_UIRT_setup(struct usb_serial_port *port);
++static void  ftdi_HE_TIRA1_setup(struct usb_serial_port *port);
+ 
+ static struct ftdi_sio_quirk ftdi_jtag_quirk = {
+ 	.probe	= ftdi_jtag_probe,
+@@ -1808,11 +1808,11 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
+ 
+ 	priv->flags = ASYNC_LOW_LATENCY;
+ 
+-	if (quirk && quirk->port_probe)
+-		quirk->port_probe(priv);
+-
+ 	usb_set_serial_port_data(port, priv);
+ 
++	if (quirk && quirk->port_probe)
++		quirk->port_probe(port);
++
+ 	ftdi_determine_type(port);
+ 	ftdi_set_max_packet_size(port);
+ 	if (read_latency_timer(port) < 0)
+@@ -1825,8 +1825,10 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
+ /* Setup for the USB-UIRT device, which requires hardwired
+  * baudrate (38400 gets mapped to 312500) */
+ /* Called from usbserial:serial_probe */
+-static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
++static void ftdi_USB_UIRT_setup(struct usb_serial_port *port)
+ {
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++
+ 	priv->flags |= ASYNC_SPD_CUST;
+ 	priv->custom_divisor = 77;
+ 	priv->force_baud = 38400;
+@@ -1835,8 +1837,10 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
+ /* Setup for the HE-TIRA1 device, which requires hardwired
+  * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled.  */
+ 
+-static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
++static void ftdi_HE_TIRA1_setup(struct usb_serial_port *port)
+ {
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++
+ 	priv->flags |= ASYNC_SPD_CUST;
+ 	priv->custom_divisor = 240;
+ 	priv->force_baud = 38400;
+-- 
+2.9.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4.4.14/0003-USB-serial-ftdi_sio-add-support-for-FreeCalypso-DUAR.patch	Mon Dec 11 05:55:17 2023 +0000
@@ -0,0 +1,163 @@
+From 32c23625ab6e7cdc7da7849e866ccee66cbe2ee9 Mon Sep 17 00:00:00 2001
+From: "Mychaela N. Falconia" <falcon@freecalypso.org>
+Date: Sat, 5 Dec 2020 20:53:18 +0000
+Subject: [PATCH 3/3] USB: serial: ftdi_sio: add support for FreeCalypso
+ DUART28C adapter
+
+FreeCalypso DUART28C is an FT2232D-based USB to dual UART adapter
+with a special quirk: Channel B RTS and DTR outputs (BDBUS2 and BDBUS4
+on the chip) have been repurposed to drive PWON and RESET controls
+on Calypso targets.  The circuit is wired such that BDBUS[24] high
+(RTS/DTR inactive) is the normal state with Iota VRPC controls
+NOT activated, whereas BDBUS[24] low (RTS or DTR active) turn ON
+the corresponding open drain control signal drivers.
+
+A special ftdi_sio driver quirk is needed in order to suppress
+automatic assertion of DTR & RTS on device open: this device's
+special PWON and RESET control drivers MUST NOT be activated
+when the port is ordinarily opened for plain serial communication,
+instead they must only be activated when a special userspace
+application explicitly requests such activation with a TIOCMBIS ioctl.
+These special userspace applications are responsible for making the
+needed pulse with a TIOCMBIS, delay, TIOCMBIC sequence.
+
+The special quirk is conditionalized on the DUART28C adapter's custom
+USB ID, and is further limited to FT2232D Channel B only: Channel A
+is wired normally, with the chip's ADBUS2 and ADBUS4 outputs
+actually being RTS and DTR rather than something else.
+
+Signed-off-by: Mychaela N. Falconia <falcon@freecalypso.org>
+---
+ drivers/usb/serial/ftdi_sio.c     | 61 +++++++++++++++++++++++++++++++++++----
+ drivers/usb/serial/ftdi_sio_ids.h |  1 +
+ 2 files changed, 57 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index 60d1831ee8c3..b9abe8571aa1 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -73,6 +73,8 @@ struct ftdi_private {
+ 				   this value */
+ 	int force_rtscts;	/* if non-zero, force RTS-CTS to always
+ 				   be enabled */
++	int no_auto_dtr_rts;	/* if non-zero, suppress automatic assertion
++				   of DTR & RTS on device open */
+ 
+ 	unsigned int latency;		/* latency setting in use */
+ 	unsigned short max_packet_size;
+@@ -92,6 +94,7 @@ static int   ftdi_stmclite_probe(struct usb_serial *serial);
+ static int   ftdi_8u2232c_probe(struct usb_serial *serial);
+ static void  ftdi_USB_UIRT_setup(struct usb_serial_port *port);
+ static void  ftdi_HE_TIRA1_setup(struct usb_serial_port *port);
++static void  ftdi_duart28c_setup(struct usb_serial_port *port);
+ 
+ static struct ftdi_sio_quirk ftdi_jtag_quirk = {
+ 	.probe	= ftdi_jtag_probe,
+@@ -117,6 +120,10 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
+ 	.probe	= ftdi_8u2232c_probe,
+ };
+ 
++static struct ftdi_sio_quirk ftdi_duart28c_quirk = {
++	.port_probe = ftdi_duart28c_setup,
++};
++
+ /*
+  * The 8U232AM has the same API as the sio except for:
+  * - it can support MUCH higher baudrates; up to:
+@@ -1013,6 +1020,8 @@ static const struct usb_device_id id_table_combined[] = {
+ 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ 	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID),
+ 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
++	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_DUART28C_PID),
++		.driver_info = (kernel_ulong_t)&ftdi_duart28c_quirk },
+ 	{ }					/* Terminating entry */
+ };
+ 
+@@ -1935,6 +1944,39 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
+ 	return 0;
+ }
+ 
++/*
++ * FreeCalypso DUART28C is an FT2232D-based USB to dual UART adapter
++ * with a special quirk: Channel B RTS and DTR outputs (BDBUS2 and BDBUS4
++ * on the chip) have been repurposed to drive PWON and RESET controls
++ * on Calypso targets.  The circuit is wired such that BDBUS[24] high
++ * (RTS/DTR inactive) is the normal state with Iota VRPC controls
++ * NOT activated, whereas BDBUS[24] low (RTS or DTR active) turn ON
++ * the corresponding open drain control signal drivers.
++ *
++ * A special ftdi_sio driver quirk is needed in order to suppress
++ * automatic assertion of DTR & RTS on device open: this device's
++ * special PWON and RESET control drivers MUST NOT be activated
++ * when the port is ordinarily opened for plain serial communication,
++ * instead they must only be activated when a special userspace
++ * application explicitly requests such activation with a TIOCMBIS ioctl.
++ * These special userspace applications are responsible for making the
++ * needed pulse with a TIOCMBIS, delay, TIOCMBIC sequence.
++ *
++ * The special quirk must be applied only to FT2232D Channel B:
++ * Channel A is wired normally, with the chip's ADBUS2 and ADBUS4 outputs
++ * actually being RTS and DTR rather than something else.
++ */
++static void ftdi_duart28c_setup(struct usb_serial_port *port)
++{
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++	struct usb_serial *serial = port->serial;
++	struct usb_interface *intf = serial->interface;
++	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
++
++	if (ifnum == 1)
++		priv->no_auto_dtr_rts = 1;
++}
++
+ static int ftdi_sio_port_remove(struct usb_serial_port *port)
+ {
+ 	struct ftdi_private *priv = usb_get_serial_port_data(port);
+@@ -1984,10 +2026,18 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
+ 			dev_err(&port->dev, "error from flowcontrol urb\n");
+ 		}
+ 	}
+-	/* drop RTS and DTR */
+-	if (on)
+-		set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+-	else
++	/*
++	 * Assert or negate RTS and DTR as requested.  When DUART28C
++	 * quirk is applied, we suppress automatic assertion, but
++	 * automatic negation on device close is retained - these
++	 * special control signals are meant to be pulsed, and leaving
++	 * either of them stuck on when the responsible userspace
++	 * program has terminated unexpectedly is undesirable.
++	 */
++	if (on) {
++		if (!priv->no_auto_dtr_rts)
++			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
++	} else
+ 		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ }
+ 
+@@ -2325,7 +2375,8 @@ no_data_parity_stop_changes:
+ 			dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
+ 		mutex_unlock(&priv->cfg_lock);
+ 		/* Ensure RTS and DTR are raised when baudrate changed from 0 */
+-		if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
++		if (old_termios && (old_termios->c_cflag & CBAUD) == B0
++		    && !priv->no_auto_dtr_rts)
+ 			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ 	}
+ 
+diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
+index 6218f9c45016..5720768859fe 100644
+--- a/drivers/usb/serial/ftdi_sio_ids.h
++++ b/drivers/usb/serial/ftdi_sio_ids.h
+@@ -44,6 +44,7 @@
+  */
+ #define FTDI_FALCONIA_JTAG_BUF_PID	0x7150
+ #define FTDI_FALCONIA_JTAG_UNBUF_PID	0x7151
++#define FTDI_FALCONIA_DUART28C_PID	0x7152
+ 
+ /* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
+ #define CYBER_CORTEX_AV_PID	0x8698
+-- 
+2.9.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4.4.240/0002-USB-serial-ftdi_sio-pass-port-to-quirk-port_probe-fu.patch	Mon Dec 11 05:55:17 2023 +0000
@@ -0,0 +1,85 @@
+From 269f94070f6ae14abbc47a36ec2556e977ea9bec Mon Sep 17 00:00:00 2001
+From: "Mychaela N. Falconia" <falcon@freecalypso.org>
+Date: Fri, 2 Oct 2020 17:38:56 +0000
+Subject: [PATCH 2/3] USB: serial: ftdi_sio: pass port to quirk port_probe
+ functions
+
+The original code passed only the pointer to the ftdi_private struct
+to quirk port_probe functions.  However, some quirks may need to be
+applied conditionally only to some channels of a multichannel FT2232x
+or FT4232H device, and if a given quirk's port_probe function needs
+to figure out which channel of a multichannel device is currently
+being considered, it needs access to the port pointer passed to the
+ftdi_sio_port_probe() function, so it can traverse USB data structures
+from there.
+
+Signed-off-by: Mychaela N. Falconia <falcon@freecalypso.org>
+---
+ drivers/usb/serial/ftdi_sio.c | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index 5b42b8d760cb..2d23fd7b93cb 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -83,15 +83,15 @@ struct ftdi_private {
+ struct ftdi_sio_quirk {
+ 	int (*probe)(struct usb_serial *);
+ 	/* Special settings for probed ports. */
+-	void (*port_probe)(struct ftdi_private *);
++	void (*port_probe)(struct usb_serial_port *);
+ };
+ 
+ static int   ftdi_jtag_probe(struct usb_serial *serial);
+ static int   ftdi_NDI_device_setup(struct usb_serial *serial);
+ static int   ftdi_stmclite_probe(struct usb_serial *serial);
+ 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 void  ftdi_USB_UIRT_setup(struct usb_serial_port *port);
++static void  ftdi_HE_TIRA1_setup(struct usb_serial_port *port);
+ 
+ static struct ftdi_sio_quirk ftdi_jtag_quirk = {
+ 	.probe	= ftdi_jtag_probe,
+@@ -1833,11 +1833,11 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
+ 
+ 	mutex_init(&priv->cfg_lock);
+ 
+-	if (quirk && quirk->port_probe)
+-		quirk->port_probe(priv);
+-
+ 	usb_set_serial_port_data(port, priv);
+ 
++	if (quirk && quirk->port_probe)
++		quirk->port_probe(port);
++
+ 	ftdi_determine_type(port);
+ 	ftdi_set_max_packet_size(port);
+ 	if (read_latency_timer(port) < 0)
+@@ -1850,8 +1850,10 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
+ /* Setup for the USB-UIRT device, which requires hardwired
+  * baudrate (38400 gets mapped to 312500) */
+ /* Called from usbserial:serial_probe */
+-static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
++static void ftdi_USB_UIRT_setup(struct usb_serial_port *port)
+ {
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++
+ 	priv->flags |= ASYNC_SPD_CUST;
+ 	priv->custom_divisor = 77;
+ 	priv->force_baud = 38400;
+@@ -1860,8 +1862,10 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
+ /* Setup for the HE-TIRA1 device, which requires hardwired
+  * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled.  */
+ 
+-static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
++static void ftdi_HE_TIRA1_setup(struct usb_serial_port *port)
+ {
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++
+ 	priv->flags |= ASYNC_SPD_CUST;
+ 	priv->custom_divisor = 240;
+ 	priv->force_baud = 38400;
+-- 
+2.9.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4.4.240/0003-USB-serial-ftdi_sio-add-support-for-FreeCalypso-DUAR.patch	Mon Dec 11 05:55:17 2023 +0000
@@ -0,0 +1,163 @@
+From 6bfda041e99ef9f1175c0583f2f3c87b491e19b4 Mon Sep 17 00:00:00 2001
+From: "Mychaela N. Falconia" <falcon@freecalypso.org>
+Date: Sat, 5 Dec 2020 20:53:18 +0000
+Subject: [PATCH 3/3] USB: serial: ftdi_sio: add support for FreeCalypso
+ DUART28C adapter
+
+FreeCalypso DUART28C is an FT2232D-based USB to dual UART adapter
+with a special quirk: Channel B RTS and DTR outputs (BDBUS2 and BDBUS4
+on the chip) have been repurposed to drive PWON and RESET controls
+on Calypso targets.  The circuit is wired such that BDBUS[24] high
+(RTS/DTR inactive) is the normal state with Iota VRPC controls
+NOT activated, whereas BDBUS[24] low (RTS or DTR active) turn ON
+the corresponding open drain control signal drivers.
+
+A special ftdi_sio driver quirk is needed in order to suppress
+automatic assertion of DTR & RTS on device open: this device's
+special PWON and RESET control drivers MUST NOT be activated
+when the port is ordinarily opened for plain serial communication,
+instead they must only be activated when a special userspace
+application explicitly requests such activation with a TIOCMBIS ioctl.
+These special userspace applications are responsible for making the
+needed pulse with a TIOCMBIS, delay, TIOCMBIC sequence.
+
+The special quirk is conditionalized on the DUART28C adapter's custom
+USB ID, and is further limited to FT2232D Channel B only: Channel A
+is wired normally, with the chip's ADBUS2 and ADBUS4 outputs
+actually being RTS and DTR rather than something else.
+
+Signed-off-by: Mychaela N. Falconia <falcon@freecalypso.org>
+---
+ drivers/usb/serial/ftdi_sio.c     | 61 +++++++++++++++++++++++++++++++++++----
+ drivers/usb/serial/ftdi_sio_ids.h |  1 +
+ 2 files changed, 57 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index 2d23fd7b93cb..41f73b519023 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -73,6 +73,8 @@ struct ftdi_private {
+ 				   this value */
+ 	int force_rtscts;	/* if non-zero, force RTS-CTS to always
+ 				   be enabled */
++	int no_auto_dtr_rts;	/* if non-zero, suppress automatic assertion
++				   of DTR & RTS on device open */
+ 
+ 	unsigned int latency;		/* latency setting in use */
+ 	unsigned short max_packet_size;
+@@ -92,6 +94,7 @@ static int   ftdi_stmclite_probe(struct usb_serial *serial);
+ static int   ftdi_8u2232c_probe(struct usb_serial *serial);
+ static void  ftdi_USB_UIRT_setup(struct usb_serial_port *port);
+ static void  ftdi_HE_TIRA1_setup(struct usb_serial_port *port);
++static void  ftdi_duart28c_setup(struct usb_serial_port *port);
+ 
+ static struct ftdi_sio_quirk ftdi_jtag_quirk = {
+ 	.probe	= ftdi_jtag_probe,
+@@ -117,6 +120,10 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
+ 	.probe	= ftdi_8u2232c_probe,
+ };
+ 
++static struct ftdi_sio_quirk ftdi_duart28c_quirk = {
++	.port_probe = ftdi_duart28c_setup,
++};
++
+ /*
+  * The 8U232AM has the same API as the sio except for:
+  * - it can support MUCH higher baudrates; up to:
+@@ -1037,6 +1044,8 @@ static const struct usb_device_id id_table_combined[] = {
+ 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ 	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID),
+ 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
++	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_DUART28C_PID),
++		.driver_info = (kernel_ulong_t)&ftdi_duart28c_quirk },
+ 	{ }					/* Terminating entry */
+ };
+ 
+@@ -1961,6 +1970,39 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
+ 	return 0;
+ }
+ 
++/*
++ * FreeCalypso DUART28C is an FT2232D-based USB to dual UART adapter
++ * with a special quirk: Channel B RTS and DTR outputs (BDBUS2 and BDBUS4
++ * on the chip) have been repurposed to drive PWON and RESET controls
++ * on Calypso targets.  The circuit is wired such that BDBUS[24] high
++ * (RTS/DTR inactive) is the normal state with Iota VRPC controls
++ * NOT activated, whereas BDBUS[24] low (RTS or DTR active) turn ON
++ * the corresponding open drain control signal drivers.
++ *
++ * A special ftdi_sio driver quirk is needed in order to suppress
++ * automatic assertion of DTR & RTS on device open: this device's
++ * special PWON and RESET control drivers MUST NOT be activated
++ * when the port is ordinarily opened for plain serial communication,
++ * instead they must only be activated when a special userspace
++ * application explicitly requests such activation with a TIOCMBIS ioctl.
++ * These special userspace applications are responsible for making the
++ * needed pulse with a TIOCMBIS, delay, TIOCMBIC sequence.
++ *
++ * The special quirk must be applied only to FT2232D Channel B:
++ * Channel A is wired normally, with the chip's ADBUS2 and ADBUS4 outputs
++ * actually being RTS and DTR rather than something else.
++ */
++static void ftdi_duart28c_setup(struct usb_serial_port *port)
++{
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++	struct usb_serial *serial = port->serial;
++	struct usb_interface *intf = serial->interface;
++	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
++
++	if (ifnum == 1)
++		priv->no_auto_dtr_rts = 1;
++}
++
+ static int ftdi_sio_port_remove(struct usb_serial_port *port)
+ {
+ 	struct ftdi_private *priv = usb_get_serial_port_data(port);
+@@ -2010,10 +2052,18 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
+ 			dev_err(&port->dev, "error from flowcontrol urb\n");
+ 		}
+ 	}
+-	/* drop RTS and DTR */
+-	if (on)
+-		set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+-	else
++	/*
++	 * Assert or negate RTS and DTR as requested.  When DUART28C
++	 * quirk is applied, we suppress automatic assertion, but
++	 * automatic negation on device close is retained - these
++	 * special control signals are meant to be pulsed, and leaving
++	 * either of them stuck on when the responsible userspace
++	 * program has terminated unexpectedly is undesirable.
++	 */
++	if (on) {
++		if (!priv->no_auto_dtr_rts)
++			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
++	} else
+ 		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ }
+ 
+@@ -2355,7 +2405,8 @@ no_data_parity_stop_changes:
+ 			dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
+ 		mutex_unlock(&priv->cfg_lock);
+ 		/* Ensure RTS and DTR are raised when baudrate changed from 0 */
+-		if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
++		if (old_termios && (old_termios->c_cflag & CBAUD) == B0
++		    && !priv->no_auto_dtr_rts)
+ 			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ 	}
+ 
+diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
+index f3302516a1e4..f756b80cb361 100644
+--- a/drivers/usb/serial/ftdi_sio_ids.h
++++ b/drivers/usb/serial/ftdi_sio_ids.h
+@@ -44,6 +44,7 @@
+  */
+ #define FTDI_FALCONIA_JTAG_BUF_PID	0x7150
+ #define FTDI_FALCONIA_JTAG_UNBUF_PID	0x7151
++#define FTDI_FALCONIA_DUART28C_PID	0x7152
+ 
+ /* Sienna Serial Interface by Secyourit GmbH */
+ #define FTDI_SIENNA_PID		0x8348
+-- 
+2.9.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4.9.240/0002-USB-serial-ftdi_sio-pass-port-to-quirk-port_probe-fu.patch	Mon Dec 11 05:55:17 2023 +0000
@@ -0,0 +1,85 @@
+From 214b1d2da22e380b05ecf6e546962ca867e3a60e Mon Sep 17 00:00:00 2001
+From: "Mychaela N. Falconia" <falcon@freecalypso.org>
+Date: Fri, 2 Oct 2020 17:38:56 +0000
+Subject: [PATCH 2/3] USB: serial: ftdi_sio: pass port to quirk port_probe
+ functions
+
+The original code passed only the pointer to the ftdi_private struct
+to quirk port_probe functions.  However, some quirks may need to be
+applied conditionally only to some channels of a multichannel FT2232x
+or FT4232H device, and if a given quirk's port_probe function needs
+to figure out which channel of a multichannel device is currently
+being considered, it needs access to the port pointer passed to the
+ftdi_sio_port_probe() function, so it can traverse USB data structures
+from there.
+
+Signed-off-by: Mychaela N. Falconia <falcon@freecalypso.org>
+---
+ drivers/usb/serial/ftdi_sio.c | 20 ++++++++++++--------
+ 1 file changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index c9f979063af1..878ab4e5625c 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -83,15 +83,15 @@ struct ftdi_private {
+ struct ftdi_sio_quirk {
+ 	int (*probe)(struct usb_serial *);
+ 	/* Special settings for probed ports. */
+-	void (*port_probe)(struct ftdi_private *);
++	void (*port_probe)(struct usb_serial_port *);
+ };
+ 
+ static int   ftdi_jtag_probe(struct usb_serial *serial);
+ static int   ftdi_NDI_device_setup(struct usb_serial *serial);
+ static int   ftdi_stmclite_probe(struct usb_serial *serial);
+ 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 void  ftdi_USB_UIRT_setup(struct usb_serial_port *port);
++static void  ftdi_HE_TIRA1_setup(struct usb_serial_port *port);
+ 
+ static const struct ftdi_sio_quirk ftdi_jtag_quirk = {
+ 	.probe	= ftdi_jtag_probe,
+@@ -1833,11 +1833,11 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
+ 
+ 	mutex_init(&priv->cfg_lock);
+ 
+-	if (quirk && quirk->port_probe)
+-		quirk->port_probe(priv);
+-
+ 	usb_set_serial_port_data(port, priv);
+ 
++	if (quirk && quirk->port_probe)
++		quirk->port_probe(port);
++
+ 	ftdi_determine_type(port);
+ 	ftdi_set_max_packet_size(port);
+ 	if (read_latency_timer(port) < 0)
+@@ -1850,8 +1850,10 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
+ /* Setup for the USB-UIRT device, which requires hardwired
+  * baudrate (38400 gets mapped to 312500) */
+ /* Called from usbserial:serial_probe */
+-static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
++static void ftdi_USB_UIRT_setup(struct usb_serial_port *port)
+ {
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++
+ 	priv->flags |= ASYNC_SPD_CUST;
+ 	priv->custom_divisor = 77;
+ 	priv->force_baud = 38400;
+@@ -1860,8 +1862,10 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
+ /* Setup for the HE-TIRA1 device, which requires hardwired
+  * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled.  */
+ 
+-static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
++static void ftdi_HE_TIRA1_setup(struct usb_serial_port *port)
+ {
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++
+ 	priv->flags |= ASYNC_SPD_CUST;
+ 	priv->custom_divisor = 240;
+ 	priv->force_baud = 38400;
+-- 
+2.9.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4.9.240/0003-USB-serial-ftdi_sio-add-support-for-FreeCalypso-DUAR.patch	Mon Dec 11 05:55:17 2023 +0000
@@ -0,0 +1,163 @@
+From 8edb5017764d4ad9d90a631c420caca41827cd6e Mon Sep 17 00:00:00 2001
+From: "Mychaela N. Falconia" <falcon@freecalypso.org>
+Date: Fri, 2 Oct 2020 18:01:12 +0000
+Subject: [PATCH 3/3] USB: serial: ftdi_sio: add support for FreeCalypso
+ DUART28C adapter
+
+FreeCalypso DUART28C is an FT2232D-based USB to dual UART adapter
+with a special quirk: Channel B RTS and DTR outputs (BDBUS2 and BDBUS4
+on the chip) have been repurposed to drive PWON and RESET controls
+on Calypso targets.  The circuit is wired such that BDBUS[24] high
+(RTS/DTR inactive) is the normal state with Iota VRPC controls
+NOT activated, whereas BDBUS[24] low (RTS or DTR active) turn ON
+the corresponding open drain control signal drivers.
+
+A special ftdi_sio driver quirk is needed in order to suppress
+automatic assertion of DTR & RTS on device open: this device's
+special PWON and RESET control drivers MUST NOT be activated
+when the port is ordinarily opened for plain serial communication,
+instead they must only be activated when a special userspace
+application explicitly requests such activation with a TIOCMBIS ioctl.
+These special userspace applications are responsible for making the
+needed pulse with a TIOCMBIS, delay, TIOCMBIC sequence.
+
+The special quirk is conditionalized on the DUART28C adapter's custom
+USB ID, and is further limited to FT2232D Channel B only: Channel A
+is wired normally, with the chip's ADBUS2 and ADBUS4 outputs
+actually being RTS and DTR rather than something else.
+
+Signed-off-by: Mychaela N. Falconia <falcon@freecalypso.org>
+---
+ drivers/usb/serial/ftdi_sio.c     | 61 +++++++++++++++++++++++++++++++++++----
+ drivers/usb/serial/ftdi_sio_ids.h |  1 +
+ 2 files changed, 57 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index 878ab4e5625c..443aee847556 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -73,6 +73,8 @@ struct ftdi_private {
+ 				   this value */
+ 	int force_rtscts;	/* if non-zero, force RTS-CTS to always
+ 				   be enabled */
++	int no_auto_dtr_rts;	/* if non-zero, suppress automatic assertion
++				   of DTR & RTS on device open */
+ 
+ 	unsigned int latency;		/* latency setting in use */
+ 	unsigned short max_packet_size;
+@@ -92,6 +94,7 @@ static int   ftdi_stmclite_probe(struct usb_serial *serial);
+ static int   ftdi_8u2232c_probe(struct usb_serial *serial);
+ static void  ftdi_USB_UIRT_setup(struct usb_serial_port *port);
+ static void  ftdi_HE_TIRA1_setup(struct usb_serial_port *port);
++static void  ftdi_duart28c_setup(struct usb_serial_port *port);
+ 
+ static const struct ftdi_sio_quirk ftdi_jtag_quirk = {
+ 	.probe	= ftdi_jtag_probe,
+@@ -117,6 +120,10 @@ static const struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
+ 	.probe	= ftdi_8u2232c_probe,
+ };
+ 
++static const struct ftdi_sio_quirk ftdi_duart28c_quirk = {
++	.port_probe = ftdi_duart28c_setup,
++};
++
+ /*
+  * The 8U232AM has the same API as the sio except for:
+  * - it can support MUCH higher baudrates; up to:
+@@ -1037,6 +1044,8 @@ static const struct usb_device_id id_table_combined[] = {
+ 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ 	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID),
+ 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
++	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_DUART28C_PID),
++		.driver_info = (kernel_ulong_t)&ftdi_duart28c_quirk },
+ 	{ }					/* Terminating entry */
+ };
+ 
+@@ -1961,6 +1970,39 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
+ 	return 0;
+ }
+ 
++/*
++ * FreeCalypso DUART28C is an FT2232D-based USB to dual UART adapter
++ * with a special quirk: Channel B RTS and DTR outputs (BDBUS2 and BDBUS4
++ * on the chip) have been repurposed to drive PWON and RESET controls
++ * on Calypso targets.  The circuit is wired such that BDBUS[24] high
++ * (RTS/DTR inactive) is the normal state with Iota VRPC controls
++ * NOT activated, whereas BDBUS[24] low (RTS or DTR active) turn ON
++ * the corresponding open drain control signal drivers.
++ *
++ * A special ftdi_sio driver quirk is needed in order to suppress
++ * automatic assertion of DTR & RTS on device open: this device's
++ * special PWON and RESET control drivers MUST NOT be activated
++ * when the port is ordinarily opened for plain serial communication,
++ * instead they must only be activated when a special userspace
++ * application explicitly requests such activation with a TIOCMBIS ioctl.
++ * These special userspace applications are responsible for making the
++ * needed pulse with a TIOCMBIS, delay, TIOCMBIC sequence.
++ *
++ * The special quirk must be applied only to FT2232D Channel B:
++ * Channel A is wired normally, with the chip's ADBUS2 and ADBUS4 outputs
++ * actually being RTS and DTR rather than something else.
++ */
++static void ftdi_duart28c_setup(struct usb_serial_port *port)
++{
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++	struct usb_serial *serial = port->serial;
++	struct usb_interface *intf = serial->interface;
++	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
++
++	if (ifnum == 1)
++		priv->no_auto_dtr_rts = 1;
++}
++
+ static int ftdi_sio_port_remove(struct usb_serial_port *port)
+ {
+ 	struct ftdi_private *priv = usb_get_serial_port_data(port);
+@@ -2010,10 +2052,18 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
+ 			dev_err(&port->dev, "error from flowcontrol urb\n");
+ 		}
+ 	}
+-	/* drop RTS and DTR */
+-	if (on)
+-		set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+-	else
++	/*
++	 * Assert or negate RTS and DTR as requested.  When DUART28C
++	 * quirk is applied, we suppress automatic assertion, but
++	 * automatic negation on device close is retained - these
++	 * special control signals are meant to be pulsed, and leaving
++	 * either of them stuck on when the responsible userspace
++	 * program has terminated unexpectedly is undesirable.
++	 */
++	if (on) {
++		if (!priv->no_auto_dtr_rts)
++			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
++	} else
+ 		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ }
+ 
+@@ -2355,7 +2405,8 @@ static void ftdi_set_termios(struct tty_struct *tty,
+ 			dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
+ 		mutex_unlock(&priv->cfg_lock);
+ 		/* Ensure RTS and DTR are raised when baudrate changed from 0 */
+-		if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
++		if (old_termios && (old_termios->c_cflag & CBAUD) == B0
++		    && !priv->no_auto_dtr_rts)
+ 			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ 	}
+ 
+diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
+index f3302516a1e4..f756b80cb361 100644
+--- a/drivers/usb/serial/ftdi_sio_ids.h
++++ b/drivers/usb/serial/ftdi_sio_ids.h
+@@ -44,6 +44,7 @@
+  */
+ #define FTDI_FALCONIA_JTAG_BUF_PID	0x7150
+ #define FTDI_FALCONIA_JTAG_UNBUF_PID	0x7151
++#define FTDI_FALCONIA_DUART28C_PID	0x7152
+ 
+ /* Sienna Serial Interface by Secyourit GmbH */
+ #define FTDI_SIENNA_PID		0x8348
+-- 
+2.9.0
+