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