1 /* $NetBSD: aic_pcmcia.c,v 1.18 2001/11/13 07:26:32 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Marc Horowitz. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Marc Horowitz. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: aic_pcmcia.c,v 1.18 2001/11/13 07:26:32 lukem Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/select.h> 38 #include <sys/device.h> 39 40 #include <machine/cpu.h> 41 #include <machine/bus.h> 42 #include <machine/intr.h> 43 44 #include <dev/scsipi/scsipi_all.h> 45 #include <dev/scsipi/scsipiconf.h> 46 #include <dev/scsipi/scsi_all.h> 47 48 #include <dev/ic/aic6360var.h> 49 50 #include <dev/pcmcia/pcmciareg.h> 51 #include <dev/pcmcia/pcmciavar.h> 52 #include <dev/pcmcia/pcmciadevs.h> 53 54 int aic_pcmcia_match __P((struct device *, struct cfdata *, void *)); 55 void aic_pcmcia_attach __P((struct device *, struct device *, void *)); 56 int aic_pcmcia_detach __P((struct device *, int)); 57 58 struct aic_pcmcia_softc { 59 struct aic_softc sc_aic; /* real "aic" softc */ 60 61 /* PCMCIA-specific goo. */ 62 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */ 63 int sc_io_window; /* our i/o window */ 64 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 65 void *sc_ih; /* interrupt handler */ 66 int sc_flags; 67 #define AIC_PCMCIA_ATTACH 0x0001 /* attach is in progress */ 68 }; 69 70 struct cfattach aic_pcmcia_ca = { 71 sizeof(struct aic_pcmcia_softc), aic_pcmcia_match, aic_pcmcia_attach, 72 aic_pcmcia_detach, aic_activate 73 }; 74 75 int aic_pcmcia_enable __P((struct device *, int)); 76 77 const struct pcmcia_product aic_pcmcia_products[] = { 78 { PCMCIA_STR_ADAPTEC_APA1460, PCMCIA_VENDOR_ADAPTEC, 79 PCMCIA_PRODUCT_ADAPTEC_APA1460, 0 }, 80 81 { PCMCIA_STR_ADAPTEC_APA1460A, PCMCIA_VENDOR_ADAPTEC, 82 PCMCIA_PRODUCT_ADAPTEC_APA1460A, 0 }, 83 84 { PCMCIA_STR_NEWMEDIA_BUSTOASTER, PCMCIA_VENDOR_NEWMEDIA, 85 PCMCIA_PRODUCT_NEWMEDIA_BUSTOASTER, 0 }, 86 87 { NULL } 88 }; 89 90 int 91 aic_pcmcia_match(parent, match, aux) 92 struct device *parent; 93 struct cfdata *match; 94 void *aux; 95 { 96 struct pcmcia_attach_args *pa = aux; 97 98 if (pcmcia_product_lookup(pa, aic_pcmcia_products, 99 sizeof aic_pcmcia_products[0], NULL) != NULL) 100 return (1); 101 return (0); 102 } 103 104 void 105 aic_pcmcia_attach(parent, self, aux) 106 struct device *parent, *self; 107 void *aux; 108 { 109 struct aic_pcmcia_softc *psc = (void *)self; 110 struct aic_softc *sc = &psc->sc_aic; 111 struct pcmcia_attach_args *pa = aux; 112 struct pcmcia_config_entry *cfe; 113 struct pcmcia_function *pf = pa->pf; 114 const struct pcmcia_product *pp; 115 116 psc->sc_pf = pf; 117 118 for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL; 119 cfe = SIMPLEQ_NEXT(cfe, cfe_list)) { 120 if (cfe->num_memspace != 0 || 121 cfe->num_iospace != 1) 122 continue; 123 124 /* 125 * The bustoaster has a default config as first 126 * entry, we don't want to use that. 127 */ 128 if (pa->manufacturer == PCMCIA_VENDOR_NEWMEDIA && 129 pa->product == PCMCIA_PRODUCT_NEWMEDIA_BUSTOASTER && 130 cfe->iospace[0].start == 0) 131 continue; 132 133 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start, 134 cfe->iospace[0].length, 0, &psc->sc_pcioh) == 0) 135 break; 136 } 137 138 if (cfe == 0) { 139 printf(": can't alloc i/o space\n"); 140 goto no_config_entry; 141 } 142 143 sc->sc_iot = psc->sc_pcioh.iot; 144 sc->sc_ioh = psc->sc_pcioh.ioh; 145 146 /* Enable the card. */ 147 pcmcia_function_init(pf, cfe); 148 if (pcmcia_function_enable(pf)) { 149 printf(": function enable failed\n"); 150 goto enable_failed; 151 } 152 153 /* Map in the io space */ 154 if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, psc->sc_pcioh.size, 155 &psc->sc_pcioh, &psc->sc_io_window)) { 156 printf(": can't map i/o space\n"); 157 goto iomap_failed; 158 } 159 160 if (!aic_find(sc->sc_iot, sc->sc_ioh)) { 161 printf(": unable to detect chip!\n"); 162 goto no_aic_found; 163 } 164 165 pp = pcmcia_product_lookup(pa, aic_pcmcia_products, 166 sizeof aic_pcmcia_products[0], NULL); 167 if (pp == NULL) { 168 printf("\n"); 169 panic("aic_pcmcia_attach: impossible"); 170 } 171 172 printf(": %s\n", pp->pp_name); 173 174 /* We can enable and disable the controller. */ 175 sc->sc_adapter.adapt_enable = aic_pcmcia_enable; 176 177 psc->sc_flags |= AIC_PCMCIA_ATTACH; 178 aicattach(sc); 179 psc->sc_flags &= ~AIC_PCMCIA_ATTACH; 180 return; 181 182 no_aic_found: 183 /* Unmap our i/o window. */ 184 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window); 185 186 iomap_failed: 187 /* Disable the device. */ 188 pcmcia_function_disable(psc->sc_pf); 189 190 enable_failed: 191 /* Unmap our i/o space. */ 192 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh); 193 194 no_config_entry: 195 psc->sc_io_window = -1; 196 } 197 198 int 199 aic_pcmcia_detach(self, flags) 200 struct device *self; 201 int flags; 202 { 203 struct aic_pcmcia_softc *sc = (struct aic_pcmcia_softc *)self; 204 int error; 205 206 if (sc->sc_io_window == -1) 207 /* Nothing to detach. */ 208 return (0); 209 210 if ((error = aic_detach(self, flags)) != 0) 211 return (error); 212 213 /* Unmap our i/o window and i/o space. */ 214 pcmcia_io_unmap(sc->sc_pf, sc->sc_io_window); 215 pcmcia_io_free(sc->sc_pf, &sc->sc_pcioh); 216 217 return (0); 218 } 219 int 220 aic_pcmcia_enable(self, onoff) 221 struct device *self; 222 int onoff; 223 { 224 struct aic_pcmcia_softc *psc = (void *)self; 225 226 if (onoff) { 227 /* Establish the interrupt handler. */ 228 psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_BIO, 229 aicintr, &psc->sc_aic); 230 if (psc->sc_ih == NULL) { 231 printf("%s: couldn't establish interrupt handler\n", 232 psc->sc_aic.sc_dev.dv_xname); 233 return (EIO); 234 } 235 236 /* 237 * If attach is in progress, we know that card power is 238 * enabled and chip will be initialized later. 239 * Otherwise, enable and reset now. 240 */ 241 if ((psc->sc_flags & AIC_PCMCIA_ATTACH) == 0) { 242 if (pcmcia_function_enable(psc->sc_pf)) { 243 printf("%s: couldn't enable PCMCIA function\n", 244 psc->sc_aic.sc_dev.dv_xname); 245 pcmcia_intr_disestablish(psc->sc_pf, 246 psc->sc_ih); 247 return (EIO); 248 } 249 250 /* Initialize only chip. */ 251 aic_init(&psc->sc_aic, 0); 252 } 253 } else { 254 pcmcia_function_disable(psc->sc_pf); 255 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); 256 } 257 258 return (0); 259 } 260