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