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