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