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