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; }