xref: /freebsd/sys/dev/cardbus/cardbus_cis.c (revision 66e390feb69f20436d5a680b0423a7997f302ae8)
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,	\
6266e390feSWarner Losh 		 uint8_t *tupledata, uint32_t start, uint32_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,
8466e390feSWarner Losh 		    uint32_t start, uint32_t *off, int *tupleid, int *len,
8566e390feSWarner Losh 		    uint8_t *tupledata);
8663fa9f4cSJonathan Chen static int	cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
8766e390feSWarner Losh 		    uint32_t start, uint32_t *off, int *tupleid, int *len,
8866e390feSWarner Losh 		    uint8_t *tupledata);
89255b159fSJonathan Chen static int	cardbus_read_tuple(device_t cbdev, device_t child,
9066e390feSWarner Losh 		    struct resource *res, uint32_t start, uint32_t *off,
9166e390feSWarner Losh 		    int *tupleid, int *len, uint8_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,
9566e390feSWarner Losh 		    uint32_t *start, int *rid);
96255b159fSJonathan Chen static int	decode_tuple(device_t cbdev, device_t child, int tupleid,
9766e390feSWarner Losh 		    int len, uint8_t *tupledata, uint32_t start,
9866e390feSWarner Losh 		    uint32_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 {
12366e390feSWarner Losh 	uint32_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),
17144956c98SAlfred Perlstein 	    M_DEVBUF, 0);
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;
18144956c98SAlfred Perlstein 	cisread_buf[ncisread_buf].data = malloc(len, M_DEVBUF, 0);
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;
214fbe9cff1SWarner Losh 
2157bec1dd5SJonathan Chen 	printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
2160db7e66cSJonathan Chen 	printf("Product name: ");
2170db7e66cSJonathan Chen 	for (i = 2; i < len; i++) {
2187bec1dd5SJonathan Chen 		if (tupledata[i] == '\0')
2190db7e66cSJonathan Chen 			printf(" | ");
2207bec1dd5SJonathan Chen 		else if (tupledata[i] == 0xff)
2210db7e66cSJonathan Chen 			break;
2220db7e66cSJonathan Chen 		else
2237bec1dd5SJonathan Chen 			printf("%c", tupledata[i]);
2240db7e66cSJonathan Chen 	}
2250db7e66cSJonathan Chen 	printf("\n");
226a3133b58SWarner Losh 	return (0);
2270db7e66cSJonathan Chen }
2280db7e66cSJonathan Chen 
2290db7e66cSJonathan Chen DECODE_PROTOTYPE(funcid)
2300db7e66cSJonathan Chen {
231fbe9cff1SWarner Losh 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
2320db7e66cSJonathan Chen 	int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
233fbe9cff1SWarner Losh 	int i;
2340db7e66cSJonathan Chen 
2350db7e66cSJonathan Chen 	printf("Functions: ");
2360db7e66cSJonathan Chen 	for (i = 0; i < len; i++) {
2377bec1dd5SJonathan Chen 		if (tupledata[i] < numnames)
2387bec1dd5SJonathan Chen 			printf("%s", funcnames[tupledata[i]]);
2390db7e66cSJonathan Chen 		else
2407bec1dd5SJonathan Chen 			printf("Unknown(%d)", tupledata[i]);
241255b159fSJonathan Chen 		if (i < len-1)
242255b159fSJonathan Chen 			printf(", ");
2430db7e66cSJonathan Chen 	}
244fbe9cff1SWarner Losh 
245fbe9cff1SWarner Losh 	if (len > 0)
246fbe9cff1SWarner Losh 		dinfo->funcid = tupledata[0];		/* use first in list */
2470db7e66cSJonathan Chen 	printf("\n");
248a3133b58SWarner Losh 	return (0);
2490db7e66cSJonathan Chen }
2500db7e66cSJonathan Chen 
2510db7e66cSJonathan Chen DECODE_PROTOTYPE(manfid)
2520db7e66cSJonathan Chen {
253fbe9cff1SWarner Losh 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
2540db7e66cSJonathan Chen 	int i;
255fbe9cff1SWarner Losh 
2560db7e66cSJonathan Chen 	printf("Manufacturer ID: ");
2570db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2587bec1dd5SJonathan Chen 		printf("%02x", tupledata[i]);
2590db7e66cSJonathan Chen 	printf("\n");
260fbe9cff1SWarner Losh 
261fbe9cff1SWarner Losh 	if (len == 5) {
262fbe9cff1SWarner Losh 		dinfo->mfrid = tupledata[1] | (tupledata[2]<<8);
263fbe9cff1SWarner Losh 		dinfo->prodid = tupledata[3] | (tupledata[4]<<8);
264fbe9cff1SWarner Losh 	}
265a3133b58SWarner Losh 	return (0);
2660db7e66cSJonathan Chen }
2670db7e66cSJonathan Chen 
2680db7e66cSJonathan Chen DECODE_PROTOTYPE(funce)
2690db7e66cSJonathan Chen {
270fbe9cff1SWarner Losh 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
271fbe9cff1SWarner Losh 	int type, i;
272fbe9cff1SWarner Losh 
2730db7e66cSJonathan Chen 	printf("Function Extension: ");
2740db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2757bec1dd5SJonathan Chen 		printf("%02x", tupledata[i]);
2760db7e66cSJonathan Chen 	printf("\n");
277fbe9cff1SWarner Losh 	if (len < 2)			/* too short */
278fbe9cff1SWarner Losh 		return (0);
279fbe9cff1SWarner Losh 	type = tupledata[0];		/* XXX <32 always? */
280fbe9cff1SWarner Losh 	switch (dinfo->funcid) {
281fbe9cff1SWarner Losh 	case TPL_FUNC_SERIAL:
282fbe9cff1SWarner Losh 		if (type == TPL_FUNCE_SER_UART) {	/* NB: len known > 1 */
283fbe9cff1SWarner Losh 			dinfo->funce.sio.type = tupledata[1] & 0x1f;
284fbe9cff1SWarner Losh 		}
285fbe9cff1SWarner Losh 		dinfo->fepresent |= 1<<type;
286fbe9cff1SWarner Losh 		break;
287fbe9cff1SWarner Losh 	case TPL_FUNC_LAN:
288fbe9cff1SWarner Losh 		switch (type) {
289fbe9cff1SWarner Losh 		case TPL_FUNCE_LAN_TECH:
290fbe9cff1SWarner Losh 			dinfo->funce.lan.tech = tupledata[1];	/* XXX mask? */
291fbe9cff1SWarner Losh 			break;
292fbe9cff1SWarner Losh #if 0
293fbe9cff1SWarner Losh 		case TPL_FUNCE_LAN_SPEED:
294fbe9cff1SWarner Losh 			for (i = 0; i < 3; i++) {
295fbe9cff1SWarner Losh 				if (dinfo->funce.lan.speed[i] == 0) {
296fbe9cff1SWarner Losh 					if (len > 4) {
297fbe9cff1SWarner Losh 						dinfo->funce.lan.speed[i] =
298fbe9cff1SWarner Losh 							...;
299fbe9cff1SWarner Losh 					}
300fbe9cff1SWarner Losh 					break;
301fbe9cff1SWarner Losh 				}
302fbe9cff1SWarner Losh 			}
303fbe9cff1SWarner Losh 			break;
304fbe9cff1SWarner Losh #endif
305fbe9cff1SWarner Losh 		case TPL_FUNCE_LAN_MEDIA:
306fbe9cff1SWarner Losh 			for (i = 0; i < 4 && dinfo->funce.lan.media[i]; i++) {
307fbe9cff1SWarner Losh 				if (dinfo->funce.lan.media[i] == 0) {
308fbe9cff1SWarner Losh 					/* NB: len known > 1 */
309fbe9cff1SWarner Losh 					dinfo->funce.lan.media[i] =
310fbe9cff1SWarner Losh 						tupledata[1];	/*XXX? mask */
311fbe9cff1SWarner Losh 					break;
312fbe9cff1SWarner Losh 				}
313fbe9cff1SWarner Losh 			}
314fbe9cff1SWarner Losh 			break;
315fbe9cff1SWarner Losh 		case TPL_FUNCE_LAN_NID:
316fbe9cff1SWarner Losh 			if (len > 6)
317fbe9cff1SWarner Losh 				bcopy(&tupledata[1], dinfo->funce.lan.nid, 6);
318fbe9cff1SWarner Losh 			break;
319fbe9cff1SWarner Losh 		case TPL_FUNCE_LAN_CONN:
320fbe9cff1SWarner Losh 			dinfo->funce.lan.contype = tupledata[1];/*XXX mask? */
321fbe9cff1SWarner Losh 			break;
322fbe9cff1SWarner Losh 		}
323fbe9cff1SWarner Losh 		dinfo->fepresent |= 1<<type;
324fbe9cff1SWarner Losh 		break;
325fbe9cff1SWarner Losh 	}
326a3133b58SWarner Losh 	return (0);
3270db7e66cSJonathan Chen }
3280db7e66cSJonathan Chen 
3290db7e66cSJonathan Chen DECODE_PROTOTYPE(bar)
3300db7e66cSJonathan Chen {
33163fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
3320db7e66cSJonathan Chen 	int type;
3330db7e66cSJonathan Chen 	int reg;
33466e390feSWarner Losh 	uint32_t bar;
3350db7e66cSJonathan Chen 
336e6e272b9SScott Long 	if (len != 6) {
337e6e272b9SScott Long 		printf("*** ERROR *** BAR length not 6 (%d)\n", len);
338e6e272b9SScott Long 		return (EINVAL);
339e6e272b9SScott Long 	}
34066e390feSWarner Losh 	reg = *(uint16_t*)tupledata;
34166e390feSWarner Losh 	len = *(uint32_t*)(tupledata + 2);
3420db7e66cSJonathan Chen 	if (reg & TPL_BAR_REG_AS) {
3430db7e66cSJonathan Chen 		type = SYS_RES_IOPORT;
3440db7e66cSJonathan Chen 	} else {
3450db7e66cSJonathan Chen 		type = SYS_RES_MEMORY;
3460db7e66cSJonathan Chen 	}
3470db7e66cSJonathan Chen 	bar = (reg & TPL_BAR_REG_ASI_MASK) - 1;
348255b159fSJonathan Chen 	if (bar < 0 || bar > 5 ||
349255b159fSJonathan Chen 	    (type == SYS_RES_IOPORT && bar == 5)) {
350255b159fSJonathan Chen 		device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n",
3510db7e66cSJonathan Chen 		    reg, bar);
352a3133b58SWarner Losh 		return (0);
3530db7e66cSJonathan Chen 	}
3540db7e66cSJonathan Chen 	bar = CARDBUS_BASE0_REG + bar * 4;
35563fa9f4cSJonathan Chen 	if (type == SYS_RES_MEMORY) {
35663fa9f4cSJonathan Chen 		if (bar & TPL_BAR_REG_PREFETCHABLE)
35763fa9f4cSJonathan Chen 			dinfo->mprefetchable |= BARBIT(bar);
35863fa9f4cSJonathan Chen 		if (bar & TPL_BAR_REG_BELOW1MB)
35963fa9f4cSJonathan Chen 			dinfo->mbelow1mb |= BARBIT(bar);
36063fa9f4cSJonathan Chen 	} else if (type == SYS_RES_IOPORT) {
36163fa9f4cSJonathan Chen 		if (bar & TPL_BAR_REG_BELOW1MB)
36263fa9f4cSJonathan Chen 			dinfo->ibelow1mb |= BARBIT(bar);
3630db7e66cSJonathan Chen 	}
364e6e272b9SScott Long 	DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
36563fa9f4cSJonathan Chen 	    (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
36663fa9f4cSJonathan Chen 	    (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
367e6e272b9SScott Long 	    " (Prefetchable)" : "", type == SYS_RES_MEMORY ?
368e6e272b9SScott Long 	    ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") :
369e6e272b9SScott Long 	    (dinfo->ibelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "" ));
37063fa9f4cSJonathan Chen 
3717ba175acSWarner Losh 	resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len);
372e6e272b9SScott Long 
3739fb92b64SScott Long 	/*
3749fb92b64SScott Long 	 * Mark the appropriate bit in the PCI command register so that
37501f2fb65SWarner Losh 	 * device drivers will know which type of BARs can be used.
3769fb92b64SScott Long 	 */
3779fb92b64SScott Long 	pci_enable_io(child, type);
378a3133b58SWarner Losh 	return (0);
3790db7e66cSJonathan Chen }
3800db7e66cSJonathan Chen 
3810db7e66cSJonathan Chen DECODE_PROTOTYPE(unhandled)
3820db7e66cSJonathan Chen {
3830db7e66cSJonathan Chen 	printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
384a3133b58SWarner Losh 	return (-1);
3850db7e66cSJonathan Chen }
3860db7e66cSJonathan Chen 
3870db7e66cSJonathan Chen DECODE_PROTOTYPE(end)
3880db7e66cSJonathan Chen {
3890c95c705SJonathan Chen 	printf("CIS reading done\n");
390a3133b58SWarner Losh 	return (0);
3910db7e66cSJonathan Chen }
3920db7e66cSJonathan Chen 
393255b159fSJonathan Chen /*
394255b159fSJonathan Chen  * Functions to read the a tuple from the card
395255b159fSJonathan Chen  */
396255b159fSJonathan Chen 
3970db7e66cSJonathan Chen static int
39866e390feSWarner Losh cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start,
39966e390feSWarner Losh     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
4007bec1dd5SJonathan Chen {
4017bec1dd5SJonathan Chen 	int i, j;
40266e390feSWarner Losh 	uint32_t e;
40366e390feSWarner Losh 	uint32_t loc;
4047bec1dd5SJonathan Chen 
40563fa9f4cSJonathan Chen 	loc = start + *off;
40649f158ccSJonathan Chen 
40749f158ccSJonathan Chen 	e = pci_read_config(child, loc - loc % 4, 4);
40849f158ccSJonathan Chen 	for (j = loc % 4; j > 0; j--)
4097bec1dd5SJonathan Chen 		e >>= 8;
4107bec1dd5SJonathan Chen 	*len = 0;
41149f158ccSJonathan Chen 	for (i = loc, j = -2; j < *len; j++, i++) {
4127bec1dd5SJonathan Chen 		if (i % 4 == 0)
4137bec1dd5SJonathan Chen 			e = pci_read_config(child, i, 4);
4147bec1dd5SJonathan Chen 		if (j == -2)
4157bec1dd5SJonathan Chen 			*tupleid = 0xff & e;
4167bec1dd5SJonathan Chen 		else if (j == -1)
4177bec1dd5SJonathan Chen 			*len = 0xff & e;
4187bec1dd5SJonathan Chen 		else
4197bec1dd5SJonathan Chen 			tupledata[j] = 0xff & e;
4207bec1dd5SJonathan Chen 		e >>= 8;
4217bec1dd5SJonathan Chen 	}
4227bec1dd5SJonathan Chen 	*off += *len + 2;
423a3133b58SWarner Losh 	return (0);
4247bec1dd5SJonathan Chen }
4257bec1dd5SJonathan Chen 
4267bec1dd5SJonathan Chen static int
42766e390feSWarner Losh cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start,
42866e390feSWarner Losh     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
4290db7e66cSJonathan Chen {
43063fa9f4cSJonathan Chen 	bus_space_tag_t bt;
43163fa9f4cSJonathan Chen 	bus_space_handle_t bh;
43263fa9f4cSJonathan Chen 	int ret;
4330db7e66cSJonathan Chen 
43463fa9f4cSJonathan Chen 	bt = rman_get_bustag(res);
43563fa9f4cSJonathan Chen 	bh = rman_get_bushandle(res);
4360db7e66cSJonathan Chen 
43763fa9f4cSJonathan Chen 	*tupleid = bus_space_read_1(bt, bh, start + *off);
43863fa9f4cSJonathan Chen 	*len = bus_space_read_1(bt, bh, start + *off + 1);
43963fa9f4cSJonathan Chen 	bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
44063fa9f4cSJonathan Chen 	ret = 0;
44163fa9f4cSJonathan Chen 	*off += *len + 2;
442a3133b58SWarner Losh 	return (ret);
4430db7e66cSJonathan Chen }
44463fa9f4cSJonathan Chen 
44563fa9f4cSJonathan Chen static int
44663fa9f4cSJonathan Chen cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
44766e390feSWarner Losh     uint32_t start, uint32_t *off, int *tupleid, int *len,
44866e390feSWarner Losh     uint8_t *tupledata)
44963fa9f4cSJonathan Chen {
45063fa9f4cSJonathan Chen 	if (res == (struct resource*)~0UL) {
451a3133b58SWarner Losh 		return (cardbus_read_tuple_conf(cbdev, child, start, off,
452a3133b58SWarner Losh 		    tupleid, len, tupledata));
45363fa9f4cSJonathan Chen 	} else {
454a3133b58SWarner Losh 		return (cardbus_read_tuple_mem(cbdev, res, start, off,
455a3133b58SWarner Losh 		    tupleid, len, tupledata));
45663fa9f4cSJonathan Chen 	}
45763fa9f4cSJonathan Chen }
45863fa9f4cSJonathan Chen 
45963fa9f4cSJonathan Chen static void
46063fa9f4cSJonathan Chen cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
46163fa9f4cSJonathan Chen     struct resource *res)
46263fa9f4cSJonathan Chen {
46363fa9f4cSJonathan Chen 	if (res != (struct resource*)~0UL) {
46463fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
46563fa9f4cSJonathan Chen 		pci_write_config(child, rid, 0, 4);
46663fa9f4cSJonathan Chen 		PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
46763fa9f4cSJonathan Chen 	}
46863fa9f4cSJonathan Chen }
46963fa9f4cSJonathan Chen 
47063fa9f4cSJonathan Chen static struct resource *
47166e390feSWarner Losh cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
47263fa9f4cSJonathan Chen     int *rid)
47363fa9f4cSJonathan Chen {
47466e390feSWarner Losh 	uint32_t testval;
47566e390feSWarner Losh 	uint32_t size;
47663fa9f4cSJonathan Chen 	struct resource *res;
47763fa9f4cSJonathan Chen 
47863fa9f4cSJonathan Chen 	switch (CARDBUS_CIS_SPACE(*start)) {
47963fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_TUPLE:
480e6e272b9SScott Long 		/* CIS in PCI config space need no initialization */
48121677473SWarner Losh 		return ((struct resource*)~0UL);
48263fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR0:
48363fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR1:
48463fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR2:
48563fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR3:
48663fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR4:
48763fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR5:
48863fa9f4cSJonathan Chen 		*rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
48963fa9f4cSJonathan Chen 		break;
49063fa9f4cSJonathan Chen 	case CARDBUS_CIS_ASI_ROM:
49163fa9f4cSJonathan Chen 		*rid = CARDBUS_ROM_REG;
492e6e272b9SScott Long #if 0
493e6e272b9SScott Long 		/*
494e6e272b9SScott Long 		 * This mask doesn't contain the bit that actually enables
495e6e272b9SScott Long 		 * the Option ROM.
496e6e272b9SScott Long 		 */
49763fa9f4cSJonathan Chen 		pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4);
498e6e272b9SScott Long #endif
49963fa9f4cSJonathan Chen 		break;
50063fa9f4cSJonathan Chen 	default:
50163fa9f4cSJonathan Chen 		device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
50263fa9f4cSJonathan Chen 		    CARDBUS_CIS_SPACE(*start));
503a3133b58SWarner Losh 		return (NULL);
50463fa9f4cSJonathan Chen 	}
50563fa9f4cSJonathan Chen 
50663fa9f4cSJonathan Chen 	/* figure out how much space we need */
507e6e272b9SScott Long 	pci_write_config(child, *rid, 0xffffffff, 4);
50863fa9f4cSJonathan Chen 	testval = pci_read_config(child, *rid, 4);
509e6e272b9SScott Long 
510e6e272b9SScott Long 	/*
511e6e272b9SScott Long 	 * This bit has a different meaning depending if we are dealing
5121e06ae99SScott Long 	 * with a normal BAR or an Option ROM BAR.
513e6e272b9SScott Long 	 */
514e6e272b9SScott Long 	if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) {
51563fa9f4cSJonathan Chen 		device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
516a3133b58SWarner Losh 		return (NULL);
51763fa9f4cSJonathan Chen 	}
518e6e272b9SScott Long 
51963fa9f4cSJonathan Chen 	size = CARDBUS_MAPREG_MEM_SIZE(testval);
520e6e272b9SScott Long 	/* XXX Is this some kind of hack? */
52163fa9f4cSJonathan Chen 	if (size < 4096)
52263fa9f4cSJonathan Chen 		size = 4096;
52363fa9f4cSJonathan Chen 	/* allocate the memory space to read CIS */
52463fa9f4cSJonathan Chen 	res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size,
52563fa9f4cSJonathan Chen 	    rman_make_alignment_flags(size) | RF_ACTIVE);
52663fa9f4cSJonathan Chen 	if (res == NULL) {
52763fa9f4cSJonathan Chen 		device_printf(cbdev, "Unable to allocate resource "
52863fa9f4cSJonathan Chen 		    "to read CIS.\n");
529a3133b58SWarner Losh 		return (NULL);
53063fa9f4cSJonathan Chen 	}
53163fa9f4cSJonathan Chen 	pci_write_config(child, *rid,
53263fa9f4cSJonathan Chen 	    rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)?
53363fa9f4cSJonathan Chen 		CARDBUS_ROM_ENABLE : 0),
53463fa9f4cSJonathan Chen 	    4);
53563fa9f4cSJonathan Chen 	PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY);
53663fa9f4cSJonathan Chen 
53763fa9f4cSJonathan Chen 	/* Flip to the right ROM image if CIS is in ROM */
53863fa9f4cSJonathan Chen 	if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
53963fa9f4cSJonathan Chen 		bus_space_tag_t bt;
54063fa9f4cSJonathan Chen 		bus_space_handle_t bh;
54166e390feSWarner Losh 		uint32_t imagesize;
54266e390feSWarner Losh 		uint32_t imagebase = 0;
54366e390feSWarner Losh 		uint32_t pcidata;
54466e390feSWarner Losh 		uint16_t romsig;
54563fa9f4cSJonathan Chen 		int romnum = 0;
546e6e272b9SScott Long 		int imagenum;
54763fa9f4cSJonathan Chen 
54863fa9f4cSJonathan Chen 		bt = rman_get_bustag(res);
54963fa9f4cSJonathan Chen 		bh = rman_get_bushandle(res);
55063fa9f4cSJonathan Chen 
55163fa9f4cSJonathan Chen 		imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
55263fa9f4cSJonathan Chen 		for (romnum = 0;; romnum++) {
553e6e272b9SScott Long 			romsig = bus_space_read_2(bt, bh,
554e6e272b9SScott Long 			    imagebase + CARDBUS_EXROM_SIGNATURE);
555e6e272b9SScott Long 			if (romsig != 0xaa55) {
55663fa9f4cSJonathan Chen 				device_printf(cbdev, "Bad header in rom %d: "
557e6e272b9SScott Long 				    "[%x] %04x\n", romnum, imagebase +
558e6e272b9SScott Long 				    CARDBUS_EXROM_SIGNATURE, romsig);
55963fa9f4cSJonathan Chen 				bus_release_resource(cbdev, SYS_RES_MEMORY,
56063fa9f4cSJonathan Chen 				    *rid, res);
56163fa9f4cSJonathan Chen 				*rid = 0;
562a3133b58SWarner Losh 				return (NULL);
56363fa9f4cSJonathan Chen 			}
564e6e272b9SScott Long 
565e6e272b9SScott Long 			/*
566e6e272b9SScott Long 			 * If this was the Option ROM image that we were
567e6e272b9SScott Long 			 * looking for, then we are done.
568e6e272b9SScott Long 			 */
569e6e272b9SScott Long 			if (romnum == imagenum)
570e6e272b9SScott Long 				break;
571e6e272b9SScott Long 
572e6e272b9SScott Long 			/* Find out where the next Option ROM image is */
573e6e272b9SScott Long 			pcidata = imagebase + bus_space_read_2(bt, bh,
574e6e272b9SScott Long 			    imagebase + CARDBUS_EXROM_DATA_PTR);
57563fa9f4cSJonathan Chen 			imagesize = bus_space_read_2(bt, bh,
576e6e272b9SScott Long 			    pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
5770db7e66cSJonathan Chen 
5787bec1dd5SJonathan Chen 			if (imagesize == 0) {
5790db7e66cSJonathan Chen 				/*
5800db7e66cSJonathan Chen 				 * XXX some ROMs seem to have this as zero,
5810db7e66cSJonathan Chen 				 * can we assume this means 1 block?
5820db7e66cSJonathan Chen 				 */
583e6e272b9SScott Long 				device_printf(cbdev, "Warning, size of Option "
584e6e272b9SScott Long 				    "ROM image %d is 0 bytes, assuming 512 "
585e6e272b9SScott Long 				    "bytes.\n", romnum);
5860db7e66cSJonathan Chen 				imagesize = 1;
5877bec1dd5SJonathan Chen 			}
588e6e272b9SScott Long 
589e6e272b9SScott Long 			/* Image size is in 512 byte units */
5900db7e66cSJonathan Chen 			imagesize <<= 9;
5910db7e66cSJonathan Chen 
592e6e272b9SScott Long 			if ((bus_space_read_1(bt, bh, pcidata +
5931e06ae99SScott Long 			    CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
594e6e272b9SScott Long 				device_printf(cbdev, "Cannot find CIS in "
595e6e272b9SScott Long 				    "Option ROM\n");
596e6e272b9SScott Long 				bus_release_resource(cbdev, SYS_RES_MEMORY,
597e6e272b9SScott Long 				    *rid, res);
598e6e272b9SScott Long 				*rid = 0;
599a3133b58SWarner Losh 				return (NULL);
6000db7e66cSJonathan Chen 			}
601e6e272b9SScott Long 			imagebase += imagesize;
6020db7e66cSJonathan Chen 		}
603e6e272b9SScott Long 		*start = imagebase + CARDBUS_CIS_ADDR(*start);
6040db7e66cSJonathan Chen 	} else {
605e6e272b9SScott Long 		*start = CARDBUS_CIS_ADDR(*start);
6060db7e66cSJonathan Chen 	}
607e6e272b9SScott Long 
608a3133b58SWarner Losh 	return (res);
6097bec1dd5SJonathan Chen }
6107bec1dd5SJonathan Chen 
611255b159fSJonathan Chen /*
612255b159fSJonathan Chen  * Dispatch the right handler function per tuple
613255b159fSJonathan Chen  */
614255b159fSJonathan Chen 
6157bec1dd5SJonathan Chen static int
616255b159fSJonathan Chen decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
61766e390feSWarner Losh     uint8_t *tupledata, uint32_t start, uint32_t *off,
6180c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
6197bec1dd5SJonathan Chen {
6207bec1dd5SJonathan Chen 	int i;
6210c95c705SJonathan Chen 	for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
6220c95c705SJonathan Chen 		if (tupleid == callbacks[i].id)
623a3133b58SWarner Losh 			return (callbacks[i].func(cbdev, child, tupleid, len,
624a3133b58SWarner Losh 			    tupledata, start, off, &callbacks[i]));
6257bec1dd5SJonathan Chen 	}
6267bec1dd5SJonathan Chen 
62749f158ccSJonathan Chen 	if (tupleid < CISTPL_CUSTOMSTART) {
628255b159fSJonathan Chen 		device_printf(cbdev, "Undefined tuple encountered, "
629255b159fSJonathan Chen 		    "CIS parsing terminated\n");
630a3133b58SWarner Losh 		return (EINVAL);
63149f158ccSJonathan Chen 	}
632a3133b58SWarner Losh 	return (callbacks[i].func(cbdev, child, tupleid, len,
633a3133b58SWarner Losh 	    tupledata, start, off, NULL));
6340db7e66cSJonathan Chen }
6350db7e66cSJonathan Chen 
6360c95c705SJonathan Chen static int
637255b159fSJonathan Chen cardbus_parse_cis(device_t cbdev, device_t child,
6380c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
6390db7e66cSJonathan Chen {
64066e390feSWarner Losh 	uint8_t tupledata[MAXTUPLESIZE];
6417bec1dd5SJonathan Chen 	int tupleid;
6427bec1dd5SJonathan Chen 	int len;
6437bec1dd5SJonathan Chen 	int expect_linktarget;
64466e390feSWarner Losh 	uint32_t start, off;
64563fa9f4cSJonathan Chen 	struct resource *res;
64663fa9f4cSJonathan Chen 	int rid;
6470db7e66cSJonathan Chen 
6480db7e66cSJonathan Chen 	bzero(tupledata, MAXTUPLESIZE);
6497bec1dd5SJonathan Chen 	expect_linktarget = TRUE;
650e6e272b9SScott Long 	if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0)
651e6e272b9SScott Long 		return (ENXIO);
65249f158ccSJonathan Chen 	off = 0;
65363fa9f4cSJonathan Chen 	res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
65463fa9f4cSJonathan Chen 	if (res == NULL)
655a3133b58SWarner Losh 		return (ENXIO);
6567bec1dd5SJonathan Chen 	do {
65763fa9f4cSJonathan Chen 		if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
65863fa9f4cSJonathan Chen 		    &tupleid, &len, tupledata)) {
65963fa9f4cSJonathan Chen 			device_printf(cbdev, "Failed to read CIS.\n");
66063fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
661a3133b58SWarner Losh 			return (ENXIO);
66263fa9f4cSJonathan Chen 		}
6637bec1dd5SJonathan Chen 
6647bec1dd5SJonathan Chen 		if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
665255b159fSJonathan Chen 			device_printf(cbdev, "Expecting link target, got 0x%x\n",
6667bec1dd5SJonathan Chen 			    tupleid);
66763fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
668a3133b58SWarner Losh 			return (EINVAL);
6697bec1dd5SJonathan Chen 		}
670255b159fSJonathan Chen 		expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
67163fa9f4cSJonathan Chen 		    tupledata, start, &off, callbacks);
67263fa9f4cSJonathan Chen 		if (expect_linktarget != 0) {
67363fa9f4cSJonathan Chen 			cardbus_read_tuple_finish(cbdev, child, rid, res);
674a3133b58SWarner Losh 			return (expect_linktarget);
67563fa9f4cSJonathan Chen 		}
6767bec1dd5SJonathan Chen 	} while (tupleid != CISTPL_END);
67763fa9f4cSJonathan Chen 	cardbus_read_tuple_finish(cbdev, child, rid, res);
678a3133b58SWarner Losh 	return (0);
6790db7e66cSJonathan Chen }
6800db7e66cSJonathan Chen 
68163fa9f4cSJonathan Chen static int
68263fa9f4cSJonathan Chen barsort(const void *a, const void *b)
68363fa9f4cSJonathan Chen {
68478b226dcSAlfred Perlstein 	return ((*(const struct resource_list_entry * const *)b)->count -
68578b226dcSAlfred Perlstein 	    (*(const struct resource_list_entry * const *)a)->count);
68663fa9f4cSJonathan Chen }
68763fa9f4cSJonathan Chen 
68863fa9f4cSJonathan Chen static int
68963fa9f4cSJonathan Chen cardbus_alloc_resources(device_t cbdev, device_t child)
69063fa9f4cSJonathan Chen {
69163fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
69263fa9f4cSJonathan Chen 	int count;
69363fa9f4cSJonathan Chen 	struct resource_list_entry *rle;
69463fa9f4cSJonathan Chen 	struct resource_list_entry **barlist;
69563fa9f4cSJonathan Chen 	int tmp;
69666e390feSWarner Losh 	uint32_t mem_psize = 0, mem_nsize = 0, io_size = 0;
69763fa9f4cSJonathan Chen 	struct resource *res;
69866e390feSWarner Losh 	uint32_t start,end;
69921677473SWarner Losh 	int rid, flags;
70063fa9f4cSJonathan Chen 
70163fa9f4cSJonathan Chen 	count = 0;
70221677473SWarner Losh 	SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
70363fa9f4cSJonathan Chen 		count++;
70421677473SWarner Losh 	}
70563fa9f4cSJonathan Chen 	if (count == 0)
706a3133b58SWarner Losh 		return (0);
70763fa9f4cSJonathan Chen 	barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF,
70844956c98SAlfred Perlstein 	    0);
70963fa9f4cSJonathan Chen 	count = 0;
71021677473SWarner Losh 	SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
71163fa9f4cSJonathan Chen 		barlist[count] = rle;
71263fa9f4cSJonathan Chen 		if (rle->type == SYS_RES_IOPORT) {
71363fa9f4cSJonathan Chen 			io_size += rle->count;
71463fa9f4cSJonathan Chen 		} else if (rle->type == SYS_RES_MEMORY) {
71563fa9f4cSJonathan Chen 			if (dinfo->mprefetchable & BARBIT(rle->rid))
71663fa9f4cSJonathan Chen 				mem_psize += rle->count;
71763fa9f4cSJonathan Chen 			else
71863fa9f4cSJonathan Chen 				mem_nsize += rle->count;
71963fa9f4cSJonathan Chen 		}
72063fa9f4cSJonathan Chen 		count++;
72163fa9f4cSJonathan Chen 	}
72263fa9f4cSJonathan Chen 
72363fa9f4cSJonathan Chen 	/*
72463fa9f4cSJonathan Chen 	 * We want to allocate the largest resource first, so that our
72563fa9f4cSJonathan Chen 	 * allocated memory is packed.
72663fa9f4cSJonathan Chen 	 */
72763fa9f4cSJonathan Chen 	qsort(barlist, count, sizeof(struct resource_list_entry*), barsort);
72863fa9f4cSJonathan Chen 
72963fa9f4cSJonathan Chen 	/* Allocate prefetchable memory */
73063fa9f4cSJonathan Chen 	flags = 0;
73163fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
73263fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
73363fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_MEMORY &&
73463fa9f4cSJonathan Chen 		    dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) {
73563fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
73663fa9f4cSJonathan Chen 			break;
73763fa9f4cSJonathan Chen 		}
73863fa9f4cSJonathan Chen 	}
73963fa9f4cSJonathan Chen 	if (flags > 0) { /* If any prefetchable memory is requested... */
74063fa9f4cSJonathan Chen 		/*
74163fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
74263fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
74363fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
74463fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
74563fa9f4cSJonathan Chen 		 * within the window.
74663fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
74763fa9f4cSJonathan Chen 		 */
74863fa9f4cSJonathan Chen 		rid = 0;
74963fa9f4cSJonathan Chen 		res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
75063fa9f4cSJonathan Chen 		    (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL,
75163fa9f4cSJonathan Chen 		    mem_psize, flags);
75263fa9f4cSJonathan Chen 		start = rman_get_start(res);
75363fa9f4cSJonathan Chen 		end = rman_get_end(res);
75463fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end));
75563fa9f4cSJonathan Chen 		/*
75663fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
75763fa9f4cSJonathan Chen 		 * out piece by piece.
75863fa9f4cSJonathan Chen 		 */
75963fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
76063fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
76163fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
76263fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_MEMORY &&
76363fa9f4cSJonathan Chen 			    dinfo->mprefetchable & BARBIT(barlist[tmp]->rid)) {
76463fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
76563fa9f4cSJonathan Chen 				    barlist[tmp]->type,
76663fa9f4cSJonathan Chen 				    &barlist[tmp]->rid, start, end,
76763fa9f4cSJonathan Chen 				    barlist[tmp]->count,
76863fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
76963fa9f4cSJonathan Chen 				    barlist[tmp]->count));
77063fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
77163fa9f4cSJonathan Chen 					mem_nsize += barlist[tmp]->count;
77263fa9f4cSJonathan Chen 					dinfo->mprefetchable &=
77363fa9f4cSJonathan Chen 					    ~BARBIT(barlist[tmp]->rid);
77463fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
77563fa9f4cSJonathan Chen 					    "prefetchable memory, will try as "
77663fa9f4cSJonathan Chen 					    "non-prefetchable.\n"));
77721677473SWarner Losh 				} else {
77863fa9f4cSJonathan Chen 					barlist[tmp]->start =
77963fa9f4cSJonathan Chen 					    rman_get_start(barlist[tmp]->res);
78063fa9f4cSJonathan Chen 					barlist[tmp]->end =
78163fa9f4cSJonathan Chen 					    rman_get_end(barlist[tmp]->res);
78263fa9f4cSJonathan Chen 					pci_write_config(child,
78363fa9f4cSJonathan Chen 					    barlist[tmp]->rid,
78463fa9f4cSJonathan Chen 					    barlist[tmp]->start, 4);
78563fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Prefetchable memory "
78663fa9f4cSJonathan Chen 					    "rid=%x at %lx-%lx\n",
78763fa9f4cSJonathan Chen 					    barlist[tmp]->rid,
78863fa9f4cSJonathan Chen 					    barlist[tmp]->start,
78963fa9f4cSJonathan Chen 					    barlist[tmp]->end));
79063fa9f4cSJonathan Chen 				}
79163fa9f4cSJonathan Chen 			}
79263fa9f4cSJonathan Chen 		}
79321677473SWarner Losh 	}
79463fa9f4cSJonathan Chen 
79563fa9f4cSJonathan Chen 	/* Allocate non-prefetchable memory */
79663fa9f4cSJonathan Chen 	flags = 0;
79763fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
79863fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
79963fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_MEMORY) {
80063fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
80163fa9f4cSJonathan Chen 			break;
80263fa9f4cSJonathan Chen 		}
80363fa9f4cSJonathan Chen 	}
80463fa9f4cSJonathan Chen 	if (flags > 0) { /* If any non-prefetchable memory is requested... */
80563fa9f4cSJonathan Chen 		/*
80663fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
80763fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
80863fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
80963fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
81063fa9f4cSJonathan Chen 		 * within the window.
81163fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
81263fa9f4cSJonathan Chen 		 */
81363fa9f4cSJonathan Chen 		rid = 0;
81463fa9f4cSJonathan Chen 		res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
81563fa9f4cSJonathan Chen 		    ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL,
81663fa9f4cSJonathan Chen 		    mem_nsize, flags);
81763fa9f4cSJonathan Chen 		start = rman_get_start(res);
81863fa9f4cSJonathan Chen 		end = rman_get_end(res);
81963fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n",
82063fa9f4cSJonathan Chen 		    start, end));
82163fa9f4cSJonathan Chen 		/*
82263fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
82363fa9f4cSJonathan Chen 		 * out piece by piece.
82463fa9f4cSJonathan Chen 		 */
82563fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
82663fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
82763fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
82863fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_MEMORY) {
82963fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
83063fa9f4cSJonathan Chen 				    barlist[tmp]->type, &barlist[tmp]->rid,
83163fa9f4cSJonathan Chen 				    start, end, barlist[tmp]->count,
83263fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
83363fa9f4cSJonathan Chen 				    barlist[tmp]->count));
83463fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
83563fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
83663fa9f4cSJonathan Chen 					    "memory for cardbus device\n"));
837214c0b3dSWarner Losh 					free(barlist, M_DEVBUF);
8387ba175acSWarner Losh 					return (ENOMEM);
83963fa9f4cSJonathan Chen 				}
84063fa9f4cSJonathan Chen 				barlist[tmp]->start =
84163fa9f4cSJonathan Chen 				    rman_get_start(barlist[tmp]->res);
84263fa9f4cSJonathan Chen 				barlist[tmp]->end = rman_get_end(
84363fa9f4cSJonathan Chen 					barlist[tmp]->res);
84463fa9f4cSJonathan Chen 				pci_write_config(child, barlist[tmp]->rid,
84563fa9f4cSJonathan Chen 				    barlist[tmp]->start, 4);
84663fa9f4cSJonathan Chen 				DEVPRINTF((cbdev, "Non-prefetchable memory "
84763fa9f4cSJonathan Chen 				    "rid=%x at %lx-%lx (%lx)\n",
84863fa9f4cSJonathan Chen 				    barlist[tmp]->rid, barlist[tmp]->start,
84963fa9f4cSJonathan Chen 				    barlist[tmp]->end, barlist[tmp]->count));
85063fa9f4cSJonathan Chen 			}
85163fa9f4cSJonathan Chen 		}
85263fa9f4cSJonathan Chen 	}
85363fa9f4cSJonathan Chen 
85463fa9f4cSJonathan Chen 	/* Allocate IO ports */
85563fa9f4cSJonathan Chen 	flags = 0;
85663fa9f4cSJonathan Chen 	for (tmp = 0; tmp < count; tmp++) {
85763fa9f4cSJonathan Chen 		if (barlist[tmp]->res == NULL &&
85863fa9f4cSJonathan Chen 		    barlist[tmp]->type == SYS_RES_IOPORT) {
85963fa9f4cSJonathan Chen 			flags = rman_make_alignment_flags(barlist[tmp]->count);
86063fa9f4cSJonathan Chen 			break;
86163fa9f4cSJonathan Chen 		}
86263fa9f4cSJonathan Chen 	}
86363fa9f4cSJonathan Chen 	if (flags > 0) { /* If any IO port is requested... */
86463fa9f4cSJonathan Chen 		/*
86563fa9f4cSJonathan Chen 		 * First we allocate one big space for all resources of this
86663fa9f4cSJonathan Chen 		 * type.  We do this because our parent, pccbb, needs to open
86763fa9f4cSJonathan Chen 		 * a window to forward all addresses within the window, and
86863fa9f4cSJonathan Chen 		 * it would be best if nobody else has resources allocated
86963fa9f4cSJonathan Chen 		 * within the window.
87063fa9f4cSJonathan Chen 		 * (XXX: Perhaps there might be a better way to do this?)
87163fa9f4cSJonathan Chen 		 */
87263fa9f4cSJonathan Chen 		rid = 0;
87321677473SWarner Losh 		res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0,
87421677473SWarner Losh 		    (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags);
87563fa9f4cSJonathan Chen 		start = rman_get_start(res);
87663fa9f4cSJonathan Chen 		end = rman_get_end(res);
87763fa9f4cSJonathan Chen 		DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end));
87863fa9f4cSJonathan Chen 		/*
87963fa9f4cSJonathan Chen 		 * Now that we know the region is free, release it and hand it
88021677473SWarner Losh 		 * out piece by piece.
88163fa9f4cSJonathan Chen 		 */
88263fa9f4cSJonathan Chen 		bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res);
88363fa9f4cSJonathan Chen 		for (tmp = 0; tmp < count; tmp++) {
88463fa9f4cSJonathan Chen 			if (barlist[tmp]->res == NULL &&
88563fa9f4cSJonathan Chen 			    barlist[tmp]->type == SYS_RES_IOPORT) {
88663fa9f4cSJonathan Chen 				barlist[tmp]->res = bus_alloc_resource(cbdev,
88763fa9f4cSJonathan Chen 				    barlist[tmp]->type, &barlist[tmp]->rid,
88863fa9f4cSJonathan Chen 				    start, end, barlist[tmp]->count,
88963fa9f4cSJonathan Chen 				    rman_make_alignment_flags(
89063fa9f4cSJonathan Chen 				    barlist[tmp]->count));
89163fa9f4cSJonathan Chen 				if (barlist[tmp]->res == NULL) {
89263fa9f4cSJonathan Chen 					DEVPRINTF((cbdev, "Cannot pre-allocate "
89363fa9f4cSJonathan Chen 					    "IO port for cardbus device\n"));
894214c0b3dSWarner Losh 					free(barlist, M_DEVBUF);
895a3133b58SWarner Losh 					return (ENOMEM);
89663fa9f4cSJonathan Chen 				}
89763fa9f4cSJonathan Chen 				barlist[tmp]->start =
89863fa9f4cSJonathan Chen 				    rman_get_start(barlist[tmp]->res);
89963fa9f4cSJonathan Chen 				barlist[tmp]->end =
90063fa9f4cSJonathan Chen 				    rman_get_end(barlist[tmp]->res);
90163fa9f4cSJonathan Chen 			pci_write_config(child, barlist[tmp]->rid,
90263fa9f4cSJonathan Chen 			    barlist[tmp]->start, 4);
90363fa9f4cSJonathan Chen 			DEVPRINTF((cbdev, "IO port rid=%x at %lx-%lx\n",
90463fa9f4cSJonathan Chen 			    barlist[tmp]->rid, barlist[tmp]->start,
90563fa9f4cSJonathan Chen 			    barlist[tmp]->end));
90663fa9f4cSJonathan Chen 			}
90763fa9f4cSJonathan Chen 		}
90863fa9f4cSJonathan Chen 	}
90963fa9f4cSJonathan Chen 
91063fa9f4cSJonathan Chen 	/* Allocate IRQ */
91163fa9f4cSJonathan Chen 	rid = 0;
91263fa9f4cSJonathan Chen 	res = bus_alloc_resource(cbdev, SYS_RES_IRQ, &rid, 0, ~0UL, 1,
91363fa9f4cSJonathan Chen 	    RF_SHAREABLE);
91421677473SWarner Losh 	resource_list_add(&dinfo->pci.resources, SYS_RES_IRQ, rid,
91521677473SWarner Losh 	    rman_get_start(res), rman_get_end(res), 1);
91621677473SWarner Losh 	rle = resource_list_find(&dinfo->pci.resources, SYS_RES_IRQ, rid);
91721677473SWarner Losh 	rle->res = res;
91821677473SWarner Losh 	dinfo->pci.cfg.intline = rman_get_start(res);
91921677473SWarner Losh 	pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1);
92063fa9f4cSJonathan Chen 
921214c0b3dSWarner Losh 	free(barlist, M_DEVBUF);
922a3133b58SWarner Losh 	return (0);
92363fa9f4cSJonathan Chen }
92463fa9f4cSJonathan Chen 
92563fa9f4cSJonathan Chen /*
92663fa9f4cSJonathan Chen  * Adding a memory/io resource (sans CIS)
92763fa9f4cSJonathan Chen  */
92863fa9f4cSJonathan Chen 
92963fa9f4cSJonathan Chen static void
93063fa9f4cSJonathan Chen cardbus_add_map(device_t cbdev, device_t child, int reg)
93163fa9f4cSJonathan Chen {
93263fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
93321677473SWarner Losh 	struct resource_list_entry *rle;
93466e390feSWarner Losh 	uint32_t size;
93566e390feSWarner Losh 	uint32_t testval;
93663fa9f4cSJonathan Chen 	int type;
93763fa9f4cSJonathan Chen 
93821677473SWarner Losh 	SLIST_FOREACH(rle, &dinfo->pci.resources, link) {
93921677473SWarner Losh 		if (rle->rid == reg)
94063fa9f4cSJonathan Chen 			return;
94121677473SWarner Losh 	}
94263fa9f4cSJonathan Chen 
94363fa9f4cSJonathan Chen 	if (reg == CARDBUS_ROM_REG)
94463fa9f4cSJonathan Chen 		testval = CARDBUS_ROM_ADDRMASK;
94563fa9f4cSJonathan Chen 	else
94663fa9f4cSJonathan Chen 		testval = ~0;
94763fa9f4cSJonathan Chen 
94863fa9f4cSJonathan Chen 	pci_write_config(child, reg, testval, 4);
94963fa9f4cSJonathan Chen 	testval = pci_read_config(child, reg, 4);
95063fa9f4cSJonathan Chen 
95163fa9f4cSJonathan Chen 	if (testval == ~0 || testval == 0)
95263fa9f4cSJonathan Chen 		return;
95363fa9f4cSJonathan Chen 
95463fa9f4cSJonathan Chen 	if ((testval & 1) == 0)
95563fa9f4cSJonathan Chen 		type = SYS_RES_MEMORY;
95663fa9f4cSJonathan Chen 	else
95763fa9f4cSJonathan Chen 		type = SYS_RES_IOPORT;
95863fa9f4cSJonathan Chen 
95963fa9f4cSJonathan Chen 	size = CARDBUS_MAPREG_MEM_SIZE(testval);
96021677473SWarner Losh 	device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n",
96121677473SWarner Losh 	    reg, size);
96221677473SWarner Losh 	resource_list_add(&dinfo->pci.resources, type, reg, 0UL, ~0UL, size);
96363fa9f4cSJonathan Chen }
96463fa9f4cSJonathan Chen 
96563fa9f4cSJonathan Chen static void
96663fa9f4cSJonathan Chen cardbus_pickup_maps(device_t cbdev, device_t child)
96763fa9f4cSJonathan Chen {
96863fa9f4cSJonathan Chen 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
96963fa9f4cSJonathan Chen 	struct cardbus_quirk *q;
97063fa9f4cSJonathan Chen 	int reg;
97163fa9f4cSJonathan Chen 
97263fa9f4cSJonathan Chen 	/*
97363fa9f4cSJonathan Chen 	 * Try to pick up any resources that was not specified in CIS.
97463fa9f4cSJonathan Chen 	 * Some devices (eg, 3c656) does not list all resources required by
97563fa9f4cSJonathan Chen 	 * the driver in its CIS.
97663fa9f4cSJonathan Chen 	 * XXX: should we do this or use quirks?
97763fa9f4cSJonathan Chen 	 */
9787ba175acSWarner Losh 	for (reg = 0; reg < dinfo->pci.cfg.nummaps; reg++) {
97963fa9f4cSJonathan Chen 		cardbus_add_map(cbdev, child, PCIR_MAPS + reg * 4);
98063fa9f4cSJonathan Chen 	}
98163fa9f4cSJonathan Chen 
98263fa9f4cSJonathan Chen 	for (q = &cardbus_quirks[0]; q->devid; q++) {
98321677473SWarner Losh 		if (q->devid == ((dinfo->pci.cfg.device << 16) | dinfo->pci.cfg.vendor)
98463fa9f4cSJonathan Chen 		    && q->type == CARDBUS_QUIRK_MAP_REG) {
98563fa9f4cSJonathan Chen 			cardbus_add_map(cbdev, child, q->arg1);
98663fa9f4cSJonathan Chen 		}
98763fa9f4cSJonathan Chen 	}
98863fa9f4cSJonathan Chen }
98963fa9f4cSJonathan Chen 
9900c95c705SJonathan Chen int
99166e390feSWarner Losh cardbus_cis_read(device_t cbdev, device_t child, uint8_t id,
9920c95c705SJonathan Chen     struct cis_tupleinfo **buff, int *nret)
9930c95c705SJonathan Chen {
9940c95c705SJonathan Chen 	struct tuple_callbacks cisread_callbacks[] = {
9950c95c705SJonathan Chen 		MAKETUPLE(NULL,			nothing),
9960c95c705SJonathan Chen 		/* first entry will be overwritten */
9970c95c705SJonathan Chen 		MAKETUPLE(NULL,			nothing),
9980c95c705SJonathan Chen 		MAKETUPLE(DEVICE,		nothing),
9990c95c705SJonathan Chen 		MAKETUPLE(LONG_LINK_CB,		unhandled),
10000c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
10010c95c705SJonathan Chen 		MAKETUPLE(CONFIG_CB,		nothing),
10020c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY_CB,	nothing),
10030c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
10040c95c705SJonathan Chen 		MAKETUPLE(BAR,			nothing),
10050c95c705SJonathan Chen 		MAKETUPLE(PWR_MGMNT,		nothing),
10060c95c705SJonathan Chen 		MAKETUPLE(EXTDEVICE,		nothing),
10070c95c705SJonathan Chen 		MAKETUPLE(CHECKSUM,		nothing),
10080c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
10090c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
10100c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		nothing),
10110c95c705SJonathan Chen 		MAKETUPLE(NO_LINK,		nothing),
10120c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		nothing),
10130c95c705SJonathan Chen 		MAKETUPLE(ALTSTR,		nothing),
10140c95c705SJonathan Chen 		MAKETUPLE(DEVICE_A,		nothing),
10150c95c705SJonathan Chen 		MAKETUPLE(JEDEC_C,		nothing),
10160c95c705SJonathan Chen 		MAKETUPLE(JEDEC_A,		nothing),
10170c95c705SJonathan Chen 		MAKETUPLE(CONFIG,		nothing),
10180c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY,	nothing),
10190c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OC,		nothing),
10200c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OA,		nothing),
10210c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO,		nothing),
10220c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO_A,		nothing),
10230c95c705SJonathan Chen 		MAKETUPLE(MANFID,		nothing),
10240c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		nothing),
10250c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		nothing),
10260c95c705SJonathan Chen 		MAKETUPLE(SWIL,			nothing),
10270c95c705SJonathan Chen 		MAKETUPLE(VERS_2,		nothing),
10280c95c705SJonathan Chen 		MAKETUPLE(FORMAT,		nothing),
10290c95c705SJonathan Chen 		MAKETUPLE(GEOMETRY,		nothing),
10300c95c705SJonathan Chen 		MAKETUPLE(BYTEORDER,		nothing),
10310c95c705SJonathan Chen 		MAKETUPLE(DATE,			nothing),
10320c95c705SJonathan Chen 		MAKETUPLE(BATTERY,		nothing),
10330c95c705SJonathan Chen 		MAKETUPLE(ORG,			nothing),
10340c95c705SJonathan Chen 		MAKETUPLE(END,			end),
10350c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		nothing),
10360c95c705SJonathan Chen 	};
10370c95c705SJonathan Chen 	int ret;
10380c95c705SJonathan Chen 
10390c95c705SJonathan Chen 	cisread_callbacks[0].id = id;
10400c95c705SJonathan Chen 	cisread_callbacks[0].name = "COPY";
10410c95c705SJonathan Chen 	cisread_callbacks[0].func = decode_tuple_copy;
10420c95c705SJonathan Chen 	ncisread_buf = 0;
10430c95c705SJonathan Chen 	cisread_buf = NULL;
1044255b159fSJonathan Chen 	ret = cardbus_parse_cis(cbdev, child, cisread_callbacks);
10450c95c705SJonathan Chen 
10460c95c705SJonathan Chen 	*buff = cisread_buf;
10470c95c705SJonathan Chen 	*nret = ncisread_buf;
1048a3133b58SWarner Losh 	return (ret);
10490c95c705SJonathan Chen }
10500c95c705SJonathan Chen 
10510c95c705SJonathan Chen void
1052255b159fSJonathan Chen cardbus_cis_free(device_t cbdev, struct cis_tupleinfo *buff, int *nret)
10530c95c705SJonathan Chen {
10540c95c705SJonathan Chen 	int i;
10556f39832cSPeter Wemm 	for (i = 0; i < *nret; i++)
10560c95c705SJonathan Chen 		free(buff[i].data, M_DEVBUF);
10576f39832cSPeter Wemm 	if (*nret > 0)
10580c95c705SJonathan Chen 		free(buff, M_DEVBUF);
10590c95c705SJonathan Chen }
10600c95c705SJonathan Chen 
10610c95c705SJonathan Chen int
1062255b159fSJonathan Chen cardbus_do_cis(device_t cbdev, device_t child)
10630c95c705SJonathan Chen {
106463fa9f4cSJonathan Chen 	int ret;
10650c95c705SJonathan Chen 	struct tuple_callbacks init_callbacks[] = {
10660c95c705SJonathan Chen 		MAKETUPLE(NULL,			generic),
10670c95c705SJonathan Chen 		MAKETUPLE(DEVICE,		generic),
10680c95c705SJonathan Chen 		MAKETUPLE(LONG_LINK_CB,		unhandled),
10690c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
10700c95c705SJonathan Chen 		MAKETUPLE(CONFIG_CB,		generic),
10710c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY_CB,	generic),
10720c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
10730c95c705SJonathan Chen 		MAKETUPLE(BAR,			bar),
10740c95c705SJonathan Chen 		MAKETUPLE(PWR_MGMNT,		generic),
10750c95c705SJonathan Chen 		MAKETUPLE(EXTDEVICE,		generic),
10760c95c705SJonathan Chen 		MAKETUPLE(CHECKSUM,		generic),
10770c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
10780c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
10790c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		linktarget),
10800c95c705SJonathan Chen 		MAKETUPLE(NO_LINK,		generic),
10810c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		vers_1),
10820c95c705SJonathan Chen 		MAKETUPLE(ALTSTR,		generic),
10830c95c705SJonathan Chen 		MAKETUPLE(DEVICE_A,		generic),
10840c95c705SJonathan Chen 		MAKETUPLE(JEDEC_C,		generic),
10850c95c705SJonathan Chen 		MAKETUPLE(JEDEC_A,		generic),
10860c95c705SJonathan Chen 		MAKETUPLE(CONFIG,		generic),
10870c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY,	generic),
10880c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OC,		generic),
10890c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OA,		generic),
10900c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO,		generic),
10910c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO_A,		generic),
10920c95c705SJonathan Chen 		MAKETUPLE(MANFID,		manfid),
10930c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		funcid),
10940c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		funce),
10950c95c705SJonathan Chen 		MAKETUPLE(SWIL,			generic),
10960c95c705SJonathan Chen 		MAKETUPLE(VERS_2,		generic),
10970c95c705SJonathan Chen 		MAKETUPLE(FORMAT,		generic),
10980c95c705SJonathan Chen 		MAKETUPLE(GEOMETRY,		generic),
10990c95c705SJonathan Chen 		MAKETUPLE(BYTEORDER,		generic),
11000c95c705SJonathan Chen 		MAKETUPLE(DATE,			generic),
11010c95c705SJonathan Chen 		MAKETUPLE(BATTERY,		generic),
11020c95c705SJonathan Chen 		MAKETUPLE(ORG,			generic),
11030c95c705SJonathan Chen 		MAKETUPLE(END,			end),
11040c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		generic),
11050c95c705SJonathan Chen 	};
110663fa9f4cSJonathan Chen 
110763fa9f4cSJonathan Chen 	ret = cardbus_parse_cis(cbdev, child, init_callbacks);
110863fa9f4cSJonathan Chen 	if (ret < 0)
1109a3133b58SWarner Losh 		return (ret);
111063fa9f4cSJonathan Chen 	cardbus_pickup_maps(cbdev, child);
1111a3133b58SWarner Losh 	return (cardbus_alloc_resources(cbdev, child));
11120c95c705SJonathan Chen }
1113