readcis.c revision 35310
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: readcis.c,v 1.12 1998/03/20 04:49:19 hosokawa Exp $"; 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/cardinfo.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->manuf = *cp->vers = *cp->add_info1 = *cp->add_info2 = '\0'; 174 cp->maj_v = *p++; 175 cp->min_v = *p++; 176 if (*p == 0xff) return; 177 strncpy(cp->manuf, p, CIS_MAXSTR - 1); 178 while (*p++); 179 if (*p == 0xff) return; 180 strncpy(cp->vers, p, CIS_MAXSTR - 1); 181 while (*p++); 182 if (*p == 0xff) return; 183 strncpy(cp->add_info1, p, CIS_MAXSTR - 1); 184 while (*p++); 185 if (*p == 0xff) return; 186 strncpy(cp->add_info2, p, CIS_MAXSTR - 1); 187} 188 189/* 190 * device_desc - decode device descriptor. 191 */ 192static void 193device_desc(unsigned char *p, int len, struct dev_mem *dp) 194{ 195 while (len > 0 && *p != 0xFF) { 196 dp->valid = 1; 197 dp->type = (*p & 0xF0) >> 4; 198 dp->wps = !!(*p & 0x8); 199 dp->speed = *p & 7; 200 p++; 201 if (*p != 0xFF) { 202 dp->addr = *p >> 3; 203 dp->units = *p & 7; 204 } 205 p++; 206 len -= 2; 207 } 208} 209 210/* 211 * configuration map of card control register. 212 */ 213static void 214config_map(struct cis *cp, unsigned char *p, int len) 215{ 216 unsigned char *p1; 217 int i; 218 union { 219 unsigned long l; 220 unsigned char b[4]; 221 } u; 222 223 p1 = p + 1; 224 cp->last_config = *p1++ & 0x3F; 225 u.l = 0; 226 for (i = 0; i <= (*p & 3); i++) 227 u.b[i] = *p1++; 228 cp->reg_addr = u.l; 229 cp->ccrs = *p1; 230} 231 232/* 233 * CIS config entry - Decode and build configuration entry. 234 */ 235static void 236cis_config(struct cis *cp, unsigned char *p, int len) 237{ 238 int x; 239 int i, j; 240 union { 241 unsigned long l; 242 unsigned char b[4]; 243 } u; 244 struct cis_config *conf, *last; 245 struct cis_memblk *mem; 246 unsigned char feat; 247 struct cis_memblk *lastmem = 0; 248 249 conf = xmalloc(sizeof(*conf)); 250 if ((last = cp->conf) != 0) { 251 while (last->next) 252 last = last->next; 253 last->next = conf; 254 } else 255 cp->conf = conf; 256 conf->id = *p & 0x3F; 257 if (*p & 0x40) 258 cp->def_config = conf; 259 if (*p++ & 0x80) 260 p++; 261 feat = *p++; 262 for (i = 0; i < CIS_FEAT_POWER(feat); i++) { 263 unsigned char parms = *p++; 264 265 conf->pwr = 1; 266 for (j = 0; j < 8; j++) 267 if (parms & (1 << j)) 268 while (*p++ & 0x80); 269 } 270 if (feat & CIS_FEAT_TIMING) { 271 conf->timing = 1; 272 i = *p++; 273 if (CIS_WAIT_SCALE(i) != 3) 274 p++; 275 if (CIS_READY_SCALE(i) != 7) 276 p++; 277 if (CIS_RESERVED_SCALE(i) != 7) 278 p++; 279 } 280 if (feat & CIS_FEAT_I_O) { 281 conf->iospace = 1; 282 if (CIS_IO_RANGE & *p) 283 conf->io_blks = CIS_IO_BLKS(p[1]) + 1; 284 conf->io_addr = CIS_IO_ADDR(*p); 285 conf->io_bus = (*p >> 5) & 3; 286 if (*p++ & CIS_IO_RANGE) { 287 struct cis_ioblk *io, *last = 0; 288 i = CIS_IO_ADSZ(*p); 289 j = CIS_IO_BLKSZ(*p++); 290 for (x = 0; x < conf->io_blks; x++) { 291 io = xmalloc(sizeof(*io)); 292 if (last) 293 last->next = io; 294 else 295 conf->io = io; 296 last = io; 297 u.l = 0; 298 switch (i) { 299 case 0: 300 break; 301 case 1: 302 u.b[0] = *p++; 303 break; 304 case 2: 305 u.b[0] = *p++; 306 u.b[1] = *p++; 307 break; 308 case 3: 309 u.b[0] = *p++; 310 u.b[1] = *p++; 311 u.b[2] = *p++; 312 u.b[3] = *p++; 313 break; 314 } 315 io->addr = u.l; 316 u.l = 0; 317 switch (j) { 318 case 0: 319 break; 320 case 1: 321 u.b[0] = *p++; 322 u.l++; 323 break; 324 case 2: 325 u.b[0] = *p++; 326 u.b[1] = *p++; 327 u.l++; 328 break; 329 case 3: 330 u.b[0] = *p++; 331 u.b[1] = *p++; 332 u.b[2] = *p++; 333 u.b[3] = *p++; 334 u.l++; 335 break; 336 } 337 io->size = u.l; 338 } 339 } 340 } 341 if (feat & CIS_FEAT_IRQ) { 342 conf->irq = 1; 343 conf->irqlevel = *p & 0xF; 344 conf->irq_flags = *p & 0xF0; 345 if (*p++ & CIS_IRQ_MASK) { 346 conf->irq_mask = (p[1] << 8) | p[0]; 347 p += 2; 348 } 349 } 350 switch (CIS_FEAT_MEMORY(feat)) { 351 case 0: 352 break; 353 case 1: 354 conf->memspace = 1; 355 conf->mem = xmalloc(sizeof(*conf->mem)); 356 conf->mem->length = ((p[1] << 8) | p[0]) << 8; 357 break; 358 case 2: 359 conf->memspace = 1; 360 conf->mem = xmalloc(sizeof(*conf->mem)); 361 conf->mem->length = ((p[1] << 8) | p[0]) << 8; 362 conf->mem->address = ((p[3] << 8) | p[2]) << 8; 363 break; 364 case 3: 365 conf->memspace = 1; 366 x = *p++; 367 conf->memwins = CIS_MEM_WINS(x); 368 for (i = 0; i < conf->memwins; i++) { 369 mem = xmalloc(sizeof(*mem)); 370 if (i == 0) 371 conf->mem = mem; 372 else 373 lastmem->next = mem; 374 lastmem = mem; 375 u.l = 0; 376 for (j = 0; j < CIS_MEM_LENSZ(x); j++) 377 u.b[j] = *p++; 378 mem->length = u.l << 8; 379 u.l = 0; 380 for (j = 0; j < CIS_MEM_ADDRSZ(x); j++) 381 u.b[j] = *p++; 382 mem->address = u.l << 8; 383 if (x & CIS_MEM_HOST) { 384 u.l = 0; 385 for (j = 0; j < CIS_MEM_ADDRSZ(x); j++) 386 u.b[j] = *p++; 387 mem->host_address = u.l << 8; 388 } 389 } 390 break; 391 } 392 if (feat & 0x80) { 393 conf->misc_valid = 1; 394 conf->misc = *p++; 395 } 396} 397 398/* 399 * Read the tuples from the card. 400 * The processing of tuples is as follows: 401 * - Read tuples at attribute memory, offset 0. 402 * - If a CIS_END is the first tuple, look for 403 * a tuple list at common memory offset 0; this list 404 * must start with a LINKTARGET. 405 * - If a long link tuple was encountered, execute the long 406 * link. 407 * - If a no-link tuple was seen, terminate processing. 408 * - If no no-link tuple exists, and no long link tuple 409 * exists while processing the primary tuple list, 410 * then look for a LINKTARGET tuple in common memory. 411 * - If a long link tuple is found in any list, then process 412 * it. Only one link is allowed per list. 413 */ 414static struct tuple_list *tlist; 415 416static struct tuple_list * 417read_tuples(int fd) 418{ 419 struct tuple_list *tl = 0, *last_tl; 420 struct tuple *tp; 421 int flag; 422 off_t offs; 423 424 tlist = 0; 425 last_tl = tlist = read_one_tuplelist(fd, MDF_ATTR, (off_t) 0); 426 427 /* Now start processing the links (if any). */ 428 do { 429 flag = MDF_ATTR; 430 tp = find_tuple_in_list(last_tl, CIS_LONGLINK_A); 431 if (tp == 0) { 432 flag = 0; 433 tp = find_tuple_in_list(last_tl, CIS_LONGLINK_C); 434 } 435 if (tp && tp->length == 4) { 436 offs = tp->data[0] | 437 (tp->data[1] << 8) | 438 (tp->data[2] << 16) | 439 (tp->data[3] << 24); 440#ifdef DEBUG 441 printf("Checking long link at %ld (%s memory)\n", 442 offs, flag ? "Attribute" : "Common"); 443#endif 444 /* If a link was found, read the tuple list from it. */ 445 if (ck_linktarget(fd, offs, flag)) { 446 tl = read_one_tuplelist(fd, flag, offs); 447 last_tl->next = tl; 448 last_tl = tl; 449 } 450 } else 451 tl = 0; 452 } while (tl); 453 454 /* 455 * If the primary list had no NOLINK tuple, and no LINKTARGET, 456 * then try to read a tuple list at common memory (offset 0). 457 */ 458 if (find_tuple_in_list(tlist, CIS_NOLINK) == 0 && tlist->next == 0 && 459 ck_linktarget(fd, (off_t) 0, 0)) { 460#ifdef DEBUG 461 printf("Reading long link at %ld (%s memory)\n", 462 offs, flag ? "Attribute" : "Common"); 463#endif 464 tlist->next = read_one_tuplelist(fd, 0, (off_t) 0); 465 } 466 return (tlist); 467} 468 469/* 470 * Read one tuple list from the card. 471 */ 472static struct tuple_list * 473read_one_tuplelist(int fd, int flags, off_t offs) 474{ 475 struct tuple *tp, *last_tp = 0; 476 struct tuple_list *tl; 477 struct tuple_info *tinfo; 478 int total = 0; 479 unsigned char code, length; 480 481 /* Check to see if this memory has already been scanned. */ 482 for (tl = tlist; tl; tl = tl->next) 483 if (tl->offs == offs && tl->flags == (flags & MDF_ATTR)) 484 return (0); 485 tl = xmalloc(sizeof(*tl)); 486 tl->offs = offs; 487 tl->flags = flags & MDF_ATTR; 488 ioctl(fd, PIOCRWFLAG, &flags); 489 lseek(fd, offs, SEEK_SET); 490 do { 491 if (read_attr(fd, &code, 1) != 1) { 492 warn("CIS code read"); 493 break; 494 } 495 total++; 496 if (code == CIS_NULL) 497 continue; 498 tp = xmalloc(sizeof(*tp)); 499 tp->code = code; 500 if (read_attr(fd, &length, 1) != 1) { 501 warn("CIS len read"); 502 break; 503 } 504 total++; 505 tp->length = length; 506#ifdef DEBUG 507 printf("Tuple code = 0x%x, len = %d\n", code, length); 508#endif 509 if (length == 0xFF) { 510 length = tp->length = 0; 511 code = CIS_END; 512 } 513 if (length != 0) { 514 total += length; 515 tp->data = xmalloc(length); 516 if (read_attr(fd, tp->data, length) != length) { 517 warn("CIS read"); 518 break; 519 } 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 printf("code %s ignored\n", tuple_name(code)); 529 tp->code = CIS_NULL; 530 } 531 if (tl->tuples == 0) 532 tl->tuples = tp; 533 else 534 last_tp->next = tp; 535 last_tp = tp; 536 } while (code != CIS_END && total < 1024); 537 return (tl); 538} 539 540/* 541 * return true if the offset points to a LINKTARGET tuple. 542 */ 543static int 544ck_linktarget(int fd, off_t offs, int flag) 545{ 546 char 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/* 562 * find_tuple_in_list - find a tuple within a 563 * single tuple list. 564 */ 565static struct tuple * 566find_tuple_in_list(struct tuple_list *tl, unsigned char code) 567{ 568 struct tuple *tp; 569 570 for (tp = tl->tuples; tp; tp = tp->next) 571 if (tp->code == code) 572 break; 573 return (tp); 574} 575 576static int 577read_attr(int fd, char *bp, int len) 578{ 579 char blk[1024], *p = blk; 580 int i, l; 581 582 if (len > sizeof(blk) / 2) 583 len = sizeof(blk) / 2; 584 l = i = read(fd, blk, len * 2); 585 if (i <= 0) { 586 printf("Read return %d bytes (expected %d)\n", i, len * 2); 587 return (i); 588 } 589 while (i > 0) { 590 *bp++ = *p++; 591 p++; 592 i -= 2; 593 } 594 return (l / 2); 595} 596 597/* 598 * return table entry for code. 599 */ 600static struct tuple_info * 601get_tuple_info(unsigned char code) 602{ 603 struct tuple_info *tp; 604 605 for (tp = tuple_info; tp->name; tp++) 606 if (tp->code == code) 607 return (tp); 608 printf("Code %d not found\n", code); 609 return (0); 610} 611 612char * 613tuple_name(unsigned char code) 614{ 615 struct tuple_info *tp; 616 617 tp = get_tuple_info(code); 618 if (tp) 619 return (tp->name); 620 return ("Unknown"); 621} 622