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