1 /* $NetBSD: isa.c,v 1.110 2002/01/07 21:47:09 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum; by Jason R. Thorpe of Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: isa.c,v 1.110 2002/01/07 21:47:09 thorpej Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/malloc.h> 46 #include <sys/device.h> 47 48 #include <machine/intr.h> 49 50 #include <dev/isa/isareg.h> 51 #include <dev/isa/isavar.h> 52 #include <dev/isa/isadmareg.h> 53 54 #include "isadma.h" 55 56 #include "isapnp.h" 57 #if NISAPNP > 0 58 #include <dev/isapnp/isapnpreg.h> 59 #include <dev/isapnp/isapnpvar.h> 60 #endif 61 62 int isamatch(struct device *, struct cfdata *, void *); 63 void isaattach(struct device *, struct device *, void *); 64 int isaprint(void *, const char *); 65 66 struct cfattach isa_ca = { 67 sizeof(struct isa_softc), isamatch, isaattach 68 }; 69 70 void isa_attach_knowndevs(struct isa_softc *); 71 void isa_free_knowndevs(struct isa_softc *); 72 73 int isasubmatch(struct device *, struct cfdata *, void *); 74 int isasearch(struct device *, struct cfdata *, void *); 75 76 int 77 isamatch(struct device *parent, struct cfdata *cf, void *aux) 78 { 79 struct isabus_attach_args *iba = aux; 80 81 if (strcmp(iba->iba_busname, cf->cf_driver->cd_name)) 82 return (0); 83 84 /* XXX check other indicators */ 85 86 return (1); 87 } 88 89 void 90 isaattach(struct device *parent, struct device *self, void *aux) 91 { 92 struct isa_softc *sc = (struct isa_softc *)self; 93 struct isabus_attach_args *iba = aux; 94 95 TAILQ_INIT(&sc->sc_knowndevs); 96 sc->sc_dynamicdevs = 0; 97 98 isa_attach_hook(parent, self, iba); 99 printf("\n"); 100 101 /* XXX Add code to fetch known-devices. */ 102 103 sc->sc_iot = iba->iba_iot; 104 sc->sc_memt = iba->iba_memt; 105 sc->sc_dmat = iba->iba_dmat; 106 sc->sc_ic = iba->iba_ic; 107 108 #if NISAPNP > 0 109 /* 110 * Reset isapnp cards that the bios configured for us 111 */ 112 isapnp_isa_attach_hook(sc); 113 #endif 114 115 #if NISADMA > 0 116 /* 117 * Initialize our DMA state. 118 */ 119 isa_dmainit(sc->sc_ic, sc->sc_iot, sc->sc_dmat, self); 120 #endif 121 122 /* Attach all direct-config children. */ 123 isa_attach_knowndevs(sc); 124 125 /* 126 * If we don't support dynamic hello/goodbye of devices, 127 * then free the knowndevs info now. 128 */ 129 if (sc->sc_dynamicdevs == 0) 130 isa_free_knowndevs(sc); 131 132 /* Attach all indrect-config children. */ 133 config_search(isasearch, self, NULL); 134 } 135 136 void 137 isa_attach_knowndevs(struct isa_softc *sc) 138 { 139 struct isa_attach_args ia; 140 struct isa_knowndev *ik; 141 142 if (TAILQ_EMPTY(&sc->sc_knowndevs)) 143 return; 144 145 TAILQ_FOREACH(ik, &sc->sc_knowndevs, ik_list) { 146 if (ik->ik_claimed != NULL) 147 continue; 148 149 ia.ia_iot = sc->sc_iot; 150 ia.ia_memt = sc->sc_memt; 151 ia.ia_dmat = sc->sc_dmat; 152 ia.ia_ic = sc->sc_ic; 153 154 ia.ia_pnpname = ik->ik_pnpname; 155 ia.ia_pnpcompatnames = ik->ik_pnpcompatnames; 156 157 ia.ia_io = ik->ik_io; 158 ia.ia_nio = ik->ik_nio; 159 160 ia.ia_iomem = ik->ik_iomem; 161 ia.ia_niomem = ik->ik_niomem; 162 163 ia.ia_irq = ik->ik_irq; 164 ia.ia_nirq = ik->ik_nirq; 165 166 ia.ia_drq = ik->ik_drq; 167 ia.ia_ndrq = ik->ik_ndrq; 168 169 ia.ia_aux = NULL; 170 171 ik->ik_claimed = config_found_sm(&sc->sc_dev, &ia, 172 isaprint, isasubmatch); 173 } 174 } 175 176 void 177 isa_free_knowndevs(struct isa_softc *sc) 178 { 179 struct isa_knowndev *ik; 180 struct isa_pnpname *ipn; 181 182 #define FREEIT(x) if (x != NULL) free(x, M_DEVBUF) 183 184 while ((ik = TAILQ_FIRST(&sc->sc_knowndevs)) != NULL) { 185 TAILQ_REMOVE(&sc->sc_knowndevs, ik, ik_list); 186 FREEIT(ik->ik_pnpname); 187 while ((ipn = ik->ik_pnpcompatnames) != NULL) { 188 ik->ik_pnpcompatnames = ipn->ipn_next; 189 free(ipn->ipn_name, M_DEVBUF); 190 free(ipn, M_DEVBUF); 191 } 192 FREEIT(ik->ik_io); 193 FREEIT(ik->ik_iomem); 194 FREEIT(ik->ik_irq); 195 FREEIT(ik->ik_drq); 196 free(ik, M_DEVBUF); 197 } 198 199 #undef FREEIT 200 } 201 202 int 203 isasubmatch(struct device *parent, struct cfdata *cf, void *aux) 204 { 205 struct isa_attach_args *ia = aux; 206 int i; 207 208 if (ia->ia_nio == 0) { 209 if (cf->cf_iobase != ISACF_PORT_DEFAULT) 210 return (0); 211 } else { 212 if (cf->cf_iobase != ISACF_PORT_DEFAULT && 213 cf->cf_iobase != ia->ia_io[0].ir_addr) 214 return (0); 215 } 216 217 if (ia->ia_niomem == 0) { 218 if (cf->cf_maddr != ISACF_IOMEM_DEFAULT) 219 return (0); 220 } else { 221 if (cf->cf_maddr != ISACF_IOMEM_DEFAULT && 222 cf->cf_maddr != ia->ia_iomem[0].ir_addr) 223 return (0); 224 } 225 226 if (ia->ia_nirq == 0) { 227 if (cf->cf_irq != ISACF_IRQ_DEFAULT) 228 return (0); 229 } else { 230 if (cf->cf_irq != ISACF_IRQ_DEFAULT && 231 cf->cf_irq != ia->ia_irq[0].ir_irq) 232 return (0); 233 } 234 235 if (ia->ia_ndrq == 0) { 236 if (cf->cf_drq != ISACF_DRQ_DEFAULT) 237 return (0); 238 if (cf->cf_drq2 != ISACF_DRQ_DEFAULT) 239 return (0); 240 } else { 241 for (i = 0; i < 2; i++) { 242 if (i == ia->ia_ndrq) 243 break; 244 if (cf->cf_loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT && 245 cf->cf_loc[ISACF_DRQ + i] != ia->ia_drq[i].ir_drq) 246 return (0); 247 } 248 for (; i < 2; i++) { 249 if (cf->cf_loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT) 250 return (0); 251 } 252 } 253 254 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 255 } 256 257 int 258 isaprint(void *aux, const char *isa) 259 { 260 struct isa_attach_args *ia = aux; 261 const char *sep; 262 int i; 263 264 /* 265 * This block of code only fires if we have a direct-config'd 266 * device for which there is no driver match. 267 */ 268 if (isa != NULL) { 269 struct isa_pnpname *ipn; 270 271 if (ia->ia_pnpname != NULL) 272 printf("%s", ia->ia_pnpname); 273 if ((ipn = ia->ia_pnpcompatnames) != NULL) { 274 printf(" ("); /* ) */ 275 for (sep = ""; ipn != NULL; 276 ipn = ipn->ipn_next, sep = " ") { 277 printf("%s%s", sep, ipn->ipn_name); 278 } 279 /* ( */ printf(")"); 280 } 281 printf(" at %s", isa); 282 } 283 284 if (ia->ia_nio) { 285 sep = ""; 286 printf(" port "); 287 for (i = 0; i < ia->ia_nio; i++) { 288 if (ia->ia_io[i].ir_size == 0) 289 continue; 290 printf("%s0x%x", sep, ia->ia_io[i].ir_addr); 291 if (ia->ia_io[i].ir_size > 1) 292 printf("-0x%x", ia->ia_io[i].ir_addr + 293 ia->ia_io[i].ir_size - 1); 294 sep = ","; 295 } 296 } 297 298 if (ia->ia_niomem) { 299 sep = ""; 300 printf(" iomem "); 301 for (i = 0; i < ia->ia_niomem; i++) { 302 if (ia->ia_iomem[i].ir_size == 0) 303 continue; 304 printf("%s0x%x", sep, ia->ia_iomem[i].ir_addr); 305 if (ia->ia_iomem[i].ir_size > 1) 306 printf("-0x%x", ia->ia_iomem[i].ir_addr + 307 ia->ia_iomem[i].ir_size - 1); 308 sep = ","; 309 } 310 } 311 312 if (ia->ia_nirq) { 313 sep = ""; 314 printf(" irq "); 315 for (i = 0; i < ia->ia_nirq; i++) { 316 if (ia->ia_irq[i].ir_irq == ISACF_IRQ_DEFAULT) 317 continue; 318 printf("%s%d", sep, ia->ia_irq[i].ir_irq); 319 sep = ","; 320 } 321 } 322 323 if (ia->ia_ndrq) { 324 sep = ""; 325 printf(" drq "); 326 for (i = 0; i < ia->ia_ndrq; i++) { 327 if (ia->ia_drq[i].ir_drq == ISACF_DRQ_DEFAULT) 328 continue; 329 printf("%s%d", sep, ia->ia_drq[i].ir_drq); 330 sep = ","; 331 } 332 } 333 334 return (UNCONF); 335 } 336 337 int 338 isasearch(struct device *parent, struct cfdata *cf, void *aux) 339 { 340 struct isa_io res_io[1]; 341 struct isa_iomem res_mem[1]; 342 struct isa_irq res_irq[1]; 343 struct isa_drq res_drq[2]; 344 struct isa_softc *sc = (struct isa_softc *)parent; 345 struct isa_attach_args ia; 346 int tryagain; 347 348 do { 349 ia.ia_pnpname = NULL; 350 ia.ia_pnpcompatnames = NULL; 351 352 res_io[0].ir_addr = cf->cf_loc[ISACF_PORT]; 353 res_io[0].ir_size = 0; 354 355 res_mem[0].ir_addr = cf->cf_loc[ISACF_IOMEM]; 356 res_mem[0].ir_size = cf->cf_loc[ISACF_IOSIZ]; 357 358 res_irq[0].ir_irq = 359 cf->cf_loc[ISACF_IRQ] == 2 ? 9 : cf->cf_loc[ISACF_IRQ]; 360 361 res_drq[0].ir_drq = cf->cf_loc[ISACF_DRQ]; 362 res_drq[1].ir_drq = cf->cf_loc[ISACF_DRQ2]; 363 364 ia.ia_iot = sc->sc_iot; 365 ia.ia_memt = sc->sc_memt; 366 ia.ia_dmat = sc->sc_dmat; 367 ia.ia_ic = sc->sc_ic; 368 369 ia.ia_io = res_io; 370 ia.ia_nio = 1; 371 372 ia.ia_iomem = res_mem; 373 ia.ia_niomem = 1; 374 375 ia.ia_irq = res_irq; 376 ia.ia_nirq = 1; 377 378 ia.ia_drq = res_drq; 379 ia.ia_ndrq = 2; 380 381 tryagain = 0; 382 if ((*cf->cf_attach->ca_match)(parent, cf, &ia) > 0) { 383 config_attach(parent, cf, &ia, isaprint); 384 tryagain = (cf->cf_fstate == FSTATE_STAR); 385 } 386 } while (tryagain); 387 388 return (0); 389 } 390 391 char * 392 isa_intr_typename(int type) 393 { 394 395 switch (type) { 396 case IST_NONE : 397 return ("none"); 398 case IST_PULSE: 399 return ("pulsed"); 400 case IST_EDGE: 401 return ("edge-triggered"); 402 case IST_LEVEL: 403 return ("level-triggered"); 404 default: 405 panic("isa_intr_typename: invalid type %d", type); 406 } 407 } 408