#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/scc/scc_bus.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_bus.h>
static int uart_scc_attach(device_t dev);
static int uart_scc_probe(device_t dev);
static device_method_t uart_scc_methods[] = {
DEVMETHOD(device_probe, uart_scc_probe),
DEVMETHOD(device_attach, uart_scc_attach),
DEVMETHOD(device_detach, uart_bus_detach),
DEVMETHOD(serdev_ihand, uart_bus_ihand),
DEVMETHOD(serdev_sysdev, uart_bus_sysdev),
DEVMETHOD_END
};
static driver_t uart_scc_driver = {
uart_driver_name,
uart_scc_methods,
sizeof(struct uart_softc),
};
static int
uart_scc_attach(device_t dev)
{
device_t parent;
struct uart_softc *sc;
uintptr_t mtx;
parent = device_get_parent(dev);
sc = device_get_softc(dev);
if (BUS_READ_IVAR(parent, dev, SCC_IVAR_HWMTX, &mtx))
return (ENXIO);
sc->sc_hwmtx = (struct mtx *)(void *)mtx;
return (uart_bus_attach(dev));
}
static int
uart_scc_probe(device_t dev)
{
device_t parent;
struct uart_softc *sc;
uintptr_t ch, cl, md, rs;
parent = device_get_parent(dev);
sc = device_get_softc(dev);
if (BUS_READ_IVAR(parent, dev, SCC_IVAR_MODE, &md) ||
BUS_READ_IVAR(parent, dev, SCC_IVAR_CLASS, &cl))
return (ENXIO);
if (md != SCC_MODE_ASYNC)
return (ENXIO);
switch (cl) {
case SCC_CLASS_QUICC:
sc->sc_class = &uart_quicc_class;
break;
case SCC_CLASS_Z8530:
sc->sc_class = &uart_z8530_class;
break;
default:
return (ENXIO);
}
if (BUS_READ_IVAR(parent, dev, SCC_IVAR_CHANNEL, &ch) ||
BUS_READ_IVAR(parent, dev, SCC_IVAR_CLOCK, &cl) ||
BUS_READ_IVAR(parent, dev, SCC_IVAR_REGSHFT, &rs))
return (ENXIO);
return (uart_bus_probe(dev, rs, 0, cl, 0, ch, 0));
}
DRIVER_MODULE(uart, scc, uart_scc_driver, 0, 0);