xref: /freebsd/sys/dev/cardbus/cardbus_cis.c (revision 63fa9f4c0df3db694d5fc73334e820ca55fb769e)
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 #define	CARDBUS_DEBUG
360db7e66cSJonathan Chen 
370db7e66cSJonathan Chen #include <sys/param.h>
380db7e66cSJonathan Chen #include <sys/systm.h>
390db7e66cSJonathan Chen #include <sys/kernel.h>
400c95c705SJonathan Chen #include <sys/malloc.h>
410db7e66cSJonathan Chen 
420db7e66cSJonathan Chen #include <sys/bus.h>
430db7e66cSJonathan Chen #include <machine/bus.h>
440db7e66cSJonathan Chen #include <machine/resource.h>
450db7e66cSJonathan Chen #include <sys/rman.h>
460db7e66cSJonathan Chen 
4763fa9f4cSJonathan Chen #include <dev/pci/pcivar.h>
4863fa9f4cSJonathan Chen #include <dev/pci/pcireg.h>
4963fa9f4cSJonathan Chen #include <sys/pciio.h>
500db7e66cSJonathan Chen 
510db7e66cSJonathan Chen #include <dev/cardbus/cardbusreg.h>
5263fa9f4cSJonathan Chen #include <dev/cardbus/cardbusvar.h>
530db7e66cSJonathan Chen #include <dev/cardbus/cardbus_cis.h>
540db7e66cSJonathan Chen 
550c95c705SJonathan Chen #include "card_if.h"
560c95c705SJonathan Chen 
570db7e66cSJonathan Chen #if defined CARDBUS_DEBUG
580db7e66cSJonathan Chen #define	DPRINTF(a) printf a
590db7e66cSJonathan Chen #define	DEVPRINTF(x) device_printf x
600db7e66cSJonathan Chen #else
610db7e66cSJonathan Chen #define	DPRINTF(a)
620db7e66cSJonathan Chen #define	DEVPRINTF(x)
630db7e66cSJonathan Chen #endif
640db7e66cSJonathan Chen 
650db7e66cSJonathan Chen #if !defined(lint)
660db7e66cSJonathan Chen static const char rcsid[] =
670db7e66cSJonathan Chen     "$FreeBSD$";
680db7e66cSJonathan Chen #endif
690db7e66cSJonathan Chen 
700c95c705SJonathan Chen #define	DECODE_PARAMS							\
71255b159fSJonathan Chen 		(device_t cbdev, device_t child, int id, int len,	\
7263fa9f4cSJonathan Chen 		 u_int8_t *tupledata, u_int32_t start, u_int32_t *off,	\
730c95c705SJonathan Chen 		 struct tuple_callbacks *info)
740db7e66cSJonathan Chen 
750c95c705SJonathan Chen struct tuple_callbacks {
760c95c705SJonathan Chen 	int	id;
770db7e66cSJonathan Chen 	char	*name;
780c95c705SJonathan Chen 	int	(*func) DECODE_PARAMS;
790db7e66cSJonathan Chen };
80255b159fSJonathan Chen 
81255b159fSJonathan Chen #define	DECODE_PROTOTYPE(NAME) static int decode_tuple_ ## NAME DECODE_PARAMS
82255b159fSJonathan Chen DECODE_PROTOTYPE(generic);
83255b159fSJonathan Chen DECODE_PROTOTYPE(nothing);
84255b159fSJonathan Chen DECODE_PROTOTYPE(copy);
85255b159fSJonathan Chen DECODE_PROTOTYPE(linktarget);
86255b159fSJonathan Chen DECODE_PROTOTYPE(vers_1);
87255b159fSJonathan Chen DECODE_PROTOTYPE(funcid);
88255b159fSJonathan Chen DECODE_PROTOTYPE(manfid);
89255b159fSJonathan Chen DECODE_PROTOTYPE(funce);
90255b159fSJonathan Chen DECODE_PROTOTYPE(bar);
91255b159fSJonathan Chen DECODE_PROTOTYPE(unhandled);
92255b159fSJonathan Chen DECODE_PROTOTYPE(end);
93255b159fSJonathan Chen static int	cardbus_read_tuple_conf(device_t cbdev, device_t child,
9463fa9f4cSJonathan Chen 		    u_int32_t start, u_int32_t *off, int *tupleid, int *len,
95255b159fSJonathan Chen 		    u_int8_t *tupledata);
9663fa9f4cSJonathan Chen static int	cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
9763fa9f4cSJonathan Chen 		    u_int32_t start, u_int32_t *off, int *tupleid, int *len,
98255b159fSJonathan Chen 		    u_int8_t *tupledata);
99255b159fSJonathan Chen static int	cardbus_read_tuple(device_t cbdev, device_t child,
10063fa9f4cSJonathan Chen 		    struct resource *res, u_int32_t start, u_int32_t *off,
10163fa9f4cSJonathan Chen 		    int *tupleid, int *len, u_int8_t *tupledata);
10263fa9f4cSJonathan Chen static void	cardbus_read_tuple_finish(device_t cbdev, device_t child,
10363fa9f4cSJonathan Chen 		    int rid, struct resource *res);
10463fa9f4cSJonathan Chen static struct resource	*cardbus_read_tuple_init(device_t cbdev, device_t child,
10563fa9f4cSJonathan Chen 		    u_int32_t *start, int *rid);
106255b159fSJonathan Chen static int	decode_tuple(device_t cbdev, device_t child, int tupleid,
10763fa9f4cSJonathan Chen 		    int len, u_int8_t *tupledata, u_int32_t start,
108255b159fSJonathan Chen 		    u_int32_t *off, struct tuple_callbacks *callbacks);
109255b159fSJonathan Chen static int	cardbus_parse_cis(device_t cbdev, device_t child,
110255b159fSJonathan Chen 		    struct tuple_callbacks *callbacks);
11163fa9f4cSJonathan Chen static int	barsort(const void *a, const void *b);
11263fa9f4cSJonathan Chen static int	cardbus_alloc_resources(device_t cbdev, device_t child);
11363fa9f4cSJonathan Chen static void	cardbus_add_map(device_t cbdev, device_t child, int reg);
11463fa9f4cSJonathan Chen static void	cardbus_pickup_maps(device_t cbdev, device_t child);
11563fa9f4cSJonathan Chen 
116255b159fSJonathan Chen 
1170c95c705SJonathan Chen #define	MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
1180db7e66cSJonathan Chen 
1190db7e66cSJonathan Chen static char *funcnames[] = {
1200db7e66cSJonathan Chen 	"Multi-Functioned",
1210db7e66cSJonathan Chen 	"Memory",
1220db7e66cSJonathan Chen 	"Serial Port",
1230db7e66cSJonathan Chen 	"Parallel Port",
1240db7e66cSJonathan Chen 	"Fixed Disk",
1250db7e66cSJonathan Chen 	"Video Adaptor",
1260db7e66cSJonathan Chen 	"Network Adaptor",
1270db7e66cSJonathan Chen 	"AIMS",
1280db7e66cSJonathan Chen 	"SCSI",
1290db7e66cSJonathan Chen 	"Security"
1300db7e66cSJonathan Chen };
1310db7e66cSJonathan Chen 
13263fa9f4cSJonathan Chen struct cardbus_quirk {
13363fa9f4cSJonathan Chen 	u_int32_t devid;	/* Vendor/device of the card */
13463fa9f4cSJonathan Chen 	int	type;
13563fa9f4cSJonathan Chen #define	CARDBUS_QUIRK_MAP_REG	1 /* PCI map register in weird place */
13663fa9f4cSJonathan Chen 	int	arg1;
13763fa9f4cSJonathan Chen 	int	arg2;
13863fa9f4cSJonathan Chen };
13963fa9f4cSJonathan Chen 
14063fa9f4cSJonathan Chen struct cardbus_quirk cardbus_quirks[] = {
14163fa9f4cSJonathan Chen 	{ 0 }
14263fa9f4cSJonathan Chen };
14363fa9f4cSJonathan Chen 
1440c95c705SJonathan Chen static struct cis_tupleinfo *cisread_buf;
1450c95c705SJonathan Chen static int ncisread_buf;
1460c95c705SJonathan Chen 
147255b159fSJonathan Chen /*
148255b159fSJonathan Chen  * Handler functions for various CIS tuples
149255b159fSJonathan Chen  */
150255b159fSJonathan Chen 
1510db7e66cSJonathan Chen DECODE_PROTOTYPE(generic)
1520db7e66cSJonathan Chen {
1530db7e66cSJonathan Chen #ifdef CARDBUS_DEBUG
1540db7e66cSJonathan Chen 	int i;
1550db7e66cSJonathan Chen 
1560db7e66cSJonathan Chen 	if (info)
1570db7e66cSJonathan Chen 		printf("TUPLE: %s [%d]:", info->name, len);
1580db7e66cSJonathan Chen 	else
1590db7e66cSJonathan Chen 		printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
1600db7e66cSJonathan Chen 
1610db7e66cSJonathan Chen 	for (i = 0; i < len; i++) {
1620db7e66cSJonathan Chen 		if (i % 0x10 == 0 && len > 0x10)
1630db7e66cSJonathan Chen 			printf("\n       0x%02x:", i);
1647bec1dd5SJonathan Chen 		printf(" %02x", tupledata[i]);
1650db7e66cSJonathan Chen 	}
1660db7e66cSJonathan Chen 	printf("\n");
1670db7e66cSJonathan Chen #endif
1680db7e66cSJonathan Chen 	return 0;
1690db7e66cSJonathan Chen }
1700db7e66cSJonathan Chen 
1710c95c705SJonathan Chen DECODE_PROTOTYPE(nothing)
1720c95c705SJonathan Chen {
1730c95c705SJonathan Chen 	return 0;
1740c95c705SJonathan Chen }
1750c95c705SJonathan Chen 
1760c95c705SJonathan Chen DECODE_PROTOTYPE(copy)
1770c95c705SJonathan Chen {
1780c95c705SJonathan Chen 	struct cis_tupleinfo *tmpbuf;
1790c95c705SJonathan Chen 
1800c95c705SJonathan Chen 	tmpbuf = malloc(sizeof(struct cis_tupleinfo) * (ncisread_buf+1),
1810c95c705SJonathan Chen 	    M_DEVBUF, M_WAITOK);
1820c95c705SJonathan Chen 	if (ncisread_buf > 0) {
1830c95c705SJonathan Chen 		memcpy(tmpbuf, cisread_buf,
1840c95c705SJonathan Chen 		    sizeof(struct cis_tupleinfo) * ncisread_buf);
1850c95c705SJonathan Chen 		free(cisread_buf, M_DEVBUF);
1860c95c705SJonathan Chen 	}
1870c95c705SJonathan Chen 	cisread_buf = tmpbuf;
1880c95c705SJonathan Chen 
1890c95c705SJonathan Chen 	cisread_buf[ncisread_buf].id = id;
1900c95c705SJonathan Chen 	cisread_buf[ncisread_buf].len = len;
1910c95c705SJonathan Chen 	cisread_buf[ncisread_buf].data = malloc(len, M_DEVBUF, M_WAITOK);
1920c95c705SJonathan Chen 	memcpy(cisread_buf[ncisread_buf].data, tupledata, len);
1930c95c705SJonathan Chen 	ncisread_buf++;
1940c95c705SJonathan Chen 	return 0;
1950c95c705SJonathan Chen }
1960c95c705SJonathan Chen 
1970db7e66cSJonathan Chen DECODE_PROTOTYPE(linktarget)
1980db7e66cSJonathan Chen {
19949f158ccSJonathan Chen #ifdef CARDBUS_DEBUG
20049f158ccSJonathan Chen 	int i;
20149f158ccSJonathan Chen 
20249f158ccSJonathan Chen 	printf("TUPLE: %s [%d]:", info->name, len);
20349f158ccSJonathan Chen 
20449f158ccSJonathan Chen 	for (i = 0; i < len; i++) {
20549f158ccSJonathan Chen 		if (i % 0x10 == 0 && len > 0x10)
20649f158ccSJonathan Chen 			printf("\n       0x%02x:", i);
20749f158ccSJonathan Chen 		printf(" %02x", tupledata[i]);
20849f158ccSJonathan Chen 	}
20949f158ccSJonathan Chen 	printf("\n");
21049f158ccSJonathan Chen #endif
2117bec1dd5SJonathan Chen 	if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
2127bec1dd5SJonathan Chen 	    tupledata[2] != 'S') {
2130db7e66cSJonathan Chen 		printf("Invalid data for CIS Link Target!\n");
214255b159fSJonathan Chen 		decode_tuple_generic(cbdev, child, id, len, tupledata,
21549f158ccSJonathan Chen 		    start, off, info);
2160db7e66cSJonathan Chen 		return EINVAL;
2170db7e66cSJonathan Chen 	}
2180db7e66cSJonathan Chen 	return 0;
2190db7e66cSJonathan Chen }
2200db7e66cSJonathan Chen 
2210db7e66cSJonathan Chen DECODE_PROTOTYPE(vers_1)
2220db7e66cSJonathan Chen {
2230db7e66cSJonathan Chen 	int i;
2247bec1dd5SJonathan Chen 	printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
2250db7e66cSJonathan Chen 	printf("Product name: ");
2260db7e66cSJonathan Chen 	for (i = 2; i < len; i++) {
2277bec1dd5SJonathan Chen 		if (tupledata[i] == '\0')
2280db7e66cSJonathan Chen 			printf(" | ");
2297bec1dd5SJonathan Chen 		else if (tupledata[i] == 0xff)
2300db7e66cSJonathan Chen 			break;
2310db7e66cSJonathan Chen 		else
2327bec1dd5SJonathan Chen 			printf("%c", tupledata[i]);
2330db7e66cSJonathan Chen 	}
2340db7e66cSJonathan Chen 	printf("\n");
2350db7e66cSJonathan Chen 	return 0;
2360db7e66cSJonathan Chen }
2370db7e66cSJonathan Chen 
2380db7e66cSJonathan Chen DECODE_PROTOTYPE(funcid)
2390db7e66cSJonathan Chen {
2400db7e66cSJonathan Chen 	int i;
2410db7e66cSJonathan Chen 	int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
2420db7e66cSJonathan Chen 
2430db7e66cSJonathan Chen 	printf("Functions: ");
2440db7e66cSJonathan Chen 	for (i = 0; i < len; i++) {
2457bec1dd5SJonathan Chen 		if (tupledata[i] < numnames)
2467bec1dd5SJonathan Chen 			printf("%s", funcnames[tupledata[i]]);
2470db7e66cSJonathan Chen 		else
2487bec1dd5SJonathan Chen 			printf("Unknown(%d)", tupledata[i]);
249255b159fSJonathan Chen 		if (i < len-1)
250255b159fSJonathan Chen 			printf(", ");
2510db7e66cSJonathan Chen 	}
2520db7e66cSJonathan Chen 	printf("\n");
2530db7e66cSJonathan Chen 	return 0;
2540db7e66cSJonathan Chen }
2550db7e66cSJonathan Chen 
2560db7e66cSJonathan Chen DECODE_PROTOTYPE(manfid)
2570db7e66cSJonathan Chen {
2580db7e66cSJonathan Chen 	int i;
2590db7e66cSJonathan Chen 	printf("Manufacturer ID: ");
2600db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2617bec1dd5SJonathan Chen 		printf("%02x", tupledata[i]);
2620db7e66cSJonathan Chen 	printf("\n");
2630db7e66cSJonathan Chen 	return 0;
2640db7e66cSJonathan Chen }
2650db7e66cSJonathan Chen 
2660db7e66cSJonathan Chen DECODE_PROTOTYPE(funce)
2670db7e66cSJonathan Chen {
2680db7e66cSJonathan Chen 	int i;
2690db7e66cSJonathan Chen 	printf("Function Extension: ");
2700db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2717bec1dd5SJonathan Chen 		printf("%02x", tupledata[i]);
2720db7e66cSJonathan Chen 	printf("\n");
2730db7e66cSJonathan Chen 	return 0;
2740db7e66cSJonathan Chen }
2750db7e66cSJonathan Chen 
2760db7e66cSJonathan Chen DECODE_PROTOTYPE(bar)
2770db7e66cSJonathan Chen {
2780db7e66cSJonathan Chen 	if (len != 6) {
2790db7e66cSJonathan Chen 		printf("*** ERROR *** BAR length not 6 (%d)\n", len);
2800db7e66cSJonathan Chen 		return EINVAL;
2810db7e66cSJonathan Chen 	} else {
28263fa9f4cSJonathan Chen 		struct cardbus_devinfo *dinfo = device_get_ivars(child);
2830db7e66cSJonathan Chen 		int type;
2840db7e66cSJonathan Chen 		int reg;
2850db7e66cSJonathan Chen 		u_int32_t bar;
2860db7e66cSJonathan Chen 
2877bec1dd5SJonathan Chen 		reg = *(u_int16_t*)tupledata;
2887bec1dd5SJonathan Chen 		len = *(u_int32_t*)(tupledata + 2);
2890db7e66cSJonathan Chen 		if (reg & TPL_BAR_REG_AS) {
2900db7e66cSJonathan Chen 			type = SYS_RES_IOPORT;
2910db7e66cSJonathan Chen 		} else {
2920db7e66cSJonathan Chen 			type = SYS_RES_MEMORY;
2930db7e66cSJonathan Chen 		}
2940db7e66cSJonathan Chen 		bar = (reg & TPL_BAR_REG_ASI_MASK) - 1;
295255b159fSJonathan Chen 		if (bar < 0 || bar > 5 ||
296255b159fSJonathan Chen 		    (type == SYS_RES_IOPORT && bar == 5)) {
297255b159fSJonathan Chen 			device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n",
2980db7e66cSJonathan Chen 			    reg, bar);
2990c95c705SJonathan Chen 			return 0;
3000db7e66cSJonathan Chen 		}
3010db7e66cSJonathan Chen 		bar = CARDBUS_BASE0_REG + bar * 4;
30263fa9f4cSJonathan Chen 		if (type == SYS_RES_MEMORY) {
30363fa9f4cSJonathan Chen 			if (bar & TPL_BAR_REG_PREFETCHABLE)
30463fa9f4cSJonathan Chen 				dinfo->mprefetchable |= BARBIT(bar);
30563fa9f4cSJonathan Chen 			if (bar & TPL_BAR_REG_BELOW1MB)
30663fa9f4cSJonathan Chen 				dinfo->mbelow1mb |= BARBIT(bar);
30763fa9f4cSJonathan Chen 		} else if (type == SYS_RES_IOPORT) {
30863fa9f4cSJonathan Chen 			if (bar & TPL_BAR_REG_BELOW1MB)
30963fa9f4cSJonathan Chen 				dinfo->ibelow1mb |= BARBIT(bar);
3100db7e66cSJonathan Chen 		}
31163fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, "
31263fa9f4cSJonathan Chen 		    "len=%04x%s%s\n",
31363fa9f4cSJonathan Chen 		    (type==SYS_RES_MEMORY)?"MEM":"IO", bar, len,
31463fa9f4cSJonathan Chen 		    (type==SYS_RES_MEMORY&&dinfo->mprefetchable&BARBIT(bar))?
31563fa9f4cSJonathan Chen 		    " (Prefetchable)":"",
31663fa9f4cSJonathan Chen 		    type==SYS_RES_MEMORY?
31763fa9f4cSJonathan Chen 		    ((dinfo->mbelow1mb&BARBIT(bar))?" (Below 1Mb)":"")
31863fa9f4cSJonathan Chen 		    :(dinfo->ibelow1mb&BARBIT(bar))?" (Below 1Mb)":""
31963fa9f4cSJonathan Chen 		    ));
32063fa9f4cSJonathan Chen 
32163fa9f4cSJonathan Chen 		resource_list_add(&dinfo->resources, type, bar, 0UL, ~0UL, len);
3220db7e66cSJonathan Chen 	}
3230db7e66cSJonathan Chen 	return 0;
3240db7e66cSJonathan Chen }
3250db7e66cSJonathan Chen 
3260db7e66cSJonathan Chen DECODE_PROTOTYPE(unhandled)
3270db7e66cSJonathan Chen {
3280db7e66cSJonathan Chen 	printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
3290db7e66cSJonathan Chen 	return -1;
3300db7e66cSJonathan Chen }
3310db7e66cSJonathan Chen 
3320db7e66cSJonathan Chen DECODE_PROTOTYPE(end)
3330db7e66cSJonathan Chen {
3340c95c705SJonathan Chen 	printf("CIS reading done\n");
3357bec1dd5SJonathan Chen 	return 0;
3360db7e66cSJonathan Chen }
3370db7e66cSJonathan Chen 
338255b159fSJonathan Chen /*
339255b159fSJonathan Chen  * Functions to read the a tuple from the card
340255b159fSJonathan Chen  */
341255b159fSJonathan Chen 
3420db7e66cSJonathan Chen static int
34363fa9f4cSJonathan Chen cardbus_read_tuple_conf(device_t cbdev, device_t child, u_int32_t start,
344255b159fSJonathan Chen     u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata)
3457bec1dd5SJonathan Chen {
3467bec1dd5SJonathan Chen 	int i, j;
3477bec1dd5SJonathan Chen 	u_int32_t e;
34849f158ccSJonathan Chen 	u_int32_t loc;
3497bec1dd5SJonathan Chen 
35063fa9f4cSJonathan Chen 	loc = start + *off;
35149f158ccSJonathan Chen 
35249f158ccSJonathan Chen 	e = pci_read_config(child, loc - loc % 4, 4);
35349f158ccSJonathan Chen 	for (j = loc % 4; j > 0; j--)
3547bec1dd5SJonathan Chen 		e >>= 8;
3557bec1dd5SJonathan Chen 	*len = 0;
35649f158ccSJonathan Chen 	for (i = loc, j = -2; j < *len; j++, i++) {
3577bec1dd5SJonathan Chen 		if (i % 4 == 0)
3587bec1dd5SJonathan Chen 			e = pci_read_config(child, i, 4);
3597bec1dd5SJonathan Chen 		if (j == -2)
3607bec1dd5SJonathan Chen 			*tupleid = 0xff & e;
3617bec1dd5SJonathan Chen 		else if (j == -1)
3627bec1dd5SJonathan Chen 			*len = 0xff & e;
3637bec1dd5SJonathan Chen 		else
3647bec1dd5SJonathan Chen 			tupledata[j] = 0xff & e;
3657bec1dd5SJonathan Chen 		e >>= 8;
3667bec1dd5SJonathan Chen 	}
3677bec1dd5SJonathan Chen 	*off += *len + 2;
3687bec1dd5SJonathan Chen 	return 0;
3697bec1dd5SJonathan Chen }
3707bec1dd5SJonathan Chen 
3717bec1dd5SJonathan Chen static int
37263fa9f4cSJonathan Chen cardbus_read_tuple_mem(device_t cbdev, struct resource *res, u_int32_t start,
373255b159fSJonathan Chen     u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata)
3740db7e66cSJonathan Chen {
37563fa9f4cSJonathan Chen 	bus_space_tag_t bt;
37663fa9f4cSJonathan Chen 	bus_space_handle_t bh;
37763fa9f4cSJonathan Chen 	int ret;
3780db7e66cSJonathan Chen 
37963fa9f4cSJonathan Chen 	bt = rman_get_bustag(res);
38063fa9f4cSJonathan Chen 	bh = rman_get_bushandle(res);
3810db7e66cSJonathan Chen 
38263fa9f4cSJonathan Chen 	*tupleid = bus_space_read_1(bt, bh, start + *off);
38363fa9f4cSJonathan Chen 	*len = bus_space_read_1(bt, bh, start + *off + 1);
38463fa9f4cSJonathan Chen 	bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
38563fa9f4cSJonathan Chen 	ret = 0;
38663fa9f4cSJonathan Chen 	*off += *len + 2;
38763fa9f4cSJonathan Chen 	return ret;
3880db7e66cSJonathan Chen }
38963fa9f4cSJonathan Chen 
39063fa9f4cSJonathan Chen static int
39163fa9f4cSJonathan Chen cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
39263fa9f4cSJonathan Chen     u_int32_t start, u_int32_t *off, int *tupleid, int *len,
39363fa9f4cSJonathan Chen     u_int8_t *tupledata)
39463fa9f4cSJonathan Chen {
39563fa9f4cSJonathan Chen 	if (res == (struct resource*)~0UL) {
39663fa9f4cSJonathan Chen 		return cardbus_read_tuple_conf(cbdev, child, start, off,
39763fa9f4cSJonathan Chen 		    tupleid, len, tupledata);
39863fa9f4cSJonathan Chen 	} else {
39963fa9f4cSJonathan Chen 		return cardbus_read_tuple_mem(cbdev, res, start, off,
40063fa9f4cSJonathan Chen 		    tupleid, len, tupledata);
40163fa9f4cSJonathan Chen 	}
40263fa9f4cSJonathan Chen }
40363fa9f4cSJonathan Chen 
40463fa9f4cSJonathan Chen static void
40563fa9f4cSJonathan Chen cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
40663fa9f4cSJonathan Chen     struct resource *res)
40763fa9f4cSJonathan Chen {
40863fa9f4cSJonathan Chen 	if (res != (struct resource*)~0UL) {
40963fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
41063fa9f4cSJonathan Chen 		pci_write_config(child, rid, 0, 4);
41163fa9f4cSJonathan Chen 		PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
41263fa9f4cSJonathan Chen 	}
41363fa9f4cSJonathan Chen }
41463fa9f4cSJonathan Chen 
41563fa9f4cSJonathan Chen static struct resource *
41663fa9f4cSJonathan Chen cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start,
41763fa9f4cSJonathan Chen     int *rid)
41863fa9f4cSJonathan Chen {
41963fa9f4cSJonathan Chen 	u_int32_t testval;
42063fa9f4cSJonathan Chen 	u_int32_t size;
42163fa9f4cSJonathan Chen 	struct resource *res;
42263fa9f4cSJonathan Chen 
42363fa9f4cSJonathan Chen 	switch (CARDBUS_CIS_SPACE(*start)) {
42463fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_TUPLE:
42563fa9f4cSJonathan Chen 		/* CIS in tuple space need no initialization */
42663fa9f4cSJonathan Chen 		return (struct resource*)~0UL;
42763fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR0:
42863fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR1:
42963fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR2:
43063fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR3:
43163fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR4:
43263fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR5:
43363fa9f4cSJonathan Chen 		*rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
43463fa9f4cSJonathan Chen 		pci_write_config(child, *rid, ~0UL, 4);
43563fa9f4cSJonathan Chen 		break;
43663fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_ROM:
43763fa9f4cSJonathan Chen 		*rid = CARDBUS_ROM_REG;
43863fa9f4cSJonathan Chen 		pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4);
43963fa9f4cSJonathan Chen 		break;
44063fa9f4cSJonathan Chen 	default:
44163fa9f4cSJonathan Chen 		device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
44263fa9f4cSJonathan Chen 		    CARDBUS_CIS_SPACE(*start));
44363fa9f4cSJonathan Chen 		return NULL;
44463fa9f4cSJonathan Chen 	}
44563fa9f4cSJonathan Chen 
44663fa9f4cSJonathan Chen 	/* figure out how much space we need */
44763fa9f4cSJonathan Chen 	testval = pci_read_config(child, *rid, 4);
44863fa9f4cSJonathan Chen 	if (testval & 1) {
44963fa9f4cSJonathan Chen 		device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
45063fa9f4cSJonathan Chen 		return NULL;
45163fa9f4cSJonathan Chen 	}
45263fa9f4cSJonathan Chen 	size = CARDBUS_MAPREG_MEM_SIZE(testval);
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");
46163fa9f4cSJonathan Chen 		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 		int imagenum;
47463fa9f4cSJonathan Chen 		u_int32_t imagesize;
47563fa9f4cSJonathan Chen 		int mystart = 0;
47663fa9f4cSJonathan Chen 		int romnum = 0;
47763fa9f4cSJonathan Chen 		int dataptr;
47863fa9f4cSJonathan Chen 
47963fa9f4cSJonathan Chen 		bt = rman_get_bustag(res);
48063fa9f4cSJonathan Chen 		bh = rman_get_bushandle(res);
48163fa9f4cSJonathan Chen 
48263fa9f4cSJonathan Chen 		imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
48363fa9f4cSJonathan Chen 		for (romnum = 0;; romnum++) {
48463fa9f4cSJonathan Chen 			if (bus_space_read_2(bt, bh,
48563fa9f4cSJonathan Chen 			    mystart+CARDBUS_EXROM_SIGNATURE) != 0xaa55) {
48663fa9f4cSJonathan Chen 				device_printf(cbdev, "Bad header in rom %d: "
48763fa9f4cSJonathan Chen 				    "[%x] %04x\n", romnum, mystart +
48863fa9f4cSJonathan Chen 				    CARDBUS_EXROM_SIGNATURE,
48963fa9f4cSJonathan Chen 				    bus_space_read_2(bt, bh,
49063fa9f4cSJonathan Chen 				    mystart+CARDBUS_EXROM_SIGNATURE));
49163fa9f4cSJonathan Chen 				bus_release_resource(cbdev, SYS_RES_MEMORY,
49263fa9f4cSJonathan Chen 				    *rid, res);
49363fa9f4cSJonathan Chen 				*rid = 0;
49463fa9f4cSJonathan Chen 				return NULL;
49563fa9f4cSJonathan Chen 			}
49663fa9f4cSJonathan Chen 			dataptr = mystart + bus_space_read_2(bt, bh,
49763fa9f4cSJonathan Chen 			    mystart + CARDBUS_EXROM_DATA_PTR);
49863fa9f4cSJonathan Chen 			imagesize = bus_space_read_2(bt, bh,
49963fa9f4cSJonathan Chen 			    dataptr + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
5000db7e66cSJonathan Chen 
5017bec1dd5SJonathan Chen 			if (imagesize == 0) {
5020db7e66cSJonathan Chen 				/*
5030db7e66cSJonathan Chen 				 * XXX some ROMs seem to have this as zero,
5040db7e66cSJonathan Chen 				 * can we assume this means 1 block?
5050db7e66cSJonathan Chen 				 */
5060db7e66cSJonathan Chen 				imagesize = 1;
5077bec1dd5SJonathan Chen 			}
5080db7e66cSJonathan Chen 			imagesize <<= 9;
5090db7e66cSJonathan Chen 
51063fa9f4cSJonathan Chen 			if (romnum == imagenum)
51163fa9f4cSJonathan Chen 				break;
51263fa9f4cSJonathan Chen 			if ((bus_space_read_1(bt, bh, mystart +
51363fa9f4cSJonathan Chen 			    CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0) {
51463fa9f4cSJonathan Chen 				device_printf(cbdev, "Cannot read CIS: "
51563fa9f4cSJonathan Chen 				    "Not enough images of rom\n");
51663fa9f4cSJonathan Chen 				return NULL;
5170db7e66cSJonathan Chen 			}
51863fa9f4cSJonathan Chen 			mystart += imagesize;
5190db7e66cSJonathan Chen 		}
52063fa9f4cSJonathan Chen 		*start = mystart + CARDBUS_CIS_ADDR(*start);
5210db7e66cSJonathan Chen 	} else {
52263fa9f4cSJonathan Chen 		*start = CARDBUS_CIS_SPACE(*start);
5230db7e66cSJonathan Chen 	}
52463fa9f4cSJonathan Chen 	return res;
5257bec1dd5SJonathan Chen }
5267bec1dd5SJonathan Chen 
527255b159fSJonathan Chen /*
528255b159fSJonathan Chen  * Dispatch the right handler function per tuple
529255b159fSJonathan Chen  */
530255b159fSJonathan Chen 
5317bec1dd5SJonathan Chen static int
532255b159fSJonathan Chen decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
53363fa9f4cSJonathan Chen     u_int8_t *tupledata, u_int32_t start, u_int32_t *off,
5340c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
5357bec1dd5SJonathan Chen {
5367bec1dd5SJonathan Chen 	int i;
5370c95c705SJonathan Chen 	for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
5380c95c705SJonathan Chen 		if (tupleid == callbacks[i].id)
539255b159fSJonathan Chen 			return callbacks[i].func(cbdev, child, tupleid, len,
540255b159fSJonathan Chen 			    tupledata, start, off, &callbacks[i]);
5417bec1dd5SJonathan Chen 	}
5427bec1dd5SJonathan Chen 
54349f158ccSJonathan Chen 	if (tupleid < CISTPL_CUSTOMSTART) {
544255b159fSJonathan Chen 		device_printf(cbdev, "Undefined tuple encountered, "
545255b159fSJonathan Chen 		    "CIS parsing terminated\n");
54649f158ccSJonathan Chen 		return EINVAL;
54749f158ccSJonathan Chen 	}
548255b159fSJonathan Chen 	return callbacks[i].func(cbdev, child, tupleid, len,
549255b159fSJonathan Chen 	    tupledata, start, off, NULL);
5500db7e66cSJonathan Chen }
5510db7e66cSJonathan Chen 
5520c95c705SJonathan Chen static int
553255b159fSJonathan Chen cardbus_parse_cis(device_t cbdev, device_t child,
5540c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
5550db7e66cSJonathan Chen {
5560db7e66cSJonathan Chen 	u_int8_t tupledata[MAXTUPLESIZE];
5577bec1dd5SJonathan Chen 	int tupleid;
5587bec1dd5SJonathan Chen 	int len;
5597bec1dd5SJonathan Chen 	int expect_linktarget;
56049f158ccSJonathan Chen 	u_int32_t start, off;
56163fa9f4cSJonathan Chen 	struct resource *res;
56263fa9f4cSJonathan Chen 	int rid;
5630db7e66cSJonathan Chen 
5640db7e66cSJonathan Chen 	bzero(tupledata, MAXTUPLESIZE);
5657bec1dd5SJonathan Chen 	expect_linktarget = TRUE;
56649f158ccSJonathan Chen 	start = pci_read_config(child, CARDBUS_CIS_REG, 4);
56749f158ccSJonathan Chen 	off = 0;
56863fa9f4cSJonathan Chen 	res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
56963fa9f4cSJonathan Chen 	if (res == NULL)
57063fa9f4cSJonathan Chen 		return ENXIO;
5717bec1dd5SJonathan Chen 	do {
57263fa9f4cSJonathan Chen 		if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
57363fa9f4cSJonathan Chen 		    &tupleid, &len, tupledata)) {
57463fa9f4cSJonathan Chen 			device_printf(cbdev, "Failed to read CIS.\n");
57563fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
57663fa9f4cSJonathan Chen 			return ENXIO;
57763fa9f4cSJonathan Chen 		}
5787bec1dd5SJonathan Chen 
5797bec1dd5SJonathan Chen 		if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
580255b159fSJonathan Chen 			device_printf(cbdev, "Expecting link target, got 0x%x\n",
5817bec1dd5SJonathan Chen 			    tupleid);
58263fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
5837bec1dd5SJonathan Chen 			return EINVAL;
5847bec1dd5SJonathan Chen 		}
585255b159fSJonathan Chen 		expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
58663fa9f4cSJonathan Chen 		    tupledata, start, &off, callbacks);
58763fa9f4cSJonathan Chen 		if (expect_linktarget != 0) {
58863fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
5897bec1dd5SJonathan Chen 			return expect_linktarget;
59063fa9f4cSJonathan Chen 		}
5917bec1dd5SJonathan Chen 	} while (tupleid != CISTPL_END);
59263fa9f4cSJonathan Chen 	cardbus_read_tuple_finish(cbdev, child, rid, res);
5937bec1dd5SJonathan Chen 	return 0;
5940db7e66cSJonathan Chen }
5950db7e66cSJonathan Chen 
59663fa9f4cSJonathan Chen static int
59763fa9f4cSJonathan Chen barsort(const void *a, const void *b)
59863fa9f4cSJonathan Chen {
59963fa9f4cSJonathan Chen 	return (*(const struct resource_list_entry **)b)->count -
60063fa9f4cSJonathan Chen 	    (*(const struct resource_list_entry **)a)->count;
60163fa9f4cSJonathan Chen }
60263fa9f4cSJonathan Chen 
60363fa9f4cSJonathan Chen static int
60463fa9f4cSJonathan Chen cardbus_alloc_resources(device_t cbdev, device_t child)
60563fa9f4cSJonathan Chen {
60663fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
60763fa9f4cSJonathan Chen 	int count;
60863fa9f4cSJonathan Chen 	struct resource_list_entry *rle;
60963fa9f4cSJonathan Chen 	struct resource_list_entry **barlist;
61063fa9f4cSJonathan Chen 	int tmp;
61163fa9f4cSJonathan Chen 	u_int32_t mem_psize = 0, mem_nsize = 0, io_size = 0;
61263fa9f4cSJonathan Chen 	struct resource *res;
61363fa9f4cSJonathan Chen 	u_int32_t start,end;
61463fa9f4cSJonathan Chen 	int rid, flags;
61563fa9f4cSJonathan Chen 
61663fa9f4cSJonathan Chen 	count = 0;
61763fa9f4cSJonathan Chen 	SLIST_FOREACH(rle, &dinfo->resources, link) {
61863fa9f4cSJonathan Chen 		count++;
61963fa9f4cSJonathan Chen 	}
62063fa9f4cSJonathan Chen 	if (count == 0)
62163fa9f4cSJonathan Chen 		return 0;
62263fa9f4cSJonathan Chen 	barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF,
62363fa9f4cSJonathan Chen 	    M_WAITOK);
62463fa9f4cSJonathan Chen 	count = 0;
62563fa9f4cSJonathan Chen 	SLIST_FOREACH(rle, &dinfo->resources, link) {
62663fa9f4cSJonathan Chen 		barlist[count] = rle;
62763fa9f4cSJonathan Chen 		if (rle->type == SYS_RES_IOPORT) {
62863fa9f4cSJonathan Chen 			io_size += rle->count;
62963fa9f4cSJonathan Chen 		} else if (rle->type == SYS_RES_MEMORY) {
63063fa9f4cSJonathan Chen 			if (dinfo->mprefetchable & BARBIT(rle->rid))
63163fa9f4cSJonathan Chen 				mem_psize += rle->count;
63263fa9f4cSJonathan Chen 			else
63363fa9f4cSJonathan Chen 				mem_nsize += rle->count;
63463fa9f4cSJonathan Chen 		}
63563fa9f4cSJonathan Chen 		count++;
63663fa9f4cSJonathan Chen 	}
63763fa9f4cSJonathan Chen 
63863fa9f4cSJonathan Chen 	/*
63963fa9f4cSJonathan Chen 	 * We want to allocate the largest resource first, so that our
64063fa9f4cSJonathan Chen 	 * allocated memory is packed.
64163fa9f4cSJonathan Chen 	 */
64263fa9f4cSJonathan Chen 	qsort(barlist, count, sizeof(struct resource_list_entry*), barsort);
64363fa9f4cSJonathan Chen 
64463fa9f4cSJonathan Chen 	/* Allocate prefetchable memory */
64563fa9f4cSJonathan Chen 	flags = 0;
64663fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
64763fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
64863fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_MEMORY &&
64963fa9f4cSJonathan Chen 		    dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) {
65063fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
65163fa9f4cSJonathan Chen 			break;
65263fa9f4cSJonathan Chen 		}
65363fa9f4cSJonathan Chen 	}
65463fa9f4cSJonathan Chen 	if (flags > 0) { /* If any prefetchable memory is requested... */
65563fa9f4cSJonathan Chen 		/*
65663fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
65763fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
65863fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
65963fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
66063fa9f4cSJonathan Chen 		 * within the window.
66163fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
66263fa9f4cSJonathan Chen 		 */
66363fa9f4cSJonathan Chen 		rid = 0;
66463fa9f4cSJonathan Chen 		res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
66563fa9f4cSJonathan Chen 		    (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL,
66663fa9f4cSJonathan Chen 		    mem_psize, flags);
66763fa9f4cSJonathan Chen 		start = rman_get_start(res);
66863fa9f4cSJonathan Chen 		end = rman_get_end(res);
66963fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end));
67063fa9f4cSJonathan Chen 		/*
67163fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
67263fa9f4cSJonathan Chen 		 * out piece by piece.
67363fa9f4cSJonathan Chen 		 */
67463fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
67563fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
67663fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
67763fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_MEMORY &&
67863fa9f4cSJonathan Chen 			    dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) {
67963fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
68063fa9f4cSJonathan Chen 				    barlist[tmp]->type,
68163fa9f4cSJonathan Chen 				    &barlist[tmp]->rid, start, end,
68263fa9f4cSJonathan Chen 				    barlist[tmp]->count,
68363fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
68463fa9f4cSJonathan Chen 				    barlist[tmp]->count));
68563fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
68663fa9f4cSJonathan Chen 					mem_nsize += barlist[tmp]->count;
68763fa9f4cSJonathan Chen 					dinfo->mprefetchable &=
68863fa9f4cSJonathan Chen 					    ~BARBIT(barlist[tmp]->rid);
68963fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
69063fa9f4cSJonathan Chen 					    "prefetchable memory, will try as "
69163fa9f4cSJonathan Chen 					    "non-prefetchable.\n"));
69263fa9f4cSJonathan Chen 				} else {
69363fa9f4cSJonathan Chen 					barlist[tmp]->start =
69463fa9f4cSJonathan Chen 					    rman_get_start(barlist[tmp]->res);
69563fa9f4cSJonathan Chen 					barlist[tmp]->end =
69663fa9f4cSJonathan Chen 					    rman_get_end(barlist[tmp]->res);
69763fa9f4cSJonathan Chen 					pci_write_config(child,
69863fa9f4cSJonathan Chen 					    barlist[tmp]->rid,
69963fa9f4cSJonathan Chen 					    barlist[tmp]->start, 4);
70063fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Prefetchable memory "
70163fa9f4cSJonathan Chen 					    "rid=%x at %lx-%lx\n",
70263fa9f4cSJonathan Chen 					    barlist[tmp]->rid,
70363fa9f4cSJonathan Chen 					    barlist[tmp]->start,
70463fa9f4cSJonathan Chen 					    barlist[tmp]->end));
70563fa9f4cSJonathan Chen 				}
70663fa9f4cSJonathan Chen 			}
70763fa9f4cSJonathan Chen 		}
70863fa9f4cSJonathan Chen 	}
70963fa9f4cSJonathan Chen 
71063fa9f4cSJonathan Chen 	/* Allocate non-prefetchable memory */
71163fa9f4cSJonathan Chen 	flags = 0;
71263fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
71363fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
71463fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_MEMORY) {
71563fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
71663fa9f4cSJonathan Chen 			break;
71763fa9f4cSJonathan Chen 		}
71863fa9f4cSJonathan Chen 	}
71963fa9f4cSJonathan Chen 	if (flags > 0) { /* If any non-prefetchable memory is requested... */
72063fa9f4cSJonathan Chen 		/*
72163fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
72263fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
72363fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
72463fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
72563fa9f4cSJonathan Chen 		 * within the window.
72663fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
72763fa9f4cSJonathan Chen 		 */
72863fa9f4cSJonathan Chen 		rid = 0;
72963fa9f4cSJonathan Chen 		res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
73063fa9f4cSJonathan Chen 		    ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL,
73163fa9f4cSJonathan Chen 		    mem_nsize, flags);
73263fa9f4cSJonathan Chen 		start = rman_get_start(res);
73363fa9f4cSJonathan Chen 		end = rman_get_end(res);
73463fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n",
73563fa9f4cSJonathan Chen 		    start, end));
73663fa9f4cSJonathan Chen 		/*
73763fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
73863fa9f4cSJonathan Chen 		 * out piece by piece.
73963fa9f4cSJonathan Chen 		 */
74063fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
74163fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
74263fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
74363fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_MEMORY) {
74463fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
74563fa9f4cSJonathan Chen 				    barlist[tmp]->type, &barlist[tmp]->rid,
74663fa9f4cSJonathan Chen 				    start, end, barlist[tmp]->count,
74763fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
74863fa9f4cSJonathan Chen 				    barlist[tmp]->count));
74963fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
75063fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
75163fa9f4cSJonathan Chen 					    "memory for cardbus device\n"));
75263fa9f4cSJonathan Chen 					return ENOMEM;
75363fa9f4cSJonathan Chen 				}
75463fa9f4cSJonathan Chen 				barlist[tmp]->start =
75563fa9f4cSJonathan Chen 				    rman_get_start(barlist[tmp]->res);
75663fa9f4cSJonathan Chen 				barlist[tmp]->end = rman_get_end(
75763fa9f4cSJonathan Chen 					barlist[tmp]->res);
75863fa9f4cSJonathan Chen 				pci_write_config(child, barlist[tmp]->rid,
75963fa9f4cSJonathan Chen 				    barlist[tmp]->start, 4);
76063fa9f4cSJonathan Chen 				DEVPRINTF((cbdev, "Non-prefetchable memory "
76163fa9f4cSJonathan Chen 				    "rid=%x at %lx-%lx (%lx)\n",
76263fa9f4cSJonathan Chen 				    barlist[tmp]->rid, barlist[tmp]->start,
76363fa9f4cSJonathan Chen 				    barlist[tmp]->end, barlist[tmp]->count));
76463fa9f4cSJonathan Chen 			}
76563fa9f4cSJonathan Chen 		}
76663fa9f4cSJonathan Chen 	}
76763fa9f4cSJonathan Chen 
76863fa9f4cSJonathan Chen 	/* Allocate IO ports */
76963fa9f4cSJonathan Chen 	flags = 0;
77063fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
77163fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
77263fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_IOPORT) {
77363fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
77463fa9f4cSJonathan Chen 			break;
77563fa9f4cSJonathan Chen 		}
77663fa9f4cSJonathan Chen 	}
77763fa9f4cSJonathan Chen 	if (flags > 0) { /* If any IO port is requested... */
77863fa9f4cSJonathan Chen 		/*
77963fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
78063fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
78163fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
78263fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
78363fa9f4cSJonathan Chen 		 * within the window.
78463fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
78563fa9f4cSJonathan Chen 		 */
78663fa9f4cSJonathan Chen 		rid = 0;
78763fa9f4cSJonathan Chen 		res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0,
78863fa9f4cSJonathan Chen 		    (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags);
78963fa9f4cSJonathan Chen 		start = rman_get_start(res);
79063fa9f4cSJonathan Chen 		end = rman_get_end(res);
79163fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end));
79263fa9f4cSJonathan Chen 		/*
79363fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
79463fa9f4cSJonathan Chen 		 * out piece by piece.
79563fa9f4cSJonathan Chen 		 */
79663fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res);
79763fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
79863fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
79963fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_IOPORT) {
80063fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
80163fa9f4cSJonathan Chen 				    barlist[tmp]->type, &barlist[tmp]->rid,
80263fa9f4cSJonathan Chen 				    start, end, barlist[tmp]->count,
80363fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
80463fa9f4cSJonathan Chen 				    barlist[tmp]->count));
80563fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
80663fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
80763fa9f4cSJonathan Chen 					    "IO port for cardbus device\n"));
80863fa9f4cSJonathan Chen 					return ENOMEM;
80963fa9f4cSJonathan Chen 				}
81063fa9f4cSJonathan Chen 				barlist[tmp]->start =
81163fa9f4cSJonathan Chen 				    rman_get_start(barlist[tmp]->res);
81263fa9f4cSJonathan Chen 				barlist[tmp]->end =
81363fa9f4cSJonathan Chen 				    rman_get_end(barlist[tmp]->res);
81463fa9f4cSJonathan Chen 			pci_write_config(child, barlist[tmp]->rid,
81563fa9f4cSJonathan Chen 			    barlist[tmp]->start, 4);
81663fa9f4cSJonathan Chen 			DEVPRINTF((cbdev, "IO port rid=%x at %lx-%lx\n",
81763fa9f4cSJonathan Chen 			    barlist[tmp]->rid, barlist[tmp]->start,
81863fa9f4cSJonathan Chen 			    barlist[tmp]->end));
81963fa9f4cSJonathan Chen 			}
82063fa9f4cSJonathan Chen 		}
82163fa9f4cSJonathan Chen 	}
82263fa9f4cSJonathan Chen 
82363fa9f4cSJonathan Chen 	/* Allocate IRQ */
82463fa9f4cSJonathan Chen 	/* XXX: Search CIS for IRQ description */
82563fa9f4cSJonathan Chen 	rid = 0;
82663fa9f4cSJonathan Chen 	res = bus_alloc_resource(cbdev, SYS_RES_IRQ, &rid, 0, ~0UL, 1,
82763fa9f4cSJonathan Chen 	    RF_SHAREABLE);
82863fa9f4cSJonathan Chen 	resource_list_add(&dinfo->resources, SYS_RES_IRQ, rid,
82963fa9f4cSJonathan Chen 	    rman_get_start(res), rman_get_end(res), 1);
83063fa9f4cSJonathan Chen 	rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid);
83163fa9f4cSJonathan Chen 	rle->res = res;
83263fa9f4cSJonathan Chen 	dinfo->cfg.intline = rman_get_start(res);
83363fa9f4cSJonathan Chen 	pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1);
83463fa9f4cSJonathan Chen 
83563fa9f4cSJonathan Chen 	return 0;
83663fa9f4cSJonathan Chen }
83763fa9f4cSJonathan Chen 
83863fa9f4cSJonathan Chen /*
83963fa9f4cSJonathan Chen  * Adding a memory/io resource (sans CIS)
84063fa9f4cSJonathan Chen  */
84163fa9f4cSJonathan Chen 
84263fa9f4cSJonathan Chen static void
84363fa9f4cSJonathan Chen cardbus_add_map(device_t cbdev, device_t child, int reg)
84463fa9f4cSJonathan Chen {
84563fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
84663fa9f4cSJonathan Chen 	struct resource_list_entry *rle;
84763fa9f4cSJonathan Chen 	u_int32_t size;
84863fa9f4cSJonathan Chen 	u_int32_t testval;
84963fa9f4cSJonathan Chen 	int type;
85063fa9f4cSJonathan Chen 
85163fa9f4cSJonathan Chen 	SLIST_FOREACH(rle, &dinfo->resources, link) {
85263fa9f4cSJonathan Chen 		if (rle->rid == reg)
85363fa9f4cSJonathan Chen 			return;
85463fa9f4cSJonathan Chen 	}
85563fa9f4cSJonathan Chen 
85663fa9f4cSJonathan Chen 	if (reg == CARDBUS_ROM_REG)
85763fa9f4cSJonathan Chen 		testval = CARDBUS_ROM_ADDRMASK;
85863fa9f4cSJonathan Chen 	else
85963fa9f4cSJonathan Chen 		testval = ~0;
86063fa9f4cSJonathan Chen 
86163fa9f4cSJonathan Chen 	pci_write_config(child, reg, testval, 4);
86263fa9f4cSJonathan Chen 	testval = pci_read_config(child, reg, 4);
86363fa9f4cSJonathan Chen 
86463fa9f4cSJonathan Chen 	if (testval == ~0 || testval == 0)
86563fa9f4cSJonathan Chen 		return;
86663fa9f4cSJonathan Chen 
86763fa9f4cSJonathan Chen 	if ((testval & 1) == 0)
86863fa9f4cSJonathan Chen 		type = SYS_RES_MEMORY;
86963fa9f4cSJonathan Chen 	else
87063fa9f4cSJonathan Chen 		type = SYS_RES_IOPORT;
87163fa9f4cSJonathan Chen 
87263fa9f4cSJonathan Chen 	size = CARDBUS_MAPREG_MEM_SIZE(testval);
87363fa9f4cSJonathan Chen 	device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n",
87463fa9f4cSJonathan Chen 	    reg, size);
87563fa9f4cSJonathan Chen 	resource_list_add(&dinfo->resources, type, reg, 0UL, ~0UL, size);
87663fa9f4cSJonathan Chen }
87763fa9f4cSJonathan Chen 
87863fa9f4cSJonathan Chen static void
87963fa9f4cSJonathan Chen cardbus_pickup_maps(device_t cbdev, device_t child)
88063fa9f4cSJonathan Chen {
88163fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
88263fa9f4cSJonathan Chen 	struct cardbus_quirk *q;
88363fa9f4cSJonathan Chen 	int reg;
88463fa9f4cSJonathan Chen 
88563fa9f4cSJonathan Chen 	/*
88663fa9f4cSJonathan Chen 	 * Try to pick up any resources that was not specified in CIS.
88763fa9f4cSJonathan Chen 	 * Some devices (eg, 3c656) does not list all resources required by
88863fa9f4cSJonathan Chen 	 * the driver in its CIS.
88963fa9f4cSJonathan Chen 	 * XXX: should we do this or use quirks?
89063fa9f4cSJonathan Chen 	 */
89163fa9f4cSJonathan Chen 	for (reg = 0; reg < dinfo->cfg.nummaps; reg++) {
89263fa9f4cSJonathan Chen 		cardbus_add_map(cbdev, child, PCIR_MAPS + reg * 4);
89363fa9f4cSJonathan Chen 	}
89463fa9f4cSJonathan Chen 
89563fa9f4cSJonathan Chen 	for (q = &cardbus_quirks[0]; q->devid; q++) {
89663fa9f4cSJonathan Chen 		if (q->devid == ((dinfo->cfg.device << 16) | dinfo->cfg.vendor)
89763fa9f4cSJonathan Chen 		    && q->type == CARDBUS_QUIRK_MAP_REG) {
89863fa9f4cSJonathan Chen 			cardbus_add_map(cbdev, child, q->arg1);
89963fa9f4cSJonathan Chen 		}
90063fa9f4cSJonathan Chen 	}
90163fa9f4cSJonathan Chen }
90263fa9f4cSJonathan Chen 
9030c95c705SJonathan Chen int
904255b159fSJonathan Chen cardbus_cis_read(device_t cbdev, device_t child, u_int8_t id,
9050c95c705SJonathan Chen     struct cis_tupleinfo **buff, int *nret)
9060c95c705SJonathan Chen {
9070c95c705SJonathan Chen 	struct tuple_callbacks cisread_callbacks[] = {
9080c95c705SJonathan Chen 		MAKETUPLE(NULL,			nothing),
9090c95c705SJonathan Chen 		/* first entry will be overwritten */
9100c95c705SJonathan Chen 		MAKETUPLE(NULL,			nothing),
9110c95c705SJonathan Chen 		MAKETUPLE(DEVICE,		nothing),
9120c95c705SJonathan Chen 		MAKETUPLE(LONG_LINK_CB,		unhandled),
9130c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
9140c95c705SJonathan Chen 		MAKETUPLE(CONFIG_CB,		nothing),
9150c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY_CB,	nothing),
9160c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
9170c95c705SJonathan Chen 		MAKETUPLE(BAR,			nothing),
9180c95c705SJonathan Chen 		MAKETUPLE(PWR_MGMNT,		nothing),
9190c95c705SJonathan Chen 		MAKETUPLE(EXTDEVICE,		nothing),
9200c95c705SJonathan Chen 		MAKETUPLE(CHECKSUM,		nothing),
9210c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
9220c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
9230c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		nothing),
9240c95c705SJonathan Chen 		MAKETUPLE(NO_LINK,		nothing),
9250c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		nothing),
9260c95c705SJonathan Chen 		MAKETUPLE(ALTSTR,		nothing),
9270c95c705SJonathan Chen 		MAKETUPLE(DEVICE_A,		nothing),
9280c95c705SJonathan Chen 		MAKETUPLE(JEDEC_C,		nothing),
9290c95c705SJonathan Chen 		MAKETUPLE(JEDEC_A,		nothing),
9300c95c705SJonathan Chen 		MAKETUPLE(CONFIG,		nothing),
9310c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY,	nothing),
9320c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OC,		nothing),
9330c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OA,		nothing),
9340c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO,		nothing),
9350c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO_A,		nothing),
9360c95c705SJonathan Chen 		MAKETUPLE(MANFID,		nothing),
9370c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		nothing),
9380c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		nothing),
9390c95c705SJonathan Chen 		MAKETUPLE(SWIL,			nothing),
9400c95c705SJonathan Chen 		MAKETUPLE(VERS_2,		nothing),
9410c95c705SJonathan Chen 		MAKETUPLE(FORMAT,		nothing),
9420c95c705SJonathan Chen 		MAKETUPLE(GEOMETRY,		nothing),
9430c95c705SJonathan Chen 		MAKETUPLE(BYTEORDER,		nothing),
9440c95c705SJonathan Chen 		MAKETUPLE(DATE,			nothing),
9450c95c705SJonathan Chen 		MAKETUPLE(BATTERY,		nothing),
9460c95c705SJonathan Chen 		MAKETUPLE(ORG,			nothing),
9470c95c705SJonathan Chen 		MAKETUPLE(END,			end),
9480c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		nothing),
9490c95c705SJonathan Chen 	};
9500c95c705SJonathan Chen 	int ret;
9510c95c705SJonathan Chen 
9520c95c705SJonathan Chen 	cisread_callbacks[0].id = id;
9530c95c705SJonathan Chen 	cisread_callbacks[0].name = "COPY";
9540c95c705SJonathan Chen 	cisread_callbacks[0].func = decode_tuple_copy;
9550c95c705SJonathan Chen 	ncisread_buf = 0;
9560c95c705SJonathan Chen 	cisread_buf = NULL;
957255b159fSJonathan Chen 	ret = cardbus_parse_cis(cbdev, child, cisread_callbacks);
9580c95c705SJonathan Chen 
9590c95c705SJonathan Chen 	*buff = cisread_buf;
9600c95c705SJonathan Chen 	*nret = ncisread_buf;
9610c95c705SJonathan Chen 	return ret;
9620c95c705SJonathan Chen }
9630c95c705SJonathan Chen 
9640c95c705SJonathan Chen void
965255b159fSJonathan Chen cardbus_cis_free(device_t cbdev, struct cis_tupleinfo *buff, int *nret)
9660c95c705SJonathan Chen {
9670c95c705SJonathan Chen 	int i;
9686f39832cSPeter Wemm 	for (i = 0; i < *nret; i++)
9690c95c705SJonathan Chen 		free(buff[i].data, M_DEVBUF);
9706f39832cSPeter Wemm 	if (*nret > 0)
9710c95c705SJonathan Chen 		free(buff, M_DEVBUF);
9720c95c705SJonathan Chen }
9730c95c705SJonathan Chen 
9740c95c705SJonathan Chen int
975255b159fSJonathan Chen cardbus_do_cis(device_t cbdev, device_t child)
9760c95c705SJonathan Chen {
97763fa9f4cSJonathan Chen 	int ret;
9780c95c705SJonathan Chen 	struct tuple_callbacks init_callbacks[] = {
9790c95c705SJonathan Chen 		MAKETUPLE(NULL,			generic),
9800c95c705SJonathan Chen 		MAKETUPLE(DEVICE,		generic),
9810c95c705SJonathan Chen 		MAKETUPLE(LONG_LINK_CB,		unhandled),
9820c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
9830c95c705SJonathan Chen 		MAKETUPLE(CONFIG_CB,		generic),
9840c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY_CB,	generic),
9850c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
9860c95c705SJonathan Chen 		MAKETUPLE(BAR,			bar),
9870c95c705SJonathan Chen 		MAKETUPLE(PWR_MGMNT,		generic),
9880c95c705SJonathan Chen 		MAKETUPLE(EXTDEVICE,		generic),
9890c95c705SJonathan Chen 		MAKETUPLE(CHECKSUM,		generic),
9900c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
9910c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
9920c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		linktarget),
9930c95c705SJonathan Chen 		MAKETUPLE(NO_LINK,		generic),
9940c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		vers_1),
9950c95c705SJonathan Chen 		MAKETUPLE(ALTSTR,		generic),
9960c95c705SJonathan Chen 		MAKETUPLE(DEVICE_A,		generic),
9970c95c705SJonathan Chen 		MAKETUPLE(JEDEC_C,		generic),
9980c95c705SJonathan Chen 		MAKETUPLE(JEDEC_A,		generic),
9990c95c705SJonathan Chen 		MAKETUPLE(CONFIG,		generic),
10000c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY,	generic),
10010c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OC,		generic),
10020c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OA,		generic),
10030c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO,		generic),
10040c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO_A,		generic),
10050c95c705SJonathan Chen 		MAKETUPLE(MANFID,		manfid),
10060c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		funcid),
10070c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		funce),
10080c95c705SJonathan Chen 		MAKETUPLE(SWIL,			generic),
10090c95c705SJonathan Chen 		MAKETUPLE(VERS_2,		generic),
10100c95c705SJonathan Chen 		MAKETUPLE(FORMAT,		generic),
10110c95c705SJonathan Chen 		MAKETUPLE(GEOMETRY,		generic),
10120c95c705SJonathan Chen 		MAKETUPLE(BYTEORDER,		generic),
10130c95c705SJonathan Chen 		MAKETUPLE(DATE,			generic),
10140c95c705SJonathan Chen 		MAKETUPLE(BATTERY,		generic),
10150c95c705SJonathan Chen 		MAKETUPLE(ORG,			generic),
10160c95c705SJonathan Chen 		MAKETUPLE(END,			end),
10170c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		generic),
10180c95c705SJonathan Chen 	};
101963fa9f4cSJonathan Chen 
102063fa9f4cSJonathan Chen 	ret = cardbus_parse_cis(cbdev, child, init_callbacks);
102163fa9f4cSJonathan Chen 	if (ret < 0)
102263fa9f4cSJonathan Chen 		return ret;
102363fa9f4cSJonathan Chen 	cardbus_pickup_maps(cbdev, child);
102463fa9f4cSJonathan Chen 	return cardbus_alloc_resources(cbdev, child);
10250c95c705SJonathan Chen }
1026