#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/ioctl.h>
#include <machine/autoconf.h>
#include <machine/board.h>
#include <machine/conf.h>
#include <machine/pcex.h>
#include <luna88k/cbus/cbusvar.h>
extern int hz;
#if 0
#define PCEX_DEBUG
#endif
int pcex_match(struct device *, void *, void *);
void pcex_attach(struct device *, struct device *, void *);
struct pcex_softc {
struct device sc_dev;
int intr_use[NCBUSISR];
};
const struct cfattach pcex_ca = {
sizeof(struct pcex_softc), pcex_match, pcex_attach
};
struct cfdriver pcex_cd = {
NULL, "pcex", DV_DULL
};
int pcex_intr(void *);
int pcex_set_int(struct pcex_softc *, u_int);
int pcex_reset_int(struct pcex_softc *, u_int);
int pcex_wait_int(struct pcex_softc *, u_int);
int
pcex_match(struct device *parent, void *cf, void *aux)
{
struct cbus_attach_args *caa = aux;
if (strcmp(caa->ca_name, pcex_cd.cd_name))
return 0;
return 1;
}
void
pcex_attach(struct device *parent, struct device *self, void *args)
{
struct pcex_softc *sc = (struct pcex_softc *)self;
int i;
for (i = 0; i < NCBUSISR; i++)
sc->intr_use[i] = 0;
printf("\n");
return;
}
int
pcexopen(dev_t dev, int flag, int mode, struct proc *p)
{
switch (minor(dev)) {
case 0:
case 1:
return 0;
default:
return ENXIO;
}
}
int
pcexclose(dev_t dev, int flag, int mode, struct proc *p)
{
return (0);
}
paddr_t
pcexmmap(dev_t dev, off_t offset, int prot)
{
paddr_t cookie = -1;
switch (minor(dev)) {
case 0:
if (offset >= 0 && offset < 0x1000000)
cookie = (paddr_t)(PCEXMEM_BASE + offset);
break;
case 1:
if (offset >= 0 && offset < 0x10000)
cookie = (paddr_t)(PCEXIO_BASE + offset);
break;
default:
break;
}
return cookie;
}
int
pcexioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
{
struct pcex_softc *sc = NULL;
u_int level;
if (pcex_cd.cd_ndevs != 0)
sc = pcex_cd.cd_devs[0];
if (sc == NULL)
return ENXIO;
level = *(u_int *)data;
switch(cmd) {
case PCEXSETLEVEL:
return pcex_set_int(sc, level);
case PCEXRESETLEVEL:
return pcex_reset_int(sc, level);
case PCEXWAITINT:
return pcex_wait_int(sc, level);
default:
return ENOTTY;
}
}
int
pcex_set_int(struct pcex_softc *sc, u_int level)
{
if (level > 6)
return EINVAL;
if (sc->intr_use[level] != 0)
return EINVAL;
sc->intr_use[level] = 1;
cbus_isrlink(pcex_intr, &(sc->intr_use[level]), level, IPL_NET,
sc->sc_dev.dv_xname);
return 0;
}
int
pcex_reset_int(struct pcex_softc *sc, u_int level)
{
if (level > 6)
return EINVAL;
if (sc->intr_use[level] == 0)
return EINVAL;
sc->intr_use[level] = 0;
cbus_isrunlink(pcex_intr, level);
return 0;
}
int
pcex_wait_int(struct pcex_softc *sc, u_int level)
{
int ret;
if (level > 6)
return EINVAL;
if (sc->intr_use[level] == 0)
return EINVAL;
ret = tsleep_nsec(&(sc->intr_use[level]), PWAIT | PCATCH, "pcex",
SEC_TO_NSEC(1));
#ifdef PCEX_DEBUG
if (ret == EWOULDBLOCK)
printf("pcex_wait_int: timeout in tsleep_nsec\n");
#endif
return ret;
}
int
pcex_intr(void *arg)
{
#ifdef PCEX_DEBUG
printf("pcex_intr: called, arg=%p\n", arg);
#endif
wakeup(arg);
return 1;
}