xref: /freebsd/sys/dev/cardbus/cardbus_cis.c (revision 41ac33a2b6c7eef4c04e5f4016e8351f025f8293)
1098ca2bdSWarner Losh /*-
20db7e66cSJonathan Chen  * Copyright (c) 2000,2001 Jonathan Chen.
30db7e66cSJonathan Chen  * All rights reserved.
40db7e66cSJonathan Chen  *
50db7e66cSJonathan Chen  * Redistribution and use in source and binary forms, with or without
60db7e66cSJonathan Chen  * modification, are permitted provided that the following conditions
70db7e66cSJonathan Chen  * are met:
80db7e66cSJonathan Chen  * 1. Redistributions of source code must retain the above copyright
92dd5c91eSWarner Losh  *    notice, this list of conditions and the following disclaimer.
100db7e66cSJonathan Chen  * 2. Redistributions in binary form must reproduce the above copyright
112dd5c91eSWarner Losh  *    notice, this list of conditions and the following disclaimer in the
122dd5c91eSWarner Losh  *    documentation and/or other materials provided with the distribution.
130db7e66cSJonathan Chen  *
140db7e66cSJonathan Chen  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
150db7e66cSJonathan Chen  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
160db7e66cSJonathan Chen  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172dd5c91eSWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182dd5c91eSWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
190db7e66cSJonathan Chen  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
200db7e66cSJonathan Chen  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
210db7e66cSJonathan Chen  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
220db7e66cSJonathan Chen  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
230db7e66cSJonathan Chen  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
240db7e66cSJonathan Chen  * SUCH DAMAGE.
250db7e66cSJonathan Chen  */
260db7e66cSJonathan Chen 
27aad970f1SDavid E. O'Brien #include <sys/cdefs.h>
28aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$");
29aad970f1SDavid E. O'Brien 
300db7e66cSJonathan Chen /*
310db7e66cSJonathan Chen  * CIS Handling for the Cardbus Bus
320db7e66cSJonathan Chen  */
330db7e66cSJonathan Chen 
340db7e66cSJonathan Chen #include <sys/param.h>
350db7e66cSJonathan Chen #include <sys/systm.h>
360db7e66cSJonathan Chen #include <sys/kernel.h>
370c95c705SJonathan Chen #include <sys/malloc.h>
380db7e66cSJonathan Chen 
390db7e66cSJonathan Chen #include <sys/bus.h>
400db7e66cSJonathan Chen #include <machine/bus.h>
410db7e66cSJonathan Chen #include <machine/resource.h>
420db7e66cSJonathan Chen #include <sys/rman.h>
431e962d00SScott Long #include <sys/endian.h>
440db7e66cSJonathan Chen 
457ba175acSWarner Losh #include <sys/pciio.h>
4663fa9f4cSJonathan Chen #include <dev/pci/pcivar.h>
4763fa9f4cSJonathan Chen #include <dev/pci/pcireg.h>
480db7e66cSJonathan Chen 
49a294cdb6SWarner Losh #include <dev/pccard/pccardvar.h>
50a294cdb6SWarner Losh #include <dev/pccard/pccard_cis.h>
51a294cdb6SWarner Losh 
520db7e66cSJonathan Chen #include <dev/cardbus/cardbusreg.h>
5363fa9f4cSJonathan Chen #include <dev/cardbus/cardbusvar.h>
540db7e66cSJonathan Chen #include <dev/cardbus/cardbus_cis.h>
550db7e66cSJonathan Chen 
56b3889b68SWarner Losh extern int cardbus_cis_debug;
57b3889b68SWarner Losh 
58b3889b68SWarner Losh #define	DPRINTF(a) if (cardbus_cis_debug) printf a
59b3889b68SWarner Losh #define	DEVPRINTF(x) if (cardbus_cis_debug) device_printf x
60b3889b68SWarner Losh 
6122acd92bSWarner Losh struct tuple_callbacks;
6222acd92bSWarner Losh 
6322acd92bSWarner Losh typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
6422acd92bSWarner Losh 		 uint8_t *tupledata, uint32_t start, uint32_t *off,
6522acd92bSWarner Losh 		 struct tuple_callbacks *info);
660db7e66cSJonathan Chen 
670c95c705SJonathan Chen struct tuple_callbacks {
680c95c705SJonathan Chen 	int	id;
690db7e66cSJonathan Chen 	char	*name;
7022acd92bSWarner Losh 	tuple_cb *func;
710db7e66cSJonathan Chen };
72255b159fSJonathan Chen 
7322acd92bSWarner Losh static int decode_tuple_generic(device_t cbdev, device_t child, int id,
7422acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
7522acd92bSWarner Losh     struct tuple_callbacks *info);
7622acd92bSWarner Losh static int decode_tuple_linktarget(device_t cbdev, device_t child, int id,
7722acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
7822acd92bSWarner Losh     struct tuple_callbacks *info);
7922acd92bSWarner Losh static int decode_tuple_vers_1(device_t cbdev, device_t child, int id,
8022acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
8122acd92bSWarner Losh     struct tuple_callbacks *info);
8222acd92bSWarner Losh static int decode_tuple_funcid(device_t cbdev, device_t child, int id,
8322acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
8422acd92bSWarner Losh     struct tuple_callbacks *info);
8522acd92bSWarner Losh static int decode_tuple_manfid(device_t cbdev, device_t child, int id,
8622acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
8722acd92bSWarner Losh     struct tuple_callbacks *info);
8822acd92bSWarner Losh static int decode_tuple_funce(device_t cbdev, device_t child, int id,
8922acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
9022acd92bSWarner Losh     struct tuple_callbacks *info);
9122acd92bSWarner Losh static int decode_tuple_bar(device_t cbdev, device_t child, int id,
9222acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
9322acd92bSWarner Losh     struct tuple_callbacks *info);
9422acd92bSWarner Losh static int decode_tuple_unhandled(device_t cbdev, device_t child, int id,
9522acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
9622acd92bSWarner Losh     struct tuple_callbacks *info);
9722acd92bSWarner Losh static int decode_tuple_end(device_t cbdev, device_t child, int id,
9822acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
9922acd92bSWarner Losh     struct tuple_callbacks *info);
10022acd92bSWarner Losh 
101255b159fSJonathan Chen static int	cardbus_read_tuple_conf(device_t cbdev, device_t child,
10266e390feSWarner Losh 		    uint32_t start, uint32_t *off, int *tupleid, int *len,
10366e390feSWarner Losh 		    uint8_t *tupledata);
10463fa9f4cSJonathan Chen static int	cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
10566e390feSWarner Losh 		    uint32_t start, uint32_t *off, int *tupleid, int *len,
10666e390feSWarner Losh 		    uint8_t *tupledata);
107255b159fSJonathan Chen static int	cardbus_read_tuple(device_t cbdev, device_t child,
10866e390feSWarner Losh 		    struct resource *res, uint32_t start, uint32_t *off,
10966e390feSWarner Losh 		    int *tupleid, int *len, uint8_t *tupledata);
11063fa9f4cSJonathan Chen static void	cardbus_read_tuple_finish(device_t cbdev, device_t child,
11163fa9f4cSJonathan Chen 		    int rid, struct resource *res);
11263fa9f4cSJonathan Chen static struct resource	*cardbus_read_tuple_init(device_t cbdev, device_t child,
11366e390feSWarner Losh 		    uint32_t *start, int *rid);
114255b159fSJonathan Chen static int	decode_tuple(device_t cbdev, device_t child, int tupleid,
11566e390feSWarner Losh 		    int len, uint8_t *tupledata, uint32_t start,
11666e390feSWarner Losh 		    uint32_t *off, struct tuple_callbacks *callbacks);
117255b159fSJonathan Chen static int	cardbus_parse_cis(device_t cbdev, device_t child,
118255b159fSJonathan Chen 		    struct tuple_callbacks *callbacks);
119255b159fSJonathan Chen 
1200c95c705SJonathan Chen #define	MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
1210db7e66cSJonathan Chen 
1220db7e66cSJonathan Chen static char *funcnames[] = {
1230db7e66cSJonathan Chen 	"Multi-Functioned",
1240db7e66cSJonathan Chen 	"Memory",
1250db7e66cSJonathan Chen 	"Serial Port",
1260db7e66cSJonathan Chen 	"Parallel Port",
1270db7e66cSJonathan Chen 	"Fixed Disk",
1280db7e66cSJonathan Chen 	"Video Adaptor",
1290db7e66cSJonathan Chen 	"Network Adaptor",
1300db7e66cSJonathan Chen 	"AIMS",
1310db7e66cSJonathan Chen 	"SCSI",
1320db7e66cSJonathan Chen 	"Security"
1330db7e66cSJonathan Chen };
1340db7e66cSJonathan Chen 
135255b159fSJonathan Chen /*
136255b159fSJonathan Chen  * Handler functions for various CIS tuples
137255b159fSJonathan Chen  */
138255b159fSJonathan Chen 
13922acd92bSWarner Losh static int
14022acd92bSWarner Losh decode_tuple_generic(device_t cbdev, device_t child, int id,
14122acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
14222acd92bSWarner Losh     struct tuple_callbacks *info)
1430db7e66cSJonathan Chen {
1440db7e66cSJonathan Chen 	int i;
1450db7e66cSJonathan Chen 
14622acd92bSWarner Losh 	if (cardbus_cis_debug) {
1470db7e66cSJonathan Chen 		if (info)
1480db7e66cSJonathan Chen 			printf("TUPLE: %s [%d]:", info->name, len);
1490db7e66cSJonathan Chen 		else
1500db7e66cSJonathan Chen 			printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
1510db7e66cSJonathan Chen 
1520db7e66cSJonathan Chen 		for (i = 0; i < len; i++) {
1530db7e66cSJonathan Chen 			if (i % 0x10 == 0 && len > 0x10)
1540db7e66cSJonathan Chen 				printf("\n       0x%02x:", i);
1557bec1dd5SJonathan Chen 			printf(" %02x", tupledata[i]);
1560db7e66cSJonathan Chen 		}
1570db7e66cSJonathan Chen 		printf("\n");
15822acd92bSWarner Losh 	}
159a3133b58SWarner Losh 	return (0);
1600db7e66cSJonathan Chen }
1610db7e66cSJonathan Chen 
16222acd92bSWarner Losh static int
16322acd92bSWarner Losh decode_tuple_linktarget(device_t cbdev, device_t child, int id,
16422acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
16522acd92bSWarner Losh     struct tuple_callbacks *info)
1660db7e66cSJonathan Chen {
16749f158ccSJonathan Chen 	int i;
16849f158ccSJonathan Chen 
16922acd92bSWarner Losh 	if (cardbus_cis_debug) {
17049f158ccSJonathan Chen 		printf("TUPLE: %s [%d]:", info->name, len);
17149f158ccSJonathan Chen 
17249f158ccSJonathan Chen 		for (i = 0; i < len; i++) {
17349f158ccSJonathan Chen 			if (i % 0x10 == 0 && len > 0x10)
17449f158ccSJonathan Chen 				printf("\n       0x%02x:", i);
17549f158ccSJonathan Chen 			printf(" %02x", tupledata[i]);
17649f158ccSJonathan Chen 		}
17749f158ccSJonathan Chen 		printf("\n");
17822acd92bSWarner Losh 	}
1797bec1dd5SJonathan Chen 	if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
1807bec1dd5SJonathan Chen 	    tupledata[2] != 'S') {
1810db7e66cSJonathan Chen 		printf("Invalid data for CIS Link Target!\n");
182255b159fSJonathan Chen 		decode_tuple_generic(cbdev, child, id, len, tupledata,
18349f158ccSJonathan Chen 		    start, off, info);
184a3133b58SWarner Losh 		return (EINVAL);
1850db7e66cSJonathan Chen 	}
186a3133b58SWarner Losh 	return (0);
1870db7e66cSJonathan Chen }
1880db7e66cSJonathan Chen 
18922acd92bSWarner Losh static int
19022acd92bSWarner Losh decode_tuple_vers_1(device_t cbdev, device_t child, int id,
19122acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
19222acd92bSWarner Losh     struct tuple_callbacks *info)
1930db7e66cSJonathan Chen {
1940db7e66cSJonathan Chen 	int i;
195fbe9cff1SWarner Losh 
19622acd92bSWarner Losh 	if (cardbus_cis_debug) {
1977bec1dd5SJonathan Chen 		printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
1980db7e66cSJonathan Chen 		printf("Product name: ");
1990db7e66cSJonathan Chen 		for (i = 2; i < len; i++) {
2007bec1dd5SJonathan Chen 			if (tupledata[i] == '\0')
2010db7e66cSJonathan Chen 				printf(" | ");
2027bec1dd5SJonathan Chen 			else if (tupledata[i] == 0xff)
2030db7e66cSJonathan Chen 				break;
2040db7e66cSJonathan Chen 			else
2057bec1dd5SJonathan Chen 				printf("%c", tupledata[i]);
2060db7e66cSJonathan Chen 		}
2070db7e66cSJonathan Chen 		printf("\n");
20822acd92bSWarner Losh 	}
209a3133b58SWarner Losh 	return (0);
2100db7e66cSJonathan Chen }
2110db7e66cSJonathan Chen 
21222acd92bSWarner Losh static int
21322acd92bSWarner Losh decode_tuple_funcid(device_t cbdev, device_t child, int id,
21422acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
21522acd92bSWarner Losh     struct tuple_callbacks *info)
2160db7e66cSJonathan Chen {
217fbe9cff1SWarner Losh 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
2180db7e66cSJonathan Chen 	int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
219fbe9cff1SWarner Losh 	int i;
2200db7e66cSJonathan Chen 
22122acd92bSWarner Losh 	if (cardbus_cis_debug) {
2220db7e66cSJonathan Chen 		printf("Functions: ");
2230db7e66cSJonathan Chen 		for (i = 0; i < len; i++) {
2247bec1dd5SJonathan Chen 			if (tupledata[i] < numnames)
2257bec1dd5SJonathan Chen 				printf("%s", funcnames[tupledata[i]]);
2260db7e66cSJonathan Chen 			else
2277bec1dd5SJonathan Chen 				printf("Unknown(%d)", tupledata[i]);
228255b159fSJonathan Chen 			if (i < len-1)
229255b159fSJonathan Chen 				printf(", ");
2300db7e66cSJonathan Chen 		}
23122acd92bSWarner Losh 		printf("\n");
23222acd92bSWarner Losh 	}
233fbe9cff1SWarner Losh 	if (len > 0)
234fbe9cff1SWarner Losh 		dinfo->funcid = tupledata[0];		/* use first in list */
235a3133b58SWarner Losh 	return (0);
2360db7e66cSJonathan Chen }
2370db7e66cSJonathan Chen 
23822acd92bSWarner Losh static int
23922acd92bSWarner Losh decode_tuple_manfid(device_t cbdev, device_t child, int id,
24022acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
24122acd92bSWarner Losh     struct tuple_callbacks *info)
2420db7e66cSJonathan Chen {
243fbe9cff1SWarner Losh 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
2440db7e66cSJonathan Chen 	int i;
245fbe9cff1SWarner Losh 
24622acd92bSWarner Losh 	if (cardbus_cis_debug) {
2470db7e66cSJonathan Chen 		printf("Manufacturer ID: ");
2480db7e66cSJonathan Chen 		for (i = 0; i < len; i++)
2497bec1dd5SJonathan Chen 			printf("%02x", tupledata[i]);
2500db7e66cSJonathan Chen 		printf("\n");
25122acd92bSWarner Losh 	}
252fbe9cff1SWarner Losh 
253fbe9cff1SWarner Losh 	if (len == 5) {
254fbe9cff1SWarner Losh 		dinfo->mfrid = tupledata[1] | (tupledata[2] << 8);
255fbe9cff1SWarner Losh 		dinfo->prodid = tupledata[3] | (tupledata[4] << 8);
256fbe9cff1SWarner Losh 	}
257a3133b58SWarner Losh 	return (0);
2580db7e66cSJonathan Chen }
2590db7e66cSJonathan Chen 
26022acd92bSWarner Losh static int
26122acd92bSWarner Losh decode_tuple_funce(device_t cbdev, device_t child, int id,
26222acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
26322acd92bSWarner Losh     struct tuple_callbacks *info)
2640db7e66cSJonathan Chen {
265fbe9cff1SWarner Losh 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
266fbe9cff1SWarner Losh 	int type, i;
267fbe9cff1SWarner Losh 
26822acd92bSWarner Losh 	if (cardbus_cis_debug) {
2690db7e66cSJonathan Chen 		printf("Function Extension: ");
2700db7e66cSJonathan Chen 		for (i = 0; i < len; i++)
2717bec1dd5SJonathan Chen 			printf("%02x", tupledata[i]);
2720db7e66cSJonathan Chen 		printf("\n");
27322acd92bSWarner Losh 	}
274fbe9cff1SWarner Losh 	if (len < 2)			/* too short */
275fbe9cff1SWarner Losh 		return (0);
276fbe9cff1SWarner Losh 	type = tupledata[0];		/* XXX <32 always? */
277fbe9cff1SWarner Losh 	switch (dinfo->funcid) {
278440b5adeSWarner Losh 	case PCCARD_FUNCTION_NETWORK:
279fbe9cff1SWarner Losh 		switch (type) {
280440b5adeSWarner Losh 		case PCCARD_TPLFE_TYPE_LAN_NID:
28122acd92bSWarner Losh 			if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) {
28222acd92bSWarner Losh 				/* ignore, warning? */
28322acd92bSWarner Losh 				return (0);
28422acd92bSWarner Losh 			}
28522acd92bSWarner Losh 			bcopy(tupledata + 2, dinfo->funce.lan.nid,
28622acd92bSWarner Losh 			    tupledata[1]);
287fbe9cff1SWarner Losh 			break;
288fbe9cff1SWarner Losh 		}
289fbe9cff1SWarner Losh 		dinfo->fepresent |= 1<<type;
290fbe9cff1SWarner Losh 		break;
291fbe9cff1SWarner Losh 	}
292a3133b58SWarner Losh 	return (0);
2930db7e66cSJonathan Chen }
2940db7e66cSJonathan Chen 
29522acd92bSWarner Losh static int
29622acd92bSWarner Losh decode_tuple_bar(device_t cbdev, device_t child, int id,
29722acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
29822acd92bSWarner Losh     struct tuple_callbacks *info)
2990db7e66cSJonathan Chen {
30063fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
3010db7e66cSJonathan Chen 	int type;
3021e962d00SScott Long 	uint8_t reg;
30372d3502eSScott Long 	uint32_t bar, pci_bar;
3040db7e66cSJonathan Chen 
305e6e272b9SScott Long 	if (len != 6) {
3061e962d00SScott Long 		device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len);
307e6e272b9SScott Long 		return (EINVAL);
308e6e272b9SScott Long 	}
3091e962d00SScott Long 
3101e962d00SScott Long 	reg = *tupledata;
3111e962d00SScott Long 	len = le32toh(*(uint32_t*)(tupledata + 2));
3120db7e66cSJonathan Chen 	if (reg & TPL_BAR_REG_AS) {
3130db7e66cSJonathan Chen 		type = SYS_RES_IOPORT;
3140db7e66cSJonathan Chen 	} else {
3150db7e66cSJonathan Chen 		type = SYS_RES_MEMORY;
3160db7e66cSJonathan Chen 	}
3171e962d00SScott Long 
3181e962d00SScott Long 	bar = reg & TPL_BAR_REG_ASI_MASK;
3191e962d00SScott Long 	if (bar == 0) {
3201e962d00SScott Long 		device_printf(cbdev, "Invalid BAR type 0 in CIS\n");
3211e962d00SScott Long 		return (EINVAL);	/* XXX Return an error? */
3221e962d00SScott Long 	} else if (bar == 7) {
3231e962d00SScott Long 		/* XXX Should we try to map in Option ROMs? */
324a3133b58SWarner Losh 		return (0);
3250db7e66cSJonathan Chen 	}
3261e962d00SScott Long 
32772d3502eSScott Long 	/* Convert from BAR type to BAR offset */
328495036f2SWarner Losh 	bar = PCIR_BAR(bar - 1);
3291e962d00SScott Long 
33063fa9f4cSJonathan Chen 	if (type == SYS_RES_MEMORY) {
33172d3502eSScott Long 		if (reg & TPL_BAR_REG_PREFETCHABLE)
33263fa9f4cSJonathan Chen 			dinfo->mprefetchable |= BARBIT(bar);
333f9aedaa4SWarner Losh #if 0
334a7c43559SWarner Losh 		/*
335a7c43559SWarner Losh 		 * XXX: It appears from a careful reading of the spec
336a7c43559SWarner Losh 		 * that we're not supposed to honor this when the bridge
337a7c43559SWarner Losh 		 * is not on the main system bus.  PCI spec doesn't appear
338a7c43559SWarner Losh 		 * to allow for memory ranges not listed in the bridge's
339a7c43559SWarner Losh 		 * decode range to be decoded.  The PC Card spec seems to
340a7c43559SWarner Losh 		 * indicate that this should only be done on x86 based
341a7c43559SWarner Losh 		 * machines, which seems to imply that on non-x86 machines
342a7c43559SWarner Losh 		 * the adddresses can be anywhere.  This further implies that
343a7c43559SWarner Losh 		 * since the hardware can do it on non-x86 machines, it should
344a7c43559SWarner Losh 		 * be able to do it on x86 machines.  Therefore, we can and
345a7c43559SWarner Losh 		 * should ignore this hint.  Furthermore, the PC Card spec
346a7c43559SWarner Losh 		 * recommends always allocating memory above 1MB, contradicting
347a7c43559SWarner Losh 		 * the other part of the PC Card spec.
348a7c43559SWarner Losh 		 *
349a7c43559SWarner Losh 		 * NetBSD ignores this bit, but it also ignores the
350a7c43559SWarner Losh 		 * prefetchable bit too, so that's not an indication of
351a7c43559SWarner Losh 		 * correctness.
352a7c43559SWarner Losh 		 */
35372d3502eSScott Long 		if (reg & TPL_BAR_REG_BELOW1MB)
35463fa9f4cSJonathan Chen 			dinfo->mbelow1mb |= BARBIT(bar);
355f9aedaa4SWarner Losh #endif
3560db7e66cSJonathan Chen 	}
3571e962d00SScott Long 
35872d3502eSScott Long 	/*
35972d3502eSScott Long 	 * Sanity check the BAR length reported in the CIS with the length
36072d3502eSScott Long 	 * encoded in the PCI BAR.  The latter seems to be more reliable.
36172d3502eSScott Long 	 * XXX - This probably belongs elsewhere.
36272d3502eSScott Long 	 */
36372d3502eSScott Long 	pci_write_config(child, bar, 0xffffffff, 4);
36472d3502eSScott Long 	pci_bar = pci_read_config(child, bar, 4);
36572d3502eSScott Long 	if ((pci_bar != 0x0) && (pci_bar != 0xffffffff)) {
36672d3502eSScott Long 		if (type == SYS_RES_MEMORY) {
36772d3502eSScott Long 			pci_bar &= ~0xf;
36872d3502eSScott Long 		} else {
36972d3502eSScott Long 			pci_bar &= ~0x3;
37072d3502eSScott Long 		}
37172d3502eSScott Long 		len = 1 << (ffs(pci_bar) - 1);
37272d3502eSScott Long 	}
37372d3502eSScott Long 
374e6e272b9SScott Long 	DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
37563fa9f4cSJonathan Chen 	    (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
37663fa9f4cSJonathan Chen 	    (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
377e6e272b9SScott Long 	    " (Prefetchable)" : "", type == SYS_RES_MEMORY ?
3781e962d00SScott Long 	    ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") : ""));
37963fa9f4cSJonathan Chen 
3807ba175acSWarner Losh 	resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len);
381e6e272b9SScott Long 
3829fb92b64SScott Long 	/*
3839fb92b64SScott Long 	 * Mark the appropriate bit in the PCI command register so that
38401f2fb65SWarner Losh 	 * device drivers will know which type of BARs can be used.
3859fb92b64SScott Long 	 */
3869fb92b64SScott Long 	pci_enable_io(child, type);
387a3133b58SWarner Losh 	return (0);
3880db7e66cSJonathan Chen }
3890db7e66cSJonathan Chen 
39022acd92bSWarner Losh static int
39122acd92bSWarner Losh decode_tuple_unhandled(device_t cbdev, device_t child, int id,
39222acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
39322acd92bSWarner Losh     struct tuple_callbacks *info)
3940db7e66cSJonathan Chen {
39522acd92bSWarner Losh 	/* Make this message suck less XXX */
3960db7e66cSJonathan Chen 	printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
397a3133b58SWarner Losh 	return (-1);
3980db7e66cSJonathan Chen }
3990db7e66cSJonathan Chen 
40022acd92bSWarner Losh static int
40122acd92bSWarner Losh decode_tuple_end(device_t cbdev, device_t child, int id,
40222acd92bSWarner Losh     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
40322acd92bSWarner Losh     struct tuple_callbacks *info)
4040db7e66cSJonathan Chen {
405509cfe6fSWarner Losh 	if (cardbus_cis_debug)
4060c95c705SJonathan Chen 		printf("CIS reading done\n");
407a3133b58SWarner Losh 	return (0);
4080db7e66cSJonathan Chen }
4090db7e66cSJonathan Chen 
410255b159fSJonathan Chen /*
411255b159fSJonathan Chen  * Functions to read the a tuple from the card
412255b159fSJonathan Chen  */
413255b159fSJonathan Chen 
4140db7e66cSJonathan Chen static int
41566e390feSWarner Losh cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start,
41666e390feSWarner Losh     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
4177bec1dd5SJonathan Chen {
4187bec1dd5SJonathan Chen 	int i, j;
41966e390feSWarner Losh 	uint32_t e;
42066e390feSWarner Losh 	uint32_t loc;
4217bec1dd5SJonathan Chen 
42263fa9f4cSJonathan Chen 	loc = start + *off;
42349f158ccSJonathan Chen 
42449f158ccSJonathan Chen 	e = pci_read_config(child, loc - loc % 4, 4);
42549f158ccSJonathan Chen 	for (j = loc % 4; j > 0; j--)
4267bec1dd5SJonathan Chen 		e >>= 8;
4277bec1dd5SJonathan Chen 	*len = 0;
42849f158ccSJonathan Chen 	for (i = loc, j = -2; j < *len; j++, i++) {
4297bec1dd5SJonathan Chen 		if (i % 4 == 0)
4307bec1dd5SJonathan Chen 			e = pci_read_config(child, i, 4);
4317bec1dd5SJonathan Chen 		if (j == -2)
4327bec1dd5SJonathan Chen 			*tupleid = 0xff & e;
4337bec1dd5SJonathan Chen 		else if (j == -1)
4347bec1dd5SJonathan Chen 			*len = 0xff & e;
4357bec1dd5SJonathan Chen 		else
4367bec1dd5SJonathan Chen 			tupledata[j] = 0xff & e;
4377bec1dd5SJonathan Chen 		e >>= 8;
4387bec1dd5SJonathan Chen 	}
4397bec1dd5SJonathan Chen 	*off += *len + 2;
440a3133b58SWarner Losh 	return (0);
4417bec1dd5SJonathan Chen }
4427bec1dd5SJonathan Chen 
4437bec1dd5SJonathan Chen static int
44466e390feSWarner Losh cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start,
44566e390feSWarner Losh     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
4460db7e66cSJonathan Chen {
44763fa9f4cSJonathan Chen 	bus_space_tag_t bt;
44863fa9f4cSJonathan Chen 	bus_space_handle_t bh;
44963fa9f4cSJonathan Chen 	int ret;
4500db7e66cSJonathan Chen 
45163fa9f4cSJonathan Chen 	bt = rman_get_bustag(res);
45263fa9f4cSJonathan Chen 	bh = rman_get_bushandle(res);
4530db7e66cSJonathan Chen 
45463fa9f4cSJonathan Chen 	*tupleid = bus_space_read_1(bt, bh, start + *off);
45563fa9f4cSJonathan Chen 	*len = bus_space_read_1(bt, bh, start + *off + 1);
45663fa9f4cSJonathan Chen 	bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
45763fa9f4cSJonathan Chen 	ret = 0;
45863fa9f4cSJonathan Chen 	*off += *len + 2;
459a3133b58SWarner Losh 	return (ret);
4600db7e66cSJonathan Chen }
46163fa9f4cSJonathan Chen 
46263fa9f4cSJonathan Chen static int
46363fa9f4cSJonathan Chen cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
46466e390feSWarner Losh     uint32_t start, uint32_t *off, int *tupleid, int *len,
46566e390feSWarner Losh     uint8_t *tupledata)
46663fa9f4cSJonathan Chen {
46763fa9f4cSJonathan Chen 	if (res == (struct resource*)~0UL) {
468a3133b58SWarner Losh 		return (cardbus_read_tuple_conf(cbdev, child, start, off,
469a3133b58SWarner Losh 		    tupleid, len, tupledata));
47063fa9f4cSJonathan Chen 	} else {
471a3133b58SWarner Losh 		return (cardbus_read_tuple_mem(cbdev, res, start, off,
472a3133b58SWarner Losh 		    tupleid, len, tupledata));
47363fa9f4cSJonathan Chen 	}
47463fa9f4cSJonathan Chen }
47563fa9f4cSJonathan Chen 
47663fa9f4cSJonathan Chen static void
47763fa9f4cSJonathan Chen cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
47863fa9f4cSJonathan Chen     struct resource *res)
47963fa9f4cSJonathan Chen {
48063fa9f4cSJonathan Chen 	if (res != (struct resource*)~0UL) {
48163fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
48263fa9f4cSJonathan Chen 		pci_write_config(child, rid, 0, 4);
48363fa9f4cSJonathan Chen 		PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
48463fa9f4cSJonathan Chen 	}
48563fa9f4cSJonathan Chen }
48663fa9f4cSJonathan Chen 
48763fa9f4cSJonathan Chen static struct resource *
48866e390feSWarner Losh cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
48963fa9f4cSJonathan Chen     int *rid)
49063fa9f4cSJonathan Chen {
49166e390feSWarner Losh 	uint32_t testval;
49266e390feSWarner Losh 	uint32_t size;
49363fa9f4cSJonathan Chen 	struct resource *res;
494495036f2SWarner Losh 	uint32_t space;
49563fa9f4cSJonathan Chen 
49641ac33a2SWarner Losh 	space = *start & PCIM_CIS_ASI_MASK;
497495036f2SWarner Losh 	switch (space) {
49841ac33a2SWarner Losh 	case PCIM_CIS_ASI_TUPLE:
499e6e272b9SScott Long 		/* CIS in PCI config space need no initialization */
50021677473SWarner Losh 		return ((struct resource*)~0UL);
50141ac33a2SWarner Losh 	case PCIM_CIS_ASI_BAR0:
50241ac33a2SWarner Losh 	case PCIM_CIS_ASI_BAR1:
50341ac33a2SWarner Losh 	case PCIM_CIS_ASI_BAR2:
50441ac33a2SWarner Losh 	case PCIM_CIS_ASI_BAR3:
50541ac33a2SWarner Losh 	case PCIM_CIS_ASI_BAR4:
50641ac33a2SWarner Losh 	case PCIM_CIS_ASI_BAR5:
50741ac33a2SWarner Losh 		*rid = PCIR_BAR(space - PCIM_CIS_ASI_BAR0);
50863fa9f4cSJonathan Chen 		break;
50941ac33a2SWarner Losh 	case PCIM_CIS_ASI_ROM:
51041ac33a2SWarner Losh 		*rid = PCIR_BIOS;
51163fa9f4cSJonathan Chen 		break;
51263fa9f4cSJonathan Chen 	default:
51363fa9f4cSJonathan Chen 		device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
514495036f2SWarner Losh 		    space);
515a3133b58SWarner Losh 		return (NULL);
51663fa9f4cSJonathan Chen 	}
51763fa9f4cSJonathan Chen 
51863fa9f4cSJonathan Chen 	/* figure out how much space we need */
519e6e272b9SScott Long 	pci_write_config(child, *rid, 0xffffffff, 4);
52063fa9f4cSJonathan Chen 	testval = pci_read_config(child, *rid, 4);
521e6e272b9SScott Long 
522e6e272b9SScott Long 	/*
523e6e272b9SScott Long 	 * This bit has a different meaning depending if we are dealing
5241e06ae99SScott Long 	 * with a normal BAR or an Option ROM BAR.
525e6e272b9SScott Long 	 */
52641ac33a2SWarner Losh 	if (((testval & 0x1) == 0x1) && (*rid != PCIR_BIOS)) {
52763fa9f4cSJonathan Chen 		device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
528a3133b58SWarner Losh 		return (NULL);
52963fa9f4cSJonathan Chen 	}
530e6e272b9SScott Long 
53163fa9f4cSJonathan Chen 	size = CARDBUS_MAPREG_MEM_SIZE(testval);
532e6e272b9SScott Long 	/* XXX Is this some kind of hack? */
53363fa9f4cSJonathan Chen 	if (size < 4096)
53463fa9f4cSJonathan Chen 		size = 4096;
53563fa9f4cSJonathan Chen 	/* allocate the memory space to read CIS */
53663fa9f4cSJonathan Chen 	res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size,
53763fa9f4cSJonathan Chen 	    rman_make_alignment_flags(size) | RF_ACTIVE);
53863fa9f4cSJonathan Chen 	if (res == NULL) {
53963fa9f4cSJonathan Chen 		device_printf(cbdev, "Unable to allocate resource "
54063fa9f4cSJonathan Chen 		    "to read CIS.\n");
541a3133b58SWarner Losh 		return (NULL);
54263fa9f4cSJonathan Chen 	}
54363fa9f4cSJonathan Chen 	pci_write_config(child, *rid,
54441ac33a2SWarner Losh 	    rman_get_start(res) | ((*rid == PCIR_BIOS) ? PCIM_BIOS_ENABLE : 0),
54541ac33a2SWarner Losh 	    4);
54663fa9f4cSJonathan Chen 	PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY);
54763fa9f4cSJonathan Chen 
54863fa9f4cSJonathan Chen 	/* Flip to the right ROM image if CIS is in ROM */
54941ac33a2SWarner Losh 	if (space == PCIM_CIS_ASI_ROM) {
55063fa9f4cSJonathan Chen 		bus_space_tag_t bt;
55163fa9f4cSJonathan Chen 		bus_space_handle_t bh;
55266e390feSWarner Losh 		uint32_t imagesize;
55366e390feSWarner Losh 		uint32_t imagebase = 0;
55466e390feSWarner Losh 		uint32_t pcidata;
55566e390feSWarner Losh 		uint16_t romsig;
55663fa9f4cSJonathan Chen 		int romnum = 0;
557e6e272b9SScott Long 		int imagenum;
55863fa9f4cSJonathan Chen 
55963fa9f4cSJonathan Chen 		bt = rman_get_bustag(res);
56063fa9f4cSJonathan Chen 		bh = rman_get_bushandle(res);
56163fa9f4cSJonathan Chen 
56241ac33a2SWarner Losh 		imagenum = (*start & PCIM_CIS_ROM_MASK) >> 28;
56363fa9f4cSJonathan Chen 		for (romnum = 0;; romnum++) {
564e6e272b9SScott Long 			romsig = bus_space_read_2(bt, bh,
565e6e272b9SScott Long 			    imagebase + CARDBUS_EXROM_SIGNATURE);
566e6e272b9SScott Long 			if (romsig != 0xaa55) {
56763fa9f4cSJonathan Chen 				device_printf(cbdev, "Bad header in rom %d: "
568e6e272b9SScott Long 				    "[%x] %04x\n", romnum, imagebase +
569e6e272b9SScott Long 				    CARDBUS_EXROM_SIGNATURE, romsig);
57063fa9f4cSJonathan Chen 				bus_release_resource(cbdev, SYS_RES_MEMORY,
57163fa9f4cSJonathan Chen 				    *rid, res);
57263fa9f4cSJonathan Chen 				*rid = 0;
573a3133b58SWarner Losh 				return (NULL);
57463fa9f4cSJonathan Chen 			}
575e6e272b9SScott Long 
576e6e272b9SScott Long 			/*
577e6e272b9SScott Long 			 * If this was the Option ROM image that we were
578e6e272b9SScott Long 			 * looking for, then we are done.
579e6e272b9SScott Long 			 */
580e6e272b9SScott Long 			if (romnum == imagenum)
581e6e272b9SScott Long 				break;
582e6e272b9SScott Long 
583e6e272b9SScott Long 			/* Find out where the next Option ROM image is */
584e6e272b9SScott Long 			pcidata = imagebase + bus_space_read_2(bt, bh,
585e6e272b9SScott Long 			    imagebase + CARDBUS_EXROM_DATA_PTR);
58663fa9f4cSJonathan Chen 			imagesize = bus_space_read_2(bt, bh,
587e6e272b9SScott Long 			    pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
5880db7e66cSJonathan Chen 
5897bec1dd5SJonathan Chen 			if (imagesize == 0) {
5900db7e66cSJonathan Chen 				/*
5910db7e66cSJonathan Chen 				 * XXX some ROMs seem to have this as zero,
5920db7e66cSJonathan Chen 				 * can we assume this means 1 block?
5930db7e66cSJonathan Chen 				 */
594e6e272b9SScott Long 				device_printf(cbdev, "Warning, size of Option "
595e6e272b9SScott Long 				    "ROM image %d is 0 bytes, assuming 512 "
596e6e272b9SScott Long 				    "bytes.\n", romnum);
5970db7e66cSJonathan Chen 				imagesize = 1;
5987bec1dd5SJonathan Chen 			}
599e6e272b9SScott Long 
600e6e272b9SScott Long 			/* Image size is in 512 byte units */
6010db7e66cSJonathan Chen 			imagesize <<= 9;
6020db7e66cSJonathan Chen 
603e6e272b9SScott Long 			if ((bus_space_read_1(bt, bh, pcidata +
6041e06ae99SScott Long 			    CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
605e6e272b9SScott Long 				device_printf(cbdev, "Cannot find CIS in "
606e6e272b9SScott Long 				    "Option ROM\n");
607e6e272b9SScott Long 				bus_release_resource(cbdev, SYS_RES_MEMORY,
608e6e272b9SScott Long 				    *rid, res);
609e6e272b9SScott Long 				*rid = 0;
610a3133b58SWarner Losh 				return (NULL);
6110db7e66cSJonathan Chen 			}
612e6e272b9SScott Long 			imagebase += imagesize;
6130db7e66cSJonathan Chen 		}
61441ac33a2SWarner Losh 		*start = imagebase + (*start & PCIM_CIS_ADDR_MASK);
6150db7e66cSJonathan Chen 	} else {
61641ac33a2SWarner Losh 		*start = *start & PCIM_CIS_ADDR_MASK;
6170db7e66cSJonathan Chen 	}
618e6e272b9SScott Long 
619a3133b58SWarner Losh 	return (res);
6207bec1dd5SJonathan Chen }
6217bec1dd5SJonathan Chen 
622255b159fSJonathan Chen /*
623255b159fSJonathan Chen  * Dispatch the right handler function per tuple
624255b159fSJonathan Chen  */
625255b159fSJonathan Chen 
6267bec1dd5SJonathan Chen static int
627255b159fSJonathan Chen decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
62866e390feSWarner Losh     uint8_t *tupledata, uint32_t start, uint32_t *off,
6290c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
6307bec1dd5SJonathan Chen {
6317bec1dd5SJonathan Chen 	int i;
6320c95c705SJonathan Chen 	for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
6330c95c705SJonathan Chen 		if (tupleid == callbacks[i].id)
634a3133b58SWarner Losh 			return (callbacks[i].func(cbdev, child, tupleid, len,
635a3133b58SWarner Losh 			    tupledata, start, off, &callbacks[i]));
6367bec1dd5SJonathan Chen 	}
637a3133b58SWarner Losh 	return (callbacks[i].func(cbdev, child, tupleid, len,
638a3133b58SWarner Losh 	    tupledata, start, off, NULL));
6390db7e66cSJonathan Chen }
6400db7e66cSJonathan Chen 
6410c95c705SJonathan Chen static int
642255b159fSJonathan Chen cardbus_parse_cis(device_t cbdev, device_t child,
6430c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
6440db7e66cSJonathan Chen {
64566e390feSWarner Losh 	uint8_t tupledata[MAXTUPLESIZE];
6467bec1dd5SJonathan Chen 	int tupleid;
6477bec1dd5SJonathan Chen 	int len;
6487bec1dd5SJonathan Chen 	int expect_linktarget;
64966e390feSWarner Losh 	uint32_t start, off;
65063fa9f4cSJonathan Chen 	struct resource *res;
65163fa9f4cSJonathan Chen 	int rid;
6520db7e66cSJonathan Chen 
6530db7e66cSJonathan Chen 	bzero(tupledata, MAXTUPLESIZE);
6547bec1dd5SJonathan Chen 	expect_linktarget = TRUE;
65541ac33a2SWarner Losh 	if ((start = pci_read_config(child, PCIR_CIS, 4)) == 0) {
656509cfe6fSWarner Losh 		device_printf(cbdev, "CIS pointer is 0!\n");
657e6e272b9SScott Long 		return (ENXIO);
658509cfe6fSWarner Losh 	}
65949f158ccSJonathan Chen 	off = 0;
66063fa9f4cSJonathan Chen 	res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
661509cfe6fSWarner Losh 	if (res == NULL) {
662509cfe6fSWarner Losh 		device_printf(cbdev, "Unable to allocate resources for CIS\n");
663a3133b58SWarner Losh 		return (ENXIO);
664509cfe6fSWarner Losh 	}
6651e962d00SScott Long 
6667bec1dd5SJonathan Chen 	do {
66763fa9f4cSJonathan Chen 		if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
66863fa9f4cSJonathan Chen 		    &tupleid, &len, tupledata)) {
66963fa9f4cSJonathan Chen 			device_printf(cbdev, "Failed to read CIS.\n");
67063fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
671a3133b58SWarner Losh 			return (ENXIO);
67263fa9f4cSJonathan Chen 		}
6737bec1dd5SJonathan Chen 
6747bec1dd5SJonathan Chen 		if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
675255b159fSJonathan Chen 			device_printf(cbdev, "Expecting link target, got 0x%x\n",
6767bec1dd5SJonathan Chen 			    tupleid);
67763fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
678a3133b58SWarner Losh 			return (EINVAL);
6797bec1dd5SJonathan Chen 		}
680255b159fSJonathan Chen 		expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
68163fa9f4cSJonathan Chen 		    tupledata, start, &off, callbacks);
68263fa9f4cSJonathan Chen 		if (expect_linktarget != 0) {
683509cfe6fSWarner Losh 			device_printf(cbdev, "Parsing failed with %d\n",
684509cfe6fSWarner Losh 			    expect_linktarget);
68563fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
686a3133b58SWarner Losh 			return (expect_linktarget);
68763fa9f4cSJonathan Chen 		}
6887bec1dd5SJonathan Chen 	} while (tupleid != CISTPL_END);
68963fa9f4cSJonathan Chen 	cardbus_read_tuple_finish(cbdev, child, rid, res);
690a3133b58SWarner Losh 	return (0);
6910db7e66cSJonathan Chen }
6920db7e66cSJonathan Chen 
6930c95c705SJonathan Chen int
694255b159fSJonathan Chen cardbus_do_cis(device_t cbdev, device_t child)
6950c95c705SJonathan Chen {
69663fa9f4cSJonathan Chen 	int ret;
6970c95c705SJonathan Chen 	struct tuple_callbacks init_callbacks[] = {
698a294cdb6SWarner Losh 		MAKETUPLE(LONGLINK_CB,		unhandled),
6990c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
7000c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
7010c95c705SJonathan Chen 		MAKETUPLE(BAR,			bar),
7020c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
7030c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
7040c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		linktarget),
7050c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		vers_1),
7060c95c705SJonathan Chen 		MAKETUPLE(MANFID,		manfid),
7070c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		funcid),
7080c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		funce),
7090c95c705SJonathan Chen 		MAKETUPLE(END,			end),
7100c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		generic),
7110c95c705SJonathan Chen 	};
71263fa9f4cSJonathan Chen 
71363fa9f4cSJonathan Chen 	ret = cardbus_parse_cis(cbdev, child, init_callbacks);
71463fa9f4cSJonathan Chen 	if (ret < 0)
715a3133b58SWarner Losh 		return (ret);
716440b5adeSWarner Losh 	return 0;
7170c95c705SJonathan Chen }
718