#include <sys/param.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <machine/asm_macro.h>
#include <machine/autoconf.h>
#include <machine/board.h>
#include <luna88k/cbus/cbusvar.h>
#include <luna88k/luna88k/isr.h>
#if 0
#define CBUS_DEBUG
#endif
#include "ne.h"
#include "necsb.h"
#include "pcic.h"
static struct cbus_attach_args cbus_devs[] = {
#if NNE > 0
{ "ne", -1, -1, -1, -1, -1 },
#endif
#if NNECSB > 0
{ "necsb", -1, -1, -1, -1, -1 },
#endif
#if NPCIC > 0
{ "pcic", -1, -1, -1, -1, -1 },
#endif
{ "pcex", -1, -1, -1, -1, -1 }
};
#define CBUS_INTR_STAT_REG (PC_BASE + 0x1100000)
volatile u_int8_t *cbus_isreg = (u_int8_t *)CBUS_INTR_STAT_REG;
int cbus_match(struct device *, void *, void *);
void cbus_attach(struct device *, struct device *, void *);
int cbus_print(void *, const char *);
struct cbus_softc {
struct device sc_dev;
struct cbus_isr_t cbus_isr[NCBUSISR];
u_int8_t registered;
};
const struct cfattach cbus_ca = {
sizeof(struct cbus_softc), cbus_match, cbus_attach
};
struct cfdriver cbus_cd = {
NULL, "cbus", DV_DULL
};
void cbus_isrdispatch(int);
int cbus_intr(void *);
int
cbus_match(struct device *parent, void *cf, void *aux)
{
struct mainbus_attach_args *ma = aux;
if (strcmp(ma->ma_name, cbus_cd.cd_name))
return 0;
#if 0
if (badaddr((vaddr_t)ma->ma_addr, 4))
return 0;
#endif
return 1;
}
void
cbus_attach(struct device *parent, struct device *self, void *args)
{
struct cbus_softc *sc = (struct cbus_softc *)self;
struct mainbus_attach_args *ma = args;
int i;
for (i = 0; i < NCBUSISR; i++) {
struct cbus_isr_t *ci = &sc->cbus_isr[i];
ci->isr_func = NULL;
ci->isr_arg = NULL;
ci->isr_intlevel = ci->isr_ipl = -1;
*cbus_isreg = (u_int8_t)(6 - i);
}
sc->registered = 0x00;
isrlink_autovec(cbus_intr, (void *)self, ma->ma_ilvl,
ISRPRI_TTY, self->dv_xname);
printf("\n");
for (i = 0; i < sizeof(cbus_devs)/sizeof(cbus_devs[0]); i++)
config_found(self, &cbus_devs[i], cbus_print);
return;
}
int
cbus_print(void *aux, const char *pnp)
{
struct cbus_attach_args *caa = aux;
if (pnp)
printf("%s at %s", caa->ca_name, pnp);
if (caa->ca_iobase != -1)
printf(" port 0x%x", caa->ca_iobase);
if (caa->ca_maddr != -1)
printf(" addr 0x%x", caa->ca_maddr);
if (caa->ca_int != -1)
printf(" int %d", caa->ca_int);
return UNCONF;
}
int
cbus_isrlink(int (*func)(void *), void *arg, int intlevel, int ipl,
const char *name)
{
struct cbus_softc *sc = NULL;
struct cbus_isr_t *ci;
if (cbus_cd.cd_ndevs != 0)
sc = cbus_cd.cd_devs[0];
if (sc == NULL)
panic("cbus_isrlink: can't find cbus_softc");
#ifdef DIAGNOSTIC
if (intlevel < 0 || intlevel >= NCBUSISR) {
printf("cbus_isrlink: bad INT level %d\n", intlevel);
return -1;
}
#endif
ci = &sc->cbus_isr[intlevel];
if (ci->isr_func != NULL) {
printf("cbus_isrlink: isr already assigned on INT%d\n",
intlevel);
return -1;
}
ci->isr_func = func;
ci->isr_arg = arg;
ci->isr_intlevel = intlevel;
ci->isr_ipl = ipl;
evcount_attach(&ci->isr_count, name, &ci->isr_intlevel);
sc->registered |= (1 << (6 - intlevel));
#ifdef CBUS_DEBUG
printf("cbus_isrlink: sc->registered = 0x%02x\n", sc->registered);
#endif
return 0;
}
int
cbus_isrunlink(int (*func)(void *), int intlevel)
{
struct cbus_softc *sc = NULL;
struct cbus_isr_t *ci;
if (cbus_cd.cd_ndevs != 0)
sc = cbus_cd.cd_devs[0];
if (sc == NULL)
panic("cbus_isrunlink: can't find cbus_softc");
#ifdef DIAGNOSTIC
if (intlevel < 0 || intlevel >= NCBUSISR) {
printf("cbus_isrunlink: bad INT level %d\n", intlevel);
return -1;
}
#endif
ci = &sc->cbus_isr[intlevel];
if (ci->isr_func == NULL) {
printf("cbus_isrunlink: isr not assigned on INT%d\n", intlevel);
return -1;
}
ci->isr_func = NULL;
ci->isr_arg = NULL;
ci->isr_intlevel = ci->isr_ipl = -1;
evcount_detach(&ci->isr_count);
sc->registered &= ~(1 << (6 - intlevel));
*cbus_isreg = (u_int8_t)(6 - intlevel);
#ifdef CBUS_DEBUG
printf("cbus_isrunlink: sc->registered = 0x%02x\n", sc->registered);
#endif
return 0;
}
void
cbus_isrdispatch(int intlevel)
{
int rc, s;
static int straycount, unexpected;
struct cbus_softc *sc = NULL;
struct cbus_isr_t *ci;
if (cbus_cd.cd_ndevs != 0)
sc = cbus_cd.cd_devs[0];
if (sc == NULL)
panic("cbus_isrdispatch: can't find cbus_softc");
#ifdef DIAGNOSTIC
if (intlevel < 0 || intlevel >= NCBUSISR)
panic("cbus_isrdispatch: bad INT level 0x%d", intlevel);
#endif
ci = &sc->cbus_isr[intlevel];
if (ci->isr_func == NULL) {
printf("cbus_isrdispatch: INT%d unexpected\n", intlevel);
if (++unexpected > 10)
panic("too many unexpected interrupts");
return;
}
s = splraise(ci->isr_ipl);
rc = ci->isr_func(ci->isr_arg);
splx(s);
if (rc != 0)
ci->isr_count.ec_count++;
if (rc)
straycount = 0;
else if (++straycount > 50)
panic("cbus_isrdispatch: too many stray interrupts");
else
printf("cbus_isrdispatch: stray INT%d, IPL=%d\n", intlevel,
ci->isr_ipl);
}
u_int8_t
cbus_intr_registered(void)
{
struct cbus_softc *sc = NULL;
if (cbus_cd.cd_ndevs != 0)
sc = cbus_cd.cd_devs[0];
if (sc == NULL)
panic("cbus_intr_used: can't find cbus_softc");
return sc->registered;
}
int
cbus_intr(void *arg)
{
struct cbus_softc *sc = (struct cbus_softc *)arg;
u_int8_t intr_status;
int n;
intr_status = *cbus_isreg & sc->registered;
if (intr_status == sc->registered) return 0;
#ifdef CBUS_DEBUG
printf("cbus_intr: called, *cbus_isreg=0x%02x, registered = 0x%02x\n",
*cbus_isreg, sc->registered);
#endif
intr_status = intr_status ^ sc->registered;
#ifdef CBUS_DEBUG
printf("cbus_intr: processing 0x%02x\n", intr_status);
#endif
while ((n = ff1(intr_status)) != 32) {
cbus_isrdispatch(6 - n);
*cbus_isreg = (u_int8_t)n;
intr_status &= ~(1 << n);
}
return 1;
}