readcis.c revision 185122
1132720Skan/* 2132720Skan * Copyright (c) 1995 Andrew McRae. All rights reserved. 3169691Skan * 4132720Skan * Redistribution and use in source and binary forms, with or without 5132720Skan * modification, are permitted provided that the following conditions 6132720Skan * are met: 7132720Skan * 1. Redistributions of source code must retain the above copyright 8132720Skan * notice, this list of conditions and the following disclaimer. 9132720Skan * 2. Redistributions in binary form must reproduce the above copyright 10132720Skan * notice, this list of conditions and the following disclaimer in the 11132720Skan * documentation and/or other materials provided with the distribution. 12132720Skan * 3. The name of the author may not be used to endorse or promote products 13132720Skan * derived from this software without specific prior written permission. 14132720Skan * 15132720Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16132720Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17132720Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18132720Skan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19169691Skan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20132720Skan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21132720Skan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22132720Skan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23132720Skan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24132720Skan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25132720Skan */ 26132720Skan 27132720Skan#ifndef lint 28132720Skanstatic const char rcsid[] = 29132720Skan "$FreeBSD: head/usr.sbin/dumpcis/readcis.c 185122 2008-11-20 08:14:14Z imp $"; 30132720Skan#endif /* not lint */ 31169691Skan 32169691Skan/* 33169691Skan * Code cleanup, bug-fix and extension 34169691Skan * by Tatsumi Hosokawa <hosokawa@mt.cs.keio.ac.jp> 35132720Skan */ 36132720Skan 37132720Skan#include <err.h> 38132720Skan#include <stdio.h> 39132720Skan#include <stdlib.h> 40132720Skan#include <string.h> 41132720Skan#include <unistd.h> 42169691Skan 43132720Skan#include <pccard/cardinfo.h> 44169691Skan#include <pccard/cis.h> 45169691Skan 46132720Skan#include "readcis.h" 47132720Skan 48132720Skanstatic int ck_linktarget(int, off_t, int); 49132720Skanstatic struct tuple_list *read_one_tuplelist(int, int, off_t); 50132720Skanstatic struct tuple_list *read_tuples(int); 51132720Skanstatic struct tuple *find_tuple_in_list(struct tuple_list *, unsigned char); 52132720Skanstatic struct tuple_info *get_tuple_info(unsigned char); 53132720Skan 54132720Skanstatic struct tuple_info tuple_info[] = { 55132720Skan {"Null tuple", 0x00, 0}, 56132720Skan {"Common memory descriptor", 0x01, 255}, 57132720Skan {"Long link to next chain for CardBus", 0x02, 255}, 58132720Skan {"Indirect access", 0x03, 255}, 59132720Skan {"Configuration map for CardBus", 0x04, 255}, 60132720Skan {"Configuration entry for CardBus", 0x05, 255}, 61132720Skan {"Long link to next chain for MFC", 0x06, 255}, 62169691Skan {"Base address register for CardBus", 0x07, 6}, 63169691Skan {"Checksum", 0x10, 5}, 64132720Skan {"Long link to attribute memory", 0x11, 4}, 65132720Skan {"Long link to common memory", 0x12, 4}, 66132720Skan {"Link target", 0x13, 3}, 67132720Skan {"No link", 0x14, 0}, 68132720Skan {"Version 1 info", 0x15, 255}, 69132720Skan {"Alternate language string", 0x16, 255}, 70132720Skan {"Attribute memory descriptor", 0x17, 255}, 71132720Skan {"JEDEC descr for common memory", 0x18, 255}, 72169691Skan {"JEDEC descr for attribute memory", 0x19, 255}, 73169691Skan {"Configuration map", 0x1A, 255}, 74132720Skan {"Configuration entry", 0x1B, 255}, 75132720Skan {"Other conditions for common memory", 0x1C, 255}, 76132720Skan {"Other conditions for attribute memory", 0x1D, 255}, 77132720Skan {"Geometry info for common memory", 0x1E, 255}, 78132720Skan {"Geometry info for attribute memory", 0x1F, 255}, 79132720Skan {"Manufacturer ID", 0x20, 4}, 80132720Skan {"Functional ID", 0x21, 2}, 81132720Skan {"Functional EXT", 0x22, 255}, 82132720Skan {"Software interleave", 0x23, 2}, 83132720Skan {"Version 2 Info", 0x40, 255}, 84132720Skan {"Data format", 0x41, 255}, 85132720Skan {"Geometry", 0x42, 4}, 86132720Skan {"Byte order", 0x43, 2}, 87132720Skan {"Card init date", 0x44, 4}, 88132720Skan {"Battery replacement", 0x45, 4}, 89132720Skan {"Organization", 0x46, 255}, 90132720Skan {"Terminator", 0xFF, 0}, 91132720Skan {0, 0, 0} 92132720Skan}; 93132720Skan 94132720Skanstatic void * 95132720Skanxmalloc(int sz) 96132720Skan{ 97132720Skan void *p; 98132720Skan 99132720Skan sz = (sz + 7) & ~7; 100132720Skan p = malloc(sz); 101132720Skan if (p) 102132720Skan bzero(p, sz); 103132720Skan else 104132720Skan errx(1, "malloc"); 105132720Skan return (p); 106132720Skan} 107132720Skan 108132720Skan/* 109132720Skan * After reading the tuples, decode the relevant ones. 110132720Skan */ 111132720Skanstruct tuple_list * 112132720Skanreadcis(int fd) 113132720Skan{ 114132720Skan 115132720Skan return (read_tuples(fd)); 116132720Skan} 117132720Skan 118132720Skan/* 119132720Skan * free_cis - delete cis entry. 120132720Skan */ 121132720Skanvoid 122132720Skanfreecis(struct tuple_list *tlist) 123132720Skan{ 124132720Skan struct tuple_list *tl; 125132720Skan struct tuple *tp; 126132720Skan 127132720Skan while ((tl = tlist) != 0) { 128132720Skan tlist = tl->next; 129132720Skan while ((tp = tl->tuples) != 0) { 130132720Skan tl->tuples = tp->next; 131132720Skan free(tp->data); 132132720Skan free(tp); 133132720Skan } 134132720Skan free(tl); 135132720Skan } 136132720Skan} 137132720Skan 138132720Skan/* 139132720Skan * Parse variable length value. 140132720Skan */ 141132720Skanu_int 142132720Skanparse_num(int sz, u_char *p, u_char **q, int ofs) 143132720Skan{ 144132720Skan u_int num = 0; 145132720Skan 146132720Skan switch (sz) { 147132720Skan case 0: 148132720Skan case 0x10: 149132720Skan break; 150132720Skan case 1: 151132720Skan case 0x11: 152132720Skan num = (*p++) + ofs; 153132720Skan break; 154132720Skan case 2: 155132720Skan case 0x12: 156132720Skan num = tpl16(p) + ofs; 157132720Skan p += 2; 158132720Skan break; 159132720Skan case 0x13: 160132720Skan num = tpl24(p) + ofs; 161132720Skan p += 3; 162132720Skan break; 163132720Skan case 3: 164132720Skan case 0x14: 165132720Skan num = tpl32(p) + ofs; 166132720Skan p += 4; 167132720Skan break; 168132720Skan } 169132720Skan if (q) 170132720Skan *q = p; 171132720Skan return num; 172132720Skan} 173132720Skan 174132720Skan/* 175132720Skan * Read the tuples from the card. 176132720Skan * The processing of tuples is as follows: 177132720Skan * - Read tuples at attribute memory, offset 0. 178132720Skan * - If a CIS_END is the first tuple, look for 179132720Skan * a tuple list at common memory offset 0; this list 180132720Skan * must start with a LINKTARGET. 181132720Skan * - If a long link tuple was encountered, execute the long 182132720Skan * link. 183132720Skan * - If a no-link tuple was seen, terminate processing. 184132720Skan * - If no no-link tuple exists, and no long link tuple 185132720Skan * exists while processing the primary tuple list, 186132720Skan * then look for a LINKTARGET tuple in common memory. 187132720Skan * - If a long link tuple is found in any list, then process 188132720Skan * it. Only one link is allowed per list. 189132720Skan */ 190132720Skanstatic struct tuple_list *tlist; 191132720Skan 192132720Skanstatic struct tuple_list * 193132720Skanread_tuples(int fd) 194132720Skan{ 195132720Skan struct tuple_list *tl = 0, *last_tl; 196132720Skan struct tuple *tp; 197132720Skan int flag; 198132720Skan off_t offs; 199132720Skan 200132720Skan tlist = 0; 201132720Skan last_tl = tlist = read_one_tuplelist(fd, MDF_ATTR, (off_t) 0); 202132720Skan 203132720Skan /* Now start processing the links (if any). */ 204132720Skan do { 205132720Skan flag = MDF_ATTR; 206132720Skan tp = find_tuple_in_list(last_tl, CIS_LONGLINK_A); 207132720Skan if (tp == 0) { 208132720Skan flag = 0; 209132720Skan tp = find_tuple_in_list(last_tl, CIS_LONGLINK_C); 210132720Skan } 211132720Skan if (tp && tp->length == 4) { 212132720Skan offs = tpl32(tp->data); 213132720Skan#ifdef DEBUG 214132720Skan printf("Checking long link at %zd (%s memory)\n", 215132720Skan offs, flag ? "Attribute" : "Common"); 216132720Skan#endif 217132720Skan /* If a link was found, read the tuple list from it. */ 218132720Skan if (ck_linktarget(fd, offs, flag)) { 219132720Skan tl = read_one_tuplelist(fd, flag, offs); 220132720Skan last_tl->next = tl; 221132720Skan last_tl = tl; 222132720Skan } 223132720Skan } else 224132720Skan tl = 0; 225132720Skan } while (tl); 226132720Skan 227132720Skan /* 228132720Skan * If the primary list had no NOLINK tuple, and no LINKTARGET, 229132720Skan * then try to read a tuple list at common memory (offset 0). 230132720Skan */ 231132720Skan if (find_tuple_in_list(tlist, CIS_NOLINK) == 0 && tlist->next == 0 && 232132720Skan ck_linktarget(fd, (off_t) 0, 0)) { 233132720Skan offs = 0; 234132720Skan#ifdef DEBUG 235132720Skan printf("Reading long link at %zd (%s memory)\n", 236132720Skan offs, flag ? "Attribute" : "Common"); 237132720Skan#endif 238132720Skan tlist->next = read_one_tuplelist(fd, 0, offs); 239132720Skan } 240132720Skan return (tlist); 241132720Skan} 242132720Skan 243132720Skan/* 244132720Skan * Read one tuple list from the card. 245132720Skan */ 246132720Skanstatic struct tuple_list * 247132720Skanread_one_tuplelist(int fd, int flags, off_t offs) 248132720Skan{ 249132720Skan struct tuple *tp, *last_tp = 0; 250132720Skan struct tuple_list *tl; 251132720Skan struct tuple_info *tinfo; 252132720Skan int total = 0; 253132720Skan unsigned char code, length; 254132720Skan 255132720Skan /* Check to see if this memory has already been scanned. */ 256132720Skan for (tl = tlist; tl; tl = tl->next) 257132720Skan if (tl->offs == offs && tl->flags == (flags & MDF_ATTR)) 258132720Skan return (0); 259132720Skan tl = xmalloc(sizeof(*tl)); 260132720Skan tl->offs = offs; 261132720Skan tl->flags = flags & MDF_ATTR; 262132720Skan lseek(fd, offs, SEEK_SET); 263132720Skan do { 264132720Skan if (read(fd, &code, 1) != 1) { 265132720Skan warn("CIS code read"); 266132720Skan break; 267132720Skan } 268132720Skan total++; 269132720Skan if (code == CIS_NULL) 270132720Skan continue; 271132720Skan tp = xmalloc(sizeof(*tp)); 272132720Skan tp->code = code; 273132720Skan if (code == CIS_END) 274132720Skan length = 0; 275132720Skan else { 276132720Skan if (read(fd, &length, 1) != 1) { 277132720Skan warn("CIS len read"); 278132720Skan break; 279132720Skan } 280132720Skan total++; 281132720Skan } 282132720Skan tp->length = length; 283132720Skan#ifdef DEBUG 284132720Skan printf("Tuple code = 0x%x, len = %d\n", code, length); 285132720Skan#endif 286132720Skan if (length == 0xFF) { 287132720Skan length = tp->length = 0; 288132720Skan code = CIS_END; 289132720Skan } 290132720Skan if (length != 0) { 291132720Skan total += length; 292132720Skan tp->data = xmalloc(length); 293132720Skan if (read(fd, tp->data, length) != length) { 294132720Skan warn("CIS read"); 295132720Skan break; 296132720Skan } 297132720Skan } 298132720Skan 299132720Skan /* 300132720Skan * Check the tuple, and ignore it if it isn't in the table 301132720Skan * or the length is illegal. 302132720Skan */ 303132720Skan tinfo = get_tuple_info(code); 304132720Skan if (tinfo != NULL && (tinfo->length != 255 && tinfo->length > length)) { 305132720Skan printf("code %s (%d) ignored\n", tuple_name(code), code); 306132720Skan tp->code = CIS_NULL; 307132720Skan } 308132720Skan if (tl->tuples == NULL) 309132720Skan tl->tuples = tp; 310132720Skan else 311132720Skan last_tp->next = tp; 312132720Skan last_tp = tp; 313132720Skan } while (code != CIS_END && total < 1024); 314132720Skan return (tl); 315132720Skan} 316132720Skan 317132720Skan/* 318132720Skan * return true if the offset points to a LINKTARGET tuple. 319132720Skan */ 320132720Skanstatic int 321132720Skanck_linktarget(int fd, off_t offs, int flag) 322132720Skan{ 323132720Skan char blk[5]; 324132720Skan 325132720Skan ioctl(fd, PIOCRWFLAG, &flag); 326132720Skan lseek(fd, offs, SEEK_SET); 327132720Skan if (read(fd, blk, 5) != 5) 328132720Skan return (0); 329169691Skan if (blk[0] == 0x13 && 330169691Skan blk[1] == 0x3 && 331132720Skan blk[2] == 'C' && 332132720Skan blk[3] == 'I' && 333 blk[4] == 'S') 334 return (1); 335 return (0); 336} 337 338/* 339 * find_tuple_in_list - find a tuple within a 340 * single tuple list. 341 */ 342static struct tuple * 343find_tuple_in_list(struct tuple_list *tl, unsigned char code) 344{ 345 struct tuple *tp; 346 347 for (tp = tl->tuples; tp; tp = tp->next) 348 if (tp->code == code) 349 break; 350 return (tp); 351} 352 353/* 354 * return table entry for code. 355 */ 356static struct tuple_info * 357get_tuple_info(unsigned char code) 358{ 359 struct tuple_info *tp; 360 361 for (tp = tuple_info; tp->name; tp++) 362 if (tp->code == code) 363 return (tp); 364 return (0); 365} 366 367const char * 368tuple_name(unsigned char code) 369{ 370 struct tuple_info *tp; 371 372 tp = get_tuple_info(code); 373 if (tp) 374 return (tp->name); 375 return ("Unknown"); 376} 377