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