printcis.c revision 17383
1178848Scokane/* 2178848Scokane * Copyright (c) 1995 Andrew McRae. All rights reserved. 3178848Scokane * 4178848Scokane * Redistribution and use in source and binary forms, with or without 5178848Scokane * modification, are permitted provided that the following conditions 6178848Scokane * are met: 7178848Scokane * 1. Redistributions of source code must retain the above copyright 8178848Scokane * notice, this list of conditions and the following disclaimer. 9178848Scokane * 2. Redistributions in binary form must reproduce the above copyright 10178848Scokane * notice, this list of conditions and the following disclaimer in the 11178848Scokane * documentation and/or other materials provided with the distribution. 12178848Scokane * 3. The name of the author may not be used to endorse or promote products 13178848Scokane * derived from this software without specific prior written permission. 14178848Scokane * 15178848Scokane * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16178848Scokane * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17178848Scokane * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18178848Scokane * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19178848Scokane * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20178848Scokane * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21178848Scokane * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22178848Scokane * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23178848Scokane * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24178848Scokane * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25178848Scokane * 26178848Scokane * $Id: printcis.c,v 1.4 1996/04/18 04:24:55 nate Exp $ 27178848Scokane */ 28178848Scokane#include <stdio.h> 29178848Scokane#include <unistd.h> 30178848Scokane#include <stdlib.h> 31178848Scokane#include <string.h> 32178848Scokane#include <sys/ioctl.h> 33178848Scokane 34178848Scokane#include <pccard/card.h> 35178848Scokane#include <pccard/cis.h> 36178848Scokane 37178848Scokane#include "readcis.h" 38178848Scokane 39178848Scokaneint dump_pwr_desc(unsigned char *); 40178848Scokanevoid print_ext_speed(unsigned char, int); 41178848Scokanevoid dump_device_desc(unsigned char *p, int len, char *type); 42178848Scokanevoid dump_info_v1(unsigned char *p, int len); 43178848Scokanevoid dump_config_map(struct tuple *tp); 44178848Scokanevoid dump_cis_config(struct tuple *tp); 45178848Scokanevoid dump_other_cond(unsigned char *p); 46178848Scokanevoid dump_func_ext(unsigned char *p, int len); 47178848Scokane 48178848Scokanevoid 49178848Scokanedumpcis(struct cis *cp) 50178848Scokane{ 51178848Scokane struct tuple *tp; 52178848Scokane struct tuple_list *tl; 53178848Scokane int count = 0, sz, ad, i; 54178848Scokane unsigned char *p; 55178848Scokane 56178848Scokane for (tl = cp->tlist; tl; tl = tl->next) 57178848Scokane for (tp = tl->tuples; tp; tp = tp->next) { 58178848Scokane printf("Tuple #%d, code = 0x%x (%s), length = %d\n", 59178848Scokane ++count, tp->code, tuple_name(tp->code), tp->length); 60178848Scokane p = tp->data; 61178848Scokane sz = tp->length; 62178848Scokane ad = 0; 63178848Scokane while (sz > 0) { 64178848Scokane printf(" %03x: ", ad); 65178848Scokane for (i = 0; i < ((sz < 16) ? sz : 16); i++) 66178848Scokane printf(" %02x", p[i]); 67178848Scokane printf("\n"); 68178848Scokane sz -= 16; 69178848Scokane p += 16; 70178848Scokane ad += 16; 71178848Scokane } 72178848Scokane switch (tp->code) { 73178848Scokane default: 74178848Scokane break; 75178848Scokane case CIS_MEM_COMMON: /* 0x01 */ 76178848Scokane dump_device_desc(tp->data, tp->length, "Common"); 77178848Scokane break; 78178848Scokane case CIS_CHECKSUM: /* 0x10 */ 79178848Scokane if (tp->length == 5) { 80178848Scokane printf("\tChecksum from offset %d, length %d, value is 0x%x\n", 81178848Scokane (short)((tp->data[1] << 8) | tp->data[0]), 82178848Scokane (tp->data[3] << 8) | tp->data[2], 83178848Scokane tp->data[4]); 84178848Scokane } else 85178848Scokane printf("\tIllegal length for checksum!\n"); 86178848Scokane break; 87178848Scokane case CIS_LONGLINK_A: /* 0x11 */ 88178848Scokane printf("\tLong link to attribute memory, address 0x%x\n", 89178848Scokane (tp->data[3] << 24) | 90178848Scokane (tp->data[2] << 16) | 91178848Scokane (tp->data[1] << 8) | 92178848Scokane tp->data[0]); 93178848Scokane break; 94178848Scokane case CIS_LONGLINK_C: /* 0x12 */ 95178848Scokane printf("\tLong link to common memory, address 0x%x\n", 96178848Scokane (tp->data[3] << 24) | 97178848Scokane (tp->data[2] << 16) | 98178848Scokane (tp->data[1] << 8) | 99178848Scokane tp->data[0]); 100178848Scokane break; 101178848Scokane break; 102178848Scokane case CIS_INFO_V1: /* 0x15 */ 103178848Scokane dump_info_v1(tp->data, tp->length); 104178848Scokane break; 105178848Scokane case CIS_ALTSTR: /* 0x16 */ 106178848Scokane break; 107178848Scokane case CIS_MEM_ATTR: /* 0x17 */ 108178848Scokane dump_device_desc(tp->data, tp->length, "Attribute"); 109178848Scokane break; 110178848Scokane case CIS_JEDEC_C: /* 0x18 */ 111178848Scokane break; 112178848Scokane case CIS_JEDEC_A: /* 0x19 */ 113178848Scokane break; 114178848Scokane 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 (CIS_FEAT_POWER(feat)) { 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 & CIS_FEAT_TIMING) { 285 i = CIS_WAIT_SCALE(*p); 286 j = CIS_READY_SCALE(*p); 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 & CIS_FEAT_I_O) { 304 if (CIS_IO_ADDR(*p)) 305 printf("\tCard decodes %d address lines", 306 CIS_IO_ADDR(*p)); 307 else 308 printf("\tCard provides address decode"); 309 switch (CIS_MEM_ADDRSZ(*p)) { 310 case 0: 311 break; 312 case 1: 313 printf(", 8 Bit I/O only"); 314 break; 315 case 2: 316 printf(", limited 8/16 Bit I/O"); 317 break; 318 case 3: 319 printf(", full 8/16 Bit I/O"); 320 break; 321 } 322 printf("\n"); 323 if (*p & CIS_IO_RANGE) { 324 p++; 325 c = *p++; 326 for (i = 0; i <= CIS_IO_BLKS(c); i++) { 327 printf("\t\tI/O address # %d: ", i + 1); 328 switch (CIS_IO_ADSZ(c)) { 329 case 0: 330 break; 331 case 1: 332 printf("block start = 0x%x", *p++); 333 break; 334 case 2: 335 printf("block start = 0x%x", (p[1] << 8) | *p); 336 p += 2; 337 break; 338 case 3: 339 printf("block start = 0x%x", 340 (p[3] << 24) | (p[2] << 16) | 341 (p[1] << 8) | *p); 342 p += 4; 343 break; 344 } 345 switch (CIS_IO_BLKSZ(c)) { 346 case 0: 347 break; 348 case 1: 349 printf(" block length = 0x%x", *p++ + 1); 350 break; 351 case 2: 352 printf(" block length = 0x%x", ((p[1] << 8) | *p) + 1); 353 p += 2; 354 break; 355 case 3: 356 printf(" block length = 0x%x", 357 ((p[3] << 24) | (p[2] << 16) | 358 (p[1] << 8) | *p) + 1); 359 p += 4; 360 break; 361 } 362 printf("\n"); 363 } 364 } 365 } 366 367 /* IRQ descriptor */ 368 if (feat & CIS_FEAT_IRQ) { 369 printf("\t\tIRQ modes:"); 370 c = ' '; 371 if (*p & CIS_IRQ_LEVEL) { 372 printf(" Level"); 373 c = ','; 374 } 375 if (*p & CIS_IRQ_PULSE) { 376 printf("%c Pulse", c); 377 c = ','; 378 } 379 if (*p & CIS_IRQ_SHARING) 380 printf("%c Shared", c); 381 printf("\n"); 382 if (*p & CIS_IRQ_MASK) { 383 i = p[0] | (p[1] << 8); 384 printf("\t\tIRQs: "); 385 if (*p & 1) 386 printf(" NMI"); 387 if (*p & 0x2) 388 printf(" IOCK"); 389 if (*p & 0x4) 390 printf(" BERR"); 391 if (*p & 0x8) 392 printf(" VEND"); 393 for (j = 0; j < 16; j++) 394 if (i & (1 << j)) 395 printf(" %d", j); 396 printf("\n"); 397 p += 3; 398 } else { 399 printf("\t\tIRQ level = %d\n", CIS_IRQ_IRQN(*p)); 400 p++; 401 } 402 } 403 switch (CIS_FEAT_MEMORY(feat)) { 404 case 0: 405 break; 406 case 1: 407 printf("\tMemory space length = 0x%x\n", (p[1] << 8) | p[0]); 408 p += 2; 409 break; 410 case 2: 411 printf("\tMemory space address = 0x%x, length = 0x%x\n", 412 (p[3] << 8) | p[2], 413 (p[1] << 8) | p[0]); 414 p += 4; 415 break; 416 417 /* Memory descriptors. */ 418 case 3: 419 c = *p++; 420 for (i = 0; i <= (c & 7); i++) { 421 printf("\tMemory descriptor %d\n\t\t", i + 1); 422 switch (CIS_MEM_LENSZ(c)) { 423 case 0: 424 break; 425 case 1: 426 printf(" blk length = 0x%x00", *p++); 427 break; 428 case 2: 429 printf(" blk length = 0x%x00", (p[1] << 8) | *p); 430 p += 2; 431 break; 432 case 3: 433 printf(" blk length = 0x%x00", 434 (p[3] << 24) | (p[2] << 16) | 435 (p[1] << 8) | *p); 436 p += 4; 437 break; 438 } 439 switch (CIS_MEM_ADDRSZ(c)) { 440 case 0: 441 break; 442 case 1: 443 printf(" card addr = 0x%x00", *p++); 444 break; 445 case 2: 446 printf(" card addr = 0x%x00", (p[1] << 8) | *p); 447 p += 2; 448 break; 449 case 3: 450 printf(" card addr = 0x%x00", 451 (p[3] << 24) | (p[2] << 16) | 452 (p[1] << 8) | *p); 453 p += 4; 454 break; 455 } 456 if (c & CIS_MEM_HOST) 457 switch ((c >> 5) & 3) { 458 case 0: 459 break; 460 case 1: 461 printf(" host addr = 0x%x00", *p++); 462 break; 463 case 2: 464 printf(" host addr = 0x%x00", (p[1] << 8) | *p); 465 p += 2; 466 break; 467 case 3: 468 printf(" host addr = 0x%x00", 469 (p[3] << 24) | (p[2] << 16) | 470 (p[1] << 8) | *p); 471 p += 4; 472 break; 473 } 474 printf("\n"); 475 } 476 break; 477 } 478 if (feat & CIS_FEAT_MISC) { 479 printf("\tMax twin cards = %d\n", *p & 7); 480 printf("\tMisc attr:"); 481 if (*p & 0x8) 482 printf(" (Audio-BVD2)"); 483 if (*p & 0x10) 484 printf(" (Read-only)"); 485 if (*p & 0x20) 486 printf(" (Power down supported)"); 487 if (*p & 0x80) { 488 printf(" (Ext byte = 0x%x)", p[1]); 489 p++; 490 } 491 printf("\n"); 492 p++; 493 } 494} 495 496/* 497 * dump_other_cond - Dump other conditions. 498 */ 499void 500dump_other_cond(unsigned char *p) 501{ 502 if (p[0]) { 503 printf("\t"); 504 if (p[0] & 1) 505 printf("(MWAIT)"); 506 if (p[0] & 2) 507 printf(" (3V card)"); 508 if (p[0] & 0x80) 509 printf(" (Extension bytes follow)"); 510 printf("\n"); 511 } 512} 513 514/* 515 * Dump power descriptor. 516 */ 517int 518dump_pwr_desc(unsigned char *p) 519{ 520 int len = 1, i; 521 unsigned char mask; 522 char **expp; 523 static char *pname[] = 524 {"Nominal operating supply voltage", 525 "Minimum operating supply voltage", 526 "Maximum operating supply voltage", 527 "Continuous supply current", 528 "Max current average over 1 second", 529 "Max current average over 10 ms", 530 "Power down supply current", 531 "Reserved" 532 }; 533 static char *vexp[] = 534 {"10uV", "100uV", "1mV", "10mV", "100mV", "1V", "10V", "100V"}; 535 static char *cexp[] = 536 {"10nA", "1uA", "10uA", "100uA", "1mA", "10mA", "100mA", "1A"}; 537 static char *mant[] = 538 {"1", "1.2", "1.3", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", 539 "5", "5.5", "6", "7", "8", "9"}; 540 541 mask = *p++; 542 expp = vexp; 543 for (i = 0; i < 8; i++) 544 if (mask & (1 << i)) { 545 len++; 546 if (i >= 3) 547 expp = cexp; 548 printf("\t\t%s: ", pname[i]); 549 printf("%s x %s", 550 mant[(*p >> 3) & 0xF], 551 expp[*p & 7]); 552 while (*p & 0x80) { 553 len++; 554 p++; 555 printf(", ext = 0x%x", *p); 556 } 557 printf("\n"); 558 p++; 559 } 560 return (len); 561} 562 563void 564dump_device_desc(unsigned char *p, int len, char *type) 565{ 566 static char *un_name[] = 567 {"512b", "2Kb", "8Kb", "32Kb", "128Kb", "512Kb", "2Mb", "reserved"}; 568 static char *speed[] = 569 {"No speed", "250nS", "200nS", "150nS", 570 "100nS", "Reserved", "Reserved"}; 571 static char *dev[] = 572 {"No device", "Mask ROM", "OTPROM", "UV EPROM", 573 "EEPROM", "FLASH EEPROM", "SRAM", "DRAM", 574 "Reserved", "Reserved", "Reserved", "Reserved", 575 "Reserved", "Function specific", "Extended", 576 "Reserved"}; 577 int count = 0; 578 579 while (*p != 0xFF && len > 0) { 580 unsigned char x; 581 582 x = *p++; 583 len -= 2; 584 if (count++ == 0) 585 printf("\t%s memory device information:\n", type); 586 printf("\t\tDevice number %d, type %s, WPS = %s\n", 587 count, dev[x >> 4], (x & 0x8) ? "ON" : "OFF"); 588 if ((x & 7) == 7) { 589 len--; 590 if (*p) { 591 printf("\t\t"); 592 print_ext_speed(*p, 0); 593 while (*p & 0x80) { 594 p++; 595 len--; 596 } 597 } 598 p++; 599 } else 600 printf("\t\tSpeed = %s", speed[x & 7]); 601 printf(", Memory block size = %s, %d units\n", 602 un_name[*p & 7], (*p >> 3) + 1); 603 p++; 604 } 605} 606 607/* 608 * Print version info 609 */ 610void 611dump_info_v1(unsigned char *p, int len) 612{ 613 printf("\tVersion = %d.%d", p[0], p[1]); 614 p += 2; 615 printf(", Manuf = [%s],", p); 616 while (*p++); 617 printf("card vers = [%s]\n", p); 618 while (*p++); 619 printf("\tAddit. info = [%s]", p); 620 while (*p++); 621 printf(",[%s]\n", p); 622} 623 624/* 625 * dump functional extension tuple. 626 */ 627void 628dump_func_ext(unsigned char *p, int len) 629{ 630 if (len == 0) 631 return; 632 switch (p[0]) { 633 case 0: 634 case 8: 635 case 10: 636 if (len != 4) { 637 printf("\tWrong length for serial extension\n"); 638 return; 639 } 640 printf("\tSerial interface extension:\n"); 641 switch (p[1] & 0x1F) { 642 default: 643 printf("\t\tUnkn device"); 644 break; 645 case 0: 646 printf("\t\t8250 UART"); 647 break; 648 case 1: 649 printf("\t\t16450 UART"); 650 break; 651 case 2: 652 printf("\t\t16550 UART"); 653 break; 654 } 655 printf(", Parity - %s%s%s%s", 656 (p[2] & 1) ? "Space," : "", 657 (p[2] & 2) ? "Mark," : "", 658 (p[2] & 4) ? "Odd," : "", 659 (p[2] & 8) ? "Even," : ""); 660 printf("\n"); 661 break; 662 case 1: 663 case 5: 664 case 6: 665 case 7: 666 printf("\tModem interface capabilities:\n"); 667 break; 668 case 2: 669 printf("\tData modem services available:\n"); 670 break; 671 case 9: 672 printf("\tFax/modem services available:\n"); 673 break; 674 case 4: 675 printf("\tVoice services available:\n"); 676 break; 677 } 678} 679 680/* 681 * print_ext_speed - Print extended speed. 682 */ 683void 684print_ext_speed(unsigned char x, int scale) 685{ 686 static char *mant[] = 687 {"Reserved", "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0", 688 "3.5", "4.0", "4.5", "5.0", "5.5", "6.0", "7.0", "8.0"}; 689 static char *exp[] = 690 {"1 ns", "10 ns", "100 ns", "1 us", "10 us", "100 us", 691 "1 ms", "10 ms"}; 692 static char *scale_name[] = 693 {"None", "10", "100", "1,000", "10,000", "100,000", 694 "1,000,000", "10,000,000"}; 695 696 printf("Speed = %s x %s", mant[(x >> 3) & 0xF], exp[x & 7]); 697 if (scale) 698 printf(", scaled by %s", scale_name[scale & 7]); 699} 700