isa_pci.c revision 119285
169783Smsmith/*- 269783Smsmith * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier 369783Smsmith * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 469783Smsmith * Copyright (c) 2000 BSDi 569783Smsmith * All rights reserved. 669783Smsmith * 769783Smsmith * Redistribution and use in source and binary forms, with or without 869783Smsmith * modification, are permitted provided that the following conditions 969783Smsmith * are met: 1069783Smsmith * 1. Redistributions of source code must retain the above copyright 1169783Smsmith * notice, this list of conditions and the following disclaimer. 1269783Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1369783Smsmith * notice, this list of conditions and the following disclaimer in the 1469783Smsmith * documentation and/or other materials provided with the distribution. 1569783Smsmith * 3. The name of the author may not be used to endorse or promote products 1669783Smsmith * derived from this software without specific prior written permission. 1769783Smsmith * 1869783Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1969783Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2069783Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2169783Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2269783Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2369783Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2469783Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2569783Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2669783Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2769783Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2869783Smsmith * SUCH DAMAGE. 2969783Smsmith * 3069783Smsmith * $FreeBSD: head/sys/dev/pci/isa_pci.c 119285 2003-08-22 06:42:59Z imp $ 3169783Smsmith */ 3269783Smsmith 3369783Smsmith/* 3469783Smsmith * PCI:ISA bridge support 3569783Smsmith */ 3669783Smsmith 3769783Smsmith#include <sys/param.h> 3869783Smsmith#include <sys/systm.h> 3969783Smsmith#include <sys/kernel.h> 40106219Siedowse#include <machine/bus.h> 41106219Siedowse#include <machine/resource.h> 4269783Smsmith#include <sys/bus.h> 43106219Siedowse#include <sys/rman.h> 4469783Smsmith 45117337Sjhb#include <isa/isavar.h> 46119285Simp#include <dev/pci/pcivar.h> 47119285Simp#include <dev/pci/pcireg.h> 4869783Smsmith 49106219Siedowse#define ELCR_IOADDR 0x4d0 /* Interrupt Edge/Level Control Registers */ 50106219Siedowse#define ELCR_IOLEN 2 51106219Siedowse 52106219Siedowsestruct isab_softc { 53106219Siedowse struct resource *elcr_res; 54106219Siedowse u_char saved_elcr[ELCR_IOLEN]; 55106219Siedowse}; 56106219Siedowse 5769783Smsmithstatic int isab_probe(device_t dev); 58117337Sjhbstatic int pci_isab_attach(device_t dev); 59106219Siedowsestatic int isab_detach(device_t dev); 60106219Siedowsestatic int isab_resume(device_t dev); 61106219Siedowsestatic int isab_suspend(device_t dev); 6269783Smsmith 6369783Smsmithstatic device_method_t isab_methods[] = { 6469783Smsmith /* Device interface */ 6569783Smsmith DEVMETHOD(device_probe, isab_probe), 66117337Sjhb DEVMETHOD(device_attach, pci_isab_attach), 67106219Siedowse DEVMETHOD(device_detach, isab_detach), 6869783Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 69106219Siedowse DEVMETHOD(device_suspend, isab_suspend), 70106219Siedowse DEVMETHOD(device_resume, isab_resume), 7169783Smsmith 7269783Smsmith /* Bus interface */ 7369783Smsmith DEVMETHOD(bus_print_child, bus_generic_print_child), 7469783Smsmith DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 7569783Smsmith DEVMETHOD(bus_release_resource, bus_generic_release_resource), 7669783Smsmith DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 7769783Smsmith DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 7869783Smsmith DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 7969783Smsmith DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 8069783Smsmith 8169783Smsmith { 0, 0 } 8269783Smsmith}; 8369783Smsmith 8469783Smsmithstatic driver_t isab_driver = { 8569783Smsmith "isab", 8669783Smsmith isab_methods, 87106219Siedowse sizeof(struct isab_softc), 8869783Smsmith}; 8969783Smsmith 9069783SmsmithDRIVER_MODULE(isab, pci, isab_driver, isab_devclass, 0, 0); 9169783Smsmith 9269783Smsmith/* 9369783Smsmith * XXX we need to add a quirk list here for bridges that don't correctly 9469783Smsmith * report themselves. 9569783Smsmith */ 9669783Smsmithstatic int 9769783Smsmithisab_probe(device_t dev) 9869783Smsmith{ 9969783Smsmith int matched = 0; 10069783Smsmith 10169783Smsmith /* 10269783Smsmith * Try for a generic match based on class/subclass. 10369783Smsmith */ 10469890Smsmith if ((pci_get_class(dev) == PCIC_BRIDGE) && 10569890Smsmith (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) { 10669890Smsmith matched = 1; 10769890Smsmith } else { 10869890Smsmith /* 10969890Smsmith * These are devices that we *know* are PCI:ISA bridges. 11069890Smsmith * Sometimes, however, they don't report themselves as 11169890Smsmith * such. Check in case one of them is pretending to be 11269890Smsmith * something else. 11369890Smsmith */ 11469890Smsmith switch (pci_get_devid(dev)) { 11569890Smsmith case 0x04848086: /* Intel 82378ZB/82378IB */ 11669890Smsmith case 0x122e8086: /* Intel 82371FB */ 11769890Smsmith case 0x70008086: /* Intel 82371SB */ 11869890Smsmith case 0x71108086: /* Intel 82371AB */ 11988323Spirzyk case 0x71988086: /* Intel 82443MX */ 12069890Smsmith case 0x24108086: /* Intel 82801AA (ICH) */ 12169890Smsmith case 0x24208086: /* Intel 82801AB (ICH0) */ 12269890Smsmith case 0x24408086: /* Intel 82801AB (ICH2) */ 12369890Smsmith case 0x00061004: /* VLSI 82C593 */ 12469890Smsmith case 0x05861106: /* VIA 82C586 */ 12569890Smsmith case 0x05961106: /* VIA 82C596 */ 12669890Smsmith case 0x06861106: /* VIA 82C686 */ 12769890Smsmith case 0x153310b9: /* AcerLabs M1533 */ 12869890Smsmith case 0x154310b9: /* AcerLabs M1543 */ 12969890Smsmith case 0x00081039: /* SiS 85c503 */ 13069890Smsmith case 0x00001078: /* Cyrix Cx5510 */ 13169890Smsmith case 0x01001078: /* Cyrix Cx5530 */ 13269890Smsmith case 0xc7001045: /* OPTi 82C700 (FireStar) */ 13369890Smsmith case 0x00011033: /* NEC 0001 (C-bus) */ 13469890Smsmith case 0x002c1033: /* NEC 002C (C-bus) */ 13569890Smsmith case 0x003b1033: /* NEC 003B (C-bus) */ 13669890Smsmith case 0x886a1060: /* UMC UM8886 ISA */ 13769890Smsmith case 0x02001166: /* ServerWorks IB6566 PCI */ 13869890Smsmith if (bootverbose) 13969890Smsmith printf("PCI-ISA bridge with incorrect subclass 0x%x\n", 14069890Smsmith pci_get_subclass(dev)); 14169849Smsmith matched = 1; 14269890Smsmith break; 14369849Smsmith 14469890Smsmith default: 14569890Smsmith break; 14669783Smsmith } 14769783Smsmith } 14869783Smsmith 14969783Smsmith if (matched) { 15069783Smsmith device_set_desc(dev, "PCI-ISA bridge"); 15169783Smsmith return(-10000); 15269783Smsmith } 15369783Smsmith return(ENXIO); 15469783Smsmith} 15569783Smsmith 15669783Smsmithstatic int 157117337Sjhbpci_isab_attach(device_t dev) 15869783Smsmith{ 159106219Siedowse struct isab_softc *sc = device_get_softc(dev); 160106219Siedowse int error, rid; 16169783Smsmith 16269783Smsmith /* 16369783Smsmith * Attach an ISA bus. Note that we can only have one ISA bus. 16469783Smsmith */ 165117337Sjhb error = isab_attach(dev); 166117337Sjhb if (error) 167117337Sjhb return (error); 16869783Smsmith 169106219Siedowse switch (pci_get_devid(dev)) { 170106219Siedowse case 0x71108086: /* Intel 82371AB */ 171106219Siedowse /* 172106219Siedowse * Sometimes the ELCR (Edge/Level Control Register) is not restored 173106219Siedowse * correctly on resume by the BIOS, so we handle it ourselves. 174106219Siedowse */ 175106219Siedowse rid = 0; 176106219Siedowse bus_set_resource(dev, SYS_RES_IOPORT, rid, ELCR_IOADDR, ELCR_IOLEN); 177106219Siedowse sc->elcr_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, 178106219Siedowse RF_ACTIVE); 179106219Siedowse if (sc->elcr_res == NULL) 180106219Siedowse device_printf(dev, "failed to allocate ELCR resource\n"); 181106219Siedowse break; 182106219Siedowse } 183106219Siedowse 18469783Smsmith return(0); 18569783Smsmith} 18669783Smsmith 187106219Siedowsestatic int 188106219Siedowseisab_detach(device_t dev) 189106219Siedowse{ 190106219Siedowse struct isab_softc *sc = device_get_softc(dev); 191106219Siedowse 192106219Siedowse if (sc->elcr_res != NULL) 193106219Siedowse bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->elcr_res); 194106219Siedowse 195106219Siedowse return (bus_generic_detach(dev)); 196106219Siedowse} 197106219Siedowse 198106219Siedowsestatic int 199106219Siedowseisab_suspend(device_t dev) 200106219Siedowse{ 201106219Siedowse struct isab_softc *sc = device_get_softc(dev); 202106219Siedowse bus_space_tag_t bst; 203106219Siedowse bus_space_handle_t bsh; 204106219Siedowse int i; 205106219Siedowse 206106219Siedowse /* Save the ELCR if required. */ 207106219Siedowse if (sc->elcr_res != NULL) { 208106219Siedowse bst = rman_get_bustag(sc->elcr_res); 209106219Siedowse bsh = rman_get_bushandle(sc->elcr_res); 210106219Siedowse for (i = 0; i < ELCR_IOLEN; i++) 211106219Siedowse sc->saved_elcr[i] = bus_space_read_1(bst, bsh, i); 212106219Siedowse } 213106219Siedowse 214106219Siedowse return (bus_generic_suspend(dev)); 215106219Siedowse} 216106219Siedowse 217106219Siedowsestatic int 218106219Siedowseisab_resume(device_t dev) 219106219Siedowse{ 220106219Siedowse struct isab_softc *sc = device_get_softc(dev); 221106219Siedowse bus_space_tag_t bst; 222106219Siedowse bus_space_handle_t bsh; 223106219Siedowse int i; 224106219Siedowse 225106219Siedowse /* Restore the ELCR if required. */ 226106219Siedowse if (sc->elcr_res != NULL) { 227106219Siedowse bst = rman_get_bustag(sc->elcr_res); 228106219Siedowse bsh = rman_get_bushandle(sc->elcr_res); 229106219Siedowse for (i = 0; i < ELCR_IOLEN; i++) 230106219Siedowse bus_space_write_1(bst, bsh, i, sc->saved_elcr[i]); 231106219Siedowse } 232106219Siedowse 233106219Siedowse return (bus_generic_resume(dev)); 234106219Siedowse} 235