#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/termios.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <dev/ic/comreg.h>
#include <dev/ic/comvar.h>
#include <dev/isa/isavar.h>
#define NSLAVES 8
#define STATUS_IOADDR 0x420
#define STATUS_SIZE 8
struct addcom_softc {
struct device sc_dev;
void *sc_ih;
bus_space_tag_t sc_iot;
bus_addr_t sc_iobase;
int sc_alive[NSLAVES];
void *sc_slaves[NSLAVES];
bus_space_handle_t sc_slaveioh[NSLAVES];
bus_space_handle_t sc_statusioh;
};
#define SLAVE_IOBASE_OFFSET 0x108
static int slave_iobases[8] = {
0x108,
0x110,
0x118,
0x120,
0x128,
0x130,
0x200,
0x208
};
int addcomprobe(struct device *, void *, void *);
void addcomattach(struct device *, struct device *, void *);
int addcomintr(void *);
int addcomprint(void *, const char *);
const struct cfattach addcom_isa_ca = {
sizeof(struct addcom_softc), addcomprobe, addcomattach,
};
struct cfdriver addcom_cd = {
NULL, "addcom", DV_TTY
};
int
addcomprobe(struct device *parent, void *self, void *aux)
{
struct isa_attach_args *ia = aux;
int iobase = ia->ia_iobase;
bus_space_tag_t iot = ia->ia_iot;
bus_space_handle_t ioh;
int i, rv = 1;
if (ia->ia_iobase == -1 )
return (0);
if (iobase == comconsaddr && !comconsattached)
goto checkmappings;
if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) {
rv = 0;
goto out;
}
rv = comprobe1(iot, ioh);
bus_space_unmap(iot, ioh, COM_NPORTS);
if (rv == 0)
goto out;
checkmappings:
for (i = 1; i < NSLAVES; i++) {
iobase += slave_iobases[i] - slave_iobases[i - 1];
if (iobase == comconsaddr && !comconsattached)
continue;
if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) {
rv = 0;
goto out;
}
bus_space_unmap(iot, ioh, COM_NPORTS);
}
out:
if (rv)
ia->ia_iosize = NSLAVES * COM_NPORTS;
return (rv);
}
int
addcomprint(void *aux, const char *pnp)
{
struct commulti_attach_args *ca = aux;
if (pnp)
printf("com at %s", pnp);
printf(" slave %d", ca->ca_slave);
return (UNCONF);
}
void
addcomattach(struct device *parent, struct device *self, void *aux)
{
struct addcom_softc *sc = (void *)self;
struct isa_attach_args *ia = aux;
struct commulti_attach_args ca;
bus_space_tag_t iot = ia->ia_iot;
bus_addr_t iobase;
int i;
sc->sc_iot = ia->ia_iot;
sc->sc_iobase = ia->ia_iobase;
if (ia->ia_irq == IRQUNK) {
printf(": wildcard interrupt not supported\n");
return;
}
sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
IPL_TTY, addcomintr, sc, sc->sc_dev.dv_xname);
if (sc->sc_ih == NULL) {
printf(": can't establish interrupt\n");
return;
}
if (bus_space_map(iot, STATUS_IOADDR, STATUS_SIZE,
0, &sc->sc_statusioh)) {
printf(": can't map status space\n");
return;
}
for (i = 0; i < NSLAVES; i++) {
iobase = sc->sc_iobase
+ slave_iobases[i]
- SLAVE_IOBASE_OFFSET;
if ((!(iobase == comconsaddr && !comconsattached)) &&
bus_space_map(iot, iobase, COM_NPORTS, 0,
&sc->sc_slaveioh[i])) {
printf(": can't map i/o space for slave %d\n", i);
return;
}
}
printf("\n");
for (i = 0; i < NSLAVES; i++) {
ca.ca_slave = i;
ca.ca_iot = sc->sc_iot;
ca.ca_ioh = sc->sc_slaveioh[i];
ca.ca_iobase = sc->sc_iobase
+ slave_iobases[i]
- SLAVE_IOBASE_OFFSET;
ca.ca_noien = 0;
sc->sc_slaves[i] = config_found(self, &ca, addcomprint);
if (sc->sc_slaves[i] != NULL)
sc->sc_alive[i] = 1;
}
}
int
addcomintr(void *arg)
{
struct addcom_softc *sc = arg;
int intrd, r = 0, i;
do {
intrd = 0;
for (i = 0; i < NSLAVES; i++)
if (sc->sc_alive[i] && comintr(sc->sc_slaves[i])) {
r = 1;
intrd = 1;
}
} while (intrd);
return (r);
}