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