xref: /freebsd/sys/dev/cardbus/cardbus_cis.c (revision 1e06ae996906eaddb5d636e8f39f728c457a075b)
10db7e66cSJonathan Chen /*
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
90db7e66cSJonathan Chen  *    notice, this list of conditions, and the following disclaimer,
100db7e66cSJonathan Chen  *    without modification, immediately at the beginning of the file.
110db7e66cSJonathan Chen  * 2. Redistributions in binary form must reproduce the above copyright
120db7e66cSJonathan Chen  *    notice, this list of conditions and the following disclaimer in
130db7e66cSJonathan Chen  *    the documentation and/or other materials provided with the
140db7e66cSJonathan Chen  *    distribution.
150db7e66cSJonathan Chen  *
160db7e66cSJonathan Chen  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170db7e66cSJonathan Chen  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180db7e66cSJonathan Chen  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190db7e66cSJonathan Chen  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
200db7e66cSJonathan Chen  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210db7e66cSJonathan Chen  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220db7e66cSJonathan Chen  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230db7e66cSJonathan Chen  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240db7e66cSJonathan Chen  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250db7e66cSJonathan Chen  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260db7e66cSJonathan Chen  * SUCH DAMAGE.
270db7e66cSJonathan Chen  *
280db7e66cSJonathan Chen  * $FreeBSD$
290db7e66cSJonathan Chen  */
300db7e66cSJonathan Chen 
310db7e66cSJonathan Chen /*
320db7e66cSJonathan Chen  * CIS Handling for the Cardbus Bus
330db7e66cSJonathan Chen  */
340db7e66cSJonathan Chen 
350db7e66cSJonathan Chen #include <sys/param.h>
360db7e66cSJonathan Chen #include <sys/systm.h>
370db7e66cSJonathan Chen #include <sys/kernel.h>
380c95c705SJonathan Chen #include <sys/malloc.h>
390db7e66cSJonathan Chen 
400db7e66cSJonathan Chen #include <sys/bus.h>
410db7e66cSJonathan Chen #include <machine/bus.h>
420db7e66cSJonathan Chen #include <machine/resource.h>
430db7e66cSJonathan Chen #include <sys/rman.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 
490db7e66cSJonathan Chen #include <dev/cardbus/cardbusreg.h>
5063fa9f4cSJonathan Chen #include <dev/cardbus/cardbusvar.h>
510db7e66cSJonathan Chen #include <dev/cardbus/cardbus_cis.h>
520db7e66cSJonathan Chen 
5380f10018STakanori Watanabe #include <dev/pccard/pccardvar.h>
540c95c705SJonathan Chen 
55b3889b68SWarner Losh extern int cardbus_cis_debug;
56b3889b68SWarner Losh 
57b3889b68SWarner Losh #define	DPRINTF(a) if (cardbus_cis_debug) printf a
58b3889b68SWarner Losh #define	DEVPRINTF(x) if (cardbus_cis_debug) device_printf x
59b3889b68SWarner Losh 
600c95c705SJonathan Chen #define	DECODE_PARAMS							\
61255b159fSJonathan Chen 		(device_t cbdev, device_t child, int id, int len,	\
6263fa9f4cSJonathan Chen 		 u_int8_t *tupledata, u_int32_t start, u_int32_t *off,	\
630c95c705SJonathan Chen 		 struct tuple_callbacks *info)
640db7e66cSJonathan Chen 
650c95c705SJonathan Chen struct tuple_callbacks {
660c95c705SJonathan Chen 	int	id;
670db7e66cSJonathan Chen 	char	*name;
680c95c705SJonathan Chen 	int	(*func) DECODE_PARAMS;
690db7e66cSJonathan Chen };
70255b159fSJonathan Chen 
71255b159fSJonathan Chen #define	DECODE_PROTOTYPE(NAME) static int decode_tuple_ ## NAME DECODE_PARAMS
72255b159fSJonathan Chen DECODE_PROTOTYPE(generic);
73255b159fSJonathan Chen DECODE_PROTOTYPE(nothing);
74255b159fSJonathan Chen DECODE_PROTOTYPE(copy);
75255b159fSJonathan Chen DECODE_PROTOTYPE(linktarget);
76255b159fSJonathan Chen DECODE_PROTOTYPE(vers_1);
77255b159fSJonathan Chen DECODE_PROTOTYPE(funcid);
78255b159fSJonathan Chen DECODE_PROTOTYPE(manfid);
79255b159fSJonathan Chen DECODE_PROTOTYPE(funce);
80255b159fSJonathan Chen DECODE_PROTOTYPE(bar);
81255b159fSJonathan Chen DECODE_PROTOTYPE(unhandled);
82255b159fSJonathan Chen DECODE_PROTOTYPE(end);
83255b159fSJonathan Chen static int	cardbus_read_tuple_conf(device_t cbdev, device_t child,
8463fa9f4cSJonathan Chen 		    u_int32_t start, u_int32_t *off, int *tupleid, int *len,
85255b159fSJonathan Chen 		    u_int8_t *tupledata);
8663fa9f4cSJonathan Chen static int	cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
8763fa9f4cSJonathan Chen 		    u_int32_t start, u_int32_t *off, int *tupleid, int *len,
88255b159fSJonathan Chen 		    u_int8_t *tupledata);
89255b159fSJonathan Chen static int	cardbus_read_tuple(device_t cbdev, device_t child,
9063fa9f4cSJonathan Chen 		    struct resource *res, u_int32_t start, u_int32_t *off,
9163fa9f4cSJonathan Chen 		    int *tupleid, int *len, u_int8_t *tupledata);
9263fa9f4cSJonathan Chen static void	cardbus_read_tuple_finish(device_t cbdev, device_t child,
9363fa9f4cSJonathan Chen 		    int rid, struct resource *res);
9463fa9f4cSJonathan Chen static struct resource	*cardbus_read_tuple_init(device_t cbdev, device_t child,
9563fa9f4cSJonathan Chen 		    u_int32_t *start, int *rid);
96255b159fSJonathan Chen static int	decode_tuple(device_t cbdev, device_t child, int tupleid,
9763fa9f4cSJonathan Chen 		    int len, u_int8_t *tupledata, u_int32_t start,
98255b159fSJonathan Chen 		    u_int32_t *off, struct tuple_callbacks *callbacks);
99255b159fSJonathan Chen static int	cardbus_parse_cis(device_t cbdev, device_t child,
100255b159fSJonathan Chen 		    struct tuple_callbacks *callbacks);
10163fa9f4cSJonathan Chen static int	barsort(const void *a, const void *b);
10263fa9f4cSJonathan Chen static int	cardbus_alloc_resources(device_t cbdev, device_t child);
10363fa9f4cSJonathan Chen static void	cardbus_add_map(device_t cbdev, device_t child, int reg);
10463fa9f4cSJonathan Chen static void	cardbus_pickup_maps(device_t cbdev, device_t child);
10563fa9f4cSJonathan Chen 
106255b159fSJonathan Chen 
1070c95c705SJonathan Chen #define	MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
1080db7e66cSJonathan Chen 
1090db7e66cSJonathan Chen static char *funcnames[] = {
1100db7e66cSJonathan Chen 	"Multi-Functioned",
1110db7e66cSJonathan Chen 	"Memory",
1120db7e66cSJonathan Chen 	"Serial Port",
1130db7e66cSJonathan Chen 	"Parallel Port",
1140db7e66cSJonathan Chen 	"Fixed Disk",
1150db7e66cSJonathan Chen 	"Video Adaptor",
1160db7e66cSJonathan Chen 	"Network Adaptor",
1170db7e66cSJonathan Chen 	"AIMS",
1180db7e66cSJonathan Chen 	"SCSI",
1190db7e66cSJonathan Chen 	"Security"
1200db7e66cSJonathan Chen };
1210db7e66cSJonathan Chen 
12263fa9f4cSJonathan Chen struct cardbus_quirk {
12363fa9f4cSJonathan Chen 	u_int32_t devid;	/* Vendor/device of the card */
12463fa9f4cSJonathan Chen 	int	type;
12563fa9f4cSJonathan Chen #define	CARDBUS_QUIRK_MAP_REG	1 /* PCI map register in weird place */
12663fa9f4cSJonathan Chen 	int	arg1;
12763fa9f4cSJonathan Chen 	int	arg2;
12863fa9f4cSJonathan Chen };
12963fa9f4cSJonathan Chen 
13063fa9f4cSJonathan Chen struct cardbus_quirk cardbus_quirks[] = {
13163fa9f4cSJonathan Chen 	{ 0 }
13263fa9f4cSJonathan Chen };
13363fa9f4cSJonathan Chen 
1340c95c705SJonathan Chen static struct cis_tupleinfo *cisread_buf;
1350c95c705SJonathan Chen static int ncisread_buf;
1360c95c705SJonathan Chen 
137255b159fSJonathan Chen /*
138255b159fSJonathan Chen  * Handler functions for various CIS tuples
139255b159fSJonathan Chen  */
140255b159fSJonathan Chen 
1410db7e66cSJonathan Chen DECODE_PROTOTYPE(generic)
1420db7e66cSJonathan Chen {
1430db7e66cSJonathan Chen #ifdef CARDBUS_DEBUG
1440db7e66cSJonathan Chen 	int i;
1450db7e66cSJonathan Chen 
1460db7e66cSJonathan Chen 	if (info)
1470db7e66cSJonathan Chen 		printf("TUPLE: %s [%d]:", info->name, len);
1480db7e66cSJonathan Chen 	else
1490db7e66cSJonathan Chen 		printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
1500db7e66cSJonathan Chen 
1510db7e66cSJonathan Chen 	for (i = 0; i < len; i++) {
1520db7e66cSJonathan Chen 		if (i % 0x10 == 0 && len > 0x10)
1530db7e66cSJonathan Chen 			printf("\n       0x%02x:", i);
1547bec1dd5SJonathan Chen 		printf(" %02x", tupledata[i]);
1550db7e66cSJonathan Chen 	}
1560db7e66cSJonathan Chen 	printf("\n");
1570db7e66cSJonathan Chen #endif
158a3133b58SWarner Losh 	return (0);
1590db7e66cSJonathan Chen }
1600db7e66cSJonathan Chen 
1610c95c705SJonathan Chen DECODE_PROTOTYPE(nothing)
1620c95c705SJonathan Chen {
163a3133b58SWarner Losh 	return (0);
1640c95c705SJonathan Chen }
1650c95c705SJonathan Chen 
1660c95c705SJonathan Chen DECODE_PROTOTYPE(copy)
1670c95c705SJonathan Chen {
1680c95c705SJonathan Chen 	struct cis_tupleinfo *tmpbuf;
1690c95c705SJonathan Chen 
1700c95c705SJonathan Chen 	tmpbuf = malloc(sizeof(struct cis_tupleinfo) * (ncisread_buf+1),
1710c95c705SJonathan Chen 	    M_DEVBUF, M_WAITOK);
1720c95c705SJonathan Chen 	if (ncisread_buf > 0) {
1730c95c705SJonathan Chen 		memcpy(tmpbuf, cisread_buf,
1740c95c705SJonathan Chen 		    sizeof(struct cis_tupleinfo) * ncisread_buf);
1750c95c705SJonathan Chen 		free(cisread_buf, M_DEVBUF);
1760c95c705SJonathan Chen 	}
1770c95c705SJonathan Chen 	cisread_buf = tmpbuf;
1780c95c705SJonathan Chen 
1790c95c705SJonathan Chen 	cisread_buf[ncisread_buf].id = id;
1800c95c705SJonathan Chen 	cisread_buf[ncisread_buf].len = len;
1810c95c705SJonathan Chen 	cisread_buf[ncisread_buf].data = malloc(len, M_DEVBUF, M_WAITOK);
1820c95c705SJonathan Chen 	memcpy(cisread_buf[ncisread_buf].data, tupledata, len);
1830c95c705SJonathan Chen 	ncisread_buf++;
184a3133b58SWarner Losh 	return (0);
1850c95c705SJonathan Chen }
1860c95c705SJonathan Chen 
1870db7e66cSJonathan Chen DECODE_PROTOTYPE(linktarget)
1880db7e66cSJonathan Chen {
18949f158ccSJonathan Chen #ifdef CARDBUS_DEBUG
19049f158ccSJonathan Chen 	int i;
19149f158ccSJonathan Chen 
19249f158ccSJonathan Chen 	printf("TUPLE: %s [%d]:", info->name, len);
19349f158ccSJonathan Chen 
19449f158ccSJonathan Chen 	for (i = 0; i < len; i++) {
19549f158ccSJonathan Chen 		if (i % 0x10 == 0 && len > 0x10)
19649f158ccSJonathan Chen 			printf("\n       0x%02x:", i);
19749f158ccSJonathan Chen 		printf(" %02x", tupledata[i]);
19849f158ccSJonathan Chen 	}
19949f158ccSJonathan Chen 	printf("\n");
20049f158ccSJonathan Chen #endif
2017bec1dd5SJonathan Chen 	if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
2027bec1dd5SJonathan Chen 	    tupledata[2] != 'S') {
2030db7e66cSJonathan Chen 		printf("Invalid data for CIS Link Target!\n");
204255b159fSJonathan Chen 		decode_tuple_generic(cbdev, child, id, len, tupledata,
20549f158ccSJonathan Chen 		    start, off, info);
206a3133b58SWarner Losh 		return (EINVAL);
2070db7e66cSJonathan Chen 	}
208a3133b58SWarner Losh 	return (0);
2090db7e66cSJonathan Chen }
2100db7e66cSJonathan Chen 
2110db7e66cSJonathan Chen DECODE_PROTOTYPE(vers_1)
2120db7e66cSJonathan Chen {
2130db7e66cSJonathan Chen 	int i;
2147bec1dd5SJonathan Chen 	printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
2150db7e66cSJonathan Chen 	printf("Product name: ");
2160db7e66cSJonathan Chen 	for (i = 2; i < len; i++) {
2177bec1dd5SJonathan Chen 		if (tupledata[i] == '\0')
2180db7e66cSJonathan Chen 			printf(" | ");
2197bec1dd5SJonathan Chen 		else if (tupledata[i] == 0xff)
2200db7e66cSJonathan Chen 			break;
2210db7e66cSJonathan Chen 		else
2227bec1dd5SJonathan Chen 			printf("%c", tupledata[i]);
2230db7e66cSJonathan Chen 	}
2240db7e66cSJonathan Chen 	printf("\n");
225a3133b58SWarner Losh 	return (0);
2260db7e66cSJonathan Chen }
2270db7e66cSJonathan Chen 
2280db7e66cSJonathan Chen DECODE_PROTOTYPE(funcid)
2290db7e66cSJonathan Chen {
2300db7e66cSJonathan Chen 	int i;
2310db7e66cSJonathan Chen 	int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
2320db7e66cSJonathan Chen 
2330db7e66cSJonathan Chen 	printf("Functions: ");
2340db7e66cSJonathan Chen 	for (i = 0; i < len; i++) {
2357bec1dd5SJonathan Chen 		if (tupledata[i] < numnames)
2367bec1dd5SJonathan Chen 			printf("%s", funcnames[tupledata[i]]);
2370db7e66cSJonathan Chen 		else
2387bec1dd5SJonathan Chen 			printf("Unknown(%d)", tupledata[i]);
239255b159fSJonathan Chen 		if (i < len-1)
240255b159fSJonathan Chen 			printf(", ");
2410db7e66cSJonathan Chen 	}
2420db7e66cSJonathan Chen 	printf("\n");
243a3133b58SWarner Losh 	return (0);
2440db7e66cSJonathan Chen }
2450db7e66cSJonathan Chen 
2460db7e66cSJonathan Chen DECODE_PROTOTYPE(manfid)
2470db7e66cSJonathan Chen {
2480db7e66cSJonathan Chen 	int i;
2490db7e66cSJonathan Chen 	printf("Manufacturer ID: ");
2500db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2517bec1dd5SJonathan Chen 		printf("%02x", tupledata[i]);
2520db7e66cSJonathan Chen 	printf("\n");
253a3133b58SWarner Losh 	return (0);
2540db7e66cSJonathan Chen }
2550db7e66cSJonathan Chen 
2560db7e66cSJonathan Chen DECODE_PROTOTYPE(funce)
2570db7e66cSJonathan Chen {
2580db7e66cSJonathan Chen 	int i;
2590db7e66cSJonathan Chen 	printf("Function Extension: ");
2600db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2617bec1dd5SJonathan Chen 		printf("%02x", tupledata[i]);
2620db7e66cSJonathan Chen 	printf("\n");
263a3133b58SWarner Losh 	return (0);
2640db7e66cSJonathan Chen }
2650db7e66cSJonathan Chen 
2660db7e66cSJonathan Chen DECODE_PROTOTYPE(bar)
2670db7e66cSJonathan Chen {
26863fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
2690db7e66cSJonathan Chen 	int type;
2700db7e66cSJonathan Chen 	int reg;
2710db7e66cSJonathan Chen 	u_int32_t bar;
2720db7e66cSJonathan Chen 
273e6e272b9SScott Long 	if (len != 6) {
274e6e272b9SScott Long 		printf("*** ERROR *** BAR length not 6 (%d)\n", len);
275e6e272b9SScott Long 		return (EINVAL);
276e6e272b9SScott Long 	}
2777bec1dd5SJonathan Chen 	reg = *(u_int16_t*)tupledata;
2787bec1dd5SJonathan Chen 	len = *(u_int32_t*)(tupledata + 2);
2790db7e66cSJonathan Chen 	if (reg & TPL_BAR_REG_AS) {
2800db7e66cSJonathan Chen 		type = SYS_RES_IOPORT;
2810db7e66cSJonathan Chen 	} else {
2820db7e66cSJonathan Chen 		type = SYS_RES_MEMORY;
2830db7e66cSJonathan Chen 	}
2840db7e66cSJonathan Chen 	bar = (reg & TPL_BAR_REG_ASI_MASK) - 1;
285255b159fSJonathan Chen 	if (bar < 0 || bar > 5 ||
286255b159fSJonathan Chen 	    (type == SYS_RES_IOPORT && bar == 5)) {
287255b159fSJonathan Chen 		device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n",
2880db7e66cSJonathan Chen 		    reg, bar);
289a3133b58SWarner Losh 		return (0);
2900db7e66cSJonathan Chen 	}
2910db7e66cSJonathan Chen 	bar = CARDBUS_BASE0_REG + bar * 4;
29263fa9f4cSJonathan Chen 	if (type == SYS_RES_MEMORY) {
29363fa9f4cSJonathan Chen 		if (bar & TPL_BAR_REG_PREFETCHABLE)
29463fa9f4cSJonathan Chen 			dinfo->mprefetchable |= BARBIT(bar);
29563fa9f4cSJonathan Chen 		if (bar & TPL_BAR_REG_BELOW1MB)
29663fa9f4cSJonathan Chen 			dinfo->mbelow1mb |= BARBIT(bar);
29763fa9f4cSJonathan Chen 	} else if (type == SYS_RES_IOPORT) {
29863fa9f4cSJonathan Chen 		if (bar & TPL_BAR_REG_BELOW1MB)
29963fa9f4cSJonathan Chen 			dinfo->ibelow1mb |= BARBIT(bar);
3000db7e66cSJonathan Chen 	}
301e6e272b9SScott Long 	DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
30263fa9f4cSJonathan Chen 	    (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
30363fa9f4cSJonathan Chen 	    (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
304e6e272b9SScott Long 	    " (Prefetchable)" : "", type == SYS_RES_MEMORY ?
305e6e272b9SScott Long 	    ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") :
306e6e272b9SScott Long 	    (dinfo->ibelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "" ));
30763fa9f4cSJonathan Chen 
3087ba175acSWarner Losh 	resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len);
309e6e272b9SScott Long 
310a3133b58SWarner Losh 	return (0);
3110db7e66cSJonathan Chen }
3120db7e66cSJonathan Chen 
3130db7e66cSJonathan Chen DECODE_PROTOTYPE(unhandled)
3140db7e66cSJonathan Chen {
3150db7e66cSJonathan Chen 	printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
316a3133b58SWarner Losh 	return (-1);
3170db7e66cSJonathan Chen }
3180db7e66cSJonathan Chen 
3190db7e66cSJonathan Chen DECODE_PROTOTYPE(end)
3200db7e66cSJonathan Chen {
3210c95c705SJonathan Chen 	printf("CIS reading done\n");
322a3133b58SWarner Losh 	return (0);
3230db7e66cSJonathan Chen }
3240db7e66cSJonathan Chen 
325255b159fSJonathan Chen /*
326255b159fSJonathan Chen  * Functions to read the a tuple from the card
327255b159fSJonathan Chen  */
328255b159fSJonathan Chen 
3290db7e66cSJonathan Chen static int
33063fa9f4cSJonathan Chen cardbus_read_tuple_conf(device_t cbdev, device_t child, u_int32_t start,
331255b159fSJonathan Chen     u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata)
3327bec1dd5SJonathan Chen {
3337bec1dd5SJonathan Chen 	int i, j;
3347bec1dd5SJonathan Chen 	u_int32_t e;
33549f158ccSJonathan Chen 	u_int32_t loc;
3367bec1dd5SJonathan Chen 
33763fa9f4cSJonathan Chen 	loc = start + *off;
33849f158ccSJonathan Chen 
33949f158ccSJonathan Chen 	e = pci_read_config(child, loc - loc % 4, 4);
34049f158ccSJonathan Chen 	for (j = loc % 4; j > 0; j--)
3417bec1dd5SJonathan Chen 		e >>= 8;
3427bec1dd5SJonathan Chen 	*len = 0;
34349f158ccSJonathan Chen 	for (i = loc, j = -2; j < *len; j++, i++) {
3447bec1dd5SJonathan Chen 		if (i % 4 == 0)
3457bec1dd5SJonathan Chen 			e = pci_read_config(child, i, 4);
3467bec1dd5SJonathan Chen 		if (j == -2)
3477bec1dd5SJonathan Chen 			*tupleid = 0xff & e;
3487bec1dd5SJonathan Chen 		else if (j == -1)
3497bec1dd5SJonathan Chen 			*len = 0xff & e;
3507bec1dd5SJonathan Chen 		else
3517bec1dd5SJonathan Chen 			tupledata[j] = 0xff & e;
3527bec1dd5SJonathan Chen 		e >>= 8;
3537bec1dd5SJonathan Chen 	}
3547bec1dd5SJonathan Chen 	*off += *len + 2;
355a3133b58SWarner Losh 	return (0);
3567bec1dd5SJonathan Chen }
3577bec1dd5SJonathan Chen 
3587bec1dd5SJonathan Chen static int
35963fa9f4cSJonathan Chen cardbus_read_tuple_mem(device_t cbdev, struct resource *res, u_int32_t start,
360255b159fSJonathan Chen     u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata)
3610db7e66cSJonathan Chen {
36263fa9f4cSJonathan Chen 	bus_space_tag_t bt;
36363fa9f4cSJonathan Chen 	bus_space_handle_t bh;
36463fa9f4cSJonathan Chen 	int ret;
3650db7e66cSJonathan Chen 
36663fa9f4cSJonathan Chen 	bt = rman_get_bustag(res);
36763fa9f4cSJonathan Chen 	bh = rman_get_bushandle(res);
3680db7e66cSJonathan Chen 
36963fa9f4cSJonathan Chen 	*tupleid = bus_space_read_1(bt, bh, start + *off);
37063fa9f4cSJonathan Chen 	*len = bus_space_read_1(bt, bh, start + *off + 1);
37163fa9f4cSJonathan Chen 	bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
37263fa9f4cSJonathan Chen 	ret = 0;
37363fa9f4cSJonathan Chen 	*off += *len + 2;
374a3133b58SWarner Losh 	return (ret);
3750db7e66cSJonathan Chen }
37663fa9f4cSJonathan Chen 
37763fa9f4cSJonathan Chen static int
37863fa9f4cSJonathan Chen cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
37963fa9f4cSJonathan Chen     u_int32_t start, u_int32_t *off, int *tupleid, int *len,
38063fa9f4cSJonathan Chen     u_int8_t *tupledata)
38163fa9f4cSJonathan Chen {
38263fa9f4cSJonathan Chen 	if (res == (struct resource*)~0UL) {
383a3133b58SWarner Losh 		return (cardbus_read_tuple_conf(cbdev, child, start, off,
384a3133b58SWarner Losh 		    tupleid, len, tupledata));
38563fa9f4cSJonathan Chen 	} else {
386a3133b58SWarner Losh 		return (cardbus_read_tuple_mem(cbdev, res, start, off,
387a3133b58SWarner Losh 		    tupleid, len, tupledata));
38863fa9f4cSJonathan Chen 	}
38963fa9f4cSJonathan Chen }
39063fa9f4cSJonathan Chen 
39163fa9f4cSJonathan Chen static void
39263fa9f4cSJonathan Chen cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
39363fa9f4cSJonathan Chen     struct resource *res)
39463fa9f4cSJonathan Chen {
39563fa9f4cSJonathan Chen 	if (res != (struct resource*)~0UL) {
39663fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
39763fa9f4cSJonathan Chen 		pci_write_config(child, rid, 0, 4);
39863fa9f4cSJonathan Chen 		PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
39963fa9f4cSJonathan Chen 	}
40063fa9f4cSJonathan Chen }
40163fa9f4cSJonathan Chen 
40263fa9f4cSJonathan Chen static struct resource *
40363fa9f4cSJonathan Chen cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start,
40463fa9f4cSJonathan Chen     int *rid)
40563fa9f4cSJonathan Chen {
40663fa9f4cSJonathan Chen 	u_int32_t testval;
40763fa9f4cSJonathan Chen 	u_int32_t size;
40863fa9f4cSJonathan Chen 	struct resource *res;
40963fa9f4cSJonathan Chen 
41063fa9f4cSJonathan Chen 	switch (CARDBUS_CIS_SPACE(*start)) {
41163fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_TUPLE:
412e6e272b9SScott Long 		/* CIS in PCI config space need no initialization */
41321677473SWarner Losh 		return ((struct resource*)~0UL);
41463fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR0:
41563fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR1:
41663fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR2:
41763fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR3:
41863fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR4:
41963fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR5:
42063fa9f4cSJonathan Chen 		*rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
42163fa9f4cSJonathan Chen 		break;
42263fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_ROM:
42363fa9f4cSJonathan Chen 		*rid = CARDBUS_ROM_REG;
424e6e272b9SScott Long #if 0
425e6e272b9SScott Long 		/*
426e6e272b9SScott Long 		 * This mask doesn't contain the bit that actually enables
427e6e272b9SScott Long 		 * the Option ROM.
428e6e272b9SScott Long 		 */
42963fa9f4cSJonathan Chen 		pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4);
430e6e272b9SScott Long #endif
43163fa9f4cSJonathan Chen 		break;
43263fa9f4cSJonathan Chen 	default:
43363fa9f4cSJonathan Chen 		device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
43463fa9f4cSJonathan Chen 		    CARDBUS_CIS_SPACE(*start));
435a3133b58SWarner Losh 		return (NULL);
43663fa9f4cSJonathan Chen 	}
43763fa9f4cSJonathan Chen 
43863fa9f4cSJonathan Chen 	/* figure out how much space we need */
439e6e272b9SScott Long 	pci_write_config(child, *rid, 0xffffffff, 4);
44063fa9f4cSJonathan Chen 	testval = pci_read_config(child, *rid, 4);
441e6e272b9SScott Long 
442e6e272b9SScott Long 	/*
443e6e272b9SScott Long 	 * This bit has a different meaning depending if we are dealing
4441e06ae99SScott Long 	 * with a normal BAR or an Option ROM BAR.
445e6e272b9SScott Long 	 */
446e6e272b9SScott Long 	if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) {
44763fa9f4cSJonathan Chen 		device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
448a3133b58SWarner Losh 		return (NULL);
44963fa9f4cSJonathan Chen 	}
450e6e272b9SScott Long 
45163fa9f4cSJonathan Chen 	size = CARDBUS_MAPREG_MEM_SIZE(testval);
452e6e272b9SScott Long 	/* XXX Is this some kind of hack? */
45363fa9f4cSJonathan Chen 	if (size < 4096)
45463fa9f4cSJonathan Chen 		size = 4096;
45563fa9f4cSJonathan Chen 	/* allocate the memory space to read CIS */
45663fa9f4cSJonathan Chen 	res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size,
45763fa9f4cSJonathan Chen 	    rman_make_alignment_flags(size) | RF_ACTIVE);
45863fa9f4cSJonathan Chen 	if (res == NULL) {
45963fa9f4cSJonathan Chen 		device_printf(cbdev, "Unable to allocate resource "
46063fa9f4cSJonathan Chen 		    "to read CIS.\n");
461a3133b58SWarner Losh 		return (NULL);
46263fa9f4cSJonathan Chen 	}
46363fa9f4cSJonathan Chen 	pci_write_config(child, *rid,
46463fa9f4cSJonathan Chen 	    rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)?
46563fa9f4cSJonathan Chen 		CARDBUS_ROM_ENABLE : 0),
46663fa9f4cSJonathan Chen 	    4);
46763fa9f4cSJonathan Chen 	PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY);
46863fa9f4cSJonathan Chen 
46963fa9f4cSJonathan Chen 	/* Flip to the right ROM image if CIS is in ROM */
47063fa9f4cSJonathan Chen 	if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
47163fa9f4cSJonathan Chen 		bus_space_tag_t bt;
47263fa9f4cSJonathan Chen 		bus_space_handle_t bh;
47363fa9f4cSJonathan Chen 		u_int32_t imagesize;
474e6e272b9SScott Long 		u_int32_t imagebase = 0;
475e6e272b9SScott Long 		u_int32_t pcidata;
476e6e272b9SScott Long 		u_int16_t romsig;
47763fa9f4cSJonathan Chen 		int romnum = 0;
478e6e272b9SScott Long 		int imagenum;
47963fa9f4cSJonathan Chen 
48063fa9f4cSJonathan Chen 		bt = rman_get_bustag(res);
48163fa9f4cSJonathan Chen 		bh = rman_get_bushandle(res);
48263fa9f4cSJonathan Chen 
48363fa9f4cSJonathan Chen 		imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
48463fa9f4cSJonathan Chen 		for (romnum = 0;; romnum++) {
485e6e272b9SScott Long 			romsig = bus_space_read_2(bt, bh,
486e6e272b9SScott Long 			    imagebase + CARDBUS_EXROM_SIGNATURE);
487e6e272b9SScott Long 			if (romsig != 0xaa55) {
48863fa9f4cSJonathan Chen 				device_printf(cbdev, "Bad header in rom %d: "
489e6e272b9SScott Long 				    "[%x] %04x\n", romnum, imagebase +
490e6e272b9SScott Long 				    CARDBUS_EXROM_SIGNATURE, romsig);
49163fa9f4cSJonathan Chen 				bus_release_resource(cbdev, SYS_RES_MEMORY,
49263fa9f4cSJonathan Chen 				    *rid, res);
49363fa9f4cSJonathan Chen 				*rid = 0;
494a3133b58SWarner Losh 				return (NULL);
49563fa9f4cSJonathan Chen 			}
496e6e272b9SScott Long 
497e6e272b9SScott Long 			/*
498e6e272b9SScott Long 			 * If this was the Option ROM image that we were
499e6e272b9SScott Long 			 * looking for, then we are done.
500e6e272b9SScott Long 			 */
501e6e272b9SScott Long 			if (romnum == imagenum)
502e6e272b9SScott Long 				break;
503e6e272b9SScott Long 
504e6e272b9SScott Long 			/* Find out where the next Option ROM image is */
505e6e272b9SScott Long 			pcidata = imagebase + bus_space_read_2(bt, bh,
506e6e272b9SScott Long 			    imagebase + CARDBUS_EXROM_DATA_PTR);
50763fa9f4cSJonathan Chen 			imagesize = bus_space_read_2(bt, bh,
508e6e272b9SScott Long 			    pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
5090db7e66cSJonathan Chen 
5107bec1dd5SJonathan Chen 			if (imagesize == 0) {
5110db7e66cSJonathan Chen 				/*
5120db7e66cSJonathan Chen 				 * XXX some ROMs seem to have this as zero,
5130db7e66cSJonathan Chen 				 * can we assume this means 1 block?
5140db7e66cSJonathan Chen 				 */
515e6e272b9SScott Long 				device_printf(cbdev, "Warning, size of Option "
516e6e272b9SScott Long 				    "ROM image %d is 0 bytes, assuming 512 "
517e6e272b9SScott Long 				    "bytes.\n", romnum);
5180db7e66cSJonathan Chen 				imagesize = 1;
5197bec1dd5SJonathan Chen 			}
520e6e272b9SScott Long 
521e6e272b9SScott Long 			/* Image size is in 512 byte units */
5220db7e66cSJonathan Chen 			imagesize <<= 9;
5230db7e66cSJonathan Chen 
524e6e272b9SScott Long 			if ((bus_space_read_1(bt, bh, pcidata +
5251e06ae99SScott Long 			    CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
526e6e272b9SScott Long 				device_printf(cbdev, "Cannot find CIS in "
527e6e272b9SScott Long 				    "Option ROM\n");
528e6e272b9SScott Long 				bus_release_resource(cbdev, SYS_RES_MEMORY,
529e6e272b9SScott Long 				    *rid, res);
530e6e272b9SScott Long 				*rid = 0;
531a3133b58SWarner Losh 				return (NULL);
5320db7e66cSJonathan Chen 			}
533e6e272b9SScott Long 			imagebase += imagesize;
5340db7e66cSJonathan Chen 		}
535e6e272b9SScott Long 		*start = imagebase + CARDBUS_CIS_ADDR(*start);
5360db7e66cSJonathan Chen 	} else {
537e6e272b9SScott Long 		*start = CARDBUS_CIS_ADDR(*start);
5380db7e66cSJonathan Chen 	}
539e6e272b9SScott Long 
540a3133b58SWarner Losh 	return (res);
5417bec1dd5SJonathan Chen }
5427bec1dd5SJonathan Chen 
543255b159fSJonathan Chen /*
544255b159fSJonathan Chen  * Dispatch the right handler function per tuple
545255b159fSJonathan Chen  */
546255b159fSJonathan Chen 
5477bec1dd5SJonathan Chen static int
548255b159fSJonathan Chen decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
54963fa9f4cSJonathan Chen     u_int8_t *tupledata, u_int32_t start, u_int32_t *off,
5500c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
5517bec1dd5SJonathan Chen {
5527bec1dd5SJonathan Chen 	int i;
5530c95c705SJonathan Chen 	for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
5540c95c705SJonathan Chen 		if (tupleid == callbacks[i].id)
555a3133b58SWarner Losh 			return (callbacks[i].func(cbdev, child, tupleid, len,
556a3133b58SWarner Losh 			    tupledata, start, off, &callbacks[i]));
5577bec1dd5SJonathan Chen 	}
5587bec1dd5SJonathan Chen 
55949f158ccSJonathan Chen 	if (tupleid < CISTPL_CUSTOMSTART) {
560255b159fSJonathan Chen 		device_printf(cbdev, "Undefined tuple encountered, "
561255b159fSJonathan Chen 		    "CIS parsing terminated\n");
562a3133b58SWarner Losh 		return (EINVAL);
56349f158ccSJonathan Chen 	}
564a3133b58SWarner Losh 	return (callbacks[i].func(cbdev, child, tupleid, len,
565a3133b58SWarner Losh 	    tupledata, start, off, NULL));
5660db7e66cSJonathan Chen }
5670db7e66cSJonathan Chen 
5680c95c705SJonathan Chen static int
569255b159fSJonathan Chen cardbus_parse_cis(device_t cbdev, device_t child,
5700c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
5710db7e66cSJonathan Chen {
5720db7e66cSJonathan Chen 	u_int8_t tupledata[MAXTUPLESIZE];
5737bec1dd5SJonathan Chen 	int tupleid;
5747bec1dd5SJonathan Chen 	int len;
5757bec1dd5SJonathan Chen 	int expect_linktarget;
57649f158ccSJonathan Chen 	u_int32_t start, off;
57763fa9f4cSJonathan Chen 	struct resource *res;
57863fa9f4cSJonathan Chen 	int rid;
5790db7e66cSJonathan Chen 
5800db7e66cSJonathan Chen 	bzero(tupledata, MAXTUPLESIZE);
5817bec1dd5SJonathan Chen 	expect_linktarget = TRUE;
582e6e272b9SScott Long 	if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0)
583e6e272b9SScott Long 		return (ENXIO);
58449f158ccSJonathan Chen 	off = 0;
58563fa9f4cSJonathan Chen 	res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
58663fa9f4cSJonathan Chen 	if (res == NULL)
587a3133b58SWarner Losh 		return (ENXIO);
5887bec1dd5SJonathan Chen 	do {
58963fa9f4cSJonathan Chen 		if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
59063fa9f4cSJonathan Chen 		    &tupleid, &len, tupledata)) {
59163fa9f4cSJonathan Chen 			device_printf(cbdev, "Failed to read CIS.\n");
59263fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
593a3133b58SWarner Losh 			return (ENXIO);
59463fa9f4cSJonathan Chen 		}
5957bec1dd5SJonathan Chen 
5967bec1dd5SJonathan Chen 		if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
597255b159fSJonathan Chen 			device_printf(cbdev, "Expecting link target, got 0x%x\n",
5987bec1dd5SJonathan Chen 			    tupleid);
59963fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
600a3133b58SWarner Losh 			return (EINVAL);
6017bec1dd5SJonathan Chen 		}
602255b159fSJonathan Chen 		expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
60363fa9f4cSJonathan Chen 		    tupledata, start, &off, callbacks);
60463fa9f4cSJonathan Chen 		if (expect_linktarget != 0) {
60563fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
606a3133b58SWarner Losh 			return (expect_linktarget);
60763fa9f4cSJonathan Chen 		}
6087bec1dd5SJonathan Chen 	} while (tupleid != CISTPL_END);
60963fa9f4cSJonathan Chen 	cardbus_read_tuple_finish(cbdev, child, rid, res);
610a3133b58SWarner Losh 	return (0);
6110db7e66cSJonathan Chen }
6120db7e66cSJonathan Chen 
61363fa9f4cSJonathan Chen static int
61463fa9f4cSJonathan Chen barsort(const void *a, const void *b)
61563fa9f4cSJonathan Chen {
61678b226dcSAlfred Perlstein 	return ((*(const struct resource_list_entry * const *)b)->count -
61778b226dcSAlfred Perlstein 	    (*(const struct resource_list_entry * const *)a)->count);
61863fa9f4cSJonathan Chen }
61963fa9f4cSJonathan Chen 
62063fa9f4cSJonathan Chen static int
62163fa9f4cSJonathan Chen cardbus_alloc_resources(device_t cbdev, device_t child)
62263fa9f4cSJonathan Chen {
62363fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
62463fa9f4cSJonathan Chen 	int count;
62563fa9f4cSJonathan Chen 	struct resource_list_entry *rle;
62663fa9f4cSJonathan Chen 	struct resource_list_entry **barlist;
62763fa9f4cSJonathan Chen 	int tmp;
62863fa9f4cSJonathan Chen 	u_int32_t mem_psize = 0, mem_nsize = 0, io_size = 0;
62963fa9f4cSJonathan Chen 	struct resource *res;
63063fa9f4cSJonathan Chen 	u_int32_t start,end;
63121677473SWarner Losh 	int rid, flags;
63263fa9f4cSJonathan Chen 
63363fa9f4cSJonathan Chen 	count = 0;
63421677473SWarner Losh 	SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
63563fa9f4cSJonathan Chen 		count++;
63621677473SWarner Losh 	}
63763fa9f4cSJonathan Chen 	if (count == 0)
638a3133b58SWarner Losh 		return (0);
63963fa9f4cSJonathan Chen 	barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF,
64063fa9f4cSJonathan Chen 	    M_WAITOK);
64163fa9f4cSJonathan Chen 	count = 0;
64221677473SWarner Losh 	SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
64363fa9f4cSJonathan Chen 		barlist[count] = rle;
64463fa9f4cSJonathan Chen 		if (rle->type == SYS_RES_IOPORT) {
64563fa9f4cSJonathan Chen 			io_size += rle->count;
64663fa9f4cSJonathan Chen 		} else if (rle->type == SYS_RES_MEMORY) {
64763fa9f4cSJonathan Chen 			if (dinfo->mprefetchable & BARBIT(rle->rid))
64863fa9f4cSJonathan Chen 				mem_psize += rle->count;
64963fa9f4cSJonathan Chen 			else
65063fa9f4cSJonathan Chen 				mem_nsize += rle->count;
65163fa9f4cSJonathan Chen 		}
65263fa9f4cSJonathan Chen 		count++;
65363fa9f4cSJonathan Chen 	}
65463fa9f4cSJonathan Chen 
65563fa9f4cSJonathan Chen 	/*
65663fa9f4cSJonathan Chen 	 * We want to allocate the largest resource first, so that our
65763fa9f4cSJonathan Chen 	 * allocated memory is packed.
65863fa9f4cSJonathan Chen 	 */
65963fa9f4cSJonathan Chen 	qsort(barlist, count, sizeof(struct resource_list_entry*), barsort);
66063fa9f4cSJonathan Chen 
66163fa9f4cSJonathan Chen 	/* Allocate prefetchable memory */
66263fa9f4cSJonathan Chen 	flags = 0;
66363fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
66463fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
66563fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_MEMORY &&
66663fa9f4cSJonathan Chen 		    dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) {
66763fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
66863fa9f4cSJonathan Chen 			break;
66963fa9f4cSJonathan Chen 		}
67063fa9f4cSJonathan Chen 	}
67163fa9f4cSJonathan Chen 	if (flags > 0) { /* If any prefetchable memory is requested... */
67263fa9f4cSJonathan Chen 		/*
67363fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
67463fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
67563fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
67663fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
67763fa9f4cSJonathan Chen 		 * within the window.
67863fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
67963fa9f4cSJonathan Chen 		 */
68063fa9f4cSJonathan Chen 		rid = 0;
68163fa9f4cSJonathan Chen 		res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
68263fa9f4cSJonathan Chen 		    (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL,
68363fa9f4cSJonathan Chen 		    mem_psize, flags);
68463fa9f4cSJonathan Chen 		start = rman_get_start(res);
68563fa9f4cSJonathan Chen 		end = rman_get_end(res);
68663fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end));
68763fa9f4cSJonathan Chen 		/*
68863fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
68963fa9f4cSJonathan Chen 		 * out piece by piece.
69063fa9f4cSJonathan Chen 		 */
69163fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
69263fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
69363fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
69463fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_MEMORY &&
69563fa9f4cSJonathan Chen 			    dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) {
69663fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
69763fa9f4cSJonathan Chen 				    barlist[tmp]->type,
69863fa9f4cSJonathan Chen 				    &barlist[tmp]->rid, start, end,
69963fa9f4cSJonathan Chen 				    barlist[tmp]->count,
70063fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
70163fa9f4cSJonathan Chen 				    barlist[tmp]->count));
70263fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
70363fa9f4cSJonathan Chen 					mem_nsize += barlist[tmp]->count;
70463fa9f4cSJonathan Chen 					dinfo->mprefetchable &=
70563fa9f4cSJonathan Chen 					    ~BARBIT(barlist[tmp]->rid);
70663fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
70763fa9f4cSJonathan Chen 					    "prefetchable memory, will try as "
70863fa9f4cSJonathan Chen 					    "non-prefetchable.\n"));
70921677473SWarner Losh 				} else {
71063fa9f4cSJonathan Chen 					barlist[tmp]->start =
71163fa9f4cSJonathan Chen 					    rman_get_start(barlist[tmp]->res);
71263fa9f4cSJonathan Chen 					barlist[tmp]->end =
71363fa9f4cSJonathan Chen 					    rman_get_end(barlist[tmp]->res);
71463fa9f4cSJonathan Chen 					pci_write_config(child,
71563fa9f4cSJonathan Chen 					    barlist[tmp]->rid,
71663fa9f4cSJonathan Chen 					    barlist[tmp]->start, 4);
71763fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Prefetchable memory "
71863fa9f4cSJonathan Chen 					    "rid=%x at %lx-%lx\n",
71963fa9f4cSJonathan Chen 					    barlist[tmp]->rid,
72063fa9f4cSJonathan Chen 					    barlist[tmp]->start,
72163fa9f4cSJonathan Chen 					    barlist[tmp]->end));
72263fa9f4cSJonathan Chen 				}
72363fa9f4cSJonathan Chen 			}
72463fa9f4cSJonathan Chen 		}
72521677473SWarner Losh 	}
72663fa9f4cSJonathan Chen 
72763fa9f4cSJonathan Chen 	/* Allocate non-prefetchable memory */
72863fa9f4cSJonathan Chen 	flags = 0;
72963fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
73063fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
73163fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_MEMORY) {
73263fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
73363fa9f4cSJonathan Chen 			break;
73463fa9f4cSJonathan Chen 		}
73563fa9f4cSJonathan Chen 	}
73663fa9f4cSJonathan Chen 	if (flags > 0) { /* If any non-prefetchable memory is requested... */
73763fa9f4cSJonathan Chen 		/*
73863fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
73963fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
74063fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
74163fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
74263fa9f4cSJonathan Chen 		 * within the window.
74363fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
74463fa9f4cSJonathan Chen 		 */
74563fa9f4cSJonathan Chen 		rid = 0;
74663fa9f4cSJonathan Chen 		res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
74763fa9f4cSJonathan Chen 		    ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL,
74863fa9f4cSJonathan Chen 		    mem_nsize, flags);
74963fa9f4cSJonathan Chen 		start = rman_get_start(res);
75063fa9f4cSJonathan Chen 		end = rman_get_end(res);
75163fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n",
75263fa9f4cSJonathan Chen 		    start, end));
75363fa9f4cSJonathan Chen 		/*
75463fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
75563fa9f4cSJonathan Chen 		 * out piece by piece.
75663fa9f4cSJonathan Chen 		 */
75763fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
75863fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
75963fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
76063fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_MEMORY) {
76163fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
76263fa9f4cSJonathan Chen 				    barlist[tmp]->type, &barlist[tmp]->rid,
76363fa9f4cSJonathan Chen 				    start, end, barlist[tmp]->count,
76463fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
76563fa9f4cSJonathan Chen 				    barlist[tmp]->count));
76663fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
76763fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
76863fa9f4cSJonathan Chen 					    "memory for cardbus device\n"));
769214c0b3dSWarner Losh 					free(barlist, M_DEVBUF);
7707ba175acSWarner Losh 					return (ENOMEM);
77163fa9f4cSJonathan Chen 				}
77263fa9f4cSJonathan Chen 				barlist[tmp]->start =
77363fa9f4cSJonathan Chen 				    rman_get_start(barlist[tmp]->res);
77463fa9f4cSJonathan Chen 				barlist[tmp]->end = rman_get_end(
77563fa9f4cSJonathan Chen 					barlist[tmp]->res);
77663fa9f4cSJonathan Chen 				pci_write_config(child, barlist[tmp]->rid,
77763fa9f4cSJonathan Chen 				    barlist[tmp]->start, 4);
77863fa9f4cSJonathan Chen 				DEVPRINTF((cbdev, "Non-prefetchable memory "
77963fa9f4cSJonathan Chen 				    "rid=%x at %lx-%lx (%lx)\n",
78063fa9f4cSJonathan Chen 				    barlist[tmp]->rid, barlist[tmp]->start,
78163fa9f4cSJonathan Chen 				    barlist[tmp]->end, barlist[tmp]->count));
78263fa9f4cSJonathan Chen 			}
78363fa9f4cSJonathan Chen 		}
78463fa9f4cSJonathan Chen 	}
78563fa9f4cSJonathan Chen 
78663fa9f4cSJonathan Chen 	/* Allocate IO ports */
78763fa9f4cSJonathan Chen 	flags = 0;
78863fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
78963fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
79063fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_IOPORT) {
79163fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
79263fa9f4cSJonathan Chen 			break;
79363fa9f4cSJonathan Chen 		}
79463fa9f4cSJonathan Chen 	}
79563fa9f4cSJonathan Chen 	if (flags > 0) { /* If any IO port is requested... */
79663fa9f4cSJonathan Chen 		/*
79763fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
79863fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
79963fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
80063fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
80163fa9f4cSJonathan Chen 		 * within the window.
80263fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
80363fa9f4cSJonathan Chen 		 */
80463fa9f4cSJonathan Chen 		rid = 0;
80521677473SWarner Losh 		res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0,
80621677473SWarner Losh 		    (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags);
80763fa9f4cSJonathan Chen 		start = rman_get_start(res);
80863fa9f4cSJonathan Chen 		end = rman_get_end(res);
80963fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end));
81063fa9f4cSJonathan Chen 		/*
81163fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
81221677473SWarner Losh 		 * out piece by piece.
81363fa9f4cSJonathan Chen 		 */
81463fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res);
81563fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
81663fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
81763fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_IOPORT) {
81863fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
81963fa9f4cSJonathan Chen 				    barlist[tmp]->type, &barlist[tmp]->rid,
82063fa9f4cSJonathan Chen 				    start, end, barlist[tmp]->count,
82163fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
82263fa9f4cSJonathan Chen 				    barlist[tmp]->count));
82363fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
82463fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
82563fa9f4cSJonathan Chen 					    "IO port for cardbus device\n"));
826214c0b3dSWarner Losh 					free(barlist, M_DEVBUF);
827a3133b58SWarner Losh 					return (ENOMEM);
82863fa9f4cSJonathan Chen 				}
82963fa9f4cSJonathan Chen 				barlist[tmp]->start =
83063fa9f4cSJonathan Chen 				    rman_get_start(barlist[tmp]->res);
83163fa9f4cSJonathan Chen 				barlist[tmp]->end =
83263fa9f4cSJonathan Chen 				    rman_get_end(barlist[tmp]->res);
83363fa9f4cSJonathan Chen 			pci_write_config(child, barlist[tmp]->rid,
83463fa9f4cSJonathan Chen 			    barlist[tmp]->start, 4);
83563fa9f4cSJonathan Chen 			DEVPRINTF((cbdev, "IO port rid=%x at %lx-%lx\n",
83663fa9f4cSJonathan Chen 			    barlist[tmp]->rid, barlist[tmp]->start,
83763fa9f4cSJonathan Chen 			    barlist[tmp]->end));
83863fa9f4cSJonathan Chen 			}
83963fa9f4cSJonathan Chen 		}
84063fa9f4cSJonathan Chen 	}
84163fa9f4cSJonathan Chen 
84263fa9f4cSJonathan Chen 	/* Allocate IRQ */
84363fa9f4cSJonathan Chen 	rid = 0;
84463fa9f4cSJonathan Chen 	res = bus_alloc_resource(cbdev, SYS_RES_IRQ, &rid, 0, ~0UL, 1,
84563fa9f4cSJonathan Chen 	    RF_SHAREABLE);
84621677473SWarner Losh 	resource_list_add(&dinfo->pci.resources, SYS_RES_IRQ, rid,
84721677473SWarner Losh 	    rman_get_start(res), rman_get_end(res), 1);
84821677473SWarner Losh 	rle = resource_list_find(&dinfo->pci.resources, SYS_RES_IRQ, rid);
84921677473SWarner Losh 	rle->res = res;
85021677473SWarner Losh 	dinfo->pci.cfg.intline = rman_get_start(res);
85121677473SWarner Losh 	pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1);
85263fa9f4cSJonathan Chen 
853214c0b3dSWarner Losh 	free(barlist, M_DEVBUF);
854a3133b58SWarner Losh 	return (0);
85563fa9f4cSJonathan Chen }
85663fa9f4cSJonathan Chen 
85763fa9f4cSJonathan Chen /*
85863fa9f4cSJonathan Chen  * Adding a memory/io resource (sans CIS)
85963fa9f4cSJonathan Chen  */
86063fa9f4cSJonathan Chen 
86163fa9f4cSJonathan Chen static void
86263fa9f4cSJonathan Chen cardbus_add_map(device_t cbdev, device_t child, int reg)
86363fa9f4cSJonathan Chen {
86463fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
86521677473SWarner Losh 	struct resource_list_entry *rle;
86663fa9f4cSJonathan Chen 	u_int32_t size;
86763fa9f4cSJonathan Chen 	u_int32_t testval;
86863fa9f4cSJonathan Chen 	int type;
86963fa9f4cSJonathan Chen 
87021677473SWarner Losh 	SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
87121677473SWarner Losh 		if (rle->rid == reg)
87263fa9f4cSJonathan Chen 			return;
87321677473SWarner Losh 	}
87463fa9f4cSJonathan Chen 
87563fa9f4cSJonathan Chen 	if (reg == CARDBUS_ROM_REG)
87663fa9f4cSJonathan Chen 		testval = CARDBUS_ROM_ADDRMASK;
87763fa9f4cSJonathan Chen 	else
87863fa9f4cSJonathan Chen 		testval = ~0;
87963fa9f4cSJonathan Chen 
88063fa9f4cSJonathan Chen 	pci_write_config(child, reg, testval, 4);
88163fa9f4cSJonathan Chen 	testval = pci_read_config(child, reg, 4);
88263fa9f4cSJonathan Chen 
88363fa9f4cSJonathan Chen 	if (testval == ~0 || testval == 0)
88463fa9f4cSJonathan Chen 		return;
88563fa9f4cSJonathan Chen 
88663fa9f4cSJonathan Chen 	if ((testval & 1) == 0)
88763fa9f4cSJonathan Chen 		type = SYS_RES_MEMORY;
88863fa9f4cSJonathan Chen 	else
88963fa9f4cSJonathan Chen 		type = SYS_RES_IOPORT;
89063fa9f4cSJonathan Chen 
89163fa9f4cSJonathan Chen 	size = CARDBUS_MAPREG_MEM_SIZE(testval);
89221677473SWarner Losh 	device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n",
89321677473SWarner Losh 	    reg, size);
89421677473SWarner Losh 	resource_list_add(&dinfo->pci.resources, type, reg, 0UL, ~0UL, size);
89563fa9f4cSJonathan Chen }
89663fa9f4cSJonathan Chen 
89763fa9f4cSJonathan Chen static void
89863fa9f4cSJonathan Chen cardbus_pickup_maps(device_t cbdev, device_t child)
89963fa9f4cSJonathan Chen {
90063fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
90163fa9f4cSJonathan Chen 	struct cardbus_quirk *q;
90263fa9f4cSJonathan Chen 	int reg;
90363fa9f4cSJonathan Chen 
90463fa9f4cSJonathan Chen 	/*
90563fa9f4cSJonathan Chen 	 * Try to pick up any resources that was not specified in CIS.
90663fa9f4cSJonathan Chen 	 * Some devices (eg, 3c656) does not list all resources required by
90763fa9f4cSJonathan Chen 	 * the driver in its CIS.
90863fa9f4cSJonathan Chen 	 * XXX: should we do this or use quirks?
90963fa9f4cSJonathan Chen 	 */
9107ba175acSWarner Losh 	for (reg = 0; reg < dinfo->pci.cfg.nummaps; reg++) {
91163fa9f4cSJonathan Chen 		cardbus_add_map(cbdev, child, PCIR_MAPS + reg * 4);
91263fa9f4cSJonathan Chen 	}
91363fa9f4cSJonathan Chen 
91463fa9f4cSJonathan Chen 	for (q = &cardbus_quirks[0]; q->devid; q++) {
91521677473SWarner Losh 		if (q->devid == ((dinfo->pci.cfg.device << 16) | dinfo->pci.cfg.vendor)
91663fa9f4cSJonathan Chen 		    && q->type == CARDBUS_QUIRK_MAP_REG) {
91763fa9f4cSJonathan Chen 			cardbus_add_map(cbdev, child, q->arg1);
91863fa9f4cSJonathan Chen 		}
91963fa9f4cSJonathan Chen 	}
92063fa9f4cSJonathan Chen }
92163fa9f4cSJonathan Chen 
9220c95c705SJonathan Chen int
923255b159fSJonathan Chen cardbus_cis_read(device_t cbdev, device_t child, u_int8_t id,
9240c95c705SJonathan Chen     struct cis_tupleinfo **buff, int *nret)
9250c95c705SJonathan Chen {
9260c95c705SJonathan Chen 	struct tuple_callbacks cisread_callbacks[] = {
9270c95c705SJonathan Chen 		MAKETUPLE(NULL,			nothing),
9280c95c705SJonathan Chen 		/* first entry will be overwritten */
9290c95c705SJonathan Chen 		MAKETUPLE(NULL,			nothing),
9300c95c705SJonathan Chen 		MAKETUPLE(DEVICE,		nothing),
9310c95c705SJonathan Chen 		MAKETUPLE(LONG_LINK_CB,		unhandled),
9320c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
9330c95c705SJonathan Chen 		MAKETUPLE(CONFIG_CB,		nothing),
9340c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY_CB,	nothing),
9350c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
9360c95c705SJonathan Chen 		MAKETUPLE(BAR,			nothing),
9370c95c705SJonathan Chen 		MAKETUPLE(PWR_MGMNT,		nothing),
9380c95c705SJonathan Chen 		MAKETUPLE(EXTDEVICE,		nothing),
9390c95c705SJonathan Chen 		MAKETUPLE(CHECKSUM,		nothing),
9400c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
9410c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
9420c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		nothing),
9430c95c705SJonathan Chen 		MAKETUPLE(NO_LINK,		nothing),
9440c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		nothing),
9450c95c705SJonathan Chen 		MAKETUPLE(ALTSTR,		nothing),
9460c95c705SJonathan Chen 		MAKETUPLE(DEVICE_A,		nothing),
9470c95c705SJonathan Chen 		MAKETUPLE(JEDEC_C,		nothing),
9480c95c705SJonathan Chen 		MAKETUPLE(JEDEC_A,		nothing),
9490c95c705SJonathan Chen 		MAKETUPLE(CONFIG,		nothing),
9500c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY,	nothing),
9510c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OC,		nothing),
9520c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OA,		nothing),
9530c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO,		nothing),
9540c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO_A,		nothing),
9550c95c705SJonathan Chen 		MAKETUPLE(MANFID,		nothing),
9560c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		nothing),
9570c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		nothing),
9580c95c705SJonathan Chen 		MAKETUPLE(SWIL,			nothing),
9590c95c705SJonathan Chen 		MAKETUPLE(VERS_2,		nothing),
9600c95c705SJonathan Chen 		MAKETUPLE(FORMAT,		nothing),
9610c95c705SJonathan Chen 		MAKETUPLE(GEOMETRY,		nothing),
9620c95c705SJonathan Chen 		MAKETUPLE(BYTEORDER,		nothing),
9630c95c705SJonathan Chen 		MAKETUPLE(DATE,			nothing),
9640c95c705SJonathan Chen 		MAKETUPLE(BATTERY,		nothing),
9650c95c705SJonathan Chen 		MAKETUPLE(ORG,			nothing),
9660c95c705SJonathan Chen 		MAKETUPLE(END,			end),
9670c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		nothing),
9680c95c705SJonathan Chen 	};
9690c95c705SJonathan Chen 	int ret;
9700c95c705SJonathan Chen 
9710c95c705SJonathan Chen 	cisread_callbacks[0].id = id;
9720c95c705SJonathan Chen 	cisread_callbacks[0].name = "COPY";
9730c95c705SJonathan Chen 	cisread_callbacks[0].func = decode_tuple_copy;
9740c95c705SJonathan Chen 	ncisread_buf = 0;
9750c95c705SJonathan Chen 	cisread_buf = NULL;
976255b159fSJonathan Chen 	ret = cardbus_parse_cis(cbdev, child, cisread_callbacks);
9770c95c705SJonathan Chen 
9780c95c705SJonathan Chen 	*buff = cisread_buf;
9790c95c705SJonathan Chen 	*nret = ncisread_buf;
980a3133b58SWarner Losh 	return (ret);
9810c95c705SJonathan Chen }
9820c95c705SJonathan Chen 
9830c95c705SJonathan Chen void
984255b159fSJonathan Chen cardbus_cis_free(device_t cbdev, struct cis_tupleinfo *buff, int *nret)
9850c95c705SJonathan Chen {
9860c95c705SJonathan Chen 	int i;
9876f39832cSPeter Wemm 	for (i = 0; i < *nret; i++)
9880c95c705SJonathan Chen 		free(buff[i].data, M_DEVBUF);
9896f39832cSPeter Wemm 	if (*nret > 0)
9900c95c705SJonathan Chen 		free(buff, M_DEVBUF);
9910c95c705SJonathan Chen }
9920c95c705SJonathan Chen 
9930c95c705SJonathan Chen int
994255b159fSJonathan Chen cardbus_do_cis(device_t cbdev, device_t child)
9950c95c705SJonathan Chen {
99663fa9f4cSJonathan Chen 	int ret;
9970c95c705SJonathan Chen 	struct tuple_callbacks init_callbacks[] = {
9980c95c705SJonathan Chen 		MAKETUPLE(NULL,			generic),
9990c95c705SJonathan Chen 		MAKETUPLE(DEVICE,		generic),
10000c95c705SJonathan Chen 		MAKETUPLE(LONG_LINK_CB,		unhandled),
10010c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
10020c95c705SJonathan Chen 		MAKETUPLE(CONFIG_CB,		generic),
10030c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY_CB,	generic),
10040c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
10050c95c705SJonathan Chen 		MAKETUPLE(BAR,			bar),
10060c95c705SJonathan Chen 		MAKETUPLE(PWR_MGMNT,		generic),
10070c95c705SJonathan Chen 		MAKETUPLE(EXTDEVICE,		generic),
10080c95c705SJonathan Chen 		MAKETUPLE(CHECKSUM,		generic),
10090c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
10100c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
10110c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		linktarget),
10120c95c705SJonathan Chen 		MAKETUPLE(NO_LINK,		generic),
10130c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		vers_1),
10140c95c705SJonathan Chen 		MAKETUPLE(ALTSTR,		generic),
10150c95c705SJonathan Chen 		MAKETUPLE(DEVICE_A,		generic),
10160c95c705SJonathan Chen 		MAKETUPLE(JEDEC_C,		generic),
10170c95c705SJonathan Chen 		MAKETUPLE(JEDEC_A,		generic),
10180c95c705SJonathan Chen 		MAKETUPLE(CONFIG,		generic),
10190c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY,	generic),
10200c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OC,		generic),
10210c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OA,		generic),
10220c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO,		generic),
10230c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO_A,		generic),
10240c95c705SJonathan Chen 		MAKETUPLE(MANFID,		manfid),
10250c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		funcid),
10260c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		funce),
10270c95c705SJonathan Chen 		MAKETUPLE(SWIL,			generic),
10280c95c705SJonathan Chen 		MAKETUPLE(VERS_2,		generic),
10290c95c705SJonathan Chen 		MAKETUPLE(FORMAT,		generic),
10300c95c705SJonathan Chen 		MAKETUPLE(GEOMETRY,		generic),
10310c95c705SJonathan Chen 		MAKETUPLE(BYTEORDER,		generic),
10320c95c705SJonathan Chen 		MAKETUPLE(DATE,			generic),
10330c95c705SJonathan Chen 		MAKETUPLE(BATTERY,		generic),
10340c95c705SJonathan Chen 		MAKETUPLE(ORG,			generic),
10350c95c705SJonathan Chen 		MAKETUPLE(END,			end),
10360c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		generic),
10370c95c705SJonathan Chen 	};
103863fa9f4cSJonathan Chen 
103963fa9f4cSJonathan Chen 	ret = cardbus_parse_cis(cbdev, child, init_callbacks);
104063fa9f4cSJonathan Chen 	if (ret < 0)
1041a3133b58SWarner Losh 		return (ret);
104263fa9f4cSJonathan Chen 	cardbus_pickup_maps(cbdev, child);
1043a3133b58SWarner Losh 	return (cardbus_alloc_resources(cbdev, child));
10440c95c705SJonathan Chen }
1045