Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F112046792
D16402.id45753.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D16402.id45753.diff
View Options
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->div > 65535) {
+ 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 class & instance (=softc)
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));
+}
+
+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
@@ -38,6 +38,7 @@
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
+#include <sys/tty.h>
#include <machine/bus.h>
#ifdef FDT
@@ -144,7 +145,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;
@@ -610,6 +636,7 @@
struct uart_bas *bas;
int baudrate, divisor, error;
uint8_t efr, lcr;
+ struct baud_fraction *bf;
bas = &sc->sc_bas;
error = 0;
@@ -669,6 +696,46 @@
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);
+ 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;
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,6 +293,9 @@
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);
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
@@ -614,6 +614,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);
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
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 13, 1:44 AM (13 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17128536
Default Alt Text
D16402.id45753.diff (18 KB)
Attached To
Mode
D16402: Add TIOCFBAUD UART ioctl to allow fractional baudrates
Attached
Detach File
Event Timeline
Log In to Comment