pccard_cis.c revision 104640
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 104640 2002-10-07 23:03:17Z imp $ */
352506Simp
452506Simp/*
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>
4852506Simp
4959193Simp#include "card_if.h"
5059193Simp
5191786Simpextern int	pccard_cis_debug;
5291786Simp
5359193Simp#define PCCARDCISDEBUG
5452506Simp#ifdef PCCARDCISDEBUG
5591786Simp#define	DPRINTF(arg) if (pccard_cis_debug) printf arg
5691786Simp#define	DEVPRINTF(arg) if (pccard_cis_debug) device_printf arg
5752506Simp#else
5852506Simp#define	DPRINTF(arg)
5955720Simp#define	DEVPRINTF(arg)
6052506Simp#endif
6152506Simp
6252506Simp#define	PCCARD_CIS_SIZE		1024
6352506Simp
6452506Simpstruct cis_state {
6552506Simp	int	count;
6652506Simp	int	gotmfc;
6752506Simp	struct pccard_config_entry temp_cfe;
6852506Simp	struct pccard_config_entry *default_cfe;
6952506Simp	struct pccard_card *card;
7052506Simp	struct pccard_function *pf;
7152506Simp};
7252506Simp
7354250Simpint	pccard_parse_cis_tuple(struct pccard_tuple *, void *);
7482781Sshibastatic int decode_funce(struct pccard_tuple *, struct pccard_function *);
7552506Simp
7652506Simpvoid
7755720Simppccard_read_cis(struct pccard_softc *sc)
7852506Simp{
7952506Simp	struct cis_state state;
8052506Simp
81104640Simp	bzero(&state, sizeof state);
8252506Simp
8352506Simp	state.card = &sc->card;
8452506Simp
8552506Simp	state.card->error = 0;
8652506Simp	state.card->cis1_major = -1;
8752506Simp	state.card->cis1_minor = -1;
8852506Simp	state.card->cis1_info[0] = NULL;
8952506Simp	state.card->cis1_info[1] = NULL;
9052506Simp	state.card->cis1_info[2] = NULL;
9152506Simp	state.card->cis1_info[3] = NULL;
9286272Simp	state.card->manufacturer = PCMCIA_VENDOR_INVALID;
9386272Simp	state.card->product = PCMCIA_PRODUCT_INVALID;
9452506Simp	STAILQ_INIT(&state.card->pf_head);
9552506Simp
9652506Simp	state.pf = NULL;
9752506Simp
9858997Simp	if (pccard_scan_cis(sc->dev, pccard_parse_cis_tuple,
9952506Simp	    &state) == -1)
10052506Simp		state.card->error++;
10152506Simp}
10252506Simp
10352506Simpint
10455720Simppccard_scan_cis(device_t dev, int (*fct)(struct pccard_tuple *, void *),
10555720Simp	void *arg)
10652506Simp{
10755720Simp	struct resource *res;
10855720Simp	int rid;
10952506Simp	struct pccard_tuple tuple;
11052506Simp	int longlink_present;
11152506Simp	int longlink_common;
11252506Simp	u_long longlink_addr;
11352506Simp	int mfc_count;
11452506Simp	int mfc_index;
11552506Simp	struct {
11652506Simp		int	common;
11752506Simp		u_long	addr;
11852506Simp	} mfc[256 / 5];
11952506Simp	int ret;
12052506Simp
12152506Simp	ret = 0;
12252506Simp
12352506Simp	/* allocate some memory */
12452506Simp
12555720Simp	rid = 0;
12655720Simp	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0,
12759193Simp	    PCCARD_CIS_SIZE, RF_ACTIVE);
12855720Simp	if (res == NULL) {
12955720Simp		device_printf(dev, "can't alloc memory to read attributes\n");
13052506Simp		return -1;
13152506Simp	}
13259193Simp	CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
13359193Simp	    rid, PCCARD_A_MEM_ATTR);
13455720Simp	tuple.memt = rman_get_bustag(res);
13555720Simp	tuple.memh = rman_get_bushandle(res);
13659389Simp	tuple.ptr = 0;
13752506Simp
13852506Simp	DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh));
13955720Simp
14052506Simp	tuple.mult = 2;
14152506Simp
14252506Simp	longlink_present = 1;
14352506Simp	longlink_common = 1;
14452506Simp	longlink_addr = 0;
14552506Simp
14652506Simp	mfc_count = 0;
14752506Simp	mfc_index = 0;
14852506Simp
14955720Simp	DEVPRINTF((dev, "CIS tuple chain:\n"));
15052506Simp
15152506Simp	while (1) {
15252506Simp		while (1) {
15352506Simp			/* get the tuple code */
15452506Simp
15552506Simp			tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
15652506Simp
15752506Simp			/* two special-case tuples */
15852506Simp
15952506Simp			if (tuple.code == PCCARD_CISTPL_NULL) {
16052506Simp				DPRINTF(("CISTPL_NONE\n 00\n"));
16152506Simp				tuple.ptr++;
16252506Simp				continue;
16352506Simp			} else if (tuple.code == PCCARD_CISTPL_END) {
16452506Simp				DPRINTF(("CISTPL_END\n ff\n"));
16552506Simp				/* Call the function for the END tuple, since
16652506Simp				   the CIS semantics depend on it */
16752506Simp				if ((*fct) (&tuple, arg)) {
16852506Simp					ret = 1;
16952506Simp					goto done;
17052506Simp				}
17152506Simp				tuple.ptr++;
17252506Simp				break;
17352506Simp			}
17452506Simp			/* now all the normal tuples */
17552506Simp
17652506Simp			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
17752506Simp			switch (tuple.code) {
17852506Simp			case PCCARD_CISTPL_LONGLINK_A:
17952506Simp			case PCCARD_CISTPL_LONGLINK_C:
18052506Simp				if (tuple.length < 4) {
18152506Simp					DPRINTF(("CISTPL_LONGLINK_%s too "
18252506Simp					    "short %d\n",
18352506Simp					    longlink_common ? "C" : "A",
18452506Simp					    tuple.length));
18552506Simp					break;
18652506Simp				}
18752506Simp				longlink_present = 1;
18852506Simp				longlink_common = (tuple.code ==
18952506Simp				    PCCARD_CISTPL_LONGLINK_C) ? 1 : 0;
19052506Simp				longlink_addr = pccard_tuple_read_4(&tuple, 0);
19152506Simp				DPRINTF(("CISTPL_LONGLINK_%s %lx\n",
19252506Simp				    longlink_common ? "C" : "A",
19352506Simp				    longlink_addr));
19452506Simp				break;
19552506Simp			case PCCARD_CISTPL_NO_LINK:
19652506Simp				longlink_present = 0;
19752506Simp				DPRINTF(("CISTPL_NO_LINK\n"));
19852506Simp				break;
19952506Simp			case PCCARD_CISTPL_CHECKSUM:
20052506Simp				if (tuple.length < 5) {
20152506Simp					DPRINTF(("CISTPL_CHECKSUM too "
20252506Simp					    "short %d\n", tuple.length));
20352506Simp					break;
20452506Simp				} {
20552506Simp					int16_t offset;
20652506Simp					u_long addr, length;
20752506Simp					u_int cksum, sum;
20852506Simp					int i;
20952506Simp
21090896Simp					offset = (uint16_t)
21152506Simp					    pccard_tuple_read_2(&tuple, 0);
21252506Simp					length = pccard_tuple_read_2(&tuple, 2);
21352506Simp					cksum = pccard_tuple_read_1(&tuple, 4);
21452506Simp
21552506Simp					addr = tuple.ptr + offset;
21652506Simp
21752506Simp					DPRINTF(("CISTPL_CHECKSUM addr=%lx "
21852506Simp					    "len=%lx cksum=%x",
21952506Simp					    addr, length, cksum));
22052506Simp
22152506Simp					/*
22252506Simp					 * XXX do more work to deal with
22352506Simp					 * distant regions
22452506Simp					 */
22552506Simp					if ((addr >= PCCARD_CIS_SIZE) ||
22652506Simp					    ((addr + length) >=
227104640Simp					    PCCARD_CIS_SIZE)) {
22852506Simp						DPRINTF((" skipped, "
22952506Simp						    "too distant\n"));
23052506Simp						break;
23152506Simp					}
23252506Simp					sum = 0;
23352506Simp					for (i = 0; i < length; i++)
23452506Simp						sum +=
23552506Simp						    bus_space_read_1(tuple.memt,
23652506Simp						    tuple.memh,
23752506Simp						    addr + tuple.mult * i);
23852506Simp					if (cksum != (sum & 0xff)) {
23952506Simp						DPRINTF((" failed sum=%x\n",
24052506Simp						    sum));
24155720Simp						device_printf(dev,
24255720Simp						    "CIS checksum failed\n");
24352506Simp#if 0
24452506Simp						/*
24552506Simp						 * XXX Some working cards have
24652506Simp						 * XXX bad checksums!!
24752506Simp						 */
24852506Simp						ret = -1;
24952506Simp#endif
25052506Simp					} else {
25152506Simp						DPRINTF((" ok\n"));
25252506Simp					}
25352506Simp				}
25452506Simp				break;
25552506Simp			case PCCARD_CISTPL_LONGLINK_MFC:
25652506Simp				if (tuple.length < 1) {
25752506Simp					DPRINTF(("CISTPL_LONGLINK_MFC too "
25852506Simp					    "short %d\n", tuple.length));
25952506Simp					break;
26052506Simp				}
261104640Simp				if (((tuple.length - 1) % 5) != 0) {
262104640Simp					DPRINTF(("CISTPL_LONGLINK_MFC bogus "
263104640Simp					    "length %d\n", tuple.length));
264104640Simp					break;
265104640Simp				}
26652506Simp				/*
26752506Simp				 * this is kind of ad hoc, as I don't have
26852506Simp				 * any real documentation
26952506Simp				 */
27052506Simp				{
271104640Simp					int i, tmp_count;
27252506Simp
273104640Simp					/*
274104640Simp					 * put count into tmp var so that
275104640Simp					 * if we have to bail (because it's
276104640Simp					 * a bogus count) it won't be
277104640Simp					 * remembered for later use.
278104640Simp					 */
279104640Simp					tmp_count =
28052506Simp					    pccard_tuple_read_1(&tuple, 0);
281104640Simp
28252506Simp					DPRINTF(("CISTPL_LONGLINK_MFC %d",
283104640Simp					    tmp_count));
284104640Simp
285104640Simp					/*
286104640Simp					 * make _sure_ it's the right size;
287104640Simp					 * if too short, it may be a weird
288104640Simp					 * (unknown/undefined) format
289104640Simp					 */
290104640Simp					if (tuple.length != (tmp_count*5 + 1)) {
291104640Simp						DPRINTF((" bogus length %d\n",
292104640Simp						    tuple.length));
293104640Simp						break;
294104640Simp					}
295104640Simp					/*
296104640Simp					 * sanity check for a programming
297104640Simp					 * error which is difficult to find
298104640Simp					 * when debugging.
299104640Simp					 */
300104640Simp					if (tmp_count >
301104640Simp					    howmany(sizeof mfc, sizeof mfc[0]))
302104640Simp						panic("CISTPL_LONGLINK_MFC mfc "
303104640Simp						    "count would blow stack");
304104640Simp                                        mfc_count = tmp_count;
30552506Simp					for (i = 0; i < mfc_count; i++) {
30652506Simp						mfc[i].common =
30752506Simp						    (pccard_tuple_read_1(&tuple,
30852506Simp						    1 + 5 * i) ==
30952506Simp						    PCCARD_MFC_MEM_COMMON) ?
31052506Simp						    1 : 0;
31152506Simp						mfc[i].addr =
31252506Simp						    pccard_tuple_read_4(&tuple,
31352506Simp						    1 + 5 * i + 1);
31452506Simp						DPRINTF((" %s:%lx",
31552506Simp						    mfc[i].common ? "common" :
31652506Simp						    "attr", mfc[i].addr));
31752506Simp					}
31852506Simp					DPRINTF(("\n"));
31952506Simp				}
32052506Simp				/*
32152506Simp				 * for LONGLINK_MFC, fall through to the
32252506Simp				 * function.  This tuple has structural and
32352506Simp				 * semantic content.
32452506Simp				 */
32552506Simp			default:
32652506Simp				{
32752506Simp					if ((*fct) (&tuple, arg)) {
32852506Simp						ret = 1;
32952506Simp						goto done;
33052506Simp					}
33152506Simp				}
33252506Simp				break;
33352506Simp			}	/* switch */
33452506Simp#ifdef PCCARDCISDEBUG
33552506Simp			/* print the tuple */
33652506Simp			{
33752506Simp				int i;
33852506Simp
33952506Simp				DPRINTF((" %02x %02x", tuple.code,
34052506Simp				    tuple.length));
34152506Simp
34252506Simp				for (i = 0; i < tuple.length; i++) {
34352506Simp					DPRINTF((" %02x",
34452506Simp					    pccard_tuple_read_1(&tuple, i)));
34552506Simp					if ((i % 16) == 13)
34652506Simp						DPRINTF(("\n"));
34752506Simp				}
34887352Simp
34952506Simp				if ((i % 16) != 14)
35052506Simp					DPRINTF(("\n"));
35152506Simp			}
35252506Simp#endif
35352506Simp			/* skip to the next tuple */
35452506Simp			tuple.ptr += 2 + tuple.length;
35552506Simp		}
35652506Simp
35752506Simp		/*
35852506Simp		 * the chain is done.  Clean up and move onto the next one,
35952506Simp		 * if any.  The loop is here in the case that there is an MFC
36052506Simp		 * card with no longlink (which defaults to existing, == 0).
36152506Simp		 * In general, this means that if one pointer fails, it will
36252506Simp		 * try the next one, instead of just bailing.
36352506Simp		 */
36452506Simp
36552506Simp		while (1) {
36652506Simp			if (longlink_present) {
36787352Simp				CARD_SET_RES_FLAGS(device_get_parent(dev), dev,
36887352Simp				    SYS_RES_MEMORY, rid, longlink_common ?
36993370Simp				    PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR);
37052506Simp				DPRINTF(("cis mem map %x\n",
37152506Simp				    (unsigned int) tuple.memh));
37252506Simp				tuple.mult = longlink_common ? 1 : 2;
37393370Simp				tuple.ptr = longlink_addr;
37452506Simp				longlink_present = 0;
37552506Simp				longlink_common = 1;
37652506Simp				longlink_addr = 0;
37752506Simp			} else if (mfc_count && (mfc_index < mfc_count)) {
37887352Simp				CARD_SET_RES_FLAGS(device_get_parent(dev), dev,
37987352Simp				    SYS_RES_MEMORY, rid, mfc[mfc_index].common
38093370Simp				    ? PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR);
38152506Simp				DPRINTF(("cis mem map %x\n",
38252506Simp				    (unsigned int) tuple.memh));
38352506Simp				/* set parse state, and point at the next one */
38452506Simp				tuple.mult = mfc[mfc_index].common ? 1 : 2;
38593370Simp				tuple.ptr = mfc[mfc_index].addr;
38652506Simp				mfc_index++;
38752506Simp			} else {
38852506Simp				goto done;
38952506Simp			}
39052506Simp
39152506Simp			/* make sure that the link is valid */
39252506Simp			tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
39352506Simp			if (tuple.code != PCCARD_CISTPL_LINKTARGET) {
39452506Simp				DPRINTF(("CISTPL_LINKTARGET expected, "
39552506Simp				    "code %02x observed\n", tuple.code));
39652506Simp				continue;
39752506Simp			}
39852506Simp			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
39952506Simp			if (tuple.length < 3) {
40052506Simp				DPRINTF(("CISTPL_LINKTARGET too short %d\n",
40152506Simp				    tuple.length));
40252506Simp				continue;
40352506Simp			}
40452506Simp			if ((pccard_tuple_read_1(&tuple, 0) != 'C') ||
40552506Simp			    (pccard_tuple_read_1(&tuple, 1) != 'I') ||
40652506Simp			    (pccard_tuple_read_1(&tuple, 2) != 'S')) {
40752506Simp				DPRINTF(("CISTPL_LINKTARGET magic "
40852506Simp				    "%02x%02x%02x incorrect\n",
40952506Simp				    pccard_tuple_read_1(&tuple, 0),
41052506Simp				    pccard_tuple_read_1(&tuple, 1),
41152506Simp				    pccard_tuple_read_1(&tuple, 2)));
41252506Simp				continue;
41352506Simp			}
41452506Simp			tuple.ptr += 2 + tuple.length;
41552506Simp			break;
41652506Simp		}
41752506Simp	}
41852506Simp
41952506Simpdone:
42055720Simp	bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
42152506Simp
42252506Simp	return (ret);
42352506Simp}
42452506Simp
42552506Simp/* XXX this is incredibly verbose.  Not sure what trt is */
42652506Simp
42752506Simpvoid
42852506Simppccard_print_cis(device_t dev)
42952506Simp{
43064850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
43152506Simp	struct pccard_card *card = &sc->card;
43252506Simp	struct pccard_function *pf;
43352506Simp	struct pccard_config_entry *cfe;
43452506Simp	int i;
43552506Simp
43652506Simp	device_printf(dev, "CIS version ");
43752506Simp	if (card->cis1_major == 4) {
43852506Simp		if (card->cis1_minor == 0)
43952506Simp			printf("PCCARD 1.0\n");
44052506Simp		else if (card->cis1_minor == 1)
44152506Simp			printf("PCCARD 2.0 or 2.1\n");
44252506Simp	} else if (card->cis1_major >= 5)
44352506Simp		printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor);
44452506Simp	else
44552506Simp		printf("unknown (major=%d, minor=%d)\n",
44652506Simp		    card->cis1_major, card->cis1_minor);
44752506Simp
44852506Simp	device_printf(dev, "CIS info: ");
44952506Simp	for (i = 0; i < 4; i++) {
45052506Simp		if (card->cis1_info[i] == NULL)
45152506Simp			break;
45252506Simp		if (i)
45352506Simp			printf(", ");
45452506Simp		printf("%s", card->cis1_info[i]);
45552506Simp	}
45652506Simp	printf("\n");
45752506Simp
45852506Simp	device_printf(dev, "Manufacturer code 0x%x, product 0x%x\n",
45952506Simp	    card->manufacturer, card->product);
46052506Simp
46152506Simp	STAILQ_FOREACH(pf, &card->pf_head, pf_list) {
46252506Simp		device_printf(dev, "function %d: ", pf->number);
46352506Simp
46452506Simp		switch (pf->function) {
46552506Simp		case PCCARD_FUNCTION_UNSPEC:
46652506Simp			printf("unspecified");
46752506Simp			break;
46852506Simp		case PCCARD_FUNCTION_MULTIFUNCTION:
46952506Simp			printf("multi-function");
47052506Simp			break;
47152506Simp		case PCCARD_FUNCTION_MEMORY:
47252506Simp			printf("memory");
47352506Simp			break;
47452506Simp		case PCCARD_FUNCTION_SERIAL:
47552506Simp			printf("serial port");
47652506Simp			break;
47752506Simp		case PCCARD_FUNCTION_PARALLEL:
47852506Simp			printf("parallel port");
47952506Simp			break;
48052506Simp		case PCCARD_FUNCTION_DISK:
48152506Simp			printf("fixed disk");
48252506Simp			break;
48352506Simp		case PCCARD_FUNCTION_VIDEO:
48452506Simp			printf("video adapter");
48552506Simp			break;
48652506Simp		case PCCARD_FUNCTION_NETWORK:
48752506Simp			printf("network adapter");
48852506Simp			break;
48952506Simp		case PCCARD_FUNCTION_AIMS:
49052506Simp			printf("auto incrementing mass storage");
49152506Simp			break;
49252506Simp		case PCCARD_FUNCTION_SCSI:
49352506Simp			printf("SCSI bridge");
49452506Simp			break;
49552506Simp		case PCCARD_FUNCTION_SECURITY:
49652506Simp			printf("Security services");
49752506Simp			break;
49852506Simp		case PCCARD_FUNCTION_INSTRUMENT:
49952506Simp			printf("Instrument");
50052506Simp			break;
50152506Simp		default:
50252506Simp			printf("unknown (%d)", pf->function);
50352506Simp			break;
50452506Simp		}
50552506Simp
50652506Simp		printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask);
50752506Simp
50852506Simp		STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
50952506Simp			device_printf(dev, "function %d, config table entry "
51052506Simp			    "%d: ", pf->number, cfe->number);
51152506Simp
51252506Simp			switch (cfe->iftype) {
51352506Simp			case PCCARD_IFTYPE_MEMORY:
51452506Simp				printf("memory card");
51552506Simp				break;
51652506Simp			case PCCARD_IFTYPE_IO:
51752506Simp				printf("I/O card");
51852506Simp				break;
51952506Simp			default:
52052506Simp				printf("card type unknown");
52152506Simp				break;
52252506Simp			}
52352506Simp
52452506Simp			printf("; irq mask %x", cfe->irqmask);
52552506Simp
52652506Simp			if (cfe->num_iospace) {
52752506Simp				printf("; iomask %lx, iospace", cfe->iomask);
52852506Simp
52953813Simp				for (i = 0; i < cfe->num_iospace; i++) {
53053813Simp					printf(" %lx", cfe->iospace[i].start);
53153813Simp					if (cfe->iospace[i].length)
53253813Simp						printf("-%lx",
53353813Simp						    cfe->iospace[i].start +
53453813Simp						    cfe->iospace[i].length - 1);
53553813Simp				}
53652506Simp			}
53752506Simp			if (cfe->num_memspace) {
53852506Simp				printf("; memspace");
53952506Simp
54053813Simp				for (i = 0; i < cfe->num_memspace; i++) {
54153813Simp					printf(" %lx",
54253813Simp					    cfe->memspace[i].cardaddr);
54353813Simp					if (cfe->memspace[i].length)
54453813Simp						printf("-%lx",
54553813Simp						    cfe->memspace[i].cardaddr +
54653813Simp						    cfe->memspace[i].length - 1);
54753813Simp					if (cfe->memspace[i].hostaddr)
54853813Simp						printf("@%lx",
54953813Simp						    cfe->memspace[i].hostaddr);
55053813Simp				}
55152506Simp			}
55252506Simp			if (cfe->maxtwins)
55352506Simp				printf("; maxtwins %d", cfe->maxtwins);
55452506Simp
55552506Simp			printf(";");
55652506Simp
55752506Simp			if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED)
55852506Simp				printf(" mwait_required");
55952506Simp			if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE)
56052506Simp				printf(" rdybsy_active");
56152506Simp			if (cfe->flags & PCCARD_CFE_WP_ACTIVE)
56252506Simp				printf(" wp_active");
56352506Simp			if (cfe->flags & PCCARD_CFE_BVD_ACTIVE)
56452506Simp				printf(" bvd_active");
56552506Simp			if (cfe->flags & PCCARD_CFE_IO8)
56652506Simp				printf(" io8");
56752506Simp			if (cfe->flags & PCCARD_CFE_IO16)
56852506Simp				printf(" io16");
56952506Simp			if (cfe->flags & PCCARD_CFE_IRQSHARE)
57052506Simp				printf(" irqshare");
57152506Simp			if (cfe->flags & PCCARD_CFE_IRQPULSE)
57252506Simp				printf(" irqpulse");
57352506Simp			if (cfe->flags & PCCARD_CFE_IRQLEVEL)
57452506Simp				printf(" irqlevel");
57552506Simp			if (cfe->flags & PCCARD_CFE_POWERDOWN)
57652506Simp				printf(" powerdown");
57752506Simp			if (cfe->flags & PCCARD_CFE_READONLY)
57852506Simp				printf(" readonly");
57952506Simp			if (cfe->flags & PCCARD_CFE_AUDIO)
58052506Simp				printf(" audio");
58152506Simp
58252506Simp			printf("\n");
58352506Simp		}
58452506Simp	}
58552506Simp
58652506Simp	if (card->error)
58752506Simp		device_printf(dev, "%d errors found while parsing CIS\n",
58852506Simp		    card->error);
58952506Simp}
59052506Simp
59152506Simpint
59255720Simppccard_parse_cis_tuple(struct pccard_tuple *tuple, void *arg)
59352506Simp{
59452506Simp	/* most of these are educated guesses */
59552506Simp	static struct pccard_config_entry init_cfe = {
59652506Simp		-1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE |
59752506Simp		PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY,
59852506Simp	};
59952506Simp
60052506Simp	struct cis_state *state = arg;
60152506Simp
60252506Simp	switch (tuple->code) {
60352506Simp	case PCCARD_CISTPL_END:
60452506Simp		/* if we've seen a LONGLINK_MFC, and this is the first
60552506Simp		 * END after it, reset the function list.
60652506Simp		 *
60752506Simp		 * XXX This might also be the right place to start a
60852506Simp		 * new function, but that assumes that a function
60952506Simp		 * definition never crosses any longlink, and I'm not
61052506Simp		 * sure about that.  This is probably safe for MFC
61152506Simp		 * cards, but what we have now isn't broken, so I'd
61252506Simp		 * rather not change it.
61352506Simp		 */
61452506Simp		if (state->gotmfc == 1) {
61552506Simp			struct pccard_function *pf, *pfnext;
61652506Simp
61752506Simp			for (pf = STAILQ_FIRST(&state->card->pf_head);
61852506Simp			     pf != NULL; pf = pfnext) {
61952506Simp				pfnext = STAILQ_NEXT(pf, pf_list);
62052506Simp				free(pf, M_DEVBUF);
62152506Simp			}
62252506Simp
62352506Simp			STAILQ_INIT(&state->card->pf_head);
62452506Simp
62552506Simp			state->count = 0;
62652506Simp			state->gotmfc = 2;
62752506Simp			state->pf = NULL;
62852506Simp		}
62952506Simp		break;
63052506Simp	case PCCARD_CISTPL_LONGLINK_MFC:
63152506Simp		/*
63252506Simp		 * this tuple's structure was dealt with in scan_cis.  here,
63352506Simp		 * record the fact that the MFC tuple was seen, so that
63452506Simp		 * functions declared before the MFC link can be cleaned
63552506Simp		 * up.
63652506Simp		 */
63752506Simp		state->gotmfc = 1;
63852506Simp		break;
63952506Simp#ifdef PCCARDCISDEBUG
64052506Simp	case PCCARD_CISTPL_DEVICE:
64152506Simp	case PCCARD_CISTPL_DEVICE_A:
64252506Simp		{
64352506Simp			u_int reg, dtype, dspeed;
64452506Simp
64552506Simp			reg = pccard_tuple_read_1(tuple, 0);
64652506Simp			dtype = reg & PCCARD_DTYPE_MASK;
64752506Simp			dspeed = reg & PCCARD_DSPEED_MASK;
64852506Simp
64952506Simp			DPRINTF(("CISTPL_DEVICE%s type=",
65052506Simp			(tuple->code == PCCARD_CISTPL_DEVICE) ? "" : "_A"));
65152506Simp			switch (dtype) {
65252506Simp			case PCCARD_DTYPE_NULL:
65352506Simp				DPRINTF(("null"));
65452506Simp				break;
65552506Simp			case PCCARD_DTYPE_ROM:
65652506Simp				DPRINTF(("rom"));
65752506Simp				break;
65852506Simp			case PCCARD_DTYPE_OTPROM:
65952506Simp				DPRINTF(("otprom"));
66052506Simp				break;
66152506Simp			case PCCARD_DTYPE_EPROM:
66252506Simp				DPRINTF(("eprom"));
66352506Simp				break;
66452506Simp			case PCCARD_DTYPE_EEPROM:
66552506Simp				DPRINTF(("eeprom"));
66652506Simp				break;
66752506Simp			case PCCARD_DTYPE_FLASH:
66852506Simp				DPRINTF(("flash"));
66952506Simp				break;
67052506Simp			case PCCARD_DTYPE_SRAM:
67152506Simp				DPRINTF(("sram"));
67252506Simp				break;
67352506Simp			case PCCARD_DTYPE_DRAM:
67452506Simp				DPRINTF(("dram"));
67552506Simp				break;
67652506Simp			case PCCARD_DTYPE_FUNCSPEC:
67752506Simp				DPRINTF(("funcspec"));
67852506Simp				break;
67952506Simp			case PCCARD_DTYPE_EXTEND:
68052506Simp				DPRINTF(("extend"));
68152506Simp				break;
68252506Simp			default:
68352506Simp				DPRINTF(("reserved"));
68452506Simp				break;
68552506Simp			}
68652506Simp			DPRINTF((" speed="));
68752506Simp			switch (dspeed) {
68852506Simp			case PCCARD_DSPEED_NULL:
68952506Simp				DPRINTF(("null"));
69052506Simp				break;
69152506Simp			case PCCARD_DSPEED_250NS:
69252506Simp				DPRINTF(("250ns"));
69352506Simp				break;
69452506Simp			case PCCARD_DSPEED_200NS:
69552506Simp				DPRINTF(("200ns"));
69652506Simp				break;
69752506Simp			case PCCARD_DSPEED_150NS:
69852506Simp				DPRINTF(("150ns"));
69952506Simp				break;
70052506Simp			case PCCARD_DSPEED_100NS:
70152506Simp				DPRINTF(("100ns"));
70252506Simp				break;
70352506Simp			case PCCARD_DSPEED_EXT:
70452506Simp				DPRINTF(("ext"));
70552506Simp				break;
70652506Simp			default:
70752506Simp				DPRINTF(("reserved"));
70852506Simp				break;
70952506Simp			}
71052506Simp		}
71152506Simp		DPRINTF(("\n"));
71252506Simp		break;
71352506Simp#endif
71452506Simp	case PCCARD_CISTPL_VERS_1:
71552506Simp		if (tuple->length < 6) {
71652506Simp			DPRINTF(("CISTPL_VERS_1 too short %d\n",
71752506Simp			    tuple->length));
71852506Simp			break;
71952506Simp		} {
72052506Simp			int start, i, ch, count;
72152506Simp
72252506Simp			state->card->cis1_major = pccard_tuple_read_1(tuple, 0);
72352506Simp			state->card->cis1_minor = pccard_tuple_read_1(tuple, 1);
72452506Simp
72552506Simp			for (count = 0, start = 0, i = 0;
72652506Simp			    (count < 4) && ((i + 4) < 256); i++) {
72752506Simp				ch = pccard_tuple_read_1(tuple, 2 + i);
72852506Simp				if (ch == 0xff)
72952506Simp					break;
73052506Simp				state->card->cis1_info_buf[i] = ch;
73152506Simp				if (ch == 0) {
73252506Simp					state->card->cis1_info[count] =
73352506Simp					    state->card->cis1_info_buf + start;
73452506Simp					start = i + 1;
73552506Simp					count++;
73652506Simp				}
73752506Simp			}
73852506Simp			DPRINTF(("CISTPL_VERS_1\n"));
73952506Simp		}
74052506Simp		break;
74152506Simp	case PCCARD_CISTPL_MANFID:
74252506Simp		if (tuple->length < 4) {
74352506Simp			DPRINTF(("CISTPL_MANFID too short %d\n",
74452506Simp			    tuple->length));
74552506Simp			break;
74652506Simp		}
74752506Simp		state->card->manufacturer = pccard_tuple_read_2(tuple, 0);
74852506Simp		state->card->product = pccard_tuple_read_2(tuple, 2);
74990964Sshiba		/*
750104604Simp		 * This is for xe driver. But not limited to that driver.
75190964Sshiba		 * In PC Card Standard,
75290964Sshiba		 * Manufacturer ID: 2byte.
753104604Simp		 * Product ID: typically 2bytes, but there's no limit on its
754104604Simp		 * size.  prodext is a two byte field, so maybe we should
755104604Simp		 * also handle the '6' case.  So far no cards have surfaced
756104604Simp		 * with a length of '6'.
75790964Sshiba		 */
75890964Sshiba		if (tuple->length == 5 ) {
75990964Sshiba			state->card->prodext = pccard_tuple_read_1(tuple, 4);
76090964Sshiba		}
76152506Simp		DPRINTF(("CISTPL_MANFID\n"));
76252506Simp		break;
76352506Simp	case PCCARD_CISTPL_FUNCID:
76452506Simp		if (tuple->length < 1) {
76552506Simp			DPRINTF(("CISTPL_FUNCID too short %d\n",
76652506Simp			    tuple->length));
76752506Simp			break;
76852506Simp		}
76952506Simp		if ((state->pf == NULL) || (state->gotmfc == 2)) {
77052506Simp			state->pf = malloc(sizeof(*state->pf), M_DEVBUF,
77167897Sdwmalone			    M_NOWAIT | M_ZERO);
77252506Simp			state->pf->number = state->count++;
77352506Simp			state->pf->last_config_index = -1;
77452506Simp			STAILQ_INIT(&state->pf->cfe_head);
77552506Simp
77652506Simp			STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf,
77752506Simp			    pf_list);
77852506Simp		}
77952506Simp		state->pf->function = pccard_tuple_read_1(tuple, 0);
78052506Simp
78152506Simp		DPRINTF(("CISTPL_FUNCID\n"));
78252506Simp		break;
78382781Sshiba        case PCCARD_CISTPL_FUNCE:
78482781Sshiba                if (state->pf == NULL || state->pf->function <= 0) {
78582781Sshiba                        DPRINTF(("CISTPL_FUNCE is not followed by "
78682781Sshiba                                "valid CISTPL_FUNCID\n"));
78782781Sshiba                        break;
78882781Sshiba                }
78982781Sshiba                if (tuple->length >= 2) {
79082781Sshiba                        decode_funce(tuple, state->pf);
79182781Sshiba                }
79282781Sshiba                DPRINTF(("CISTPL_FUNCE\n"));
79382781Sshiba                break;
79452506Simp	case PCCARD_CISTPL_CONFIG:
79552506Simp		if (tuple->length < 3) {
79652506Simp			DPRINTF(("CISTPL_CONFIG too short %d\n",
79752506Simp			    tuple->length));
79852506Simp			break;
79952506Simp		} {
80052506Simp			u_int reg, rasz, rmsz, rfsz;
80152506Simp			int i;
80252506Simp
80352506Simp			reg = pccard_tuple_read_1(tuple, 0);
80452506Simp			rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >>
80552506Simp			    PCCARD_TPCC_RASZ_SHIFT);
80652506Simp			rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >>
80752506Simp			    PCCARD_TPCC_RMSZ_SHIFT);
80852506Simp			rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >>
80952506Simp			    PCCARD_TPCC_RFSZ_SHIFT);
81052506Simp
81152506Simp			if (tuple->length < (rasz + rmsz + rfsz)) {
81252506Simp				DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too "
81352506Simp				    "short %d\n", rasz, rmsz, rfsz,
81452506Simp				    tuple->length));
81552506Simp				break;
81652506Simp			}
81752506Simp			if (state->pf == NULL) {
81852506Simp				state->pf = malloc(sizeof(*state->pf),
81967897Sdwmalone				    M_DEVBUF, M_NOWAIT | M_ZERO);
82052506Simp				state->pf->number = state->count++;
82152506Simp				state->pf->last_config_index = -1;
82252506Simp				STAILQ_INIT(&state->pf->cfe_head);
82352506Simp
82452506Simp				STAILQ_INSERT_TAIL(&state->card->pf_head,
82552506Simp				    state->pf, pf_list);
82652506Simp
82752506Simp				state->pf->function = PCCARD_FUNCTION_UNSPEC;
82852506Simp			}
82952506Simp			state->pf->last_config_index =
83052506Simp			    pccard_tuple_read_1(tuple, 1);
83152506Simp
83252506Simp			state->pf->ccr_base = 0;
83352506Simp			for (i = 0; i < rasz; i++)
83452506Simp				state->pf->ccr_base |=
83552506Simp				    ((pccard_tuple_read_1(tuple, 2 + i)) <<
83652506Simp				    (i * 8));
83752506Simp
83852506Simp			state->pf->ccr_mask = 0;
83952506Simp			for (i = 0; i < rmsz; i++)
84052506Simp				state->pf->ccr_mask |=
84152506Simp				    ((pccard_tuple_read_1(tuple,
84252506Simp				    2 + rasz + i)) << (i * 8));
84352506Simp
84452506Simp			/* skip the reserved area and subtuples */
84552506Simp
84652506Simp			/* reset the default cfe for each cfe list */
84752506Simp			state->temp_cfe = init_cfe;
84852506Simp			state->default_cfe = &state->temp_cfe;
84952506Simp		}
85052506Simp		DPRINTF(("CISTPL_CONFIG\n"));
85152506Simp		break;
85252506Simp	case PCCARD_CISTPL_CFTABLE_ENTRY:
85352506Simp		{
85452506Simp			int idx, i, j;
85552506Simp			u_int reg, reg2;
85652506Simp			u_int intface, def, num;
85752506Simp			u_int power, timing, iospace, irq, memspace, misc;
85852506Simp			struct pccard_config_entry *cfe;
85952506Simp
86052506Simp			idx = 0;
86152506Simp
86252506Simp			reg = pccard_tuple_read_1(tuple, idx);
86352506Simp			idx++;
86452506Simp			intface = reg & PCCARD_TPCE_INDX_INTFACE;
86552506Simp			def = reg & PCCARD_TPCE_INDX_DEFAULT;
86652506Simp			num = reg & PCCARD_TPCE_INDX_NUM_MASK;
86752506Simp
86852506Simp			/*
86952506Simp			 * this is a little messy.  Some cards have only a
87052506Simp			 * cfentry with the default bit set.  So, as we go
87152506Simp			 * through the list, we add new indexes to the queue,
87252506Simp			 * and keep a pointer to the last one with the
87352506Simp			 * default bit set.  if we see a record with the same
87452506Simp			 * index, as the default, we stash the default and
87552506Simp			 * replace the queue entry. otherwise, we just add
87652506Simp			 * new entries to the queue, pointing the default ptr
87752506Simp			 * at them if the default bit is set.  if we get to
87852506Simp			 * the end with the default pointer pointing at a
87952506Simp			 * record which hasn't had a matching index, that's
88052506Simp			 * ok; it just becomes a cfentry like any other.
88152506Simp			 */
88252506Simp
88352506Simp			/*
88452506Simp			 * if the index in the cis differs from the default
88552506Simp			 * cis, create new entry in the queue and start it
88652506Simp			 * with the current default
88752506Simp			 */
88852506Simp			if (num != state->default_cfe->number) {
88952506Simp				cfe = (struct pccard_config_entry *)
89052506Simp				    malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
89152506Simp
89252506Simp				*cfe = *state->default_cfe;
89352506Simp
89452506Simp				STAILQ_INSERT_TAIL(&state->pf->cfe_head,
89552506Simp				    cfe, cfe_list);
89652506Simp
89752506Simp				cfe->number = num;
89852506Simp
89952506Simp				/*
90052506Simp				 * if the default bit is set in the cis, then
90152506Simp				 * point the new default at whatever is being
90252506Simp				 * filled in
90352506Simp				 */
90452506Simp				if (def)
90552506Simp					state->default_cfe = cfe;
90652506Simp			} else {
90752506Simp				/*
90852506Simp				 * the cis index matches the default index,
90952506Simp				 * fill in the default cfentry.  It is
91052506Simp				 * assumed that the cfdefault index is in the
91152506Simp				 * queue.  For it to be otherwise, the cis
91252506Simp				 * index would have to be -1 (initial
91352506Simp				 * condition) which is not possible, or there
91452506Simp				 * would have to be a preceding cis entry
91552506Simp				 * which had the same cis index and had the
91652506Simp				 * default bit unset. Neither condition
91752506Simp				 * should happen.  If it does, this cfentry
91852506Simp				 * is lost (written into temp space), which
91952506Simp				 * is an acceptable failure mode.
92052506Simp				 */
92152506Simp
92252506Simp				cfe = state->default_cfe;
92352506Simp
92452506Simp				/*
92552506Simp				 * if the cis entry does not have the default
92652506Simp				 * bit set, copy the default out of the way
92752506Simp				 * first.
92852506Simp				 */
92952506Simp				if (!def) {
93052506Simp					state->temp_cfe = *state->default_cfe;
93152506Simp					state->default_cfe = &state->temp_cfe;
93252506Simp				}
93352506Simp			}
93452506Simp
93552506Simp			if (intface) {
93652506Simp				reg = pccard_tuple_read_1(tuple, idx);
93752506Simp				idx++;
938104640Simp				cfe->flags &= ~(PCCARD_CFE_MWAIT_REQUIRED
939104640Simp				    | PCCARD_CFE_RDYBSY_ACTIVE
940104640Simp				    | PCCARD_CFE_WP_ACTIVE
941104640Simp				    | PCCARD_CFE_BVD_ACTIVE);
94252506Simp				if (reg & PCCARD_TPCE_IF_MWAIT)
94352506Simp					cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED;
94452506Simp				if (reg & PCCARD_TPCE_IF_RDYBSY)
94552506Simp					cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE;
94652506Simp				if (reg & PCCARD_TPCE_IF_WP)
94752506Simp					cfe->flags |= PCCARD_CFE_WP_ACTIVE;
94852506Simp				if (reg & PCCARD_TPCE_IF_BVD)
94952506Simp					cfe->flags |= PCCARD_CFE_BVD_ACTIVE;
95052506Simp				cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE;
95152506Simp			}
95252506Simp			reg = pccard_tuple_read_1(tuple, idx);
95352506Simp			idx++;
95452506Simp
95552506Simp			power = reg & PCCARD_TPCE_FS_POWER_MASK;
95652506Simp			timing = reg & PCCARD_TPCE_FS_TIMING;
95752506Simp			iospace = reg & PCCARD_TPCE_FS_IOSPACE;
95852506Simp			irq = reg & PCCARD_TPCE_FS_IRQ;
95952506Simp			memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK;
96052506Simp			misc = reg & PCCARD_TPCE_FS_MISC;
96152506Simp
96252506Simp			if (power) {
96352506Simp				/* skip over power, don't save */
96452506Simp				/* for each parameter selection byte */
96552506Simp				for (i = 0; i < power; i++) {
96652506Simp					reg = pccard_tuple_read_1(tuple, idx);
96752506Simp					idx++;
96852506Simp					/* for each bit */
96952506Simp					for (j = 0; j < 7; j++) {
97052506Simp						/* if the bit is set */
97152506Simp						if ((reg >> j) & 0x01) {
97252506Simp							/* skip over bytes */
97352506Simp							do {
97452506Simp								reg2 = pccard_tuple_read_1(tuple, idx);
97552506Simp								idx++;
97652506Simp								/*
97752506Simp								 * until
97852506Simp								 * non-extensi
97952506Simp								 * on byte
98052506Simp								 */
98152506Simp							} while (reg2 & 0x80);
98252506Simp						}
98352506Simp					}
98452506Simp				}
98552506Simp			}
98652506Simp			if (timing) {
98752506Simp				/* skip over timing, don't save */
98852506Simp				reg = pccard_tuple_read_1(tuple, idx);
98952506Simp				idx++;
99052506Simp
99152506Simp				if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) !=
99252506Simp				    PCCARD_TPCE_TD_RESERVED_MASK)
99352506Simp					idx++;
99452506Simp				if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) !=
99552506Simp				    PCCARD_TPCE_TD_RDYBSY_MASK)
99652506Simp					idx++;
99752506Simp				if ((reg & PCCARD_TPCE_TD_WAIT_MASK) !=
99852506Simp				    PCCARD_TPCE_TD_WAIT_MASK)
99952506Simp					idx++;
100052506Simp			}
100152506Simp			if (iospace) {
100252506Simp				if (tuple->length <= idx) {
100352506Simp					DPRINTF(("ran out of space before TCPE_IO\n"));
100452506Simp					goto abort_cfe;
100552506Simp				}
100652506Simp
100752506Simp				reg = pccard_tuple_read_1(tuple, idx);
100852506Simp				idx++;
1009104640Simp				cfe->flags &=
1010104640Simp				    ~(PCCARD_CFE_IO8 | PCCARD_CFE_IO16);
101152506Simp				if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT)
101252506Simp					cfe->flags |= PCCARD_CFE_IO8;
101352506Simp				if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT)
101452506Simp					cfe->flags |= PCCARD_CFE_IO16;
101552506Simp				cfe->iomask =
101652506Simp				    reg & PCCARD_TPCE_IO_IOADDRLINES_MASK;
101752506Simp
101852506Simp				if (reg & PCCARD_TPCE_IO_HASRANGE) {
101952506Simp					reg = pccard_tuple_read_1(tuple, idx);
102052506Simp					idx++;
102152506Simp
102252506Simp					cfe->num_iospace = 1 + (reg &
102352506Simp					    PCCARD_TPCE_IO_RANGE_COUNT);
102452506Simp
102552506Simp					if (cfe->num_iospace >
102652506Simp					    (sizeof(cfe->iospace) /
102752506Simp					     sizeof(cfe->iospace[0]))) {
102852506Simp						DPRINTF(("too many io "
102952506Simp						    "spaces %d",
103052506Simp						    cfe->num_iospace));
103152506Simp						state->card->error++;
103252506Simp						break;
103352506Simp					}
103452506Simp					for (i = 0; i < cfe->num_iospace; i++) {
103552506Simp						switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) {
103652506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE:
103752506Simp							cfe->iospace[i].start =
103852506Simp								pccard_tuple_read_1(tuple, idx);
103952506Simp							idx++;
104052506Simp							break;
104152506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO:
104252506Simp							cfe->iospace[i].start =
104352506Simp								pccard_tuple_read_2(tuple, idx);
104452506Simp							idx += 2;
104552506Simp							break;
104652506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR:
104752506Simp							cfe->iospace[i].start =
104852506Simp								pccard_tuple_read_4(tuple, idx);
104952506Simp							idx += 4;
105052506Simp							break;
105152506Simp						}
105252506Simp						switch (reg &
105352506Simp							PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) {
105452506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE:
105552506Simp							cfe->iospace[i].length =
105652506Simp								pccard_tuple_read_1(tuple, idx);
105752506Simp							idx++;
105852506Simp							break;
105952506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO:
106052506Simp							cfe->iospace[i].length =
106152506Simp								pccard_tuple_read_2(tuple, idx);
106252506Simp							idx += 2;
106352506Simp							break;
106452506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR:
106552506Simp							cfe->iospace[i].length =
106652506Simp								pccard_tuple_read_4(tuple, idx);
106752506Simp							idx += 4;
106852506Simp							break;
106952506Simp						}
107052506Simp						cfe->iospace[i].length++;
107152506Simp					}
107252506Simp				} else {
107352506Simp					cfe->num_iospace = 1;
107452506Simp					cfe->iospace[0].start = 0;
107552506Simp					cfe->iospace[0].length =
107652506Simp					    (1 << cfe->iomask);
107752506Simp				}
107852506Simp			}
107952506Simp			if (irq) {
108052506Simp				if (tuple->length <= idx) {
108152506Simp					DPRINTF(("ran out of space before TCPE_IR\n"));
108252506Simp					goto abort_cfe;
108352506Simp				}
108452506Simp
108552506Simp				reg = pccard_tuple_read_1(tuple, idx);
108652506Simp				idx++;
1087104640Simp				cfe->flags &= ~(PCCARD_CFE_IRQSHARE
1088104640Simp				    | PCCARD_CFE_IRQPULSE
1089104640Simp				    | PCCARD_CFE_IRQLEVEL);
109052506Simp				if (reg & PCCARD_TPCE_IR_SHARE)
109152506Simp					cfe->flags |= PCCARD_CFE_IRQSHARE;
109252506Simp				if (reg & PCCARD_TPCE_IR_PULSE)
109352506Simp					cfe->flags |= PCCARD_CFE_IRQPULSE;
109452506Simp				if (reg & PCCARD_TPCE_IR_LEVEL)
109552506Simp					cfe->flags |= PCCARD_CFE_IRQLEVEL;
109652506Simp
109752506Simp				if (reg & PCCARD_TPCE_IR_HASMASK) {
109852506Simp					/*
109952506Simp					 * it's legal to ignore the
110052506Simp					 * special-interrupt bits, so I will
110152506Simp					 */
110252506Simp
110352506Simp					cfe->irqmask =
110452506Simp					    pccard_tuple_read_2(tuple, idx);
110552506Simp					idx += 2;
110652506Simp				} else {
110752506Simp					cfe->irqmask =
110852506Simp					    (1 << (reg & PCCARD_TPCE_IR_IRQ));
110952506Simp				}
111052506Simp			}
111152506Simp			if (memspace) {
111252506Simp				if (tuple->length <= idx) {
111352506Simp					DPRINTF(("ran out of space before TCPE_MS\n"));
111452506Simp					goto abort_cfe;
111552506Simp				}
111652506Simp
111752506Simp				if (memspace == PCCARD_TPCE_FS_MEMSPACE_NONE) {
111852506Simp					cfe->num_memspace = 0;
111952506Simp				} else if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) {
112052506Simp					cfe->num_memspace = 1;
112152506Simp					cfe->memspace[0].length = 256 *
112252506Simp					    pccard_tuple_read_2(tuple, idx);
112352506Simp					idx += 2;
112452506Simp					cfe->memspace[0].cardaddr = 0;
112552506Simp					cfe->memspace[0].hostaddr = 0;
112652506Simp				} else if (memspace ==
112752506Simp				    PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) {
112852506Simp					cfe->num_memspace = 1;
112952506Simp					cfe->memspace[0].length = 256 *
113052506Simp					    pccard_tuple_read_2(tuple, idx);
113152506Simp					idx += 2;
113252506Simp					cfe->memspace[0].cardaddr = 256 *
113352506Simp					    pccard_tuple_read_2(tuple, idx);
113452506Simp					idx += 2;
113552506Simp					cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr;
113652506Simp				} else {
113752506Simp					int lengthsize;
113852506Simp					int cardaddrsize;
113952506Simp					int hostaddrsize;
114052506Simp
114152506Simp					reg = pccard_tuple_read_1(tuple, idx);
114252506Simp					idx++;
114352506Simp
114453873Simp					cfe->num_memspace = (reg &
114553873Simp					    PCCARD_TPCE_MS_COUNT) + 1;
114652506Simp
114752506Simp					if (cfe->num_memspace >
114852506Simp					    (sizeof(cfe->memspace) /
114952506Simp					     sizeof(cfe->memspace[0]))) {
115052506Simp						DPRINTF(("too many mem "
115152506Simp						    "spaces %d",
115252506Simp						    cfe->num_memspace));
115352506Simp						state->card->error++;
115452506Simp						break;
115552506Simp					}
115652506Simp					lengthsize =
115752506Simp						((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >>
115852506Simp						 PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT);
115952506Simp					cardaddrsize =
116052506Simp						((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >>
116152506Simp						 PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT);
116252506Simp					hostaddrsize =
116352506Simp						(reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0;
116452506Simp
116552506Simp					if (lengthsize == 0) {
116652506Simp						DPRINTF(("cfe memspace "
116752506Simp						    "lengthsize == 0"));
116852506Simp						state->card->error++;
116952506Simp					}
117052506Simp					for (i = 0; i < cfe->num_memspace; i++) {
117152506Simp						if (lengthsize) {
117252506Simp							cfe->memspace[i].length =
117352506Simp								256 * pccard_tuple_read_n(tuple, lengthsize,
117452506Simp								       idx);
117552506Simp							idx += lengthsize;
117652506Simp						} else {
117752506Simp							cfe->memspace[i].length = 0;
117852506Simp						}
117952506Simp						if (cfe->memspace[i].length == 0) {
118052506Simp							DPRINTF(("cfe->memspace[%d].length == 0",
118152506Simp								 i));
118252506Simp							state->card->error++;
118352506Simp						}
118452506Simp						if (cardaddrsize) {
118552506Simp							cfe->memspace[i].cardaddr =
118652506Simp								256 * pccard_tuple_read_n(tuple, cardaddrsize,
118752506Simp								       idx);
118852506Simp							idx += cardaddrsize;
118952506Simp						} else {
119052506Simp							cfe->memspace[i].cardaddr = 0;
119152506Simp						}
119252506Simp						if (hostaddrsize) {
119352506Simp							cfe->memspace[i].hostaddr =
119452506Simp								256 * pccard_tuple_read_n(tuple, hostaddrsize,
119552506Simp								       idx);
119652506Simp							idx += hostaddrsize;
119752506Simp						} else {
119852506Simp							cfe->memspace[i].hostaddr = 0;
119952506Simp						}
120052506Simp					}
120152506Simp				}
120252506Simp			}
120352506Simp			if (misc) {
120452506Simp				if (tuple->length <= idx) {
120552506Simp					DPRINTF(("ran out of space before TCPE_MI\n"));
120652506Simp					goto abort_cfe;
120752506Simp				}
120852506Simp
120952506Simp				reg = pccard_tuple_read_1(tuple, idx);
121052506Simp				idx++;
1211104640Simp				cfe->flags &= ~(PCCARD_CFE_POWERDOWN
1212104640Simp				    | PCCARD_CFE_READONLY
1213104640Simp				    | PCCARD_CFE_AUDIO);
121452506Simp				if (reg & PCCARD_TPCE_MI_PWRDOWN)
1215104640Simp					cfe->flags |= PCCARD_CFE_POWERDOWN;
121652506Simp				if (reg & PCCARD_TPCE_MI_READONLY)
1217104640Simp					cfe->flags |= PCCARD_CFE_READONLY;
121852506Simp				if (reg & PCCARD_TPCE_MI_AUDIO)
1219104640Simp					cfe->flags |= PCCARD_CFE_AUDIO;
122052506Simp				cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS;
122152506Simp
122252506Simp				while (reg & PCCARD_TPCE_MI_EXT) {
122352506Simp					reg = pccard_tuple_read_1(tuple, idx);
122452506Simp					idx++;
122552506Simp				}
122652506Simp			}
122752506Simp			/* skip all the subtuples */
122852506Simp		}
122952506Simp
123052506Simp	abort_cfe:
123152506Simp		DPRINTF(("CISTPL_CFTABLE_ENTRY\n"));
123252506Simp		break;
123352506Simp	default:
123452506Simp		DPRINTF(("unhandled CISTPL %x\n", tuple->code));
123552506Simp		break;
123652506Simp	}
123752506Simp
123852506Simp	return (0);
123952506Simp}
124082781Sshiba
124182781Sshibastatic int
124282781Sshibadecode_funce(struct pccard_tuple *tuple, struct pccard_function *pf)
124382781Sshiba{
124482781Sshiba	int type = pccard_tuple_read_1(tuple, 0);
124582781Sshiba
124682781Sshiba	switch (pf->function) {
124782781Sshiba	case PCCARD_FUNCTION_DISK:
124882781Sshiba		if (type == PCCARD_TPLFE_TYPE_DISK_DEVICE_INTERFACE) {
124982781Sshiba			pf->pf_funce_disk_interface
125082781Sshiba				= pccard_tuple_read_1(tuple, 1);
125182781Sshiba		}
125282781Sshiba		break;
125382781Sshiba	case PCCARD_FUNCTION_NETWORK:
125482781Sshiba		if (type == PCCARD_TPLFE_TYPE_LAN_NID) {
125582781Sshiba			int i;
125682781Sshiba			int len = pccard_tuple_read_1(tuple, 1);
125782781Sshiba			if (tuple->length < 2 + len || len > 8) {
125882781Sshiba				/* tuple length not enough or nid too long */
125982781Sshiba				break;
126082781Sshiba                        }
126182781Sshiba			for (i = 0; i < len; i++) {
126282781Sshiba				pf->pf_funce_lan_nid[i]
126382781Sshiba					= pccard_tuple_read_1(tuple, i + 2);
126482781Sshiba			}
126582781Sshiba			pf->pf_funce_lan_nidlen = len;
126682781Sshiba		}
126782781Sshiba		break;
126882781Sshiba	default:
126982781Sshiba		break;
127082781Sshiba	}
127182781Sshiba	return 0;
127282781Sshiba}
1273