1 /* $NetBSD: isa.c,v 1.125 2006/10/12 01:31:17 christos 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.125 2006/10/12 01:31:17 christos 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 #include "locators.h" 63 64 int isamatch(struct device *, struct cfdata *, void *); 65 void isaattach(struct device *, struct device *, void *); 66 int isarescan(struct device *, const char *, const int *); 67 void isachilddetached(struct device *, struct device *); 68 int isaprint(void *, const char *); 69 70 CFATTACH_DECL2(isa, sizeof(struct isa_softc), 71 isamatch, isaattach, NULL, NULL, isarescan, isachilddetached); 72 73 void isa_attach_knowndevs(struct isa_softc *); 74 void isa_free_knowndevs(struct isa_softc *); 75 76 int isasubmatch(struct device *, struct cfdata *, const int *, void *); 77 int isasearch(struct device *, struct cfdata *, const int *, void *); 78 79 int 80 isamatch(struct device *parent __unused, struct cfdata *cf __unused, 81 void *aux __unused) 82 { 83 /* XXX check other indicators */ 84 85 return (1); 86 } 87 88 void 89 isaattach(struct device *parent, struct device *self, void *aux) 90 { 91 struct isa_softc *sc = (struct isa_softc *)self; 92 struct isabus_attach_args *iba = aux; 93 static const int wildcard[ISACF_NLOCS] = { 94 ISACF_PORT_DEFAULT, ISACF_SIZE_DEFAULT, 95 ISACF_IOMEM_DEFAULT, ISACF_IOSIZ_DEFAULT, 96 ISACF_IRQ_DEFAULT, ISACF_DRQ_DEFAULT, ISACF_DRQ2_DEFAULT 97 }; 98 99 TAILQ_INIT(&sc->sc_knowndevs); 100 sc->sc_dynamicdevs = 0; 101 102 isa_attach_hook(parent, self, iba); 103 printf("\n"); 104 105 /* XXX Add code to fetch known-devices. */ 106 107 sc->sc_iot = iba->iba_iot; 108 sc->sc_memt = iba->iba_memt; 109 sc->sc_dmat = iba->iba_dmat; 110 sc->sc_ic = iba->iba_ic; 111 112 #if NISAPNP > 0 113 /* 114 * Reset isapnp cards that the bios configured for us 115 */ 116 isapnp_isa_attach_hook(sc); 117 #endif 118 119 #if NISADMA > 0 120 /* 121 * Initialize our DMA state. 122 */ 123 isa_dmainit(sc->sc_ic, sc->sc_iot, sc->sc_dmat, self); 124 #endif 125 126 /* Attach all direct-config children. */ 127 isa_attach_knowndevs(sc); 128 129 /* 130 * If we don't support dynamic hello/goodbye of devices, 131 * then free the knowndevs info now. 132 */ 133 if (sc->sc_dynamicdevs == 0) 134 isa_free_knowndevs(sc); 135 136 /* Attach all indrect-config children. */ 137 isarescan(self, "isa", wildcard); 138 } 139 140 int 141 isarescan(struct device *self, const char *ifattr, const int *locators) 142 { 143 int locs[ISACF_NLOCS]; 144 145 memcpy(locs, locators, sizeof(locs)); 146 147 /* 148 * XXX Bus independant code calling this function does not 149 * know the locator default values. It assumes "-1" for now. 150 * (should be made available by "config" one day) 151 * So fixup where the "-1" is not correct. 152 */ 153 if (locs[ISACF_SIZE] == -1) 154 locs[ISACF_SIZE] = ISACF_SIZE_DEFAULT; 155 if (locs[ISACF_IOSIZ] == -1) 156 locs[ISACF_IOSIZ] = ISACF_IOSIZ_DEFAULT; 157 158 config_search_loc(isasearch, self, ifattr, locs, NULL); 159 return (0); 160 } 161 162 void 163 isachilddetached(struct device *self __unused, struct device *child __unused) 164 { 165 /* nothing to do */ 166 } 167 168 void 169 isa_attach_knowndevs(struct isa_softc *sc) 170 { 171 struct isa_attach_args ia; 172 struct isa_knowndev *ik; 173 174 if (TAILQ_EMPTY(&sc->sc_knowndevs)) 175 return; 176 177 TAILQ_FOREACH(ik, &sc->sc_knowndevs, ik_list) { 178 if (ik->ik_claimed != NULL) 179 continue; 180 181 ia.ia_iot = sc->sc_iot; 182 ia.ia_memt = sc->sc_memt; 183 ia.ia_dmat = sc->sc_dmat; 184 ia.ia_ic = sc->sc_ic; 185 186 ia.ia_pnpname = ik->ik_pnpname; 187 ia.ia_pnpcompatnames = ik->ik_pnpcompatnames; 188 189 ia.ia_io = ik->ik_io; 190 ia.ia_nio = ik->ik_nio; 191 192 ia.ia_iomem = ik->ik_iomem; 193 ia.ia_niomem = ik->ik_niomem; 194 195 ia.ia_irq = ik->ik_irq; 196 ia.ia_nirq = ik->ik_nirq; 197 198 ia.ia_drq = ik->ik_drq; 199 ia.ia_ndrq = ik->ik_ndrq; 200 201 ia.ia_aux = NULL; 202 203 /* XXX should setup locator array */ 204 205 ik->ik_claimed = config_found_sm_loc(&sc->sc_dev, 206 "isa", 0, &ia, isaprint, isasubmatch); 207 } 208 } 209 210 void 211 isa_free_knowndevs(struct isa_softc *sc) 212 { 213 struct isa_knowndev *ik; 214 struct isa_pnpname *ipn; 215 216 #define FREEIT(x) if (x != NULL) free(x, M_DEVBUF) 217 218 while ((ik = TAILQ_FIRST(&sc->sc_knowndevs)) != NULL) { 219 TAILQ_REMOVE(&sc->sc_knowndevs, ik, ik_list); 220 FREEIT(ik->ik_pnpname); 221 while ((ipn = ik->ik_pnpcompatnames) != NULL) { 222 ik->ik_pnpcompatnames = ipn->ipn_next; 223 free(ipn->ipn_name, M_DEVBUF); 224 free(ipn, M_DEVBUF); 225 } 226 FREEIT(ik->ik_io); 227 FREEIT(ik->ik_iomem); 228 FREEIT(ik->ik_irq); 229 FREEIT(ik->ik_drq); 230 free(ik, M_DEVBUF); 231 } 232 233 #undef FREEIT 234 } 235 236 static int 237 checkattachargs(struct isa_attach_args *ia, const int *loc) 238 { 239 int i; 240 241 if (ia->ia_nio == 0) { 242 if (loc[ISACF_PORT] != ISACF_PORT_DEFAULT) 243 return (0); 244 } else { 245 if (loc[ISACF_PORT] != ISACF_PORT_DEFAULT && 246 loc[ISACF_PORT] != ia->ia_io[0].ir_addr) 247 return (0); 248 } 249 250 if (ia->ia_niomem == 0) { 251 if (loc[ISACF_IOMEM] != ISACF_IOMEM_DEFAULT) 252 return (0); 253 } else { 254 if (loc[ISACF_IOMEM] != ISACF_IOMEM_DEFAULT && 255 loc[ISACF_IOMEM] != ia->ia_iomem[0].ir_addr) 256 return (0); 257 } 258 259 if (ia->ia_nirq == 0) { 260 if (loc[ISACF_IRQ] != ISACF_IRQ_DEFAULT) 261 return (0); 262 } else { 263 if (loc[ISACF_IRQ] != ISACF_IRQ_DEFAULT && 264 loc[ISACF_IRQ] != ia->ia_irq[0].ir_irq) 265 return (0); 266 } 267 268 if (ia->ia_ndrq == 0) { 269 if (loc[ISACF_DRQ] != ISACF_DRQ_DEFAULT) 270 return (0); 271 if (loc[ISACF_DRQ2] != ISACF_DRQ2_DEFAULT) 272 return (0); 273 } else { 274 for (i = 0; i < 2; i++) { 275 if (i == ia->ia_ndrq) 276 break; 277 if (loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT && 278 loc[ISACF_DRQ + i] != ia->ia_drq[i].ir_drq) 279 return (0); 280 } 281 for (; i < 2; i++) { 282 if (loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT) 283 return (0); 284 } 285 } 286 287 return (1); 288 } 289 290 int 291 isasubmatch(struct device *parent, struct cfdata *cf, 292 const int *ldesc __unused, void *aux) 293 { 294 struct isa_attach_args *ia = aux; 295 296 if (!checkattachargs(ia, cf->cf_loc)) 297 return (0); 298 299 return (config_match(parent, cf, aux)); 300 } 301 302 int 303 isaprint(void *aux, const char *isa) 304 { 305 struct isa_attach_args *ia = aux; 306 const char *sep; 307 int i; 308 309 /* 310 * This block of code only fires if we have a direct-config'd 311 * device for which there is no driver match. 312 */ 313 if (isa != NULL) { 314 struct isa_pnpname *ipn; 315 316 if (ia->ia_pnpname != NULL) 317 aprint_normal("%s", ia->ia_pnpname); 318 if ((ipn = ia->ia_pnpcompatnames) != NULL) { 319 aprint_normal(" ("); /* ) */ 320 for (sep = ""; ipn != NULL; 321 ipn = ipn->ipn_next, sep = " ") { 322 aprint_normal("%s%s", sep, ipn->ipn_name); 323 } 324 /* ( */ aprint_normal(")"); 325 } 326 aprint_normal(" at %s", isa); 327 } 328 329 if (ia->ia_nio) { 330 sep = ""; 331 aprint_normal(" port "); 332 for (i = 0; i < ia->ia_nio; i++) { 333 if (ia->ia_io[i].ir_size == 0) 334 continue; 335 aprint_normal("%s0x%x", sep, ia->ia_io[i].ir_addr); 336 if (ia->ia_io[i].ir_size > 1) 337 aprint_normal("-0x%x", ia->ia_io[i].ir_addr + 338 ia->ia_io[i].ir_size - 1); 339 sep = ","; 340 } 341 } 342 343 if (ia->ia_niomem) { 344 sep = ""; 345 aprint_normal(" iomem "); 346 for (i = 0; i < ia->ia_niomem; i++) { 347 if (ia->ia_iomem[i].ir_size == 0) 348 continue; 349 aprint_normal("%s0x%x", sep, ia->ia_iomem[i].ir_addr); 350 if (ia->ia_iomem[i].ir_size > 1) 351 aprint_normal("-0x%x", ia->ia_iomem[i].ir_addr + 352 ia->ia_iomem[i].ir_size - 1); 353 sep = ","; 354 } 355 } 356 357 if (ia->ia_nirq) { 358 sep = ""; 359 aprint_normal(" irq "); 360 for (i = 0; i < ia->ia_nirq; i++) { 361 if (ia->ia_irq[i].ir_irq == ISACF_IRQ_DEFAULT) 362 continue; 363 aprint_normal("%s%d", sep, ia->ia_irq[i].ir_irq); 364 sep = ","; 365 } 366 } 367 368 if (ia->ia_ndrq) { 369 sep = ""; 370 aprint_normal(" drq "); 371 for (i = 0; i < ia->ia_ndrq; i++) { 372 if (ia->ia_drq[i].ir_drq == ISACF_DRQ_DEFAULT) 373 continue; 374 aprint_normal("%s%d", sep, ia->ia_drq[i].ir_drq); 375 sep = ","; 376 } 377 } 378 379 return (UNCONF); 380 } 381 382 int 383 isasearch(struct device *parent, struct cfdata *cf, 384 const int *slocs, void *aux __unused) 385 { 386 struct isa_io res_io[1]; 387 struct isa_iomem res_mem[1]; 388 struct isa_irq res_irq[1]; 389 struct isa_drq res_drq[2]; 390 struct isa_softc *sc = (struct isa_softc *)parent; 391 struct isa_attach_args ia; 392 int flocs[ISACF_NLOCS]; 393 int tryagain; 394 395 do { 396 ia.ia_pnpname = NULL; 397 ia.ia_pnpcompatnames = NULL; 398 399 res_io[0].ir_addr = cf->cf_loc[ISACF_PORT]; 400 res_io[0].ir_size = 0; 401 402 res_mem[0].ir_addr = cf->cf_loc[ISACF_IOMEM]; 403 res_mem[0].ir_size = cf->cf_loc[ISACF_IOSIZ]; 404 405 res_irq[0].ir_irq = 406 cf->cf_loc[ISACF_IRQ] == 2 ? 9 : cf->cf_loc[ISACF_IRQ]; 407 408 res_drq[0].ir_drq = cf->cf_loc[ISACF_DRQ]; 409 res_drq[1].ir_drq = cf->cf_loc[ISACF_DRQ2]; 410 411 ia.ia_iot = sc->sc_iot; 412 ia.ia_memt = sc->sc_memt; 413 ia.ia_dmat = sc->sc_dmat; 414 ia.ia_ic = sc->sc_ic; 415 416 ia.ia_io = res_io; 417 ia.ia_nio = 1; 418 419 ia.ia_iomem = res_mem; 420 ia.ia_niomem = 1; 421 422 ia.ia_irq = res_irq; 423 ia.ia_nirq = 1; 424 425 ia.ia_drq = res_drq; 426 ia.ia_ndrq = 2; 427 428 if (!checkattachargs(&ia, slocs)) 429 return (0); 430 431 tryagain = 0; 432 if (config_match(parent, cf, &ia) > 0) { 433 /* 434 * This is not necessary for detach, but might 435 * still be useful to collect device information. 436 */ 437 flocs[ISACF_PORT] = ia.ia_io[0].ir_addr; 438 flocs[ISACF_SIZE] = ia.ia_io[0].ir_size; 439 flocs[ISACF_IOMEM] = ia.ia_iomem[0].ir_addr; 440 flocs[ISACF_IOSIZ] = ia.ia_iomem[0].ir_size; 441 flocs[ISACF_IRQ] = ia.ia_irq[0].ir_irq; 442 flocs[ISACF_DRQ] = ia.ia_drq[0].ir_drq; 443 flocs[ISACF_DRQ2] = ia.ia_drq[1].ir_drq; 444 config_attach_loc(parent, cf, flocs, &ia, isaprint); 445 tryagain = (cf->cf_fstate == FSTATE_STAR); 446 } 447 } while (tryagain); 448 449 return (0); 450 } 451 452 const char * 453 isa_intr_typename(int type) 454 { 455 456 switch (type) { 457 case IST_NONE : 458 return ("none"); 459 case IST_PULSE: 460 return ("pulsed"); 461 case IST_EDGE: 462 return ("edge-triggered"); 463 case IST_LEVEL: 464 return ("level-triggered"); 465 default: 466 panic("isa_intr_typename: invalid type %d", type); 467 } 468 } 469