Page MenuHomeFreeBSD

D16402.id47244.diff
No OneTemporary

D16402.id47244.diff

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 <dev/puc/puc_cfg.h>
#include <dev/puc/puc_bfe.h>
-#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 <sys/serial.h>
+
#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 <sys/kernel.h>
#include <sys/bus.h>
#include <sys/sysctl.h>
+#include <sys/limits.h>
+#include <sys/ttycom.h>
#include <machine/resource.h>
#include <machine/bus.h>
@@ -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<<d) * a;
+}
+
+/*
+ * Reduces a fraction
+ */
+static void
+puc_util_fract_reduce(struct puc_util_fract *f)
+{
+ uint64_t d = puc_util_gcd(f->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 <sys/serial.h>
#include <sys/timepps.h>
+#include <sys/ttycom.h>
/* 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 <dev/uart/uart_bus.h>
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 <sys/conf.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
+#include <sys/tty.h>
#include <machine/bus.h>
#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 <dev/uart/uart_bus.h>
#include <dev/uart/uart_cpu.h>
+#include <dev/puc/puc_bus.h>
+
#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 */

File Metadata

Mime Type
text/plain
Expires
Thu, Mar 13, 5:05 AM (16 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17130253
Default Alt Text
D16402.id47244.diff (20 KB)

Event Timeline