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