#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/extent.h>
#include <sys/reboot.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmareg.h>
#ifdef __HAVE_ACPI
#include "acpi.h"
#include <dev/acpi/acpivar.h>
#else
#define NACPI 0
#endif
int isamatch(struct device *, void *, void *);
void isaattach(struct device *, struct device *, void *);
extern int autoconf_verbose;
const struct cfattach isa_ca = {
sizeof(struct isa_softc), isamatch, isaattach
};
struct cfdriver isa_cd = {
NULL, "isa", DV_DULL, CD_INDIRECT | CD_COCOVM
};
int
isamatch(struct device *parent, void *match, void *aux)
{
struct cfdata *cf = match;
struct isabus_attach_args *iba = aux;
if (strcmp(iba->iba_busname, cf->cf_driver->cd_name))
return (0);
#if NACPI > 0
if (acpi_legacy_free)
return (0);
#endif
return (1);
}
void
isaattach(struct device *parent, struct device *self, void *aux)
{
struct isa_softc *sc = (struct isa_softc *)self;
struct isabus_attach_args *iba = aux;
isa_attach_hook(parent, self, iba);
printf("\n");
sc->sc_iot = iba->iba_iot;
sc->sc_memt = iba->iba_memt;
#if NISADMA > 0
sc->sc_dmat = iba->iba_dmat;
#endif
sc->sc_ic = iba->iba_ic;
#if NISAPNP > 0
isapnp_isa_attach_hook(sc);
#endif
#if NISADMA > 0
if (bus_space_map(sc->sc_iot, IO_DMA1, DMA1_IOSIZE, 0, &sc->sc_dma1h))
panic("isaattach: can't map DMA controller #1");
if (bus_space_map(sc->sc_iot, IO_DMA2, DMA2_IOSIZE, 0, &sc->sc_dma2h))
panic("isaattach: can't map DMA controller #2");
if (bus_space_map(sc->sc_iot, IO_DMAPG, 0xf, 0, &sc->sc_dmapgh))
panic("isaattach: can't map DMA page registers");
if (bus_space_subregion(sc->sc_iot, sc->sc_dmapgh, 0x04, 1,
&sc->sc_delaybah))
#else
if (bus_space_map(sc->sc_iot, IO_DMAPG + 0x4, 0x1, 0,
&sc->sc_delaybah))
#endif
panic("isaattach: can't map `delay port'");
TAILQ_INIT(&sc->sc_subdevs);
config_scan(isascan, self);
}
int
isaprint(void *aux, const char *isa)
{
struct isa_attach_args *ia = aux;
int irq, nirq;
int dma, ndma;
if (ia->ia_iosize)
printf(" port 0x%x", ia->ia_iobase);
if (ia->ia_iosize > 1)
printf("/%d", ia->ia_iosize);
if (ia->ia_msize)
printf(" iomem 0x%x", ia->ia_maddr);
if (ia->ia_msize > 1)
printf("/%d", ia->ia_msize);
nirq = ia->ipa_nirq;
if (nirq < 0 || nirq > nitems(ia->ipa_irq))
nirq = 1;
for (irq = 0; irq < nirq; irq++)
if (ia->ipa_irq[irq].num != IRQUNK)
printf(" irq %d", ia->ipa_irq[irq].num);
ndma = ia->ipa_ndrq;
if (ndma < 0 || ndma > nitems(ia->ipa_drq))
ndma = 2;
for (dma = 0; dma < ndma; dma++)
if (ia->ipa_drq[dma].num != DRQUNK) {
if (dma == 0)
printf(" drq");
else
printf(" drq%d", dma + 1);
printf(" %d", ia->ipa_drq[dma].num);
}
return (UNCONF);
}
void
isascan(struct device *parent, void *match)
{
struct isa_softc *sc = (struct isa_softc *)parent;
struct device *dev = match;
struct cfdata *cf = dev->dv_cfdata;
struct isa_attach_args ia;
ia.ia_iot = sc->sc_iot;
ia.ia_memt = sc->sc_memt;
#if NISADMA > 0
ia.ia_dmat = sc->sc_dmat;
#endif
ia.ia_ic = sc->sc_ic;
ia.ia_iobase = cf->cf_iobase;
ia.ia_iosize = 0x666;
ia.ia_maddr = cf->cf_maddr;
ia.ia_msize = cf->cf_msize;
ia.ia_irq = cf->cf_irq == 2 ? 9 : cf->cf_irq;
ia.ipa_nirq = ia.ia_irq == IRQUNK ? 0 : 1;
ia.ia_drq = cf->cf_drq;
ia.ia_drq2 = cf->cf_drq2;
ia.ipa_ndrq = 2;
ia.ia_delaybah = sc->sc_delaybah;
if (ISSET(boothowto, RB_COCOVM) &&
!ISSET(cf->cf_driver->cd_mode, CD_COCOVM))
return;
if (cf->cf_fstate == FSTATE_STAR) {
struct isa_attach_args ia2 = ia;
if (autoconf_verbose)
printf(">>> probing for %s*\n",
cf->cf_driver->cd_name);
while ((*cf->cf_attach->ca_match)(parent, dev, &ia2) > 0) {
#if !defined(__NO_ISA_INTR_CHECK)
if ((ia2.ia_irq != IRQUNK) &&
!isa_intr_check(sc->sc_ic, ia2.ia_irq, IST_EDGE)) {
printf("%s%d: irq %d already in use\n",
cf->cf_driver->cd_name, cf->cf_unit,
ia2.ia_irq);
ia2 = ia;
break;
}
#endif
if (autoconf_verbose)
printf(">>> probe for %s* clone into %s%d\n",
cf->cf_driver->cd_name,
cf->cf_driver->cd_name, cf->cf_unit);
if (ia2.ia_iosize == 0x666) {
printf("%s: iosize not repaired by driver\n",
sc->sc_dev.dv_xname);
ia2.ia_iosize = 0;
}
config_attach(parent, dev, &ia2, isaprint);
dev = config_make_softc(parent, cf);
#if NISADMA > 0
if (ia2.ia_drq != DRQUNK)
ISA_DRQ_ALLOC((struct device *)sc, ia2.ia_drq);
if (ia2.ia_drq2 != DRQUNK)
ISA_DRQ_ALLOC((struct device *)sc, ia2.ia_drq2);
#endif
ia2 = ia;
}
if (autoconf_verbose)
printf(">>> probing for %s* finished\n",
cf->cf_driver->cd_name);
free(dev, M_DEVBUF, cf->cf_attach->ca_devsize);
return;
}
if (autoconf_verbose)
printf(">>> probing for %s%d\n", cf->cf_driver->cd_name,
cf->cf_unit);
if ((*cf->cf_attach->ca_match)(parent, dev, &ia) > 0) {
#if !defined(__NO_ISA_INTR_CHECK)
if ((ia.ia_irq != IRQUNK) &&
!isa_intr_check(sc->sc_ic, ia.ia_irq, IST_EDGE)) {
printf("%s%d: irq %d already in use\n",
cf->cf_driver->cd_name, cf->cf_unit, ia.ia_irq);
free(dev, M_DEVBUF, cf->cf_attach->ca_devsize);
} else {
#endif
if (autoconf_verbose)
printf(">>> probing for %s%d succeeded\n",
cf->cf_driver->cd_name, cf->cf_unit);
config_attach(parent, dev, &ia, isaprint);
#if NISADMA > 0
if (ia.ia_drq != DRQUNK)
ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq);
if (ia.ia_drq2 != DRQUNK)
ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq2);
#endif
#if !defined(__NO_ISA_INTR_CHECK)
}
#endif
} else {
if (autoconf_verbose)
printf(">>> probing for %s%d failed\n",
cf->cf_driver->cd_name, cf->cf_unit);
free(dev, M_DEVBUF, cf->cf_attach->ca_devsize);
}
}
char *
isa_intr_typename(int type)
{
switch (type) {
case IST_NONE:
return ("none");
case IST_PULSE:
return ("pulsed");
case IST_EDGE:
return ("edge-triggered");
case IST_LEVEL:
return ("level-triggered");
default:
panic("isa_intr_typename: invalid type %d", type);
}
}