pccard_cis.c revision 58997
152506Simp/*	$NetBSD: pcmcia_cis.c,v 1.10 1998/12/29 09:03:15 marc Exp $	*/
252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard_cis.c 58997 2000-04-04 04:12:43Z 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/pccardchip.h>
4852506Simp#include <dev/pccard/pccardvar.h>
4952506Simp
5052506Simp#ifdef PCCARDCISDEBUG
5152506Simpint	pccardcis_debug = 0;
5252506Simp#define	DPRINTF(arg) if (pccardcis_debug) printf arg
5355720Simp#define	DEVPRINTF(arg) if (pccardcis_debug) device_printf arg
5452506Simp#else
5552506Simp#define	DPRINTF(arg)
5655720Simp#define	DEVPRINTF(arg)
5752506Simp#endif
5852506Simp
5952506Simp#define	PCCARD_CIS_SIZE		1024
6052506Simp
6152506Simpstruct cis_state {
6252506Simp	int	count;
6352506Simp	int	gotmfc;
6452506Simp	struct pccard_config_entry temp_cfe;
6552506Simp	struct pccard_config_entry *default_cfe;
6652506Simp	struct pccard_card *card;
6752506Simp	struct pccard_function *pf;
6852506Simp};
6952506Simp
7054250Simpint	pccard_parse_cis_tuple(struct pccard_tuple *, void *);
7152506Simp
7252506Simpvoid
7355720Simppccard_read_cis(struct pccard_softc *sc)
7452506Simp{
7552506Simp	struct cis_state state;
7652506Simp
7752506Simp	state.count = 0;
7852506Simp	state.gotmfc = 0;
7952506Simp
8052506Simp	state.card = &sc->card;
8152506Simp
8252506Simp	state.card->error = 0;
8352506Simp	state.card->cis1_major = -1;
8452506Simp	state.card->cis1_minor = -1;
8552506Simp	state.card->cis1_info[0] = NULL;
8652506Simp	state.card->cis1_info[1] = NULL;
8752506Simp	state.card->cis1_info[2] = NULL;
8852506Simp	state.card->cis1_info[3] = NULL;
8952506Simp	state.card->manufacturer = PCCARD_VENDOR_INVALID;
9052506Simp	state.card->product = PCCARD_PRODUCT_INVALID;
9152506Simp	STAILQ_INIT(&state.card->pf_head);
9252506Simp
9352506Simp	state.pf = NULL;
9452506Simp
9558997Simp	if (pccard_scan_cis(sc->dev, pccard_parse_cis_tuple,
9652506Simp	    &state) == -1)
9752506Simp		state.card->error++;
9852506Simp}
9952506Simp
10052506Simpint
10155720Simppccard_scan_cis(device_t dev, int (*fct)(struct pccard_tuple *, void *),
10255720Simp	void *arg)
10352506Simp{
10455720Simp	struct resource *res;
10555720Simp	int rid;
10652506Simp	struct pccard_tuple tuple;
10752506Simp	int longlink_present;
10852506Simp	int longlink_common;
10952506Simp	u_long longlink_addr;
11052506Simp	int mfc_count;
11152506Simp	int mfc_index;
11252506Simp	struct {
11352506Simp		int	common;
11452506Simp		u_long	addr;
11552506Simp	} mfc[256 / 5];
11652506Simp	int ret;
11752506Simp
11852506Simp	ret = 0;
11952506Simp
12052506Simp	/* allocate some memory */
12152506Simp
12255720Simp	rid = 0;
12355720Simp	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0,
12458581Simp	    PCCARD_CIS_SIZE, RF_ACTIVE /* | RF_PCCARD_ATTR */);
12555720Simp	if (res == NULL) {
12652506Simp#ifdef DIAGNOSTIC
12755720Simp		device_printf(dev, "can't alloc memory to read attributes\n");
12852506Simp#endif
12952506Simp		return -1;
13052506Simp	}
13155720Simp	tuple.memt = rman_get_bustag(res);
13255720Simp	tuple.memh = rman_get_bushandle(res);
13352506Simp
13452506Simp	DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh));
13555720Simp
13652506Simp	tuple.mult = 2;
13752506Simp
13852506Simp	longlink_present = 1;
13952506Simp	longlink_common = 1;
14052506Simp	longlink_addr = 0;
14152506Simp
14252506Simp	mfc_count = 0;
14352506Simp	mfc_index = 0;
14452506Simp
14555720Simp	DEVPRINTF((dev, "CIS tuple chain:\n"));
14652506Simp
14752506Simp	while (1) {
14852506Simp		while (1) {
14952506Simp			/* get the tuple code */
15052506Simp
15152506Simp			tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
15252506Simp
15352506Simp			/* two special-case tuples */
15452506Simp
15552506Simp			if (tuple.code == PCCARD_CISTPL_NULL) {
15652506Simp				DPRINTF(("CISTPL_NONE\n 00\n"));
15752506Simp				tuple.ptr++;
15852506Simp				continue;
15952506Simp			} else if (tuple.code == PCCARD_CISTPL_END) {
16052506Simp				DPRINTF(("CISTPL_END\n ff\n"));
16152506Simp				/* Call the function for the END tuple, since
16252506Simp				   the CIS semantics depend on it */
16352506Simp				if ((*fct) (&tuple, arg)) {
16452506Simp					ret = 1;
16552506Simp					goto done;
16652506Simp				}
16752506Simp				tuple.ptr++;
16852506Simp				break;
16952506Simp			}
17052506Simp			/* now all the normal tuples */
17152506Simp
17252506Simp			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
17352506Simp			switch (tuple.code) {
17452506Simp			case PCCARD_CISTPL_LONGLINK_A:
17552506Simp			case PCCARD_CISTPL_LONGLINK_C:
17652506Simp				if (tuple.length < 4) {
17752506Simp					DPRINTF(("CISTPL_LONGLINK_%s too "
17852506Simp					    "short %d\n",
17952506Simp					    longlink_common ? "C" : "A",
18052506Simp					    tuple.length));
18152506Simp					break;
18252506Simp				}
18352506Simp				longlink_present = 1;
18452506Simp				longlink_common = (tuple.code ==
18552506Simp				    PCCARD_CISTPL_LONGLINK_C) ? 1 : 0;
18652506Simp				longlink_addr = pccard_tuple_read_4(&tuple, 0);
18752506Simp				DPRINTF(("CISTPL_LONGLINK_%s %lx\n",
18852506Simp				    longlink_common ? "C" : "A",
18952506Simp				    longlink_addr));
19052506Simp				break;
19152506Simp			case PCCARD_CISTPL_NO_LINK:
19252506Simp				longlink_present = 0;
19352506Simp				DPRINTF(("CISTPL_NO_LINK\n"));
19452506Simp				break;
19552506Simp			case PCCARD_CISTPL_CHECKSUM:
19652506Simp				if (tuple.length < 5) {
19752506Simp					DPRINTF(("CISTPL_CHECKSUM too "
19852506Simp					    "short %d\n", tuple.length));
19952506Simp					break;
20052506Simp				} {
20152506Simp					int16_t offset;
20252506Simp					u_long addr, length;
20352506Simp					u_int cksum, sum;
20452506Simp					int i;
20552506Simp
20652506Simp					*((u_int16_t *) & offset) =
20752506Simp					    pccard_tuple_read_2(&tuple, 0);
20852506Simp					length = pccard_tuple_read_2(&tuple, 2);
20952506Simp					cksum = pccard_tuple_read_1(&tuple, 4);
21052506Simp
21152506Simp					addr = tuple.ptr + offset;
21252506Simp
21352506Simp					DPRINTF(("CISTPL_CHECKSUM addr=%lx "
21452506Simp					    "len=%lx cksum=%x",
21552506Simp					    addr, length, cksum));
21652506Simp
21752506Simp					/*
21852506Simp					 * XXX do more work to deal with
21952506Simp					 * distant regions
22052506Simp					 */
22152506Simp					if ((addr >= PCCARD_CIS_SIZE) ||
22252506Simp					    ((addr + length) < 0) ||
22352506Simp					    ((addr + length) >=
22452506Simp					      PCCARD_CIS_SIZE)) {
22552506Simp						DPRINTF((" skipped, "
22652506Simp						    "too distant\n"));
22752506Simp						break;
22852506Simp					}
22952506Simp					sum = 0;
23052506Simp					for (i = 0; i < length; i++)
23152506Simp						sum +=
23252506Simp						    bus_space_read_1(tuple.memt,
23352506Simp						    tuple.memh,
23452506Simp						    addr + tuple.mult * i);
23552506Simp					if (cksum != (sum & 0xff)) {
23652506Simp						DPRINTF((" failed sum=%x\n",
23752506Simp						    sum));
23855720Simp						device_printf(dev,
23955720Simp						    "CIS checksum failed\n");
24052506Simp#if 0
24152506Simp						/*
24252506Simp						 * XXX Some working cards have
24352506Simp						 * XXX bad checksums!!
24452506Simp						 */
24552506Simp						ret = -1;
24652506Simp#endif
24752506Simp					} else {
24852506Simp						DPRINTF((" ok\n"));
24952506Simp					}
25052506Simp				}
25152506Simp				break;
25252506Simp			case PCCARD_CISTPL_LONGLINK_MFC:
25352506Simp				if (tuple.length < 1) {
25452506Simp					DPRINTF(("CISTPL_LONGLINK_MFC too "
25552506Simp					    "short %d\n", tuple.length));
25652506Simp					break;
25752506Simp				}
25852506Simp				/*
25952506Simp				 * this is kind of ad hoc, as I don't have
26052506Simp				 * any real documentation
26152506Simp				 */
26252506Simp				{
26352506Simp					int i;
26452506Simp
26552506Simp					mfc_count =
26652506Simp					    pccard_tuple_read_1(&tuple, 0);
26752506Simp					DPRINTF(("CISTPL_LONGLINK_MFC %d",
26852506Simp					    mfc_count));
26952506Simp					for (i = 0; i < mfc_count; i++) {
27052506Simp						mfc[i].common =
27152506Simp						    (pccard_tuple_read_1(&tuple,
27252506Simp						    1 + 5 * i) ==
27352506Simp						    PCCARD_MFC_MEM_COMMON) ?
27452506Simp						    1 : 0;
27552506Simp						mfc[i].addr =
27652506Simp						    pccard_tuple_read_4(&tuple,
27752506Simp						    1 + 5 * i + 1);
27852506Simp						DPRINTF((" %s:%lx",
27952506Simp						    mfc[i].common ? "common" :
28052506Simp						    "attr", mfc[i].addr));
28152506Simp					}
28252506Simp					DPRINTF(("\n"));
28352506Simp				}
28452506Simp				/*
28552506Simp				 * for LONGLINK_MFC, fall through to the
28652506Simp				 * function.  This tuple has structural and
28752506Simp				 * semantic content.
28852506Simp				 */
28952506Simp			default:
29052506Simp				{
29152506Simp					if ((*fct) (&tuple, arg)) {
29252506Simp						ret = 1;
29352506Simp						goto done;
29452506Simp					}
29552506Simp				}
29652506Simp				break;
29752506Simp			}	/* switch */
29852506Simp#ifdef PCCARDCISDEBUG
29952506Simp			/* print the tuple */
30052506Simp			{
30152506Simp				int i;
30252506Simp
30352506Simp				DPRINTF((" %02x %02x", tuple.code,
30452506Simp				    tuple.length));
30552506Simp
30652506Simp				for (i = 0; i < tuple.length; i++) {
30752506Simp					DPRINTF((" %02x",
30852506Simp					    pccard_tuple_read_1(&tuple, i)));
30952506Simp					if ((i % 16) == 13)
31052506Simp						DPRINTF(("\n"));
31152506Simp				}
31252506Simp				if ((i % 16) != 14)
31352506Simp					DPRINTF(("\n"));
31452506Simp			}
31552506Simp#endif
31652506Simp			/* skip to the next tuple */
31752506Simp			tuple.ptr += 2 + tuple.length;
31852506Simp		}
31952506Simp
32055720Simp#ifdef XXX	/* I'm not up to this tonight, need to implement new API */
32155720Simp		/* to deal with moving windows and such.  At least that's */
32255720Simp		/* what it appears at this instant */
32355720Simp
32452506Simp		/*
32552506Simp		 * the chain is done.  Clean up and move onto the next one,
32652506Simp		 * if any.  The loop is here in the case that there is an MFC
32752506Simp		 * card with no longlink (which defaults to existing, == 0).
32852506Simp		 * In general, this means that if one pointer fails, it will
32952506Simp		 * try the next one, instead of just bailing.
33052506Simp		 */
33152506Simp
33252506Simp		while (1) {
33352506Simp			pccard_chip_mem_unmap(pct, pch, window);
33452506Simp
33552506Simp			if (longlink_present) {
33652506Simp				/*
33752506Simp				 * if the longlink is to attribute memory,
33852506Simp				 * then it is unindexed.  That is, if the
33952506Simp				 * link value is 0x100, then the actual
34052506Simp				 * memory address is 0x200.  This means that
34152506Simp				 * we need to multiply by 2 before calling
34252506Simp				 * mem_map, and then divide the resulting ptr
34352506Simp				 * by 2 after.
34452506Simp				 */
34552506Simp
34652506Simp				if (!longlink_common)
34752506Simp					longlink_addr *= 2;
34852506Simp
34952506Simp				pccard_chip_mem_map(pct, pch, longlink_common ?
35052506Simp				    PCCARD_MEM_COMMON : PCCARD_MEM_ATTR,
35152506Simp				    longlink_addr, PCCARD_CIS_SIZE,
35252506Simp				    &pcmh, &tuple.ptr, &window);
35352506Simp
35452506Simp				if (!longlink_common)
35552506Simp					tuple.ptr /= 2;
35652506Simp				DPRINTF(("cis mem map %x\n",
35752506Simp				    (unsigned int) tuple.memh));
35852506Simp				tuple.mult = longlink_common ? 1 : 2;
35952506Simp				longlink_present = 0;
36052506Simp				longlink_common = 1;
36152506Simp				longlink_addr = 0;
36252506Simp			} else if (mfc_count && (mfc_index < mfc_count)) {
36352506Simp				if (!mfc[mfc_index].common)
36452506Simp					mfc[mfc_index].addr *= 2;
36552506Simp
36652506Simp				pccard_chip_mem_map(pct, pch,
36752506Simp				    mfc[mfc_index].common ?
36852506Simp				    PCCARD_MEM_COMMON : PCCARD_MEM_ATTR,
36952506Simp				    mfc[mfc_index].addr, PCCARD_CIS_SIZE,
37052506Simp				    &pcmh, &tuple.ptr, &window);
37152506Simp
37252506Simp				if (!mfc[mfc_index].common)
37352506Simp					tuple.ptr /= 2;
37452506Simp				DPRINTF(("cis mem map %x\n",
37552506Simp				    (unsigned int) tuple.memh));
37652506Simp				/* set parse state, and point at the next one */
37752506Simp
37852506Simp				tuple.mult = mfc[mfc_index].common ? 1 : 2;
37952506Simp
38052506Simp				mfc_index++;
38152506Simp			} else {
38252506Simp				goto done;
38352506Simp			}
38452506Simp
38552506Simp			/* make sure that the link is valid */
38652506Simp			tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
38752506Simp			if (tuple.code != PCCARD_CISTPL_LINKTARGET) {
38852506Simp				DPRINTF(("CISTPL_LINKTARGET expected, "
38952506Simp				    "code %02x observed\n", tuple.code));
39052506Simp				continue;
39152506Simp			}
39252506Simp			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
39352506Simp			if (tuple.length < 3) {
39452506Simp				DPRINTF(("CISTPL_LINKTARGET too short %d\n",
39552506Simp				    tuple.length));
39652506Simp				continue;
39752506Simp			}
39852506Simp			if ((pccard_tuple_read_1(&tuple, 0) != 'C') ||
39952506Simp			    (pccard_tuple_read_1(&tuple, 1) != 'I') ||
40052506Simp			    (pccard_tuple_read_1(&tuple, 2) != 'S')) {
40152506Simp				DPRINTF(("CISTPL_LINKTARGET magic "
40252506Simp				    "%02x%02x%02x incorrect\n",
40352506Simp				    pccard_tuple_read_1(&tuple, 0),
40452506Simp				    pccard_tuple_read_1(&tuple, 1),
40552506Simp				    pccard_tuple_read_1(&tuple, 2)));
40652506Simp				continue;
40752506Simp			}
40852506Simp			tuple.ptr += 2 + tuple.length;
40952506Simp
41052506Simp			break;
41152506Simp		}
41255720Simp#endif /* XXX */
41352506Simp	}
41452506Simp
41552506Simpdone:
41655720Simp	bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
41752506Simp
41852506Simp	return (ret);
41952506Simp}
42052506Simp
42152506Simp/* XXX this is incredibly verbose.  Not sure what trt is */
42252506Simp
42352506Simpvoid
42452506Simppccard_print_cis(device_t dev)
42552506Simp{
42652506Simp	struct pccard_softc *sc = (struct pccard_softc *) device_get_softc(dev);
42752506Simp	struct pccard_card *card = &sc->card;
42852506Simp	struct pccard_function *pf;
42952506Simp	struct pccard_config_entry *cfe;
43052506Simp	int i;
43152506Simp
43252506Simp	device_printf(dev, "CIS version ");
43352506Simp	if (card->cis1_major == 4) {
43452506Simp		if (card->cis1_minor == 0)
43552506Simp			printf("PCCARD 1.0\n");
43652506Simp		else if (card->cis1_minor == 1)
43752506Simp			printf("PCCARD 2.0 or 2.1\n");
43852506Simp	} else if (card->cis1_major >= 5)
43952506Simp		printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor);
44052506Simp	else
44152506Simp		printf("unknown (major=%d, minor=%d)\n",
44252506Simp		    card->cis1_major, card->cis1_minor);
44352506Simp
44452506Simp	device_printf(dev, "CIS info: ");
44552506Simp	for (i = 0; i < 4; i++) {
44652506Simp		if (card->cis1_info[i] == NULL)
44752506Simp			break;
44852506Simp		if (i)
44952506Simp			printf(", ");
45052506Simp		printf("%s", card->cis1_info[i]);
45152506Simp	}
45252506Simp	printf("\n");
45352506Simp
45452506Simp	device_printf(dev, "Manufacturer code 0x%x, product 0x%x\n",
45552506Simp	    card->manufacturer, card->product);
45652506Simp
45752506Simp	STAILQ_FOREACH(pf, &card->pf_head, pf_list) {
45852506Simp		device_printf(dev, "function %d: ", pf->number);
45952506Simp
46052506Simp		switch (pf->function) {
46152506Simp		case PCCARD_FUNCTION_UNSPEC:
46252506Simp			printf("unspecified");
46352506Simp			break;
46452506Simp		case PCCARD_FUNCTION_MULTIFUNCTION:
46552506Simp			printf("multi-function");
46652506Simp			break;
46752506Simp		case PCCARD_FUNCTION_MEMORY:
46852506Simp			printf("memory");
46952506Simp			break;
47052506Simp		case PCCARD_FUNCTION_SERIAL:
47152506Simp			printf("serial port");
47252506Simp			break;
47352506Simp		case PCCARD_FUNCTION_PARALLEL:
47452506Simp			printf("parallel port");
47552506Simp			break;
47652506Simp		case PCCARD_FUNCTION_DISK:
47752506Simp			printf("fixed disk");
47852506Simp			break;
47952506Simp		case PCCARD_FUNCTION_VIDEO:
48052506Simp			printf("video adapter");
48152506Simp			break;
48252506Simp		case PCCARD_FUNCTION_NETWORK:
48352506Simp			printf("network adapter");
48452506Simp			break;
48552506Simp		case PCCARD_FUNCTION_AIMS:
48652506Simp			printf("auto incrementing mass storage");
48752506Simp			break;
48852506Simp		case PCCARD_FUNCTION_SCSI:
48952506Simp			printf("SCSI bridge");
49052506Simp			break;
49152506Simp		case PCCARD_FUNCTION_SECURITY:
49252506Simp			printf("Security services");
49352506Simp			break;
49452506Simp		case PCCARD_FUNCTION_INSTRUMENT:
49552506Simp			printf("Instrument");
49652506Simp			break;
49752506Simp		default:
49852506Simp			printf("unknown (%d)", pf->function);
49952506Simp			break;
50052506Simp		}
50152506Simp
50252506Simp		printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask);
50352506Simp
50452506Simp		STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
50552506Simp			device_printf(dev, "function %d, config table entry "
50652506Simp			    "%d: ", pf->number, cfe->number);
50752506Simp
50852506Simp			switch (cfe->iftype) {
50952506Simp			case PCCARD_IFTYPE_MEMORY:
51052506Simp				printf("memory card");
51152506Simp				break;
51252506Simp			case PCCARD_IFTYPE_IO:
51352506Simp				printf("I/O card");
51452506Simp				break;
51552506Simp			default:
51652506Simp				printf("card type unknown");
51752506Simp				break;
51852506Simp			}
51952506Simp
52052506Simp			printf("; irq mask %x", cfe->irqmask);
52152506Simp
52252506Simp			if (cfe->num_iospace) {
52352506Simp				printf("; iomask %lx, iospace", cfe->iomask);
52452506Simp
52553813Simp				for (i = 0; i < cfe->num_iospace; i++) {
52653813Simp					printf(" %lx", cfe->iospace[i].start);
52753813Simp					if (cfe->iospace[i].length)
52853813Simp						printf("-%lx",
52953813Simp						    cfe->iospace[i].start +
53053813Simp						    cfe->iospace[i].length - 1);
53153813Simp				}
53252506Simp			}
53352506Simp			if (cfe->num_memspace) {
53452506Simp				printf("; memspace");
53552506Simp
53653813Simp				for (i = 0; i < cfe->num_memspace; i++) {
53753813Simp					printf(" %lx",
53853813Simp					    cfe->memspace[i].cardaddr);
53953813Simp					if (cfe->memspace[i].length)
54053813Simp						printf("-%lx",
54153813Simp						    cfe->memspace[i].cardaddr +
54253813Simp						    cfe->memspace[i].length - 1);
54353813Simp					if (cfe->memspace[i].hostaddr)
54453813Simp						printf("@%lx",
54553813Simp						    cfe->memspace[i].hostaddr);
54653813Simp				}
54752506Simp			}
54852506Simp			if (cfe->maxtwins)
54952506Simp				printf("; maxtwins %d", cfe->maxtwins);
55052506Simp
55152506Simp			printf(";");
55252506Simp
55352506Simp			if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED)
55452506Simp				printf(" mwait_required");
55552506Simp			if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE)
55652506Simp				printf(" rdybsy_active");
55752506Simp			if (cfe->flags & PCCARD_CFE_WP_ACTIVE)
55852506Simp				printf(" wp_active");
55952506Simp			if (cfe->flags & PCCARD_CFE_BVD_ACTIVE)
56052506Simp				printf(" bvd_active");
56152506Simp			if (cfe->flags & PCCARD_CFE_IO8)
56252506Simp				printf(" io8");
56352506Simp			if (cfe->flags & PCCARD_CFE_IO16)
56452506Simp				printf(" io16");
56552506Simp			if (cfe->flags & PCCARD_CFE_IRQSHARE)
56652506Simp				printf(" irqshare");
56752506Simp			if (cfe->flags & PCCARD_CFE_IRQPULSE)
56852506Simp				printf(" irqpulse");
56952506Simp			if (cfe->flags & PCCARD_CFE_IRQLEVEL)
57052506Simp				printf(" irqlevel");
57152506Simp			if (cfe->flags & PCCARD_CFE_POWERDOWN)
57252506Simp				printf(" powerdown");
57352506Simp			if (cfe->flags & PCCARD_CFE_READONLY)
57452506Simp				printf(" readonly");
57552506Simp			if (cfe->flags & PCCARD_CFE_AUDIO)
57652506Simp				printf(" audio");
57752506Simp
57852506Simp			printf("\n");
57952506Simp		}
58052506Simp	}
58152506Simp
58252506Simp	if (card->error)
58352506Simp		device_printf(dev, "%d errors found while parsing CIS\n",
58452506Simp		    card->error);
58552506Simp}
58652506Simp
58752506Simpint
58855720Simppccard_parse_cis_tuple(struct pccard_tuple *tuple, void *arg)
58952506Simp{
59052506Simp	/* most of these are educated guesses */
59152506Simp	static struct pccard_config_entry init_cfe = {
59252506Simp		-1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE |
59352506Simp		PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY,
59452506Simp	};
59552506Simp
59652506Simp	struct cis_state *state = arg;
59752506Simp
59852506Simp	switch (tuple->code) {
59952506Simp	case PCCARD_CISTPL_END:
60052506Simp		/* if we've seen a LONGLINK_MFC, and this is the first
60152506Simp		 * END after it, reset the function list.
60252506Simp		 *
60352506Simp		 * XXX This might also be the right place to start a
60452506Simp		 * new function, but that assumes that a function
60552506Simp		 * definition never crosses any longlink, and I'm not
60652506Simp		 * sure about that.  This is probably safe for MFC
60752506Simp		 * cards, but what we have now isn't broken, so I'd
60852506Simp		 * rather not change it.
60952506Simp		 */
61052506Simp		if (state->gotmfc == 1) {
61152506Simp			struct pccard_function *pf, *pfnext;
61252506Simp
61352506Simp			for (pf = STAILQ_FIRST(&state->card->pf_head);
61452506Simp			     pf != NULL; pf = pfnext) {
61552506Simp				pfnext = STAILQ_NEXT(pf, pf_list);
61652506Simp				free(pf, M_DEVBUF);
61752506Simp			}
61852506Simp
61952506Simp			STAILQ_INIT(&state->card->pf_head);
62052506Simp
62152506Simp			state->count = 0;
62252506Simp			state->gotmfc = 2;
62352506Simp			state->pf = NULL;
62452506Simp		}
62552506Simp		break;
62652506Simp	case PCCARD_CISTPL_LONGLINK_MFC:
62752506Simp		/*
62852506Simp		 * this tuple's structure was dealt with in scan_cis.  here,
62952506Simp		 * record the fact that the MFC tuple was seen, so that
63052506Simp		 * functions declared before the MFC link can be cleaned
63152506Simp		 * up.
63252506Simp		 */
63352506Simp		state->gotmfc = 1;
63452506Simp		break;
63552506Simp#ifdef PCCARDCISDEBUG
63652506Simp	case PCCARD_CISTPL_DEVICE:
63752506Simp	case PCCARD_CISTPL_DEVICE_A:
63852506Simp		{
63952506Simp			u_int reg, dtype, dspeed;
64052506Simp
64152506Simp			reg = pccard_tuple_read_1(tuple, 0);
64252506Simp			dtype = reg & PCCARD_DTYPE_MASK;
64352506Simp			dspeed = reg & PCCARD_DSPEED_MASK;
64452506Simp
64552506Simp			DPRINTF(("CISTPL_DEVICE%s type=",
64652506Simp			(tuple->code == PCCARD_CISTPL_DEVICE) ? "" : "_A"));
64752506Simp			switch (dtype) {
64852506Simp			case PCCARD_DTYPE_NULL:
64952506Simp				DPRINTF(("null"));
65052506Simp				break;
65152506Simp			case PCCARD_DTYPE_ROM:
65252506Simp				DPRINTF(("rom"));
65352506Simp				break;
65452506Simp			case PCCARD_DTYPE_OTPROM:
65552506Simp				DPRINTF(("otprom"));
65652506Simp				break;
65752506Simp			case PCCARD_DTYPE_EPROM:
65852506Simp				DPRINTF(("eprom"));
65952506Simp				break;
66052506Simp			case PCCARD_DTYPE_EEPROM:
66152506Simp				DPRINTF(("eeprom"));
66252506Simp				break;
66352506Simp			case PCCARD_DTYPE_FLASH:
66452506Simp				DPRINTF(("flash"));
66552506Simp				break;
66652506Simp			case PCCARD_DTYPE_SRAM:
66752506Simp				DPRINTF(("sram"));
66852506Simp				break;
66952506Simp			case PCCARD_DTYPE_DRAM:
67052506Simp				DPRINTF(("dram"));
67152506Simp				break;
67252506Simp			case PCCARD_DTYPE_FUNCSPEC:
67352506Simp				DPRINTF(("funcspec"));
67452506Simp				break;
67552506Simp			case PCCARD_DTYPE_EXTEND:
67652506Simp				DPRINTF(("extend"));
67752506Simp				break;
67852506Simp			default:
67952506Simp				DPRINTF(("reserved"));
68052506Simp				break;
68152506Simp			}
68252506Simp			DPRINTF((" speed="));
68352506Simp			switch (dspeed) {
68452506Simp			case PCCARD_DSPEED_NULL:
68552506Simp				DPRINTF(("null"));
68652506Simp				break;
68752506Simp			case PCCARD_DSPEED_250NS:
68852506Simp				DPRINTF(("250ns"));
68952506Simp				break;
69052506Simp			case PCCARD_DSPEED_200NS:
69152506Simp				DPRINTF(("200ns"));
69252506Simp				break;
69352506Simp			case PCCARD_DSPEED_150NS:
69452506Simp				DPRINTF(("150ns"));
69552506Simp				break;
69652506Simp			case PCCARD_DSPEED_100NS:
69752506Simp				DPRINTF(("100ns"));
69852506Simp				break;
69952506Simp			case PCCARD_DSPEED_EXT:
70052506Simp				DPRINTF(("ext"));
70152506Simp				break;
70252506Simp			default:
70352506Simp				DPRINTF(("reserved"));
70452506Simp				break;
70552506Simp			}
70652506Simp		}
70752506Simp		DPRINTF(("\n"));
70852506Simp		break;
70952506Simp#endif
71052506Simp	case PCCARD_CISTPL_VERS_1:
71152506Simp		if (tuple->length < 6) {
71252506Simp			DPRINTF(("CISTPL_VERS_1 too short %d\n",
71352506Simp			    tuple->length));
71452506Simp			break;
71552506Simp		} {
71652506Simp			int start, i, ch, count;
71752506Simp
71852506Simp			state->card->cis1_major = pccard_tuple_read_1(tuple, 0);
71952506Simp			state->card->cis1_minor = pccard_tuple_read_1(tuple, 1);
72052506Simp
72152506Simp			for (count = 0, start = 0, i = 0;
72252506Simp			    (count < 4) && ((i + 4) < 256); i++) {
72352506Simp				ch = pccard_tuple_read_1(tuple, 2 + i);
72452506Simp				if (ch == 0xff)
72552506Simp					break;
72652506Simp				state->card->cis1_info_buf[i] = ch;
72752506Simp				if (ch == 0) {
72852506Simp					state->card->cis1_info[count] =
72952506Simp					    state->card->cis1_info_buf + start;
73052506Simp					start = i + 1;
73152506Simp					count++;
73252506Simp				}
73352506Simp			}
73452506Simp			DPRINTF(("CISTPL_VERS_1\n"));
73552506Simp		}
73652506Simp		break;
73752506Simp	case PCCARD_CISTPL_MANFID:
73852506Simp		if (tuple->length < 4) {
73952506Simp			DPRINTF(("CISTPL_MANFID too short %d\n",
74052506Simp			    tuple->length));
74152506Simp			break;
74252506Simp		}
74352506Simp		state->card->manufacturer = pccard_tuple_read_2(tuple, 0);
74452506Simp		state->card->product = pccard_tuple_read_2(tuple, 2);
74552506Simp		DPRINTF(("CISTPL_MANFID\n"));
74652506Simp		break;
74752506Simp	case PCCARD_CISTPL_FUNCID:
74852506Simp		if (tuple->length < 1) {
74952506Simp			DPRINTF(("CISTPL_FUNCID too short %d\n",
75052506Simp			    tuple->length));
75152506Simp			break;
75252506Simp		}
75352506Simp		if ((state->pf == NULL) || (state->gotmfc == 2)) {
75452506Simp			state->pf = malloc(sizeof(*state->pf), M_DEVBUF,
75552506Simp			    M_NOWAIT);
75652506Simp			bzero(state->pf, sizeof(*state->pf));
75752506Simp			state->pf->number = state->count++;
75852506Simp			state->pf->last_config_index = -1;
75952506Simp			STAILQ_INIT(&state->pf->cfe_head);
76052506Simp
76152506Simp			STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf,
76252506Simp			    pf_list);
76352506Simp		}
76452506Simp		state->pf->function = pccard_tuple_read_1(tuple, 0);
76552506Simp
76652506Simp		DPRINTF(("CISTPL_FUNCID\n"));
76752506Simp		break;
76852506Simp	case PCCARD_CISTPL_CONFIG:
76952506Simp		if (tuple->length < 3) {
77052506Simp			DPRINTF(("CISTPL_CONFIG too short %d\n",
77152506Simp			    tuple->length));
77252506Simp			break;
77352506Simp		} {
77452506Simp			u_int reg, rasz, rmsz, rfsz;
77552506Simp			int i;
77652506Simp
77752506Simp			reg = pccard_tuple_read_1(tuple, 0);
77852506Simp			rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >>
77952506Simp			    PCCARD_TPCC_RASZ_SHIFT);
78052506Simp			rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >>
78152506Simp			    PCCARD_TPCC_RMSZ_SHIFT);
78252506Simp			rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >>
78352506Simp			    PCCARD_TPCC_RFSZ_SHIFT);
78452506Simp
78552506Simp			if (tuple->length < (rasz + rmsz + rfsz)) {
78652506Simp				DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too "
78752506Simp				    "short %d\n", rasz, rmsz, rfsz,
78852506Simp				    tuple->length));
78952506Simp				break;
79052506Simp			}
79152506Simp			if (state->pf == NULL) {
79252506Simp				state->pf = malloc(sizeof(*state->pf),
79352506Simp				    M_DEVBUF, M_NOWAIT);
79452506Simp				bzero(state->pf, sizeof(*state->pf));
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,
80052506Simp				    state->pf, pf_list);
80152506Simp
80252506Simp				state->pf->function = PCCARD_FUNCTION_UNSPEC;
80352506Simp			}
80452506Simp			state->pf->last_config_index =
80552506Simp			    pccard_tuple_read_1(tuple, 1);
80652506Simp
80752506Simp			state->pf->ccr_base = 0;
80852506Simp			for (i = 0; i < rasz; i++)
80952506Simp				state->pf->ccr_base |=
81052506Simp				    ((pccard_tuple_read_1(tuple, 2 + i)) <<
81152506Simp				    (i * 8));
81252506Simp
81352506Simp			state->pf->ccr_mask = 0;
81452506Simp			for (i = 0; i < rmsz; i++)
81552506Simp				state->pf->ccr_mask |=
81652506Simp				    ((pccard_tuple_read_1(tuple,
81752506Simp				    2 + rasz + i)) << (i * 8));
81852506Simp
81952506Simp			/* skip the reserved area and subtuples */
82052506Simp
82152506Simp			/* reset the default cfe for each cfe list */
82252506Simp			state->temp_cfe = init_cfe;
82352506Simp			state->default_cfe = &state->temp_cfe;
82452506Simp		}
82552506Simp		DPRINTF(("CISTPL_CONFIG\n"));
82652506Simp		break;
82752506Simp	case PCCARD_CISTPL_CFTABLE_ENTRY:
82852506Simp		{
82952506Simp			int idx, i, j;
83052506Simp			u_int reg, reg2;
83152506Simp			u_int intface, def, num;
83252506Simp			u_int power, timing, iospace, irq, memspace, misc;
83352506Simp			struct pccard_config_entry *cfe;
83452506Simp
83552506Simp			idx = 0;
83652506Simp
83752506Simp			reg = pccard_tuple_read_1(tuple, idx);
83852506Simp			idx++;
83952506Simp			intface = reg & PCCARD_TPCE_INDX_INTFACE;
84052506Simp			def = reg & PCCARD_TPCE_INDX_DEFAULT;
84152506Simp			num = reg & PCCARD_TPCE_INDX_NUM_MASK;
84252506Simp
84352506Simp			/*
84452506Simp			 * this is a little messy.  Some cards have only a
84552506Simp			 * cfentry with the default bit set.  So, as we go
84652506Simp			 * through the list, we add new indexes to the queue,
84752506Simp			 * and keep a pointer to the last one with the
84852506Simp			 * default bit set.  if we see a record with the same
84952506Simp			 * index, as the default, we stash the default and
85052506Simp			 * replace the queue entry. otherwise, we just add
85152506Simp			 * new entries to the queue, pointing the default ptr
85252506Simp			 * at them if the default bit is set.  if we get to
85352506Simp			 * the end with the default pointer pointing at a
85452506Simp			 * record which hasn't had a matching index, that's
85552506Simp			 * ok; it just becomes a cfentry like any other.
85652506Simp			 */
85752506Simp
85852506Simp			/*
85952506Simp			 * if the index in the cis differs from the default
86052506Simp			 * cis, create new entry in the queue and start it
86152506Simp			 * with the current default
86252506Simp			 */
86352506Simp			if (num != state->default_cfe->number) {
86452506Simp				cfe = (struct pccard_config_entry *)
86552506Simp				    malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
86652506Simp
86752506Simp				*cfe = *state->default_cfe;
86852506Simp
86952506Simp				STAILQ_INSERT_TAIL(&state->pf->cfe_head,
87052506Simp				    cfe, cfe_list);
87152506Simp
87252506Simp				cfe->number = num;
87352506Simp
87452506Simp				/*
87552506Simp				 * if the default bit is set in the cis, then
87652506Simp				 * point the new default at whatever is being
87752506Simp				 * filled in
87852506Simp				 */
87952506Simp				if (def)
88052506Simp					state->default_cfe = cfe;
88152506Simp			} else {
88252506Simp				/*
88352506Simp				 * the cis index matches the default index,
88452506Simp				 * fill in the default cfentry.  It is
88552506Simp				 * assumed that the cfdefault index is in the
88652506Simp				 * queue.  For it to be otherwise, the cis
88752506Simp				 * index would have to be -1 (initial
88852506Simp				 * condition) which is not possible, or there
88952506Simp				 * would have to be a preceding cis entry
89052506Simp				 * which had the same cis index and had the
89152506Simp				 * default bit unset. Neither condition
89252506Simp				 * should happen.  If it does, this cfentry
89352506Simp				 * is lost (written into temp space), which
89452506Simp				 * is an acceptable failure mode.
89552506Simp				 */
89652506Simp
89752506Simp				cfe = state->default_cfe;
89852506Simp
89952506Simp				/*
90052506Simp				 * if the cis entry does not have the default
90152506Simp				 * bit set, copy the default out of the way
90252506Simp				 * first.
90352506Simp				 */
90452506Simp				if (!def) {
90552506Simp					state->temp_cfe = *state->default_cfe;
90652506Simp					state->default_cfe = &state->temp_cfe;
90752506Simp				}
90852506Simp			}
90952506Simp
91052506Simp			if (intface) {
91152506Simp				reg = pccard_tuple_read_1(tuple, idx);
91252506Simp				idx++;
91352506Simp				if (reg & PCCARD_TPCE_IF_MWAIT)
91452506Simp					cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED;
91552506Simp				if (reg & PCCARD_TPCE_IF_RDYBSY)
91652506Simp					cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE;
91752506Simp				if (reg & PCCARD_TPCE_IF_WP)
91852506Simp					cfe->flags |= PCCARD_CFE_WP_ACTIVE;
91952506Simp				if (reg & PCCARD_TPCE_IF_BVD)
92052506Simp					cfe->flags |= PCCARD_CFE_BVD_ACTIVE;
92152506Simp				cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE;
92252506Simp			}
92352506Simp			reg = pccard_tuple_read_1(tuple, idx);
92452506Simp			idx++;
92552506Simp
92652506Simp			power = reg & PCCARD_TPCE_FS_POWER_MASK;
92752506Simp			timing = reg & PCCARD_TPCE_FS_TIMING;
92852506Simp			iospace = reg & PCCARD_TPCE_FS_IOSPACE;
92952506Simp			irq = reg & PCCARD_TPCE_FS_IRQ;
93052506Simp			memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK;
93152506Simp			misc = reg & PCCARD_TPCE_FS_MISC;
93252506Simp
93352506Simp			if (power) {
93452506Simp				/* skip over power, don't save */
93552506Simp				/* for each parameter selection byte */
93652506Simp				for (i = 0; i < power; i++) {
93752506Simp					reg = pccard_tuple_read_1(tuple, idx);
93852506Simp					idx++;
93952506Simp					/* for each bit */
94052506Simp					for (j = 0; j < 7; j++) {
94152506Simp						/* if the bit is set */
94252506Simp						if ((reg >> j) & 0x01) {
94352506Simp							/* skip over bytes */
94452506Simp							do {
94552506Simp								reg2 = pccard_tuple_read_1(tuple, idx);
94652506Simp								idx++;
94752506Simp								/*
94852506Simp								 * until
94952506Simp								 * non-extensi
95052506Simp								 * on byte
95152506Simp								 */
95252506Simp							} while (reg2 & 0x80);
95352506Simp						}
95452506Simp					}
95552506Simp				}
95652506Simp			}
95752506Simp			if (timing) {
95852506Simp				/* skip over timing, don't save */
95952506Simp				reg = pccard_tuple_read_1(tuple, idx);
96052506Simp				idx++;
96152506Simp
96252506Simp				if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) !=
96352506Simp				    PCCARD_TPCE_TD_RESERVED_MASK)
96452506Simp					idx++;
96552506Simp				if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) !=
96652506Simp				    PCCARD_TPCE_TD_RDYBSY_MASK)
96752506Simp					idx++;
96852506Simp				if ((reg & PCCARD_TPCE_TD_WAIT_MASK) !=
96952506Simp				    PCCARD_TPCE_TD_WAIT_MASK)
97052506Simp					idx++;
97152506Simp			}
97252506Simp			if (iospace) {
97352506Simp				if (tuple->length <= idx) {
97452506Simp					DPRINTF(("ran out of space before TCPE_IO\n"));
97552506Simp					goto abort_cfe;
97652506Simp				}
97752506Simp
97852506Simp				reg = pccard_tuple_read_1(tuple, idx);
97952506Simp				idx++;
98052506Simp
98152506Simp				if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT)
98252506Simp					cfe->flags |= PCCARD_CFE_IO8;
98352506Simp				if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT)
98452506Simp					cfe->flags |= PCCARD_CFE_IO16;
98552506Simp				cfe->iomask =
98652506Simp				    reg & PCCARD_TPCE_IO_IOADDRLINES_MASK;
98752506Simp
98852506Simp				if (reg & PCCARD_TPCE_IO_HASRANGE) {
98952506Simp					reg = pccard_tuple_read_1(tuple, idx);
99052506Simp					idx++;
99152506Simp
99252506Simp					cfe->num_iospace = 1 + (reg &
99352506Simp					    PCCARD_TPCE_IO_RANGE_COUNT);
99452506Simp
99552506Simp					if (cfe->num_iospace >
99652506Simp					    (sizeof(cfe->iospace) /
99752506Simp					     sizeof(cfe->iospace[0]))) {
99852506Simp						DPRINTF(("too many io "
99952506Simp						    "spaces %d",
100052506Simp						    cfe->num_iospace));
100152506Simp						state->card->error++;
100252506Simp						break;
100352506Simp					}
100452506Simp					for (i = 0; i < cfe->num_iospace; i++) {
100552506Simp						switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) {
100652506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE:
100752506Simp							cfe->iospace[i].start =
100852506Simp								pccard_tuple_read_1(tuple, idx);
100952506Simp							idx++;
101052506Simp							break;
101152506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO:
101252506Simp							cfe->iospace[i].start =
101352506Simp								pccard_tuple_read_2(tuple, idx);
101452506Simp							idx += 2;
101552506Simp							break;
101652506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR:
101752506Simp							cfe->iospace[i].start =
101852506Simp								pccard_tuple_read_4(tuple, idx);
101952506Simp							idx += 4;
102052506Simp							break;
102152506Simp						}
102252506Simp						switch (reg &
102352506Simp							PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) {
102452506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE:
102552506Simp							cfe->iospace[i].length =
102652506Simp								pccard_tuple_read_1(tuple, idx);
102752506Simp							idx++;
102852506Simp							break;
102952506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO:
103052506Simp							cfe->iospace[i].length =
103152506Simp								pccard_tuple_read_2(tuple, idx);
103252506Simp							idx += 2;
103352506Simp							break;
103452506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR:
103552506Simp							cfe->iospace[i].length =
103652506Simp								pccard_tuple_read_4(tuple, idx);
103752506Simp							idx += 4;
103852506Simp							break;
103952506Simp						}
104052506Simp						cfe->iospace[i].length++;
104152506Simp					}
104252506Simp				} else {
104352506Simp					cfe->num_iospace = 1;
104452506Simp					cfe->iospace[0].start = 0;
104552506Simp					cfe->iospace[0].length =
104652506Simp					    (1 << cfe->iomask);
104752506Simp				}
104852506Simp			}
104952506Simp			if (irq) {
105052506Simp				if (tuple->length <= idx) {
105152506Simp					DPRINTF(("ran out of space before TCPE_IR\n"));
105252506Simp					goto abort_cfe;
105352506Simp				}
105452506Simp
105552506Simp				reg = pccard_tuple_read_1(tuple, idx);
105652506Simp				idx++;
105752506Simp
105852506Simp				if (reg & PCCARD_TPCE_IR_SHARE)
105952506Simp					cfe->flags |= PCCARD_CFE_IRQSHARE;
106052506Simp				if (reg & PCCARD_TPCE_IR_PULSE)
106152506Simp					cfe->flags |= PCCARD_CFE_IRQPULSE;
106252506Simp				if (reg & PCCARD_TPCE_IR_LEVEL)
106352506Simp					cfe->flags |= PCCARD_CFE_IRQLEVEL;
106452506Simp
106552506Simp				if (reg & PCCARD_TPCE_IR_HASMASK) {
106652506Simp					/*
106752506Simp					 * it's legal to ignore the
106852506Simp					 * special-interrupt bits, so I will
106952506Simp					 */
107052506Simp
107152506Simp					cfe->irqmask =
107252506Simp					    pccard_tuple_read_2(tuple, idx);
107352506Simp					idx += 2;
107452506Simp				} else {
107552506Simp					cfe->irqmask =
107652506Simp					    (1 << (reg & PCCARD_TPCE_IR_IRQ));
107752506Simp				}
107852506Simp			}
107952506Simp			if (memspace) {
108052506Simp				if (tuple->length <= idx) {
108152506Simp					DPRINTF(("ran out of space before TCPE_MS\n"));
108252506Simp					goto abort_cfe;
108352506Simp				}
108452506Simp
108552506Simp				if (memspace == PCCARD_TPCE_FS_MEMSPACE_NONE) {
108652506Simp					cfe->num_memspace = 0;
108752506Simp				} else if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) {
108852506Simp					cfe->num_memspace = 1;
108952506Simp					cfe->memspace[0].length = 256 *
109052506Simp					    pccard_tuple_read_2(tuple, idx);
109152506Simp					idx += 2;
109252506Simp					cfe->memspace[0].cardaddr = 0;
109352506Simp					cfe->memspace[0].hostaddr = 0;
109452506Simp				} else if (memspace ==
109552506Simp				    PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) {
109652506Simp					cfe->num_memspace = 1;
109752506Simp					cfe->memspace[0].length = 256 *
109852506Simp					    pccard_tuple_read_2(tuple, idx);
109952506Simp					idx += 2;
110052506Simp					cfe->memspace[0].cardaddr = 256 *
110152506Simp					    pccard_tuple_read_2(tuple, idx);
110252506Simp					idx += 2;
110352506Simp					cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr;
110452506Simp				} else {
110552506Simp					int lengthsize;
110652506Simp					int cardaddrsize;
110752506Simp					int hostaddrsize;
110852506Simp
110952506Simp					reg = pccard_tuple_read_1(tuple, idx);
111052506Simp					idx++;
111152506Simp
111253873Simp					cfe->num_memspace = (reg &
111353873Simp					    PCCARD_TPCE_MS_COUNT) + 1;
111452506Simp
111552506Simp					if (cfe->num_memspace >
111652506Simp					    (sizeof(cfe->memspace) /
111752506Simp					     sizeof(cfe->memspace[0]))) {
111852506Simp						DPRINTF(("too many mem "
111952506Simp						    "spaces %d",
112052506Simp						    cfe->num_memspace));
112152506Simp						state->card->error++;
112252506Simp						break;
112352506Simp					}
112452506Simp					lengthsize =
112552506Simp						((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >>
112652506Simp						 PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT);
112752506Simp					cardaddrsize =
112852506Simp						((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >>
112952506Simp						 PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT);
113052506Simp					hostaddrsize =
113152506Simp						(reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0;
113252506Simp
113352506Simp					if (lengthsize == 0) {
113452506Simp						DPRINTF(("cfe memspace "
113552506Simp						    "lengthsize == 0"));
113652506Simp						state->card->error++;
113752506Simp					}
113852506Simp					for (i = 0; i < cfe->num_memspace; i++) {
113952506Simp						if (lengthsize) {
114052506Simp							cfe->memspace[i].length =
114152506Simp								256 * pccard_tuple_read_n(tuple, lengthsize,
114252506Simp								       idx);
114352506Simp							idx += lengthsize;
114452506Simp						} else {
114552506Simp							cfe->memspace[i].length = 0;
114652506Simp						}
114752506Simp						if (cfe->memspace[i].length == 0) {
114852506Simp							DPRINTF(("cfe->memspace[%d].length == 0",
114952506Simp								 i));
115052506Simp							state->card->error++;
115152506Simp						}
115252506Simp						if (cardaddrsize) {
115352506Simp							cfe->memspace[i].cardaddr =
115452506Simp								256 * pccard_tuple_read_n(tuple, cardaddrsize,
115552506Simp								       idx);
115652506Simp							idx += cardaddrsize;
115752506Simp						} else {
115852506Simp							cfe->memspace[i].cardaddr = 0;
115952506Simp						}
116052506Simp						if (hostaddrsize) {
116152506Simp							cfe->memspace[i].hostaddr =
116252506Simp								256 * pccard_tuple_read_n(tuple, hostaddrsize,
116352506Simp								       idx);
116452506Simp							idx += hostaddrsize;
116552506Simp						} else {
116652506Simp							cfe->memspace[i].hostaddr = 0;
116752506Simp						}
116852506Simp					}
116952506Simp				}
117052506Simp			}
117152506Simp			if (misc) {
117252506Simp				if (tuple->length <= idx) {
117352506Simp					DPRINTF(("ran out of space before TCPE_MI\n"));
117452506Simp					goto abort_cfe;
117552506Simp				}
117652506Simp
117752506Simp				reg = pccard_tuple_read_1(tuple, idx);
117852506Simp				idx++;
117952506Simp
118052506Simp				if (reg & PCCARD_TPCE_MI_PWRDOWN)
118152506Simp					cfe->flags = PCCARD_CFE_POWERDOWN;
118252506Simp				if (reg & PCCARD_TPCE_MI_READONLY)
118352506Simp					cfe->flags = PCCARD_CFE_READONLY;
118452506Simp				if (reg & PCCARD_TPCE_MI_AUDIO)
118552506Simp					cfe->flags = PCCARD_CFE_AUDIO;
118652506Simp				cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS;
118752506Simp
118852506Simp				while (reg & PCCARD_TPCE_MI_EXT) {
118952506Simp					reg = pccard_tuple_read_1(tuple, idx);
119052506Simp					idx++;
119152506Simp				}
119252506Simp			}
119352506Simp			/* skip all the subtuples */
119452506Simp		}
119552506Simp
119652506Simp	abort_cfe:
119752506Simp		DPRINTF(("CISTPL_CFTABLE_ENTRY\n"));
119852506Simp		break;
119952506Simp	default:
120052506Simp		DPRINTF(("unhandled CISTPL %x\n", tuple->code));
120152506Simp		break;
120252506Simp	}
120352506Simp
120452506Simp	return (0);
120552506Simp}
1206