Index: bin/stty/modes.c =================================================================== --- bin/stty/modes.c +++ bin/stty/modes.c @@ -91,6 +91,8 @@ { "-rtsflow", 0, CRTS_IFLOW }, { "mdmbuf", MDMBUF, 0 }, { "-mdmbuf", 0, MDMBUF }, + { "rtsdtr", 0, CNO_RTSDTR }, + { "-rtsdtr", CNO_RTSDTR, 0 }, { NULL, 0, 0 }, }; Index: bin/stty/print.c =================================================================== --- bin/stty/print.c +++ bin/stty/print.c @@ -184,6 +184,7 @@ put("-dsrflow", CDSR_OFLOW, 0); put("-dtrflow", CDTR_IFLOW, 0); put("-mdmbuf", MDMBUF, 0); /* XXX mdmbuf == dtrflow */ + put("--rtsdtr", CNO_RTSDTR, 0); /* This is an inverted flag, hence the -- */ /* special control characters */ cc = tp->c_cc; Index: sys/dev/puc/puc.c =================================================================== --- sys/dev/puc/puc.c +++ sys/dev/puc/puc.c @@ -49,25 +49,6 @@ #include #include -#define PUC_ISRCCNT 5 - -struct puc_port { - struct puc_bar *p_bar; - struct resource *p_rres; - struct resource *p_ires; - device_t p_dev; - int p_nr; - int p_type; - int p_rclk; - - int p_hasintr:1; - - serdev_intr_t *p_ihsrc[PUC_ISRCCNT]; - void *p_iharg; - - int p_ipend; -}; - devclass_t puc_devclass; const char puc_driver_name[] = "puc"; @@ -728,6 +709,34 @@ return (ENOENT); } return (0); +} + +int +puc_bus_write_ivar(device_t dev, device_t child, int index, uintptr_t val) +{ + struct puc_port *port; + struct puc_softc *sc; + intptr_t *varr; + + /* Get our immediate child. */ + while (child != NULL && device_get_parent(child) != dev) + child = device_get_parent(child); + if (child == NULL) + return (EINVAL); + + port = device_get_ivars(child); + KASSERT(port != NULL, ("%s %d", __func__, __LINE__)); + + switch(index) { + case PUC_IVAR_TARGETBAUD: + sc = device_get_softc(dev); + if (sc && sc->sc_cfg && sc->sc_cfg->config_function) { + varr = (intptr_t *)val; + return sc->sc_cfg->config_function(sc, PUC_CFG_TARGETBAUD, port->p_nr - 1, varr); + } + return EOPNOTSUPP; + } + return ENOENT; } int Index: sys/dev/puc/puc_bfe.h =================================================================== --- sys/dev/puc/puc_bfe.h +++ sys/dev/puc/puc_bfe.h @@ -31,10 +31,11 @@ #ifndef _DEV_PUC_BFE_H_ #define _DEV_PUC_BFE_H_ +#include + #define PUC_PCI_BARS 6 struct puc_cfg; -struct puc_port; extern const struct puc_cfg puc_pci_devices[]; @@ -47,6 +48,25 @@ int b_type; }; +#define PUC_ISRCCNT 5 + +struct puc_port { + struct puc_bar *p_bar; + struct resource *p_rres; + struct resource *p_ires; + device_t p_dev; + int p_nr; + int p_type; + int p_rclk; + + int p_hasintr:1; + + serdev_intr_t *p_ihsrc[PUC_ISRCCNT]; + void *p_iharg; + + int p_ipend; +}; + struct puc_softc { device_t sc_dev; @@ -92,6 +112,7 @@ int puc_bus_get_resource(device_t, device_t, int, int, rman_res_t *, rman_res_t *); int puc_bus_print_child(device_t, device_t); int puc_bus_read_ivar(device_t, device_t, int, uintptr_t *); +int puc_bus_write_ivar(device_t, device_t, int, uintptr_t); int puc_bus_release_resource(device_t, device_t, int, int, struct resource *); int puc_bus_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); Index: sys/dev/puc/puc_bus.h =================================================================== --- sys/dev/puc/puc_bus.h +++ sys/dev/puc/puc_bus.h @@ -36,6 +36,7 @@ #define PUC_IVAR_CLOCK 0 #define PUC_IVAR_TYPE 1 +#define PUC_IVAR_TARGETBAUD 2 /* Port types. */ #define PUC_TYPE_SERIAL 1 Index: sys/dev/puc/puc_cfg.h =================================================================== --- sys/dev/puc/puc_cfg.h +++ sys/dev/puc/puc_cfg.h @@ -64,7 +64,8 @@ PUC_CFG_GET_OFS, PUC_CFG_GET_RID, PUC_CFG_GET_TYPE, - PUC_CFG_SETUP + PUC_CFG_SETUP, + PUC_CFG_TARGETBAUD }; struct puc_softc; Index: sys/dev/puc/puc_cfg.c =================================================================== --- sys/dev/puc/puc_cfg.c +++ sys/dev/puc/puc_cfg.c @@ -172,6 +172,9 @@ case PUC_CFG_SETUP: *r = ENXIO; return (0); + case PUC_CFG_TARGETBAUD: + *r = ENXIO; + return (0); } return (ENXIO); Index: sys/dev/puc/puc_pccard.c =================================================================== --- sys/dev/puc/puc_pccard.c +++ sys/dev/puc/puc_pccard.c @@ -83,6 +83,7 @@ DEVMETHOD(bus_release_resource, puc_bus_release_resource), DEVMETHOD(bus_get_resource, puc_bus_get_resource), DEVMETHOD(bus_read_ivar, puc_bus_read_ivar), + DEVMETHOD(bus_write_ivar, puc_bus_write_ivar), DEVMETHOD(bus_setup_intr, puc_bus_setup_intr), DEVMETHOD(bus_teardown_intr, puc_bus_teardown_intr), DEVMETHOD(bus_print_child, puc_bus_print_child), Index: sys/dev/puc/puc_pci.c =================================================================== --- sys/dev/puc/puc_pci.c +++ sys/dev/puc/puc_pci.c @@ -183,6 +183,7 @@ DEVMETHOD(bus_release_resource, puc_bus_release_resource), DEVMETHOD(bus_get_resource, puc_bus_get_resource), DEVMETHOD(bus_read_ivar, puc_bus_read_ivar), + DEVMETHOD(bus_write_ivar, puc_bus_write_ivar), DEVMETHOD(bus_setup_intr, puc_bus_setup_intr), DEVMETHOD(bus_teardown_intr, puc_bus_teardown_intr), DEVMETHOD(bus_print_child, puc_bus_print_child), Index: sys/dev/puc/pucdata.c =================================================================== --- sys/dev/puc/pucdata.c +++ sys/dev/puc/pucdata.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -1754,14 +1756,180 @@ return (ENXIO); } +struct puc_util_fract { + uint64_t n; + uint64_t d; +}; + +/* + * Returns the greatest common denomiator of a and b + * Thanks Wikipedia! + */ +static uint64_t +puc_util_gcd(uint64_t a, uint64_t b) +{ + uint64_t d = 0; + + while (((a | b) & 1) == 0) { + a >>= 1; + b >>= 1; + d++; + } + while (a != b) { + if ((a & 1) == 0) + a >>= 1; + else if ((b & 1) == 0) + b >>= 1; + else if (a > b) + a = (a - b) >> 1; + else + b = (b - a) >> 1; + } + return (1<n, f->d); + + f->n /= d; + f->d /= d; +} + +/* + * Divides two fractions + * r may equal x or y. + */ +static void +puc_util_fract_div(struct puc_util_fract *x, struct puc_util_fract *y, + struct puc_util_fract *r) +{ + uint64_t rn, rd; + + rn = x->n * y->d; + rd = x->d * y->n; + r->n = rn; + r->d = rd; + puc_util_fract_reduce(r); +} + +struct puc_oxford_1695x_result { + uint16_t cpr; + uint16_t div; + uint8_t tcr; +}; + static int +puc_oxford_1695x_solve(struct puc_util_fract *baud, + struct puc_oxford_1695x_result *res) +{ + struct puc_util_fract base = {62500000, 16}; + struct puc_util_fract prescale; + struct puc_util_fract result; + + int tcr; + int div; + int cpr; + int bcpr = INT_MAX; + int bdiv = INT_MAX; + int btcr; + int act; + int64_t err; + int64_t berr = INT64_MAX; + + /* First, try for "perfect" just using div */ + puc_util_fract_div(&base, baud, &result); + + /* We got it... done. */ + if (result.d == 1) { + if (result.n < 65536 && result.n > 0) { + res->tcr = 16; + res->cpr = 8; + res->div = result.n; + return 0; + } + } + + /* + * Now we try all combinations of tcr/cpr, picking the best one. + * We prefer high tcr, and we may still get a perfect match. + * This results in a table similar to the one in the datasheet, + * but with a preference for a high tcr and low prescaler. + * The high tcr may make it more resistant to timing errors, + * and the low prescaler shouldn't matter. + */ + for (tcr = 16; tcr >= 4; tcr--) { + base.d = tcr; + for (cpr = 8; cpr < 512; cpr++) { + prescale.n = cpr; + prescale.d = 8; + puc_util_fract_div(&base, &prescale, &prescale); + puc_util_fract_div(&prescale, baud, &result); + + /* We got a perfect match. */ + if (result.d == 1) { + if (result.n < 65536 && result.n > 0) { + res->tcr = tcr; + res->cpr = cpr; + res->div = result.n; + return 0; + } + } + div = ((result.n << 1) / result.d + 1) >> 1; + if (div > 65535) + continue; + if (div < 1) + continue; + act = (((base.n << 1) / div + 1) / base.d) >> 1; + err = (((baud->n << 1) / baud->d + 1) >> 1) - act; + + if (err < 0) + err = -err; + if (err < berr) { + bcpr = cpr; + bdiv = div; + berr = err; + btcr = tcr; + } + } + } + + res->tcr = btcr; + res->cpr = bcpr; + res->div = bdiv; + + /* + * Check for errors... + */ + if (res->tcr < 4 || res->tcr > 16 || + res->cpr < 8 || res->cpr > 511 || + res->div < 1) { + res->tcr = 16; + res->cpr = 8; + res->div = 65535; + return EINVAL; + } + + return 0; +} + +static int puc_config_oxford_pcie(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port, intptr_t *res) { const struct puc_cfg *cfg = sc->sc_cfg; + struct puc_oxford_1695x_result bres; + struct puc_util_fract baud; + struct baud_fraction *bf; int idx; struct puc_bar *bar; uint8_t value; + uint16_t prescale; + int rval; switch (cmd) { case PUC_CFG_SETUP: @@ -1820,6 +1988,87 @@ return (0); case PUC_CFG_GET_TYPE: *res = PUC_TYPE_SERIAL; + return (0); + case PUC_CFG_TARGETBAUD: + bf = (struct baud_fraction *)res; + bar = puc_get_bar(sc, cfg->rid); + if (bar == NULL) + return (ENXIO); + baud.n = bf->bf_numerator; + baud.d = bf->bf_denominator; + rval = puc_oxford_1695x_solve(&baud, &bres); + if (rval) + return rval; + value = bus_read_1(bar->b_res, 0x1000 + (port << 9) + 0x04); + if (bres.cpr == 8) { + value &= ~0x80; + bus_write_1(bar->b_res, 0x1000 + (port << 9) + 0x04, + value); + } + else { + value |= 0x80; + bus_write_1(bar->b_res, 0x1000 + (port << 9) + 0x04, + value); + bus_write_1(bar->b_res, 0x1000 + (port << 9) + 0xC1, + bres.cpr & 0xff); + /* Don't change unused bits */ + value = bus_read_1(bar->b_res, 0x1000 + (port << 9) + 0xC3); + value &= 0xfe; + value |= (bres.cpr >> 8) & 1; + bus_write_1(bar->b_res, 0x1000 + (port << 9) + 0xC3, + value); + } + value = bus_read_1(bar->b_res, 0x1000 + (port << 9) + 0xC2); + value &= 0xf0; + if (bres.tcr == 16) + bus_write_1(bar->b_res, 0x1000 + (port << 9) + 0xC2, value); + else + bus_write_1(bar->b_res, 0x1000 + (port << 9) + 0xC2, + value | (bres.tcr & 0x0f)); + sc->sc_port[port].p_rclk = 62500000; // Base rclk + sc->sc_port[port].p_rclk <<= 4; // Assumed tcr + sc->sc_port[port].p_rclk /= bres.tcr; // Real tcr + sc->sc_port[port].p_rclk <<= 3; // Prescale units 1/8 + sc->sc_port[port].p_rclk /= bres.cpr; + return (0); + case PUC_CFG_GET_CLOCK: + *res = 62500000; // Base clock is 62.5MHz + /* + * TCR sets the data-bit oversampling... UART driver + * assumes this is 16, so we scale the clock up if less + * than 16. + */ + *res <<= 4; + bar = puc_get_bar(sc, cfg->rid); + if (bar == NULL) + return (ENXIO); + value = bus_read_1(bar->b_res, 0x1000 + (port << 9) + 0xC2); + value &= 0x0f; + if (value < 4) + *res >>= 4; + else + *res /= value; + /* + * Now check MCR bit 7... if it's set, the prescaler + * is enabled. + */ + value = bus_read_1(bar->b_res, 0x1000 + (port << 9) + 0x04); + if ((value & 0x80) == 0) + return 0; + + /* + * Read the prescaler configuration + */ + value = bus_read_1(bar->b_res, 0x1000 + (port << 9) + 0xC3); + value &= 1; + prescale = value<<8; + value = bus_read_1(bar->b_res, 0x1000 + (port << 9) + 0xC1); + prescale |= value; + if (prescale < 8) + return ENXIO; + *res <<= 3; + *res /= prescale; + return (0); default: break; Index: sys/dev/uart/uart_bus.h =================================================================== --- sys/dev/uart/uart_bus.h +++ sys/dev/uart/uart_bus.h @@ -37,6 +37,7 @@ #include #include +#include /* Drain and flush targets. */ #define UART_DRAIN_RECEIVER 0x0001 @@ -55,6 +56,8 @@ #define UART_IOCTL_IFLOW 2 #define UART_IOCTL_OFLOW 3 #define UART_IOCTL_BAUD 4 +#define UART_IOCTL_SET_FBAUD 5 +#define UART_IOCTL_GET_FBAUD 6 /* UART quirk flags */ #define UART_F_BUSY_DETECT 0x1 Index: sys/dev/uart/uart_bus_puc.c =================================================================== --- sys/dev/uart/uart_bus_puc.c +++ sys/dev/uart/uart_bus_puc.c @@ -46,6 +46,7 @@ #include static int uart_puc_probe(device_t dev); +static void uart_puc_adjust_rclk(device_t dev, void *bptr); static device_method_t uart_puc_methods[] = { /* Device interface */ @@ -55,6 +56,7 @@ /* Serdev interface */ DEVMETHOD(serdev_ihand, uart_bus_ihand), DEVMETHOD(serdev_ipend, uart_bus_ipend), + DEVMETHOD(serdev_adjust_rclk, uart_puc_adjust_rclk), { 0, 0 } }; @@ -84,6 +86,20 @@ if (BUS_READ_IVAR(parent, dev, PUC_IVAR_CLOCK, &rclk)) rclk = 0; return (uart_bus_probe(dev, 0, 0, rclk, 0, 0, 0)); +} + +static void +uart_puc_adjust_rclk(device_t dev, void *bptr) +{ + struct baud_fraction *baud = bptr; + struct uart_softc *sc = device_get_softc(dev); + device_t parent; + uintptr_t rclk; + + parent = device_get_parent(sc->sc_dev); + BUS_WRITE_IVAR(parent, sc->sc_dev, PUC_IVAR_TARGETBAUD, (uintptr_t)baud); + if (BUS_READ_IVAR(parent, sc->sc_dev, PUC_IVAR_CLOCK, &rclk) == 0) + sc->sc_bas.rclk = rclk; } DRIVER_MODULE(uart, puc, uart_puc_driver, uart_devclass, 0, 0); Index: sys/dev/uart/uart_dev_ns8250.c =================================================================== --- sys/dev/uart/uart_dev_ns8250.c +++ sys/dev/uart/uart_dev_ns8250.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #ifdef FDT @@ -148,7 +149,32 @@ return (divisor); } +/* + * As above, but takes a fractional baudrate. + * This one currently does NOT enforce a maximum deviation. + */ static int +ns8250_fdivisor(int rclk, int baudrate_n, int baudrate_d) +{ + int divisor; + int divisor_n, divisor_d; + + if (baudrate_n == 0 || baudrate_d == 0) + return (0); + + divisor_n = rclk * baudrate_d; + divisor_d = baudrate_n; + + divisor = (divisor_n / (divisor_d << 3) + 1) >> 1; + if (divisor <= 0 || divisor > 65535) + return (0); + + /* TODO: Enforce max 3% error in actual baudrate */ + + return (divisor); +} + +static int ns8250_drain(struct uart_bas *bas, int what) { int delay, limit; @@ -631,9 +657,11 @@ int ns8250_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) { + struct ns8250_softc *ns8250 = (struct ns8250_softc *)sc; struct uart_bas *bas; int baudrate, divisor, error; uint8_t efr, lcr; + struct baud_fraction *bf; bas = &sc->sc_bas; error = 0; @@ -693,6 +721,47 @@ else error = ENXIO; break; + case UART_IOCTL_SET_FBAUD: { + /* Set baudrate. */ + bf = (struct baud_fraction *)data; + + divisor = ns8250_fdivisor(bas->rclk, bf->bf_numerator, bf->bf_denominator); + if (divisor == 0) { + error = EINVAL; + break; + } + lcr = uart_getreg(bas, REG_LCR); + uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); + uart_barrier(bas); + uart_setreg(bas, REG_DLL, divisor & 0xff); + uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff); + uart_barrier(bas); + uart_setreg(bas, REG_LCR, lcr); + uart_barrier(bas); + ns8250->mcr = uart_getreg(bas, REG_MCR); + sc->sc_u.u_tty.tp->t_termios.c_ispeed = ((bas->rclk / (divisor << 3)) + 1) >> 1; + sc->sc_u.u_tty.tp->t_termios.c_ospeed = sc->sc_u.u_tty.tp->t_termios.c_ispeed; + break; + case UART_IOCTL_GET_FBAUD: { + bf = (struct baud_fraction *)data; + + lcr = uart_getreg(bas, REG_LCR); + uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); + uart_barrier(bas); + divisor = uart_getreg(bas, REG_DLL) | + (uart_getreg(bas, REG_DLH) << 8); + uart_barrier(bas); + uart_setreg(bas, REG_LCR, lcr); + uart_barrier(bas); + if (divisor <= 0) + error = ENXIO; + else { + bf->bf_numerator = bas->rclk; + bf->bf_denominator = divisor << 4; + } + break; + } + } default: error = EINVAL; break; @@ -779,6 +848,7 @@ } } + ns8250->mcr = uart_getreg(bas, REG_MCR); error = ns8250_param(bas, baudrate, databits, stopbits, parity); uart_unlock(sc->sc_hwmtx); return (error); Index: sys/dev/uart/uart_tty.c =================================================================== --- sys/dev/uart/uart_tty.c +++ sys/dev/uart/uart_tty.c @@ -49,6 +49,8 @@ #include #include +#include + #include "uart_if.h" static cn_probe_t uart_cnprobe; @@ -251,6 +253,13 @@ case TIOCCBRK: UART_IOCTL(sc, UART_IOCTL_BREAK, 0); return (0); + case TIOCSFBAUD: + SERDEV_ADJUST_RCLK(sc->sc_dev, (struct baud_fraction *)data); + UART_IOCTL(sc, UART_IOCTL_SET_FBAUD, (intptr_t)data); + return (0); + case TIOCGFBAUD: + UART_IOCTL(sc, UART_IOCTL_GET_FBAUD, (intptr_t)data); + return (0); default: return pps_ioctl(cmd, data, &sc->sc_pps); } @@ -261,6 +270,7 @@ { struct uart_softc *sc; int databits, parity, stopbits; + struct baud_fraction bf; sc = tty_softc(tp); if (sc == NULL || sc->sc_leaving) @@ -283,15 +293,21 @@ UART_PARITY_EVEN; else parity = UART_PARITY_NONE; + bf.bf_numerator = t->c_ospeed; + bf.bf_denominator = 1; + SERDEV_ADJUST_RCLK(sc->sc_dev, &bf); if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0) return (EINVAL); - UART_SETSIG(sc, SER_DDTR | SER_DTR); + if ((t->c_cflag & CNO_RTSDTR) == 0) + UART_SETSIG(sc, SER_DDTR | SER_DTR); /* Set input flow control state. */ if (!sc->sc_hwiflow) { if ((t->c_cflag & CRTS_IFLOW) && sc->sc_isquelch) UART_SETSIG(sc, SER_DRTS); - else - UART_SETSIG(sc, SER_DRTS | SER_RTS); + else { + if ((t->c_cflag & CNO_RTSDTR) == 0) + UART_SETSIG(sc, SER_DRTS | SER_RTS); + } } else UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW)); /* Set output flow control state. */ Index: sys/kern/serdev_if.m =================================================================== --- sys/kern/serdev_if.m +++ sys/kern/serdev_if.m @@ -60,6 +60,12 @@ { return (0); } + + static void + default_adjust_rclk(device_t dev, void *bf) + { + return; + } }; # ihand() - Query serial device interrupt handler. @@ -92,3 +98,9 @@ device_t dev; } DEFAULT default_sysdev; +# adjust_rclk() - request rclk be adjusted to allow the specified +# fractional baud rate to be configured. +METHOD void adjust_rclk { + device_t dev; + void *baudrate; +} DEFAULT default_adjust_rclk; Index: sys/kern/tty.c =================================================================== --- sys/kern/tty.c +++ sys/kern/tty.c @@ -92,7 +92,7 @@ FLUSHO|NOKERNINFO|NOFLSH) #define TTYSUP_CFLAG (CIGNORE|CSIZE|CSTOPB|CREAD|PARENB|PARODD|\ HUPCL|CLOCAL|CCTS_OFLOW|CRTS_IFLOW|CDTR_IFLOW|\ - CDSR_OFLOW|CCAR_OFLOW) + CDSR_OFLOW|CCAR_OFLOW|CNO_RTSDTR) #define TTY_CALLOUT(tp,d) (dev2unit(d) & TTYUNIT_CALLOUT) @@ -325,7 +325,8 @@ if (TTY_CALLOUT(tp, dev) || dev == dev_console) tp->t_termios.c_cflag |= CLOCAL; - ttydevsw_modem(tp, SER_DTR|SER_RTS, 0); + if ((tp->t_termios.c_cflag & CNO_RTSDTR) == 0) + ttydevsw_modem(tp, SER_DTR|SER_RTS, 0); error = ttydevsw_open(tp); if (error != 0) @@ -614,6 +615,20 @@ new->c_ospeed = old->c_ospeed; } + if (cmd == TIOCSFBAUD) { + struct termios *lock = TTY_CALLOUT(tp, dev) ? + &tp->t_termios_lock_out : &tp->t_termios_lock_in; + + /* For lock state devices, just fail */ + if (lock->c_ispeed || lock->c_ospeed) { + error = EINVAL; + goto done; + } + error = tty_drain(tp, 0); + if (error) + goto done; + } + error = tty_ioctl(tp, cmd, data, fflag, td); done: tty_unlock(tp); @@ -1887,6 +1902,10 @@ error = ttydevsw_ioctl(tp, cmd, data, td); if (error == ENOIOCTL) error = tty_generic_ioctl(tp, cmd, data, fflag, td); + else { + if (cmd == TIOCSFBAUD) + error = tty_watermarks(tp); + } return (error); } Index: sys/sys/_termios.h =================================================================== --- sys/sys/_termios.h +++ sys/sys/_termios.h @@ -143,6 +143,7 @@ #define CDTR_IFLOW 0x00040000 /* DTR flow control of input */ #define CDSR_OFLOW 0x00080000 /* DSR flow control of output */ #define CCAR_OFLOW 0x00100000 /* DCD flow control of output */ +#define CNO_RTSDTR 0x00200000 /* Do not assert RTS or DTR automatically */ #endif Index: sys/sys/ttycom.h =================================================================== --- sys/sys/ttycom.h +++ sys/sys/ttycom.h @@ -58,6 +58,14 @@ unsigned short ws_ypixel; /* vertical size, pixels */ }; +/* + * Fractional baudrate. Used by TIOCSFBAUD and TIOCGFBAUD + */ +struct baud_fraction { + int bf_numerator; + int bf_denominator; +}; + /* 0-2 compat */ /* 3-7 unused */ /* 8-10 compat */ @@ -137,6 +145,8 @@ #define TIOCCBRK _IO('t', 122) /* clear break bit */ #define TIOCSBRK _IO('t', 123) /* set break bit */ /* 124-127 compat */ +#define TIOCSFBAUD _IOW('t', 128, struct baud_fraction) /* Set fractional baudrate */ +#define TIOCGFBAUD _IOR('t', 129, struct baud_fraction) /* Get fractional baudrate */ #define TTYDISC 0 /* termios tty line discipline */ #define SLIPDISC 4 /* serial IP discipline */