aic_pccard.c revision 296137
1268899Sbapt/*- 2234949Sbapt * Copyright (c) 1999 Luoqi Chen. 3234949Sbapt * All rights reserved. 4234949Sbapt * 5234949Sbapt * Redistribution and use in source and binary forms, with or without 6234949Sbapt * modification, are permitted provided that the following conditions 7234949Sbapt * are met: 8234949Sbapt * 1. Redistributions of source code must retain the above copyright 9234949Sbapt * notice, this list of conditions and the following disclaimer. 10234949Sbapt * 2. Redistributions in binary form must reproduce the above copyright 11234949Sbapt * notice, this list of conditions and the following disclaimer in the 12234949Sbapt * documentation and/or other materials provided with the distribution. 13234949Sbapt * 14234949Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15234949Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16234949Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17234949Sbapt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18234949Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19234949Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20234949Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21234949Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22234949Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23234949Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24234949Sbapt * SUCH DAMAGE. 25234949Sbapt */ 26234949Sbapt 27234949Sbapt#include <sys/cdefs.h> 28234949Sbapt__FBSDID("$FreeBSD: head/sys/dev/aic/aic_pccard.c 296137 2016-02-27 03:38:01Z jhibbits $"); 29234949Sbapt 30234949Sbapt#include <sys/param.h> 31234949Sbapt#include <sys/callout.h> 32234949Sbapt#include <sys/kernel.h> 33234949Sbapt#include <sys/lock.h> 34234949Sbapt#include <sys/module.h> 35234949Sbapt#include <sys/mutex.h> 36234949Sbapt#include <sys/bus.h> 37234949Sbapt 38234949Sbapt#include <machine/bus.h> 39234949Sbapt#include <machine/resource.h> 40234949Sbapt#include <sys/rman.h> 41234949Sbapt 42234949Sbapt#include <dev/aic/aicvar.h> 43234949Sbapt#include <dev/pccard/pccardvar.h> 44234949Sbapt 45268899Sbapt#include "card_if.h" 46234949Sbapt#include "pccarddevs.h" 47268899Sbapt 48234949Sbaptstruct aic_pccard_softc { 49234949Sbapt struct aic_softc sc_aic; 50234949Sbapt struct resource *sc_port; 51234949Sbapt struct resource *sc_irq; 52234949Sbapt void *sc_ih; 53234949Sbapt}; 54234949Sbapt 55234949Sbaptstatic int aic_pccard_alloc_resources(device_t); 56234949Sbaptstatic void aic_pccard_release_resources(device_t); 57234949Sbaptstatic int aic_pccard_probe(device_t); 58234949Sbaptstatic int aic_pccard_attach(device_t); 59234949Sbapt 60234949Sbaptstatic const struct pccard_product aic_pccard_products[] = { 61234949Sbapt PCMCIA_CARD(ADAPTEC, APA1460), 62234949Sbapt PCMCIA_CARD(ADAPTEC, APA1460A), 63234949Sbapt PCMCIA_CARD(NEWMEDIA, BUSTOASTER), 64234949Sbapt PCMCIA_CARD(NEWMEDIA, BUSTOASTER2), 65234949Sbapt PCMCIA_CARD(NEWMEDIA, BUSTOASTER3), 66234949Sbapt { NULL } 67234949Sbapt}; 68234949Sbapt 69234949Sbapt#define AIC_PCCARD_PORTSIZE 0x20 70234949Sbapt 71234949Sbaptstatic int 72234949Sbaptaic_pccard_alloc_resources(device_t dev) 73234949Sbapt{ 74234949Sbapt struct aic_pccard_softc *sc = device_get_softc(dev); 75234949Sbapt int rid; 76234949Sbapt 77234949Sbapt sc->sc_port = sc->sc_irq = NULL; 78234949Sbapt 79234949Sbapt rid = 0; 80234949Sbapt sc->sc_port = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid, 81234949Sbapt AIC_PCCARD_PORTSIZE, RF_ACTIVE); 82234949Sbapt if (!sc->sc_port) 83234949Sbapt return (ENOMEM); 84234949Sbapt 85234949Sbapt rid = 0; 86234949Sbapt sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 87234949Sbapt if (!sc->sc_irq) { 88234949Sbapt aic_pccard_release_resources(dev); 89234949Sbapt return (ENOMEM); 90234949Sbapt } 91234949Sbapt 92234949Sbapt sc->sc_aic.dev = dev; 93234949Sbapt sc->sc_aic.res = sc->sc_port; 94234949Sbapt mtx_init(&sc->sc_aic.lock, "aic", NULL, MTX_DEF); 95234949Sbapt return (0); 96234949Sbapt} 97234949Sbapt 98234949Sbaptstatic void 99234949Sbaptaic_pccard_release_resources(device_t dev) 100234949Sbapt{ 101234949Sbapt struct aic_pccard_softc *sc = device_get_softc(dev); 102234949Sbapt 103234949Sbapt if (sc->sc_port) 104234949Sbapt bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->sc_port); 105234949Sbapt if (sc->sc_irq) 106234949Sbapt bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq); 107234949Sbapt sc->sc_port = sc->sc_irq = NULL; 108234949Sbapt mtx_destroy(&sc->sc_aic.lock); 109234949Sbapt} 110234949Sbapt 111234949Sbaptstatic int 112234949Sbaptaic_pccard_probe(device_t dev) 113234949Sbapt{ 114234949Sbapt const struct pccard_product *pp; 115234949Sbapt 116234949Sbapt if ((pp = pccard_product_lookup(dev, aic_pccard_products, 117234949Sbapt sizeof(aic_pccard_products[0]), NULL)) != NULL) { 118234949Sbapt if (pp->pp_name != NULL) 119234949Sbapt device_set_desc(dev, pp->pp_name); 120234949Sbapt else 121234949Sbapt device_set_desc(dev, 122234949Sbapt "Adaptec 6260/6360 SCSI controller"); 123234949Sbapt return (BUS_PROBE_DEFAULT); 124234949Sbapt } 125234949Sbapt return (ENXIO); 126234949Sbapt} 127234949Sbapt 128234949Sbaptstatic int 129234949Sbaptaic_pccard_attach(device_t dev) 130234949Sbapt{ 131234949Sbapt struct aic_pccard_softc *sc = device_get_softc(dev); 132234949Sbapt struct aic_softc *aic = &sc->sc_aic; 133234949Sbapt int error; 134234949Sbapt 135234949Sbapt if (aic_pccard_alloc_resources(dev)) 136234949Sbapt return (ENXIO); 137234949Sbapt if (aic_probe(aic)) { 138234949Sbapt aic_pccard_release_resources(dev); 139234949Sbapt return (ENXIO); 140234949Sbapt } 141234949Sbapt 142234949Sbapt error = aic_attach(aic); 143234949Sbapt if (error) { 144234949Sbapt device_printf(dev, "attach failed\n"); 145234949Sbapt aic_pccard_release_resources(dev); 146234949Sbapt return (error); 147234949Sbapt } 148234949Sbapt 149234949Sbapt error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_CAM | INTR_ENTROPY | 150234949Sbapt INTR_MPSAFE, NULL, aic_intr, aic, &sc->sc_ih); 151234949Sbapt if (error) { 152234949Sbapt device_printf(dev, "failed to register interrupt handler\n"); 153234949Sbapt aic_pccard_release_resources(dev); 154234949Sbapt return (error); 155234949Sbapt } 156234949Sbapt return (0); 157234949Sbapt} 158234949Sbapt 159234949Sbaptstatic int 160234949Sbaptaic_pccard_detach(device_t dev) 161234949Sbapt{ 162234949Sbapt struct aic_pccard_softc *sc = device_get_softc(dev); 163234949Sbapt struct aic_softc *aic = &sc->sc_aic; 164234949Sbapt int error; 165234949Sbapt 166234949Sbapt error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); 167234949Sbapt if (error) { 168234949Sbapt device_printf(dev, "failed to unregister interrupt handler\n"); 169234949Sbapt } 170234949Sbapt 171234949Sbapt error = aic_detach(aic); 172234949Sbapt if (error) { 173234949Sbapt device_printf(dev, "detach failed\n"); 174234949Sbapt return (error); 175234949Sbapt } 176234949Sbapt 177234949Sbapt aic_pccard_release_resources(dev); 178234949Sbapt return (0); 179234949Sbapt} 180234949Sbapt 181234949Sbaptstatic device_method_t aic_pccard_methods[] = { 182234949Sbapt /* Device interface */ 183234949Sbapt DEVMETHOD(device_probe, aic_pccard_probe), 184234949Sbapt DEVMETHOD(device_attach, aic_pccard_attach), 185234949Sbapt DEVMETHOD(device_detach, aic_pccard_detach), 186234949Sbapt 187234949Sbapt { 0, 0 } 188234949Sbapt}; 189234949Sbapt 190234949Sbaptstatic driver_t aic_pccard_driver = { 191234949Sbapt "aic", 192234949Sbapt aic_pccard_methods, sizeof(struct aic_pccard_softc), 193234949Sbapt}; 194234949Sbapt 195234949Sbaptextern devclass_t aic_devclass; 196234949Sbapt 197234949SbaptMODULE_DEPEND(aic, cam, 1,1,1); 198234949SbaptDRIVER_MODULE(aic, pccard, aic_pccard_driver, aic_devclass, 0, 0); 199234949SbaptPCCARD_PNP_INFO(aic_pccard_products); 200234949Sbapt