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