Hi,

FTDI have a patched version of the ftdi_sio driver on their web-site
with support for their FT2232C chip.  This was produced by Steven Turner
of FTDI.  The changes have previously been incorporated into 2.6.9 with
some minor modifications and corrections.  The attached patch
incorporates the changes into the 2.4 kernel, again with some minor
modifications and corrections.  I also added a static array to map the
chip type to a chip name (as previously done in 2.6.12) as this is a
good point to do this and I didn't think it was worth the effort of
using a separate patch.

Signed off by me in the attachment.  Please apply.  TIA.

-- 
-=( Ian Abbott @ MEV Ltd.    E-mail: <[EMAIL PROTECTED]>        )=-
-=( Tel: +44 (0)161 477 1898   FAX: +44 (0)161 718 3587         )=-
ftdi_sio: Incorporated Steven Turner's support for the FT2232C chip with
some minor changes and corrections back-ported from the 2.6 kernel,
including use of a static array to map the chip type to a chip name.

Signed-off-by: Ian Abbott <[EMAIL PROTECTED]>

diff -ur a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c	2005-07-19 12:07:28.000000000 +0100
+++ b/drivers/usb/serial/ftdi_sio.c	2005-07-19 13:47:54.000000000 +0100
@@ -17,6 +17,10 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (19/Jul/2004) Ian Abbott
+ *      Incorporated Steven Turner's support for FT2232C (and the lead-free
+ *      variants) with some minor changes.
+ *
  * (10/Mar/2004) Jan Capek
  *      Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc.
  *
@@ -253,7 +257,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.3.5"
+#define DRIVER_VERSION "v1.3.6"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>, Bill Ryder <[EMAIL PROTECTED]>, Kuba Ober <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
@@ -481,6 +485,12 @@
 };
 
 
+static struct usb_device_id id_table_FT2232C[] = {
+	{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+	{ }						/* Terminating entry */
+};
+
+
 static struct usb_device_id id_table_USB_UIRT [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
 	{ }						/* Terminating entry */
@@ -504,6 +514,7 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
 	{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
 	{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
@@ -621,6 +632,13 @@
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
+static char *ftdi_chip_name[] = {
+	[SIO] = "SIO",	/* the serial part of FT8U100AX */
+	[FT8U232AM] = "FT8U232AM",
+	[FT232BM] = "FT232BM",
+	[FT2232C] = "FT2232C",
+};
+
 
 /* constants which set the number of write urb buffers */
 #define NUM_URBS			32
@@ -650,6 +668,8 @@
         wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
  	char prev_status, diff_status;        /* Used for TIOCMIWAIT */
 
+	__u16 interface;	/* FT2232C port interface (0 for FT232/245) */
+
 	struct urb	*write_urb_pool[NUM_URBS];
 	spinlock_t	write_urb_pool_lock;
 
@@ -669,6 +689,7 @@
 static int  ftdi_SIO_startup		(struct usb_serial *serial);
 static int  ftdi_8U232AM_startup	(struct usb_serial *serial);
 static int  ftdi_FT232BM_startup	(struct usb_serial *serial);
+static int  ftdi_FT2232C_startup	(struct usb_serial *serial);
 static int  ftdi_USB_UIRT_startup	(struct usb_serial *serial);
 static int  ftdi_HE_TIRA1_startup	(struct usb_serial *serial);
 static int  ftdi_userdev_startup	(struct usb_serial *serial);
@@ -763,6 +784,30 @@
 	.shutdown =		ftdi_shutdown,
 };
 
+static struct usb_serial_device_type ftdi_FT2232C_device = {
+	.owner =		THIS_MODULE,
+	.name =			"FTDI FT2232C Compatible",
+	.id_table =		id_table_FT2232C,
+	.num_interrupt_in =	0,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.open =			ftdi_open,
+	.close =		ftdi_close,
+	.throttle =		ftdi_throttle,
+	.unthrottle =		ftdi_unthrottle,
+	.write =		ftdi_write,
+	.write_room =		ftdi_write_room,
+	.chars_in_buffer =	ftdi_chars_in_buffer,
+	.read_bulk_callback =	ftdi_read_bulk_callback,
+	.write_bulk_callback =	ftdi_write_bulk_callback,
+	.ioctl =		ftdi_ioctl,
+	.set_termios =		ftdi_set_termios,
+	.break_ctl =		ftdi_break_ctl,
+	.startup =		ftdi_FT2232C_startup,
+	.shutdown =		ftdi_shutdown,
+};
+
 static struct usb_serial_device_type ftdi_USB_UIRT_device = {
 	.owner =		THIS_MODULE,
 	.name =			"USB-UIRT Infrared Tranceiver",
@@ -900,7 +945,7 @@
 			       usb_sndctrlpipe(port->serial->dev, 0),
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			       ftdi_high_or_low, 0, 
+			       ftdi_high_or_low, priv->interface, 
 			       buf, 0, WDR_TIMEOUT));
 }
 
@@ -921,7 +966,7 @@
 			       usb_sndctrlpipe(port->serial->dev, 0),
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			       ftdi_high_or_low, 0, 
+			       ftdi_high_or_low, priv->interface, 
 			       buf, 0, WDR_TIMEOUT));
 }
 
@@ -932,6 +977,7 @@
 static int change_speed(struct usb_serial_port *port)
 {
 	char buf[1];
+	struct ftdi_private * priv = (struct ftdi_private *)port->private;
         __u16 urb_value;
 	__u16 urb_index;
 	__u32 urb_index_value;
@@ -939,6 +985,9 @@
 	urb_index_value = get_ftdi_divisor(port);
 	urb_value = (__u16)urb_index_value;
 	urb_index = (__u16)(urb_index_value >> 16);
+	if (priv->interface) {	/* FT2232C */
+		urb_index = (__u16)((urb_index << 8) | priv->interface);
+	}
 	
 	return (usb_control_msg(port->serial->dev,
 			    usb_sndctrlpipe(port->serial->dev, 0),
@@ -955,7 +1004,6 @@
 	struct ftdi_private * priv = (struct ftdi_private *)port->private;
 	__u32 div_value = 0;
 	int div_okay = 1;
-	char *chip_name = "";
 	int baud;
 
 	/*
@@ -1000,7 +1048,6 @@
 	if (!baud) baud = 9600;	
 	switch(priv->chip_type) {
 	case SIO: /* SIO chip */
-		chip_name = "SIO";
 		switch(baud) {
 		case 300: div_value = ftdi_sio_b300; break;
 		case 600: div_value = ftdi_sio_b600; break;
@@ -1020,7 +1067,6 @@
 		}
 		break;
 	case FT8U232AM: /* 8U232AM chip */
-		chip_name = "FT8U232AM";
 		if (baud <= 3000000) {
 			div_value = ftdi_232am_baud_to_divisor(baud);
 		} else {
@@ -1030,7 +1076,7 @@
 		}
 		break;
 	case FT232BM: /* FT232BM chip */
-		chip_name = "FT232BM";
+	case FT2232C: /* FT2232C chip */
 		if (baud <= 3000000) {
 			div_value = ftdi_232bm_baud_to_divisor(baud);
 		} else {
@@ -1043,7 +1089,8 @@
 
 	if (div_okay) {
 		dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s",
-			__FUNCTION__, baud, (unsigned long)div_value, chip_name);
+			__FUNCTION__, baud, (unsigned long)div_value,
+			ftdi_chip_name[priv->chip_type]);
 	}
 
 	return(div_value);
@@ -1271,6 +1318,35 @@
 	return (0);
 } /* ftdi_FT232BM_startup */
 
+/* Startup for the FT2232C chip */
+/* Called from usbserial:serial_probe */
+static int ftdi_FT2232C_startup (struct usb_serial *serial)
+{ /* ftdi_FT2232C_startup */
+	struct ftdi_private *priv;
+	int err;
+	int inter;
+
+	dbg("%s",__FUNCTION__);
+	err = ftdi_common_startup(serial);
+	if (err){
+		return (err);
+	}
+
+	priv = serial->port->private;
+	priv->chip_type = FT2232C;
+	inter = serial->interface->altsetting->bInterfaceNumber;
+
+	if(inter) {
+		priv->interface = PIT_SIOB;
+	}
+	else  {
+		priv->interface = PIT_SIOA;
+	}
+	priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */
+	
+	return (0);
+} /* ftdi_FT2232C_startup */
+
 /* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */
 /* Called from usbserial:serial_probe */
 static int ftdi_USB_UIRT_startup (struct usb_serial *serial)
@@ -1407,7 +1483,7 @@
 	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
 			FTDI_SIO_RESET_SIO, 
-			0, buf, 0, WDR_TIMEOUT);
+			priv->interface, buf, 0, WDR_TIMEOUT);
 
 	/* Termios defaults are set by usb_serial_init. We don't change
 	   port->tty->termios - this would loose speed settings, etc.
@@ -1453,6 +1529,7 @@
 { /* ftdi_close */
 	struct usb_serial *serial;
 	unsigned int c_cflag = port->tty->termios->c_cflag;
+	struct ftdi_private *priv = (struct ftdi_private *)port->private;
 	char buf[1];
 	int err;
 
@@ -1469,7 +1546,8 @@
 					    usb_sndctrlpipe(serial->dev, 0),
 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-					    0, 0, buf, 0, WDR_TIMEOUT) < 0) {
+					    0, priv->interface, buf, 0,
+					    WDR_TIMEOUT) < 0) {
 				err("error from flowcontrol urb");
 			}	    
 
@@ -1882,7 +1960,7 @@
 	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			    FTDI_SIO_SET_DATA_REQUEST, 
 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
-			    urb_value , 0,
+			    urb_value , priv->interface,
 			    buf, 0, WDR_TIMEOUT) < 0) {
 		err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
 	}	   
@@ -1961,7 +2039,7 @@
 	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 			    FTDI_SIO_SET_DATA_REQUEST, 
 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
-			    urb_value , 0,
+			    urb_value , priv->interface,
 			    buf, 0, 100) < 0) {
 		err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
 	}	   
@@ -1972,7 +2050,7 @@
 		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-				    0, 0, 
+				    0, priv->interface, 
 				    buf, 0, WDR_TIMEOUT) < 0) {
 			err("%s error from disable flowcontrol urb", __FUNCTION__);
 		}	    
@@ -2006,7 +2084,7 @@
 				    usb_sndctrlpipe(serial->dev, 0),
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-				    0 , FTDI_SIO_RTS_CTS_HS,
+				    0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
 				    buf, 0, WDR_TIMEOUT) < 0) {
 			err("urb failed to set to rts/cts flow control");
 		}		
@@ -2032,7 +2110,8 @@
 					    usb_sndctrlpipe(serial->dev, 0),
 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-					    urb_value , FTDI_SIO_XON_XOFF_HS,
+					    urb_value , (FTDI_SIO_XON_XOFF_HS
+						    | priv->interface),
 					    buf, 0, WDR_TIMEOUT) < 0) {
 				err("urb failed to set to xon/xoff flow control");
 			}
@@ -2044,7 +2123,7 @@
 					    usb_sndctrlpipe(serial->dev, 0),
 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-					    0, 0, 
+					    0, priv->interface, 
 					    buf, 0, WDR_TIMEOUT) < 0) {
 				err("urb failed to clear flow control");
 			}				
@@ -2078,7 +2157,7 @@
 						   usb_rcvctrlpipe(serial->dev, 0),
 						   FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
 						   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-						   0, 0, 
+						   0, priv->interface, 
 						   buf, 1, WDR_TIMEOUT)) < 0 ) {
 				err("%s Could not get modem status of device - err: %d", __FUNCTION__,
 				    ret);
@@ -2087,13 +2166,14 @@
 			break;
 		case FT8U232AM:
 		case FT232BM:
+		case FT2232C:
 			/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
 			   format as the data returned from the in point */
 			if ((ret = usb_control_msg(serial->dev, 
 						   usb_rcvctrlpipe(serial->dev, 0),
 						   FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
 						   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-						   0, 0, 
+						   0, priv->interface, 
 						   buf, 2, WDR_TIMEOUT)) < 0 ) {
 				err("%s Could not get modem status of device - err: %d", __FUNCTION__,
 				    ret);
@@ -2270,6 +2350,7 @@
 	usb_serial_register (&ftdi_SIO_device);
 	usb_serial_register (&ftdi_8U232AM_device);
 	usb_serial_register (&ftdi_FT232BM_device);
+	usb_serial_register (&ftdi_FT2232C_device);
 	usb_serial_register (&ftdi_USB_UIRT_device);
 	usb_serial_register (&ftdi_HE_TIRA1_device);
 
@@ -2296,6 +2377,7 @@
 		usb_serial_deregister (&ftdi_userdev_device);
 	usb_serial_deregister (&ftdi_HE_TIRA1_device);
 	usb_serial_deregister (&ftdi_USB_UIRT_device);
+	usb_serial_deregister (&ftdi_FT2232C_device);
 	usb_serial_deregister (&ftdi_FT232BM_device);
 	usb_serial_deregister (&ftdi_8U232AM_device);
 	usb_serial_deregister (&ftdi_SIO_device);
diff -ur a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
--- a/drivers/usb/serial/ftdi_sio.h	2005-07-19 12:07:28.000000000 +0100
+++ b/drivers/usb/serial/ftdi_sio.h	2005-07-19 13:47:48.000000000 +0100
@@ -26,6 +26,7 @@
 #define FTDI_SIO_PID	0x8372	/* Product Id SIO application of 8U100AX  */
 #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
 #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
+#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
 #define FTDI_RELAIS_PID	0xFA10  /* Relais device from Rudolf Gugler */
 #define FTDI_NF_RIC_VID	0x0DCD	/* Vendor Id */
 #define FTDI_NF_RIC_PID	0x0001	/* Product Id */
@@ -257,6 +258,16 @@
 #define FTDI_SIO_SET_EVENT_CHAR	6 /* Set the event character */
 #define FTDI_SIO_SET_ERROR_CHAR	7 /* Set the error character */
 
+/*
+ *   BmRequestType:  1100 0000b
+ *   bRequest:       FTDI_E2_READ
+ *   wValue:         0
+ *   wIndex:         Address of word to read
+ *   wLength:        2
+ *   Data:           Will return a word of data from E2Address
+ *
+ */
+
 /* Port Identifier Table */
 #define PIT_DEFAULT 		0 /* SIOA */
 #define PIT_SIOA		1 /* SIOA */
@@ -356,6 +367,7 @@
 	SIO = 1,
 	FT8U232AM = 2,
 	FT232BM = 3,
+	FT2232C = 4,
 } ftdi_chip_type_t;
 
 typedef enum {

Reply via email to