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