xref: /freebsd/sys/dev/cardbus/cardbus_cis.c (revision 255b159f5fb68a4ff40f1e11c4917e1e43fc7809)
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 
470db7e66cSJonathan Chen #include <pci/pcivar.h>
480db7e66cSJonathan Chen 
490db7e66cSJonathan Chen #include <dev/cardbus/cardbusreg.h>
500db7e66cSJonathan Chen #include <dev/cardbus/cardbus_cis.h>
510db7e66cSJonathan Chen 
520c95c705SJonathan Chen #include "card_if.h"
530c95c705SJonathan Chen 
540db7e66cSJonathan Chen #if defined CARDBUS_DEBUG
550db7e66cSJonathan Chen #define	DPRINTF(a) printf a
560db7e66cSJonathan Chen #define	DEVPRINTF(x) device_printf x
570db7e66cSJonathan Chen #else
580db7e66cSJonathan Chen #define	DPRINTF(a)
590db7e66cSJonathan Chen #define	DEVPRINTF(x)
600db7e66cSJonathan Chen #endif
610db7e66cSJonathan Chen 
620db7e66cSJonathan Chen #if !defined(lint)
630db7e66cSJonathan Chen static const char rcsid[] =
640db7e66cSJonathan Chen     "$FreeBSD$";
650db7e66cSJonathan Chen #endif
660db7e66cSJonathan Chen 
670c95c705SJonathan Chen #define	DECODE_PARAMS							\
68255b159fSJonathan Chen 		(device_t cbdev, device_t child, int id, int len,	\
6949f158ccSJonathan Chen 		 u_int8_t *tupledata, u_int32_t *start, u_int32_t *off,	\
700c95c705SJonathan Chen 		 struct tuple_callbacks *info)
710db7e66cSJonathan Chen 
720c95c705SJonathan Chen struct tuple_callbacks {
730c95c705SJonathan Chen 	int	id;
740db7e66cSJonathan Chen 	char	*name;
750c95c705SJonathan Chen 	int	(*func) DECODE_PARAMS;
760db7e66cSJonathan Chen };
77255b159fSJonathan Chen 
78255b159fSJonathan Chen #define	DECODE_PROTOTYPE(NAME) static int decode_tuple_ ## NAME DECODE_PARAMS
79255b159fSJonathan Chen DECODE_PROTOTYPE(generic);
80255b159fSJonathan Chen DECODE_PROTOTYPE(nothing);
81255b159fSJonathan Chen DECODE_PROTOTYPE(copy);
82255b159fSJonathan Chen DECODE_PROTOTYPE(linktarget);
83255b159fSJonathan Chen DECODE_PROTOTYPE(vers_1);
84255b159fSJonathan Chen DECODE_PROTOTYPE(funcid);
85255b159fSJonathan Chen DECODE_PROTOTYPE(manfid);
86255b159fSJonathan Chen DECODE_PROTOTYPE(funce);
87255b159fSJonathan Chen DECODE_PROTOTYPE(bar);
88255b159fSJonathan Chen DECODE_PROTOTYPE(unhandled);
89255b159fSJonathan Chen DECODE_PROTOTYPE(end);
90255b159fSJonathan Chen static int	cardbus_read_tuple_conf(device_t cbdev, device_t child,
91255b159fSJonathan Chen 		    u_int32_t *start, u_int32_t *off, int *tupleid, int *len,
92255b159fSJonathan Chen 		    u_int8_t *tupledata);
93255b159fSJonathan Chen static int	cardbus_read_tuple_exrom(device_t cbdev, struct resource *mem,
94255b159fSJonathan Chen 		    u_int32_t *start, u_int32_t *off, int *tupleid, int *len,
95255b159fSJonathan Chen 		    u_int8_t *tupledata);
96255b159fSJonathan Chen static int	cardbus_read_tuple_mem(device_t cbdev, device_t child,
97255b159fSJonathan 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,
100255b159fSJonathan Chen 		    u_int32_t *start, u_int32_t *off, int *tupleid, int *len,
101255b159fSJonathan Chen 		    u_int8_t *tupledata);
102255b159fSJonathan Chen static int	decode_tuple(device_t cbdev, device_t child, int tupleid,
103255b159fSJonathan Chen 		    int len, u_int8_t *tupledata, u_int32_t *start,
104255b159fSJonathan Chen 		    u_int32_t *off, struct tuple_callbacks *callbacks);
105255b159fSJonathan Chen static int	cardbus_parse_cis(device_t cbdev, device_t child,
106255b159fSJonathan Chen 		    struct tuple_callbacks *callbacks);
107255b159fSJonathan Chen 
1080c95c705SJonathan Chen #define	MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
1090db7e66cSJonathan Chen 
1100db7e66cSJonathan Chen static char *funcnames[] = {
1110db7e66cSJonathan Chen 	"Multi-Functioned",
1120db7e66cSJonathan Chen 	"Memory",
1130db7e66cSJonathan Chen 	"Serial Port",
1140db7e66cSJonathan Chen 	"Parallel Port",
1150db7e66cSJonathan Chen 	"Fixed Disk",
1160db7e66cSJonathan Chen 	"Video Adaptor",
1170db7e66cSJonathan Chen 	"Network Adaptor",
1180db7e66cSJonathan Chen 	"AIMS",
1190db7e66cSJonathan Chen 	"SCSI",
1200db7e66cSJonathan Chen 	"Security"
1210db7e66cSJonathan Chen };
1220db7e66cSJonathan Chen 
1230c95c705SJonathan Chen static struct cis_tupleinfo *cisread_buf;
1240c95c705SJonathan Chen static int ncisread_buf;
1250c95c705SJonathan Chen 
126255b159fSJonathan Chen /*
127255b159fSJonathan Chen  * Handler functions for various CIS tuples
128255b159fSJonathan Chen  */
129255b159fSJonathan Chen 
1300db7e66cSJonathan Chen DECODE_PROTOTYPE(generic)
1310db7e66cSJonathan Chen {
1320db7e66cSJonathan Chen #ifdef CARDBUS_DEBUG
1330db7e66cSJonathan Chen 	int i;
1340db7e66cSJonathan Chen 
1350db7e66cSJonathan Chen 	if (info)
1360db7e66cSJonathan Chen 		printf("TUPLE: %s [%d]:", info->name, len);
1370db7e66cSJonathan Chen 	else
1380db7e66cSJonathan Chen 		printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
1390db7e66cSJonathan Chen 
1400db7e66cSJonathan Chen 	for (i = 0; i < len; i++) {
1410db7e66cSJonathan Chen 		if (i % 0x10 == 0 && len > 0x10)
1420db7e66cSJonathan Chen 			printf("\n       0x%02x:", i);
1437bec1dd5SJonathan Chen 		printf(" %02x", tupledata[i]);
1440db7e66cSJonathan Chen 	}
1450db7e66cSJonathan Chen 	printf("\n");
1460db7e66cSJonathan Chen #endif
1470db7e66cSJonathan Chen 	return 0;
1480db7e66cSJonathan Chen }
1490db7e66cSJonathan Chen 
1500c95c705SJonathan Chen DECODE_PROTOTYPE(nothing)
1510c95c705SJonathan Chen {
1520c95c705SJonathan Chen 	return 0;
1530c95c705SJonathan Chen }
1540c95c705SJonathan Chen 
1550c95c705SJonathan Chen DECODE_PROTOTYPE(copy)
1560c95c705SJonathan Chen {
1570c95c705SJonathan Chen 	struct cis_tupleinfo *tmpbuf;
1580c95c705SJonathan Chen 
1590c95c705SJonathan Chen 	tmpbuf = malloc(sizeof(struct cis_tupleinfo) * (ncisread_buf+1),
1600c95c705SJonathan Chen 	    M_DEVBUF, M_WAITOK);
1610c95c705SJonathan Chen 	if (ncisread_buf > 0) {
1620c95c705SJonathan Chen 		memcpy(tmpbuf, cisread_buf,
1630c95c705SJonathan Chen 		    sizeof(struct cis_tupleinfo) * ncisread_buf);
1640c95c705SJonathan Chen 		free(cisread_buf, M_DEVBUF);
1650c95c705SJonathan Chen 	}
1660c95c705SJonathan Chen 	cisread_buf = tmpbuf;
1670c95c705SJonathan Chen 
1680c95c705SJonathan Chen 	cisread_buf[ncisread_buf].id = id;
1690c95c705SJonathan Chen 	cisread_buf[ncisread_buf].len = len;
1700c95c705SJonathan Chen 	cisread_buf[ncisread_buf].data = malloc(len, M_DEVBUF, M_WAITOK);
1710c95c705SJonathan Chen 	memcpy(cisread_buf[ncisread_buf].data, tupledata, len);
1720c95c705SJonathan Chen 	ncisread_buf++;
1730c95c705SJonathan Chen 	return 0;
1740c95c705SJonathan Chen }
1750c95c705SJonathan Chen 
1760db7e66cSJonathan Chen DECODE_PROTOTYPE(linktarget)
1770db7e66cSJonathan Chen {
17849f158ccSJonathan Chen #ifdef CARDBUS_DEBUG
17949f158ccSJonathan Chen 	int i;
18049f158ccSJonathan Chen 
18149f158ccSJonathan Chen 	printf("TUPLE: %s [%d]:", info->name, len);
18249f158ccSJonathan Chen 
18349f158ccSJonathan Chen 	for (i = 0; i < len; i++) {
18449f158ccSJonathan Chen 		if (i % 0x10 == 0 && len > 0x10)
18549f158ccSJonathan Chen 			printf("\n       0x%02x:", i);
18649f158ccSJonathan Chen 		printf(" %02x", tupledata[i]);
18749f158ccSJonathan Chen 	}
18849f158ccSJonathan Chen 	printf("\n");
18949f158ccSJonathan Chen #endif
1907bec1dd5SJonathan Chen 	if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
1917bec1dd5SJonathan Chen 	    tupledata[2] != 'S') {
1920db7e66cSJonathan Chen 		printf("Invalid data for CIS Link Target!\n");
193255b159fSJonathan Chen 		decode_tuple_generic(cbdev, child, id, len, tupledata,
19449f158ccSJonathan Chen 		    start, off, info);
1950db7e66cSJonathan Chen 		return EINVAL;
1960db7e66cSJonathan Chen 	}
1970db7e66cSJonathan Chen 	return 0;
1980db7e66cSJonathan Chen }
1990db7e66cSJonathan Chen 
2000db7e66cSJonathan Chen DECODE_PROTOTYPE(vers_1)
2010db7e66cSJonathan Chen {
2020db7e66cSJonathan Chen 	int i;
2037bec1dd5SJonathan Chen 	printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
2040db7e66cSJonathan Chen 	printf("Product name: ");
2050db7e66cSJonathan Chen 	for (i = 2; i < len; i++) {
2067bec1dd5SJonathan Chen 		if (tupledata[i] == '\0')
2070db7e66cSJonathan Chen 			printf(" | ");
2087bec1dd5SJonathan Chen 		else if (tupledata[i] == 0xff)
2090db7e66cSJonathan Chen 			break;
2100db7e66cSJonathan Chen 		else
2117bec1dd5SJonathan Chen 			printf("%c", tupledata[i]);
2120db7e66cSJonathan Chen 	}
2130db7e66cSJonathan Chen 	printf("\n");
2140db7e66cSJonathan Chen 	return 0;
2150db7e66cSJonathan Chen }
2160db7e66cSJonathan Chen 
2170db7e66cSJonathan Chen DECODE_PROTOTYPE(funcid)
2180db7e66cSJonathan Chen {
2190db7e66cSJonathan Chen 	int i;
2200db7e66cSJonathan Chen 	int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
2210db7e66cSJonathan Chen 
2220db7e66cSJonathan Chen 	printf("Functions: ");
2230db7e66cSJonathan Chen 	for (i = 0; i < len; i++) {
2247bec1dd5SJonathan Chen 		if (tupledata[i] < numnames)
2257bec1dd5SJonathan Chen 			printf("%s", funcnames[tupledata[i]]);
2260db7e66cSJonathan Chen 		else
2277bec1dd5SJonathan Chen 			printf("Unknown(%d)", tupledata[i]);
228255b159fSJonathan Chen 		if (i < len-1)
229255b159fSJonathan Chen 			printf(", ");
2300db7e66cSJonathan Chen 	}
2310db7e66cSJonathan Chen 	printf("\n");
2320db7e66cSJonathan Chen 	return 0;
2330db7e66cSJonathan Chen }
2340db7e66cSJonathan Chen 
2350db7e66cSJonathan Chen DECODE_PROTOTYPE(manfid)
2360db7e66cSJonathan Chen {
2370db7e66cSJonathan Chen 	int i;
2380db7e66cSJonathan Chen 	printf("Manufacturer ID: ");
2390db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2407bec1dd5SJonathan Chen 		printf("%02x", tupledata[i]);
2410db7e66cSJonathan Chen 	printf("\n");
2420db7e66cSJonathan Chen 	return 0;
2430db7e66cSJonathan Chen }
2440db7e66cSJonathan Chen 
2450db7e66cSJonathan Chen DECODE_PROTOTYPE(funce)
2460db7e66cSJonathan Chen {
2470db7e66cSJonathan Chen 	int i;
2480db7e66cSJonathan Chen 	printf("Function Extension: ");
2490db7e66cSJonathan Chen 	for (i = 0; i < len; i++)
2507bec1dd5SJonathan Chen 		printf("%02x", tupledata[i]);
2510db7e66cSJonathan Chen 	printf("\n");
2520db7e66cSJonathan Chen 	return 0;
2530db7e66cSJonathan Chen }
2540db7e66cSJonathan Chen 
2550db7e66cSJonathan Chen DECODE_PROTOTYPE(bar)
2560db7e66cSJonathan Chen {
2570db7e66cSJonathan Chen 	if (len != 6) {
2580db7e66cSJonathan Chen 		printf("*** ERROR *** BAR length not 6 (%d)\n", len);
2590db7e66cSJonathan Chen 		return EINVAL;
2600db7e66cSJonathan Chen 	} else {
2610db7e66cSJonathan Chen 		int type;
2620db7e66cSJonathan Chen 		int reg;
2630db7e66cSJonathan Chen 		u_int32_t bar;
264fd121bf8SJustin T. Gibbs 		u_int32_t len;
2650db7e66cSJonathan Chen 		struct resource *res;
2660db7e66cSJonathan Chen 
2677bec1dd5SJonathan Chen 		reg = *(u_int16_t*)tupledata;
2687bec1dd5SJonathan Chen 		len = *(u_int32_t*)(tupledata + 2);
2690db7e66cSJonathan Chen 		if (reg & TPL_BAR_REG_AS) {
2700db7e66cSJonathan Chen 			type = SYS_RES_IOPORT;
2710db7e66cSJonathan Chen 		} else {
2720db7e66cSJonathan Chen 			type = SYS_RES_MEMORY;
2730db7e66cSJonathan Chen 		}
2740db7e66cSJonathan Chen 		bar = (reg & TPL_BAR_REG_ASI_MASK) - 1;
275255b159fSJonathan Chen 		if (bar < 0 || bar > 5 ||
276255b159fSJonathan Chen 		    (type == SYS_RES_IOPORT && bar == 5)) {
277255b159fSJonathan Chen 			device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n",
2780db7e66cSJonathan Chen 			    reg, bar);
2790c95c705SJonathan Chen 			return 0;
2800db7e66cSJonathan Chen 		}
2810db7e66cSJonathan Chen 		bar = CARDBUS_BASE0_REG + bar * 4;
282255b159fSJonathan Chen 		DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x\n",
2830db7e66cSJonathan Chen 		    (type==SYS_RES_MEMORY)?"MEM":"IO", bar, len));
284d58b9dbcSJonathan Chen 		res = bus_generic_alloc_resource(child, child, type, &bar, 0,
2850db7e66cSJonathan Chen 		    ~0, len, rman_make_alignment_flags(len) | RF_ACTIVE);
2860db7e66cSJonathan Chen 		if (res == NULL) {
287255b159fSJonathan Chen 			device_printf(cbdev, "Cannot allocate BAR %02x\n", bar);
2880db7e66cSJonathan Chen 		}
2890db7e66cSJonathan Chen 	}
2900db7e66cSJonathan Chen 	return 0;
2910db7e66cSJonathan Chen }
2920db7e66cSJonathan Chen 
2930db7e66cSJonathan Chen DECODE_PROTOTYPE(unhandled)
2940db7e66cSJonathan Chen {
2950db7e66cSJonathan Chen 	printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
2960db7e66cSJonathan Chen 	return -1;
2970db7e66cSJonathan Chen }
2980db7e66cSJonathan Chen 
2990db7e66cSJonathan Chen DECODE_PROTOTYPE(end)
3000db7e66cSJonathan Chen {
3010c95c705SJonathan Chen 	printf("CIS reading done\n");
3027bec1dd5SJonathan Chen 	return 0;
3030db7e66cSJonathan Chen }
3040db7e66cSJonathan Chen 
305255b159fSJonathan Chen /*
306255b159fSJonathan Chen  * Functions to read the a tuple from the card
307255b159fSJonathan Chen  */
308255b159fSJonathan Chen 
3090db7e66cSJonathan Chen static int
310255b159fSJonathan Chen cardbus_read_tuple_conf(device_t cbdev, device_t child, u_int32_t *start,
311255b159fSJonathan Chen     u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata)
3127bec1dd5SJonathan Chen {
3137bec1dd5SJonathan Chen 	int i, j;
3147bec1dd5SJonathan Chen 	u_int32_t e;
31549f158ccSJonathan Chen 	u_int32_t loc;
3167bec1dd5SJonathan Chen 
31749f158ccSJonathan Chen 	loc = CARDBUS_CIS_ADDR(*start) + *off;
31849f158ccSJonathan Chen 
31949f158ccSJonathan Chen 	e = pci_read_config(child, loc - loc % 4, 4);
32049f158ccSJonathan Chen 	for (j = loc % 4; j > 0; j--)
3217bec1dd5SJonathan Chen 		e >>= 8;
3227bec1dd5SJonathan Chen 	*len = 0;
32349f158ccSJonathan Chen 	for (i = loc, j = -2; j < *len; j++, i++) {
3247bec1dd5SJonathan Chen 		if (i % 4 == 0)
3257bec1dd5SJonathan Chen 			e = pci_read_config(child, i, 4);
3267bec1dd5SJonathan Chen 		if (j == -2)
3277bec1dd5SJonathan Chen 			*tupleid = 0xff & e;
3287bec1dd5SJonathan Chen 		else if (j == -1)
3297bec1dd5SJonathan Chen 			*len = 0xff & e;
3307bec1dd5SJonathan Chen 		else
3317bec1dd5SJonathan Chen 			tupledata[j] = 0xff & e;
3327bec1dd5SJonathan Chen 		e >>= 8;
3337bec1dd5SJonathan Chen 	}
3347bec1dd5SJonathan Chen 	*off += *len + 2;
3357bec1dd5SJonathan Chen 	return 0;
3367bec1dd5SJonathan Chen }
3377bec1dd5SJonathan Chen 
3387bec1dd5SJonathan Chen static int
339255b159fSJonathan Chen cardbus_read_tuple_exrom(device_t cbdev, struct resource *mem, u_int32_t *start,
340255b159fSJonathan Chen     u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata)
3410db7e66cSJonathan Chen {
3420db7e66cSJonathan Chen #define	READROM(rom, type, offset)				       \
3430db7e66cSJonathan Chen 	(*((u_int ## type ##_t *)(((unsigned char*)rom) + offset)))
3440db7e66cSJonathan Chen 
3450db7e66cSJonathan Chen 	int romnum = 0;
3460db7e66cSJonathan Chen 	unsigned char *data;
3470db7e66cSJonathan Chen 	u_int32_t imagesize;
3480db7e66cSJonathan Chen 	unsigned char *image;
3490db7e66cSJonathan Chen 	int imagenum;
3500db7e66cSJonathan Chen 
3517bec1dd5SJonathan Chen 	image = (unsigned char*)rman_get_virtual(mem);
35249f158ccSJonathan Chen 	imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
3530db7e66cSJonathan Chen 	do {
3540db7e66cSJonathan Chen 		if (READROM(image, 16, CARDBUS_EXROM_SIGNATURE) != 0xaa55) {
355255b159fSJonathan Chen 			device_printf(cbdev, "Bad header in rom %d: %04x\n",
3560db7e66cSJonathan Chen 				       romnum, *(u_int16_t*)(image +
3570db7e66cSJonathan Chen 				       CARDBUS_EXROM_SIGNATURE));
3580db7e66cSJonathan Chen 			return ENXIO;
3590db7e66cSJonathan Chen 		}
3600db7e66cSJonathan Chen 		data = image + READROM(image, 16, CARDBUS_EXROM_DATA_PTR);
3610db7e66cSJonathan Chen 		imagesize = READROM(data, 16, CARDBUS_EXROM_DATA_IMAGE_LENGTH);
3620db7e66cSJonathan Chen 
3637bec1dd5SJonathan Chen 		if (imagesize == 0) {
3640db7e66cSJonathan Chen 			/*
3650db7e66cSJonathan Chen 			 * XXX some ROMs seem to have this as zero,
3660db7e66cSJonathan Chen 			 * can we assume this means 1 block?
3670db7e66cSJonathan Chen 			 */
3680db7e66cSJonathan Chen 			imagesize = 1;
3697bec1dd5SJonathan Chen 		}
3700db7e66cSJonathan Chen 		imagesize <<= 9;
3710db7e66cSJonathan Chen 
3720db7e66cSJonathan Chen 		if (imagenum == romnum) {
37349f158ccSJonathan Chen 			image += CARDBUS_CIS_ADDR(*start) + *off;
3747bec1dd5SJonathan Chen 			*tupleid = image[0];
3757bec1dd5SJonathan Chen 			*len = image[1];
3767bec1dd5SJonathan Chen 			memcpy(tupledata, image+2, *len);
3777bec1dd5SJonathan Chen 			*off += *len+2;
3780db7e66cSJonathan Chen 			return 0;
3790db7e66cSJonathan Chen 		}
380fd121bf8SJustin T. Gibbs 		image += imagesize;
3810db7e66cSJonathan Chen 		romnum++;
3820db7e66cSJonathan Chen 	} while ((READROM(data, 8, CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0);
383255b159fSJonathan Chen 	device_printf(cbdev, "Cannot read CIS: Not enough images of rom\n");
3840db7e66cSJonathan Chen 	return ENOENT;
3850db7e66cSJonathan Chen #undef READROM
3860db7e66cSJonathan Chen }
3870db7e66cSJonathan Chen 
3880db7e66cSJonathan Chen static int
389255b159fSJonathan Chen cardbus_read_tuple_mem(device_t cbdev, device_t child, u_int32_t *start,
390255b159fSJonathan Chen     u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata)
3910db7e66cSJonathan Chen {
3920db7e66cSJonathan Chen 	struct resource *mem;
393ca604d26SWarner Losh 	bus_space_tag_t bt;
394ca604d26SWarner Losh 	bus_space_handle_t bh;
3950db7e66cSJonathan Chen 	int rid;
3960db7e66cSJonathan Chen 	int ret;
3970db7e66cSJonathan Chen 
39849f158ccSJonathan Chen 	if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
3990db7e66cSJonathan Chen 		rid = CARDBUS_ROM_REG;
4000db7e66cSJonathan Chen 	} else {
40149f158ccSJonathan Chen 		rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
4020db7e66cSJonathan Chen 	}
40349f158ccSJonathan Chen 
4040db7e66cSJonathan Chen 	mem = bus_alloc_resource(child, SYS_RES_MEMORY, &rid, 0, ~0,
4050db7e66cSJonathan Chen 				 1, RF_ACTIVE);
406ca604d26SWarner Losh 	bt = rman_get_bustag(mem);
407ca604d26SWarner Losh 	bh = rman_get_bushandle(mem);
4080db7e66cSJonathan Chen 	if (mem == NULL) {
409255b159fSJonathan Chen 		device_printf(cbdev, "Failed to get memory for CIS reading\n");
4100db7e66cSJonathan Chen 		return ENOMEM;
4110db7e66cSJonathan Chen 	}
4120db7e66cSJonathan Chen 
41349f158ccSJonathan Chen 	if(CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
414255b159fSJonathan Chen 		ret = cardbus_read_tuple_exrom(cbdev, mem, start, off, tupleid,
4157bec1dd5SJonathan Chen 					       len, tupledata);
4160db7e66cSJonathan Chen 	} else {
417ca604d26SWarner Losh 		*tupleid = bus_space_read_1(bt, bh,
418ca604d26SWarner Losh 		    CARDBUS_CIS_ADDR(*start) + *off);
419ca604d26SWarner Losh 		*len = bus_space_read_1(bt, bh,
420ca604d26SWarner Losh 		    CARDBUS_CIS_ADDR(*start) + *off + 1);
421ca604d26SWarner Losh 		bus_space_read_multi_1(rman_get_bustag(mem),
422ca604d26SWarner Losh 		    rman_get_bushandle(mem),
423ca604d26SWarner Losh 		    *off + CARDBUS_CIS_ADDR(*start), tupledata, *len);
4240db7e66cSJonathan Chen 		ret = 0;
4257bec1dd5SJonathan Chen 		*off += *len+2;
4260db7e66cSJonathan Chen 	}
4270db7e66cSJonathan Chen 	bus_release_resource(child, SYS_RES_MEMORY, rid, mem);
4280db7e66cSJonathan Chen 	return ret;
4290db7e66cSJonathan Chen }
4300db7e66cSJonathan Chen 
4310db7e66cSJonathan Chen static int
432255b159fSJonathan Chen cardbus_read_tuple(device_t cbdev, device_t child, u_int32_t *start,
433255b159fSJonathan Chen     u_int32_t *off, int *tupleid, int *len, u_int8_t *tupledata)
4340db7e66cSJonathan Chen {
43549f158ccSJonathan Chen 	switch(CARDBUS_CIS_SPACE(*start)) {
4360db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_TUPLE:
437255b159fSJonathan Chen 		return cardbus_read_tuple_conf(cbdev, child, start, off,
4387bec1dd5SJonathan Chen 		    tupleid, len, tupledata);
4390db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR0:
4400db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR1:
4410db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR2:
4420db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR3:
4430db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR4:
4440db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_BAR5:
4450db7e66cSJonathan Chen 	case CARDBUS_CIS_ASI_ROM:
446255b159fSJonathan Chen 		return cardbus_read_tuple_mem(cbdev, child, start, off,
4477bec1dd5SJonathan Chen 		    tupleid, len, tupledata);
4480db7e66cSJonathan Chen 	default:
449255b159fSJonathan Chen 		device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
45049f158ccSJonathan Chen 		    CARDBUS_CIS_SPACE(*start));
4517bec1dd5SJonathan Chen 		return EINVAL;
4520db7e66cSJonathan Chen 	}
4537bec1dd5SJonathan Chen }
4547bec1dd5SJonathan Chen 
455255b159fSJonathan Chen /*
456255b159fSJonathan Chen  * Dispatch the right handler function per tuple
457255b159fSJonathan Chen  */
458255b159fSJonathan Chen 
4597bec1dd5SJonathan Chen static int
460255b159fSJonathan Chen decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
4610c95c705SJonathan Chen     u_int8_t *tupledata, u_int32_t *start, u_int32_t *off,
4620c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
4637bec1dd5SJonathan Chen {
4647bec1dd5SJonathan Chen 	int i;
4650c95c705SJonathan Chen 	for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
4660c95c705SJonathan Chen 		if (tupleid == callbacks[i].id)
467255b159fSJonathan Chen 			return callbacks[i].func(cbdev, child, tupleid, len,
468255b159fSJonathan Chen 			    tupledata, start, off, &callbacks[i]);
4697bec1dd5SJonathan Chen 	}
4707bec1dd5SJonathan Chen 
47149f158ccSJonathan Chen 	if (tupleid < CISTPL_CUSTOMSTART) {
472255b159fSJonathan Chen 		device_printf(cbdev, "Undefined tuple encountered, "
473255b159fSJonathan Chen 		    "CIS parsing terminated\n");
47449f158ccSJonathan Chen 		return EINVAL;
47549f158ccSJonathan Chen 	}
476255b159fSJonathan Chen 	return callbacks[i].func(cbdev, child, tupleid, len,
477255b159fSJonathan Chen 	    tupledata, start, off, NULL);
4780db7e66cSJonathan Chen }
4790db7e66cSJonathan Chen 
4800c95c705SJonathan Chen static int
481255b159fSJonathan Chen cardbus_parse_cis(device_t cbdev, device_t child,
4820c95c705SJonathan Chen     struct tuple_callbacks *callbacks)
4830db7e66cSJonathan Chen {
4840db7e66cSJonathan Chen 	u_int8_t tupledata[MAXTUPLESIZE];
4857bec1dd5SJonathan Chen 	int tupleid;
4867bec1dd5SJonathan Chen 	int len;
4877bec1dd5SJonathan Chen 	int expect_linktarget;
48849f158ccSJonathan Chen 	u_int32_t start, off;
4890db7e66cSJonathan Chen 
4900db7e66cSJonathan Chen 	bzero(tupledata, MAXTUPLESIZE);
4917bec1dd5SJonathan Chen 	expect_linktarget = TRUE;
49249f158ccSJonathan Chen 	start = pci_read_config(child, CARDBUS_CIS_REG, 4);
49349f158ccSJonathan Chen 	off = 0;
4947bec1dd5SJonathan Chen 	do {
495255b159fSJonathan Chen 		cardbus_read_tuple(cbdev, child, &start, &off, &tupleid, &len,
4967bec1dd5SJonathan Chen 				   tupledata);
4977bec1dd5SJonathan Chen 
4987bec1dd5SJonathan Chen 		if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
499255b159fSJonathan Chen 			device_printf(cbdev, "Expecting link target, got 0x%x\n",
5007bec1dd5SJonathan Chen 			    tupleid);
5017bec1dd5SJonathan Chen 			return EINVAL;
5027bec1dd5SJonathan Chen 		}
503255b159fSJonathan Chen 		expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
5040c95c705SJonathan Chen 						 tupledata, &start, &off,
5050c95c705SJonathan Chen 						 callbacks);
5067bec1dd5SJonathan Chen 		if (expect_linktarget != 0)
5077bec1dd5SJonathan Chen 			return expect_linktarget;
5087bec1dd5SJonathan Chen 	} while (tupleid != CISTPL_END);
5097bec1dd5SJonathan Chen 	return 0;
5100db7e66cSJonathan Chen }
5110db7e66cSJonathan Chen 
5120c95c705SJonathan Chen int
513255b159fSJonathan Chen cardbus_cis_read(device_t cbdev, device_t child, u_int8_t id,
5140c95c705SJonathan Chen     struct cis_tupleinfo **buff, int *nret)
5150c95c705SJonathan Chen {
5160c95c705SJonathan Chen 	struct tuple_callbacks cisread_callbacks[] = {
5170c95c705SJonathan Chen 		MAKETUPLE(NULL,			nothing),
5180c95c705SJonathan Chen 		/* first entry will be overwritten */
5190c95c705SJonathan Chen 		MAKETUPLE(NULL,			nothing),
5200c95c705SJonathan Chen 		MAKETUPLE(DEVICE,		nothing),
5210c95c705SJonathan Chen 		MAKETUPLE(LONG_LINK_CB,		unhandled),
5220c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
5230c95c705SJonathan Chen 		MAKETUPLE(CONFIG_CB,		nothing),
5240c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY_CB,	nothing),
5250c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
5260c95c705SJonathan Chen 		MAKETUPLE(BAR,			nothing),
5270c95c705SJonathan Chen 		MAKETUPLE(PWR_MGMNT,		nothing),
5280c95c705SJonathan Chen 		MAKETUPLE(EXTDEVICE,		nothing),
5290c95c705SJonathan Chen 		MAKETUPLE(CHECKSUM,		nothing),
5300c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
5310c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
5320c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		nothing),
5330c95c705SJonathan Chen 		MAKETUPLE(NO_LINK,		nothing),
5340c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		nothing),
5350c95c705SJonathan Chen 		MAKETUPLE(ALTSTR,		nothing),
5360c95c705SJonathan Chen 		MAKETUPLE(DEVICE_A,		nothing),
5370c95c705SJonathan Chen 		MAKETUPLE(JEDEC_C,		nothing),
5380c95c705SJonathan Chen 		MAKETUPLE(JEDEC_A,		nothing),
5390c95c705SJonathan Chen 		MAKETUPLE(CONFIG,		nothing),
5400c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY,	nothing),
5410c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OC,		nothing),
5420c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OA,		nothing),
5430c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO,		nothing),
5440c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO_A,		nothing),
5450c95c705SJonathan Chen 		MAKETUPLE(MANFID,		nothing),
5460c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		nothing),
5470c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		nothing),
5480c95c705SJonathan Chen 		MAKETUPLE(SWIL,			nothing),
5490c95c705SJonathan Chen 		MAKETUPLE(VERS_2,		nothing),
5500c95c705SJonathan Chen 		MAKETUPLE(FORMAT,		nothing),
5510c95c705SJonathan Chen 		MAKETUPLE(GEOMETRY,		nothing),
5520c95c705SJonathan Chen 		MAKETUPLE(BYTEORDER,		nothing),
5530c95c705SJonathan Chen 		MAKETUPLE(DATE,			nothing),
5540c95c705SJonathan Chen 		MAKETUPLE(BATTERY,		nothing),
5550c95c705SJonathan Chen 		MAKETUPLE(ORG,			nothing),
5560c95c705SJonathan Chen 		MAKETUPLE(END,			end),
5570c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		nothing),
5580c95c705SJonathan Chen 	};
5590c95c705SJonathan Chen 	int ret;
5600c95c705SJonathan Chen 
5610c95c705SJonathan Chen 	cisread_callbacks[0].id = id;
5620c95c705SJonathan Chen 	cisread_callbacks[0].name = "COPY";
5630c95c705SJonathan Chen 	cisread_callbacks[0].func = decode_tuple_copy;
5640c95c705SJonathan Chen 	ncisread_buf = 0;
5650c95c705SJonathan Chen 	cisread_buf = NULL;
566255b159fSJonathan Chen 	ret = cardbus_parse_cis(cbdev, child, cisread_callbacks);
5670c95c705SJonathan Chen 
5680c95c705SJonathan Chen 	*buff = cisread_buf;
5690c95c705SJonathan Chen 	*nret = ncisread_buf;
5700c95c705SJonathan Chen 	return ret;
5710c95c705SJonathan Chen }
5720c95c705SJonathan Chen 
5730c95c705SJonathan Chen void
574255b159fSJonathan Chen cardbus_cis_free(device_t cbdev, struct cis_tupleinfo *buff, int* nret)
5750c95c705SJonathan Chen {
5760c95c705SJonathan Chen 	int i;
5776f39832cSPeter Wemm 	for (i = 0; i < *nret; i++)
5780c95c705SJonathan Chen 		free(buff[i].data, M_DEVBUF);
5796f39832cSPeter Wemm 	if (*nret > 0)
5800c95c705SJonathan Chen 		free(buff, M_DEVBUF);
5810c95c705SJonathan Chen }
5820c95c705SJonathan Chen 
5830c95c705SJonathan Chen int
584255b159fSJonathan Chen cardbus_do_cis(device_t cbdev, device_t child)
5850c95c705SJonathan Chen {
5860c95c705SJonathan Chen 	struct tuple_callbacks init_callbacks[] = {
5870c95c705SJonathan Chen 		MAKETUPLE(NULL,			generic),
5880c95c705SJonathan Chen 		MAKETUPLE(DEVICE,		generic),
5890c95c705SJonathan Chen 		MAKETUPLE(LONG_LINK_CB,		unhandled),
5900c95c705SJonathan Chen 		MAKETUPLE(INDIRECT,		unhandled),
5910c95c705SJonathan Chen 		MAKETUPLE(CONFIG_CB,		generic),
5920c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY_CB,	generic),
5930c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_MFC,		unhandled),
5940c95c705SJonathan Chen 		MAKETUPLE(BAR,			bar),
5950c95c705SJonathan Chen 		MAKETUPLE(PWR_MGMNT,		generic),
5960c95c705SJonathan Chen 		MAKETUPLE(EXTDEVICE,		generic),
5970c95c705SJonathan Chen 		MAKETUPLE(CHECKSUM,		generic),
5980c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_A,		unhandled),
5990c95c705SJonathan Chen 		MAKETUPLE(LONGLINK_C,		unhandled),
6000c95c705SJonathan Chen 		MAKETUPLE(LINKTARGET,		linktarget),
6010c95c705SJonathan Chen 		MAKETUPLE(NO_LINK,		generic),
6020c95c705SJonathan Chen 		MAKETUPLE(VERS_1,		vers_1),
6030c95c705SJonathan Chen 		MAKETUPLE(ALTSTR,		generic),
6040c95c705SJonathan Chen 		MAKETUPLE(DEVICE_A,		generic),
6050c95c705SJonathan Chen 		MAKETUPLE(JEDEC_C,		generic),
6060c95c705SJonathan Chen 		MAKETUPLE(JEDEC_A,		generic),
6070c95c705SJonathan Chen 		MAKETUPLE(CONFIG,		generic),
6080c95c705SJonathan Chen 		MAKETUPLE(CFTABLE_ENTRY,	generic),
6090c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OC,		generic),
6100c95c705SJonathan Chen 		MAKETUPLE(DEVICE_OA,		generic),
6110c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO,		generic),
6120c95c705SJonathan Chen 		MAKETUPLE(DEVICE_GEO_A,		generic),
6130c95c705SJonathan Chen 		MAKETUPLE(MANFID,		manfid),
6140c95c705SJonathan Chen 		MAKETUPLE(FUNCID,		funcid),
6150c95c705SJonathan Chen 		MAKETUPLE(FUNCE,		funce),
6160c95c705SJonathan Chen 		MAKETUPLE(SWIL,			generic),
6170c95c705SJonathan Chen 		MAKETUPLE(VERS_2,		generic),
6180c95c705SJonathan Chen 		MAKETUPLE(FORMAT,		generic),
6190c95c705SJonathan Chen 		MAKETUPLE(GEOMETRY,		generic),
6200c95c705SJonathan Chen 		MAKETUPLE(BYTEORDER,		generic),
6210c95c705SJonathan Chen 		MAKETUPLE(DATE,			generic),
6220c95c705SJonathan Chen 		MAKETUPLE(BATTERY,		generic),
6230c95c705SJonathan Chen 		MAKETUPLE(ORG,			generic),
6240c95c705SJonathan Chen 		MAKETUPLE(END,			end),
6250c95c705SJonathan Chen 		MAKETUPLE(GENERIC,		generic),
6260c95c705SJonathan Chen 	};
627255b159fSJonathan Chen 	return cardbus_parse_cis(cbdev, child, init_callbacks);
6280c95c705SJonathan Chen }
629