summaryrefslogtreecommitdiffstats
path: root/sys/dev/uart
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2007-04-02 22:00:22 +0000
committermarcel <marcel@FreeBSD.org>2007-04-02 22:00:22 +0000
commitf30daf4b49b0b9e3c8eeb46082244bf7a7f354ae (patch)
treeb3ad51f3cb65c3badfb015aea4f71d800157abb8 /sys/dev/uart
parent5f0f57215ba83757397d27e8dcc686612e48e921 (diff)
downloadFreeBSD-src-f30daf4b49b0b9e3c8eeb46082244bf7a7f354ae.zip
FreeBSD-src-f30daf4b49b0b9e3c8eeb46082244bf7a7f354ae.tar.gz
Don't expose the uart_ops structure directly, but instead have
it obtained through the uart_class structure. This allows us to declare the uart_class structure as weak and as such allows us to reference it even when it's not compiled-in. It also allows is to get the uart_ops structure by name, which makes it possible to implement the dt tag handling in uart_getenv(). The side-effect of all this is that we're using the uart_class structure more consistently which means that we now also have access to the size of the bus space block needed by the hardware when we map the bus space, eliminating any hardcoding.
Diffstat (limited to 'sys/dev/uart')
-rw-r--r--sys/dev/uart/uart.h9
-rw-r--r--sys/dev/uart/uart_bus.h5
-rw-r--r--sys/dev/uart/uart_core.c37
-rw-r--r--sys/dev/uart/uart_cpu.h29
-rw-r--r--sys/dev/uart/uart_cpu_amd64.c13
-rw-r--r--sys/dev/uart/uart_cpu_i386.c13
-rw-r--r--sys/dev/uart/uart_cpu_ia64.c14
-rw-r--r--sys/dev/uart/uart_cpu_pc98.c13
-rw-r--r--sys/dev/uart/uart_cpu_powerpc.c7
-rw-r--r--sys/dev/uart/uart_cpu_sparc64.c19
-rw-r--r--sys/dev/uart/uart_dev_ns8250.c5
-rw-r--r--sys/dev/uart/uart_dev_sab82532.c5
-rw-r--r--sys/dev/uart/uart_dev_z8530.c5
-rw-r--r--sys/dev/uart/uart_kbd_sun.c4
-rw-r--r--sys/dev/uart/uart_subr.c50
15 files changed, 165 insertions, 63 deletions
diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h
index da9bd1b..f4320d4 100644
--- a/sys/dev/uart/uart.h
+++ b/sys/dev/uart/uart.h
@@ -60,6 +60,15 @@ struct uart_bas {
BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
/*
+ * UART device classes.
+ */
+struct uart_class;
+
+extern struct uart_class uart_ns8250_class __attribute__((weak));
+extern struct uart_class uart_sab82532_class __attribute__((weak));
+extern struct uart_class uart_z8530_class __attribute__((weak));
+
+/*
* Device flags.
*/
#define UART_FLAGS_CONSOLE(f) ((f) & 0x10)
diff --git a/sys/dev/uart/uart_bus.h b/sys/dev/uart/uart_bus.h
index 5396515..7154d85 100644
--- a/sys/dev/uart/uart_bus.h
+++ b/sys/dev/uart/uart_bus.h
@@ -67,14 +67,11 @@
*/
struct uart_class {
KOBJ_CLASS_FIELDS;
+ struct uart_ops *uc_ops; /* Low-level console operations. */
u_int uc_range; /* Bus space address range. */
u_int uc_rclk; /* Default rclk for this device. */
};
-extern struct uart_class uart_ns8250_class;
-extern struct uart_class uart_sab82532_class;
-extern struct uart_class uart_z8530_class;
-
struct uart_softc {
KOBJ_FIELDS;
struct uart_class *sc_class;
diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c
index 6daf938..f991278 100644
--- a/sys/dev/uart/uart_core.c
+++ b/sys/dev/uart/uart_core.c
@@ -70,6 +70,24 @@ uart_add_sysdev(struct uart_devinfo *di)
SLIST_INSERT_HEAD(&uart_sysdevs, di, next);
}
+const char *
+uart_getname(struct uart_class *uc)
+{
+ return ((uc != NULL) ? uc->name : NULL);
+}
+
+struct uart_ops *
+uart_getops(struct uart_class *uc)
+{
+ return ((uc != NULL) ? uc->uc_ops : NULL);
+}
+
+int
+uart_getrange(struct uart_class *uc)
+{
+ return ((uc != NULL) ? uc->uc_range : 0);
+}
+
/*
* Schedule a soft interrupt. We do this on the 0 to !0 transition
* of the TTY pending interrupt status.
@@ -293,6 +311,15 @@ uart_bus_probe(device_t dev, int regshft, int rclk, int rid, int chan)
struct uart_devinfo *sysdev;
int error;
+ sc = device_get_softc(dev);
+
+ /*
+ * All uart_class references are weak. Check that the needed
+ * class has been compiled-in. Fail if not.
+ */
+ if (sc->sc_class == NULL)
+ return (ENXIO);
+
/*
* Initialize the instance. Note that the instance (=softc) does
* not necessarily match the hardware specific softc. We can't do
@@ -300,11 +327,10 @@ uart_bus_probe(device_t dev, int regshft, int rclk, int rid, int chan)
* Hardware drivers cannot use any of the class specific fields
* while probing.
*/
- sc = device_get_softc(dev);
kobj_init((kobj_t)sc, (kobj_class_t)sc->sc_class);
sc->sc_dev = dev;
if (device_get_desc(dev) == NULL)
- device_set_desc(dev, sc->sc_class->name);
+ device_set_desc(dev, uart_getname(sc->sc_class));
/*
* Allocate the register resource. We assume that all UARTs have
@@ -316,12 +342,13 @@ uart_bus_probe(device_t dev, int regshft, int rclk, int rid, int chan)
sc->sc_rrid = rid;
sc->sc_rtype = SYS_RES_IOPORT;
sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
- 0, ~0, sc->sc_class->uc_range, RF_ACTIVE);
+ 0, ~0, uart_getrange(sc->sc_class), RF_ACTIVE);
if (sc->sc_rres == NULL) {
sc->sc_rrid = rid;
sc->sc_rtype = SYS_RES_MEMORY;
sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype,
- &sc->sc_rrid, 0, ~0, sc->sc_class->uc_range, RF_ACTIVE);
+ &sc->sc_rrid, 0, ~0, uart_getrange(sc->sc_class),
+ RF_ACTIVE);
if (sc->sc_rres == NULL)
return (ENXIO);
}
@@ -390,7 +417,7 @@ uart_bus_attach(device_t dev)
* collected by uart_bus_probe() intact.
*/
sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid,
- 0, ~0, sc->sc_class->uc_range, RF_ACTIVE);
+ 0, ~0, uart_getrange(sc->sc_class), RF_ACTIVE);
if (sc->sc_rres == NULL) {
mtx_destroy(&sc->sc_hwmtx_s);
return (ENXIO);
diff --git a/sys/dev/uart/uart_cpu.h b/sys/dev/uart/uart_cpu.h
index b41ed50..db64d49 100644
--- a/sys/dev/uart/uart_cpu.h
+++ b/sys/dev/uart/uart_cpu.h
@@ -45,11 +45,6 @@ struct uart_ops {
int (*getc)(struct uart_bas *, struct mtx *);
};
-extern struct uart_ops uart_i8251_ops;
-extern struct uart_ops uart_ns8250_ops;
-extern struct uart_ops uart_sab82532_ops;
-extern struct uart_ops uart_z8530_ops;
-
extern bus_space_tag_t uart_bus_space_io;
extern bus_space_tag_t uart_bus_space_mem;
@@ -59,7 +54,7 @@ extern bus_space_tag_t uart_bus_space_mem;
struct uart_softc;
struct uart_devinfo {
SLIST_ENTRY(uart_devinfo) next;
- struct uart_ops ops;
+ struct uart_ops *ops;
struct uart_bas bas;
int baudrate;
int databits;
@@ -77,7 +72,11 @@ struct uart_devinfo {
int uart_cpu_eqres(struct uart_bas *, struct uart_bas *);
int uart_cpu_getdev(int, struct uart_devinfo *);
-int uart_getenv(int, struct uart_devinfo *);
+
+int uart_getenv(int, struct uart_devinfo *, struct uart_class *);
+const char *uart_getname(struct uart_class *);
+struct uart_ops *uart_getops(struct uart_class *);
+int uart_getrange(struct uart_class *);
void uart_add_sysdev(struct uart_devinfo *);
@@ -106,7 +105,7 @@ uart_probe(struct uart_devinfo *di)
int res;
uart_lock(di->hwmtx);
- res = di->ops.probe(&di->bas);
+ res = di->ops->probe(&di->bas);
uart_unlock(di->hwmtx);
return (res);
}
@@ -115,7 +114,7 @@ static __inline void
uart_init(struct uart_devinfo *di)
{
uart_lock(di->hwmtx);
- di->ops.init(&di->bas, di->baudrate, di->databits, di->stopbits,
+ di->ops->init(&di->bas, di->baudrate, di->databits, di->stopbits,
di->parity);
uart_unlock(di->hwmtx);
}
@@ -124,7 +123,7 @@ static __inline void
uart_term(struct uart_devinfo *di)
{
uart_lock(di->hwmtx);
- di->ops.term(&di->bas);
+ di->ops->term(&di->bas);
uart_unlock(di->hwmtx);
}
@@ -132,7 +131,7 @@ static __inline void
uart_putc(struct uart_devinfo *di, int c)
{
uart_lock(di->hwmtx);
- di->ops.putc(&di->bas, c);
+ di->ops->putc(&di->bas, c);
uart_unlock(di->hwmtx);
}
@@ -142,7 +141,7 @@ uart_rxready(struct uart_devinfo *di)
int res;
uart_lock(di->hwmtx);
- res = di->ops.rxready(&di->bas);
+ res = di->ops->rxready(&di->bas);
uart_unlock(di->hwmtx);
return (res);
}
@@ -153,8 +152,8 @@ uart_poll(struct uart_devinfo *di)
int res;
uart_lock(di->hwmtx);
- if (di->ops.rxready(&di->bas))
- res = di->ops.getc(&di->bas, NULL);
+ if (di->ops->rxready(&di->bas))
+ res = di->ops->getc(&di->bas, NULL);
else
res = -1;
uart_unlock(di->hwmtx);
@@ -165,7 +164,7 @@ static __inline int
uart_getc(struct uart_devinfo *di)
{
- return (di->ops.getc(&di->bas, di->hwmtx));
+ return (di->ops->getc(&di->bas, di->hwmtx));
}
#endif /* _DEV_UART_CPU_H_ */
diff --git a/sys/dev/uart/uart_cpu_amd64.c b/sys/dev/uart/uart_cpu_amd64.c
index fb8b994..3624f79 100644
--- a/sys/dev/uart/uart_cpu_amd64.c
+++ b/sys/dev/uart/uart_cpu_amd64.c
@@ -49,11 +49,15 @@ uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
+ struct uart_class *class;
unsigned int i, ivar;
+ class = &uart_ns8250_class;
+ if (class == NULL)
+ return (ENXIO);
+
/* Check the environment. */
- di->ops = uart_ns8250_ops;
- if (uart_getenv(devtype, di) == 0)
+ if (uart_getenv(devtype, di, class) == 0)
return (0);
/*
@@ -82,10 +86,11 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
* Got it. Fill in the instance and return it. We only have
* ns8250 and successors on i386.
*/
- di->ops = uart_ns8250_ops;
+ di->ops = uart_getops(class);
di->bas.chan = 0;
di->bas.bst = uart_bus_space_io;
- if (bus_space_map(di->bas.bst, ivar, 8, 0, &di->bas.bsh) != 0)
+ if (bus_space_map(di->bas.bst, ivar, uart_getrange(class), 0,
+ &di->bas.bsh) != 0)
continue;
di->bas.regshft = 0;
di->bas.rclk = 0;
diff --git a/sys/dev/uart/uart_cpu_i386.c b/sys/dev/uart/uart_cpu_i386.c
index c8e2e2e..0d0f0f7 100644
--- a/sys/dev/uart/uart_cpu_i386.c
+++ b/sys/dev/uart/uart_cpu_i386.c
@@ -49,11 +49,15 @@ uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
+ struct uart_class *class;
unsigned int i, ivar;
+ class = &uart_ns8250_class;
+ if (class == NULL)
+ return (ENXIO);
+
/* Check the environment. */
- di->ops = uart_ns8250_ops;
- if (uart_getenv(devtype, di) == 0)
+ if (uart_getenv(devtype, di, class) == 0)
return (0);
/*
@@ -82,10 +86,11 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
* Got it. Fill in the instance and return it. We only have
* ns8250 and successors on i386.
*/
- di->ops = uart_ns8250_ops;
+ di->ops = uart_getops(class);
di->bas.chan = 0;
di->bas.bst = uart_bus_space_io;
- if (bus_space_map(di->bas.bst, ivar, 8, 0, &di->bas.bsh) != 0)
+ if (bus_space_map(di->bas.bst, ivar, uart_getrange(class), 0,
+ &di->bas.bsh) != 0)
continue;
di->bas.regshft = 0;
di->bas.rclk = 0;
diff --git a/sys/dev/uart/uart_cpu_ia64.c b/sys/dev/uart/uart_cpu_ia64.c
index 4960492..9a71e20 100644
--- a/sys/dev/uart/uart_cpu_ia64.c
+++ b/sys/dev/uart/uart_cpu_ia64.c
@@ -59,10 +59,15 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
struct dig64_hcdp_table *tbl;
struct dig64_hcdp_entry *ent;
+ struct uart_class *class;
bus_addr_t addr;
uint64_t hcdp;
unsigned int i;
+ class = &uart_ns8250_class;
+ if (class == NULL)
+ return (ENXIO);
+
/*
* Use the DIG64 HCDP table if present.
*/
@@ -82,12 +87,12 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
addr = ent->address.addr_high;
addr = (addr << 32) + ent->address.addr_low;
- di->ops = uart_ns8250_ops;
+ di->ops = uart_getops(class);
di->bas.chan = 0;
di->bas.bst = (ent->address.addr_space == 0)
? uart_bus_space_mem : uart_bus_space_io;
- if (bus_space_map(di->bas.bst, addr, 8, 0,
- &di->bas.bsh) != 0)
+ if (bus_space_map(di->bas.bst, addr,
+ uart_getrange(class), 0, &di->bas.bsh) != 0)
continue;
di->bas.regshft = 0;
di->bas.rclk = ent->pclock << 4;
@@ -104,6 +109,5 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
}
/* Check the environment. */
- di->ops = uart_ns8250_ops;
- return (uart_getenv(devtype, di));
+ return (uart_getenv(devtype, di, class));
}
diff --git a/sys/dev/uart/uart_cpu_pc98.c b/sys/dev/uart/uart_cpu_pc98.c
index 0887a67..c0c1f4e 100644
--- a/sys/dev/uart/uart_cpu_pc98.c
+++ b/sys/dev/uart/uart_cpu_pc98.c
@@ -49,11 +49,15 @@ uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
+ struct uart_class *class;
unsigned int i, ivar, flags;
+ class = &uart_ns8250_class;
+ if (class == NULL)
+ return (ENXIO);
+
/* Check the environment. */
- di->ops = uart_ns8250_ops;
- if (uart_getenv(devtype, di) == 0)
+ if (uart_getenv(devtype, di, class) == 0)
return (0);
/*
@@ -81,10 +85,11 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
ivar == 0)
continue;
- di->ops = uart_ns8250_ops;
+ di->ops = uart_getops(class);
di->bas.chan = 0;
di->bas.bst = uart_bus_space_io;
- if (bus_space_map(di->bas.bst, ivar, 8, 0, &di->bas.bsh) != 0)
+ if (bus_space_map(di->bas.bst, ivar, uart_getrange(class), 0,
+ &di->bas.bsh) != 0)
continue;
di->bas.regshft = 0;
di->bas.rclk = 0;
diff --git a/sys/dev/uart/uart_cpu_powerpc.c b/sys/dev/uart/uart_cpu_powerpc.c
index 53f57dc..6647c7d 100644
--- a/sys/dev/uart/uart_cpu_powerpc.c
+++ b/sys/dev/uart/uart_cpu_powerpc.c
@@ -52,9 +52,14 @@ int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
char buf[64];
+ struct uart_class *class;
phandle_t input, opts;
int error;
+ class = &uart_z8530_class;
+ if (class == NULL)
+ return (ENXIO);
+
if ((opts = OF_finddevice("/options")) == -1)
return (ENXIO);
switch (devtype) {
@@ -93,7 +98,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
if (error)
return (error);
- di->ops = uart_z8530_ops;
+ di->ops = uart_getops(class);
di->bas.rclk = 230400;
di->bas.chan = 1;
diff --git a/sys/dev/uart/uart_cpu_sparc64.c b/sys/dev/uart/uart_cpu_sparc64.c
index efe0283..9d92a39 100644
--- a/sys/dev/uart/uart_cpu_sparc64.c
+++ b/sys/dev/uart/uart_cpu_sparc64.c
@@ -194,9 +194,10 @@ int
uart_cpu_getdev(int devtype, struct uart_devinfo *di)
{
char buf[32], compat[32], dev[64];
+ struct uart_class *class;
phandle_t input, options;
bus_addr_t addr;
- int baud, bits, error, space, stop;
+ int baud, bits, error, range, space, stop;
char flag, par;
if ((options = OF_finddevice("/options")) == -1)
@@ -228,14 +229,15 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
compat[0] = '\0';
di->bas.regshft = 0;
di->bas.rclk = 0;
+ class = NULL;
if (!strcmp(buf, "se") || !strcmp(compat, "sab82532")) {
- di->ops = uart_sab82532_ops;
+ class = &uart_sab82532_class;
/* SAB82532 are only known to be used for TTYs. */
if ((di->bas.chan = uart_cpu_channel(dev)) == 0)
return (ENXIO);
- addr += 64 * (di->bas.chan - 1);
+ addr += uart_getrange(class) * (di->bas.chan - 1);
} else if (!strcmp(buf, "zs")) {
- di->ops = uart_z8530_ops;
+ class = &uart_z8530_class;
if ((di->bas.chan = uart_cpu_channel(dev)) == 0) {
/*
* There's no way to determine from OF which
@@ -248,16 +250,19 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di)
return (ENXIO);
}
di->bas.regshft = 1;
- addr += 4 - 4 * (di->bas.chan - 1);
+ range = uart_getrange(class) << di->bas.regshft;
+ addr += range - range * (di->bas.chan - 1);
} else if (!strcmp(buf, "lom-console") || !strcmp(buf, "su") ||
!strcmp(buf, "su_pnp") || !strcmp(compat, "rsc-console") ||
!strcmp(compat, "su") || !strcmp(compat, "su16550")) {
- di->ops = uart_ns8250_ops;
+ class = &uart_ns8250_class;
di->bas.chan = 0;
- } else
+ }
+ if (class == NULL)
return (ENXIO);
/* Fill in the device info. */
+ di->ops = uart_getops(class);
di->bas.bst = &bst_store[devtype];
di->bas.bsh = sparc64_fake_bustag(space, addr, di->bas.bst);
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index 8e6177b..4e51417 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -222,7 +222,7 @@ static void ns8250_putc(struct uart_bas *bas, int);
static int ns8250_rxready(struct uart_bas *bas);
static int ns8250_getc(struct uart_bas *bas, struct mtx *);
-struct uart_ops uart_ns8250_ops = {
+static struct uart_ops uart_ns8250_ops = {
.probe = ns8250_probe,
.init = ns8250_init,
.term = ns8250_term,
@@ -368,9 +368,10 @@ static kobj_method_t ns8250_methods[] = {
};
struct uart_class uart_ns8250_class = {
- "ns8250 class",
+ "ns8250",
ns8250_methods,
sizeof(struct ns8250_softc),
+ .uc_ops = &uart_ns8250_ops,
.uc_range = 8,
.uc_rclk = DEFAULT_RCLK
};
diff --git a/sys/dev/uart/uart_dev_sab82532.c b/sys/dev/uart/uart_dev_sab82532.c
index e10ae17..11cdb4b 100644
--- a/sys/dev/uart/uart_dev_sab82532.c
+++ b/sys/dev/uart/uart_dev_sab82532.c
@@ -176,7 +176,7 @@ static void sab82532_putc(struct uart_bas *bas, int);
static int sab82532_rxready(struct uart_bas *bas);
static int sab82532_getc(struct uart_bas *bas, struct mtx *);
-struct uart_ops uart_sab82532_ops = {
+static struct uart_ops uart_sab82532_ops = {
.probe = sab82532_probe,
.init = sab82532_init,
.term = sab82532_term,
@@ -382,9 +382,10 @@ static kobj_method_t sab82532_methods[] = {
};
struct uart_class uart_sab82532_class = {
- "sab82532 class",
+ "sab82532",
sab82532_methods,
sizeof(struct sab82532_softc),
+ .uc_ops = &uart_sab82532_ops,
.uc_range = 64,
.uc_rclk = DEFAULT_RCLK
};
diff --git a/sys/dev/uart/uart_dev_z8530.c b/sys/dev/uart/uart_dev_z8530.c
index 8509718..33bacdc 100644
--- a/sys/dev/uart/uart_dev_z8530.c
+++ b/sys/dev/uart/uart_dev_z8530.c
@@ -195,7 +195,7 @@ static void z8530_putc(struct uart_bas *bas, int);
static int z8530_rxready(struct uart_bas *bas);
static int z8530_getc(struct uart_bas *bas, struct mtx *);
-struct uart_ops uart_z8530_ops = {
+static struct uart_ops uart_z8530_ops = {
.probe = z8530_probe,
.init = z8530_init,
.term = z8530_term,
@@ -298,9 +298,10 @@ static kobj_method_t z8530_methods[] = {
};
struct uart_class uart_z8530_class = {
- "z8530 class",
+ "z8530",
z8530_methods,
sizeof(struct z8530_softc),
+ .uc_ops = &uart_z8530_ops,
.uc_range = 2,
.uc_rclk = DEFAULT_RCLK
};
diff --git a/sys/dev/uart/uart_kbd_sun.c b/sys/dev/uart/uart_kbd_sun.c
index 7395f9d..78238a7 100644
--- a/sys/dev/uart/uart_kbd_sun.c
+++ b/sys/dev/uart/uart_kbd_sun.c
@@ -712,8 +712,8 @@ sunkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t data)
if (*(int *)data & SLKED)
c |= SKBD_LED_SCROLLLOCK;
uart_lock(sc->sc_sysdev->hwmtx);
- sc->sc_sysdev->ops.putc(&sc->sc_sysdev->bas, SKBD_CMD_SETLED);
- sc->sc_sysdev->ops.putc(&sc->sc_sysdev->bas, c);
+ sc->sc_sysdev->ops->putc(&sc->sc_sysdev->bas, SKBD_CMD_SETLED);
+ sc->sc_sysdev->ops->putc(&sc->sc_sysdev->bas, c);
uart_unlock(sc->sc_sysdev->hwmtx);
KBD_LED_VAL(kbd) = *(int *)data;
break;
diff --git a/sys/dev/uart/uart_subr.c b/sys/dev/uart/uart_subr.c
index c9b6fe7..2cab825 100644
--- a/sys/dev/uart/uart_subr.c
+++ b/sys/dev/uart/uart_subr.c
@@ -48,12 +48,41 @@ __FBSDID("$FreeBSD$");
#define UART_TAG_SB 8
#define UART_TAG_XO 9
+static struct uart_class *uart_classes[] = {
+ &uart_ns8250_class,
+ &uart_sab82532_class,
+ &uart_z8530_class,
+};
+static size_t uart_nclasses = sizeof(uart_classes) / sizeof(uart_classes[0]);
+
static bus_addr_t
uart_parse_addr(__const char **p)
{
return (strtoul(*p, (char**)(uintptr_t)p, 0));
}
+static struct uart_class *
+uart_parse_class(struct uart_class *class, __const char **p)
+{
+ struct uart_class *uc;
+ const char *nm;
+ size_t len;
+ u_int i;
+
+ for (i = 0; i < uart_nclasses; i++) {
+ uc = uart_classes[i];
+ nm = uart_getname(uc);
+ if (nm == NULL || *nm == '\0')
+ continue;
+ len = strlen(nm);
+ if (strncmp(nm, *p, len) == 0) {
+ *p += len;
+ return (uc);
+ }
+ }
+ return (class);
+}
+
static long
uart_parse_long(__const char **p)
{
@@ -161,10 +190,18 @@ out:
*/
int
-uart_getenv(int devtype, struct uart_devinfo *di)
+uart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class)
{
__const char *spec;
bus_addr_t addr = ~0U;
+ int error;
+
+ /*
+ * All uart_class references are weak. Make sure the default
+ * device class has been compiled-in.
+ */
+ if (class == NULL)
+ return (ENXIO);
/*
* Check the environment variables "hw.uart.console" and
@@ -203,7 +240,7 @@ uart_getenv(int devtype, struct uart_devinfo *di)
di->databits = uart_parse_long(&spec);
break;
case UART_TAG_DT:
- return (EINVAL); /* XXX not yet implemented. */
+ class = uart_parse_class(class, &spec);
break;
case UART_TAG_IO:
di->bas.bst = uart_bus_space_io;
@@ -261,8 +298,9 @@ uart_getenv(int devtype, struct uart_devinfo *di)
} else
di->baudrate = 0;
- /* XXX the size of the mapping depends on the UART class. */
- if (bus_space_map(di->bas.bst, addr, 8, 0, &di->bas.bsh) != 0)
- return (EINVAL);
- return (0);
+ /* Set the ops and create a bus space handle. */
+ di->ops = uart_getops(class);
+ error = bus_space_map(di->bas.bst, addr, uart_getrange(class), 0,
+ &di->bas.bsh);
+ return (error);
}
OpenPOWER on IntegriCloud