diff options
| author | Ian Dowse <iedowse@FreeBSD.org> | 2002-10-30 19:55:06 +0000 |
|---|---|---|
| committer | Ian Dowse <iedowse@FreeBSD.org> | 2002-10-30 19:55:06 +0000 |
| commit | 58164331e334cbf3444c0755d79841c8a22a9b87 (patch) | |
| tree | 7d3748ad99e2a51113e9f14204e365b6d11661d2 /sys/dev/pci | |
| parent | cb0d1e061b6b332b22e6fcd0ff826cb94543692c (diff) | |
Notes
Diffstat (limited to 'sys/dev/pci')
| -rw-r--r-- | sys/dev/pci/isa_pci.c | 93 |
1 files changed, 88 insertions, 5 deletions
diff --git a/sys/dev/pci/isa_pci.c b/sys/dev/pci/isa_pci.c index 85ef75debc7e..5690df187cfa 100644 --- a/sys/dev/pci/isa_pci.c +++ b/sys/dev/pci/isa_pci.c @@ -37,21 +37,36 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <machine/bus.h> +#include <machine/resource.h> #include <sys/bus.h> +#include <sys/rman.h> #include <pci/pcivar.h> #include <pci/pcireg.h> +#define ELCR_IOADDR 0x4d0 /* Interrupt Edge/Level Control Registers */ +#define ELCR_IOLEN 2 + +struct isab_softc { + struct resource *elcr_res; + u_char saved_elcr[ELCR_IOLEN]; +}; + static int isab_probe(device_t dev); static int isab_attach(device_t dev); +static int isab_detach(device_t dev); +static int isab_resume(device_t dev); +static int isab_suspend(device_t dev); static device_method_t isab_methods[] = { /* Device interface */ DEVMETHOD(device_probe, isab_probe), DEVMETHOD(device_attach, isab_attach), + DEVMETHOD(device_detach, isab_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_suspend, isab_suspend), + DEVMETHOD(device_resume, isab_resume), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), @@ -68,7 +83,7 @@ static device_method_t isab_methods[] = { static driver_t isab_driver = { "isab", isab_methods, - 0, + sizeof(struct isab_softc), }; static devclass_t isab_devclass; @@ -143,14 +158,82 @@ static int isab_attach(device_t dev) { device_t child; + struct isab_softc *sc = device_get_softc(dev); + int error, rid; /* * Attach an ISA bus. Note that we can only have one ISA bus. */ child = device_add_child(dev, "isa", 0); - if (child != NULL) - return(bus_generic_attach(dev)); + if (child != NULL) { + error = bus_generic_attach(dev); + if (error) + return (error); + } + + switch (pci_get_devid(dev)) { + case 0x71108086: /* Intel 82371AB */ + /* + * Sometimes the ELCR (Edge/Level Control Register) is not restored + * correctly on resume by the BIOS, so we handle it ourselves. + */ + rid = 0; + bus_set_resource(dev, SYS_RES_IOPORT, rid, ELCR_IOADDR, ELCR_IOLEN); + sc->elcr_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, + RF_ACTIVE); + if (sc->elcr_res == NULL) + device_printf(dev, "failed to allocate ELCR resource\n"); + break; + } return(0); } +static int +isab_detach(device_t dev) +{ + struct isab_softc *sc = device_get_softc(dev); + + if (sc->elcr_res != NULL) + bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->elcr_res); + + return (bus_generic_detach(dev)); +} + +static int +isab_suspend(device_t dev) +{ + struct isab_softc *sc = device_get_softc(dev); + bus_space_tag_t bst; + bus_space_handle_t bsh; + int i; + + /* Save the ELCR if required. */ + if (sc->elcr_res != NULL) { + bst = rman_get_bustag(sc->elcr_res); + bsh = rman_get_bushandle(sc->elcr_res); + for (i = 0; i < ELCR_IOLEN; i++) + sc->saved_elcr[i] = bus_space_read_1(bst, bsh, i); + } + + return (bus_generic_suspend(dev)); +} + +static int +isab_resume(device_t dev) +{ + struct isab_softc *sc = device_get_softc(dev); + bus_space_tag_t bst; + bus_space_handle_t bsh; + int i; + + /* Restore the ELCR if required. */ + if (sc->elcr_res != NULL) { + bst = rman_get_bustag(sc->elcr_res); + bsh = rman_get_bushandle(sc->elcr_res); + for (i = 0; i < ELCR_IOLEN; i++) + bus_space_write_1(bst, bsh, i, sc->saved_elcr[i]); + } + + return (bus_generic_resume(dev)); +} |
