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