readcis.c revision 185033
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: head/usr.sbin/dumpcis/readcis.c 185033 2008-11-17 22:46:29Z imp $"; 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#include <sys/ioctl.h> 4310217Sphk 4431290Snate#include <pccard/cardinfo.h> 4510217Sphk#include <pccard/cis.h> 4610217Sphk 4710217Sphk#include "readcis.h" 4810217Sphk 4916487Snatestatic int ck_linktarget(int, off_t, int); 5016487Snatestatic void cis_info(struct cis *, unsigned char *, int); 5116487Snatestatic void device_desc(unsigned char *, int, struct dev_mem *); 5216487Snatestatic void config_map(struct cis *, unsigned char *, int); 5316487Snatestatic void cis_config(struct cis *, unsigned char *, int); 5490968Sshibastatic void cis_manuf_id(struct cis *, unsigned char *, int); 5559053Siwasakistatic void cis_func_id(struct cis *, unsigned char *, int); 5659656Siwasakistatic void cis_network_ext(struct cis *, unsigned char *, int); 5716487Snatestatic struct tuple_list *read_one_tuplelist(int, int, off_t); 5816487Snatestatic struct tuple_list *read_tuples(int); 5916487Snatestatic struct tuple *find_tuple_in_list(struct tuple_list *, unsigned char); 6016487Snatestatic struct tuple_info *get_tuple_info(unsigned char); 6110217Sphk 6216487Snatestatic struct tuple_info tuple_info[] = { 6315177Snate {"Null tuple", 0x00, 0}, 6415177Snate {"Common memory descriptor", 0x01, 255}, 6559656Siwasaki {"Long link to next chain for CardBus", 0x02, 255}, 6659656Siwasaki {"Indirect access", 0x03, 255}, 6759656Siwasaki {"Configuration map for CardBus", 0x04, 255}, 6859656Siwasaki {"Configuration entry for CardBus", 0x05, 255}, 6959656Siwasaki {"Long link to next chain for MFC", 0x06, 255}, 7059656Siwasaki {"Base address register for CardBus", 0x07, 6}, 7115177Snate {"Checksum", 0x10, 5}, 7215177Snate {"Long link to attribute memory", 0x11, 4}, 7315177Snate {"Long link to common memory", 0x12, 4}, 7415177Snate {"Link target", 0x13, 3}, 7515177Snate {"No link", 0x14, 0}, 7615177Snate {"Version 1 info", 0x15, 255}, 7715177Snate {"Alternate language string", 0x16, 255}, 7815177Snate {"Attribute memory descriptor", 0x17, 255}, 7915177Snate {"JEDEC descr for common memory", 0x18, 255}, 8015177Snate {"JEDEC descr for attribute memory", 0x19, 255}, 8115177Snate {"Configuration map", 0x1A, 255}, 8215177Snate {"Configuration entry", 0x1B, 255}, 8315177Snate {"Other conditions for common memory", 0x1C, 255}, 8415177Snate {"Other conditions for attribute memory", 0x1D, 255}, 8515177Snate {"Geometry info for common memory", 0x1E, 255}, 8615177Snate {"Geometry info for attribute memory", 0x1F, 255}, 8715177Snate {"Manufacturer ID", 0x20, 4}, 8859656Siwasaki {"Functional ID", 0x21, 2}, 8915177Snate {"Functional EXT", 0x22, 255}, 9015177Snate {"Software interleave", 0x23, 2}, 9115177Snate {"Version 2 Info", 0x40, 255}, 9215177Snate {"Data format", 0x41, 255}, 9315177Snate {"Geometry", 0x42, 4}, 9415177Snate {"Byte order", 0x43, 2}, 9515177Snate {"Card init date", 0x44, 4}, 9615177Snate {"Battery replacement", 0x45, 4}, 9759656Siwasaki {"Organization", 0x46, 255}, 9859656Siwasaki {"Terminator", 0xFF, 0}, 9915177Snate {0, 0, 0} 10015177Snate}; 10110217Sphk 102185033Simp 103185033Simpstatic void * 104185033Simpxmalloc(int sz) 105185033Simp{ 106185033Simp void *p; 107185033Simp 108185033Simp sz = (sz + 7) & ~7; 109185033Simp p = malloc(sz); 110185033Simp if (p) 111185033Simp bzero(p, sz); 112185033Simp else 113185033Simp errx(1, "malloc"); 114185033Simp return (p); 115185033Simp} 116185033Simp 11710217Sphk/* 11810217Sphk * After reading the tuples, decode the relevant ones. 11910217Sphk */ 12010217Sphkstruct cis * 12110217Sphkreadcis(int fd) 12210217Sphk{ 12315177Snate struct tuple_list *tl; 12415177Snate struct tuple *tp; 12515177Snate struct cis *cp; 12610217Sphk 12710217Sphk cp = xmalloc(sizeof(*cp)); 12810217Sphk cp->tlist = read_tuples(fd); 12910217Sphk if (cp->tlist == 0) 13015177Snate return (NULL); 13110217Sphk 13210217Sphk for (tl = cp->tlist; tl; tl = tl->next) 13315177Snate for (tp = tl->tuples; tp; tp = tp->next) { 13461804Sroberto#if 0 13515177Snate printf("tuple code = 0x%02x, data is\n", tp->code); 13615177Snate dump(tp->data, tp->length); 13710217Sphk#endif 13815177Snate switch (tp->code) { 13915177Snate case CIS_MEM_COMMON: /* 0x01 */ 14015177Snate device_desc(tp->data, tp->length, &cp->common_mem); 14115177Snate break; 14215177Snate case CIS_INFO_V1: /* 0x15 */ 14315177Snate cis_info(cp, tp->data, tp->length); 14415177Snate break; 14515177Snate case CIS_MEM_ATTR: /* 0x17 */ 14615177Snate device_desc(tp->data, tp->length, &cp->attr_mem); 14715177Snate break; 14815177Snate case CIS_CONF_MAP: /* 0x1A */ 14915177Snate config_map(cp, tp->data, tp->length); 15015177Snate break; 15115177Snate case CIS_CONFIG: /* 0x1B */ 15215177Snate cis_config(cp, tp->data, tp->length); 15315177Snate break; 15490968Sshiba case CIS_MANUF_ID: /* 0x20 */ 15590968Sshiba cis_manuf_id(cp, tp->data, tp->length); 15690968Sshiba break; 15759656Siwasaki case CIS_FUNC_ID: /* 0x21 */ 15859053Siwasaki cis_func_id(cp, tp->data, tp->length); 15959053Siwasaki break; 16059656Siwasaki case CIS_FUNC_EXT: /* 0x22 */ 16159656Siwasaki if (cp->func_id1 == 6) /* LAN adaptor */ 16259656Siwasaki cis_network_ext(cp, tp->data, tp->length); 16359656Siwasaki break; 16410217Sphk } 16510217Sphk } 16615177Snate return (cp); 16710217Sphk} 16815177Snate 16910217Sphk/* 17010217Sphk * free_cis - delete cis entry. 17110217Sphk */ 17210217Sphkvoid 17310217Sphkfreecis(struct cis *cp) 17410217Sphk{ 17515177Snate struct cis_ioblk *io; 17615177Snate struct cis_memblk *mem; 17715177Snate struct cis_config *conf; 17815177Snate struct tuple *tp; 17915177Snate struct tuple_list *tl; 18010217Sphk 18115177Snate while ((tl = cp->tlist) != 0) { 18210217Sphk cp->tlist = tl->next; 18315177Snate while ((tp = tl->tuples) != 0) { 18410217Sphk tl->tuples = tp->next; 18510217Sphk if (tp->data) 18610217Sphk free(tp->data); 18710217Sphk } 18815177Snate } 18910217Sphk 19015177Snate while ((conf = cp->conf) != 0) { 19110217Sphk cp->conf = conf->next; 19215177Snate while ((io = conf->io) != 0) { 19310217Sphk conf->io = io->next; 19410217Sphk free(io); 19515177Snate } 19615177Snate while ((mem = conf->mem) != 0) { 19710217Sphk conf->mem = mem->next; 19810217Sphk free(mem); 19915177Snate } 20010217Sphk free(conf); 20115177Snate } 20210217Sphk free(cp); 20310217Sphk} 20415177Snate 20510217Sphk/* 20610217Sphk * Fills in CIS version data. 20710217Sphk */ 20816487Snatestatic void 20910217Sphkcis_info(struct cis *cp, unsigned char *p, int len) 21010217Sphk{ 21110217Sphk cp->maj_v = *p++; 21210217Sphk cp->min_v = *p++; 21359656Siwasaki len -= 2; 21459656Siwasaki if (cp->manuf) { 21559656Siwasaki free(cp->manuf); 21659656Siwasaki cp->manuf = NULL; 21759656Siwasaki } 21859656Siwasaki if (len > 1 && *p != 0xff) { 21959656Siwasaki cp->manuf = strdup(p); 22088961Simp len -= strlen(p) + 1; 22188961Simp p += strlen(p) + 1; 22259656Siwasaki } 22359656Siwasaki if (cp->vers) { 22459656Siwasaki free(cp->vers); 22559656Siwasaki cp->vers = NULL; 22659656Siwasaki } 22759656Siwasaki if (len > 1 && *p != 0xff) { 22859656Siwasaki cp->vers = strdup(p); 22988961Simp len -= strlen(p) + 1; 23088961Simp p += strlen(p) + 1; 23159656Siwasaki } else { 23288961Simp cp->vers = strdup("[none]"); 23359656Siwasaki } 23459656Siwasaki if (cp->add_info1) { 23559656Siwasaki free(cp->add_info1); 23659656Siwasaki cp->add_info1 = NULL; 23759656Siwasaki } 23859656Siwasaki if (len > 1 && *p != 0xff) { 23959656Siwasaki cp->add_info1 = strdup(p); 24088961Simp len -= strlen(p) + 1; 24188961Simp p += strlen(p) + 1; 24288961Simp } else { 24388961Simp cp->add_info1 = strdup("[none]"); 24459656Siwasaki } 24559656Siwasaki if (cp->add_info2) { 24659656Siwasaki free(cp->add_info2); 24759656Siwasaki cp->add_info2 = NULL; 24859656Siwasaki } 24959656Siwasaki if (len > 1 && *p != 0xff) 25059656Siwasaki cp->add_info2 = strdup(p); 25188961Simp else 25288961Simp cp->add_info2 = strdup("[none]"); 25310217Sphk} 25459656Siwasaki 25590968Sshibastatic void 25690968Sshibacis_manuf_id(struct cis *cp, unsigned char *p, int len) 25790968Sshiba{ 258112243Simp if (len >= 4) { 25990968Sshiba cp->manufacturer = tpl16(p); 26090968Sshiba cp->product = tpl16(p+2); 26190968Sshiba if (len == 5) 26290968Sshiba cp->prodext = *(p+4); /* For xe driver */ 26390968Sshiba } else { 26490968Sshiba cp->manufacturer=0; 26590968Sshiba cp->product=0; 26690968Sshiba cp->prodext=0; 26790968Sshiba } 26890968Sshiba} 26959053Siwasaki/* 27059656Siwasaki * Fills in CIS function ID. 27159053Siwasaki */ 27259053Siwasakistatic void 273185033Simpcis_func_id(struct cis *cp, unsigned char *p, int len __unused) 27459053Siwasaki{ 27559053Siwasaki cp->func_id1 = *p++; 27659053Siwasaki cp->func_id2 = *p++; 27759053Siwasaki} 27815177Snate 27959656Siwasakistatic void 280185033Simpcis_network_ext(struct cis *cp, unsigned char *p, int len __unused) 28159656Siwasaki{ 28259656Siwasaki int i; 28359656Siwasaki 28459656Siwasaki switch (p[0]) { 28559656Siwasaki case 4: /* Node ID */ 28659656Siwasaki if (len <= 2 || len < p[1] + 2) 28759656Siwasaki return; 28859656Siwasaki 28959656Siwasaki if (cp->lan_nid) 29059656Siwasaki free(cp->lan_nid); 29159656Siwasaki cp->lan_nid = xmalloc(p[1]); 29259656Siwasaki 29359656Siwasaki for (i = 0; i <= p[1]; i++) 29459656Siwasaki cp->lan_nid[i] = p[i + 1]; 29559656Siwasaki break; 29659656Siwasaki } 29759656Siwasaki} 29859656Siwasaki 29910217Sphk/* 30010217Sphk * device_desc - decode device descriptor. 30110217Sphk */ 30216487Snatestatic void 30310255Sphkdevice_desc(unsigned char *p, int len, struct dev_mem *dp) 30410217Sphk{ 30515177Snate while (len > 0 && *p != 0xFF) { 30610217Sphk dp->valid = 1; 30710217Sphk dp->type = (*p & 0xF0) >> 4; 30810217Sphk dp->wps = !!(*p & 0x8); 30910217Sphk dp->speed = *p & 7; 31010217Sphk p++; 31115177Snate if (*p != 0xFF) { 31259656Siwasaki dp->addr = (*p >> 3) & 0xF; 31310217Sphk dp->units = *p & 7; 31415177Snate } 31510217Sphk p++; 31610217Sphk len -= 2; 31715177Snate } 31810217Sphk} 31915177Snate 32010217Sphk/* 32110217Sphk * configuration map of card control register. 32210217Sphk */ 32316487Snatestatic void 324185033Simpconfig_map(struct cis *cp, unsigned char *p, int len __unused) 32510217Sphk{ 32615177Snate unsigned char *p1; 32759656Siwasaki int rlen = (*p & 3) + 1; 32810217Sphk 32910217Sphk p1 = p + 1; 33010217Sphk cp->last_config = *p1++ & 0x3F; 33159656Siwasaki cp->reg_addr = parse_num(rlen | 0x10, p1, &p1, 0); 33210217Sphk cp->ccrs = *p1; 33310217Sphk} 33415177Snate 33510217Sphk/* 33659656Siwasaki * Parse variable length value. 33759656Siwasaki */ 33859656Siwasakiu_int 33959656Siwasakiparse_num(int sz, u_char *p, u_char **q, int ofs) 34059656Siwasaki{ 34159656Siwasaki u_int num = 0; 34259656Siwasaki 34359656Siwasaki switch (sz) { 34459656Siwasaki case 0: 34559656Siwasaki case 0x10: 34659656Siwasaki break; 34759656Siwasaki case 1: 34859656Siwasaki case 0x11: 34959656Siwasaki num = (*p++) + ofs; 35059656Siwasaki break; 35159656Siwasaki case 2: 35259656Siwasaki case 0x12: 35359656Siwasaki num = tpl16(p) + ofs; 35459656Siwasaki p += 2; 35559656Siwasaki break; 35659656Siwasaki case 0x13: 35759656Siwasaki num = tpl24(p) + ofs; 35859656Siwasaki p += 3; 35959656Siwasaki break; 36059656Siwasaki case 3: 36159656Siwasaki case 0x14: 36259656Siwasaki num = tpl32(p) + ofs; 36359656Siwasaki p += 4; 36459656Siwasaki break; 36559656Siwasaki } 36659656Siwasaki if (q) 36759656Siwasaki *q = p; 36859656Siwasaki return num; 36959656Siwasaki} 37059656Siwasaki 37159656Siwasaki/* 37210217Sphk * CIS config entry - Decode and build configuration entry. 37310217Sphk */ 37416487Snatestatic void 375185033Simpcis_config(struct cis *cp, unsigned char *p, int len __unused) 37610217Sphk{ 37715177Snate int x; 37815177Snate int i, j; 37915177Snate struct cis_config *conf, *last; 38015177Snate unsigned char feat; 38110217Sphk 38210217Sphk conf = xmalloc(sizeof(*conf)); 38315177Snate if ((last = cp->conf) != 0) { 38410217Sphk while (last->next) 38510217Sphk last = last->next; 38610217Sphk last->next = conf; 38715177Snate } else 38810217Sphk cp->conf = conf; 38959656Siwasaki conf->id = *p & 0x3F; /* Config index */ 39059656Siwasaki if (*p & 0x40) /* Default flag */ 39110217Sphk cp->def_config = conf; 39210217Sphk if (*p++ & 0x80) 39359656Siwasaki p++; /* Interface byte skip */ 39459656Siwasaki feat = *p++; /* Features byte */ 39515177Snate for (i = 0; i < CIS_FEAT_POWER(feat); i++) { 39610217Sphk unsigned char parms = *p++; 39710217Sphk 39810217Sphk conf->pwr = 1; 39910217Sphk for (j = 0; j < 8; j++) 40010217Sphk if (parms & (1 << j)) 40115177Snate while (*p++ & 0x80); 40215177Snate } 40315177Snate if (feat & CIS_FEAT_TIMING) { 40410217Sphk conf->timing = 1; 40510217Sphk i = *p++; 40610217Sphk if (CIS_WAIT_SCALE(i) != 3) 40710217Sphk p++; 40810217Sphk if (CIS_READY_SCALE(i) != 7) 40910217Sphk p++; 41010217Sphk if (CIS_RESERVED_SCALE(i) != 7) 41110217Sphk p++; 41215177Snate } 41315177Snate if (feat & CIS_FEAT_I_O) { 41410217Sphk conf->iospace = 1; 41510217Sphk if (CIS_IO_RANGE & *p) 41615177Snate conf->io_blks = CIS_IO_BLKS(p[1]) + 1; 41710217Sphk conf->io_addr = CIS_IO_ADDR(*p); 41859656Siwasaki conf->io_bus = (*p >> 5) & 3; /* CIS_IO_8BIT | CIS_IO_16BIT */ 41915177Snate if (*p++ & CIS_IO_RANGE) { 42059656Siwasaki struct cis_ioblk *io; 42159656Siwasaki struct cis_ioblk *last_io = NULL; 42259656Siwasaki 42310217Sphk i = CIS_IO_ADSZ(*p); 42410217Sphk j = CIS_IO_BLKSZ(*p++); 42515177Snate for (x = 0; x < conf->io_blks; x++) { 42610217Sphk io = xmalloc(sizeof(*io)); 42759656Siwasaki if (last_io) 42859656Siwasaki last_io->next = io; 42910217Sphk else 43010217Sphk conf->io = io; 43159656Siwasaki last_io = io; 43259656Siwasaki io->addr = parse_num(i, p, &p, 0); 43359656Siwasaki io->size = parse_num(j, p, &p, 1); 43410217Sphk } 43510217Sphk } 43615177Snate } 43715177Snate if (feat & CIS_FEAT_IRQ) { 43810217Sphk conf->irq = 1; 43910217Sphk conf->irqlevel = *p & 0xF; 44010217Sphk conf->irq_flags = *p & 0xF0; 44115177Snate if (*p++ & CIS_IRQ_MASK) { 44259656Siwasaki conf->irq_mask = tpl16(p); 44310217Sphk p += 2; 44410217Sphk } 44515177Snate } 44615177Snate switch (CIS_FEAT_MEMORY(feat)) { 44776343Sdmlb case CIS_FEAT_MEM_NONE: 44810217Sphk break; 44976343Sdmlb case CIS_FEAT_MEM_LEN: 45010217Sphk conf->memspace = 1; 45110217Sphk conf->mem = xmalloc(sizeof(*conf->mem)); 45259656Siwasaki conf->mem->length = tpl16(p) << 8; 45310217Sphk break; 45476343Sdmlb case CIS_FEAT_MEM_ADDR: 45510217Sphk conf->memspace = 1; 45610217Sphk conf->mem = xmalloc(sizeof(*conf->mem)); 45759656Siwasaki conf->mem->length = tpl16(p) << 8; 45859656Siwasaki conf->mem->address = tpl16(p + 2) << 8; 45910217Sphk break; 46076343Sdmlb case CIS_FEAT_MEM_WIN: { 46159656Siwasaki struct cis_memblk *mem; 46259656Siwasaki struct cis_memblk *last_mem = NULL; 46359656Siwasaki 46410217Sphk conf->memspace = 1; 46510217Sphk x = *p++; 46610217Sphk conf->memwins = CIS_MEM_WINS(x); 46715177Snate for (i = 0; i < conf->memwins; i++) { 46810217Sphk mem = xmalloc(sizeof(*mem)); 46959656Siwasaki if (last_mem) 47059656Siwasaki last_mem->next = mem; 47159656Siwasaki else 47210217Sphk conf->mem = mem; 47359656Siwasaki last_mem = mem; 47459656Siwasaki mem->length = parse_num(CIS_MEM_LENSZ(x) | 0x10, p, &p, 0) << 8; 47559656Siwasaki mem->address = parse_num(CIS_MEM_ADDRSZ(x) | 0x10, p, &p, 0) << 8; 47615177Snate if (x & CIS_MEM_HOST) { 47759656Siwasaki mem->host_address = parse_num(CIS_MEM_ADDRSZ(x) | 0x10, 47859656Siwasaki p, &p, 0) << 8; 47910217Sphk } 48015177Snate } 48110217Sphk break; 48259656Siwasaki } 48315177Snate } 48459656Siwasaki if (feat & CIS_FEAT_MISC) { 48510217Sphk conf->misc_valid = 1; 48610217Sphk conf->misc = *p++; 48715177Snate } 48810217Sphk} 48915177Snate 49010217Sphk/* 49110217Sphk * Read the tuples from the card. 49210217Sphk * The processing of tuples is as follows: 49310217Sphk * - Read tuples at attribute memory, offset 0. 49410217Sphk * - If a CIS_END is the first tuple, look for 49510217Sphk * a tuple list at common memory offset 0; this list 49610217Sphk * must start with a LINKTARGET. 49710217Sphk * - If a long link tuple was encountered, execute the long 49810217Sphk * link. 49910217Sphk * - If a no-link tuple was seen, terminate processing. 50010217Sphk * - If no no-link tuple exists, and no long link tuple 50110217Sphk * exists while processing the primary tuple list, 50210217Sphk * then look for a LINKTARGET tuple in common memory. 50310217Sphk * - If a long link tuple is found in any list, then process 50410217Sphk * it. Only one link is allowed per list. 50510217Sphk */ 50610217Sphkstatic struct tuple_list *tlist; 50710217Sphk 50816487Snatestatic struct tuple_list * 50910217Sphkread_tuples(int fd) 51010217Sphk{ 51115177Snate struct tuple_list *tl = 0, *last_tl; 51215177Snate struct tuple *tp; 51315177Snate int flag; 51415177Snate off_t offs; 51510217Sphk 51610217Sphk tlist = 0; 51715177Snate last_tl = tlist = read_one_tuplelist(fd, MDF_ATTR, (off_t) 0); 51815177Snate 51915177Snate /* Now start processing the links (if any). */ 52015177Snate do { 52110217Sphk flag = MDF_ATTR; 52210217Sphk tp = find_tuple_in_list(last_tl, CIS_LONGLINK_A); 52315177Snate if (tp == 0) { 52410217Sphk flag = 0; 52510217Sphk tp = find_tuple_in_list(last_tl, CIS_LONGLINK_C); 52615177Snate } 52715177Snate if (tp && tp->length == 4) { 52859656Siwasaki offs = tpl32(tp->data); 52910217Sphk#ifdef DEBUG 53059656Siwasaki printf("Checking long link at %qd (%s memory)\n", 53115177Snate offs, flag ? "Attribute" : "Common"); 53210217Sphk#endif 53315177Snate /* If a link was found, read the tuple list from it. */ 53415177Snate if (ck_linktarget(fd, offs, flag)) { 53510217Sphk tl = read_one_tuplelist(fd, flag, offs); 53610217Sphk last_tl->next = tl; 53710217Sphk last_tl = tl; 53810217Sphk } 53935310Snate } else 54035310Snate tl = 0; 54115177Snate } while (tl); 54215177Snate 54315177Snate /* 54415177Snate * If the primary list had no NOLINK tuple, and no LINKTARGET, 54515177Snate * then try to read a tuple list at common memory (offset 0). 54615177Snate */ 54715177Snate if (find_tuple_in_list(tlist, CIS_NOLINK) == 0 && tlist->next == 0 && 54815177Snate ck_linktarget(fd, (off_t) 0, 0)) { 54910217Sphk#ifdef DEBUG 55059656Siwasaki printf("Reading long link at %qd (%s memory)\n", 55115177Snate offs, flag ? "Attribute" : "Common"); 55210217Sphk#endif 55315177Snate tlist->next = read_one_tuplelist(fd, 0, (off_t) 0); 55415177Snate } 55515177Snate return (tlist); 55610217Sphk} 55715177Snate 55810217Sphk/* 55910217Sphk * Read one tuple list from the card. 56010217Sphk */ 56116487Snatestatic struct tuple_list * 56210217Sphkread_one_tuplelist(int fd, int flags, off_t offs) 56310217Sphk{ 56415177Snate struct tuple *tp, *last_tp = 0; 56515177Snate struct tuple_list *tl; 56615177Snate struct tuple_info *tinfo; 56715177Snate int total = 0; 56815177Snate unsigned char code, length; 56959656Siwasaki int fmvj182 = 0; 57059656Siwasaki#ifdef HSSYNTH 57159656Siwasaki int hss = 0; 57259656Siwasaki#endif /* HSSYNTH */ 57310217Sphk 57415177Snate /* Check to see if this memory has already been scanned. */ 57510217Sphk for (tl = tlist; tl; tl = tl->next) 57610217Sphk if (tl->offs == offs && tl->flags == (flags & MDF_ATTR)) 57715177Snate return (0); 57810217Sphk tl = xmalloc(sizeof(*tl)); 57910217Sphk tl->offs = offs; 58010217Sphk tl->flags = flags & MDF_ATTR; 58110217Sphk ioctl(fd, PIOCRWFLAG, &flags); 58210217Sphk lseek(fd, offs, SEEK_SET); 58315177Snate do { 584185033Simp if (read(fd, &code, 1) != 1) { 58530171Scharnier warn("CIS code read"); 58610217Sphk break; 58715177Snate } 58810217Sphk total++; 58910217Sphk if (code == CIS_NULL) 59010217Sphk continue; 59110217Sphk tp = xmalloc(sizeof(*tp)); 59210217Sphk tp->code = code; 59359656Siwasaki if (code == CIS_END) 59459656Siwasaki length = 0; 59559656Siwasaki else { 596185033Simp if (read(fd, &length, 1) != 1) { 59759656Siwasaki warn("CIS len read"); 59859656Siwasaki break; 59959656Siwasaki } 60059656Siwasaki total++; 60159656Siwasaki if (fmvj182 && (code == 0x1b) && (length == 25)) 60259656Siwasaki length = 31; 60315177Snate } 60410217Sphk tp->length = length; 60510217Sphk#ifdef DEBUG 60621371Snate printf("Tuple code = 0x%x, len = %d\n", code, length); 60710217Sphk#endif 60815177Snate if (length == 0xFF) { 60910217Sphk length = tp->length = 0; 61010217Sphk code = CIS_END; 61115177Snate } 61215177Snate if (length != 0) { 61310217Sphk total += length; 61410217Sphk tp->data = xmalloc(length); 615185033Simp if (read(fd, tp->data, length) != length) { 61630171Scharnier warn("CIS read"); 61710217Sphk break; 61810217Sphk } 61915177Snate } 62015177Snate 62115177Snate /* 62215177Snate * Check the tuple, and ignore it if it isn't in the table 62315177Snate * or the length is illegal. 62415177Snate */ 62510217Sphk tinfo = get_tuple_info(code); 626112233Simp if (tinfo != NULL && (tinfo->length != 255 && tinfo->length > length)) { 62710217Sphk printf("code %s ignored\n", tuple_name(code)); 62810217Sphk tp->code = CIS_NULL; 62915177Snate } 63059656Siwasaki if (tl->tuples == NULL) 63110217Sphk tl->tuples = tp; 63210217Sphk else 63310217Sphk last_tp->next = tp; 63410217Sphk last_tp = tp; 63515177Snate } while (code != CIS_END && total < 1024); 63615177Snate return (tl); 63710217Sphk} 63815177Snate 63910217Sphk/* 64010217Sphk * return true if the offset points to a LINKTARGET tuple. 64110217Sphk */ 64216487Snatestatic int 64310217Sphkck_linktarget(int fd, off_t offs, int flag) 64410217Sphk{ 64515177Snate char blk[5]; 64610217Sphk 64710217Sphk ioctl(fd, PIOCRWFLAG, &flag); 64810217Sphk lseek(fd, offs, SEEK_SET); 649185033Simp if (read(fd, blk, 5) != 5) 65015177Snate return (0); 65110217Sphk if (blk[0] == 0x13 && 65210217Sphk blk[1] == 0x3 && 65310217Sphk blk[2] == 'C' && 65410217Sphk blk[3] == 'I' && 65510217Sphk blk[4] == 'S') 65615177Snate return (1); 65715177Snate return (0); 65810217Sphk} 65915177Snate 66010217Sphk/* 66110217Sphk * find_tuple_in_list - find a tuple within a 66210217Sphk * single tuple list. 66310217Sphk */ 66416487Snatestatic struct tuple * 66510217Sphkfind_tuple_in_list(struct tuple_list *tl, unsigned char code) 66610217Sphk{ 66715177Snate struct tuple *tp; 66810217Sphk 66910217Sphk for (tp = tl->tuples; tp; tp = tp->next) 67010217Sphk if (tp->code == code) 67110217Sphk break; 67215177Snate return (tp); 67310217Sphk} 67415177Snate 67510217Sphk/* 67610217Sphk * return table entry for code. 67710217Sphk */ 67816487Snatestatic struct tuple_info * 67910217Sphkget_tuple_info(unsigned char code) 68010217Sphk{ 68115177Snate struct tuple_info *tp; 68210217Sphk 68310217Sphk for (tp = tuple_info; tp->name; tp++) 68410217Sphk if (tp->code == code) 68515177Snate return (tp); 68615177Snate return (0); 68710217Sphk} 68815177Snate 689185033Simpconst char * 69010217Sphktuple_name(unsigned char code) 69110217Sphk{ 69215177Snate struct tuple_info *tp; 69310217Sphk 69410217Sphk tp = get_tuple_info(code); 69510217Sphk if (tp) 69615177Snate return (tp->name); 69715177Snate return ("Unknown"); 69810217Sphk} 699