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