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