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