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