pccard_cis.c revision 147962
1104640Simp/* $NetBSD: pcmcia_cis.c,v 1.17 2000/02/10 09:01:52 chopps Exp $ */
252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard_cis.c 147962 2005-07-13 14:59:06Z imp $ */
352506Simp
4139749Simp/*-
552506Simp * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
652506Simp *
752506Simp * Redistribution and use in source and binary forms, with or without
852506Simp * modification, are permitted provided that the following conditions
952506Simp * are met:
1052506Simp * 1. Redistributions of source code must retain the above copyright
1152506Simp *    notice, this list of conditions and the following disclaimer.
1252506Simp * 2. Redistributions in binary form must reproduce the above copyright
1352506Simp *    notice, this list of conditions and the following disclaimer in the
1452506Simp *    documentation and/or other materials provided with the distribution.
1552506Simp * 3. All advertising materials mentioning features or use of this software
1652506Simp *    must display the following acknowledgement:
1752506Simp *	This product includes software developed by Marc Horowitz.
1852506Simp * 4. The name of the author may not be used to endorse or promote products
1952506Simp *    derived from this software without specific prior written permission.
2052506Simp *
2152506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2252506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2352506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2452506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2552506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2652506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2752506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2852506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2952506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3052506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3152506Simp */
3252506Simp
3352506Simp#include <sys/param.h>
3452506Simp#include <sys/systm.h>
3552506Simp#include <sys/malloc.h>
3652506Simp#include <sys/module.h>
3752506Simp#include <sys/kernel.h>
3852506Simp#include <sys/queue.h>
3952506Simp#include <sys/types.h>
4052506Simp
4152506Simp#include <sys/bus.h>
4252506Simp#include <machine/bus.h>
4352506Simp#include <sys/rman.h>
4452506Simp#include <machine/resource.h>
4552506Simp
4652506Simp#include <dev/pccard/pccardreg.h>
4752506Simp#include <dev/pccard/pccardvar.h>
48120868Simp#include <dev/pccard/pccard_cis.h>
4952506Simp
5059193Simp#include "card_if.h"
5159193Simp
5291786Simpextern int	pccard_cis_debug;
5391786Simp
5459193Simp#define PCCARDCISDEBUG
5552506Simp#ifdef PCCARDCISDEBUG
56119161Simp#define	DPRINTF(arg) do { if (pccard_cis_debug) printf arg; } while (0)
57119161Simp#define	DEVPRINTF(arg) do { if (pccard_cis_debug) device_printf arg; } while (0)
5852506Simp#else
5952506Simp#define	DPRINTF(arg)
6055720Simp#define	DEVPRINTF(arg)
6152506Simp#endif
6252506Simp
63128169Simp#define	PCCARD_CIS_SIZE		4096
6452506Simp
6552506Simpstruct cis_state {
6652506Simp	int	count;
6752506Simp	int	gotmfc;
6852506Simp	struct pccard_config_entry temp_cfe;
6952506Simp	struct pccard_config_entry *default_cfe;
7052506Simp	struct pccard_card *card;
7152506Simp	struct pccard_function *pf;
7252506Simp};
7352506Simp
74147729Simpstatic int pccard_parse_cis_tuple(const struct pccard_tuple *, void *);
75147729Simpstatic int decode_funce(const struct pccard_tuple *, struct pccard_function *);
7652506Simp
7752506Simpvoid
7855720Simppccard_read_cis(struct pccard_softc *sc)
7952506Simp{
8052506Simp	struct cis_state state;
8152506Simp
82104640Simp	bzero(&state, sizeof state);
8352506Simp	state.card = &sc->card;
8452506Simp	state.card->error = 0;
8552506Simp	state.card->cis1_major = -1;
8652506Simp	state.card->cis1_minor = -1;
8752506Simp	state.card->cis1_info[0] = NULL;
8852506Simp	state.card->cis1_info[1] = NULL;
8952506Simp	state.card->cis1_info[2] = NULL;
9052506Simp	state.card->cis1_info[3] = NULL;
9186272Simp	state.card->manufacturer = PCMCIA_VENDOR_INVALID;
9286272Simp	state.card->product = PCMCIA_PRODUCT_INVALID;
9352506Simp	STAILQ_INIT(&state.card->pf_head);
9452506Simp	state.pf = NULL;
9552506Simp
96128169Simp	tsleep(&state, 0, "pccard", hz);
9758997Simp	if (pccard_scan_cis(sc->dev, pccard_parse_cis_tuple,
9852506Simp	    &state) == -1)
9952506Simp		state.card->error++;
10052506Simp}
10152506Simp
10252506Simpint
103147711Simppccard_scan_cis(device_t dev, pccard_scan_t fct, void *arg)
10452506Simp{
10555720Simp	struct resource *res;
10655720Simp	int rid;
10752506Simp	struct pccard_tuple tuple;
10852506Simp	int longlink_present;
10952506Simp	int longlink_common;
110112358Simp	u_long longlink_addr;		/* Type suspect */
11152506Simp	int mfc_count;
11252506Simp	int mfc_index;
113119161Simp#ifdef PCCARDCISDEBUG
114119161Simp	int cis_none_cnt = 10;	/* Only report 10 CIS_NONEs */
115119161Simp#endif
11652506Simp	struct {
11752506Simp		int	common;
11852506Simp		u_long	addr;
11952506Simp	} mfc[256 / 5];
12052506Simp	int ret;
12152506Simp
12252506Simp	ret = 0;
12352506Simp
12452506Simp	/* allocate some memory */
12552506Simp
126128169Simp	/*
127128169Simp	 * Some reports from the field suggest that a 64k memory boundary
128128169Simp	 * helps card CIS being able to be read.  Try it here and see what
129128169Simp	 * the results actually are.  I'm not sure I understand why this
130128169Simp	 * would make cards work better, but it is easy enough to test.
131128169Simp	 */
13255720Simp	rid = 0;
133128169Simp	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0,
134128169Simp	    PCCARD_CIS_SIZE, RF_ACTIVE | rman_make_alignment_flags(64*1024));
13555720Simp	if (res == NULL) {
13655720Simp		device_printf(dev, "can't alloc memory to read attributes\n");
13752506Simp		return -1;
13852506Simp	}
13959193Simp	CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
14059193Simp	    rid, PCCARD_A_MEM_ATTR);
14155720Simp	tuple.memt = rman_get_bustag(res);
14255720Simp	tuple.memh = rman_get_bushandle(res);
14359389Simp	tuple.ptr = 0;
14452506Simp
145119060Simp	DPRINTF(("cis mem map 0x%x (resource: 0x%lx)\n",
146119060Simp	    (unsigned int) tuple.memh, rman_get_start(res)));
14755720Simp
14852506Simp	tuple.mult = 2;
14952506Simp
15052506Simp	longlink_present = 1;
15152506Simp	longlink_common = 1;
15252506Simp	longlink_addr = 0;
15352506Simp
15452506Simp	mfc_count = 0;
15552506Simp	mfc_index = 0;
15652506Simp
15755720Simp	DEVPRINTF((dev, "CIS tuple chain:\n"));
15852506Simp
15952506Simp	while (1) {
16052506Simp		while (1) {
161119060Simp			/*
162119060Simp			 * Perform boundary check for insane cards.
163119060Simp			 * If CIS is too long, simulate CIS end.
164119060Simp			 * (This check may not be sufficient for
165119060Simp			 * malicious cards.)
166119060Simp			 */
167119060Simp			if (tuple.mult * tuple.ptr >= PCCARD_CIS_SIZE - 1
168119060Simp			    - 32 /* ad hoc value */ ) {
169119060Simp				printf("CIS is too long -- truncating\n");
170120868Simp				tuple.code = CISTPL_END;
171119060Simp			} else {
172119060Simp				/* get the tuple code */
173119060Simp				tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
174119060Simp			}
17552506Simp
17652506Simp			/* two special-case tuples */
17752506Simp
178120868Simp			if (tuple.code == CISTPL_NULL) {
179119161Simp#ifdef PCCARDCISDEBUG
180119161Simp				if (cis_none_cnt > 0)
181119161Simp					DPRINTF(("CISTPL_NONE\n 00\n"));
182119161Simp				else if (cis_none_cnt == 0)
183119161Simp					DPRINTF(("TOO MANY CIS_NONE\n"));
184119161Simp				cis_none_cnt--;
185119161Simp#endif
18652506Simp				tuple.ptr++;
18752506Simp				continue;
188120868Simp			} else if (tuple.code == CISTPL_END) {
18952506Simp				DPRINTF(("CISTPL_END\n ff\n"));
19052506Simp				/* Call the function for the END tuple, since
19152506Simp				   the CIS semantics depend on it */
192147711Simp				if ((*fct)(&tuple, arg)) {
19352506Simp					ret = 1;
19452506Simp					goto done;
19552506Simp				}
19652506Simp				tuple.ptr++;
19752506Simp				break;
19852506Simp			}
19952506Simp			/* now all the normal tuples */
20052506Simp
20152506Simp			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
20252506Simp			switch (tuple.code) {
203120868Simp			case CISTPL_LONGLINK_A:
204120868Simp			case CISTPL_LONGLINK_C:
20552506Simp				if (tuple.length < 4) {
20652506Simp					DPRINTF(("CISTPL_LONGLINK_%s too "
20752506Simp					    "short %d\n",
20852506Simp					    longlink_common ? "C" : "A",
20952506Simp					    tuple.length));
21052506Simp					break;
21152506Simp				}
21252506Simp				longlink_present = 1;
21352506Simp				longlink_common = (tuple.code ==
214120868Simp				    CISTPL_LONGLINK_C) ? 1 : 0;
21552506Simp				longlink_addr = pccard_tuple_read_4(&tuple, 0);
21652506Simp				DPRINTF(("CISTPL_LONGLINK_%s %lx\n",
21752506Simp				    longlink_common ? "C" : "A",
21852506Simp				    longlink_addr));
21952506Simp				break;
220120868Simp			case CISTPL_NO_LINK:
22152506Simp				longlink_present = 0;
22252506Simp				DPRINTF(("CISTPL_NO_LINK\n"));
22352506Simp				break;
224120868Simp			case CISTPL_CHECKSUM:
22552506Simp				if (tuple.length < 5) {
22652506Simp					DPRINTF(("CISTPL_CHECKSUM too "
22752506Simp					    "short %d\n", tuple.length));
22852506Simp					break;
22952506Simp				} {
23052506Simp					int16_t offset;
23152506Simp					u_long addr, length;
23252506Simp					u_int cksum, sum;
23352506Simp					int i;
23452506Simp
23590896Simp					offset = (uint16_t)
23652506Simp					    pccard_tuple_read_2(&tuple, 0);
23752506Simp					length = pccard_tuple_read_2(&tuple, 2);
23852506Simp					cksum = pccard_tuple_read_1(&tuple, 4);
23952506Simp
24052506Simp					addr = tuple.ptr + offset;
24152506Simp
24252506Simp					DPRINTF(("CISTPL_CHECKSUM addr=%lx "
24352506Simp					    "len=%lx cksum=%x",
24452506Simp					    addr, length, cksum));
24552506Simp
24652506Simp					/*
24752506Simp					 * XXX do more work to deal with
24852506Simp					 * distant regions
24952506Simp					 */
25052506Simp					if ((addr >= PCCARD_CIS_SIZE) ||
25152506Simp					    ((addr + length) >=
252104640Simp					    PCCARD_CIS_SIZE)) {
25352506Simp						DPRINTF((" skipped, "
25452506Simp						    "too distant\n"));
25552506Simp						break;
25652506Simp					}
25752506Simp					sum = 0;
25852506Simp					for (i = 0; i < length; i++)
25952506Simp						sum +=
26052506Simp						    bus_space_read_1(tuple.memt,
26152506Simp						    tuple.memh,
26252506Simp						    addr + tuple.mult * i);
26352506Simp					if (cksum != (sum & 0xff)) {
26452506Simp						DPRINTF((" failed sum=%x\n",
26552506Simp						    sum));
26655720Simp						device_printf(dev,
26755720Simp						    "CIS checksum failed\n");
26852506Simp#if 0
26952506Simp						/*
27052506Simp						 * XXX Some working cards have
27152506Simp						 * XXX bad checksums!!
27252506Simp						 */
27352506Simp						ret = -1;
27452506Simp#endif
27552506Simp					} else {
27652506Simp						DPRINTF((" ok\n"));
27752506Simp					}
27852506Simp				}
27952506Simp				break;
280120868Simp			case CISTPL_LONGLINK_MFC:
28152506Simp				if (tuple.length < 1) {
28252506Simp					DPRINTF(("CISTPL_LONGLINK_MFC too "
28352506Simp					    "short %d\n", tuple.length));
28452506Simp					break;
28552506Simp				}
286104640Simp				if (((tuple.length - 1) % 5) != 0) {
287104640Simp					DPRINTF(("CISTPL_LONGLINK_MFC bogus "
288104640Simp					    "length %d\n", tuple.length));
289104640Simp					break;
290104640Simp				}
29152506Simp				/*
29252506Simp				 * this is kind of ad hoc, as I don't have
29352506Simp				 * any real documentation
29452506Simp				 */
29552506Simp				{
296104640Simp					int i, tmp_count;
29752506Simp
298104640Simp					/*
299104640Simp					 * put count into tmp var so that
300104640Simp					 * if we have to bail (because it's
301104640Simp					 * a bogus count) it won't be
302104640Simp					 * remembered for later use.
303104640Simp					 */
304104640Simp					tmp_count =
30552506Simp					    pccard_tuple_read_1(&tuple, 0);
306104640Simp
30752506Simp					DPRINTF(("CISTPL_LONGLINK_MFC %d",
308104640Simp					    tmp_count));
309104640Simp
310104640Simp					/*
311104640Simp					 * make _sure_ it's the right size;
312104640Simp					 * if too short, it may be a weird
313104640Simp					 * (unknown/undefined) format
314104640Simp					 */
315104640Simp					if (tuple.length != (tmp_count*5 + 1)) {
316104640Simp						DPRINTF((" bogus length %d\n",
317104640Simp						    tuple.length));
318104640Simp						break;
319104640Simp					}
320104640Simp					/*
321104640Simp					 * sanity check for a programming
322104640Simp					 * error which is difficult to find
323104640Simp					 * when debugging.
324104640Simp					 */
325104640Simp					if (tmp_count >
326104640Simp					    howmany(sizeof mfc, sizeof mfc[0]))
327104640Simp						panic("CISTPL_LONGLINK_MFC mfc "
328104640Simp						    "count would blow stack");
329104640Simp                                        mfc_count = tmp_count;
33052506Simp					for (i = 0; i < mfc_count; i++) {
33152506Simp						mfc[i].common =
33252506Simp						    (pccard_tuple_read_1(&tuple,
33352506Simp						    1 + 5 * i) ==
33452506Simp						    PCCARD_MFC_MEM_COMMON) ?
33552506Simp						    1 : 0;
33652506Simp						mfc[i].addr =
33752506Simp						    pccard_tuple_read_4(&tuple,
33852506Simp						    1 + 5 * i + 1);
33952506Simp						DPRINTF((" %s:%lx",
34052506Simp						    mfc[i].common ? "common" :
34152506Simp						    "attr", mfc[i].addr));
34252506Simp					}
34352506Simp					DPRINTF(("\n"));
34452506Simp				}
34552506Simp				/*
34652506Simp				 * for LONGLINK_MFC, fall through to the
34752506Simp				 * function.  This tuple has structural and
34852506Simp				 * semantic content.
34952506Simp				 */
35052506Simp			default:
35152506Simp				{
352147711Simp					if ((*fct)(&tuple, arg)) {
35352506Simp						ret = 1;
35452506Simp						goto done;
35552506Simp					}
35652506Simp				}
35752506Simp				break;
35852506Simp			}	/* switch */
35952506Simp#ifdef PCCARDCISDEBUG
36052506Simp			/* print the tuple */
36152506Simp			{
36252506Simp				int i;
36352506Simp
36452506Simp				DPRINTF((" %02x %02x", tuple.code,
36552506Simp				    tuple.length));
36652506Simp
36752506Simp				for (i = 0; i < tuple.length; i++) {
36852506Simp					DPRINTF((" %02x",
36952506Simp					    pccard_tuple_read_1(&tuple, i)));
37052506Simp					if ((i % 16) == 13)
37152506Simp						DPRINTF(("\n"));
37252506Simp				}
37387352Simp
37452506Simp				if ((i % 16) != 14)
37552506Simp					DPRINTF(("\n"));
37652506Simp			}
37752506Simp#endif
37852506Simp			/* skip to the next tuple */
37952506Simp			tuple.ptr += 2 + tuple.length;
38052506Simp		}
38152506Simp
38252506Simp		/*
38352506Simp		 * the chain is done.  Clean up and move onto the next one,
38452506Simp		 * if any.  The loop is here in the case that there is an MFC
38552506Simp		 * card with no longlink (which defaults to existing, == 0).
38652506Simp		 * In general, this means that if one pointer fails, it will
38752506Simp		 * try the next one, instead of just bailing.
38852506Simp		 */
38952506Simp		while (1) {
39052506Simp			if (longlink_present) {
39187352Simp				CARD_SET_RES_FLAGS(device_get_parent(dev), dev,
39287352Simp				    SYS_RES_MEMORY, rid, longlink_common ?
39393370Simp				    PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR);
39452506Simp				DPRINTF(("cis mem map %x\n",
39552506Simp				    (unsigned int) tuple.memh));
39652506Simp				tuple.mult = longlink_common ? 1 : 2;
39793370Simp				tuple.ptr = longlink_addr;
39852506Simp				longlink_present = 0;
39952506Simp				longlink_common = 1;
40052506Simp				longlink_addr = 0;
40152506Simp			} else if (mfc_count && (mfc_index < mfc_count)) {
40287352Simp				CARD_SET_RES_FLAGS(device_get_parent(dev), dev,
40387352Simp				    SYS_RES_MEMORY, rid, mfc[mfc_index].common
40493370Simp				    ? PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR);
40552506Simp				DPRINTF(("cis mem map %x\n",
40652506Simp				    (unsigned int) tuple.memh));
40752506Simp				/* set parse state, and point at the next one */
40852506Simp				tuple.mult = mfc[mfc_index].common ? 1 : 2;
40993370Simp				tuple.ptr = mfc[mfc_index].addr;
41052506Simp				mfc_index++;
41152506Simp			} else {
41252506Simp				goto done;
41352506Simp			}
41452506Simp
41552506Simp			/* make sure that the link is valid */
41652506Simp			tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
417120868Simp			if (tuple.code != CISTPL_LINKTARGET) {
41852506Simp				DPRINTF(("CISTPL_LINKTARGET expected, "
41952506Simp				    "code %02x observed\n", tuple.code));
42052506Simp				continue;
42152506Simp			}
42252506Simp			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
42352506Simp			if (tuple.length < 3) {
42452506Simp				DPRINTF(("CISTPL_LINKTARGET too short %d\n",
42552506Simp				    tuple.length));
42652506Simp				continue;
42752506Simp			}
42852506Simp			if ((pccard_tuple_read_1(&tuple, 0) != 'C') ||
42952506Simp			    (pccard_tuple_read_1(&tuple, 1) != 'I') ||
43052506Simp			    (pccard_tuple_read_1(&tuple, 2) != 'S')) {
43152506Simp				DPRINTF(("CISTPL_LINKTARGET magic "
43252506Simp				    "%02x%02x%02x incorrect\n",
43352506Simp				    pccard_tuple_read_1(&tuple, 0),
43452506Simp				    pccard_tuple_read_1(&tuple, 1),
43552506Simp				    pccard_tuple_read_1(&tuple, 2)));
43652506Simp				continue;
43752506Simp			}
43852506Simp			tuple.ptr += 2 + tuple.length;
43952506Simp			break;
44052506Simp		}
44152506Simp	}
44252506Simp
44352506Simpdone:
44455720Simp	bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
44552506Simp
44652506Simp	return (ret);
44752506Simp}
44852506Simp
44952506Simp/* XXX this is incredibly verbose.  Not sure what trt is */
45052506Simp
45152506Simpvoid
45252506Simppccard_print_cis(device_t dev)
45352506Simp{
45464850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
45552506Simp	struct pccard_card *card = &sc->card;
45652506Simp	struct pccard_function *pf;
45752506Simp	struct pccard_config_entry *cfe;
45852506Simp	int i;
45952506Simp
46052506Simp	device_printf(dev, "CIS version ");
46152506Simp	if (card->cis1_major == 4) {
46252506Simp		if (card->cis1_minor == 0)
46352506Simp			printf("PCCARD 1.0\n");
46452506Simp		else if (card->cis1_minor == 1)
46552506Simp			printf("PCCARD 2.0 or 2.1\n");
46652506Simp	} else if (card->cis1_major >= 5)
46752506Simp		printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor);
46852506Simp	else
46952506Simp		printf("unknown (major=%d, minor=%d)\n",
47052506Simp		    card->cis1_major, card->cis1_minor);
47152506Simp
47252506Simp	device_printf(dev, "CIS info: ");
47352506Simp	for (i = 0; i < 4; i++) {
47452506Simp		if (card->cis1_info[i] == NULL)
47552506Simp			break;
47652506Simp		if (i)
47752506Simp			printf(", ");
47852506Simp		printf("%s", card->cis1_info[i]);
47952506Simp	}
48052506Simp	printf("\n");
48152506Simp
48252506Simp	device_printf(dev, "Manufacturer code 0x%x, product 0x%x\n",
48352506Simp	    card->manufacturer, card->product);
48452506Simp
48552506Simp	STAILQ_FOREACH(pf, &card->pf_head, pf_list) {
48652506Simp		device_printf(dev, "function %d: ", pf->number);
48752506Simp
48852506Simp		switch (pf->function) {
48952506Simp		case PCCARD_FUNCTION_UNSPEC:
49052506Simp			printf("unspecified");
49152506Simp			break;
49252506Simp		case PCCARD_FUNCTION_MULTIFUNCTION:
49352506Simp			printf("multi-function");
49452506Simp			break;
49552506Simp		case PCCARD_FUNCTION_MEMORY:
49652506Simp			printf("memory");
49752506Simp			break;
49852506Simp		case PCCARD_FUNCTION_SERIAL:
49952506Simp			printf("serial port");
50052506Simp			break;
50152506Simp		case PCCARD_FUNCTION_PARALLEL:
50252506Simp			printf("parallel port");
50352506Simp			break;
50452506Simp		case PCCARD_FUNCTION_DISK:
50552506Simp			printf("fixed disk");
50652506Simp			break;
50752506Simp		case PCCARD_FUNCTION_VIDEO:
50852506Simp			printf("video adapter");
50952506Simp			break;
51052506Simp		case PCCARD_FUNCTION_NETWORK:
51152506Simp			printf("network adapter");
51252506Simp			break;
51352506Simp		case PCCARD_FUNCTION_AIMS:
51452506Simp			printf("auto incrementing mass storage");
51552506Simp			break;
51652506Simp		case PCCARD_FUNCTION_SCSI:
51752506Simp			printf("SCSI bridge");
51852506Simp			break;
51952506Simp		case PCCARD_FUNCTION_SECURITY:
52052506Simp			printf("Security services");
52152506Simp			break;
52252506Simp		case PCCARD_FUNCTION_INSTRUMENT:
52352506Simp			printf("Instrument");
52452506Simp			break;
52552506Simp		default:
52652506Simp			printf("unknown (%d)", pf->function);
52752506Simp			break;
52852506Simp		}
52952506Simp
530106914Smux		printf(", ccr addr %x mask %x\n", pf->ccr_base, pf->ccr_mask);
53152506Simp
53252506Simp		STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
53352506Simp			device_printf(dev, "function %d, config table entry "
53452506Simp			    "%d: ", pf->number, cfe->number);
53552506Simp
53652506Simp			switch (cfe->iftype) {
53752506Simp			case PCCARD_IFTYPE_MEMORY:
53852506Simp				printf("memory card");
53952506Simp				break;
54052506Simp			case PCCARD_IFTYPE_IO:
54152506Simp				printf("I/O card");
54252506Simp				break;
54352506Simp			default:
54452506Simp				printf("card type unknown");
54552506Simp				break;
54652506Simp			}
54752506Simp
54852506Simp			printf("; irq mask %x", cfe->irqmask);
54952506Simp
55052506Simp			if (cfe->num_iospace) {
55152506Simp				printf("; iomask %lx, iospace", cfe->iomask);
55252506Simp
55353813Simp				for (i = 0; i < cfe->num_iospace; i++) {
55453813Simp					printf(" %lx", cfe->iospace[i].start);
55553813Simp					if (cfe->iospace[i].length)
55653813Simp						printf("-%lx",
55753813Simp						    cfe->iospace[i].start +
55853813Simp						    cfe->iospace[i].length - 1);
55953813Simp				}
56052506Simp			}
56152506Simp			if (cfe->num_memspace) {
56252506Simp				printf("; memspace");
56352506Simp
56453813Simp				for (i = 0; i < cfe->num_memspace; i++) {
56553813Simp					printf(" %lx",
56653813Simp					    cfe->memspace[i].cardaddr);
56753813Simp					if (cfe->memspace[i].length)
56853813Simp						printf("-%lx",
56953813Simp						    cfe->memspace[i].cardaddr +
57053813Simp						    cfe->memspace[i].length - 1);
57153813Simp					if (cfe->memspace[i].hostaddr)
57253813Simp						printf("@%lx",
57353813Simp						    cfe->memspace[i].hostaddr);
57453813Simp				}
57552506Simp			}
57652506Simp			if (cfe->maxtwins)
57752506Simp				printf("; maxtwins %d", cfe->maxtwins);
57852506Simp
57952506Simp			printf(";");
58052506Simp
58152506Simp			if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED)
58252506Simp				printf(" mwait_required");
58352506Simp			if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE)
58452506Simp				printf(" rdybsy_active");
58552506Simp			if (cfe->flags & PCCARD_CFE_WP_ACTIVE)
58652506Simp				printf(" wp_active");
58752506Simp			if (cfe->flags & PCCARD_CFE_BVD_ACTIVE)
58852506Simp				printf(" bvd_active");
58952506Simp			if (cfe->flags & PCCARD_CFE_IO8)
59052506Simp				printf(" io8");
59152506Simp			if (cfe->flags & PCCARD_CFE_IO16)
59252506Simp				printf(" io16");
59352506Simp			if (cfe->flags & PCCARD_CFE_IRQSHARE)
59452506Simp				printf(" irqshare");
59552506Simp			if (cfe->flags & PCCARD_CFE_IRQPULSE)
59652506Simp				printf(" irqpulse");
59752506Simp			if (cfe->flags & PCCARD_CFE_IRQLEVEL)
59852506Simp				printf(" irqlevel");
59952506Simp			if (cfe->flags & PCCARD_CFE_POWERDOWN)
60052506Simp				printf(" powerdown");
60152506Simp			if (cfe->flags & PCCARD_CFE_READONLY)
60252506Simp				printf(" readonly");
60352506Simp			if (cfe->flags & PCCARD_CFE_AUDIO)
60452506Simp				printf(" audio");
60552506Simp
60652506Simp			printf("\n");
60752506Simp		}
60852506Simp	}
60952506Simp
61052506Simp	if (card->error)
61152506Simp		device_printf(dev, "%d errors found while parsing CIS\n",
61252506Simp		    card->error);
61352506Simp}
61452506Simp
615147711Simpstatic int
616147729Simppccard_parse_cis_tuple(const struct pccard_tuple *tuple, void *arg)
61752506Simp{
61852506Simp	/* most of these are educated guesses */
61952506Simp	static struct pccard_config_entry init_cfe = {
62052506Simp		-1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE |
62152506Simp		PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY,
62252506Simp	};
62352506Simp
62452506Simp	struct cis_state *state = arg;
62552506Simp
62652506Simp	switch (tuple->code) {
627120868Simp	case CISTPL_END:
62852506Simp		/* if we've seen a LONGLINK_MFC, and this is the first
62952506Simp		 * END after it, reset the function list.
63052506Simp		 *
63152506Simp		 * XXX This might also be the right place to start a
63252506Simp		 * new function, but that assumes that a function
63352506Simp		 * definition never crosses any longlink, and I'm not
63452506Simp		 * sure about that.  This is probably safe for MFC
63552506Simp		 * cards, but what we have now isn't broken, so I'd
63652506Simp		 * rather not change it.
63752506Simp		 */
63852506Simp		if (state->gotmfc == 1) {
63952506Simp			struct pccard_function *pf, *pfnext;
64052506Simp
64152506Simp			for (pf = STAILQ_FIRST(&state->card->pf_head);
64252506Simp			     pf != NULL; pf = pfnext) {
64352506Simp				pfnext = STAILQ_NEXT(pf, pf_list);
64452506Simp				free(pf, M_DEVBUF);
64552506Simp			}
64652506Simp
64752506Simp			STAILQ_INIT(&state->card->pf_head);
64852506Simp
64952506Simp			state->count = 0;
65052506Simp			state->gotmfc = 2;
65152506Simp			state->pf = NULL;
65252506Simp		}
65352506Simp		break;
654120868Simp	case CISTPL_LONGLINK_MFC:
65552506Simp		/*
65652506Simp		 * this tuple's structure was dealt with in scan_cis.  here,
65752506Simp		 * record the fact that the MFC tuple was seen, so that
65852506Simp		 * functions declared before the MFC link can be cleaned
65952506Simp		 * up.
66052506Simp		 */
66152506Simp		state->gotmfc = 1;
66252506Simp		break;
66352506Simp#ifdef PCCARDCISDEBUG
664120868Simp	case CISTPL_DEVICE:
665120868Simp	case CISTPL_DEVICE_A:
66652506Simp		{
66752506Simp			u_int reg, dtype, dspeed;
66852506Simp
66952506Simp			reg = pccard_tuple_read_1(tuple, 0);
67052506Simp			dtype = reg & PCCARD_DTYPE_MASK;
67152506Simp			dspeed = reg & PCCARD_DSPEED_MASK;
67252506Simp
67352506Simp			DPRINTF(("CISTPL_DEVICE%s type=",
674120868Simp			(tuple->code == CISTPL_DEVICE) ? "" : "_A"));
67552506Simp			switch (dtype) {
67652506Simp			case PCCARD_DTYPE_NULL:
67752506Simp				DPRINTF(("null"));
67852506Simp				break;
67952506Simp			case PCCARD_DTYPE_ROM:
68052506Simp				DPRINTF(("rom"));
68152506Simp				break;
68252506Simp			case PCCARD_DTYPE_OTPROM:
68352506Simp				DPRINTF(("otprom"));
68452506Simp				break;
68552506Simp			case PCCARD_DTYPE_EPROM:
68652506Simp				DPRINTF(("eprom"));
68752506Simp				break;
68852506Simp			case PCCARD_DTYPE_EEPROM:
68952506Simp				DPRINTF(("eeprom"));
69052506Simp				break;
69152506Simp			case PCCARD_DTYPE_FLASH:
69252506Simp				DPRINTF(("flash"));
69352506Simp				break;
69452506Simp			case PCCARD_DTYPE_SRAM:
69552506Simp				DPRINTF(("sram"));
69652506Simp				break;
69752506Simp			case PCCARD_DTYPE_DRAM:
69852506Simp				DPRINTF(("dram"));
69952506Simp				break;
70052506Simp			case PCCARD_DTYPE_FUNCSPEC:
70152506Simp				DPRINTF(("funcspec"));
70252506Simp				break;
70352506Simp			case PCCARD_DTYPE_EXTEND:
70452506Simp				DPRINTF(("extend"));
70552506Simp				break;
70652506Simp			default:
70752506Simp				DPRINTF(("reserved"));
70852506Simp				break;
70952506Simp			}
71052506Simp			DPRINTF((" speed="));
71152506Simp			switch (dspeed) {
71252506Simp			case PCCARD_DSPEED_NULL:
71352506Simp				DPRINTF(("null"));
71452506Simp				break;
71552506Simp			case PCCARD_DSPEED_250NS:
71652506Simp				DPRINTF(("250ns"));
71752506Simp				break;
71852506Simp			case PCCARD_DSPEED_200NS:
71952506Simp				DPRINTF(("200ns"));
72052506Simp				break;
72152506Simp			case PCCARD_DSPEED_150NS:
72252506Simp				DPRINTF(("150ns"));
72352506Simp				break;
72452506Simp			case PCCARD_DSPEED_100NS:
72552506Simp				DPRINTF(("100ns"));
72652506Simp				break;
72752506Simp			case PCCARD_DSPEED_EXT:
72852506Simp				DPRINTF(("ext"));
72952506Simp				break;
73052506Simp			default:
73152506Simp				DPRINTF(("reserved"));
73252506Simp				break;
73352506Simp			}
73452506Simp		}
73552506Simp		DPRINTF(("\n"));
73652506Simp		break;
73752506Simp#endif
738120868Simp	case CISTPL_VERS_1:
73952506Simp		if (tuple->length < 6) {
74052506Simp			DPRINTF(("CISTPL_VERS_1 too short %d\n",
74152506Simp			    tuple->length));
74252506Simp			break;
74352506Simp		} {
74452506Simp			int start, i, ch, count;
74552506Simp
74652506Simp			state->card->cis1_major = pccard_tuple_read_1(tuple, 0);
74752506Simp			state->card->cis1_minor = pccard_tuple_read_1(tuple, 1);
74852506Simp
74952506Simp			for (count = 0, start = 0, i = 0;
75052506Simp			    (count < 4) && ((i + 4) < 256); i++) {
75152506Simp				ch = pccard_tuple_read_1(tuple, 2 + i);
75252506Simp				if (ch == 0xff)
75352506Simp					break;
75452506Simp				state->card->cis1_info_buf[i] = ch;
75552506Simp				if (ch == 0) {
75652506Simp					state->card->cis1_info[count] =
75752506Simp					    state->card->cis1_info_buf + start;
75852506Simp					start = i + 1;
75952506Simp					count++;
76052506Simp				}
76152506Simp			}
76252506Simp			DPRINTF(("CISTPL_VERS_1\n"));
76352506Simp		}
76452506Simp		break;
765120868Simp	case CISTPL_MANFID:
76652506Simp		if (tuple->length < 4) {
76752506Simp			DPRINTF(("CISTPL_MANFID too short %d\n",
76852506Simp			    tuple->length));
76952506Simp			break;
77052506Simp		}
77152506Simp		state->card->manufacturer = pccard_tuple_read_2(tuple, 0);
77252506Simp		state->card->product = pccard_tuple_read_2(tuple, 2);
77390964Sshiba		/*
774104604Simp		 * This is for xe driver. But not limited to that driver.
77590964Sshiba		 * In PC Card Standard,
77690964Sshiba		 * Manufacturer ID: 2byte.
777104604Simp		 * Product ID: typically 2bytes, but there's no limit on its
778104604Simp		 * size.  prodext is a two byte field, so maybe we should
779104604Simp		 * also handle the '6' case.  So far no cards have surfaced
780104604Simp		 * with a length of '6'.
78190964Sshiba		 */
782147962Simp		if (tuple->length == 5 )
78390964Sshiba			state->card->prodext = pccard_tuple_read_1(tuple, 4);
78452506Simp		DPRINTF(("CISTPL_MANFID\n"));
78552506Simp		break;
786120868Simp	case CISTPL_FUNCID:
78752506Simp		if (tuple->length < 1) {
78852506Simp			DPRINTF(("CISTPL_FUNCID too short %d\n",
78952506Simp			    tuple->length));
79052506Simp			break;
79152506Simp		}
79252506Simp		if ((state->pf == NULL) || (state->gotmfc == 2)) {
79352506Simp			state->pf = malloc(sizeof(*state->pf), M_DEVBUF,
79467897Sdwmalone			    M_NOWAIT | M_ZERO);
79552506Simp			state->pf->number = state->count++;
79652506Simp			state->pf->last_config_index = -1;
79752506Simp			STAILQ_INIT(&state->pf->cfe_head);
79852506Simp
79952506Simp			STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf,
80052506Simp			    pf_list);
80152506Simp		}
80252506Simp		state->pf->function = pccard_tuple_read_1(tuple, 0);
80352506Simp
80452506Simp		DPRINTF(("CISTPL_FUNCID\n"));
80552506Simp		break;
806120868Simp        case CISTPL_FUNCE:
80782781Sshiba                if (state->pf == NULL || state->pf->function <= 0) {
80882781Sshiba                        DPRINTF(("CISTPL_FUNCE is not followed by "
80982781Sshiba                                "valid CISTPL_FUNCID\n"));
81082781Sshiba                        break;
81182781Sshiba                }
812147729Simp                if (tuple->length >= 2)
81382781Sshiba                        decode_funce(tuple, state->pf);
81482781Sshiba                DPRINTF(("CISTPL_FUNCE\n"));
81582781Sshiba                break;
816120868Simp	case CISTPL_CONFIG:
81752506Simp		if (tuple->length < 3) {
81852506Simp			DPRINTF(("CISTPL_CONFIG too short %d\n",
81952506Simp			    tuple->length));
82052506Simp			break;
82152506Simp		} {
82252506Simp			u_int reg, rasz, rmsz, rfsz;
82352506Simp			int i;
82452506Simp
82552506Simp			reg = pccard_tuple_read_1(tuple, 0);
82652506Simp			rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >>
82752506Simp			    PCCARD_TPCC_RASZ_SHIFT);
82852506Simp			rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >>
82952506Simp			    PCCARD_TPCC_RMSZ_SHIFT);
83052506Simp			rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >>
83152506Simp			    PCCARD_TPCC_RFSZ_SHIFT);
83252506Simp
83352506Simp			if (tuple->length < (rasz + rmsz + rfsz)) {
83452506Simp				DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too "
83552506Simp				    "short %d\n", rasz, rmsz, rfsz,
83652506Simp				    tuple->length));
83752506Simp				break;
83852506Simp			}
83952506Simp			if (state->pf == NULL) {
84052506Simp				state->pf = malloc(sizeof(*state->pf),
84167897Sdwmalone				    M_DEVBUF, M_NOWAIT | M_ZERO);
84252506Simp				state->pf->number = state->count++;
84352506Simp				state->pf->last_config_index = -1;
84452506Simp				STAILQ_INIT(&state->pf->cfe_head);
84552506Simp
84652506Simp				STAILQ_INSERT_TAIL(&state->card->pf_head,
84752506Simp				    state->pf, pf_list);
84852506Simp
84952506Simp				state->pf->function = PCCARD_FUNCTION_UNSPEC;
85052506Simp			}
85152506Simp			state->pf->last_config_index =
85252506Simp			    pccard_tuple_read_1(tuple, 1);
85352506Simp
85452506Simp			state->pf->ccr_base = 0;
85552506Simp			for (i = 0; i < rasz; i++)
85652506Simp				state->pf->ccr_base |=
85752506Simp				    ((pccard_tuple_read_1(tuple, 2 + i)) <<
85852506Simp				    (i * 8));
85952506Simp
86052506Simp			state->pf->ccr_mask = 0;
86152506Simp			for (i = 0; i < rmsz; i++)
86252506Simp				state->pf->ccr_mask |=
86352506Simp				    ((pccard_tuple_read_1(tuple,
86452506Simp				    2 + rasz + i)) << (i * 8));
86552506Simp
86652506Simp			/* skip the reserved area and subtuples */
86752506Simp
86852506Simp			/* reset the default cfe for each cfe list */
86952506Simp			state->temp_cfe = init_cfe;
87052506Simp			state->default_cfe = &state->temp_cfe;
87152506Simp		}
87252506Simp		DPRINTF(("CISTPL_CONFIG\n"));
87352506Simp		break;
874120868Simp	case CISTPL_CFTABLE_ENTRY:
87552506Simp		{
87652506Simp			int idx, i, j;
87752506Simp			u_int reg, reg2;
87852506Simp			u_int intface, def, num;
87952506Simp			u_int power, timing, iospace, irq, memspace, misc;
88052506Simp			struct pccard_config_entry *cfe;
88152506Simp
88252506Simp			idx = 0;
88352506Simp
88452506Simp			reg = pccard_tuple_read_1(tuple, idx);
88552506Simp			idx++;
88652506Simp			intface = reg & PCCARD_TPCE_INDX_INTFACE;
88752506Simp			def = reg & PCCARD_TPCE_INDX_DEFAULT;
88852506Simp			num = reg & PCCARD_TPCE_INDX_NUM_MASK;
88952506Simp
89052506Simp			/*
89152506Simp			 * this is a little messy.  Some cards have only a
89252506Simp			 * cfentry with the default bit set.  So, as we go
89352506Simp			 * through the list, we add new indexes to the queue,
89452506Simp			 * and keep a pointer to the last one with the
89552506Simp			 * default bit set.  if we see a record with the same
89652506Simp			 * index, as the default, we stash the default and
89752506Simp			 * replace the queue entry. otherwise, we just add
89852506Simp			 * new entries to the queue, pointing the default ptr
89952506Simp			 * at them if the default bit is set.  if we get to
90052506Simp			 * the end with the default pointer pointing at a
90152506Simp			 * record which hasn't had a matching index, that's
90252506Simp			 * ok; it just becomes a cfentry like any other.
90352506Simp			 */
90452506Simp
90552506Simp			/*
90652506Simp			 * if the index in the cis differs from the default
90752506Simp			 * cis, create new entry in the queue and start it
90852506Simp			 * with the current default
90952506Simp			 */
91052506Simp			if (num != state->default_cfe->number) {
91152506Simp				cfe = (struct pccard_config_entry *)
91252506Simp				    malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
913144159Ssam				if (cfe == NULL) {
914144159Ssam					DPRINTF(("no memory for config entry\n"));
915144159Ssam					goto abort_cfe;
916144159Ssam				}
91752506Simp				*cfe = *state->default_cfe;
91852506Simp
91952506Simp				STAILQ_INSERT_TAIL(&state->pf->cfe_head,
92052506Simp				    cfe, cfe_list);
92152506Simp
92252506Simp				cfe->number = num;
92352506Simp
92452506Simp				/*
92552506Simp				 * if the default bit is set in the cis, then
92652506Simp				 * point the new default at whatever is being
92752506Simp				 * filled in
92852506Simp				 */
92952506Simp				if (def)
93052506Simp					state->default_cfe = cfe;
93152506Simp			} else {
93252506Simp				/*
93352506Simp				 * the cis index matches the default index,
93452506Simp				 * fill in the default cfentry.  It is
93552506Simp				 * assumed that the cfdefault index is in the
93652506Simp				 * queue.  For it to be otherwise, the cis
93752506Simp				 * index would have to be -1 (initial
93852506Simp				 * condition) which is not possible, or there
93952506Simp				 * would have to be a preceding cis entry
94052506Simp				 * which had the same cis index and had the
94152506Simp				 * default bit unset. Neither condition
94252506Simp				 * should happen.  If it does, this cfentry
94352506Simp				 * is lost (written into temp space), which
94452506Simp				 * is an acceptable failure mode.
94552506Simp				 */
94652506Simp
94752506Simp				cfe = state->default_cfe;
94852506Simp
94952506Simp				/*
95052506Simp				 * if the cis entry does not have the default
95152506Simp				 * bit set, copy the default out of the way
95252506Simp				 * first.
95352506Simp				 */
95452506Simp				if (!def) {
95552506Simp					state->temp_cfe = *state->default_cfe;
95652506Simp					state->default_cfe = &state->temp_cfe;
95752506Simp				}
95852506Simp			}
95952506Simp
96052506Simp			if (intface) {
96152506Simp				reg = pccard_tuple_read_1(tuple, idx);
96252506Simp				idx++;
963104640Simp				cfe->flags &= ~(PCCARD_CFE_MWAIT_REQUIRED
964104640Simp				    | PCCARD_CFE_RDYBSY_ACTIVE
965104640Simp				    | PCCARD_CFE_WP_ACTIVE
966104640Simp				    | PCCARD_CFE_BVD_ACTIVE);
96752506Simp				if (reg & PCCARD_TPCE_IF_MWAIT)
96852506Simp					cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED;
96952506Simp				if (reg & PCCARD_TPCE_IF_RDYBSY)
97052506Simp					cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE;
97152506Simp				if (reg & PCCARD_TPCE_IF_WP)
97252506Simp					cfe->flags |= PCCARD_CFE_WP_ACTIVE;
97352506Simp				if (reg & PCCARD_TPCE_IF_BVD)
97452506Simp					cfe->flags |= PCCARD_CFE_BVD_ACTIVE;
97552506Simp				cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE;
97652506Simp			}
97752506Simp			reg = pccard_tuple_read_1(tuple, idx);
97852506Simp			idx++;
97952506Simp
98052506Simp			power = reg & PCCARD_TPCE_FS_POWER_MASK;
98152506Simp			timing = reg & PCCARD_TPCE_FS_TIMING;
98252506Simp			iospace = reg & PCCARD_TPCE_FS_IOSPACE;
98352506Simp			irq = reg & PCCARD_TPCE_FS_IRQ;
98452506Simp			memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK;
98552506Simp			misc = reg & PCCARD_TPCE_FS_MISC;
98652506Simp
98752506Simp			if (power) {
98852506Simp				/* skip over power, don't save */
98952506Simp				/* for each parameter selection byte */
99052506Simp				for (i = 0; i < power; i++) {
99152506Simp					reg = pccard_tuple_read_1(tuple, idx);
99252506Simp					idx++;
99352506Simp					/* for each bit */
99452506Simp					for (j = 0; j < 7; j++) {
99552506Simp						/* if the bit is set */
99652506Simp						if ((reg >> j) & 0x01) {
99752506Simp							/* skip over bytes */
99852506Simp							do {
99952506Simp								reg2 = pccard_tuple_read_1(tuple, idx);
100052506Simp								idx++;
100152506Simp								/*
100252506Simp								 * until
100352506Simp								 * non-extensi
100452506Simp								 * on byte
100552506Simp								 */
100652506Simp							} while (reg2 & 0x80);
100752506Simp						}
100852506Simp					}
100952506Simp				}
101052506Simp			}
101152506Simp			if (timing) {
101252506Simp				/* skip over timing, don't save */
101352506Simp				reg = pccard_tuple_read_1(tuple, idx);
101452506Simp				idx++;
101552506Simp
101652506Simp				if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) !=
101752506Simp				    PCCARD_TPCE_TD_RESERVED_MASK)
101852506Simp					idx++;
101952506Simp				if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) !=
102052506Simp				    PCCARD_TPCE_TD_RDYBSY_MASK)
102152506Simp					idx++;
102252506Simp				if ((reg & PCCARD_TPCE_TD_WAIT_MASK) !=
102352506Simp				    PCCARD_TPCE_TD_WAIT_MASK)
102452506Simp					idx++;
102552506Simp			}
102652506Simp			if (iospace) {
102752506Simp				if (tuple->length <= idx) {
102852506Simp					DPRINTF(("ran out of space before TCPE_IO\n"));
102952506Simp					goto abort_cfe;
103052506Simp				}
103152506Simp
103252506Simp				reg = pccard_tuple_read_1(tuple, idx);
103352506Simp				idx++;
1034104640Simp				cfe->flags &=
1035104640Simp				    ~(PCCARD_CFE_IO8 | PCCARD_CFE_IO16);
103652506Simp				if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT)
103752506Simp					cfe->flags |= PCCARD_CFE_IO8;
103852506Simp				if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT)
103952506Simp					cfe->flags |= PCCARD_CFE_IO16;
104052506Simp				cfe->iomask =
104152506Simp				    reg & PCCARD_TPCE_IO_IOADDRLINES_MASK;
104252506Simp
104352506Simp				if (reg & PCCARD_TPCE_IO_HASRANGE) {
104452506Simp					reg = pccard_tuple_read_1(tuple, idx);
104552506Simp					idx++;
104652506Simp
104752506Simp					cfe->num_iospace = 1 + (reg &
104852506Simp					    PCCARD_TPCE_IO_RANGE_COUNT);
104952506Simp
105052506Simp					if (cfe->num_iospace >
105152506Simp					    (sizeof(cfe->iospace) /
105252506Simp					     sizeof(cfe->iospace[0]))) {
105352506Simp						DPRINTF(("too many io "
105452506Simp						    "spaces %d",
105552506Simp						    cfe->num_iospace));
105652506Simp						state->card->error++;
105752506Simp						break;
105852506Simp					}
105952506Simp					for (i = 0; i < cfe->num_iospace; i++) {
106052506Simp						switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) {
106152506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE:
106252506Simp							cfe->iospace[i].start =
106352506Simp								pccard_tuple_read_1(tuple, idx);
106452506Simp							idx++;
106552506Simp							break;
106652506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO:
106752506Simp							cfe->iospace[i].start =
106852506Simp								pccard_tuple_read_2(tuple, idx);
106952506Simp							idx += 2;
107052506Simp							break;
107152506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR:
107252506Simp							cfe->iospace[i].start =
107352506Simp								pccard_tuple_read_4(tuple, idx);
107452506Simp							idx += 4;
107552506Simp							break;
107652506Simp						}
107752506Simp						switch (reg &
107852506Simp							PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) {
107952506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE:
108052506Simp							cfe->iospace[i].length =
108152506Simp								pccard_tuple_read_1(tuple, idx);
108252506Simp							idx++;
108352506Simp							break;
108452506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO:
108552506Simp							cfe->iospace[i].length =
108652506Simp								pccard_tuple_read_2(tuple, idx);
108752506Simp							idx += 2;
108852506Simp							break;
108952506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR:
109052506Simp							cfe->iospace[i].length =
109152506Simp								pccard_tuple_read_4(tuple, idx);
109252506Simp							idx += 4;
109352506Simp							break;
109452506Simp						}
109552506Simp						cfe->iospace[i].length++;
109652506Simp					}
109752506Simp				} else {
109852506Simp					cfe->num_iospace = 1;
109952506Simp					cfe->iospace[0].start = 0;
110052506Simp					cfe->iospace[0].length =
110152506Simp					    (1 << cfe->iomask);
110252506Simp				}
110352506Simp			}
110452506Simp			if (irq) {
110552506Simp				if (tuple->length <= idx) {
110652506Simp					DPRINTF(("ran out of space before TCPE_IR\n"));
110752506Simp					goto abort_cfe;
110852506Simp				}
110952506Simp
111052506Simp				reg = pccard_tuple_read_1(tuple, idx);
111152506Simp				idx++;
1112104640Simp				cfe->flags &= ~(PCCARD_CFE_IRQSHARE
1113104640Simp				    | PCCARD_CFE_IRQPULSE
1114104640Simp				    | PCCARD_CFE_IRQLEVEL);
111552506Simp				if (reg & PCCARD_TPCE_IR_SHARE)
111652506Simp					cfe->flags |= PCCARD_CFE_IRQSHARE;
111752506Simp				if (reg & PCCARD_TPCE_IR_PULSE)
111852506Simp					cfe->flags |= PCCARD_CFE_IRQPULSE;
111952506Simp				if (reg & PCCARD_TPCE_IR_LEVEL)
112052506Simp					cfe->flags |= PCCARD_CFE_IRQLEVEL;
112152506Simp
112252506Simp				if (reg & PCCARD_TPCE_IR_HASMASK) {
112352506Simp					/*
112452506Simp					 * it's legal to ignore the
112552506Simp					 * special-interrupt bits, so I will
112652506Simp					 */
112752506Simp
112852506Simp					cfe->irqmask =
112952506Simp					    pccard_tuple_read_2(tuple, idx);
113052506Simp					idx += 2;
113152506Simp				} else {
113252506Simp					cfe->irqmask =
113352506Simp					    (1 << (reg & PCCARD_TPCE_IR_IRQ));
113452506Simp				}
113552506Simp			}
113652506Simp			if (memspace) {
113752506Simp				if (tuple->length <= idx) {
113852506Simp					DPRINTF(("ran out of space before TCPE_MS\n"));
113952506Simp					goto abort_cfe;
114052506Simp				}
114152506Simp
1142142027Simp				if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) {
114352506Simp					cfe->num_memspace = 1;
114452506Simp					cfe->memspace[0].length = 256 *
114552506Simp					    pccard_tuple_read_2(tuple, idx);
114652506Simp					idx += 2;
114752506Simp					cfe->memspace[0].cardaddr = 0;
114852506Simp					cfe->memspace[0].hostaddr = 0;
114952506Simp				} else if (memspace ==
115052506Simp				    PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) {
115152506Simp					cfe->num_memspace = 1;
115252506Simp					cfe->memspace[0].length = 256 *
115352506Simp					    pccard_tuple_read_2(tuple, idx);
115452506Simp					idx += 2;
115552506Simp					cfe->memspace[0].cardaddr = 256 *
115652506Simp					    pccard_tuple_read_2(tuple, idx);
115752506Simp					idx += 2;
115852506Simp					cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr;
115952506Simp				} else {
116052506Simp					int lengthsize;
116152506Simp					int cardaddrsize;
116252506Simp					int hostaddrsize;
116352506Simp
116452506Simp					reg = pccard_tuple_read_1(tuple, idx);
116552506Simp					idx++;
116652506Simp
116753873Simp					cfe->num_memspace = (reg &
116853873Simp					    PCCARD_TPCE_MS_COUNT) + 1;
116952506Simp
117052506Simp					if (cfe->num_memspace >
117152506Simp					    (sizeof(cfe->memspace) /
117252506Simp					     sizeof(cfe->memspace[0]))) {
117352506Simp						DPRINTF(("too many mem "
117452506Simp						    "spaces %d",
117552506Simp						    cfe->num_memspace));
117652506Simp						state->card->error++;
117752506Simp						break;
117852506Simp					}
117952506Simp					lengthsize =
118052506Simp						((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >>
118152506Simp						 PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT);
118252506Simp					cardaddrsize =
118352506Simp						((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >>
118452506Simp						 PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT);
118552506Simp					hostaddrsize =
118652506Simp						(reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0;
118752506Simp
118852506Simp					if (lengthsize == 0) {
118952506Simp						DPRINTF(("cfe memspace "
119052506Simp						    "lengthsize == 0"));
119152506Simp						state->card->error++;
119252506Simp					}
119352506Simp					for (i = 0; i < cfe->num_memspace; i++) {
119452506Simp						if (lengthsize) {
119552506Simp							cfe->memspace[i].length =
119652506Simp								256 * pccard_tuple_read_n(tuple, lengthsize,
119752506Simp								       idx);
119852506Simp							idx += lengthsize;
119952506Simp						} else {
120052506Simp							cfe->memspace[i].length = 0;
120152506Simp						}
120252506Simp						if (cfe->memspace[i].length == 0) {
120352506Simp							DPRINTF(("cfe->memspace[%d].length == 0",
120452506Simp								 i));
120552506Simp							state->card->error++;
120652506Simp						}
120752506Simp						if (cardaddrsize) {
120852506Simp							cfe->memspace[i].cardaddr =
120952506Simp								256 * pccard_tuple_read_n(tuple, cardaddrsize,
121052506Simp								       idx);
121152506Simp							idx += cardaddrsize;
121252506Simp						} else {
121352506Simp							cfe->memspace[i].cardaddr = 0;
121452506Simp						}
121552506Simp						if (hostaddrsize) {
121652506Simp							cfe->memspace[i].hostaddr =
121752506Simp								256 * pccard_tuple_read_n(tuple, hostaddrsize,
121852506Simp								       idx);
121952506Simp							idx += hostaddrsize;
122052506Simp						} else {
122152506Simp							cfe->memspace[i].hostaddr = 0;
122252506Simp						}
122352506Simp					}
122452506Simp				}
1225142027Simp			} else
1226142027Simp				cfe->num_memspace = 0;
122752506Simp			if (misc) {
122852506Simp				if (tuple->length <= idx) {
122952506Simp					DPRINTF(("ran out of space before TCPE_MI\n"));
123052506Simp					goto abort_cfe;
123152506Simp				}
123252506Simp
123352506Simp				reg = pccard_tuple_read_1(tuple, idx);
123452506Simp				idx++;
1235104640Simp				cfe->flags &= ~(PCCARD_CFE_POWERDOWN
1236104640Simp				    | PCCARD_CFE_READONLY
1237104640Simp				    | PCCARD_CFE_AUDIO);
123852506Simp				if (reg & PCCARD_TPCE_MI_PWRDOWN)
1239104640Simp					cfe->flags |= PCCARD_CFE_POWERDOWN;
124052506Simp				if (reg & PCCARD_TPCE_MI_READONLY)
1241104640Simp					cfe->flags |= PCCARD_CFE_READONLY;
124252506Simp				if (reg & PCCARD_TPCE_MI_AUDIO)
1243104640Simp					cfe->flags |= PCCARD_CFE_AUDIO;
124452506Simp				cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS;
124552506Simp
124652506Simp				while (reg & PCCARD_TPCE_MI_EXT) {
124752506Simp					reg = pccard_tuple_read_1(tuple, idx);
124852506Simp					idx++;
124952506Simp				}
125052506Simp			}
125152506Simp			/* skip all the subtuples */
125252506Simp		}
125352506Simp
125452506Simp	abort_cfe:
125552506Simp		DPRINTF(("CISTPL_CFTABLE_ENTRY\n"));
125652506Simp		break;
125752506Simp	default:
125852506Simp		DPRINTF(("unhandled CISTPL %x\n", tuple->code));
125952506Simp		break;
126052506Simp	}
126152506Simp
126252506Simp	return (0);
126352506Simp}
126482781Sshiba
126582781Sshibastatic int
1266147729Simpdecode_funce(const struct pccard_tuple *tuple, struct pccard_function *pf)
126782781Sshiba{
1268140542Simp	int i;
1269140542Simp	int len;
127082781Sshiba	int type = pccard_tuple_read_1(tuple, 0);
127182781Sshiba
127282781Sshiba	switch (pf->function) {
127382781Sshiba	case PCCARD_FUNCTION_DISK:
127482781Sshiba		if (type == PCCARD_TPLFE_TYPE_DISK_DEVICE_INTERFACE) {
127582781Sshiba			pf->pf_funce_disk_interface
127682781Sshiba				= pccard_tuple_read_1(tuple, 1);
127782781Sshiba		}
127882781Sshiba		break;
127982781Sshiba	case PCCARD_FUNCTION_NETWORK:
128082781Sshiba		if (type == PCCARD_TPLFE_TYPE_LAN_NID) {
1281140542Simp			len = pccard_tuple_read_1(tuple, 1);
128282781Sshiba			if (tuple->length < 2 + len || len > 8) {
128382781Sshiba				/* tuple length not enough or nid too long */
128482781Sshiba				break;
128582781Sshiba                        }
128682781Sshiba			for (i = 0; i < len; i++) {
128782781Sshiba				pf->pf_funce_lan_nid[i]
128882781Sshiba					= pccard_tuple_read_1(tuple, i + 2);
128982781Sshiba			}
129082781Sshiba			pf->pf_funce_lan_nidlen = len;
129182781Sshiba		}
129282781Sshiba		break;
129382781Sshiba	default:
129482781Sshiba		break;
129582781Sshiba	}
129682781Sshiba	return 0;
129782781Sshiba}
1298