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