1 /* 2 * Copyright (c) 1995 Andrew McRae. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #ifndef lint 28 static const char rcsid[] = 29 "$FreeBSD$"; 30 #endif /* not lint */ 31 32 /* 33 * Code cleanup, bug-fix and extension 34 * by Tatsumi Hosokawa <hosokawa@mt.cs.keio.ac.jp> 35 */ 36 37 #include <err.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <sys/ioctl.h> 43 44 #include "cis.h" 45 #include "readcis.h" 46 47 static void dump_config_map(struct tuple *tp); 48 static void dump_cis_config(struct tuple *tp); 49 static void dump_other_cond(u_char *p, int len); 50 static void dump_device_desc(u_char *p, int len, const char *type); 51 static void dump_info_v1(u_char *p, int len); 52 static void dump_longlink_mfc(u_char *p, int len); 53 static void dump_bar(u_char *p, int len); 54 static void dump_device_geo(u_char *p, int len); 55 static void dump_func_id(u_char *p); 56 static void dump_serial_ext(u_char *p, int len); 57 static void dump_disk_ext(u_char *p, int len); 58 static void dump_network_ext(u_char *p, int len); 59 static void dump_info_v2(u_char *p, int len); 60 static void dump_org(u_char *p, int len); 61 62 void 63 dumpcis(struct tuple_list *tlist) 64 { 65 struct tuple *tp; 66 struct tuple_list *tl; 67 int count = 0, sz, ad, i; 68 u_char *p; 69 int func = 0; 70 71 for (tl = tlist; tl; tl = tl->next) 72 for (tp = tl->tuples; tp; tp = tp->next) { 73 printf("Tuple #%d, code = 0x%x (%s), length = %d\n", 74 ++count, tp->code, tuple_name(tp->code), tp->length); 75 p = tp->data; 76 sz = tp->length; 77 ad = 0; 78 while (sz > 0) { 79 printf(" %03x: ", ad); 80 for (i = 0; i < ((sz < 16) ? sz : 16); i++) 81 printf(" %02x", p[i]); 82 printf("\n"); 83 sz -= 16; 84 p += 16; 85 ad += 16; 86 } 87 switch (tp->code) { 88 default: 89 break; 90 case CIS_MEM_COMMON: /* 0x01 */ 91 dump_device_desc(tp->data, tp->length, "Common"); 92 break; 93 case CIS_CONF_MAP_CB: /* 0x04 */ 94 dump_config_map(tp); 95 break; 96 case CIS_CONFIG_CB: /* 0x05 */ 97 dump_cis_config(tp); 98 break; 99 case CIS_LONGLINK_MFC: /* 0x06 */ 100 dump_longlink_mfc(tp->data, tp->length); 101 break; 102 case CIS_BAR: /* 0x07 */ 103 dump_bar(tp->data, tp->length); 104 break; 105 case CIS_CHECKSUM: /* 0x10 */ 106 printf("\tChecksum from offset %d, length %d, value is 0x%x\n", 107 tpl16(tp->data), 108 tpl16(tp->data + 2), 109 tp->data[4]); 110 break; 111 case CIS_LONGLINK_A: /* 0x11 */ 112 printf("\tLong link to attribute memory, address 0x%x\n", 113 tpl32(tp->data)); 114 break; 115 case CIS_LONGLINK_C: /* 0x12 */ 116 printf("\tLong link to common memory, address 0x%x\n", 117 tpl32(tp->data)); 118 break; 119 case CIS_INFO_V1: /* 0x15 */ 120 dump_info_v1(tp->data, tp->length); 121 break; 122 case CIS_ALTSTR: /* 0x16 */ 123 break; 124 case CIS_MEM_ATTR: /* 0x17 */ 125 dump_device_desc(tp->data, tp->length, "Attribute"); 126 break; 127 case CIS_JEDEC_C: /* 0x18 */ 128 case CIS_JEDEC_A: /* 0x19 */ 129 break; 130 case CIS_CONF_MAP: /* 0x1A */ 131 dump_config_map(tp); 132 break; 133 case CIS_CONFIG: /* 0x1B */ 134 dump_cis_config(tp); 135 break; 136 case CIS_DEVICE_OC: /* 0x1C */ 137 case CIS_DEVICE_OA: /* 0x1D */ 138 dump_other_cond(tp->data, tp->length); 139 break; 140 case CIS_DEVICEGEO: /* 0x1E */ 141 case CIS_DEVICEGEO_A: /* 0x1F */ 142 dump_device_geo(tp->data, tp->length); 143 break; 144 case CIS_MANUF_ID: /* 0x20 */ 145 printf("\tPCMCIA ID = 0x%x, OEM ID = 0x%x\n", 146 tpl16(tp->data), 147 tpl16(tp->data + 2)); 148 break; 149 case CIS_FUNC_ID: /* 0x21 */ 150 func = tp->data[0]; 151 dump_func_id(tp->data); 152 break; 153 case CIS_FUNC_EXT: /* 0x22 */ 154 switch (func) { 155 case 2: 156 dump_serial_ext(tp->data, tp->length); 157 break; 158 case 4: 159 dump_disk_ext(tp->data, tp->length); 160 break; 161 case 6: 162 dump_network_ext(tp->data, tp->length); 163 break; 164 } 165 break; 166 case CIS_VERS_2: /* 0x40 */ 167 dump_info_v2(tp->data, tp->length); 168 break; 169 case CIS_ORG: /* 0x46 */ 170 dump_org(tp->data, tp->length); 171 break; 172 } 173 } 174 } 175 176 /* 177 * CIS_CONF_MAP : Dump configuration map tuple. 178 * CIS_CONF_MAP_CB: Dump configuration map for CardBus 179 */ 180 static void 181 dump_config_map(struct tuple *tp) 182 { 183 u_char *p = tp->data, x; 184 int rlen, mlen = 0; 185 int i; 186 187 rlen = (p[0] & 3) + 1; 188 if (tp->code == CIS_CONF_MAP) 189 mlen = ((p[0] >> 2) & 3) + 1; 190 if (tp->length < rlen + mlen + 2) { 191 printf("\tWrong length for configuration map tuple\n"); 192 return; 193 } 194 printf("\tReg len = %d, config register addr = 0x%x, last config = 0x%x\n", 195 rlen, parse_num(rlen | 0x10, p + 2, &p, 0), p[1]); 196 if (mlen) { 197 printf("\tRegisters: "); 198 for (i = 0; i < mlen; i++, p++) { 199 for (x = 0x1; x; x <<= 1) 200 printf("%c", x & *p ? 'X' : '-'); 201 putchar(' '); 202 } 203 } 204 i = tp->length - (rlen + mlen + 2); 205 if (i) { 206 if (!mlen) 207 putchar('\t'); 208 printf("%d bytes in subtuples", i); 209 } 210 if (mlen || i) 211 putchar('\n'); 212 } 213 214 /* 215 * Dump power descriptor. 216 * call from dump_cis_config() 217 */ 218 static int 219 print_pwr_desc(u_char *p) 220 { 221 int len = 1, i; 222 u_char mask; 223 const char **expp; 224 static const char *pname[] = 225 {"Nominal operating supply voltage", 226 "Minimum operating supply voltage", 227 "Maximum operating supply voltage", 228 "Continuous supply current", 229 "Max current average over 1 second", 230 "Max current average over 10 ms", 231 "Power down supply current", 232 "Reserved" 233 }; 234 static const char *vexp[] = 235 {"10uV", "100uV", "1mV", "10mV", "100mV", "1V", "10V", "100V"}; 236 static const char *cexp[] = 237 {"10nA", "1uA", "10uA", "100uA", "1mA", "10mA", "100mA", "1A"}; 238 static const char *mant[] = 239 {"1", "1.2", "1.3", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", 240 "5", "5.5", "6", "7", "8", "9"}; 241 242 mask = *p++; 243 expp = vexp; 244 for (i = 0; i < 8; i++) 245 if (mask & (1 << i)) { 246 len++; 247 if (i >= 3) 248 expp = cexp; 249 printf("\t\t%s: ", pname[i]); 250 printf("%s x %s", 251 mant[(*p >> 3) & 0xF], 252 expp[*p & 7]); 253 while (*p & 0x80) { 254 len++; 255 p++; 256 printf(", ext = 0x%x", *p); 257 } 258 printf("\n"); 259 p++; 260 } 261 return (len); 262 } 263 264 /* 265 * print_ext_speed - Print extended speed. 266 * call from dump_cis_config(), dump_device_desc() 267 */ 268 static void 269 print_ext_speed(u_char x, int scale) 270 { 271 static const char *mant[] = 272 {"Reserved", "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0", 273 "3.5", "4.0", "4.5", "5.0", "5.5", "6.0", "7.0", "8.0"}; 274 static const char *exp[] = 275 {"1 ns", "10 ns", "100 ns", "1 us", "10 us", "100 us", 276 "1 ms", "10 ms"}; 277 static const char *scale_name[] = 278 {"None", "10", "100", "1,000", "10,000", "100,000", 279 "1,000,000", "10,000,000"}; 280 281 printf("Speed = %s x %s", mant[(x >> 3) & 0xF], exp[x & 7]); 282 if (scale) 283 printf(", scaled by %s", scale_name[scale & 7]); 284 } 285 286 /* 287 * Print variable length value. 288 * call from print_io_map(), print_mem_map() 289 */ 290 static int 291 print_num(int sz, const char *fmt, u_char *p, int ofs) 292 { 293 switch (sz) { 294 case 0: 295 case 0x10: 296 return 0; 297 case 1: 298 case 0x11: 299 printf(fmt, *p + ofs); 300 return 1; 301 case 2: 302 case 0x12: 303 printf(fmt, tpl16(p) + ofs); 304 return 2; 305 case 0x13: 306 printf(fmt, tpl24(p) + ofs); 307 return 3; 308 case 3: 309 case 0x14: 310 printf(fmt, tpl32(p) + ofs); 311 return 4; 312 } 313 errx(1, "print_num(0x%x): Illegal arguments", sz); 314 /*NOTREACHED*/ 315 } 316 317 /* 318 * Print I/O mapping sub-tuple. 319 * call from dump_cis_config() 320 */ 321 static u_char * 322 print_io_map(u_char *p, u_char *q) 323 { 324 int i, j; 325 u_char c; 326 327 if (q <= p) 328 goto err; 329 if (CIS_IO_ADDR(*p)) /* I/O address line */ 330 printf("\tCard decodes %d address lines", 331 CIS_IO_ADDR(*p)); 332 else 333 printf("\tCard provides address decode"); 334 335 /* 8/16 bit I/O */ 336 switch (*p & (CIS_IO_8BIT | CIS_IO_16BIT)) { 337 case CIS_IO_8BIT: 338 printf(", 8 Bit I/O only"); 339 break; 340 case CIS_IO_16BIT: 341 printf(", limited 8/16 Bit I/O"); 342 break; 343 case (CIS_IO_8BIT | CIS_IO_16BIT): 344 printf(", full 8/16 Bit I/O"); 345 break; 346 } 347 putchar('\n'); 348 349 /* I/O block sub-tuple exist */ 350 if (*p++ & CIS_IO_RANGE) { 351 if (q <= p) 352 goto err; 353 c = *p++; 354 /* calculate byte length */ 355 j = CIS_IO_ADSZ(c) + CIS_IO_BLKSZ(c); 356 if (CIS_IO_ADSZ(c) == 3) 357 j++; 358 if (CIS_IO_BLKSZ(c) == 3) 359 j++; 360 /* number of I/O block sub-tuples */ 361 for (i = 0; i <= CIS_IO_BLKS(c); i++) { 362 if (q - p < j) 363 goto err; 364 printf("\t\tI/O address # %d: ", i + 1); 365 /* start block address */ 366 p += print_num(CIS_IO_ADSZ(c), 367 "block start = 0x%x", p, 0); 368 /* block size */ 369 p += print_num(CIS_IO_BLKSZ(c), 370 " block length = 0x%x", p, 1); 371 putchar('\n'); 372 } 373 } 374 return p; 375 376 err: /* warning */ 377 printf("\tWrong length for I/O mapping sub-tuple\n"); 378 return p; 379 } 380 381 /* 382 * Print IRQ sub-tuple. 383 * call from dump_cis_config() 384 */ 385 static u_char * 386 print_irq_map(u_char *p, u_char *q) 387 { 388 int i, j; 389 u_char c; 390 391 if (q <= p) 392 goto err; 393 printf("\t\tIRQ modes:"); 394 c = ' '; 395 if (*p & CIS_IRQ_LEVEL) { /* Level triggered interrupts */ 396 printf(" Level"); 397 c = ','; 398 } 399 if (*p & CIS_IRQ_PULSE) { /* Pulse triggered requests */ 400 printf("%c Pulse", c); 401 c = ','; 402 } 403 if (*p & CIS_IRQ_SHARING) /* Interrupt sharing */ 404 printf("%c Shared", c); 405 putchar('\n'); 406 407 /* IRQ mask values exist */ 408 if (*p & CIS_IRQ_MASK) { 409 if (q - p < 3) 410 goto err; 411 i = tpl16(p + 1); /* IRQ mask */ 412 printf("\t\tIRQs: "); 413 if (*p & 1) 414 printf(" NMI"); 415 if (*p & 0x2) 416 printf(" IOCK"); 417 if (*p & 0x4) 418 printf(" BERR"); 419 if (*p & 0x8) 420 printf(" VEND"); 421 for (j = 0; j < 16; j++) 422 if (i & (1 << j)) 423 printf(" %d", j); 424 putchar('\n'); 425 p += 3; 426 } else { 427 printf("\t\tIRQ level = %d\n", CIS_IRQ_IRQN(*p)); 428 p++; 429 } 430 return p; 431 432 err: /* warning */ 433 printf("\tWrong length for IRQ sub-tuple\n"); 434 return p; 435 } 436 437 /* 438 * Print memory map sub-tuple. 439 * call from dump_cis_config() 440 */ 441 static u_char * 442 print_mem_map(u_char feat, u_char *p, u_char *q) 443 { 444 int i, j; 445 u_char c; 446 447 switch (CIS_FEAT_MEMORY(feat)) { 448 449 case CIS_FEAT_MEM_NONE: /* No memory block */ 450 break; 451 case CIS_FEAT_MEM_LEN: /* Specify memory length */ 452 if (q - p < 2) 453 goto err; 454 printf("\tMemory space length = 0x%x\n", tpl16(p)); 455 p += 2; 456 break; 457 case CIS_FEAT_MEM_ADDR: /* Memory address and length */ 458 if (q - p < 4) 459 goto err; 460 printf("\tMemory space address = 0x%x, length = 0x%x\n", 461 tpl16(p + 2), tpl16(p)); 462 p += 4; 463 break; 464 case CIS_FEAT_MEM_WIN: /* Memory descriptors. */ 465 if (q <= p) 466 goto err; 467 c = *p++; 468 /* calculate byte length */ 469 j = CIS_MEM_LENSZ(c) + CIS_MEM_ADDRSZ(c); 470 if (c & CIS_MEM_HOST) 471 j += CIS_MEM_ADDRSZ(c); 472 /* number of memory block */ 473 for (i = 0; i < CIS_MEM_WINS(c); i++) { 474 if (q - p < j) 475 goto err; 476 printf("\tMemory descriptor %d\n\t\t", i + 1); 477 /* memory length */ 478 p += print_num(CIS_MEM_LENSZ(c) | 0x10, 479 " blk length = 0x%x00", p, 0); 480 /* card address */ 481 p += print_num(CIS_MEM_ADDRSZ(c) | 0x10, 482 " card addr = 0x%x00", p, 0); 483 if (c & CIS_MEM_HOST) /* Host address value exist */ 484 p += print_num(CIS_MEM_ADDRSZ(c) | 0x10, 485 " host addr = 0x%x00", p, 0); 486 putchar('\n'); 487 } 488 break; 489 } 490 return p; 491 492 err: /* warning */ 493 printf("\tWrong length for memory mapping sub-tuple\n"); 494 return p; 495 } 496 497 /* 498 * CIS_CONFIG : Dump a config entry. 499 * CIS_CONFIG_CB: Dump a configuration entry for CardBus 500 */ 501 static void 502 dump_cis_config(struct tuple *tp) 503 { 504 u_char *p, *q, feat; 505 int i, j; 506 char c; 507 508 p = tp->data; 509 q = p + tp->length; 510 printf("\tConfig index = 0x%x%s\n", *p & 0x3F, 511 *p & 0x40 ? "(default)" : ""); 512 513 /* Interface byte exists */ 514 if (tp->code == CIS_CONFIG && (*p & 0x80)) { 515 p++; 516 printf("\tInterface byte = 0x%x ", *p); 517 switch (*p & 0xF) { /* Interface type */ 518 default: 519 printf("(reserved)"); 520 break; 521 case 0: 522 printf("(memory)"); 523 break; 524 case 1: 525 printf("(I/O)"); 526 break; 527 case 4: 528 case 5: 529 case 6: 530 case 7: 531 case 8: 532 printf("(custom)"); 533 break; 534 } 535 c = ' '; 536 if (*p & 0x10) { /* Battery voltage detect */ 537 printf(" BVD1/2 active"); 538 c = ','; 539 } 540 if (*p & 0x20) { /* Write protect active */ 541 printf("%c card WP active", c); /* Write protect */ 542 c = ','; 543 } 544 if (*p & 0x40) { /* RdyBsy active bit */ 545 printf("%c +RDY/-BSY active", c); 546 c = ','; 547 } 548 if (*p & 0x80) /* Wait signal required */ 549 printf("%c wait signal supported", c); 550 printf("\n"); 551 } 552 553 /* features byte */ 554 p++; 555 feat = *p++; 556 557 /* Power structure sub-tuple */ 558 switch (CIS_FEAT_POWER(feat)) { /* Power sub-tuple(s) exists */ 559 case 0: 560 break; 561 case 1: 562 printf("\tVcc pwr:\n"); 563 p += print_pwr_desc(p); 564 break; 565 case 2: 566 printf("\tVcc pwr:\n"); 567 p += print_pwr_desc(p); 568 printf("\tVpp pwr:\n"); 569 p += print_pwr_desc(p); 570 break; 571 case 3: 572 printf("\tVcc pwr:\n"); 573 p += print_pwr_desc(p); 574 printf("\tVpp1 pwr:\n"); 575 p += print_pwr_desc(p); 576 printf("\tVpp2 pwr:\n"); 577 p += print_pwr_desc(p); 578 break; 579 } 580 581 /* Timing sub-tuple */ 582 if (tp->code == CIS_CONFIG && 583 (feat & CIS_FEAT_TIMING)) { /* Timing sub-tuple exists */ 584 i = *p++; 585 j = CIS_WAIT_SCALE(i); 586 if (j != 3) { 587 printf("\tWait scale "); 588 print_ext_speed(*p++, j); 589 printf("\n"); 590 } 591 j = CIS_READY_SCALE(i); 592 if (j != 7) { 593 printf("\tRDY/BSY scale "); 594 print_ext_speed(*p++, j); 595 printf("\n"); 596 } 597 j = CIS_RESERVED_SCALE(i); 598 if (j != 7) { 599 printf("\tExternal scale "); 600 print_ext_speed(*p++, j); 601 printf("\n"); 602 } 603 } 604 605 /* I/O mapping sub-tuple */ 606 if (feat & CIS_FEAT_I_O) { /* I/O space sub-tuple exists */ 607 if (tp->code == CIS_CONFIG) 608 p = print_io_map(p, q); 609 else { /* CIS_CONFIG_CB */ 610 printf("\tI/O base:"); 611 for (i = 0; i < 8; i++) 612 if (*p & (1 << i)) 613 printf(" %d", i); 614 putchar('\n'); 615 p++; 616 } 617 } 618 619 /* IRQ descriptor sub-tuple */ 620 if (feat & CIS_FEAT_IRQ) /* IRQ sub-tuple exists */ 621 p = print_irq_map(p, q); 622 623 /* Memory map sub-tuple */ 624 if (CIS_FEAT_MEMORY(feat)) { /* Memory space sub-tuple(s) exists */ 625 if (tp->code == CIS_CONFIG) 626 p = print_mem_map(feat, p, q); 627 else { /* CIS_CONFIG_CB */ 628 printf("\tMemory base:"); 629 for (i = 0; i < 8; i++) 630 if (*p & (1 << i)) 631 printf(" %d", i); 632 putchar('\n'); 633 p++; 634 } 635 } 636 637 /* Misc sub-tuple */ 638 if (feat & CIS_FEAT_MISC) { /* Miscellaneous sub-tuple exists */ 639 if (tp->code == CIS_CONFIG) { 640 printf("\tMax twin cards = %d\n", *p & 7); 641 printf("\tMisc attr:%s%s%s", 642 (*p & 8) ? " (Audio-BVD2)" : "", 643 (*p & 0x10) ? " (Read-only)" : "", 644 (*p & 0x20) ? " (Power down supported)" : ""); 645 if (*p++ & 0x80) { 646 printf(" (Ext byte = 0x%x)", *p); 647 p++; 648 } 649 putchar('\n'); 650 } 651 else { /* CIS_CONFIG_CB */ 652 printf("\tMisc attr:"); 653 printf("%s%s%s%s%s%s%s", 654 (*p & 1) ? " (Master)" : "", 655 (*p & 2) ? " (Invalidate)" : "", 656 (*p & 4) ? " (VGA palette)" : "", 657 (*p & 8) ? " (Parity)" : "", 658 (*p & 0x10) ? " (Wait)" : "", 659 (*p & 0x20) ? " (Serr)" : "", 660 (*p & 0x40) ? " (Fast back)" : ""); 661 if (*p++ & 0x80) { 662 printf("%s%s", 663 (*p & 1) ? " (Binary audio)" : "", 664 (*p & 2) ? " (pwm audio)" : ""); 665 p++; 666 } 667 putchar('\n'); 668 } 669 } 670 } 671 672 /* 673 * CIS_DEVICE_OC, CIS_DEVICE_OA: 674 * Dump other conditions for common/attribute memory 675 */ 676 static void 677 dump_other_cond(u_char *p, int len) 678 { 679 if (p[0] && len > 0) { 680 printf("\t"); 681 if (p[0] & 1) 682 printf("(MWAIT)"); 683 if (p[0] & 2) 684 printf(" (3V card)"); 685 if (p[0] & 0x80) 686 printf(" (Extension bytes follow)"); 687 printf("\n"); 688 } 689 } 690 691 /* 692 * CIS_MEM_COMMON, CIS_MEM_ATTR: 693 * Common / Attribute memory descripter 694 */ 695 static void 696 dump_device_desc(u_char *p, int len, const char *type) 697 { 698 static const char *un_name[] = 699 {"512b", "2Kb", "8Kb", "32Kb", "128Kb", "512Kb", "2Mb", "reserved"}; 700 static const char *speed[] = 701 {"No speed", "250nS", "200nS", "150nS", 702 "100nS", "Reserved", "Reserved"}; 703 static const char *dev[] = 704 {"No device", "Mask ROM", "OTPROM", "UV EPROM", 705 "EEPROM", "FLASH EEPROM", "SRAM", "DRAM", 706 "Reserved", "Reserved", "Reserved", "Reserved", 707 "Reserved", "Function specific", "Extended", 708 "Reserved"}; 709 int count = 0; 710 711 while (*p != 0xFF && len > 0) { 712 u_char x; 713 714 x = *p++; 715 len -= 2; 716 if (count++ == 0) 717 printf("\t%s memory device information:\n", type); 718 printf("\t\tDevice number %d, type %s, WPS = %s\n", 719 count, dev[x >> 4], (x & 0x8) ? "ON" : "OFF"); 720 if ((x & 7) == 7) { 721 len--; 722 if (*p) { 723 printf("\t\t"); 724 print_ext_speed(*p, 0); 725 while (*p & 0x80) { 726 p++; 727 len--; 728 } 729 } 730 p++; 731 } else 732 printf("\t\tSpeed = %s", speed[x & 7]); 733 printf(", Memory block size = %s, %d units\n", 734 un_name[*p & 7], (*p >> 3) + 1); 735 p++; 736 } 737 } 738 739 /* 740 * CIS_INFO_V1: Print version-1 info 741 */ 742 static void 743 dump_info_v1(u_char *p, int len) 744 { 745 if (len < 2) { 746 printf("\tWrong length for version-1 info tuple\n"); 747 return; 748 } 749 printf("\tVersion = %d.%d", p[0], p[1]); 750 p += 2; 751 len -= 2; 752 if (len > 1 && *p != 0xff) { 753 printf(", Manuf = [%s]", p); 754 while (*p++ && --len > 0); 755 } 756 if (len > 1 && *p != 0xff) { 757 printf(", card vers = [%s]", p); 758 while (*p++ && --len > 0); 759 } else { 760 printf("\n\tWrong length for version-1 info tuple\n"); 761 return; 762 } 763 putchar('\n'); 764 if (len > 1 && *p != 0xff) { 765 printf("\tAddit. info = [%.*s]", len, p); 766 while (*p++ && --len > 0); 767 if (len > 1 && *p != 0xff) 768 printf(",[%.*s]", len, p); 769 putchar('\n'); 770 } 771 } 772 773 /* 774 * CIS_FUNC_ID: Functional ID 775 */ 776 static void 777 dump_func_id(u_char *p) 778 { 779 static const char *id[] = { 780 "Multifunction card", 781 "Memory card", 782 "Serial port/modem", 783 "Parallel port", 784 "Fixed disk card", 785 "Video adapter", 786 "Network/LAN adapter", 787 "AIMS", 788 "SCSI card", 789 "Security" 790 }; 791 792 printf("\t%s%s%s\n", 793 (*p <= 9) ? id[*p] : "Unknown function", 794 (p[1] & 1) ? " - POST initialize" : "", 795 (p[1] & 2) ? " - Card has ROM" : ""); 796 } 797 798 /* 799 * CIS_FUNC_EXT: Dump functional extension tuple. 800 * (Serial port/modem) 801 */ 802 static void 803 dump_serial_ext(u_char *p, int len) 804 { 805 static const char *type[] = { 806 "", "Modem", "Data", "Fax", "Voice", "Data modem", 807 "Fax/modem", "Voice", " (Data)", " (Fax)", " (Voice)" 808 }; 809 810 if (len < 1) 811 return; 812 switch (p[0]) { 813 case 0: /* Serial */ 814 case 8: /* Data */ 815 case 9: /* Fax */ 816 case 10: /* Voice */ 817 printf("\tSerial interface extension:%s\n", type[*p]); 818 if (len < 4) 819 goto err; 820 switch (p[1] & 0x1F) { 821 default: 822 printf("\t\tUnknown device"); 823 break; 824 case 0: 825 printf("\t\t8250 UART"); 826 break; 827 case 1: 828 printf("\t\t16450 UART"); 829 break; 830 case 2: 831 printf("\t\t16550 UART"); 832 break; 833 } 834 printf(", Parity - %s%s%s%s\n", 835 (p[2] & 1) ? "Space," : "", 836 (p[2] & 2) ? "Mark," : "", 837 (p[2] & 4) ? "Odd," : "", 838 (p[2] & 8) ? "Even" : ""); 839 printf("\t\tData bit - %s%s%s%s Stop bit - %s%s%s\n", 840 (p[3] & 1) ? "5bit," : "", 841 (p[3] & 2) ? "6bit," : "", 842 (p[3] & 4) ? "7bit," : "", 843 (p[3] & 8) ? "8bit," : "", 844 (p[3] & 0x10) ? "1bit," : "", 845 (p[3] & 0x20) ? "1.5bit," : "", 846 (p[3] & 0x40) ? "2bit" : ""); 847 break; 848 case 1: /* Serial */ 849 case 5: /* Data */ 850 case 6: /* Fax */ 851 case 7: /* Voice */ 852 printf("\t%s interface capabilities:\n", type[*p]); 853 if (len < 9) 854 goto err; 855 break; 856 case 2: /* Data */ 857 printf("\tData modem services available:\n"); 858 break; 859 case 0x13: /* Fax1 */ 860 case 0x23: /* Fax2 */ 861 case 0x33: /* Fax3 */ 862 printf("\tFax%d/modem services available:\n", *p >> 4); 863 break; 864 case 0x84: /* Voice */ 865 printf("\tVoice services available:\n"); 866 break; 867 err: /* warning */ 868 printf("\tWrong length for serial extension tuple\n"); 869 return; 870 } 871 } 872 873 /* 874 * CIS_FUNC_EXT: Dump functional extension tuple. 875 * (Fixed disk card) 876 */ 877 static void 878 dump_disk_ext(u_char *p, int len) 879 { 880 if (len < 1) 881 return; 882 switch (p[0]) { 883 case 1: /* IDE interface */ 884 if (len < 2) 885 goto err; 886 printf("\tDisk interface: %s\n", 887 (p[1] & 1) ? "IDE" : "Undefined"); 888 break; 889 case 2: /* Master */ 890 case 3: /* Slave */ 891 if (len < 3) 892 goto err; 893 printf("\tDisk features: %s, %s%s\n", 894 (p[1] & 0x04) ? "Silicon" : "Rotating", 895 (p[1] & 0x08) ? "Unique, " : "", 896 (p[1] & 0x10) ? "Dual" : "Single"); 897 if (p[2] & 0x7f) 898 printf("\t\t%s%s%s%s%s%s%s\n", 899 (p[2] & 0x01) ? "Sleep, " : "", 900 (p[2] & 0x02) ? "Standby, " : "", 901 (p[2] & 0x04) ? "Idle, " : "", 902 (p[2] & 0x08) ? "Low power, " : "", 903 (p[2] & 0x10) ? "Reg inhibit, " : "", 904 (p[2] & 0x20) ? "Index, " : "", 905 (p[2] & 0x40) ? "Iois16" : ""); 906 break; 907 err: /* warning */ 908 printf("\tWrong length for fixed disk extension tuple\n"); 909 return; 910 } 911 } 912 913 static void 914 print_speed(u_int i) 915 { 916 if (i < 1000) 917 printf("%u bits/sec", i); 918 else if (i < 1000000) 919 printf("%u kb/sec", i / 1000); 920 else 921 printf("%u Mb/sec", i / 1000000); 922 } 923 924 /* 925 * CIS_FUNC_EXT: Dump functional extension tuple. 926 * (Network/LAN adapter) 927 */ 928 static void 929 dump_network_ext(u_char *p, int len) 930 { 931 static const char *tech[] = { 932 "Undefined", "ARCnet", "Ethernet", "Token ring", 933 "Localtalk", "FDDI/CDDI", "ATM", "Wireless" 934 }; 935 static const char *media[] = { 936 "Undefined", "UTP", "STP", "Thin coax", 937 "THICK coax", "Fiber", "900 MHz", "2.4 GHz", 938 "5.4 GHz", "Diffuse Infrared", "Point to point Infrared" 939 }; 940 u_int i = 0; 941 942 if (len < 1) 943 return; 944 switch (p[0]) { 945 case 1: /* Network technology */ 946 if (len < 2) 947 goto err; 948 printf("\tNetwork technology: %s\n", tech[p[1] & 7]); 949 break; 950 case 2: /* Network speed */ 951 if (len < 5) 952 goto err; 953 printf("\tNetwork speed: "); 954 print_speed(tpl32(p + 1)); 955 putchar('\n'); 956 break; 957 case 3: /* Network media */ 958 if (len < 2) 959 goto err; 960 if (p[1] <= 10) 961 i = p[1]; 962 printf("\tNetwork media: %s\n", media[i]); 963 break; 964 case 4: /* Node ID */ 965 if (len <= 2 || len < p[1] + 2) 966 goto err; 967 printf("\tNetwork node ID:"); 968 for (i = 0; i < p[1]; i++) 969 printf(" %02x", p[i + 2]); 970 putchar('\n'); 971 break; 972 case 5: /* Connector type */ 973 if (len < 2) 974 goto err; 975 printf("\tNetwork connector: %s connector standard\n", 976 (p[1] == 0) ? "open" : "closed"); 977 break; 978 err: /* warning */ 979 printf("\tWrong length for network extension tuple\n"); 980 return; 981 } 982 } 983 984 /* 985 * CIS_LONGLINK_MFC: Long link to next chain for Multi function card 986 */ 987 static void 988 dump_longlink_mfc(u_char *p, int len) 989 { 990 u_int i, n = *p++; 991 992 --len; 993 for (i = 0; i < n; i++) { 994 if (len < 5) { 995 printf("\tWrong length for long link MFC tuple\n"); 996 return; 997 } 998 printf("\tFunction %d: %s memory, address 0x%x\n", 999 i, (*p ? "common" : "attribute"), tpl32(p + 1)); 1000 p += 5; 1001 len -= 5; 1002 } 1003 } 1004 1005 /* 1006 * CIS_DEVICEGEO, CIS_DEVICEGEO_A: 1007 * Geometry info for common/attribute memory 1008 */ 1009 static void 1010 dump_device_geo(u_char *p, int len) 1011 { 1012 while (len >= 6) { 1013 printf("\twidth = %d, erase = 0x%x, read = 0x%x, write = 0x%x\n" 1014 "\t\tpartition = 0x%x, interleave = 0x%x\n", 1015 p[0], 1 << (p[1] - 1), 1016 1 << (p[2] - 1), 1 << (p[3] - 1), 1017 1 << (p[4] - 1), 1 << (p[5] - 1)); 1018 len -= 6; 1019 } 1020 } 1021 1022 /* 1023 * CIS_INFO_V2: Print version-2 info 1024 */ 1025 static void 1026 dump_info_v2(u_char *p, int len) 1027 { 1028 if (len < 9) { 1029 printf("\tWrong length for version-2 info tuple\n"); 1030 return; 1031 } 1032 printf("\tVersion = 0x%x, compliance = 0x%x, dindex = 0x%x\n", 1033 p[0], p[1], tpl16(p + 2)); 1034 printf("\tVspec8 = 0x%x, vspec9 = 0x%x, nhdr = %d\n", 1035 p[6], p[7], p[8]); 1036 p += 9; 1037 len -= 9; 1038 if (len <= 1 || *p == 0xff) 1039 return; 1040 printf("\tVendor = [%.*s]", len, p); 1041 while (*p++ && --len > 0); 1042 if (len > 1 && *p != 0xff) 1043 printf(", info = [%.*s]", len, p); 1044 putchar('\n'); 1045 } 1046 1047 /* 1048 * CIS_ORG: Organization 1049 */ 1050 static void 1051 dump_org(u_char *p, int len) 1052 { 1053 if (len < 1) { 1054 printf("\tWrong length for organization tuple\n"); 1055 return; 1056 } 1057 switch (*p) { 1058 case 0: 1059 printf("\tFilesystem"); 1060 break; 1061 case 1: 1062 printf("\tApp specific"); 1063 break; 1064 case 2: 1065 printf("\tCode"); 1066 break; 1067 default: 1068 if (*p < 0x80) 1069 printf("\tReserved"); 1070 else 1071 printf("\tVendor specific"); 1072 break; 1073 } 1074 printf(" [%.*s]\n", len - 1, p + 1); 1075 } 1076 1077 static void 1078 print_size(u_int i) 1079 { 1080 if (i < 1024) 1081 printf("%ubits", i); 1082 else if (i < 1024*1024) 1083 printf("%ukb", i / 1024); 1084 else 1085 printf("%uMb", i / (1024*1024)); 1086 } 1087 1088 /* 1089 * CIS_BAR: Base address register for CardBus 1090 */ 1091 static void 1092 dump_bar(u_char *p, int len) 1093 { 1094 if (len < 6) { 1095 printf("\tWrong length for BAR tuple\n"); 1096 return; 1097 } 1098 printf("\tBAR %d: size = ", *p & 7); 1099 print_size(tpl32(p + 2)); 1100 printf(", %s%s%s%s\n", 1101 (*p & 0x10) ? "I/O" : "Memory", 1102 (*p & 0x20) ? ", Prefetch" : "", 1103 (*p & 0x40) ? ", Cacheable" : "", 1104 (*p & 0x80) ? ", <1Mb" : ""); 1105 } 1106