115177Snate/* 215284Snate * Copyright (c) 1995 Andrew McRae. All rights reserved. 315284Snate * 415284Snate * Redistribution and use in source and binary forms, with or without 515284Snate * modification, are permitted provided that the following conditions 615284Snate * are met: 715284Snate * 1. Redistributions of source code must retain the above copyright 815284Snate * notice, this list of conditions and the following disclaimer. 915284Snate * 2. Redistributions in binary form must reproduce the above copyright 1015284Snate * notice, this list of conditions and the following disclaimer in the 1115284Snate * documentation and/or other materials provided with the distribution. 1215284Snate * 3. The name of the author may not be used to endorse or promote products 1315284Snate * derived from this software without specific prior written permission. 1415284Snate * 1515284Snate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1615284Snate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1715284Snate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1815284Snate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1915284Snate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2015284Snate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2115284Snate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2215284Snate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2315284Snate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2415284Snate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2510217Sphk */ 2630171Scharnier 2730171Scharnier#ifndef lint 2830171Scharnierstatic const char rcsid[] = 2950479Speter "$FreeBSD$"; 3030171Scharnier#endif /* not lint */ 3130171Scharnier 3259656Siwasaki/* 3359656Siwasaki * Code cleanup, bug-fix and extension 3459656Siwasaki * by Tatsumi Hosokawa <hosokawa@mt.cs.keio.ac.jp> 3559656Siwasaki */ 3659656Siwasaki 3730171Scharnier#include <err.h> 3810217Sphk#include <stdio.h> 3910217Sphk#include <stdlib.h> 4010217Sphk#include <string.h> 4130171Scharnier#include <unistd.h> 4210217Sphk 43188633Simp#include "cardinfo.h" 44188633Simp#include "cis.h" 4510217Sphk#include "readcis.h" 4610217Sphk 4716487Snatestatic int ck_linktarget(int, off_t, int); 4816487Snatestatic struct tuple_list *read_one_tuplelist(int, int, off_t); 4916487Snatestatic struct tuple_list *read_tuples(int); 5016487Snatestatic struct tuple *find_tuple_in_list(struct tuple_list *, unsigned char); 5116487Snatestatic struct tuple_info *get_tuple_info(unsigned char); 5210217Sphk 5316487Snatestatic struct tuple_info tuple_info[] = { 54185124Simp {"Null tuple", CIS_NULL, 0}, 55185124Simp {"Common memory descriptor", CIS_MEM_COMMON, 255}, 56185124Simp {"Long link to next chain for CardBus", CIS_LONGLINK_CB, 255}, 57185124Simp {"Indirect access", CIS_INDIRECT, 255}, 58185124Simp {"Configuration map for CardBus", CIS_CONF_MAP_CB, 255}, 59185124Simp {"Configuration entry for CardBus", CIS_CONFIG_CB, 255}, 60185124Simp {"Long link to next chain for MFC", CIS_LONGLINK_MFC, 255}, 61185124Simp {"Base address register for CardBus", CIS_BAR, 6}, 62185124Simp {"Checksum", CIS_CHECKSUM, 5}, 63185124Simp {"Long link to attribute memory", CIS_LONGLINK_A, 4}, 64185124Simp {"Long link to common memory", CIS_LONGLINK_C, 4}, 65185124Simp {"Link target", CIS_LINKTARGET, 3}, 66185124Simp {"No link", CIS_NOLINK, 0}, 67185124Simp {"Version 1 info", CIS_INFO_V1, 255}, 68185124Simp {"Alternate language string", CIS_ALTSTR, 255}, 69185124Simp {"Attribute memory descriptor", CIS_MEM_ATTR, 255}, 70185124Simp {"JEDEC descr for common memory", CIS_JEDEC_C, 255}, 71185124Simp {"JEDEC descr for attribute memory", CIS_JEDEC_A, 255}, 72185124Simp {"Configuration map", CIS_CONF_MAP, 255}, 73185124Simp {"Configuration entry", CIS_CONFIG, 255}, 74185124Simp {"Other conditions for common memory", CIS_DEVICE_OC, 255}, 75185124Simp {"Other conditions for attribute memory", CIS_DEVICE_OA, 255}, 76185124Simp {"Geometry info for common memory", CIS_DEVICEGEO, 255}, 77185124Simp {"Geometry info for attribute memory", CIS_DEVICEGEO_A, 255}, 78185124Simp {"Manufacturer ID", CIS_MANUF_ID, 4}, 79185124Simp {"Functional ID", CIS_FUNC_ID, 2}, 80185124Simp {"Functional EXT", CIS_FUNC_EXT, 255}, 81185124Simp {"Software interleave", CIS_SW_INTERLV, 2}, 82185124Simp {"Version 2 Info", CIS_VERS_2, 255}, 83185124Simp {"Data format", CIS_FORMAT, 255}, 84185124Simp {"Geometry", CIS_GEOMETRY, 4}, 85185124Simp {"Byte order", CIS_BYTEORDER, 2}, 86185124Simp {"Card init date", CIS_DATE, 4}, 87185124Simp {"Battery replacement", CIS_BATTERY, 4}, 88185124Simp {"Organization", CIS_ORG, 255}, 89185124Simp {"Terminator", CIS_END, 0}, 9015177Snate {0, 0, 0} 9115177Snate}; 9210217Sphk 93185033Simpstatic void * 94185033Simpxmalloc(int sz) 95185033Simp{ 96185033Simp void *p; 97185033Simp 98185033Simp sz = (sz + 7) & ~7; 99185033Simp p = malloc(sz); 100185033Simp if (p) 101185033Simp bzero(p, sz); 102185033Simp else 103185033Simp errx(1, "malloc"); 104185033Simp return (p); 105185033Simp} 106185033Simp 10710217Sphk/* 10810217Sphk * After reading the tuples, decode the relevant ones. 10910217Sphk */ 110185121Simpstruct tuple_list * 11110217Sphkreadcis(int fd) 11210217Sphk{ 11310217Sphk 114185121Simp return (read_tuples(fd)); 11510217Sphk} 11615177Snate 11710217Sphk/* 11810217Sphk * free_cis - delete cis entry. 11910217Sphk */ 12010217Sphkvoid 121185121Simpfreecis(struct tuple_list *tlist) 12210217Sphk{ 123185121Simp struct tuple_list *tl; 12415177Snate struct tuple *tp; 12510217Sphk 126185121Simp while ((tl = tlist) != 0) { 127185121Simp tlist = tl->next; 12815177Snate while ((tp = tl->tuples) != 0) { 12910217Sphk tl->tuples = tp->next; 130185121Simp free(tp->data); 131185121Simp free(tp); 13210217Sphk } 133185121Simp free(tl); 13415177Snate } 13510217Sphk} 13615177Snate 13710217Sphk/* 13859656Siwasaki * Parse variable length value. 13959656Siwasaki */ 14059656Siwasakiu_int 14159656Siwasakiparse_num(int sz, u_char *p, u_char **q, int ofs) 14259656Siwasaki{ 14359656Siwasaki u_int num = 0; 14459656Siwasaki 14559656Siwasaki switch (sz) { 14659656Siwasaki case 0: 14759656Siwasaki case 0x10: 14859656Siwasaki break; 14959656Siwasaki case 1: 15059656Siwasaki case 0x11: 15159656Siwasaki num = (*p++) + ofs; 15259656Siwasaki break; 15359656Siwasaki case 2: 15459656Siwasaki case 0x12: 15559656Siwasaki num = tpl16(p) + ofs; 15659656Siwasaki p += 2; 15759656Siwasaki break; 15859656Siwasaki case 0x13: 15959656Siwasaki num = tpl24(p) + ofs; 16059656Siwasaki p += 3; 16159656Siwasaki break; 16259656Siwasaki case 3: 16359656Siwasaki case 0x14: 16459656Siwasaki num = tpl32(p) + ofs; 16559656Siwasaki p += 4; 16659656Siwasaki break; 16759656Siwasaki } 16859656Siwasaki if (q) 16959656Siwasaki *q = p; 17059656Siwasaki return num; 17159656Siwasaki} 17259656Siwasaki 17359656Siwasaki/* 17410217Sphk * Read the tuples from the card. 17510217Sphk * The processing of tuples is as follows: 17610217Sphk * - Read tuples at attribute memory, offset 0. 17710217Sphk * - If a CIS_END is the first tuple, look for 17810217Sphk * a tuple list at common memory offset 0; this list 17910217Sphk * must start with a LINKTARGET. 18010217Sphk * - If a long link tuple was encountered, execute the long 18110217Sphk * link. 18210217Sphk * - If a no-link tuple was seen, terminate processing. 18310217Sphk * - If no no-link tuple exists, and no long link tuple 18410217Sphk * exists while processing the primary tuple list, 18510217Sphk * then look for a LINKTARGET tuple in common memory. 18610217Sphk * - If a long link tuple is found in any list, then process 18710217Sphk * it. Only one link is allowed per list. 18810217Sphk */ 18910217Sphkstatic struct tuple_list *tlist; 19010217Sphk 19116487Snatestatic struct tuple_list * 19210217Sphkread_tuples(int fd) 19310217Sphk{ 19415177Snate struct tuple_list *tl = 0, *last_tl; 19515177Snate struct tuple *tp; 19615177Snate int flag; 19715177Snate off_t offs; 19810217Sphk 19910217Sphk tlist = 0; 20015177Snate last_tl = tlist = read_one_tuplelist(fd, MDF_ATTR, (off_t) 0); 20115177Snate 20215177Snate /* Now start processing the links (if any). */ 20315177Snate do { 20410217Sphk flag = MDF_ATTR; 20510217Sphk tp = find_tuple_in_list(last_tl, CIS_LONGLINK_A); 20615177Snate if (tp == 0) { 20710217Sphk flag = 0; 20810217Sphk tp = find_tuple_in_list(last_tl, CIS_LONGLINK_C); 20915177Snate } 21015177Snate if (tp && tp->length == 4) { 21159656Siwasaki offs = tpl32(tp->data); 21210217Sphk#ifdef DEBUG 213185121Simp printf("Checking long link at %zd (%s memory)\n", 21415177Snate offs, flag ? "Attribute" : "Common"); 21510217Sphk#endif 21615177Snate /* If a link was found, read the tuple list from it. */ 21715177Snate if (ck_linktarget(fd, offs, flag)) { 21810217Sphk tl = read_one_tuplelist(fd, flag, offs); 21910217Sphk last_tl->next = tl; 22010217Sphk last_tl = tl; 22110217Sphk } 22235310Snate } else 22335310Snate tl = 0; 22415177Snate } while (tl); 22515177Snate 22615177Snate /* 22715177Snate * If the primary list had no NOLINK tuple, and no LINKTARGET, 22815177Snate * then try to read a tuple list at common memory (offset 0). 22915177Snate */ 230185124Simp if (find_tuple_in_list(tlist, CIS_NOLINK) == 0 && 231185124Simp find_tuple_in_list(tlist, CIS_LINKTARGET) == 0 && 23215177Snate ck_linktarget(fd, (off_t) 0, 0)) { 233185121Simp offs = 0; 23410217Sphk#ifdef DEBUG 235185121Simp printf("Reading long link at %zd (%s memory)\n", 23615177Snate offs, flag ? "Attribute" : "Common"); 23710217Sphk#endif 238185121Simp tlist->next = read_one_tuplelist(fd, 0, offs); 23915177Snate } 24015177Snate return (tlist); 24110217Sphk} 24215177Snate 24310217Sphk/* 24410217Sphk * Read one tuple list from the card. 24510217Sphk */ 24616487Snatestatic struct tuple_list * 24710217Sphkread_one_tuplelist(int fd, int flags, off_t offs) 24810217Sphk{ 24915177Snate struct tuple *tp, *last_tp = 0; 25015177Snate struct tuple_list *tl; 25115177Snate struct tuple_info *tinfo; 25215177Snate int total = 0; 25315177Snate unsigned char code, length; 25410217Sphk 25515177Snate /* Check to see if this memory has already been scanned. */ 25610217Sphk for (tl = tlist; tl; tl = tl->next) 25710217Sphk if (tl->offs == offs && tl->flags == (flags & MDF_ATTR)) 25815177Snate return (0); 25910217Sphk tl = xmalloc(sizeof(*tl)); 26010217Sphk tl->offs = offs; 26110217Sphk tl->flags = flags & MDF_ATTR; 262185123Simp ioctl(fd, PIOCRWFLAG, &flags); 26310217Sphk lseek(fd, offs, SEEK_SET); 26415177Snate do { 265185033Simp if (read(fd, &code, 1) != 1) { 26630171Scharnier warn("CIS code read"); 26710217Sphk break; 26815177Snate } 26910217Sphk total++; 27010217Sphk if (code == CIS_NULL) 27110217Sphk continue; 27210217Sphk tp = xmalloc(sizeof(*tp)); 27310217Sphk tp->code = code; 27459656Siwasaki if (code == CIS_END) 27559656Siwasaki length = 0; 27659656Siwasaki else { 277185033Simp if (read(fd, &length, 1) != 1) { 27859656Siwasaki warn("CIS len read"); 27959656Siwasaki break; 28059656Siwasaki } 28159656Siwasaki total++; 28215177Snate } 28310217Sphk tp->length = length; 28410217Sphk#ifdef DEBUG 28521371Snate printf("Tuple code = 0x%x, len = %d\n", code, length); 28610217Sphk#endif 28715177Snate if (length == 0xFF) { 28810217Sphk length = tp->length = 0; 28910217Sphk code = CIS_END; 29015177Snate } 29115177Snate if (length != 0) { 29210217Sphk total += length; 29310217Sphk tp->data = xmalloc(length); 294185033Simp if (read(fd, tp->data, length) != length) { 29530171Scharnier warn("CIS read"); 29610217Sphk break; 29710217Sphk } 29815177Snate } 29915177Snate 30015177Snate /* 30115177Snate * Check the tuple, and ignore it if it isn't in the table 30215177Snate * or the length is illegal. 30315177Snate */ 30410217Sphk tinfo = get_tuple_info(code); 305112233Simp if (tinfo != NULL && (tinfo->length != 255 && tinfo->length > length)) { 306185121Simp printf("code %s (%d) ignored\n", tuple_name(code), code); 30710217Sphk tp->code = CIS_NULL; 30815177Snate } 30959656Siwasaki if (tl->tuples == NULL) 31010217Sphk tl->tuples = tp; 31110217Sphk else 31210217Sphk last_tp->next = tp; 31310217Sphk last_tp = tp; 31415177Snate } while (code != CIS_END && total < 1024); 31515177Snate return (tl); 31610217Sphk} 31715177Snate 31810217Sphk/* 31910217Sphk * return true if the offset points to a LINKTARGET tuple. 32010217Sphk */ 32116487Snatestatic int 32210217Sphkck_linktarget(int fd, off_t offs, int flag) 32310217Sphk{ 32415177Snate char blk[5]; 32510217Sphk 32610217Sphk ioctl(fd, PIOCRWFLAG, &flag); 32710217Sphk lseek(fd, offs, SEEK_SET); 328185033Simp if (read(fd, blk, 5) != 5) 32915177Snate return (0); 330185124Simp if (blk[0] == CIS_LINKTARGET && 33110217Sphk blk[1] == 0x3 && 33210217Sphk blk[2] == 'C' && 33310217Sphk blk[3] == 'I' && 33410217Sphk blk[4] == 'S') 33515177Snate return (1); 33615177Snate return (0); 33710217Sphk} 33815177Snate 33910217Sphk/* 34010217Sphk * find_tuple_in_list - find a tuple within a 34110217Sphk * single tuple list. 34210217Sphk */ 34316487Snatestatic struct tuple * 34410217Sphkfind_tuple_in_list(struct tuple_list *tl, unsigned char code) 34510217Sphk{ 34615177Snate struct tuple *tp; 34710217Sphk 34810217Sphk for (tp = tl->tuples; tp; tp = tp->next) 34910217Sphk if (tp->code == code) 35010217Sphk break; 35115177Snate return (tp); 35210217Sphk} 35315177Snate 35410217Sphk/* 35510217Sphk * return table entry for code. 35610217Sphk */ 35716487Snatestatic struct tuple_info * 35810217Sphkget_tuple_info(unsigned char code) 35910217Sphk{ 36015177Snate struct tuple_info *tp; 36110217Sphk 36210217Sphk for (tp = tuple_info; tp->name; tp++) 36310217Sphk if (tp->code == code) 36415177Snate return (tp); 36515177Snate return (0); 36610217Sphk} 36715177Snate 368185033Simpconst char * 36910217Sphktuple_name(unsigned char code) 37010217Sphk{ 37115177Snate struct tuple_info *tp; 37210217Sphk 37310217Sphk tp = get_tuple_info(code); 37410217Sphk if (tp) 37515177Snate return (tp->name); 37615177Snate return ("Unknown"); 37710217Sphk} 378