readcis.c revision 185033
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 "$FreeBSD: head/usr.sbin/dumpcis/readcis.c 185033 2008-11-17 22:46:29Z imp $"; 30#endif /* not lint */ 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 <pccard/cardinfo.h> 45#include <pccard/cis.h> 46 47#include "readcis.h" 48 49static int ck_linktarget(int, off_t, int); 50static void cis_info(struct cis *, unsigned char *, int); 51static void device_desc(unsigned char *, int, struct dev_mem *); 52static void config_map(struct cis *, unsigned char *, int); 53static void cis_config(struct cis *, unsigned char *, int); 54static void cis_manuf_id(struct cis *, unsigned char *, int); 55static void cis_func_id(struct cis *, unsigned char *, int); 56static void cis_network_ext(struct cis *, unsigned char *, int); 57static struct tuple_list *read_one_tuplelist(int, int, off_t); 58static struct tuple_list *read_tuples(int); 59static struct tuple *find_tuple_in_list(struct tuple_list *, unsigned char); 60static struct tuple_info *get_tuple_info(unsigned char); 61 62static struct tuple_info tuple_info[] = { 63 {"Null tuple", 0x00, 0}, 64 {"Common memory descriptor", 0x01, 255}, 65 {"Long link to next chain for CardBus", 0x02, 255}, 66 {"Indirect access", 0x03, 255}, 67 {"Configuration map for CardBus", 0x04, 255}, 68 {"Configuration entry for CardBus", 0x05, 255}, 69 {"Long link to next chain for MFC", 0x06, 255}, 70 {"Base address register for CardBus", 0x07, 6}, 71 {"Checksum", 0x10, 5}, 72 {"Long link to attribute memory", 0x11, 4}, 73 {"Long link to common memory", 0x12, 4}, 74 {"Link target", 0x13, 3}, 75 {"No link", 0x14, 0}, 76 {"Version 1 info", 0x15, 255}, 77 {"Alternate language string", 0x16, 255}, 78 {"Attribute memory descriptor", 0x17, 255}, 79 {"JEDEC descr for common memory", 0x18, 255}, 80 {"JEDEC descr for attribute memory", 0x19, 255}, 81 {"Configuration map", 0x1A, 255}, 82 {"Configuration entry", 0x1B, 255}, 83 {"Other conditions for common memory", 0x1C, 255}, 84 {"Other conditions for attribute memory", 0x1D, 255}, 85 {"Geometry info for common memory", 0x1E, 255}, 86 {"Geometry info for attribute memory", 0x1F, 255}, 87 {"Manufacturer ID", 0x20, 4}, 88 {"Functional ID", 0x21, 2}, 89 {"Functional EXT", 0x22, 255}, 90 {"Software interleave", 0x23, 2}, 91 {"Version 2 Info", 0x40, 255}, 92 {"Data format", 0x41, 255}, 93 {"Geometry", 0x42, 4}, 94 {"Byte order", 0x43, 2}, 95 {"Card init date", 0x44, 4}, 96 {"Battery replacement", 0x45, 4}, 97 {"Organization", 0x46, 255}, 98 {"Terminator", 0xFF, 0}, 99 {0, 0, 0} 100}; 101 102 103static void * 104xmalloc(int sz) 105{ 106 void *p; 107 108 sz = (sz + 7) & ~7; 109 p = malloc(sz); 110 if (p) 111 bzero(p, sz); 112 else 113 errx(1, "malloc"); 114 return (p); 115} 116 117/* 118 * After reading the tuples, decode the relevant ones. 119 */ 120struct cis * 121readcis(int fd) 122{ 123 struct tuple_list *tl; 124 struct tuple *tp; 125 struct cis *cp; 126 127 cp = xmalloc(sizeof(*cp)); 128 cp->tlist = read_tuples(fd); 129 if (cp->tlist == 0) 130 return (NULL); 131 132 for (tl = cp->tlist; tl; tl = tl->next) 133 for (tp = tl->tuples; tp; tp = tp->next) { 134#if 0 135 printf("tuple code = 0x%02x, data is\n", tp->code); 136 dump(tp->data, tp->length); 137#endif 138 switch (tp->code) { 139 case CIS_MEM_COMMON: /* 0x01 */ 140 device_desc(tp->data, tp->length, &cp->common_mem); 141 break; 142 case CIS_INFO_V1: /* 0x15 */ 143 cis_info(cp, tp->data, tp->length); 144 break; 145 case CIS_MEM_ATTR: /* 0x17 */ 146 device_desc(tp->data, tp->length, &cp->attr_mem); 147 break; 148 case CIS_CONF_MAP: /* 0x1A */ 149 config_map(cp, tp->data, tp->length); 150 break; 151 case CIS_CONFIG: /* 0x1B */ 152 cis_config(cp, tp->data, tp->length); 153 break; 154 case CIS_MANUF_ID: /* 0x20 */ 155 cis_manuf_id(cp, tp->data, tp->length); 156 break; 157 case CIS_FUNC_ID: /* 0x21 */ 158 cis_func_id(cp, tp->data, tp->length); 159 break; 160 case CIS_FUNC_EXT: /* 0x22 */ 161 if (cp->func_id1 == 6) /* LAN adaptor */ 162 cis_network_ext(cp, tp->data, tp->length); 163 break; 164 } 165 } 166 return (cp); 167} 168 169/* 170 * free_cis - delete cis entry. 171 */ 172void 173freecis(struct cis *cp) 174{ 175 struct cis_ioblk *io; 176 struct cis_memblk *mem; 177 struct cis_config *conf; 178 struct tuple *tp; 179 struct tuple_list *tl; 180 181 while ((tl = cp->tlist) != 0) { 182 cp->tlist = tl->next; 183 while ((tp = tl->tuples) != 0) { 184 tl->tuples = tp->next; 185 if (tp->data) 186 free(tp->data); 187 } 188 } 189 190 while ((conf = cp->conf) != 0) { 191 cp->conf = conf->next; 192 while ((io = conf->io) != 0) { 193 conf->io = io->next; 194 free(io); 195 } 196 while ((mem = conf->mem) != 0) { 197 conf->mem = mem->next; 198 free(mem); 199 } 200 free(conf); 201 } 202 free(cp); 203} 204 205/* 206 * Fills in CIS version data. 207 */ 208static void 209cis_info(struct cis *cp, unsigned char *p, int len) 210{ 211 cp->maj_v = *p++; 212 cp->min_v = *p++; 213 len -= 2; 214 if (cp->manuf) { 215 free(cp->manuf); 216 cp->manuf = NULL; 217 } 218 if (len > 1 && *p != 0xff) { 219 cp->manuf = strdup(p); 220 len -= strlen(p) + 1; 221 p += strlen(p) + 1; 222 } 223 if (cp->vers) { 224 free(cp->vers); 225 cp->vers = NULL; 226 } 227 if (len > 1 && *p != 0xff) { 228 cp->vers = strdup(p); 229 len -= strlen(p) + 1; 230 p += strlen(p) + 1; 231 } else { 232 cp->vers = strdup("[none]"); 233 } 234 if (cp->add_info1) { 235 free(cp->add_info1); 236 cp->add_info1 = NULL; 237 } 238 if (len > 1 && *p != 0xff) { 239 cp->add_info1 = strdup(p); 240 len -= strlen(p) + 1; 241 p += strlen(p) + 1; 242 } else { 243 cp->add_info1 = strdup("[none]"); 244 } 245 if (cp->add_info2) { 246 free(cp->add_info2); 247 cp->add_info2 = NULL; 248 } 249 if (len > 1 && *p != 0xff) 250 cp->add_info2 = strdup(p); 251 else 252 cp->add_info2 = strdup("[none]"); 253} 254 255static void 256cis_manuf_id(struct cis *cp, unsigned char *p, int len) 257{ 258 if (len >= 4) { 259 cp->manufacturer = tpl16(p); 260 cp->product = tpl16(p+2); 261 if (len == 5) 262 cp->prodext = *(p+4); /* For xe driver */ 263 } else { 264 cp->manufacturer=0; 265 cp->product=0; 266 cp->prodext=0; 267 } 268} 269/* 270 * Fills in CIS function ID. 271 */ 272static void 273cis_func_id(struct cis *cp, unsigned char *p, int len __unused) 274{ 275 cp->func_id1 = *p++; 276 cp->func_id2 = *p++; 277} 278 279static void 280cis_network_ext(struct cis *cp, unsigned char *p, int len __unused) 281{ 282 int i; 283 284 switch (p[0]) { 285 case 4: /* Node ID */ 286 if (len <= 2 || len < p[1] + 2) 287 return; 288 289 if (cp->lan_nid) 290 free(cp->lan_nid); 291 cp->lan_nid = xmalloc(p[1]); 292 293 for (i = 0; i <= p[1]; i++) 294 cp->lan_nid[i] = p[i + 1]; 295 break; 296 } 297} 298 299/* 300 * device_desc - decode device descriptor. 301 */ 302static void 303device_desc(unsigned char *p, int len, struct dev_mem *dp) 304{ 305 while (len > 0 && *p != 0xFF) { 306 dp->valid = 1; 307 dp->type = (*p & 0xF0) >> 4; 308 dp->wps = !!(*p & 0x8); 309 dp->speed = *p & 7; 310 p++; 311 if (*p != 0xFF) { 312 dp->addr = (*p >> 3) & 0xF; 313 dp->units = *p & 7; 314 } 315 p++; 316 len -= 2; 317 } 318} 319 320/* 321 * configuration map of card control register. 322 */ 323static void 324config_map(struct cis *cp, unsigned char *p, int len __unused) 325{ 326 unsigned char *p1; 327 int rlen = (*p & 3) + 1; 328 329 p1 = p + 1; 330 cp->last_config = *p1++ & 0x3F; 331 cp->reg_addr = parse_num(rlen | 0x10, p1, &p1, 0); 332 cp->ccrs = *p1; 333} 334 335/* 336 * Parse variable length value. 337 */ 338u_int 339parse_num(int sz, u_char *p, u_char **q, int ofs) 340{ 341 u_int num = 0; 342 343 switch (sz) { 344 case 0: 345 case 0x10: 346 break; 347 case 1: 348 case 0x11: 349 num = (*p++) + ofs; 350 break; 351 case 2: 352 case 0x12: 353 num = tpl16(p) + ofs; 354 p += 2; 355 break; 356 case 0x13: 357 num = tpl24(p) + ofs; 358 p += 3; 359 break; 360 case 3: 361 case 0x14: 362 num = tpl32(p) + ofs; 363 p += 4; 364 break; 365 } 366 if (q) 367 *q = p; 368 return num; 369} 370 371/* 372 * CIS config entry - Decode and build configuration entry. 373 */ 374static void 375cis_config(struct cis *cp, unsigned char *p, int len __unused) 376{ 377 int x; 378 int i, j; 379 struct cis_config *conf, *last; 380 unsigned char feat; 381 382 conf = xmalloc(sizeof(*conf)); 383 if ((last = cp->conf) != 0) { 384 while (last->next) 385 last = last->next; 386 last->next = conf; 387 } else 388 cp->conf = conf; 389 conf->id = *p & 0x3F; /* Config index */ 390 if (*p & 0x40) /* Default flag */ 391 cp->def_config = conf; 392 if (*p++ & 0x80) 393 p++; /* Interface byte skip */ 394 feat = *p++; /* Features byte */ 395 for (i = 0; i < CIS_FEAT_POWER(feat); i++) { 396 unsigned char parms = *p++; 397 398 conf->pwr = 1; 399 for (j = 0; j < 8; j++) 400 if (parms & (1 << j)) 401 while (*p++ & 0x80); 402 } 403 if (feat & CIS_FEAT_TIMING) { 404 conf->timing = 1; 405 i = *p++; 406 if (CIS_WAIT_SCALE(i) != 3) 407 p++; 408 if (CIS_READY_SCALE(i) != 7) 409 p++; 410 if (CIS_RESERVED_SCALE(i) != 7) 411 p++; 412 } 413 if (feat & CIS_FEAT_I_O) { 414 conf->iospace = 1; 415 if (CIS_IO_RANGE & *p) 416 conf->io_blks = CIS_IO_BLKS(p[1]) + 1; 417 conf->io_addr = CIS_IO_ADDR(*p); 418 conf->io_bus = (*p >> 5) & 3; /* CIS_IO_8BIT | CIS_IO_16BIT */ 419 if (*p++ & CIS_IO_RANGE) { 420 struct cis_ioblk *io; 421 struct cis_ioblk *last_io = NULL; 422 423 i = CIS_IO_ADSZ(*p); 424 j = CIS_IO_BLKSZ(*p++); 425 for (x = 0; x < conf->io_blks; x++) { 426 io = xmalloc(sizeof(*io)); 427 if (last_io) 428 last_io->next = io; 429 else 430 conf->io = io; 431 last_io = io; 432 io->addr = parse_num(i, p, &p, 0); 433 io->size = parse_num(j, p, &p, 1); 434 } 435 } 436 } 437 if (feat & CIS_FEAT_IRQ) { 438 conf->irq = 1; 439 conf->irqlevel = *p & 0xF; 440 conf->irq_flags = *p & 0xF0; 441 if (*p++ & CIS_IRQ_MASK) { 442 conf->irq_mask = tpl16(p); 443 p += 2; 444 } 445 } 446 switch (CIS_FEAT_MEMORY(feat)) { 447 case CIS_FEAT_MEM_NONE: 448 break; 449 case CIS_FEAT_MEM_LEN: 450 conf->memspace = 1; 451 conf->mem = xmalloc(sizeof(*conf->mem)); 452 conf->mem->length = tpl16(p) << 8; 453 break; 454 case CIS_FEAT_MEM_ADDR: 455 conf->memspace = 1; 456 conf->mem = xmalloc(sizeof(*conf->mem)); 457 conf->mem->length = tpl16(p) << 8; 458 conf->mem->address = tpl16(p + 2) << 8; 459 break; 460 case CIS_FEAT_MEM_WIN: { 461 struct cis_memblk *mem; 462 struct cis_memblk *last_mem = NULL; 463 464 conf->memspace = 1; 465 x = *p++; 466 conf->memwins = CIS_MEM_WINS(x); 467 for (i = 0; i < conf->memwins; i++) { 468 mem = xmalloc(sizeof(*mem)); 469 if (last_mem) 470 last_mem->next = mem; 471 else 472 conf->mem = mem; 473 last_mem = mem; 474 mem->length = parse_num(CIS_MEM_LENSZ(x) | 0x10, p, &p, 0) << 8; 475 mem->address = parse_num(CIS_MEM_ADDRSZ(x) | 0x10, p, &p, 0) << 8; 476 if (x & CIS_MEM_HOST) { 477 mem->host_address = parse_num(CIS_MEM_ADDRSZ(x) | 0x10, 478 p, &p, 0) << 8; 479 } 480 } 481 break; 482 } 483 } 484 if (feat & CIS_FEAT_MISC) { 485 conf->misc_valid = 1; 486 conf->misc = *p++; 487 } 488} 489 490/* 491 * Read the tuples from the card. 492 * The processing of tuples is as follows: 493 * - Read tuples at attribute memory, offset 0. 494 * - If a CIS_END is the first tuple, look for 495 * a tuple list at common memory offset 0; this list 496 * must start with a LINKTARGET. 497 * - If a long link tuple was encountered, execute the long 498 * link. 499 * - If a no-link tuple was seen, terminate processing. 500 * - If no no-link tuple exists, and no long link tuple 501 * exists while processing the primary tuple list, 502 * then look for a LINKTARGET tuple in common memory. 503 * - If a long link tuple is found in any list, then process 504 * it. Only one link is allowed per list. 505 */ 506static struct tuple_list *tlist; 507 508static struct tuple_list * 509read_tuples(int fd) 510{ 511 struct tuple_list *tl = 0, *last_tl; 512 struct tuple *tp; 513 int flag; 514 off_t offs; 515 516 tlist = 0; 517 last_tl = tlist = read_one_tuplelist(fd, MDF_ATTR, (off_t) 0); 518 519 /* Now start processing the links (if any). */ 520 do { 521 flag = MDF_ATTR; 522 tp = find_tuple_in_list(last_tl, CIS_LONGLINK_A); 523 if (tp == 0) { 524 flag = 0; 525 tp = find_tuple_in_list(last_tl, CIS_LONGLINK_C); 526 } 527 if (tp && tp->length == 4) { 528 offs = tpl32(tp->data); 529#ifdef DEBUG 530 printf("Checking long link at %qd (%s memory)\n", 531 offs, flag ? "Attribute" : "Common"); 532#endif 533 /* If a link was found, read the tuple list from it. */ 534 if (ck_linktarget(fd, offs, flag)) { 535 tl = read_one_tuplelist(fd, flag, offs); 536 last_tl->next = tl; 537 last_tl = tl; 538 } 539 } else 540 tl = 0; 541 } while (tl); 542 543 /* 544 * If the primary list had no NOLINK tuple, and no LINKTARGET, 545 * then try to read a tuple list at common memory (offset 0). 546 */ 547 if (find_tuple_in_list(tlist, CIS_NOLINK) == 0 && tlist->next == 0 && 548 ck_linktarget(fd, (off_t) 0, 0)) { 549#ifdef DEBUG 550 printf("Reading long link at %qd (%s memory)\n", 551 offs, flag ? "Attribute" : "Common"); 552#endif 553 tlist->next = read_one_tuplelist(fd, 0, (off_t) 0); 554 } 555 return (tlist); 556} 557 558/* 559 * Read one tuple list from the card. 560 */ 561static struct tuple_list * 562read_one_tuplelist(int fd, int flags, off_t offs) 563{ 564 struct tuple *tp, *last_tp = 0; 565 struct tuple_list *tl; 566 struct tuple_info *tinfo; 567 int total = 0; 568 unsigned char code, length; 569 int fmvj182 = 0; 570#ifdef HSSYNTH 571 int hss = 0; 572#endif /* HSSYNTH */ 573 574 /* Check to see if this memory has already been scanned. */ 575 for (tl = tlist; tl; tl = tl->next) 576 if (tl->offs == offs && tl->flags == (flags & MDF_ATTR)) 577 return (0); 578 tl = xmalloc(sizeof(*tl)); 579 tl->offs = offs; 580 tl->flags = flags & MDF_ATTR; 581 ioctl(fd, PIOCRWFLAG, &flags); 582 lseek(fd, offs, SEEK_SET); 583 do { 584 if (read(fd, &code, 1) != 1) { 585 warn("CIS code read"); 586 break; 587 } 588 total++; 589 if (code == CIS_NULL) 590 continue; 591 tp = xmalloc(sizeof(*tp)); 592 tp->code = code; 593 if (code == CIS_END) 594 length = 0; 595 else { 596 if (read(fd, &length, 1) != 1) { 597 warn("CIS len read"); 598 break; 599 } 600 total++; 601 if (fmvj182 && (code == 0x1b) && (length == 25)) 602 length = 31; 603 } 604 tp->length = length; 605#ifdef DEBUG 606 printf("Tuple code = 0x%x, len = %d\n", code, length); 607#endif 608 if (length == 0xFF) { 609 length = tp->length = 0; 610 code = CIS_END; 611 } 612 if (length != 0) { 613 total += length; 614 tp->data = xmalloc(length); 615 if (read(fd, tp->data, length) != length) { 616 warn("CIS read"); 617 break; 618 } 619 } 620 621 /* 622 * Check the tuple, and ignore it if it isn't in the table 623 * or the length is illegal. 624 */ 625 tinfo = get_tuple_info(code); 626 if (tinfo != NULL && (tinfo->length != 255 && tinfo->length > length)) { 627 printf("code %s ignored\n", tuple_name(code)); 628 tp->code = CIS_NULL; 629 } 630 if (tl->tuples == NULL) 631 tl->tuples = tp; 632 else 633 last_tp->next = tp; 634 last_tp = tp; 635 } while (code != CIS_END && total < 1024); 636 return (tl); 637} 638 639/* 640 * return true if the offset points to a LINKTARGET tuple. 641 */ 642static int 643ck_linktarget(int fd, off_t offs, int flag) 644{ 645 char blk[5]; 646 647 ioctl(fd, PIOCRWFLAG, &flag); 648 lseek(fd, offs, SEEK_SET); 649 if (read(fd, blk, 5) != 5) 650 return (0); 651 if (blk[0] == 0x13 && 652 blk[1] == 0x3 && 653 blk[2] == 'C' && 654 blk[3] == 'I' && 655 blk[4] == 'S') 656 return (1); 657 return (0); 658} 659 660/* 661 * find_tuple_in_list - find a tuple within a 662 * single tuple list. 663 */ 664static struct tuple * 665find_tuple_in_list(struct tuple_list *tl, unsigned char code) 666{ 667 struct tuple *tp; 668 669 for (tp = tl->tuples; tp; tp = tp->next) 670 if (tp->code == code) 671 break; 672 return (tp); 673} 674 675/* 676 * return table entry for code. 677 */ 678static struct tuple_info * 679get_tuple_info(unsigned char code) 680{ 681 struct tuple_info *tp; 682 683 for (tp = tuple_info; tp->name; tp++) 684 if (tp->code == code) 685 return (tp); 686 return (0); 687} 688 689const char * 690tuple_name(unsigned char code) 691{ 692 struct tuple_info *tp; 693 694 tp = get_tuple_info(code); 695 if (tp) 696 return (tp->name); 697 return ("Unknown"); 698} 699