xref: /freebsd/sys/dev/cardbus/cardbus_cis.c (revision 0db7e66cdc52a79ee5bd40d02c0241e98771278e)
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>
400db7e66cSJonathan Chen 
410db7e66cSJonathan Chen #include <sys/bus.h>
420db7e66cSJonathan Chen #include <machine/bus.h>
430db7e66cSJonathan Chen #include <machine/resource.h>
440db7e66cSJonathan Chen #include <sys/rman.h>
450db7e66cSJonathan Chen 
460db7e66cSJonathan Chen #include <pci/pcivar.h>
470db7e66cSJonathan Chen 
480db7e66cSJonathan Chen #include <dev/cardbus/cardbusreg.h>
490db7e66cSJonathan Chen #include <dev/cardbus/cardbus_cis.h>
500db7e66cSJonathan Chen 
510db7e66cSJonathan Chen #include "pccbb_if.h"
520db7e66cSJonathan Chen 
530db7e66cSJonathan Chen #if defined CARDBUS_DEBUG
540db7e66cSJonathan Chen #define STATIC
550db7e66cSJonathan Chen #define DPRINTF(a) printf a
560db7e66cSJonathan Chen #define DEVPRINTF(x) device_printf x
570db7e66cSJonathan Chen #else
580db7e66cSJonathan Chen #define STATIC static
590db7e66cSJonathan Chen #define DPRINTF(a)
600db7e66cSJonathan Chen #define DEVPRINTF(x)
610db7e66cSJonathan Chen #endif
620db7e66cSJonathan Chen 
630db7e66cSJonathan Chen #if !defined(lint)
640db7e66cSJonathan Chen static const char rcsid[] =
650db7e66cSJonathan Chen   "$FreeBSD$";
660db7e66cSJonathan Chen #endif
670db7e66cSJonathan Chen 
680db7e66cSJonathan Chen struct tupleinfo;
690db7e66cSJonathan Chen 
700db7e66cSJonathan Chen static int decode_tuples(device_t dev, device_t child,
710db7e66cSJonathan Chen 			 u_int8_t *tuples, int len);
720db7e66cSJonathan Chen static int cardbus_read_exrom_cis(device_t dev, struct resource *res,
730db7e66cSJonathan Chen 				  int cis, u_int8_t* tuple, int len);
740db7e66cSJonathan Chen static int cardbus_read_tuples_conf(device_t dev, device_t child,
750db7e66cSJonathan Chen 				    u_int32_t cis_ptr, u_int8_t *tuples,
760db7e66cSJonathan Chen 				    int len);
770db7e66cSJonathan Chen static int cardbus_read_tuples_mem(device_t dev, device_t child, int space,
780db7e66cSJonathan Chen 				   u_int32_t cis_ptr, u_int8_t *tuples,
790db7e66cSJonathan Chen 				   int len);
800db7e66cSJonathan Chen static int cardbus_read_tuples(device_t dev, device_t child, u_int8_t *tuples,
810db7e66cSJonathan Chen 			       int len);
820db7e66cSJonathan Chen 
830db7e66cSJonathan Chen #define DECODE_PROTOTYPE(NAME) static int decode_tuple_ ## NAME		\
840db7e66cSJonathan Chen 		(device_t dev, device_t child, int id, int len, 	\
850db7e66cSJonathan Chen 		 u_int8_t *buff, struct tupleinfo *info)
860db7e66cSJonathan Chen DECODE_PROTOTYPE(generic);
870db7e66cSJonathan Chen DECODE_PROTOTYPE(bar);
880db7e66cSJonathan Chen DECODE_PROTOTYPE(linktarget);
890db7e66cSJonathan Chen DECODE_PROTOTYPE(vers_1);
900db7e66cSJonathan Chen DECODE_PROTOTYPE(manfid);
910db7e66cSJonathan Chen DECODE_PROTOTYPE(funcid);
920db7e66cSJonathan Chen DECODE_PROTOTYPE(funce);
930db7e66cSJonathan Chen DECODE_PROTOTYPE(end);
940db7e66cSJonathan Chen DECODE_PROTOTYPE(unhandled);
950db7e66cSJonathan Chen 
960db7e66cSJonathan Chen static struct tupleinfo {
970db7e66cSJonathan Chen 	u_int8_t id;
980db7e66cSJonathan Chen 	char* name;
990db7e66cSJonathan Chen 	int (*func)(device_t dev, device_t child, int id, int len,
1000db7e66cSJonathan Chen 		    u_int8_t *buff, struct tupleinfo *info);
1010db7e66cSJonathan Chen } tupleinfo[] = {
1020db7e66cSJonathan Chen #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
1030db7e66cSJonathan Chen 	MAKETUPLE(NULL,			generic),
1040db7e66cSJonathan Chen 	MAKETUPLE(DEVICE,		generic),
1050db7e66cSJonathan Chen 	MAKETUPLE(LONG_LINK_CB,		unhandled),
1060db7e66cSJonathan Chen 	MAKETUPLE(INDIRECT,		unhandled),
1070db7e66cSJonathan Chen 	MAKETUPLE(CONFIG_CB,		generic),
1080db7e66cSJonathan Chen 	MAKETUPLE(CFTABLE_ENTRY_CB,	generic),
1090db7e66cSJonathan Chen 	MAKETUPLE(LONGLINK_MFC,		unhandled),
1100db7e66cSJonathan Chen 	MAKETUPLE(BAR,			bar),
1110db7e66cSJonathan Chen 	MAKETUPLE(PWR_MGMNT,		generic),
1120db7e66cSJonathan Chen 	MAKETUPLE(EXTDEVICE,		generic),
1130db7e66cSJonathan Chen 	MAKETUPLE(CHECKSUM,		generic),
1140db7e66cSJonathan Chen 	MAKETUPLE(LONGLINK_A,		unhandled),
1150db7e66cSJonathan Chen 	MAKETUPLE(LONGLINK_C,		unhandled),
1160db7e66cSJonathan Chen 	MAKETUPLE(LINKTARGET,		linktarget),
1170db7e66cSJonathan Chen 	MAKETUPLE(NO_LINK,		generic),
1180db7e66cSJonathan Chen 	MAKETUPLE(VERS_1,		vers_1),
1190db7e66cSJonathan Chen 	MAKETUPLE(ALTSTR,		generic),
1200db7e66cSJonathan Chen 	MAKETUPLE(DEVICE_A,		generic),
1210db7e66cSJonathan Chen 	MAKETUPLE(JEDEC_C,		generic),
1220db7e66cSJonathan Chen 	MAKETUPLE(JEDEC_A,		generic),
1230db7e66cSJonathan Chen 	MAKETUPLE(CONFIG,		generic),
1240db7e66cSJonathan Chen 	MAKETUPLE(CFTABLE_ENTRY,	generic),
1250db7e66cSJonathan Chen 	MAKETUPLE(DEVICE_OC,		generic),
1260db7e66cSJonathan Chen 	MAKETUPLE(DEVICE_OA,		generic),
1270db7e66cSJonathan Chen 	MAKETUPLE(DEVICE_GEO,		generic),
1280db7e66cSJonathan Chen 	MAKETUPLE(DEVICE_GEO_A,		generic),
1290db7e66cSJonathan Chen 	MAKETUPLE(MANFID,		manfid),
1300db7e66cSJonathan Chen 	MAKETUPLE(FUNCID,		funcid),
1310db7e66cSJonathan Chen 	MAKETUPLE(FUNCE,		funce),
1320db7e66cSJonathan Chen 	MAKETUPLE(SWIL,			generic),
1330db7e66cSJonathan Chen 	MAKETUPLE(VERS_2,		generic),
1340db7e66cSJonathan Chen 	MAKETUPLE(FORMAT,		generic),
1350db7e66cSJonathan Chen 	MAKETUPLE(GEOMETRY,		generic),
1360db7e66cSJonathan Chen 	MAKETUPLE(BYTEORDER,		generic),
1370db7e66cSJonathan Chen 	MAKETUPLE(DATE,			generic),
1380db7e66cSJonathan Chen 	MAKETUPLE(BATTERY,		generic),
1390db7e66cSJonathan Chen 	MAKETUPLE(ORG,			generic),
1400db7e66cSJonathan Chen 	MAKETUPLE(END,			 end),
1410db7e66cSJonathan Chen #undef MAKETUPLE
1420db7e66cSJonathan Chen };
1430db7e66cSJonathan Chen 
1440db7e66cSJonathan Chen static char* funcnames[] = {
1450db7e66cSJonathan Chen 	"Multi-Functioned",
1460db7e66cSJonathan Chen 	"Memory",
1470db7e66cSJonathan Chen 	"Serial Port",
1480db7e66cSJonathan Chen 	"Parallel Port",
1490db7e66cSJonathan Chen 	"Fixed Disk",
1500db7e66cSJonathan Chen 	"Video Adaptor",
1510db7e66cSJonathan Chen 	"Network Adaptor",
1520db7e66cSJonathan Chen 	"AIMS",
1530db7e66cSJonathan Chen 	"SCSI",
1540db7e66cSJonathan Chen 	"Security"
1550db7e66cSJonathan Chen };
1560db7e66cSJonathan Chen 
1570db7e66cSJonathan Chen DECODE_PROTOTYPE(generic)
1580db7e66cSJonathan Chen {
1590db7e66cSJonathan Chen #ifdef CARDBUS_DEBUG
1600db7e66cSJonathan Chen 	int i;
1610db7e66cSJonathan Chen 
1620db7e66cSJonathan Chen 	if (info)
1630db7e66cSJonathan Chen 		printf ("TUPLE: %s [%d]:", info->name, len);
1640db7e66cSJonathan Chen 	else
1650db7e66cSJonathan Chen 		printf ("TUPLE: Unknown(0x%02x) [%d]:", id, len);
1660db7e66cSJonathan Chen 
1670db7e66cSJonathan Chen 	for (i = 0; i < len; i++) {
1680db7e66cSJonathan Chen 		if (i % 0x10 == 0 && len > 0x10)
1690db7e66cSJonathan Chen 			printf ("\n       0x%02x:", i);
1700db7e66cSJonathan Chen 		printf (" %02x", buff[i]);
1710db7e66cSJonathan Chen 	}
1720db7e66cSJonathan Chen 	printf ("\n");
1730db7e66cSJonathan Chen #endif
1740db7e66cSJonathan Chen 	return 0;
1750db7e66cSJonathan Chen }
1760db7e66cSJonathan Chen 
1770db7e66cSJonathan Chen DECODE_PROTOTYPE(linktarget)
1780db7e66cSJonathan Chen {
1790db7e66cSJonathan Chen 	if (len != 3 || buff[0] != 'C' || buff[1] != 'I' || buff[2] != 'S') {
1800db7e66cSJonathan Chen 		printf("Invalid data for CIS Link Target!\n");
1810db7e66cSJonathan Chen 		decode_tuple_generic(dev, child, id, len, buff, info);
1820db7e66cSJonathan Chen 		return EINVAL;
1830db7e66cSJonathan Chen 	}
1840db7e66cSJonathan Chen 	return 0;
1850db7e66cSJonathan Chen }
1860db7e66cSJonathan Chen 
1870db7e66cSJonathan Chen DECODE_PROTOTYPE(vers_1)
1880db7e66cSJonathan Chen {
1890db7e66cSJonathan Chen 	int i;
1900db7e66cSJonathan Chen 	printf("Product version: %d.%d\n", buff[0], buff[1]);
1910db7e66cSJonathan Chen 	printf("Product name: ");
1920db7e66cSJonathan Chen 	for (i = 2; i < len; i++) {
1930db7e66cSJonathan Chen 		if (buff[i] == '\0')
1940db7e66cSJonathan Chen 			printf (" | ");
1950db7e66cSJonathan Chen 		else if (buff[i] == 0xff)
1960db7e66cSJonathan Chen 			break;
1970db7e66cSJonathan Chen 		else
1980db7e66cSJonathan Chen 			printf("%c", buff[i]);
1990db7e66cSJonathan Chen 	}
2000db7e66cSJonathan Chen 	printf("\n");
2010db7e66cSJonathan Chen 	return 0;
2020db7e66cSJonathan Chen }
2030db7e66cSJonathan Chen 
2040db7e66cSJonathan Chen DECODE_PROTOTYPE(funcid)
2050db7e66cSJonathan Chen {
2060db7e66cSJonathan Chen 	int i;
2070db7e66cSJonathan Chen 	int numnames = sizeof(funcnames)/sizeof(funcnames[0]);
2080db7e66cSJonathan Chen 
2090db7e66cSJonathan Chen 	printf("Functions: ");
2100db7e66cSJonathan Chen 	for(i = 0; i < len; i++) {
2110db7e66cSJonathan Chen 		if (buff[i] < numnames)
2120db7e66cSJonathan Chen 			printf ("%s", funcnames[buff[i]]);
2130db7e66cSJonathan Chen 		else
2140db7e66cSJonathan Chen 			printf ("Unknown(%d)", buff[i]);
2150db7e66cSJonathan Chen 		if (i < len-1) printf(", ");
2160db7e66cSJonathan Chen 	}
2170db7e66cSJonathan Chen 	printf ("\n");
2180db7e66cSJonathan Chen 	return 0;
2190db7e66cSJonathan Chen }
2200db7e66cSJonathan Chen 
2210db7e66cSJonathan Chen DECODE_PROTOTYPE(manfid)
2220db7e66cSJonathan Chen {
2230db7e66cSJonathan Chen 	int i;
2240db7e66cSJonathan Chen 	printf ("Manufacturer ID: ");
2250db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2260db7e66cSJonathan Chen 		printf("%02x", buff[i]);
2270db7e66cSJonathan Chen 	printf("\n");
2280db7e66cSJonathan Chen 	return 0;
2290db7e66cSJonathan Chen }
2300db7e66cSJonathan Chen 
2310db7e66cSJonathan Chen DECODE_PROTOTYPE(funce)
2320db7e66cSJonathan Chen {
2330db7e66cSJonathan Chen 	int i;
2340db7e66cSJonathan Chen 	printf ("Function Extension: ");
2350db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2360db7e66cSJonathan Chen 		printf("%02x", buff[i]);
2370db7e66cSJonathan Chen 	printf("\n");
2380db7e66cSJonathan Chen 	return 0;
2390db7e66cSJonathan Chen }
2400db7e66cSJonathan Chen 
2410db7e66cSJonathan Chen DECODE_PROTOTYPE(bar)
2420db7e66cSJonathan Chen {
2430db7e66cSJonathan Chen 	if (len != 6) {
2440db7e66cSJonathan Chen 		printf ("*** ERROR *** BAR length not 6 (%d)\n", len);
2450db7e66cSJonathan Chen 		return EINVAL;
2460db7e66cSJonathan Chen 	} else {
2470db7e66cSJonathan Chen 		int type;
2480db7e66cSJonathan Chen 		int reg;
2490db7e66cSJonathan Chen 		u_int32_t bar;
2500db7e66cSJonathan Chen 		u_int32_t start, len;
2510db7e66cSJonathan Chen 		struct resource *res;
2520db7e66cSJonathan Chen 
2530db7e66cSJonathan Chen 		reg = *(u_int16_t*)buff;
2540db7e66cSJonathan Chen 		len = *(u_int32_t*)(buff+2);
2550db7e66cSJonathan Chen 		if (reg & TPL_BAR_REG_AS) {
2560db7e66cSJonathan Chen 			type = SYS_RES_IOPORT;
2570db7e66cSJonathan Chen 		} else {
2580db7e66cSJonathan Chen 			type = SYS_RES_MEMORY;
2590db7e66cSJonathan Chen 		}
2600db7e66cSJonathan Chen 		bar = (reg & TPL_BAR_REG_ASI_MASK) - 1;
2610db7e66cSJonathan Chen 		if (bar < 0 || bar > 6) {
2620db7e66cSJonathan Chen 			device_printf(dev, "Invalid BAR number: %02x(%02x)\n",
2630db7e66cSJonathan Chen 				      reg, bar);
2640db7e66cSJonathan Chen 			return EINVAL;
2650db7e66cSJonathan Chen 		}
2660db7e66cSJonathan Chen 		bar = CARDBUS_BASE0_REG + bar * 4;
2670db7e66cSJonathan Chen 		DEVPRINTF((dev, "Opening BAR: type=%s, bar=%02x, len=%04x\n",
2680db7e66cSJonathan Chen 			   (type==SYS_RES_MEMORY)?"MEM":"IO", bar, len));
2690db7e66cSJonathan Chen 		res = bus_generic_alloc_resource(child, child, type, &reg, 0,
2700db7e66cSJonathan Chen 			 ~0, len, rman_make_alignment_flags(len) | RF_ACTIVE);
2710db7e66cSJonathan Chen 		if (res == NULL) {
2720db7e66cSJonathan Chen 			device_printf(dev, "Cannot allocate BAR %02x\n", reg);
2730db7e66cSJonathan Chen 		} else {
2740db7e66cSJonathan Chen 			start = rman_get_start(res);
2750db7e66cSJonathan Chen 			if (reg == CARDBUS_ROM_REG) start |= 1;
2760db7e66cSJonathan Chen 			pci_write_config(child, reg, start, 4);
2770db7e66cSJonathan Chen 		}
2780db7e66cSJonathan Chen 	}
2790db7e66cSJonathan Chen 	return 0;
2800db7e66cSJonathan Chen }
2810db7e66cSJonathan Chen 
2820db7e66cSJonathan Chen DECODE_PROTOTYPE(unhandled)
2830db7e66cSJonathan Chen {
2840db7e66cSJonathan Chen 	printf ("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
2850db7e66cSJonathan Chen 	return -1;
2860db7e66cSJonathan Chen }
2870db7e66cSJonathan Chen 
2880db7e66cSJonathan Chen DECODE_PROTOTYPE(end)
2890db7e66cSJonathan Chen {
2900db7e66cSJonathan Chen 	return -1;
2910db7e66cSJonathan Chen }
2920db7e66cSJonathan Chen 
2930db7e66cSJonathan Chen static int decode_tuples(device_t dev, device_t child,
2940db7e66cSJonathan Chen 			 u_int8_t *tuples, int len)
2950db7e66cSJonathan Chen {
2960db7e66cSJonathan Chen 	int ret = 0;
2970db7e66cSJonathan Chen 	if (CISTPL_LINKTARGET != *tuples) {
2980db7e66cSJonathan Chen 		device_printf(dev, "CIS does not start with link target\n");
2990db7e66cSJonathan Chen 		return EINVAL;
3000db7e66cSJonathan Chen 	}
3010db7e66cSJonathan Chen 	do {
3020db7e66cSJonathan Chen 		int i;
3030db7e66cSJonathan Chen 		int numtupleids = sizeof(tupleinfo)/sizeof(tupleinfo[0]);
3040db7e66cSJonathan Chen 		for (i = 0; i < numtupleids; i++) {
3050db7e66cSJonathan Chen 			if (tuples[0] == tupleinfo[i].id) {
3060db7e66cSJonathan Chen 				ret = tupleinfo[i].func(dev, child, tuples[0],
3070db7e66cSJonathan Chen 							tuples[1], tuples+2,
3080db7e66cSJonathan Chen 							&tupleinfo[i]);
3090db7e66cSJonathan Chen 				break;
3100db7e66cSJonathan Chen 			}
3110db7e66cSJonathan Chen 		}
3120db7e66cSJonathan Chen 		if (i == numtupleids)
3130db7e66cSJonathan Chen 			ret = decode_tuple_generic(dev, child, tuples[0],
3140db7e66cSJonathan Chen 						   tuples[1], tuples+2, NULL);
3150db7e66cSJonathan Chen 
3160db7e66cSJonathan Chen 		len -= (tuples[1]+2);
3170db7e66cSJonathan Chen 		tuples += tuples[1]+2;
3180db7e66cSJonathan Chen 	} while (len > 0 && ret == 0);
3190db7e66cSJonathan Chen 
3200db7e66cSJonathan Chen 	if (ret < 0) return 0;
3210db7e66cSJonathan Chen 	else if (ret != 0) return ret;
3220db7e66cSJonathan Chen 	else {
3230db7e66cSJonathan Chen 		device_printf(dev, "CIS too long or END not encountered!\n");
3240db7e66cSJonathan Chen 		return EFBIG;
3250db7e66cSJonathan Chen 	}
3260db7e66cSJonathan Chen }
3270db7e66cSJonathan Chen 
3280db7e66cSJonathan Chen static int
3290db7e66cSJonathan Chen cardbus_read_exrom_cis(device_t dev, struct resource *res, int cis,
3300db7e66cSJonathan Chen 		       u_int8_t* tuple, int len)
3310db7e66cSJonathan Chen {
3320db7e66cSJonathan Chen #define READROM(rom, type, offset)				       \
3330db7e66cSJonathan Chen 	(*((u_int ## type ##_t *)(((unsigned char*)rom) + offset)))
3340db7e66cSJonathan Chen 
3350db7e66cSJonathan Chen 	u_int32_t addr = 0; /* offset of current rom image */
3360db7e66cSJonathan Chen 	int romnum = 0;
3370db7e66cSJonathan Chen 	unsigned char *data;
3380db7e66cSJonathan Chen 	u_int32_t imagesize;
3390db7e66cSJonathan Chen 	unsigned char *image;
3400db7e66cSJonathan Chen 	int imagenum;
3410db7e66cSJonathan Chen 
3420db7e66cSJonathan Chen 	image = (unsigned char*)rman_get_virtual(res);
3430db7e66cSJonathan Chen 	imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(cis);
3440db7e66cSJonathan Chen 	do {
3450db7e66cSJonathan Chen 		if (READROM(image, 16, CARDBUS_EXROM_SIGNATURE) != 0xaa55) {
3460db7e66cSJonathan Chen 			device_printf (dev, "Bad header in rom %d: %04x\n",
3470db7e66cSJonathan Chen 				       romnum, *(u_int16_t*)(image +
3480db7e66cSJonathan Chen 				       CARDBUS_EXROM_SIGNATURE));
3490db7e66cSJonathan Chen 			return ENXIO;
3500db7e66cSJonathan Chen 		}
3510db7e66cSJonathan Chen 		data = image + READROM(image, 16, CARDBUS_EXROM_DATA_PTR);
3520db7e66cSJonathan Chen 		imagesize = READROM(data, 16, CARDBUS_EXROM_DATA_IMAGE_LENGTH);
3530db7e66cSJonathan Chen 
3540db7e66cSJonathan Chen 		if(imagesize == 0)
3550db7e66cSJonathan Chen 			/*
3560db7e66cSJonathan Chen 			 * XXX some ROMs seem to have this as zero,
3570db7e66cSJonathan Chen 			 * can we assume this means 1 block?
3580db7e66cSJonathan Chen 			 */
3590db7e66cSJonathan Chen 			imagesize = 1;
3600db7e66cSJonathan Chen 		imagesize <<= 9;
3610db7e66cSJonathan Chen 
3620db7e66cSJonathan Chen 		if (imagenum == romnum) {
3630db7e66cSJonathan Chen 			romnum = -1;
3640db7e66cSJonathan Chen 			memcpy(tuple, image+CARDBUS_CIS_ADDR(cis), len);
3650db7e66cSJonathan Chen 			return 0;
3660db7e66cSJonathan Chen 		}
3670db7e66cSJonathan Chen 
3680db7e66cSJonathan Chen 		addr += imagesize;
3690db7e66cSJonathan Chen 		romnum++;
3700db7e66cSJonathan Chen 	} while ((READROM(data, 8, CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0);
3710db7e66cSJonathan Chen 	device_printf(dev, "Cannot read CIS: Not enough images of rom\n");
3720db7e66cSJonathan Chen 	return ENOENT;
3730db7e66cSJonathan Chen #undef READROM
3740db7e66cSJonathan Chen }
3750db7e66cSJonathan Chen 
3760db7e66cSJonathan Chen static int
3770db7e66cSJonathan Chen cardbus_read_tuples_conf(device_t dev, device_t child, u_int32_t cis_ptr,
3780db7e66cSJonathan Chen 			 u_int8_t *tuples, int len)
3790db7e66cSJonathan Chen {
3800db7e66cSJonathan Chen 	int i, j;
3810db7e66cSJonathan Chen 
3820db7e66cSJonathan Chen 	DEVPRINTF((dev, "reading CIS data from configuration space\n"));
3830db7e66cSJonathan Chen 	for (i = cis_ptr, j = 0; i < len; i += 4) {
3840db7e66cSJonathan Chen 		u_int32_t e = pci_read_config(child, i, 4);
3850db7e66cSJonathan Chen 		tuples[j] = 0xff & e;
3860db7e66cSJonathan Chen 		e >>= 8;
3870db7e66cSJonathan Chen 		tuples[j + 1] = 0xff & e;
3880db7e66cSJonathan Chen 		e >>= 8;
3890db7e66cSJonathan Chen 		tuples[j + 2] = 0xff & e;
3900db7e66cSJonathan Chen 		e >>= 8;
3910db7e66cSJonathan Chen 		tuples[j + 3] = 0xff & e;
3920db7e66cSJonathan Chen 		j += 4;
3930db7e66cSJonathan Chen 	}
3940db7e66cSJonathan Chen 	return 0;
3950db7e66cSJonathan Chen }
3960db7e66cSJonathan Chen 
3970db7e66cSJonathan Chen static int
3980db7e66cSJonathan Chen cardbus_read_tuples_mem(device_t dev, device_t child, int space,
3990db7e66cSJonathan Chen 			u_int32_t cis_ptr, u_int8_t *tuples, int len)
4000db7e66cSJonathan Chen {
4010db7e66cSJonathan Chen 	struct resource *mem;
4020db7e66cSJonathan Chen 	int rid;
4030db7e66cSJonathan Chen 	int ret;
4040db7e66cSJonathan Chen 
4050db7e66cSJonathan Chen 	if(space == CARDBUS_CIS_ASI_ROM) {
4060db7e66cSJonathan Chen 		rid = CARDBUS_ROM_REG;
4070db7e66cSJonathan Chen 		DEVPRINTF((dev, "reading CIS data from ROM\n"));
4080db7e66cSJonathan Chen 	} else {
4090db7e66cSJonathan Chen 		rid = CARDBUS_BASE0_REG + (space - 1) * 4;
4100db7e66cSJonathan Chen 		DEVPRINTF((dev, "reading CIS data from BAR%d\n", space - 1));
4110db7e66cSJonathan Chen 	}
4120db7e66cSJonathan Chen 	mem = bus_alloc_resource(child, SYS_RES_MEMORY, &rid, 0, ~0,
4130db7e66cSJonathan Chen 				 1, RF_ACTIVE);
4140db7e66cSJonathan Chen 	if (mem == NULL) {
4150db7e66cSJonathan Chen 		device_printf(dev, "Failed to get memory for CIS reading\n");
4160db7e66cSJonathan Chen 		return ENOMEM;
4170db7e66cSJonathan Chen 	}
4180db7e66cSJonathan Chen 
4190db7e66cSJonathan Chen 	if(space == CARDBUS_CIS_ASI_ROM) {
4200db7e66cSJonathan Chen 		int s;
4210db7e66cSJonathan Chen 		s = splhigh();
4220db7e66cSJonathan Chen 		ret = cardbus_read_exrom_cis(dev, mem, cis_ptr, tuples, len);
4230db7e66cSJonathan Chen 		splx(s);
4240db7e66cSJonathan Chen 	} else {
4250db7e66cSJonathan Chen 		/* XXX byte order? */
4260db7e66cSJonathan Chen 		memcpy(tuples, (unsigned char*)rman_get_virtual(mem)+cis_ptr,
4270db7e66cSJonathan Chen 		       len);
4280db7e66cSJonathan Chen 		ret = 0;
4290db7e66cSJonathan Chen 	}
4300db7e66cSJonathan Chen 	bus_release_resource(child, SYS_RES_MEMORY, rid, mem);
4310db7e66cSJonathan Chen 	return ret;
4320db7e66cSJonathan Chen }
4330db7e66cSJonathan Chen 
4340db7e66cSJonathan Chen static int
4350db7e66cSJonathan Chen cardbus_read_tuples(device_t dev, device_t child, u_int8_t *tuples, int len)
4360db7e66cSJonathan Chen {
4370db7e66cSJonathan Chen 	u_int32_t cis_ptr = pci_read_config(child, CARDBUS_CIS_REG, 4);
4380db7e66cSJonathan Chen 	int cardbus_space = cis_ptr & CARDBUS_CIS_ASIMASK;
4390db7e66cSJonathan Chen 	int ret = 0;
4400db7e66cSJonathan Chen 	cis_ptr = cis_ptr & CARDBUS_CIS_ADDRMASK;
4410db7e66cSJonathan Chen 
4420db7e66cSJonathan Chen 	switch(cardbus_space) {
4430db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_TUPLE:
4440db7e66cSJonathan Chen 		ret = cardbus_read_tuples_conf(dev, child, cis_ptr, tuples,
4450db7e66cSJonathan Chen 					       len);
4460db7e66cSJonathan Chen 		break;
4470db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR0:
4480db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR1:
4490db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR2:
4500db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR3:
4510db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR4:
4520db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR5:
4530db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_ROM:
4540db7e66cSJonathan Chen 		ret = cardbus_read_tuples_mem(dev, child, cardbus_space,
4550db7e66cSJonathan Chen 					      cis_ptr, tuples, len);
4560db7e66cSJonathan Chen 		break;
4570db7e66cSJonathan Chen 	default:
4580db7e66cSJonathan Chen 		device_printf(dev, "Unable to read CIS: Unknown space: %d\n",
4590db7e66cSJonathan Chen 			      cardbus_space);
4600db7e66cSJonathan Chen 		ret = EINVAL;
4610db7e66cSJonathan Chen 	}
4620db7e66cSJonathan Chen 	return ret;
4630db7e66cSJonathan Chen }
4640db7e66cSJonathan Chen 
4650db7e66cSJonathan Chen int
4660db7e66cSJonathan Chen cardbus_do_cis(device_t dev, device_t child)
4670db7e66cSJonathan Chen {
4680db7e66cSJonathan Chen 	u_int8_t tupledata[MAXTUPLESIZE];
4690db7e66cSJonathan Chen 	int ret;
4700db7e66cSJonathan Chen 
4710db7e66cSJonathan Chen 	bzero(tupledata, MAXTUPLESIZE);
4720db7e66cSJonathan Chen 
4730db7e66cSJonathan Chen 	ret = cardbus_read_tuples(dev, child, tupledata, MAXTUPLESIZE);
4740db7e66cSJonathan Chen 	if (ret != 0) return ret;
4750db7e66cSJonathan Chen 	return decode_tuples(dev, child, tupledata, MAXTUPLESIZE);
4760db7e66cSJonathan Chen }
4770db7e66cSJonathan Chen 
478