printcis.c revision 30171
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 28static const char rcsid[] = 29 "$Id$"; 30#endif /* not lint */ 31 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <unistd.h> 36#include <sys/ioctl.h> 37 38#include <pccard/card.h> 39#include <pccard/cis.h> 40 41#include "readcis.h" 42 43int dump_pwr_desc(unsigned char *); 44void print_ext_speed(unsigned char, int); 45void dump_device_desc(unsigned char *p, int len, char *type); 46void dump_info_v1(unsigned char *p, int len); 47void dump_config_map(struct tuple *tp); 48void dump_cis_config(struct tuple *tp); 49void dump_other_cond(unsigned char *p); 50void dump_func_ext(unsigned char *p, int len); 51 52void 53dumpcis(struct cis *cp) 54{ 55 struct tuple *tp; 56 struct tuple_list *tl; 57 int count = 0, sz, ad, i; 58 unsigned char *p; 59 60 for (tl = cp->tlist; tl; tl = tl->next) 61 for (tp = tl->tuples; tp; tp = tp->next) { 62 printf("Tuple #%d, code = 0x%x (%s), length = %d\n", 63 ++count, tp->code, tuple_name(tp->code), tp->length); 64 p = tp->data; 65 sz = tp->length; 66 ad = 0; 67 while (sz > 0) { 68 printf(" %03x: ", ad); 69 for (i = 0; i < ((sz < 16) ? sz : 16); i++) 70 printf(" %02x", p[i]); 71 printf("\n"); 72 sz -= 16; 73 p += 16; 74 ad += 16; 75 } 76 switch (tp->code) { 77 default: 78 break; 79 case CIS_MEM_COMMON: /* 0x01 */ 80 dump_device_desc(tp->data, tp->length, "Common"); 81 break; 82 case CIS_CHECKSUM: /* 0x10 */ 83 if (tp->length == 5) { 84 printf("\tChecksum from offset %d, length %d, value is 0x%x\n", 85 (short)((tp->data[1] << 8) | tp->data[0]), 86 (tp->data[3] << 8) | tp->data[2], 87 tp->data[4]); 88 } else 89 printf("\tIllegal length for checksum!\n"); 90 break; 91 case CIS_LONGLINK_A: /* 0x11 */ 92 printf("\tLong link to attribute memory, address 0x%x\n", 93 (tp->data[3] << 24) | 94 (tp->data[2] << 16) | 95 (tp->data[1] << 8) | 96 tp->data[0]); 97 break; 98 case CIS_LONGLINK_C: /* 0x12 */ 99 printf("\tLong link to common memory, address 0x%x\n", 100 (tp->data[3] << 24) | 101 (tp->data[2] << 16) | 102 (tp->data[1] << 8) | 103 tp->data[0]); 104 break; 105 break; 106 case CIS_INFO_V1: /* 0x15 */ 107 dump_info_v1(tp->data, tp->length); 108 break; 109 case CIS_ALTSTR: /* 0x16 */ 110 break; 111 case CIS_MEM_ATTR: /* 0x17 */ 112 dump_device_desc(tp->data, tp->length, "Attribute"); 113 break; 114 case CIS_JEDEC_C: /* 0x18 */ 115 break; 116 case CIS_JEDEC_A: /* 0x19 */ 117 break; 118 case CIS_CONF_MAP: /* 0x1A */ 119 dump_config_map(tp); 120 break; 121 case CIS_CONFIG: /* 0x1B */ 122 dump_cis_config(tp); 123 break; 124 case CIS_DEVICE_OC: /* 0x1C */ 125 dump_other_cond(tp->data); 126 break; 127 case CIS_DEVICE_OA: /* 0x1D */ 128 dump_other_cond(tp->data); 129 break; 130 case CIS_DEVICEGEO: /* 0x1E */ 131 break; 132 case CIS_DEVICEGEO_A: /* 0x1F */ 133 break; 134 case CIS_MANUF_ID: /* 0x20 */ 135 printf("\tPCMCIA ID = 0x%x, OEM ID = 0x%x\n", 136 (tp->data[1] << 8) | tp->data[0], 137 (tp->data[3] << 8) | tp->data[2]); 138 break; 139 case CIS_FUNC_ID: /* 0x21 */ 140 switch (tp->data[0]) { 141 default: 142 printf("\tUnknown function"); 143 break; 144 case 0: 145 printf("\tMultifunction card"); 146 break; 147 case 1: 148 printf("\tMemory card"); 149 break; 150 case 2: 151 printf("\tSerial port/modem"); 152 break; 153 case 3: 154 printf("\tParallel port"); 155 break; 156 case 4: 157 printf("\tFixed disk card"); 158 break; 159 case 5: 160 printf("\tVideo adapter"); 161 break; 162 case 6: 163 printf("\tNetwork/LAN adapter"); 164 break; 165 case 7: 166 printf("\tAIMS"); 167 break; 168 } 169 printf("%s%s\n", (tp->data[1] & 1) ? " - POST initialize" : "", 170 (tp->data[1] & 2) ? " - Card has ROM" : ""); 171 break; 172 case CIS_FUNC_EXT: /* 0x22 */ 173 dump_func_ext(tp->data, tp->length); 174 break; 175 case CIS_VERS_2: /* 0x40 */ 176 break; 177 } 178 } 179} 180 181/* 182 * Dump configuration map tuple. 183 */ 184void 185dump_config_map(struct tuple *tp) 186{ 187 unsigned char *p, x; 188 int rlen, mlen; 189 int i; 190 union { 191 unsigned long l; 192 unsigned char b[4]; 193 } u; 194 195 rlen = (tp->data[0] & 3) + 1; 196 mlen = ((tp->data[0] >> 2) & 3) + 1; 197 u.l = 0; 198 p = tp->data + 2; 199 for (i = 0; i < rlen; i++) 200 u.b[i] = *p++; 201 printf("\tReg len = %d, config register addr = 0x%lx, last config = 0x%x\n", 202 rlen, u.l, tp->data[1]); 203 if (mlen) 204 printf("\tRegisters: "); 205 for (i = 0; i < mlen; i++, p++) { 206 for (x = 0x1; x; x <<= 1) 207 printf("%c", x & *p ? 'X' : '-'); 208 printf(" "); 209 } 210 printf("\n"); 211} 212 213/* 214 * Dump a config entry. 215 */ 216void 217dump_cis_config(struct tuple *tp) 218{ 219 unsigned char *p, feat; 220 int i, j; 221 char c; 222 223 p = tp->data; 224 printf("\tConfig index = 0x%x%s\n", *p & 0x3F, 225 *p & 0x40 ? "(default)" : ""); 226 if (*p & 0x80) { 227 p++; 228 printf("\tInterface byte = 0x%x ", *p); 229 switch (*p & 0xF) { 230 default: 231 printf("(reserved)"); 232 break; 233 case 0: 234 printf("(memory)"); 235 break; 236 case 1: 237 printf("(I/O)"); 238 break; 239 case 4: 240 case 5: 241 case 6: 242 case 7: 243 case 8: 244 printf("(custom)"); 245 break; 246 } 247 c = ' '; 248 if (*p & 0x10) { 249 printf(" BVD1/2 active"); 250 c = ','; 251 } 252 if (*p & 0x20) { 253 printf("%c card WP active", c); /* Write protect */ 254 c = ','; 255 } 256 if (*p & 0x40) { 257 printf("%c +RDY/-BSY active", c); 258 c = ','; 259 } 260 if (*p & 0x80) 261 printf("%c wait signal supported", c); 262 printf("\n"); 263 } 264 p++; 265 feat = *p++; 266 switch (CIS_FEAT_POWER(feat)) { 267 case 0: 268 break; 269 case 1: 270 printf("\tVcc pwr:\n"); 271 p += dump_pwr_desc(p); 272 break; 273 case 2: 274 printf("\tVcc pwr:\n"); 275 p += dump_pwr_desc(p); 276 printf("\tVpp pwr:\n"); 277 p += dump_pwr_desc(p); 278 break; 279 case 3: 280 printf("\tVcc pwr:\n"); 281 p += dump_pwr_desc(p); 282 printf("\tVpp1 pwr:\n"); 283 p += dump_pwr_desc(p); 284 printf("\tVpp2 pwr:\n"); 285 p += dump_pwr_desc(p); 286 break; 287 } 288 if (feat & CIS_FEAT_TIMING) { 289 i = CIS_WAIT_SCALE(*p); 290 j = CIS_READY_SCALE(*p); 291 p++; 292 if (i != 3) { 293 printf("\tWait scale "); 294 print_ext_speed(*p, i); 295 while (*p & 0x80) 296 p++; 297 printf("\n"); 298 } 299 if (j != 7) { 300 printf("\tRDY/BSY scale "); 301 print_ext_speed(*p, j); 302 while (*p & 0x80) 303 p++; 304 printf("\n"); 305 } 306 } 307 if (feat & CIS_FEAT_I_O) { 308 if (CIS_IO_ADDR(*p)) 309 printf("\tCard decodes %d address lines", 310 CIS_IO_ADDR(*p)); 311 else 312 printf("\tCard provides address decode"); 313 switch (CIS_MEM_ADDRSZ(*p)) { 314 case 0: 315 break; 316 case 1: 317 printf(", 8 Bit I/O only"); 318 break; 319 case 2: 320 printf(", limited 8/16 Bit I/O"); 321 break; 322 case 3: 323 printf(", full 8/16 Bit I/O"); 324 break; 325 } 326 printf("\n"); 327 if (*p & CIS_IO_RANGE) { 328 p++; 329 c = *p++; 330 for (i = 0; i <= CIS_IO_BLKS(c); i++) { 331 printf("\t\tI/O address # %d: ", i + 1); 332 switch (CIS_IO_ADSZ(c)) { 333 case 0: 334 break; 335 case 1: 336 printf("block start = 0x%x", *p++); 337 break; 338 case 2: 339 printf("block start = 0x%x", (p[1] << 8) | *p); 340 p += 2; 341 break; 342 case 3: 343 printf("block start = 0x%x", 344 (p[3] << 24) | (p[2] << 16) | 345 (p[1] << 8) | *p); 346 p += 4; 347 break; 348 } 349 switch (CIS_IO_BLKSZ(c)) { 350 case 0: 351 break; 352 case 1: 353 printf(" block length = 0x%x", *p++ + 1); 354 break; 355 case 2: 356 printf(" block length = 0x%x", ((p[1] << 8) | *p) + 1); 357 p += 2; 358 break; 359 case 3: 360 printf(" block length = 0x%x", 361 ((p[3] << 24) | (p[2] << 16) | 362 (p[1] << 8) | *p) + 1); 363 p += 4; 364 break; 365 } 366 printf("\n"); 367 } 368 } 369 } 370 371 /* IRQ descriptor */ 372 if (feat & CIS_FEAT_IRQ) { 373 printf("\t\tIRQ modes:"); 374 c = ' '; 375 if (*p & CIS_IRQ_LEVEL) { 376 printf(" Level"); 377 c = ','; 378 } 379 if (*p & CIS_IRQ_PULSE) { 380 printf("%c Pulse", c); 381 c = ','; 382 } 383 if (*p & CIS_IRQ_SHARING) 384 printf("%c Shared", c); 385 printf("\n"); 386 if (*p & CIS_IRQ_MASK) { 387 i = p[0] | (p[1] << 8); 388 printf("\t\tIRQs: "); 389 if (*p & 1) 390 printf(" NMI"); 391 if (*p & 0x2) 392 printf(" IOCK"); 393 if (*p & 0x4) 394 printf(" BERR"); 395 if (*p & 0x8) 396 printf(" VEND"); 397 for (j = 0; j < 16; j++) 398 if (i & (1 << j)) 399 printf(" %d", j); 400 printf("\n"); 401 p += 3; 402 } else { 403 printf("\t\tIRQ level = %d\n", CIS_IRQ_IRQN(*p)); 404 p++; 405 } 406 } 407 switch (CIS_FEAT_MEMORY(feat)) { 408 case 0: 409 break; 410 case 1: 411 printf("\tMemory space length = 0x%x\n", (p[1] << 8) | p[0]); 412 p += 2; 413 break; 414 case 2: 415 printf("\tMemory space address = 0x%x, length = 0x%x\n", 416 (p[3] << 8) | p[2], 417 (p[1] << 8) | p[0]); 418 p += 4; 419 break; 420 421 /* Memory descriptors. */ 422 case 3: 423 c = *p++; 424 for (i = 0; i <= (c & 7); i++) { 425 printf("\tMemory descriptor %d\n\t\t", i + 1); 426 switch (CIS_MEM_LENSZ(c)) { 427 case 0: 428 break; 429 case 1: 430 printf(" blk length = 0x%x00", *p++); 431 break; 432 case 2: 433 printf(" blk length = 0x%x00", (p[1] << 8) | *p); 434 p += 2; 435 break; 436 case 3: 437 printf(" blk length = 0x%x00", 438 (p[3] << 24) | (p[2] << 16) | 439 (p[1] << 8) | *p); 440 p += 4; 441 break; 442 } 443 switch (CIS_MEM_ADDRSZ(c)) { 444 case 0: 445 break; 446 case 1: 447 printf(" card addr = 0x%x00", *p++); 448 break; 449 case 2: 450 printf(" card addr = 0x%x00", (p[1] << 8) | *p); 451 p += 2; 452 break; 453 case 3: 454 printf(" card addr = 0x%x00", 455 (p[3] << 24) | (p[2] << 16) | 456 (p[1] << 8) | *p); 457 p += 4; 458 break; 459 } 460 if (c & CIS_MEM_HOST) 461 switch ((c >> 5) & 3) { 462 case 0: 463 break; 464 case 1: 465 printf(" host addr = 0x%x00", *p++); 466 break; 467 case 2: 468 printf(" host addr = 0x%x00", (p[1] << 8) | *p); 469 p += 2; 470 break; 471 case 3: 472 printf(" host addr = 0x%x00", 473 (p[3] << 24) | (p[2] << 16) | 474 (p[1] << 8) | *p); 475 p += 4; 476 break; 477 } 478 printf("\n"); 479 } 480 break; 481 } 482 if (feat & CIS_FEAT_MISC) { 483 printf("\tMax twin cards = %d\n", *p & 7); 484 printf("\tMisc attr:"); 485 if (*p & 0x8) 486 printf(" (Audio-BVD2)"); 487 if (*p & 0x10) 488 printf(" (Read-only)"); 489 if (*p & 0x20) 490 printf(" (Power down supported)"); 491 if (*p & 0x80) { 492 printf(" (Ext byte = 0x%x)", p[1]); 493 p++; 494 } 495 printf("\n"); 496 p++; 497 } 498} 499 500/* 501 * dump_other_cond - Dump other conditions. 502 */ 503void 504dump_other_cond(unsigned char *p) 505{ 506 if (p[0]) { 507 printf("\t"); 508 if (p[0] & 1) 509 printf("(MWAIT)"); 510 if (p[0] & 2) 511 printf(" (3V card)"); 512 if (p[0] & 0x80) 513 printf(" (Extension bytes follow)"); 514 printf("\n"); 515 } 516} 517 518/* 519 * Dump power descriptor. 520 */ 521int 522dump_pwr_desc(unsigned char *p) 523{ 524 int len = 1, i; 525 unsigned char mask; 526 char **expp; 527 static char *pname[] = 528 {"Nominal operating supply voltage", 529 "Minimum operating supply voltage", 530 "Maximum operating supply voltage", 531 "Continuous supply current", 532 "Max current average over 1 second", 533 "Max current average over 10 ms", 534 "Power down supply current", 535 "Reserved" 536 }; 537 static char *vexp[] = 538 {"10uV", "100uV", "1mV", "10mV", "100mV", "1V", "10V", "100V"}; 539 static char *cexp[] = 540 {"10nA", "1uA", "10uA", "100uA", "1mA", "10mA", "100mA", "1A"}; 541 static char *mant[] = 542 {"1", "1.2", "1.3", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", 543 "5", "5.5", "6", "7", "8", "9"}; 544 545 mask = *p++; 546 expp = vexp; 547 for (i = 0; i < 8; i++) 548 if (mask & (1 << i)) { 549 len++; 550 if (i >= 3) 551 expp = cexp; 552 printf("\t\t%s: ", pname[i]); 553 printf("%s x %s", 554 mant[(*p >> 3) & 0xF], 555 expp[*p & 7]); 556 while (*p & 0x80) { 557 len++; 558 p++; 559 printf(", ext = 0x%x", *p); 560 } 561 printf("\n"); 562 p++; 563 } 564 return (len); 565} 566 567void 568dump_device_desc(unsigned char *p, int len, char *type) 569{ 570 static char *un_name[] = 571 {"512b", "2Kb", "8Kb", "32Kb", "128Kb", "512Kb", "2Mb", "reserved"}; 572 static char *speed[] = 573 {"No speed", "250nS", "200nS", "150nS", 574 "100nS", "Reserved", "Reserved"}; 575 static char *dev[] = 576 {"No device", "Mask ROM", "OTPROM", "UV EPROM", 577 "EEPROM", "FLASH EEPROM", "SRAM", "DRAM", 578 "Reserved", "Reserved", "Reserved", "Reserved", 579 "Reserved", "Function specific", "Extended", 580 "Reserved"}; 581 int count = 0; 582 583 while (*p != 0xFF && len > 0) { 584 unsigned char x; 585 586 x = *p++; 587 len -= 2; 588 if (count++ == 0) 589 printf("\t%s memory device information:\n", type); 590 printf("\t\tDevice number %d, type %s, WPS = %s\n", 591 count, dev[x >> 4], (x & 0x8) ? "ON" : "OFF"); 592 if ((x & 7) == 7) { 593 len--; 594 if (*p) { 595 printf("\t\t"); 596 print_ext_speed(*p, 0); 597 while (*p & 0x80) { 598 p++; 599 len--; 600 } 601 } 602 p++; 603 } else 604 printf("\t\tSpeed = %s", speed[x & 7]); 605 printf(", Memory block size = %s, %d units\n", 606 un_name[*p & 7], (*p >> 3) + 1); 607 p++; 608 } 609} 610 611/* 612 * Print version info 613 */ 614void 615dump_info_v1(unsigned char *p, int len) 616{ 617 printf("\tVersion = %d.%d", p[0], p[1]); 618 p += 2; 619 printf(", Manuf = [%s],", p); 620 while (*p++); 621 printf("card vers = [%s]\n", p); 622 while (*p++); 623 printf("\tAddit. info = [%s]", p); 624 while (*p++); 625 printf(",[%s]\n", p); 626} 627 628/* 629 * dump functional extension tuple. 630 */ 631void 632dump_func_ext(unsigned char *p, int len) 633{ 634 if (len == 0) 635 return; 636 switch (p[0]) { 637 case 0: 638 case 8: 639 case 10: 640 if (len != 4) { 641 printf("\tWrong length for serial extension\n"); 642 return; 643 } 644 printf("\tSerial interface extension:\n"); 645 switch (p[1] & 0x1F) { 646 default: 647 printf("\t\tUnkn device"); 648 break; 649 case 0: 650 printf("\t\t8250 UART"); 651 break; 652 case 1: 653 printf("\t\t16450 UART"); 654 break; 655 case 2: 656 printf("\t\t16550 UART"); 657 break; 658 } 659 printf(", Parity - %s%s%s%s", 660 (p[2] & 1) ? "Space," : "", 661 (p[2] & 2) ? "Mark," : "", 662 (p[2] & 4) ? "Odd," : "", 663 (p[2] & 8) ? "Even," : ""); 664 printf("\n"); 665 break; 666 case 1: 667 case 5: 668 case 6: 669 case 7: 670 printf("\tModem interface capabilities:\n"); 671 break; 672 case 2: 673 printf("\tData modem services available:\n"); 674 break; 675 case 9: 676 printf("\tFax/modem services available:\n"); 677 break; 678 case 4: 679 printf("\tVoice services available:\n"); 680 break; 681 } 682} 683 684/* 685 * print_ext_speed - Print extended speed. 686 */ 687void 688print_ext_speed(unsigned char x, int scale) 689{ 690 static char *mant[] = 691 {"Reserved", "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0", 692 "3.5", "4.0", "4.5", "5.0", "5.5", "6.0", "7.0", "8.0"}; 693 static char *exp[] = 694 {"1 ns", "10 ns", "100 ns", "1 us", "10 us", "100 us", 695 "1 ms", "10 ms"}; 696 static char *scale_name[] = 697 {"None", "10", "100", "1,000", "10,000", "100,000", 698 "1,000,000", "10,000,000"}; 699 700 printf("Speed = %s x %s", mant[(x >> 3) & 0xF], exp[x & 7]); 701 if (scale) 702 printf(", scaled by %s", scale_name[scale & 7]); 703} 704