Allow custom baud rates for FTDI serial ports
- Termios: cf{get,set}{i,o}speed can handle arbitrary speed values. - The value is stored in the appropriate fields of the termios structure in this case. The old constants (stored in the flags) are preserved for BeOS binary compatibility. - Adjust the FTDI FT232* driver to accept custom rates, by replacing the hardcoded regster values with a function that will compute it according to FTDI documentation (confirmed giving the same values for the existing baudrates).
This commit is contained in:
parent
44547a899c
commit
93ea83e53d
@ -21,8 +21,8 @@ struct termios {
|
||||
tcflag_t c_cflag; /* control modes */
|
||||
tcflag_t c_lflag; /* local modes */
|
||||
char c_line; /* line discipline */
|
||||
speed_t c_ispeed; /* (unused) */
|
||||
speed_t c_ospeed; /* (unused) */
|
||||
speed_t c_ispeed; /* custom input baudrate */
|
||||
speed_t c_ospeed; /* custom output baudrate */
|
||||
cc_t c_cc[NCCS]; /* control characters */
|
||||
};
|
||||
|
||||
|
@ -111,26 +111,24 @@ FTDIDevice::SetLineCoding(usb_cdc_line_coding *lineCoding)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (lineCoding->speed) {
|
||||
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;
|
||||
default:
|
||||
rate = ftdi_sio_b19200;
|
||||
/* Compute baudrate register value as documented in AN232B-05 from FTDI.
|
||||
Bits 13-0 are the integer divider, and bits 16-14 are the fractional
|
||||
divider setting. 3Mbaud and 2Mbaud are special values, and at such
|
||||
high speeds the use of the fractional divider is not possible. */
|
||||
if (lineCoding->speed == 3000000)
|
||||
rate = 0;
|
||||
else if (lineCoding->speed == 2000000)
|
||||
rate = 1;
|
||||
else {
|
||||
if (lineCoding->speed > 1500000) {
|
||||
TRACE_ALWAYS("= FTDIDevice::SetLineCoding(): Datarate: %d is "
|
||||
"not supported by this hardware. Defaulted to %d\n",
|
||||
lineCoding->speed, rate);
|
||||
break;
|
||||
lineCoding->speed, 19200);
|
||||
lineCoding->speed = 19200;
|
||||
}
|
||||
rate = 3000000 * 8 / lineCoding->speed;
|
||||
int frac = ftdi_8u232am_frac[rate & 0x7];
|
||||
rate = (rate >> 3) | frac;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,20 +101,17 @@ 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
|
||||
|
||||
/* Fractional divider values for FT232A/B devices */
|
||||
static const int ftdi_8u232am_frac[8] = {
|
||||
0x0 << 14, /* .0 */
|
||||
0x3 << 14, /* .125 */
|
||||
0x2 << 14, /* .25 */
|
||||
0x4 << 14, /* .375 */
|
||||
0x1 << 14, /* .5 */
|
||||
0x5 << 14, /* .625 */
|
||||
0x6 << 14, /* .75 */
|
||||
0x7 << 14 /* .875 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -161,8 +161,8 @@ SerialDevice::SetModes(struct termios *tios)
|
||||
uint8 baud = tios->c_cflag & CBAUD;
|
||||
int32 speed = baud_index_to_speed(baud);
|
||||
if (speed < 0) {
|
||||
baud = B19200;
|
||||
speed = 19200;
|
||||
baud = CBAUD;
|
||||
speed = tios->c_ospeed;
|
||||
}
|
||||
|
||||
// update our master config in full
|
||||
|
@ -105,6 +105,11 @@ tcsendbreak(int fd, int duration)
|
||||
speed_t
|
||||
cfgetispeed(const struct termios *termios)
|
||||
{
|
||||
if (termios->c_cflag & CBAUD == CBAUD)
|
||||
{
|
||||
return termios->c_ispeed;
|
||||
}
|
||||
|
||||
return termios->c_cflag & CBAUD;
|
||||
}
|
||||
|
||||
@ -112,14 +117,14 @@ cfgetispeed(const struct termios *termios)
|
||||
int
|
||||
cfsetispeed(struct termios *termios, speed_t speed)
|
||||
{
|
||||
/* Check for values that the system cannot handle:
|
||||
greater values than B230400 which is
|
||||
the maximum value defined in termios.h
|
||||
Note that errors from hardware device are detected only
|
||||
until the tcsetattr() function is called */
|
||||
if (speed > B230400 || (speed & CBAUD) != speed) {
|
||||
__set_errno(EINVAL);
|
||||
return -1;
|
||||
/* Check for custom baudrates, which must be stored in the c_ispeed
|
||||
field instead of inlined in the flags.
|
||||
Note that errors from hardware device (unsupported baudrates, etc) are
|
||||
detected only when the tcsetattr() function is called */
|
||||
if (speed > B31250) {
|
||||
termios->c_cflag |= CBAUD;
|
||||
termios->c_ispeed = speed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
termios->c_cflag &= ~CBAUD;
|
||||
@ -131,6 +136,11 @@ cfsetispeed(struct termios *termios, speed_t speed)
|
||||
speed_t
|
||||
cfgetospeed(const struct termios *termios)
|
||||
{
|
||||
if (termios->c_cflag & CBAUD == CBAUD)
|
||||
{
|
||||
return termios->c_ospeed;
|
||||
}
|
||||
|
||||
return termios->c_cflag & CBAUD;
|
||||
}
|
||||
|
||||
@ -138,10 +148,11 @@ cfgetospeed(const struct termios *termios)
|
||||
int
|
||||
cfsetospeed(struct termios *termios, speed_t speed)
|
||||
{
|
||||
/* Check for unaccepted speed values (see above) */
|
||||
if (speed > B230400 || (speed & CBAUD) != speed) {
|
||||
__set_errno(EINVAL);
|
||||
return -1;
|
||||
/* Check for custom speed values (see above) */
|
||||
if (speed > B31250) {
|
||||
termios->c_cflag |= CBAUD;
|
||||
termios->c_ospeed = speed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
termios->c_cflag &= ~CBAUD;
|
||||
|
Loading…
x
Reference in New Issue
Block a user