1 /* $OpenBSD: isapnpres.c,v 1.6 2002/06/30 16:05:59 miod Exp $ */ 2 /* $NetBSD: isapnpres.c,v 1.7.4.1 1997/11/20 07:46:13 mellon Exp $ */ 3 4 /* 5 * Copyright (c) 1996 Christos Zoulas. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christos Zoulas. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Resource parser for Plug and Play cards. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 42 #include <machine/bus.h> 43 44 #include <dev/isa/isapnpreg.h> 45 46 #include <dev/isa/isavar.h> 47 48 int isapnp_wait_status(struct isapnp_softc *); 49 struct isa_attach_args * 50 isapnp_newdev(struct isa_attach_args *); 51 struct isa_attach_args * 52 isapnp_newconf(struct isa_attach_args *); 53 void isapnp_merge(struct isa_attach_args *, 54 const struct isa_attach_args *); 55 struct isa_attach_args * 56 isapnp_flatten(struct isa_attach_args *); 57 int isapnp_process_tag(u_char, u_char, u_char *, 58 struct isa_attach_args **, struct isa_attach_args **, 59 struct isa_attach_args **); 60 61 #ifdef DEBUG_ISAPNP 62 # define DPRINTF(a) printf a 63 #else 64 # define DPRINTF(a) 65 #endif 66 67 /* isapnp_wait_status(): 68 * Wait for the next byte of resource data to become available 69 */ 70 int 71 isapnp_wait_status(sc) 72 struct isapnp_softc *sc; 73 { 74 int i; 75 76 /* wait up to 1 ms for each resource byte */ 77 for (i = 0; i < 10; i++) { 78 if (isapnp_read_reg(sc, ISAPNP_STATUS) & 1) 79 return 0; 80 DELAY(100); 81 } 82 return 1; 83 } 84 85 86 /* isapnp_newdev(): 87 * Add a new logical device to the current card; expand the configuration 88 * resources of the current card if needed. 89 */ 90 struct isa_attach_args * 91 isapnp_newdev(card) 92 struct isa_attach_args *card; 93 { 94 struct isa_attach_args *ipa, *dev = ISAPNP_MALLOC(sizeof(*dev)); 95 96 ISAPNP_CLONE_SETUP(dev, card); 97 98 dev->ipa_pref = ISAPNP_DEP_ACCEPTABLE; 99 bcopy(card->ipa_devident, dev->ipa_devident, 100 sizeof(card->ipa_devident)); 101 102 if (card->ipa_child == NULL) 103 card->ipa_child = dev; 104 else { 105 for (ipa = card->ipa_child; ipa->ipa_sibling != NULL; 106 ipa = ipa->ipa_sibling) 107 continue; 108 ipa->ipa_sibling = dev; 109 } 110 111 112 return dev; 113 } 114 115 116 /* isapnp_newconf(): 117 * Add a new alternate configuration to a logical device 118 */ 119 struct isa_attach_args * 120 isapnp_newconf(dev) 121 struct isa_attach_args *dev; 122 { 123 struct isa_attach_args *ipa, *conf = ISAPNP_MALLOC(sizeof(*conf)); 124 125 ISAPNP_CLONE_SETUP(conf, dev); 126 127 bcopy(dev->ipa_devident, conf->ipa_devident, 128 sizeof(conf->ipa_devident)); 129 bcopy(dev->ipa_devlogic, conf->ipa_devlogic, 130 sizeof(conf->ipa_devlogic)); 131 bcopy(dev->ipa_devcompat, conf->ipa_devcompat, 132 sizeof(conf->ipa_devcompat)); 133 bcopy(dev->ipa_devclass, conf->ipa_devclass, 134 sizeof(conf->ipa_devclass)); 135 136 if (dev->ipa_child == NULL) 137 dev->ipa_child = conf; 138 else { 139 for (ipa = dev->ipa_child; ipa->ipa_sibling; 140 ipa = ipa->ipa_sibling) 141 continue; 142 ipa->ipa_sibling = conf; 143 } 144 145 return conf; 146 } 147 148 149 /* isapnp_merge(): 150 * Merge the common device configurations to the subconfigurations 151 */ 152 void 153 isapnp_merge(c, d) 154 struct isa_attach_args *c; 155 const struct isa_attach_args *d; 156 { 157 int i; 158 159 for (i = 0; i < d->ipa_nio; i++) 160 c->ipa_io[c->ipa_nio++] = d->ipa_io[i]; 161 162 for (i = 0; i < d->ipa_nmem; i++) 163 c->ipa_mem[c->ipa_nmem++] = d->ipa_mem[i]; 164 165 for (i = 0; i < d->ipa_nmem32; i++) 166 c->ipa_mem32[c->ipa_nmem32++] = d->ipa_mem32[i]; 167 168 for (i = 0; i < d->ipa_nirq; i++) 169 c->ipa_irq[c->ipa_nirq++] = d->ipa_irq[i]; 170 171 for (i = 0; i < d->ipa_ndrq; i++) 172 c->ipa_drq[c->ipa_ndrq++] = d->ipa_drq[i]; 173 } 174 175 176 /* isapnp_flatten(): 177 * Flatten the tree to a list of config entries. 178 */ 179 struct isa_attach_args * 180 isapnp_flatten(card) 181 struct isa_attach_args *card; 182 { 183 struct isa_attach_args *dev, *conf, *d, *c, *pa; 184 185 dev = card->ipa_child; 186 ISAPNP_FREE(card); 187 188 for (conf = c = NULL, d = dev; d; d = dev) { 189 dev = d->ipa_sibling; 190 if (d->ipa_child == NULL) { 191 /* 192 * No subconfigurations; all configuration info 193 * is in the device node. 194 */ 195 d->ipa_sibling = NULL; 196 pa = d; 197 } 198 else { 199 /* 200 * Push down device configuration info to the 201 * subconfigurations 202 */ 203 for (pa = d->ipa_child; pa; pa = pa->ipa_sibling) 204 isapnp_merge(pa, d); 205 206 pa = d->ipa_child; 207 ISAPNP_FREE(d); 208 } 209 210 if (c == NULL) 211 c = conf = pa; 212 else 213 c->ipa_sibling = pa; 214 215 while (c->ipa_sibling) 216 c = c->ipa_sibling; 217 } 218 return conf; 219 } 220 221 222 /* isapnp_process_tag(): 223 * Process a resource tag 224 */ 225 int 226 isapnp_process_tag(tag, len, buf, card, dev, conf) 227 u_char tag, len, *buf; 228 struct isa_attach_args **card, **dev, **conf; 229 { 230 char str[64]; 231 struct isapnp_region *r; 232 struct isapnp_pin *p; 233 struct isa_attach_args *pa; 234 235 #define COPY(a, b) strncpy((a), (b), sizeof(a)), (a)[sizeof(a) - 1] = '\0' 236 237 switch (tag) { 238 case ISAPNP_TAG_VERSION_NUM: 239 DPRINTF(("PnP version %d.%d, Vendor version %d.%d\n", 240 buf[0] >> 4, buf[0] & 0xf, buf[1] >> 4, buf[1] & 0xf)); 241 return 0; 242 243 case ISAPNP_TAG_LOGICAL_DEV_ID: 244 (void) isapnp_id_to_vendor(str, buf); 245 DPRINTF(("Logical device id %s\n", str)); 246 247 *dev = isapnp_newdev(*card); 248 COPY((*dev)->ipa_devlogic, str); 249 return 0; 250 251 case ISAPNP_TAG_COMPAT_DEV_ID: 252 (void) isapnp_id_to_vendor(str, buf); 253 DPRINTF(("Compatible device id %s\n", str)); 254 255 if (*dev == NULL) 256 return -1; 257 258 if (*(*dev)->ipa_devcompat == '\0') 259 COPY((*dev)->ipa_devcompat, str); 260 return 0; 261 262 case ISAPNP_TAG_DEP_START: 263 if (len == 0) 264 buf[0] = ISAPNP_DEP_ACCEPTABLE; 265 266 if (*dev == NULL) 267 return -1; 268 269 *conf = isapnp_newconf(*dev); 270 (*conf)->ipa_pref = buf[0]; 271 #ifdef DEBUG_ISAPNP 272 isapnp_print_dep_start(">>> Start dependent function ", 273 (*conf)->ipa_pref); 274 #endif 275 return 0; 276 277 case ISAPNP_TAG_DEP_END: 278 DPRINTF(("<<<End dependent functions\n")); 279 *conf = NULL; 280 return 0; 281 282 case ISAPNP_TAG_ANSI_IDENT_STRING: 283 buf[len] = '\0'; 284 DPRINTF(("ANSI Ident: %s\n", buf)); 285 if (*dev == NULL) 286 COPY((*card)->ipa_devident, buf); 287 else 288 COPY((*dev)->ipa_devclass, buf); 289 return 0; 290 291 case ISAPNP_TAG_END: 292 *dev = NULL; 293 return 0; 294 295 default: 296 /* Handled below */ 297 break; 298 } 299 300 301 /* 302 * Decide which configuration we add the tag to 303 */ 304 if (*conf) 305 pa = *conf; 306 else if (*dev) 307 pa = *dev; 308 else 309 /* error */ 310 return -1; 311 312 switch (tag) { 313 case ISAPNP_TAG_IRQ_FORMAT: 314 if (len < 2) 315 break; 316 317 if (len != 3) 318 buf[2] = ISAPNP_IRQTYPE_EDGE_PLUS; 319 320 p = &pa->ipa_irq[pa->ipa_nirq++]; 321 p->bits = buf[0] | (buf[1] << 8); 322 p->flags = buf[2]; 323 #ifdef DEBUG_ISAPNP 324 isapnp_print_irq("", p); 325 #endif 326 break; 327 328 case ISAPNP_TAG_DMA_FORMAT: 329 if (buf[0] == 0) 330 break; 331 332 p = &pa->ipa_drq[pa->ipa_ndrq++]; 333 p->bits = buf[0]; 334 p->flags = buf[1]; 335 #ifdef DEBUG_ISAPNP 336 isapnp_print_drq("", p); 337 #endif 338 break; 339 340 341 case ISAPNP_TAG_IO_PORT_DESC: 342 r = &pa->ipa_io[pa->ipa_nio++]; 343 r->flags = buf[0]; 344 r->minbase = (buf[2] << 8) | buf[1]; 345 r->maxbase = (buf[4] << 8) | buf[3]; 346 r->align = buf[5]; 347 r->length = buf[6]; 348 #ifdef DEBUG_ISAPNP 349 isapnp_print_io("", r); 350 #endif 351 break; 352 353 case ISAPNP_TAG_FIXED_IO_PORT_DESC: 354 r = &pa->ipa_io[pa->ipa_nio++]; 355 r->flags = 0; 356 r->minbase = (buf[1] << 8) | buf[0]; 357 r->maxbase = r->minbase; 358 r->align = 1; 359 r->length = buf[2]; 360 #ifdef DEBUG_ISAPNP 361 isapnp_print_io("FIXED ", r); 362 #endif 363 break; 364 365 case ISAPNP_TAG_VENDOR_DEF: 366 DPRINTF(("Vendor defined (short)\n")); 367 break; 368 369 case ISAPNP_TAG_MEM_RANGE_DESC: 370 r = &pa->ipa_mem[pa->ipa_nmem++]; 371 r->flags = buf[0]; 372 r->minbase = (buf[2] << 16) | (buf[1] << 8); 373 r->maxbase = (buf[4] << 16) | (buf[3] << 8); 374 r->align = (buf[6] << 8) | buf[5]; 375 r->length = (buf[8] << 16) | (buf[7] << 8); 376 #ifdef DEBUG_ISAPNP 377 isapnp_print_mem("", r); 378 #endif 379 break; 380 381 382 case ISAPNP_TAG_UNICODE_IDENT_STRING: 383 DPRINTF(("Unicode Ident\n")); 384 break; 385 386 case ISAPNP_TAG_VENDOR_DEFINED: 387 DPRINTF(("Vendor defined (long)\n")); 388 break; 389 390 case ISAPNP_TAG_MEM32_RANGE_DESC: 391 r = &pa->ipa_mem32[pa->ipa_nmem32++]; 392 r->flags = buf[0]; 393 r->minbase = (buf[4] << 24) | (buf[3] << 16) | 394 (buf[2] << 8) | buf[1]; 395 r->maxbase = (buf[8] << 24) | (buf[7] << 16) | 396 (buf[6] << 8) | buf[5]; 397 r->align = (buf[12] << 24) | (buf[11] << 16) | 398 (buf[10] << 8) | buf[9]; 399 r->length = (buf[16] << 24) | (buf[15] << 16) | 400 (buf[14] << 8) | buf[13]; 401 #ifdef DEBUG_ISAPNP 402 isapnp_print_mem("32-bit ", r); 403 #endif 404 break; 405 406 case ISAPNP_TAG_FIXED_MEM32_RANGE_DESC: 407 r = &pa->ipa_mem32[pa->ipa_nmem32++]; 408 r->flags = buf[0]; 409 r->minbase = (buf[4] << 24) | (buf[3] << 16) | 410 (buf[2] << 8) | buf[1]; 411 r->maxbase = r->minbase; 412 r->align = 1; 413 r->length = (buf[8] << 24) | (buf[7] << 16) | 414 (buf[6] << 8) | buf[5]; 415 #ifdef DEBUG_ISAPNP 416 isapnp_print_mem("FIXED 32-bit ", r); 417 #endif 418 break; 419 420 default: 421 #ifdef DEBUG_ISAPNP 422 { 423 int i; 424 printf("tag %.2x, len %d: ", tag, len); 425 for (i = 0; i < len; i++) 426 printf("%.2x ", buf[i]); 427 printf("\n"); 428 } 429 #endif 430 break; 431 } 432 return 0; 433 } 434 435 436 /* isapnp_get_resource(): 437 * Read the resources for card c 438 */ 439 struct isa_attach_args * 440 isapnp_get_resource(sc, c, template) 441 struct isapnp_softc *sc; 442 int c; 443 struct isa_attach_args *template; 444 { 445 u_char d, tag; 446 u_short len; 447 int i; 448 int warned = 0; 449 struct isa_attach_args *card, *dev = NULL, *conf = NULL; 450 u_char buf[ISAPNP_MAX_TAGSIZE], *p; 451 452 bzero(buf, sizeof(buf)); 453 454 card = ISAPNP_MALLOC(sizeof(*card)); 455 ISAPNP_CLONE_SETUP(card, template); 456 457 #define NEXT_BYTE \ 458 if (isapnp_wait_status(sc)) \ 459 goto bad; \ 460 d = isapnp_read_reg(sc, ISAPNP_RESOURCE_DATA) 461 462 for (i = 0; i < ISAPNP_SERIAL_SIZE; i++) { 463 NEXT_BYTE; 464 465 if (d != sc->sc_id[c][i] && i != ISAPNP_SERIAL_SIZE - 1) { 466 if (!warned) { 467 printf("%s: card %d violates PnP spec; byte %d\n", 468 sc->sc_dev.dv_xname, c + 1, i); 469 warned++; 470 } 471 if (i == 0) { 472 /* 473 * Magic! If this is the first byte, we 474 * assume that the tag data begins here. 475 */ 476 goto parse; 477 } 478 } 479 } 480 481 do { 482 NEXT_BYTE; 483 parse: 484 485 if (d & ISAPNP_LARGE_TAG) { 486 tag = d; 487 NEXT_BYTE; 488 buf[0] = d; 489 NEXT_BYTE; 490 buf[1] = d; 491 len = (buf[1] << 8) | buf[0]; 492 } 493 else { 494 tag = (d >> 3) & 0xf; 495 len = d & 0x7; 496 } 497 498 for (p = buf, i = 0; i < len; i++) { 499 NEXT_BYTE; 500 if (i < ISAPNP_MAX_TAGSIZE) 501 *p++ = d; 502 } 503 504 if (len >= ISAPNP_MAX_TAGSIZE) { 505 printf("%s: Maximum tag size exceeded, card %d\n", 506 sc->sc_dev.dv_xname, c + 1); 507 len = ISAPNP_MAX_TAGSIZE; 508 if (++warned == 10) 509 goto bad; 510 } 511 512 if (isapnp_process_tag(tag, len, buf, &card, &dev, &conf) == -1) { 513 printf("%s: No current device for tag, card %d\n", 514 sc->sc_dev.dv_xname, c + 1); 515 if (++warned == 10) 516 goto bad; 517 } 518 } 519 while (tag != ISAPNP_TAG_END); 520 return isapnp_flatten(card); 521 522 bad: 523 for (card = isapnp_flatten(card); card; ) { 524 dev = card->ipa_sibling; 525 ISAPNP_FREE(card); 526 card = dev; 527 } 528 printf("%s: %s, card %d\n", sc->sc_dev.dv_xname, 529 warned >= 10 ? "Too many tag errors" : "Resource timeout", c + 1); 530 return NULL; 531 } 532