ChangeSet 1.811.1.10, 2002/12/12 13:45:00-08:00, kuba@mareimbrium.org

[PATCH] USB: ftdi-sio update

Attached is a patch which updates ftdi sio driver with better (i.e. always
correct ;-) fractional divisor code. The previous one was an
oversimplification that would not always give the best approximation of the
divisor. It also became an internal static function -- exposing it as a (yet
another) macro was unnecessary.


diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c	Mon Dec 16 16:34:03 2002
+++ b/drivers/usb/serial/ftdi_sio.c	Mon Dec 16 16:34:03 2002
@@ -17,6 +17,14 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (07/Jun/2002) Kuba Ober
+ *	Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
+ *	function. It was getting too complex.
+ *	Fix the divisor calculation logic which was setting divisor of 0.125
+ *	instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
+ *	Also make it bump up the divisor to next integer in case of 7/8 - it's
+ *	a better approximation.
+ *
  * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
  *      Not tested by me but it doesn't break anything I use.
  * 
@@ -203,6 +211,10 @@
 static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
 static int  ftdi_ioctl			(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 static void ftdi_break_ctl		(struct usb_serial_port *port, int break_state );
+static unsigned short int ftdi_baud_base_to_divisor
+					(int baud, int base);
+static unsigned short int ftdi_baud_to_divisor
+					(int baud);
 
 static struct usb_serial_device_type ftdi_SIO_device = {
 	.owner =		THIS_MODULE,
@@ -257,6 +269,23 @@
  * ***************************************************************************
  */
 
+static unsigned short int ftdi_baud_base_to_divisor(int baud, int base)
+{
+	unsigned short int divisor;
+	int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
+	if ((divisor3 & 0x7) == 7) divisor3 ++; // round x.7/8 up to x+1
+	divisor = divisor3 >> 3;
+	divisor3 &= 0x7;
+	if (divisor3 == 1) divisor |= 0xc000; else // 0.125
+	if (divisor3 >= 4) divisor |= 0x4000; else // 0.5
+	if (divisor3 != 0) divisor |= 0x8000;      // 0.25
+	return divisor;
+}
+
+static unsigned short int ftdi_baud_to_divisor(int baud)
+{
+	 return(ftdi_baud_base_to_divisor(baud, 48000000));
+}
 
 static int set_rts(struct usb_device *dev,
 		   unsigned int pipe,
@@ -373,7 +402,7 @@
 		break;
 	case FT8U232AM: /* 8U232AM chip */
 		if (baud <= 3000000) {
-			urb_value = FTDI_SIO_BAUD_TO_DIVISOR(baud);
+			urb_value = ftdi_baud_to_divisor(baud);
 		} else {
 	                dbg("%s - Baud rate too high!", __FUNCTION__);
 		}
diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
--- a/drivers/usb/serial/ftdi_sio.h	Mon Dec 16 16:34:03 2002
+++ b/drivers/usb/serial/ftdi_sio.h	Mon Dec 16 16:34:03 2002
@@ -125,17 +125,9 @@
  ftdi_sio_b115200 = 9
 } FTDI_SIO_baudrate_t ;
 
-#define FTDI_SIO_BASE_BAUD_TO_DIVISOR(base, baud) ( \
-((base/2/baud) >> 3) | \
-(((base/2/baud) & 2) ? 0x8000 : 0) | \
-(((base/2/baud) & 4) ? 0x4000 : 0) | \
-((((base/2/baud) & 0x7) == 1) ? 0xc000 : 0) )
-
-#define FTDI_SIO_BAUD_TO_DIVISOR(baud) FTDI_SIO_BASE_BAUD_TO_DIVISOR(48000000, baud)
-
 /*
- * The ftdi_8U232AM_xxMHz_byyy constans have been removed. Their values can
- * be calculated as follows: FTDI_SIO_BAUD_TO_DIVISOR(xx000000, yyy)
+ * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor values
+ * are calculated internally.
  */
 
 #define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
