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