1 /* $NetBSD: isa.c,v 1.115 2002/10/02 03:10:48 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.115 2002/10/02 03:10:48 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 CFATTACH_DECL(isa, sizeof(struct isa_softc), 67 isamatch, isaattach, NULL, NULL); 68 69 void isa_attach_knowndevs(struct isa_softc *); 70 void isa_free_knowndevs(struct isa_softc *); 71 72 int isasubmatch(struct device *, struct cfdata *, void *); 73 int isasearch(struct device *, struct cfdata *, void *); 74 75 int 76 isamatch(struct device *parent, struct cfdata *cf, void *aux) 77 { 78 struct isabus_attach_args *iba = aux; 79 80 if (strcmp(iba->iba_busname, cf->cf_name)) 81 return (0); 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 94 TAILQ_INIT(&sc->sc_knowndevs); 95 sc->sc_dynamicdevs = 0; 96 97 isa_attach_hook(parent, self, iba); 98 printf("\n"); 99 100 /* XXX Add code to fetch known-devices. */ 101 102 sc->sc_iot = iba->iba_iot; 103 sc->sc_memt = iba->iba_memt; 104 sc->sc_dmat = iba->iba_dmat; 105 sc->sc_ic = iba->iba_ic; 106 107 #if NISAPNP > 0 108 /* 109 * Reset isapnp cards that the bios configured for us 110 */ 111 isapnp_isa_attach_hook(sc); 112 #endif 113 114 #if NISADMA > 0 115 /* 116 * Initialize our DMA state. 117 */ 118 isa_dmainit(sc->sc_ic, sc->sc_iot, sc->sc_dmat, self); 119 #endif 120 121 /* Attach all direct-config children. */ 122 isa_attach_knowndevs(sc); 123 124 /* 125 * If we don't support dynamic hello/goodbye of devices, 126 * then free the knowndevs info now. 127 */ 128 if (sc->sc_dynamicdevs == 0) 129 isa_free_knowndevs(sc); 130 131 /* Attach all indrect-config children. */ 132 config_search(isasearch, self, NULL); 133 } 134 135 void 136 isa_attach_knowndevs(struct isa_softc *sc) 137 { 138 struct isa_attach_args ia; 139 struct isa_knowndev *ik; 140 141 if (TAILQ_EMPTY(&sc->sc_knowndevs)) 142 return; 143 144 TAILQ_FOREACH(ik, &sc->sc_knowndevs, ik_list) { 145 if (ik->ik_claimed != NULL) 146 continue; 147 148 ia.ia_iot = sc->sc_iot; 149 ia.ia_memt = sc->sc_memt; 150 ia.ia_dmat = sc->sc_dmat; 151 ia.ia_ic = sc->sc_ic; 152 153 ia.ia_pnpname = ik->ik_pnpname; 154 ia.ia_pnpcompatnames = ik->ik_pnpcompatnames; 155 156 ia.ia_io = ik->ik_io; 157 ia.ia_nio = ik->ik_nio; 158 159 ia.ia_iomem = ik->ik_iomem; 160 ia.ia_niomem = ik->ik_niomem; 161 162 ia.ia_irq = ik->ik_irq; 163 ia.ia_nirq = ik->ik_nirq; 164 165 ia.ia_drq = ik->ik_drq; 166 ia.ia_ndrq = ik->ik_ndrq; 167 168 ia.ia_aux = NULL; 169 170 ik->ik_claimed = config_found_sm(&sc->sc_dev, &ia, 171 isaprint, isasubmatch); 172 } 173 } 174 175 void 176 isa_free_knowndevs(struct isa_softc *sc) 177 { 178 struct isa_knowndev *ik; 179 struct isa_pnpname *ipn; 180 181 #define FREEIT(x) if (x != NULL) free(x, M_DEVBUF) 182 183 while ((ik = TAILQ_FIRST(&sc->sc_knowndevs)) != NULL) { 184 TAILQ_REMOVE(&sc->sc_knowndevs, ik, ik_list); 185 FREEIT(ik->ik_pnpname); 186 while ((ipn = ik->ik_pnpcompatnames) != NULL) { 187 ik->ik_pnpcompatnames = ipn->ipn_next; 188 free(ipn->ipn_name, M_DEVBUF); 189 free(ipn, M_DEVBUF); 190 } 191 FREEIT(ik->ik_io); 192 FREEIT(ik->ik_iomem); 193 FREEIT(ik->ik_irq); 194 FREEIT(ik->ik_drq); 195 free(ik, M_DEVBUF); 196 } 197 198 #undef FREEIT 199 } 200 201 int 202 isasubmatch(struct device *parent, struct cfdata *cf, void *aux) 203 { 204 struct isa_attach_args *ia = aux; 205 int i; 206 207 if (ia->ia_nio == 0) { 208 if (cf->cf_iobase != ISACF_PORT_DEFAULT) 209 return (0); 210 } else { 211 if (cf->cf_iobase != ISACF_PORT_DEFAULT && 212 cf->cf_iobase != ia->ia_io[0].ir_addr) 213 return (0); 214 } 215 216 if (ia->ia_niomem == 0) { 217 if (cf->cf_maddr != ISACF_IOMEM_DEFAULT) 218 return (0); 219 } else { 220 if (cf->cf_maddr != ISACF_IOMEM_DEFAULT && 221 cf->cf_maddr != ia->ia_iomem[0].ir_addr) 222 return (0); 223 } 224 225 if (ia->ia_nirq == 0) { 226 if (cf->cf_irq != ISACF_IRQ_DEFAULT) 227 return (0); 228 } else { 229 if (cf->cf_irq != ISACF_IRQ_DEFAULT && 230 cf->cf_irq != ia->ia_irq[0].ir_irq) 231 return (0); 232 } 233 234 if (ia->ia_ndrq == 0) { 235 if (cf->cf_drq != ISACF_DRQ_DEFAULT) 236 return (0); 237 if (cf->cf_drq2 != ISACF_DRQ_DEFAULT) 238 return (0); 239 } else { 240 for (i = 0; i < 2; i++) { 241 if (i == ia->ia_ndrq) 242 break; 243 if (cf->cf_loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT && 244 cf->cf_loc[ISACF_DRQ + i] != ia->ia_drq[i].ir_drq) 245 return (0); 246 } 247 for (; i < 2; i++) { 248 if (cf->cf_loc[ISACF_DRQ + i] != ISACF_DRQ_DEFAULT) 249 return (0); 250 } 251 } 252 253 return (config_match(parent, cf, aux)); 254 } 255 256 int 257 isaprint(void *aux, const char *isa) 258 { 259 struct isa_attach_args *ia = aux; 260 const char *sep; 261 int i; 262 263 /* 264 * This block of code only fires if we have a direct-config'd 265 * device for which there is no driver match. 266 */ 267 if (isa != NULL) { 268 struct isa_pnpname *ipn; 269 270 if (ia->ia_pnpname != NULL) 271 printf("%s", ia->ia_pnpname); 272 if ((ipn = ia->ia_pnpcompatnames) != NULL) { 273 printf(" ("); /* ) */ 274 for (sep = ""; ipn != NULL; 275 ipn = ipn->ipn_next, sep = " ") { 276 printf("%s%s", sep, ipn->ipn_name); 277 } 278 /* ( */ printf(")"); 279 } 280 printf(" at %s", isa); 281 } 282 283 if (ia->ia_nio) { 284 sep = ""; 285 printf(" port "); 286 for (i = 0; i < ia->ia_nio; i++) { 287 if (ia->ia_io[i].ir_size == 0) 288 continue; 289 printf("%s0x%x", sep, ia->ia_io[i].ir_addr); 290 if (ia->ia_io[i].ir_size > 1) 291 printf("-0x%x", ia->ia_io[i].ir_addr + 292 ia->ia_io[i].ir_size - 1); 293 sep = ","; 294 } 295 } 296 297 if (ia->ia_niomem) { 298 sep = ""; 299 printf(" iomem "); 300 for (i = 0; i < ia->ia_niomem; i++) { 301 if (ia->ia_iomem[i].ir_size == 0) 302 continue; 303 printf("%s0x%x", sep, ia->ia_iomem[i].ir_addr); 304 if (ia->ia_iomem[i].ir_size > 1) 305 printf("-0x%x", ia->ia_iomem[i].ir_addr + 306 ia->ia_iomem[i].ir_size - 1); 307 sep = ","; 308 } 309 } 310 311 if (ia->ia_nirq) { 312 sep = ""; 313 printf(" irq "); 314 for (i = 0; i < ia->ia_nirq; i++) { 315 if (ia->ia_irq[i].ir_irq == ISACF_IRQ_DEFAULT) 316 continue; 317 printf("%s%d", sep, ia->ia_irq[i].ir_irq); 318 sep = ","; 319 } 320 } 321 322 if (ia->ia_ndrq) { 323 sep = ""; 324 printf(" drq "); 325 for (i = 0; i < ia->ia_ndrq; i++) { 326 if (ia->ia_drq[i].ir_drq == ISACF_DRQ_DEFAULT) 327 continue; 328 printf("%s%d", sep, ia->ia_drq[i].ir_drq); 329 sep = ","; 330 } 331 } 332 333 return (UNCONF); 334 } 335 336 int 337 isasearch(struct device *parent, struct cfdata *cf, void *aux) 338 { 339 struct isa_io res_io[1]; 340 struct isa_iomem res_mem[1]; 341 struct isa_irq res_irq[1]; 342 struct isa_drq res_drq[2]; 343 struct isa_softc *sc = (struct isa_softc *)parent; 344 struct isa_attach_args ia; 345 int tryagain; 346 347 do { 348 ia.ia_pnpname = NULL; 349 ia.ia_pnpcompatnames = NULL; 350 351 res_io[0].ir_addr = cf->cf_loc[ISACF_PORT]; 352 res_io[0].ir_size = 0; 353 354 res_mem[0].ir_addr = cf->cf_loc[ISACF_IOMEM]; 355 res_mem[0].ir_size = cf->cf_loc[ISACF_IOSIZ]; 356 357 res_irq[0].ir_irq = 358 cf->cf_loc[ISACF_IRQ] == 2 ? 9 : cf->cf_loc[ISACF_IRQ]; 359 360 res_drq[0].ir_drq = cf->cf_loc[ISACF_DRQ]; 361 res_drq[1].ir_drq = cf->cf_loc[ISACF_DRQ2]; 362 363 ia.ia_iot = sc->sc_iot; 364 ia.ia_memt = sc->sc_memt; 365 ia.ia_dmat = sc->sc_dmat; 366 ia.ia_ic = sc->sc_ic; 367 368 ia.ia_io = res_io; 369 ia.ia_nio = 1; 370 371 ia.ia_iomem = res_mem; 372 ia.ia_niomem = 1; 373 374 ia.ia_irq = res_irq; 375 ia.ia_nirq = 1; 376 377 ia.ia_drq = res_drq; 378 ia.ia_ndrq = 2; 379 380 tryagain = 0; 381 if (config_match(parent, cf, &ia) > 0) { 382 config_attach(parent, cf, &ia, isaprint); 383 tryagain = (cf->cf_fstate == FSTATE_STAR); 384 } 385 } while (tryagain); 386 387 return (0); 388 } 389 390 char * 391 isa_intr_typename(int type) 392 { 393 394 switch (type) { 395 case IST_NONE : 396 return ("none"); 397 case IST_PULSE: 398 return ("pulsed"); 399 case IST_EDGE: 400 return ("edge-triggered"); 401 case IST_LEVEL: 402 return ("level-triggered"); 403 default: 404 panic("isa_intr_typename: invalid type %d", type); 405 } 406 } 407