pccard_cis.c revision 104604
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 104604 2002-10-07 06:35:04Z 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
8152506Simp	state.count = 0;
8252506Simp	state.gotmfc = 0;
8352506Simp
8452506Simp	state.card = &sc->card;
8552506Simp
8652506Simp	state.card->error = 0;
8752506Simp	state.card->cis1_major = -1;
8852506Simp	state.card->cis1_minor = -1;
8952506Simp	state.card->cis1_info[0] = NULL;
9052506Simp	state.card->cis1_info[1] = NULL;
9152506Simp	state.card->cis1_info[2] = NULL;
9252506Simp	state.card->cis1_info[3] = NULL;
9386272Simp	state.card->manufacturer = PCMCIA_VENDOR_INVALID;
9486272Simp	state.card->product = PCMCIA_PRODUCT_INVALID;
9552506Simp	STAILQ_INIT(&state.card->pf_head);
9652506Simp
9752506Simp	state.pf = NULL;
9852506Simp
9958997Simp	if (pccard_scan_cis(sc->dev, pccard_parse_cis_tuple,
10052506Simp	    &state) == -1)
10152506Simp		state.card->error++;
10252506Simp}
10352506Simp
10452506Simpint
10555720Simppccard_scan_cis(device_t dev, int (*fct)(struct pccard_tuple *, void *),
10655720Simp	void *arg)
10752506Simp{
10855720Simp	struct resource *res;
10955720Simp	int rid;
11052506Simp	struct pccard_tuple tuple;
11152506Simp	int longlink_present;
11252506Simp	int longlink_common;
11352506Simp	u_long longlink_addr;
11452506Simp	int mfc_count;
11552506Simp	int mfc_index;
11652506Simp	struct {
11752506Simp		int	common;
11852506Simp		u_long	addr;
11952506Simp	} mfc[256 / 5];
12052506Simp	int ret;
12152506Simp
12252506Simp	ret = 0;
12352506Simp
12452506Simp	/* allocate some memory */
12552506Simp
12655720Simp	rid = 0;
12755720Simp	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0,
12859193Simp	    PCCARD_CIS_SIZE, RF_ACTIVE);
12955720Simp	if (res == NULL) {
13055720Simp		device_printf(dev, "can't alloc memory to read attributes\n");
13152506Simp		return -1;
13252506Simp	}
13359193Simp	CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
13459193Simp	    rid, PCCARD_A_MEM_ATTR);
13555720Simp	tuple.memt = rman_get_bustag(res);
13655720Simp	tuple.memh = rman_get_bushandle(res);
13759389Simp	tuple.ptr = 0;
13852506Simp
13952506Simp	DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh));
14055720Simp
14152506Simp	tuple.mult = 2;
14252506Simp
14352506Simp	longlink_present = 1;
14452506Simp	longlink_common = 1;
14552506Simp	longlink_addr = 0;
14652506Simp
14752506Simp	mfc_count = 0;
14852506Simp	mfc_index = 0;
14952506Simp
15055720Simp	DEVPRINTF((dev, "CIS tuple chain:\n"));
15152506Simp
15252506Simp	while (1) {
15352506Simp		while (1) {
15452506Simp			/* get the tuple code */
15552506Simp
15652506Simp			tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
15752506Simp
15852506Simp			/* two special-case tuples */
15952506Simp
16052506Simp			if (tuple.code == PCCARD_CISTPL_NULL) {
16152506Simp				DPRINTF(("CISTPL_NONE\n 00\n"));
16252506Simp				tuple.ptr++;
16352506Simp				continue;
16452506Simp			} else if (tuple.code == PCCARD_CISTPL_END) {
16552506Simp				DPRINTF(("CISTPL_END\n ff\n"));
16652506Simp				/* Call the function for the END tuple, since
16752506Simp				   the CIS semantics depend on it */
16852506Simp				if ((*fct) (&tuple, arg)) {
16952506Simp					ret = 1;
17052506Simp					goto done;
17152506Simp				}
17252506Simp				tuple.ptr++;
17352506Simp				break;
17452506Simp			}
17552506Simp			/* now all the normal tuples */
17652506Simp
17752506Simp			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
17852506Simp			switch (tuple.code) {
17952506Simp			case PCCARD_CISTPL_LONGLINK_A:
18052506Simp			case PCCARD_CISTPL_LONGLINK_C:
18152506Simp				if (tuple.length < 4) {
18252506Simp					DPRINTF(("CISTPL_LONGLINK_%s too "
18352506Simp					    "short %d\n",
18452506Simp					    longlink_common ? "C" : "A",
18552506Simp					    tuple.length));
18652506Simp					break;
18752506Simp				}
18852506Simp				longlink_present = 1;
18952506Simp				longlink_common = (tuple.code ==
19052506Simp				    PCCARD_CISTPL_LONGLINK_C) ? 1 : 0;
19152506Simp				longlink_addr = pccard_tuple_read_4(&tuple, 0);
19252506Simp				DPRINTF(("CISTPL_LONGLINK_%s %lx\n",
19352506Simp				    longlink_common ? "C" : "A",
19452506Simp				    longlink_addr));
19552506Simp				break;
19652506Simp			case PCCARD_CISTPL_NO_LINK:
19752506Simp				longlink_present = 0;
19852506Simp				DPRINTF(("CISTPL_NO_LINK\n"));
19952506Simp				break;
20052506Simp			case PCCARD_CISTPL_CHECKSUM:
20152506Simp				if (tuple.length < 5) {
20252506Simp					DPRINTF(("CISTPL_CHECKSUM too "
20352506Simp					    "short %d\n", tuple.length));
20452506Simp					break;
20552506Simp				} {
20652506Simp					int16_t offset;
20752506Simp					u_long addr, length;
20852506Simp					u_int cksum, sum;
20952506Simp					int i;
21052506Simp
21190896Simp					offset = (uint16_t)
21252506Simp					    pccard_tuple_read_2(&tuple, 0);
21352506Simp					length = pccard_tuple_read_2(&tuple, 2);
21452506Simp					cksum = pccard_tuple_read_1(&tuple, 4);
21552506Simp
21652506Simp					addr = tuple.ptr + offset;
21752506Simp
21852506Simp					DPRINTF(("CISTPL_CHECKSUM addr=%lx "
21952506Simp					    "len=%lx cksum=%x",
22052506Simp					    addr, length, cksum));
22152506Simp
22252506Simp					/*
22352506Simp					 * XXX do more work to deal with
22452506Simp					 * distant regions
22552506Simp					 */
22652506Simp					if ((addr >= PCCARD_CIS_SIZE) ||
22752506Simp					    ((addr + length) < 0) ||
22852506Simp					    ((addr + length) >=
22952506Simp					      PCCARD_CIS_SIZE)) {
23052506Simp						DPRINTF((" skipped, "
23152506Simp						    "too distant\n"));
23252506Simp						break;
23352506Simp					}
23452506Simp					sum = 0;
23552506Simp					for (i = 0; i < length; i++)
23652506Simp						sum +=
23752506Simp						    bus_space_read_1(tuple.memt,
23852506Simp						    tuple.memh,
23952506Simp						    addr + tuple.mult * i);
24052506Simp					if (cksum != (sum & 0xff)) {
24152506Simp						DPRINTF((" failed sum=%x\n",
24252506Simp						    sum));
24355720Simp						device_printf(dev,
24455720Simp						    "CIS checksum failed\n");
24552506Simp#if 0
24652506Simp						/*
24752506Simp						 * XXX Some working cards have
24852506Simp						 * XXX bad checksums!!
24952506Simp						 */
25052506Simp						ret = -1;
25152506Simp#endif
25252506Simp					} else {
25352506Simp						DPRINTF((" ok\n"));
25452506Simp					}
25552506Simp				}
25652506Simp				break;
25752506Simp			case PCCARD_CISTPL_LONGLINK_MFC:
25852506Simp				if (tuple.length < 1) {
25952506Simp					DPRINTF(("CISTPL_LONGLINK_MFC too "
26052506Simp					    "short %d\n", tuple.length));
26152506Simp					break;
26252506Simp				}
26352506Simp				/*
26452506Simp				 * this is kind of ad hoc, as I don't have
26552506Simp				 * any real documentation
26652506Simp				 */
26752506Simp				{
26852506Simp					int i;
26952506Simp
27052506Simp					mfc_count =
27152506Simp					    pccard_tuple_read_1(&tuple, 0);
27252506Simp					DPRINTF(("CISTPL_LONGLINK_MFC %d",
27352506Simp					    mfc_count));
27452506Simp					for (i = 0; i < mfc_count; i++) {
27552506Simp						mfc[i].common =
27652506Simp						    (pccard_tuple_read_1(&tuple,
27752506Simp						    1 + 5 * i) ==
27852506Simp						    PCCARD_MFC_MEM_COMMON) ?
27952506Simp						    1 : 0;
28052506Simp						mfc[i].addr =
28152506Simp						    pccard_tuple_read_4(&tuple,
28252506Simp						    1 + 5 * i + 1);
28352506Simp						DPRINTF((" %s:%lx",
28452506Simp						    mfc[i].common ? "common" :
28552506Simp						    "attr", mfc[i].addr));
28652506Simp					}
28752506Simp					DPRINTF(("\n"));
28852506Simp				}
28952506Simp				/*
29052506Simp				 * for LONGLINK_MFC, fall through to the
29152506Simp				 * function.  This tuple has structural and
29252506Simp				 * semantic content.
29352506Simp				 */
29452506Simp			default:
29552506Simp				{
29652506Simp					if ((*fct) (&tuple, arg)) {
29752506Simp						ret = 1;
29852506Simp						goto done;
29952506Simp					}
30052506Simp				}
30152506Simp				break;
30252506Simp			}	/* switch */
30352506Simp#ifdef PCCARDCISDEBUG
30452506Simp			/* print the tuple */
30552506Simp			{
30652506Simp				int i;
30752506Simp
30852506Simp				DPRINTF((" %02x %02x", tuple.code,
30952506Simp				    tuple.length));
31052506Simp
31152506Simp				for (i = 0; i < tuple.length; i++) {
31252506Simp					DPRINTF((" %02x",
31352506Simp					    pccard_tuple_read_1(&tuple, i)));
31452506Simp					if ((i % 16) == 13)
31552506Simp						DPRINTF(("\n"));
31652506Simp				}
31787352Simp
31852506Simp				if ((i % 16) != 14)
31952506Simp					DPRINTF(("\n"));
32052506Simp			}
32152506Simp#endif
32252506Simp			/* skip to the next tuple */
32352506Simp			tuple.ptr += 2 + tuple.length;
32452506Simp		}
32552506Simp
32652506Simp		/*
32752506Simp		 * the chain is done.  Clean up and move onto the next one,
32852506Simp		 * if any.  The loop is here in the case that there is an MFC
32952506Simp		 * card with no longlink (which defaults to existing, == 0).
33052506Simp		 * In general, this means that if one pointer fails, it will
33152506Simp		 * try the next one, instead of just bailing.
33252506Simp		 */
33352506Simp
33452506Simp		while (1) {
33552506Simp			if (longlink_present) {
33687352Simp				CARD_SET_RES_FLAGS(device_get_parent(dev), dev,
33787352Simp				    SYS_RES_MEMORY, rid, longlink_common ?
33893370Simp				    PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR);
33952506Simp				DPRINTF(("cis mem map %x\n",
34052506Simp				    (unsigned int) tuple.memh));
34152506Simp				tuple.mult = longlink_common ? 1 : 2;
34293370Simp				tuple.ptr = longlink_addr;
34352506Simp				longlink_present = 0;
34452506Simp				longlink_common = 1;
34552506Simp				longlink_addr = 0;
34652506Simp			} else if (mfc_count && (mfc_index < mfc_count)) {
34787352Simp				CARD_SET_RES_FLAGS(device_get_parent(dev), dev,
34887352Simp				    SYS_RES_MEMORY, rid, mfc[mfc_index].common
34993370Simp				    ? PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR);
35052506Simp				DPRINTF(("cis mem map %x\n",
35152506Simp				    (unsigned int) tuple.memh));
35252506Simp				/* set parse state, and point at the next one */
35352506Simp				tuple.mult = mfc[mfc_index].common ? 1 : 2;
35493370Simp				tuple.ptr = mfc[mfc_index].addr;
35552506Simp				mfc_index++;
35652506Simp			} else {
35752506Simp				goto done;
35852506Simp			}
35952506Simp
36052506Simp			/* make sure that the link is valid */
36152506Simp			tuple.code = pccard_cis_read_1(&tuple, tuple.ptr);
36252506Simp			if (tuple.code != PCCARD_CISTPL_LINKTARGET) {
36352506Simp				DPRINTF(("CISTPL_LINKTARGET expected, "
36452506Simp				    "code %02x observed\n", tuple.code));
36552506Simp				continue;
36652506Simp			}
36752506Simp			tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1);
36852506Simp			if (tuple.length < 3) {
36952506Simp				DPRINTF(("CISTPL_LINKTARGET too short %d\n",
37052506Simp				    tuple.length));
37152506Simp				continue;
37252506Simp			}
37352506Simp			if ((pccard_tuple_read_1(&tuple, 0) != 'C') ||
37452506Simp			    (pccard_tuple_read_1(&tuple, 1) != 'I') ||
37552506Simp			    (pccard_tuple_read_1(&tuple, 2) != 'S')) {
37652506Simp				DPRINTF(("CISTPL_LINKTARGET magic "
37752506Simp				    "%02x%02x%02x incorrect\n",
37852506Simp				    pccard_tuple_read_1(&tuple, 0),
37952506Simp				    pccard_tuple_read_1(&tuple, 1),
38052506Simp				    pccard_tuple_read_1(&tuple, 2)));
38152506Simp				continue;
38252506Simp			}
38352506Simp			tuple.ptr += 2 + tuple.length;
38452506Simp			break;
38552506Simp		}
38652506Simp	}
38752506Simp
38852506Simpdone:
38955720Simp	bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
39052506Simp
39152506Simp	return (ret);
39252506Simp}
39352506Simp
39452506Simp/* XXX this is incredibly verbose.  Not sure what trt is */
39552506Simp
39652506Simpvoid
39752506Simppccard_print_cis(device_t dev)
39852506Simp{
39964850Simp	struct pccard_softc *sc = PCCARD_SOFTC(dev);
40052506Simp	struct pccard_card *card = &sc->card;
40152506Simp	struct pccard_function *pf;
40252506Simp	struct pccard_config_entry *cfe;
40352506Simp	int i;
40452506Simp
40552506Simp	device_printf(dev, "CIS version ");
40652506Simp	if (card->cis1_major == 4) {
40752506Simp		if (card->cis1_minor == 0)
40852506Simp			printf("PCCARD 1.0\n");
40952506Simp		else if (card->cis1_minor == 1)
41052506Simp			printf("PCCARD 2.0 or 2.1\n");
41152506Simp	} else if (card->cis1_major >= 5)
41252506Simp		printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor);
41352506Simp	else
41452506Simp		printf("unknown (major=%d, minor=%d)\n",
41552506Simp		    card->cis1_major, card->cis1_minor);
41652506Simp
41752506Simp	device_printf(dev, "CIS info: ");
41852506Simp	for (i = 0; i < 4; i++) {
41952506Simp		if (card->cis1_info[i] == NULL)
42052506Simp			break;
42152506Simp		if (i)
42252506Simp			printf(", ");
42352506Simp		printf("%s", card->cis1_info[i]);
42452506Simp	}
42552506Simp	printf("\n");
42652506Simp
42752506Simp	device_printf(dev, "Manufacturer code 0x%x, product 0x%x\n",
42852506Simp	    card->manufacturer, card->product);
42952506Simp
43052506Simp	STAILQ_FOREACH(pf, &card->pf_head, pf_list) {
43152506Simp		device_printf(dev, "function %d: ", pf->number);
43252506Simp
43352506Simp		switch (pf->function) {
43452506Simp		case PCCARD_FUNCTION_UNSPEC:
43552506Simp			printf("unspecified");
43652506Simp			break;
43752506Simp		case PCCARD_FUNCTION_MULTIFUNCTION:
43852506Simp			printf("multi-function");
43952506Simp			break;
44052506Simp		case PCCARD_FUNCTION_MEMORY:
44152506Simp			printf("memory");
44252506Simp			break;
44352506Simp		case PCCARD_FUNCTION_SERIAL:
44452506Simp			printf("serial port");
44552506Simp			break;
44652506Simp		case PCCARD_FUNCTION_PARALLEL:
44752506Simp			printf("parallel port");
44852506Simp			break;
44952506Simp		case PCCARD_FUNCTION_DISK:
45052506Simp			printf("fixed disk");
45152506Simp			break;
45252506Simp		case PCCARD_FUNCTION_VIDEO:
45352506Simp			printf("video adapter");
45452506Simp			break;
45552506Simp		case PCCARD_FUNCTION_NETWORK:
45652506Simp			printf("network adapter");
45752506Simp			break;
45852506Simp		case PCCARD_FUNCTION_AIMS:
45952506Simp			printf("auto incrementing mass storage");
46052506Simp			break;
46152506Simp		case PCCARD_FUNCTION_SCSI:
46252506Simp			printf("SCSI bridge");
46352506Simp			break;
46452506Simp		case PCCARD_FUNCTION_SECURITY:
46552506Simp			printf("Security services");
46652506Simp			break;
46752506Simp		case PCCARD_FUNCTION_INSTRUMENT:
46852506Simp			printf("Instrument");
46952506Simp			break;
47052506Simp		default:
47152506Simp			printf("unknown (%d)", pf->function);
47252506Simp			break;
47352506Simp		}
47452506Simp
47552506Simp		printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask);
47652506Simp
47752506Simp		STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
47852506Simp			device_printf(dev, "function %d, config table entry "
47952506Simp			    "%d: ", pf->number, cfe->number);
48052506Simp
48152506Simp			switch (cfe->iftype) {
48252506Simp			case PCCARD_IFTYPE_MEMORY:
48352506Simp				printf("memory card");
48452506Simp				break;
48552506Simp			case PCCARD_IFTYPE_IO:
48652506Simp				printf("I/O card");
48752506Simp				break;
48852506Simp			default:
48952506Simp				printf("card type unknown");
49052506Simp				break;
49152506Simp			}
49252506Simp
49352506Simp			printf("; irq mask %x", cfe->irqmask);
49452506Simp
49552506Simp			if (cfe->num_iospace) {
49652506Simp				printf("; iomask %lx, iospace", cfe->iomask);
49752506Simp
49853813Simp				for (i = 0; i < cfe->num_iospace; i++) {
49953813Simp					printf(" %lx", cfe->iospace[i].start);
50053813Simp					if (cfe->iospace[i].length)
50153813Simp						printf("-%lx",
50253813Simp						    cfe->iospace[i].start +
50353813Simp						    cfe->iospace[i].length - 1);
50453813Simp				}
50552506Simp			}
50652506Simp			if (cfe->num_memspace) {
50752506Simp				printf("; memspace");
50852506Simp
50953813Simp				for (i = 0; i < cfe->num_memspace; i++) {
51053813Simp					printf(" %lx",
51153813Simp					    cfe->memspace[i].cardaddr);
51253813Simp					if (cfe->memspace[i].length)
51353813Simp						printf("-%lx",
51453813Simp						    cfe->memspace[i].cardaddr +
51553813Simp						    cfe->memspace[i].length - 1);
51653813Simp					if (cfe->memspace[i].hostaddr)
51753813Simp						printf("@%lx",
51853813Simp						    cfe->memspace[i].hostaddr);
51953813Simp				}
52052506Simp			}
52152506Simp			if (cfe->maxtwins)
52252506Simp				printf("; maxtwins %d", cfe->maxtwins);
52352506Simp
52452506Simp			printf(";");
52552506Simp
52652506Simp			if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED)
52752506Simp				printf(" mwait_required");
52852506Simp			if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE)
52952506Simp				printf(" rdybsy_active");
53052506Simp			if (cfe->flags & PCCARD_CFE_WP_ACTIVE)
53152506Simp				printf(" wp_active");
53252506Simp			if (cfe->flags & PCCARD_CFE_BVD_ACTIVE)
53352506Simp				printf(" bvd_active");
53452506Simp			if (cfe->flags & PCCARD_CFE_IO8)
53552506Simp				printf(" io8");
53652506Simp			if (cfe->flags & PCCARD_CFE_IO16)
53752506Simp				printf(" io16");
53852506Simp			if (cfe->flags & PCCARD_CFE_IRQSHARE)
53952506Simp				printf(" irqshare");
54052506Simp			if (cfe->flags & PCCARD_CFE_IRQPULSE)
54152506Simp				printf(" irqpulse");
54252506Simp			if (cfe->flags & PCCARD_CFE_IRQLEVEL)
54352506Simp				printf(" irqlevel");
54452506Simp			if (cfe->flags & PCCARD_CFE_POWERDOWN)
54552506Simp				printf(" powerdown");
54652506Simp			if (cfe->flags & PCCARD_CFE_READONLY)
54752506Simp				printf(" readonly");
54852506Simp			if (cfe->flags & PCCARD_CFE_AUDIO)
54952506Simp				printf(" audio");
55052506Simp
55152506Simp			printf("\n");
55252506Simp		}
55352506Simp	}
55452506Simp
55552506Simp	if (card->error)
55652506Simp		device_printf(dev, "%d errors found while parsing CIS\n",
55752506Simp		    card->error);
55852506Simp}
55952506Simp
56052506Simpint
56155720Simppccard_parse_cis_tuple(struct pccard_tuple *tuple, void *arg)
56252506Simp{
56352506Simp	/* most of these are educated guesses */
56452506Simp	static struct pccard_config_entry init_cfe = {
56552506Simp		-1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE |
56652506Simp		PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY,
56752506Simp	};
56852506Simp
56952506Simp	struct cis_state *state = arg;
57052506Simp
57152506Simp	switch (tuple->code) {
57252506Simp	case PCCARD_CISTPL_END:
57352506Simp		/* if we've seen a LONGLINK_MFC, and this is the first
57452506Simp		 * END after it, reset the function list.
57552506Simp		 *
57652506Simp		 * XXX This might also be the right place to start a
57752506Simp		 * new function, but that assumes that a function
57852506Simp		 * definition never crosses any longlink, and I'm not
57952506Simp		 * sure about that.  This is probably safe for MFC
58052506Simp		 * cards, but what we have now isn't broken, so I'd
58152506Simp		 * rather not change it.
58252506Simp		 */
58352506Simp		if (state->gotmfc == 1) {
58452506Simp			struct pccard_function *pf, *pfnext;
58552506Simp
58652506Simp			for (pf = STAILQ_FIRST(&state->card->pf_head);
58752506Simp			     pf != NULL; pf = pfnext) {
58852506Simp				pfnext = STAILQ_NEXT(pf, pf_list);
58952506Simp				free(pf, M_DEVBUF);
59052506Simp			}
59152506Simp
59252506Simp			STAILQ_INIT(&state->card->pf_head);
59352506Simp
59452506Simp			state->count = 0;
59552506Simp			state->gotmfc = 2;
59652506Simp			state->pf = NULL;
59752506Simp		}
59852506Simp		break;
59952506Simp	case PCCARD_CISTPL_LONGLINK_MFC:
60052506Simp		/*
60152506Simp		 * this tuple's structure was dealt with in scan_cis.  here,
60252506Simp		 * record the fact that the MFC tuple was seen, so that
60352506Simp		 * functions declared before the MFC link can be cleaned
60452506Simp		 * up.
60552506Simp		 */
60652506Simp		state->gotmfc = 1;
60752506Simp		break;
60852506Simp#ifdef PCCARDCISDEBUG
60952506Simp	case PCCARD_CISTPL_DEVICE:
61052506Simp	case PCCARD_CISTPL_DEVICE_A:
61152506Simp		{
61252506Simp			u_int reg, dtype, dspeed;
61352506Simp
61452506Simp			reg = pccard_tuple_read_1(tuple, 0);
61552506Simp			dtype = reg & PCCARD_DTYPE_MASK;
61652506Simp			dspeed = reg & PCCARD_DSPEED_MASK;
61752506Simp
61852506Simp			DPRINTF(("CISTPL_DEVICE%s type=",
61952506Simp			(tuple->code == PCCARD_CISTPL_DEVICE) ? "" : "_A"));
62052506Simp			switch (dtype) {
62152506Simp			case PCCARD_DTYPE_NULL:
62252506Simp				DPRINTF(("null"));
62352506Simp				break;
62452506Simp			case PCCARD_DTYPE_ROM:
62552506Simp				DPRINTF(("rom"));
62652506Simp				break;
62752506Simp			case PCCARD_DTYPE_OTPROM:
62852506Simp				DPRINTF(("otprom"));
62952506Simp				break;
63052506Simp			case PCCARD_DTYPE_EPROM:
63152506Simp				DPRINTF(("eprom"));
63252506Simp				break;
63352506Simp			case PCCARD_DTYPE_EEPROM:
63452506Simp				DPRINTF(("eeprom"));
63552506Simp				break;
63652506Simp			case PCCARD_DTYPE_FLASH:
63752506Simp				DPRINTF(("flash"));
63852506Simp				break;
63952506Simp			case PCCARD_DTYPE_SRAM:
64052506Simp				DPRINTF(("sram"));
64152506Simp				break;
64252506Simp			case PCCARD_DTYPE_DRAM:
64352506Simp				DPRINTF(("dram"));
64452506Simp				break;
64552506Simp			case PCCARD_DTYPE_FUNCSPEC:
64652506Simp				DPRINTF(("funcspec"));
64752506Simp				break;
64852506Simp			case PCCARD_DTYPE_EXTEND:
64952506Simp				DPRINTF(("extend"));
65052506Simp				break;
65152506Simp			default:
65252506Simp				DPRINTF(("reserved"));
65352506Simp				break;
65452506Simp			}
65552506Simp			DPRINTF((" speed="));
65652506Simp			switch (dspeed) {
65752506Simp			case PCCARD_DSPEED_NULL:
65852506Simp				DPRINTF(("null"));
65952506Simp				break;
66052506Simp			case PCCARD_DSPEED_250NS:
66152506Simp				DPRINTF(("250ns"));
66252506Simp				break;
66352506Simp			case PCCARD_DSPEED_200NS:
66452506Simp				DPRINTF(("200ns"));
66552506Simp				break;
66652506Simp			case PCCARD_DSPEED_150NS:
66752506Simp				DPRINTF(("150ns"));
66852506Simp				break;
66952506Simp			case PCCARD_DSPEED_100NS:
67052506Simp				DPRINTF(("100ns"));
67152506Simp				break;
67252506Simp			case PCCARD_DSPEED_EXT:
67352506Simp				DPRINTF(("ext"));
67452506Simp				break;
67552506Simp			default:
67652506Simp				DPRINTF(("reserved"));
67752506Simp				break;
67852506Simp			}
67952506Simp		}
68052506Simp		DPRINTF(("\n"));
68152506Simp		break;
68252506Simp#endif
68352506Simp	case PCCARD_CISTPL_VERS_1:
68452506Simp		if (tuple->length < 6) {
68552506Simp			DPRINTF(("CISTPL_VERS_1 too short %d\n",
68652506Simp			    tuple->length));
68752506Simp			break;
68852506Simp		} {
68952506Simp			int start, i, ch, count;
69052506Simp
69152506Simp			state->card->cis1_major = pccard_tuple_read_1(tuple, 0);
69252506Simp			state->card->cis1_minor = pccard_tuple_read_1(tuple, 1);
69352506Simp
69452506Simp			for (count = 0, start = 0, i = 0;
69552506Simp			    (count < 4) && ((i + 4) < 256); i++) {
69652506Simp				ch = pccard_tuple_read_1(tuple, 2 + i);
69752506Simp				if (ch == 0xff)
69852506Simp					break;
69952506Simp				state->card->cis1_info_buf[i] = ch;
70052506Simp				if (ch == 0) {
70152506Simp					state->card->cis1_info[count] =
70252506Simp					    state->card->cis1_info_buf + start;
70352506Simp					start = i + 1;
70452506Simp					count++;
70552506Simp				}
70652506Simp			}
70752506Simp			DPRINTF(("CISTPL_VERS_1\n"));
70852506Simp		}
70952506Simp		break;
71052506Simp	case PCCARD_CISTPL_MANFID:
71152506Simp		if (tuple->length < 4) {
71252506Simp			DPRINTF(("CISTPL_MANFID too short %d\n",
71352506Simp			    tuple->length));
71452506Simp			break;
71552506Simp		}
71652506Simp		state->card->manufacturer = pccard_tuple_read_2(tuple, 0);
71752506Simp		state->card->product = pccard_tuple_read_2(tuple, 2);
71890964Sshiba		/*
719104604Simp		 * This is for xe driver. But not limited to that driver.
72090964Sshiba		 * In PC Card Standard,
72190964Sshiba		 * Manufacturer ID: 2byte.
722104604Simp		 * Product ID: typically 2bytes, but there's no limit on its
723104604Simp		 * size.  prodext is a two byte field, so maybe we should
724104604Simp		 * also handle the '6' case.  So far no cards have surfaced
725104604Simp		 * with a length of '6'.
72690964Sshiba		 */
72790964Sshiba		if (tuple->length == 5 ) {
72890964Sshiba			state->card->prodext = pccard_tuple_read_1(tuple, 4);
72990964Sshiba		}
73052506Simp		DPRINTF(("CISTPL_MANFID\n"));
73152506Simp		break;
73252506Simp	case PCCARD_CISTPL_FUNCID:
73352506Simp		if (tuple->length < 1) {
73452506Simp			DPRINTF(("CISTPL_FUNCID too short %d\n",
73552506Simp			    tuple->length));
73652506Simp			break;
73752506Simp		}
73852506Simp		if ((state->pf == NULL) || (state->gotmfc == 2)) {
73952506Simp			state->pf = malloc(sizeof(*state->pf), M_DEVBUF,
74067897Sdwmalone			    M_NOWAIT | M_ZERO);
74152506Simp			state->pf->number = state->count++;
74252506Simp			state->pf->last_config_index = -1;
74352506Simp			STAILQ_INIT(&state->pf->cfe_head);
74452506Simp
74552506Simp			STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf,
74652506Simp			    pf_list);
74752506Simp		}
74852506Simp		state->pf->function = pccard_tuple_read_1(tuple, 0);
74952506Simp
75052506Simp		DPRINTF(("CISTPL_FUNCID\n"));
75152506Simp		break;
75282781Sshiba        case PCCARD_CISTPL_FUNCE:
75382781Sshiba                if (state->pf == NULL || state->pf->function <= 0) {
75482781Sshiba                        DPRINTF(("CISTPL_FUNCE is not followed by "
75582781Sshiba                                "valid CISTPL_FUNCID\n"));
75682781Sshiba                        break;
75782781Sshiba                }
75882781Sshiba                if (tuple->length >= 2) {
75982781Sshiba                        decode_funce(tuple, state->pf);
76082781Sshiba                }
76182781Sshiba                DPRINTF(("CISTPL_FUNCE\n"));
76282781Sshiba                break;
76352506Simp	case PCCARD_CISTPL_CONFIG:
76452506Simp		if (tuple->length < 3) {
76552506Simp			DPRINTF(("CISTPL_CONFIG too short %d\n",
76652506Simp			    tuple->length));
76752506Simp			break;
76852506Simp		} {
76952506Simp			u_int reg, rasz, rmsz, rfsz;
77052506Simp			int i;
77152506Simp
77252506Simp			reg = pccard_tuple_read_1(tuple, 0);
77352506Simp			rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >>
77452506Simp			    PCCARD_TPCC_RASZ_SHIFT);
77552506Simp			rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >>
77652506Simp			    PCCARD_TPCC_RMSZ_SHIFT);
77752506Simp			rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >>
77852506Simp			    PCCARD_TPCC_RFSZ_SHIFT);
77952506Simp
78052506Simp			if (tuple->length < (rasz + rmsz + rfsz)) {
78152506Simp				DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too "
78252506Simp				    "short %d\n", rasz, rmsz, rfsz,
78352506Simp				    tuple->length));
78452506Simp				break;
78552506Simp			}
78652506Simp			if (state->pf == NULL) {
78752506Simp				state->pf = malloc(sizeof(*state->pf),
78867897Sdwmalone				    M_DEVBUF, M_NOWAIT | M_ZERO);
78952506Simp				state->pf->number = state->count++;
79052506Simp				state->pf->last_config_index = -1;
79152506Simp				STAILQ_INIT(&state->pf->cfe_head);
79252506Simp
79352506Simp				STAILQ_INSERT_TAIL(&state->card->pf_head,
79452506Simp				    state->pf, pf_list);
79552506Simp
79652506Simp				state->pf->function = PCCARD_FUNCTION_UNSPEC;
79752506Simp			}
79852506Simp			state->pf->last_config_index =
79952506Simp			    pccard_tuple_read_1(tuple, 1);
80052506Simp
80152506Simp			state->pf->ccr_base = 0;
80252506Simp			for (i = 0; i < rasz; i++)
80352506Simp				state->pf->ccr_base |=
80452506Simp				    ((pccard_tuple_read_1(tuple, 2 + i)) <<
80552506Simp				    (i * 8));
80652506Simp
80752506Simp			state->pf->ccr_mask = 0;
80852506Simp			for (i = 0; i < rmsz; i++)
80952506Simp				state->pf->ccr_mask |=
81052506Simp				    ((pccard_tuple_read_1(tuple,
81152506Simp				    2 + rasz + i)) << (i * 8));
81252506Simp
81352506Simp			/* skip the reserved area and subtuples */
81452506Simp
81552506Simp			/* reset the default cfe for each cfe list */
81652506Simp			state->temp_cfe = init_cfe;
81752506Simp			state->default_cfe = &state->temp_cfe;
81852506Simp		}
81952506Simp		DPRINTF(("CISTPL_CONFIG\n"));
82052506Simp		break;
82152506Simp	case PCCARD_CISTPL_CFTABLE_ENTRY:
82252506Simp		{
82352506Simp			int idx, i, j;
82452506Simp			u_int reg, reg2;
82552506Simp			u_int intface, def, num;
82652506Simp			u_int power, timing, iospace, irq, memspace, misc;
82752506Simp			struct pccard_config_entry *cfe;
82852506Simp
82952506Simp			idx = 0;
83052506Simp
83152506Simp			reg = pccard_tuple_read_1(tuple, idx);
83252506Simp			idx++;
83352506Simp			intface = reg & PCCARD_TPCE_INDX_INTFACE;
83452506Simp			def = reg & PCCARD_TPCE_INDX_DEFAULT;
83552506Simp			num = reg & PCCARD_TPCE_INDX_NUM_MASK;
83652506Simp
83752506Simp			/*
83852506Simp			 * this is a little messy.  Some cards have only a
83952506Simp			 * cfentry with the default bit set.  So, as we go
84052506Simp			 * through the list, we add new indexes to the queue,
84152506Simp			 * and keep a pointer to the last one with the
84252506Simp			 * default bit set.  if we see a record with the same
84352506Simp			 * index, as the default, we stash the default and
84452506Simp			 * replace the queue entry. otherwise, we just add
84552506Simp			 * new entries to the queue, pointing the default ptr
84652506Simp			 * at them if the default bit is set.  if we get to
84752506Simp			 * the end with the default pointer pointing at a
84852506Simp			 * record which hasn't had a matching index, that's
84952506Simp			 * ok; it just becomes a cfentry like any other.
85052506Simp			 */
85152506Simp
85252506Simp			/*
85352506Simp			 * if the index in the cis differs from the default
85452506Simp			 * cis, create new entry in the queue and start it
85552506Simp			 * with the current default
85652506Simp			 */
85752506Simp			if (num != state->default_cfe->number) {
85852506Simp				cfe = (struct pccard_config_entry *)
85952506Simp				    malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
86052506Simp
86152506Simp				*cfe = *state->default_cfe;
86252506Simp
86352506Simp				STAILQ_INSERT_TAIL(&state->pf->cfe_head,
86452506Simp				    cfe, cfe_list);
86552506Simp
86652506Simp				cfe->number = num;
86752506Simp
86852506Simp				/*
86952506Simp				 * if the default bit is set in the cis, then
87052506Simp				 * point the new default at whatever is being
87152506Simp				 * filled in
87252506Simp				 */
87352506Simp				if (def)
87452506Simp					state->default_cfe = cfe;
87552506Simp			} else {
87652506Simp				/*
87752506Simp				 * the cis index matches the default index,
87852506Simp				 * fill in the default cfentry.  It is
87952506Simp				 * assumed that the cfdefault index is in the
88052506Simp				 * queue.  For it to be otherwise, the cis
88152506Simp				 * index would have to be -1 (initial
88252506Simp				 * condition) which is not possible, or there
88352506Simp				 * would have to be a preceding cis entry
88452506Simp				 * which had the same cis index and had the
88552506Simp				 * default bit unset. Neither condition
88652506Simp				 * should happen.  If it does, this cfentry
88752506Simp				 * is lost (written into temp space), which
88852506Simp				 * is an acceptable failure mode.
88952506Simp				 */
89052506Simp
89152506Simp				cfe = state->default_cfe;
89252506Simp
89352506Simp				/*
89452506Simp				 * if the cis entry does not have the default
89552506Simp				 * bit set, copy the default out of the way
89652506Simp				 * first.
89752506Simp				 */
89852506Simp				if (!def) {
89952506Simp					state->temp_cfe = *state->default_cfe;
90052506Simp					state->default_cfe = &state->temp_cfe;
90152506Simp				}
90252506Simp			}
90352506Simp
90452506Simp			if (intface) {
90552506Simp				reg = pccard_tuple_read_1(tuple, idx);
90652506Simp				idx++;
90752506Simp				if (reg & PCCARD_TPCE_IF_MWAIT)
90852506Simp					cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED;
90952506Simp				if (reg & PCCARD_TPCE_IF_RDYBSY)
91052506Simp					cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE;
91152506Simp				if (reg & PCCARD_TPCE_IF_WP)
91252506Simp					cfe->flags |= PCCARD_CFE_WP_ACTIVE;
91352506Simp				if (reg & PCCARD_TPCE_IF_BVD)
91452506Simp					cfe->flags |= PCCARD_CFE_BVD_ACTIVE;
91552506Simp				cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE;
91652506Simp			}
91752506Simp			reg = pccard_tuple_read_1(tuple, idx);
91852506Simp			idx++;
91952506Simp
92052506Simp			power = reg & PCCARD_TPCE_FS_POWER_MASK;
92152506Simp			timing = reg & PCCARD_TPCE_FS_TIMING;
92252506Simp			iospace = reg & PCCARD_TPCE_FS_IOSPACE;
92352506Simp			irq = reg & PCCARD_TPCE_FS_IRQ;
92452506Simp			memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK;
92552506Simp			misc = reg & PCCARD_TPCE_FS_MISC;
92652506Simp
92752506Simp			if (power) {
92852506Simp				/* skip over power, don't save */
92952506Simp				/* for each parameter selection byte */
93052506Simp				for (i = 0; i < power; i++) {
93152506Simp					reg = pccard_tuple_read_1(tuple, idx);
93252506Simp					idx++;
93352506Simp					/* for each bit */
93452506Simp					for (j = 0; j < 7; j++) {
93552506Simp						/* if the bit is set */
93652506Simp						if ((reg >> j) & 0x01) {
93752506Simp							/* skip over bytes */
93852506Simp							do {
93952506Simp								reg2 = pccard_tuple_read_1(tuple, idx);
94052506Simp								idx++;
94152506Simp								/*
94252506Simp								 * until
94352506Simp								 * non-extensi
94452506Simp								 * on byte
94552506Simp								 */
94652506Simp							} while (reg2 & 0x80);
94752506Simp						}
94852506Simp					}
94952506Simp				}
95052506Simp			}
95152506Simp			if (timing) {
95252506Simp				/* skip over timing, don't save */
95352506Simp				reg = pccard_tuple_read_1(tuple, idx);
95452506Simp				idx++;
95552506Simp
95652506Simp				if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) !=
95752506Simp				    PCCARD_TPCE_TD_RESERVED_MASK)
95852506Simp					idx++;
95952506Simp				if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) !=
96052506Simp				    PCCARD_TPCE_TD_RDYBSY_MASK)
96152506Simp					idx++;
96252506Simp				if ((reg & PCCARD_TPCE_TD_WAIT_MASK) !=
96352506Simp				    PCCARD_TPCE_TD_WAIT_MASK)
96452506Simp					idx++;
96552506Simp			}
96652506Simp			if (iospace) {
96752506Simp				if (tuple->length <= idx) {
96852506Simp					DPRINTF(("ran out of space before TCPE_IO\n"));
96952506Simp					goto abort_cfe;
97052506Simp				}
97152506Simp
97252506Simp				reg = pccard_tuple_read_1(tuple, idx);
97352506Simp				idx++;
97452506Simp
97552506Simp				if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT)
97652506Simp					cfe->flags |= PCCARD_CFE_IO8;
97752506Simp				if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT)
97852506Simp					cfe->flags |= PCCARD_CFE_IO16;
97952506Simp				cfe->iomask =
98052506Simp				    reg & PCCARD_TPCE_IO_IOADDRLINES_MASK;
98152506Simp
98252506Simp				if (reg & PCCARD_TPCE_IO_HASRANGE) {
98352506Simp					reg = pccard_tuple_read_1(tuple, idx);
98452506Simp					idx++;
98552506Simp
98652506Simp					cfe->num_iospace = 1 + (reg &
98752506Simp					    PCCARD_TPCE_IO_RANGE_COUNT);
98852506Simp
98952506Simp					if (cfe->num_iospace >
99052506Simp					    (sizeof(cfe->iospace) /
99152506Simp					     sizeof(cfe->iospace[0]))) {
99252506Simp						DPRINTF(("too many io "
99352506Simp						    "spaces %d",
99452506Simp						    cfe->num_iospace));
99552506Simp						state->card->error++;
99652506Simp						break;
99752506Simp					}
99852506Simp					for (i = 0; i < cfe->num_iospace; i++) {
99952506Simp						switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) {
100052506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE:
100152506Simp							cfe->iospace[i].start =
100252506Simp								pccard_tuple_read_1(tuple, idx);
100352506Simp							idx++;
100452506Simp							break;
100552506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO:
100652506Simp							cfe->iospace[i].start =
100752506Simp								pccard_tuple_read_2(tuple, idx);
100852506Simp							idx += 2;
100952506Simp							break;
101052506Simp						case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR:
101152506Simp							cfe->iospace[i].start =
101252506Simp								pccard_tuple_read_4(tuple, idx);
101352506Simp							idx += 4;
101452506Simp							break;
101552506Simp						}
101652506Simp						switch (reg &
101752506Simp							PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) {
101852506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE:
101952506Simp							cfe->iospace[i].length =
102052506Simp								pccard_tuple_read_1(tuple, idx);
102152506Simp							idx++;
102252506Simp							break;
102352506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO:
102452506Simp							cfe->iospace[i].length =
102552506Simp								pccard_tuple_read_2(tuple, idx);
102652506Simp							idx += 2;
102752506Simp							break;
102852506Simp						case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR:
102952506Simp							cfe->iospace[i].length =
103052506Simp								pccard_tuple_read_4(tuple, idx);
103152506Simp							idx += 4;
103252506Simp							break;
103352506Simp						}
103452506Simp						cfe->iospace[i].length++;
103552506Simp					}
103652506Simp				} else {
103752506Simp					cfe->num_iospace = 1;
103852506Simp					cfe->iospace[0].start = 0;
103952506Simp					cfe->iospace[0].length =
104052506Simp					    (1 << cfe->iomask);
104152506Simp				}
104252506Simp			}
104352506Simp			if (irq) {
104452506Simp				if (tuple->length <= idx) {
104552506Simp					DPRINTF(("ran out of space before TCPE_IR\n"));
104652506Simp					goto abort_cfe;
104752506Simp				}
104852506Simp
104952506Simp				reg = pccard_tuple_read_1(tuple, idx);
105052506Simp				idx++;
105152506Simp
105252506Simp				if (reg & PCCARD_TPCE_IR_SHARE)
105352506Simp					cfe->flags |= PCCARD_CFE_IRQSHARE;
105452506Simp				if (reg & PCCARD_TPCE_IR_PULSE)
105552506Simp					cfe->flags |= PCCARD_CFE_IRQPULSE;
105652506Simp				if (reg & PCCARD_TPCE_IR_LEVEL)
105752506Simp					cfe->flags |= PCCARD_CFE_IRQLEVEL;
105852506Simp
105952506Simp				if (reg & PCCARD_TPCE_IR_HASMASK) {
106052506Simp					/*
106152506Simp					 * it's legal to ignore the
106252506Simp					 * special-interrupt bits, so I will
106352506Simp					 */
106452506Simp
106552506Simp					cfe->irqmask =
106652506Simp					    pccard_tuple_read_2(tuple, idx);
106752506Simp					idx += 2;
106852506Simp				} else {
106952506Simp					cfe->irqmask =
107052506Simp					    (1 << (reg & PCCARD_TPCE_IR_IRQ));
107152506Simp				}
107252506Simp			}
107352506Simp			if (memspace) {
107452506Simp				if (tuple->length <= idx) {
107552506Simp					DPRINTF(("ran out of space before TCPE_MS\n"));
107652506Simp					goto abort_cfe;
107752506Simp				}
107852506Simp
107952506Simp				if (memspace == PCCARD_TPCE_FS_MEMSPACE_NONE) {
108052506Simp					cfe->num_memspace = 0;
108152506Simp				} else if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) {
108252506Simp					cfe->num_memspace = 1;
108352506Simp					cfe->memspace[0].length = 256 *
108452506Simp					    pccard_tuple_read_2(tuple, idx);
108552506Simp					idx += 2;
108652506Simp					cfe->memspace[0].cardaddr = 0;
108752506Simp					cfe->memspace[0].hostaddr = 0;
108852506Simp				} else if (memspace ==
108952506Simp				    PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) {
109052506Simp					cfe->num_memspace = 1;
109152506Simp					cfe->memspace[0].length = 256 *
109252506Simp					    pccard_tuple_read_2(tuple, idx);
109352506Simp					idx += 2;
109452506Simp					cfe->memspace[0].cardaddr = 256 *
109552506Simp					    pccard_tuple_read_2(tuple, idx);
109652506Simp					idx += 2;
109752506Simp					cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr;
109852506Simp				} else {
109952506Simp					int lengthsize;
110052506Simp					int cardaddrsize;
110152506Simp					int hostaddrsize;
110252506Simp
110352506Simp					reg = pccard_tuple_read_1(tuple, idx);
110452506Simp					idx++;
110552506Simp
110653873Simp					cfe->num_memspace = (reg &
110753873Simp					    PCCARD_TPCE_MS_COUNT) + 1;
110852506Simp
110952506Simp					if (cfe->num_memspace >
111052506Simp					    (sizeof(cfe->memspace) /
111152506Simp					     sizeof(cfe->memspace[0]))) {
111252506Simp						DPRINTF(("too many mem "
111352506Simp						    "spaces %d",
111452506Simp						    cfe->num_memspace));
111552506Simp						state->card->error++;
111652506Simp						break;
111752506Simp					}
111852506Simp					lengthsize =
111952506Simp						((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >>
112052506Simp						 PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT);
112152506Simp					cardaddrsize =
112252506Simp						((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >>
112352506Simp						 PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT);
112452506Simp					hostaddrsize =
112552506Simp						(reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0;
112652506Simp
112752506Simp					if (lengthsize == 0) {
112852506Simp						DPRINTF(("cfe memspace "
112952506Simp						    "lengthsize == 0"));
113052506Simp						state->card->error++;
113152506Simp					}
113252506Simp					for (i = 0; i < cfe->num_memspace; i++) {
113352506Simp						if (lengthsize) {
113452506Simp							cfe->memspace[i].length =
113552506Simp								256 * pccard_tuple_read_n(tuple, lengthsize,
113652506Simp								       idx);
113752506Simp							idx += lengthsize;
113852506Simp						} else {
113952506Simp							cfe->memspace[i].length = 0;
114052506Simp						}
114152506Simp						if (cfe->memspace[i].length == 0) {
114252506Simp							DPRINTF(("cfe->memspace[%d].length == 0",
114352506Simp								 i));
114452506Simp							state->card->error++;
114552506Simp						}
114652506Simp						if (cardaddrsize) {
114752506Simp							cfe->memspace[i].cardaddr =
114852506Simp								256 * pccard_tuple_read_n(tuple, cardaddrsize,
114952506Simp								       idx);
115052506Simp							idx += cardaddrsize;
115152506Simp						} else {
115252506Simp							cfe->memspace[i].cardaddr = 0;
115352506Simp						}
115452506Simp						if (hostaddrsize) {
115552506Simp							cfe->memspace[i].hostaddr =
115652506Simp								256 * pccard_tuple_read_n(tuple, hostaddrsize,
115752506Simp								       idx);
115852506Simp							idx += hostaddrsize;
115952506Simp						} else {
116052506Simp							cfe->memspace[i].hostaddr = 0;
116152506Simp						}
116252506Simp					}
116352506Simp				}
116452506Simp			}
116552506Simp			if (misc) {
116652506Simp				if (tuple->length <= idx) {
116752506Simp					DPRINTF(("ran out of space before TCPE_MI\n"));
116852506Simp					goto abort_cfe;
116952506Simp				}
117052506Simp
117152506Simp				reg = pccard_tuple_read_1(tuple, idx);
117252506Simp				idx++;
117352506Simp
117452506Simp				if (reg & PCCARD_TPCE_MI_PWRDOWN)
117552506Simp					cfe->flags = PCCARD_CFE_POWERDOWN;
117652506Simp				if (reg & PCCARD_TPCE_MI_READONLY)
117752506Simp					cfe->flags = PCCARD_CFE_READONLY;
117852506Simp				if (reg & PCCARD_TPCE_MI_AUDIO)
117952506Simp					cfe->flags = PCCARD_CFE_AUDIO;
118052506Simp				cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS;
118152506Simp
118252506Simp				while (reg & PCCARD_TPCE_MI_EXT) {
118352506Simp					reg = pccard_tuple_read_1(tuple, idx);
118452506Simp					idx++;
118552506Simp				}
118652506Simp			}
118752506Simp			/* skip all the subtuples */
118852506Simp		}
118952506Simp
119052506Simp	abort_cfe:
119152506Simp		DPRINTF(("CISTPL_CFTABLE_ENTRY\n"));
119252506Simp		break;
119352506Simp	default:
119452506Simp		DPRINTF(("unhandled CISTPL %x\n", tuple->code));
119552506Simp		break;
119652506Simp	}
119752506Simp
119852506Simp	return (0);
119952506Simp}
120082781Sshiba
120182781Sshibastatic int
120282781Sshibadecode_funce(struct pccard_tuple *tuple, struct pccard_function *pf)
120382781Sshiba{
120482781Sshiba	int type = pccard_tuple_read_1(tuple, 0);
120582781Sshiba
120682781Sshiba	switch (pf->function) {
120782781Sshiba	case PCCARD_FUNCTION_DISK:
120882781Sshiba		if (type == PCCARD_TPLFE_TYPE_DISK_DEVICE_INTERFACE) {
120982781Sshiba			pf->pf_funce_disk_interface
121082781Sshiba				= pccard_tuple_read_1(tuple, 1);
121182781Sshiba		}
121282781Sshiba		break;
121382781Sshiba	case PCCARD_FUNCTION_NETWORK:
121482781Sshiba		if (type == PCCARD_TPLFE_TYPE_LAN_NID) {
121582781Sshiba			int i;
121682781Sshiba			int len = pccard_tuple_read_1(tuple, 1);
121782781Sshiba			if (tuple->length < 2 + len || len > 8) {
121882781Sshiba				/* tuple length not enough or nid too long */
121982781Sshiba				break;
122082781Sshiba                        }
122182781Sshiba			for (i = 0; i < len; i++) {
122282781Sshiba				pf->pf_funce_lan_nid[i]
122382781Sshiba					= pccard_tuple_read_1(tuple, i + 2);
122482781Sshiba			}
122582781Sshiba			pf->pf_funce_lan_nidlen = len;
122682781Sshiba		}
122782781Sshiba		break;
122882781Sshiba	default:
122982781Sshiba		break;
123082781Sshiba	}
123182781Sshiba	return 0;
123282781Sshiba}
1233