Calculate baud rate divisor instead of allowing only a fixed set of

standard rates.

Obtained from OpenBSD
  src/sys/dev/usb/uftdi.c 1.29
  src/sys/dev/usb/uftdireg.h 1.11

OpenBSD revisions noted by: ticso, on hackers
This commit is contained in:
Ed Maste 2008-01-25 02:41:44 +00:00
parent 515594a06f
commit 27e05557a5
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=175655
2 changed files with 71 additions and 35 deletions

View file

@ -121,6 +121,7 @@ static void uftdi_read(void *sc, int portno, u_char **ptr,u_int32_t *count);
static void uftdi_write(void *sc, int portno, u_char *to, u_char *from,
u_int32_t *count);
static void uftdi_break(void *sc, int portno, int onoff);
static int uftdi_8u232am_getrate(speed_t speed, int *rate);
struct ucom_callback uftdi_callback = {
uftdi_get_status,
@ -569,25 +570,8 @@ uftdi_param(void *vsc, int portno, struct termios *t)
break;
case UFTDI_TYPE_8U232AM:
switch(t->c_ospeed) {
case 300: rate = ftdi_8u232am_b300; break;
case 600: rate = ftdi_8u232am_b600; break;
case 1200: rate = ftdi_8u232am_b1200; break;
case 2400: rate = ftdi_8u232am_b2400; break;
case 4800: rate = ftdi_8u232am_b4800; break;
case 9600: rate = ftdi_8u232am_b9600; break;
case 19200: rate = ftdi_8u232am_b19200; break;
case 38400: rate = ftdi_8u232am_b38400; break;
case 57600: rate = ftdi_8u232am_b57600; break;
case 115200: rate = ftdi_8u232am_b115200; break;
case 230400: rate = ftdi_8u232am_b230400; break;
case 460800: rate = ftdi_8u232am_b460800; break;
case 921600: rate = ftdi_8u232am_b921600; break;
case 2000000: rate = ftdi_8u232am_b2000000; break;
case 3000000: rate = ftdi_8u232am_b3000000; break;
default:
if (uftdi_8u232am_getrate(t->c_ospeed, &rate) == -1)
return (EINVAL);
}
break;
}
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
@ -702,6 +686,70 @@ uftdi_break(void *vsc, int portno, int onoff)
(void)usbd_do_request(ucom->sc_udev, &req, NULL);
}
static int
uftdi_8u232am_getrate(speed_t speed, int *rate)
{
/* Table of the nearest even powers-of-2 for values 0..15. */
static const unsigned char roundoff[16] = {
0, 2, 2, 4, 4, 4, 8, 8,
8, 8, 8, 8, 16, 16, 16, 16,
};
unsigned int d, freq;
int result;
if (speed <= 0)
return (-1);
/* Special cases for 2M and 3M. */
if (speed >= 3000000 * 100 / 103 &&
speed <= 3000000 * 100 / 97) {
result = 0;
goto done;
}
if (speed >= 2000000 * 100 / 103 &&
speed <= 2000000 * 100 / 97) {
result = 1;
goto done;
}
d = (FTDI_8U232AM_FREQ << 4) / speed;
d = (d & ~15) + roundoff[d & 15];
if (d < FTDI_8U232AM_MIN_DIV)
d = FTDI_8U232AM_MIN_DIV;
else if (d > FTDI_8U232AM_MAX_DIV)
d = FTDI_8U232AM_MAX_DIV;
/*
* Calculate the frequency needed for d to exactly divide down
* to our target speed, and check that the actual frequency is
* within 3% of this.
*/
freq = speed * d;
if (freq < (quad_t)(FTDI_8U232AM_FREQ << 4) * 100 / 103 ||
freq > (quad_t)(FTDI_8U232AM_FREQ << 4) * 100 / 97)
return (-1);
/*
* Pack the divisor into the resultant value. The lower
* 14-bits hold the integral part, while the upper 2 bits
* encode the fractional component: either 0, 0.5, 0.25, or
* 0.125.
*/
result = d >> 4;
if (d & 8)
result |= 0x4000;
else if (d & 4)
result |= 0x8000;
else if (d & 2)
result |= 0xc000;
done:
*rate = result;
return (0);
}
static device_method_t uftdi_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, uftdi_match),

View file

@ -91,23 +91,11 @@ enum {
ftdi_sio_b115200 = 9
};
enum {
ftdi_8u232am_b300 = 0x2710,
ftdi_8u232am_b600 = 0x1388,
ftdi_8u232am_b1200 = 0x09c4,
ftdi_8u232am_b2400 = 0x04e2,
ftdi_8u232am_b4800 = 0x0271,
ftdi_8u232am_b9600 = 0x4138,
ftdi_8u232am_b19200 = 0x809c,
ftdi_8u232am_b38400 = 0xc04e,
ftdi_8u232am_b57600 = 0x0034,
ftdi_8u232am_b115200 = 0x001a,
ftdi_8u232am_b230400 = 0x000d,
ftdi_8u232am_b460800 = 0x4006,
ftdi_8u232am_b921600 = 0x8003,
ftdi_8u232am_b2000000 = 0x0001, /* special case for 2M baud */
ftdi_8u232am_b3000000 = 0x0000, /* special case for 3M baud */
};
#define FTDI_8U232AM_FREQ 3000000
/* Bounds for normal divisors as 4-bit fixed precision ints. */
#define FTDI_8U232AM_MIN_DIV 0x20
#define FTDI_8U232AM_MAX_DIV 0x3fff8
/*
* BmRequestType: 0100 0000B