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