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