This diff is about the baud rate divisor calculation.
The driver should now support the full range of possible baud rates for
FT232BM and later devices.
(The calculation is described in the document "AN_120 Aliasing VCP
Baud Rates" from ftdi.)


Index: sys/dev/usb/uftdireg.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/uftdireg.h,v
retrieving revision 1.13
diff -u -p -r1.13 uftdireg.h
--- sys/dev/usb/uftdireg.h      11 Sep 2012 16:04:44 -0000      1.13
+++ sys/dev/usb/uftdireg.h      20 Sep 2012 21:42:51 -0000
@@ -36,6 +36,7 @@
 enum uftdi_type {
        UFTDI_TYPE_SIO,
        UFTDI_TYPE_8U232AM,
+       UFTDI_TYPE_232BM,
        UFTDI_TYPE_2232H
 };

Index: sys/dev/usb/uftdi.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uftdi.c,v
retrieving revision 1.63
diff -u -p -r1.63 uftdi.c
--- sys/dev/usb/uftdi.c 11 Sep 2012 16:04:44 -0000      1.63
+++ sys/dev/usb/uftdi.c 20 Sep 2012 21:42:52 -0000
@@ -105,7 +105,7 @@ void        uftdi_write(void *sc, int portno, u
                            u_int32_t *count);
 void   uftdi_break(void *sc, int portno, int onoff);
 int    uftdi_8u232am_getrate(speed_t speed, int *rate);
-int    uftdi_2232h_getrate(speed_t speed, int *rate);
+int    uftdi_232bm_getrate(speed_t speed, int freq, int *rate);

 struct ucom_methods uftdi_methods = {
        uftdi_get_status,
@@ -821,17 +821,19 @@ uftdi_attach(struct device *parent, stru

        sc->sc_udev = dev;
        sc->sc_iface = iface;
+       sc->sc_hdrlen = 0;

        if (uaa->release < 0x0200) {
                sc->sc_type = UFTDI_TYPE_SIO;
                sc->sc_hdrlen = 1;
-       } else if (uaa->release == 0x0700  || uaa->release == 0x0800) {
+       } else if (uaa->release < 0x0500)
+               sc->sc_type = UFTDI_TYPE_8U232AM;
+       else if (uaa->release < 0x0700)
+               sc->sc_type = UFTDI_TYPE_232BM;
+       else if (uaa->release < 0x0A00)
                sc->sc_type = UFTDI_TYPE_2232H;
-               sc->sc_hdrlen = 0;
-       } else {
+       else
                sc->sc_type = UFTDI_TYPE_8U232AM;
-               sc->sc_hdrlen = 0;
-       }

        uca.bulkin = uca.bulkout = -1;
        for (i = 0; i < id->bNumEndpoints; i++) {
@@ -1083,9 +1085,19 @@ uftdi_param(void *vsc, int portno, struc
                if (uftdi_8u232am_getrate(t->c_ospeed, &rate) == -1)
                        return (EINVAL);
                break;
+       case UFTDI_TYPE_232BM:
+               if (uftdi_232bm_getrate(t->c_ospeed, FTDI_8U232AM_FREQ, &rate) 
== -1)
+                       return (EINVAL);
        case UFTDI_TYPE_2232H:
-               if (uftdi_2232h_getrate(t->c_ospeed, &rate) == -1)
-                        return (EINVAL);
+               if (t->c_ospeed <= FTDI_8U232AM_FREQ) {
+                       if (uftdi_232bm_getrate(t->c_ospeed, FTDI_8U232AM_FREQ, 
&rate) == -1)
+                               return (EINVAL);
+               } else {
+                       if (uftdi_232bm_getrate(t->c_ospeed, FTDI_2232H_FREQ, 
&rate) == -1)
+                               return (EINVAL);
+                       /* Set this bit to turn off a divide by 2.5 */
+                       rate|= 0x00020000;
+               }
                break;
        }
        req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
@@ -1263,31 +1275,37 @@ done:
 }

 int
-uftdi_2232h_getrate(speed_t speed, int *rate)
+uftdi_232bm_getrate(speed_t speed, int freq, int *rate)
 {
        char sub[8] = {0, 3, 2, 4, 1, 5, 6, 7};
-       int n = (FTDI_2232H_FREQ << 3) / speed;
+       int n = ((freq << 3) + (speed >> 1)) / speed;
        int s = n & 7;
-       int result = (n >> 3) | (sub[s] << 14);
+       int resultint = (n >> 3);
+       int result = resultint | (sub[s] << 14);
        int resultspeed, accuracy;

        /* Special cases */
-       if (result == 1)
-               result = 0;
-       else if (result == 0x4001)
+       if (resultint == 0 || resultint > 16384)
+               return -1;
+       else if (speed > 2000000 * 97 / 100 && speed < 2000000 * 103 / 100) {
                result = 1;
+               goto done;
+       }
+       else if (resultint == 1) {
+               result = 0;
+               s = 0;
+       }

        /* Check if resulting baud rate is within 3%. */
-       if (result == 0)
+       if (resultint == 0)
                goto done;
-       resultspeed = (FTDI_2232H_FREQ << 3) /
-           (((result & 0x00003FFF) << 3) | s);
+       resultspeed = (freq << 3) /
+           ((resultint << 3) | s);
        accuracy = (abs(speed - resultspeed) * 100) / speed;
-       if (accuracy > 3)
+       if (accuracy >= 3)
                return -1;

 done:
-       result|= 0x00020000; /* Set this bit to turn off a divide by 2.5 */
        *rate = result;
        return 0;
 }

Reply via email to