1*10412f8dSjason /* $OpenBSD: pcmcia_cis.c,v 1.9 2002/11/19 18:36:18 jason Exp $ */ 20720f62cSfgsch /* $NetBSD: pcmcia_cis.c,v 1.9 1998/08/22 23:41:48 msaitoh Exp $ */ 30720f62cSfgsch 40720f62cSfgsch /* 50720f62cSfgsch * Copyright (c) 1997 Marc Horowitz. All rights reserved. 60720f62cSfgsch * 70720f62cSfgsch * Redistribution and use in source and binary forms, with or without 80720f62cSfgsch * modification, are permitted provided that the following conditions 90720f62cSfgsch * are met: 100720f62cSfgsch * 1. Redistributions of source code must retain the above copyright 110720f62cSfgsch * notice, this list of conditions and the following disclaimer. 120720f62cSfgsch * 2. Redistributions in binary form must reproduce the above copyright 130720f62cSfgsch * notice, this list of conditions and the following disclaimer in the 140720f62cSfgsch * documentation and/or other materials provided with the distribution. 150720f62cSfgsch * 3. All advertising materials mentioning features or use of this software 160720f62cSfgsch * must display the following acknowledgement: 170720f62cSfgsch * This product includes software developed by Marc Horowitz. 180720f62cSfgsch * 4. The name of the author may not be used to endorse or promote products 190720f62cSfgsch * derived from this software without specific prior written permission. 200720f62cSfgsch * 210720f62cSfgsch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 220720f62cSfgsch * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 230720f62cSfgsch * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 240720f62cSfgsch * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 250720f62cSfgsch * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 260720f62cSfgsch * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 270720f62cSfgsch * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 280720f62cSfgsch * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 290720f62cSfgsch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 300720f62cSfgsch * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 310720f62cSfgsch */ 320720f62cSfgsch 330720f62cSfgsch #include <sys/types.h> 340720f62cSfgsch #include <sys/param.h> 350720f62cSfgsch #include <sys/systm.h> 360720f62cSfgsch #include <sys/device.h> 370720f62cSfgsch #include <sys/malloc.h> 380720f62cSfgsch 390720f62cSfgsch #include <dev/pcmcia/pcmciareg.h> 400720f62cSfgsch #include <dev/pcmcia/pcmciachip.h> 410720f62cSfgsch #include <dev/pcmcia/pcmciavar.h> 420720f62cSfgsch 430720f62cSfgsch #ifdef PCMCIACISDEBUG 44709e0656Sfgsch #define DPRINTF(arg) printf arg 450720f62cSfgsch #else 460720f62cSfgsch #define DPRINTF(arg) 470720f62cSfgsch #endif 480720f62cSfgsch 490720f62cSfgsch #define PCMCIA_CIS_SIZE 1024 500720f62cSfgsch 510720f62cSfgsch struct cis_state { 520720f62cSfgsch int count; 530720f62cSfgsch int gotmfc; 540720f62cSfgsch struct pcmcia_config_entry temp_cfe; 550720f62cSfgsch struct pcmcia_config_entry *default_cfe; 560720f62cSfgsch struct pcmcia_card *card; 570720f62cSfgsch struct pcmcia_function *pf; 580720f62cSfgsch }; 590720f62cSfgsch 60c4071fd1Smillert int pcmcia_parse_cis_tuple(struct pcmcia_tuple *, void *); 610720f62cSfgsch 620720f62cSfgsch void 630720f62cSfgsch pcmcia_read_cis(sc) 640720f62cSfgsch struct pcmcia_softc *sc; 650720f62cSfgsch { 660720f62cSfgsch struct cis_state state; 670720f62cSfgsch 680720f62cSfgsch state.count = 0; 690720f62cSfgsch state.gotmfc = 0; 700720f62cSfgsch 710720f62cSfgsch state.card = &sc->card; 720720f62cSfgsch 730720f62cSfgsch state.card->error = 0; 740720f62cSfgsch state.card->cis1_major = -1; 750720f62cSfgsch state.card->cis1_minor = -1; 760720f62cSfgsch state.card->cis1_info[0] = NULL; 770720f62cSfgsch state.card->cis1_info[1] = NULL; 780720f62cSfgsch state.card->cis1_info[2] = NULL; 790720f62cSfgsch state.card->cis1_info[3] = NULL; 800720f62cSfgsch state.card->manufacturer = PCMCIA_VENDOR_INVALID; 810720f62cSfgsch state.card->product = PCMCIA_PRODUCT_INVALID; 820720f62cSfgsch SIMPLEQ_INIT(&state.card->pf_head); 830720f62cSfgsch 840720f62cSfgsch state.pf = NULL; 850720f62cSfgsch 860720f62cSfgsch if (pcmcia_scan_cis((struct device *)sc, pcmcia_parse_cis_tuple, 870720f62cSfgsch &state) == -1) 880720f62cSfgsch state.card->error++; 890720f62cSfgsch } 900720f62cSfgsch 910720f62cSfgsch int 920720f62cSfgsch pcmcia_scan_cis(dev, fct, arg) 930720f62cSfgsch struct device *dev; 94c4071fd1Smillert int (*fct)(struct pcmcia_tuple *, void *); 950720f62cSfgsch void *arg; 960720f62cSfgsch { 970720f62cSfgsch struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; 980720f62cSfgsch pcmcia_chipset_tag_t pct; 990720f62cSfgsch pcmcia_chipset_handle_t pch; 1000720f62cSfgsch int window; 1010720f62cSfgsch struct pcmcia_mem_handle pcmh; 1020720f62cSfgsch struct pcmcia_tuple tuple; 1030720f62cSfgsch int longlink_present; 1040720f62cSfgsch int longlink_common; 1050720f62cSfgsch u_long longlink_addr; 1060720f62cSfgsch int mfc_count; 1070720f62cSfgsch int mfc_index; 1080720f62cSfgsch struct { 1090720f62cSfgsch int common; 1100720f62cSfgsch u_long addr; 1110720f62cSfgsch } mfc[256 / 5]; 1120720f62cSfgsch int ret; 1130720f62cSfgsch 1140720f62cSfgsch ret = 0; 1150720f62cSfgsch 1160720f62cSfgsch pct = sc->pct; 1170720f62cSfgsch pch = sc->pch; 1180720f62cSfgsch 1190720f62cSfgsch /* allocate some memory */ 1200720f62cSfgsch 1210720f62cSfgsch if (pcmcia_chip_mem_alloc(pct, pch, PCMCIA_CIS_SIZE, &pcmh)) { 1220720f62cSfgsch #ifdef DIAGNOSTIC 1230720f62cSfgsch printf("%s: can't alloc memory to read attributes\n", 1240720f62cSfgsch sc->dev.dv_xname); 1250720f62cSfgsch #endif 1260720f62cSfgsch return -1; 1270720f62cSfgsch } 1280720f62cSfgsch 1290720f62cSfgsch /* initialize state for the primary tuple chain */ 1300720f62cSfgsch if (pcmcia_chip_mem_map(pct, pch, PCMCIA_MEM_ATTR, 0, 1310720f62cSfgsch PCMCIA_CIS_SIZE, &pcmh, &tuple.ptr, &window)) { 1320720f62cSfgsch pcmcia_chip_mem_free(pct, pch, &pcmh); 1330720f62cSfgsch #ifdef DIAGNOSTIC 1340720f62cSfgsch printf("%s: can't map memory to read attributes\n", 1350720f62cSfgsch sc->dev.dv_xname); 1360720f62cSfgsch #endif 1370720f62cSfgsch return -1; 1380720f62cSfgsch } 139c773fb73Sfgsch tuple.memt = pcmh.memt; 140c773fb73Sfgsch tuple.memh = pcmh.memh; 141c773fb73Sfgsch 1420720f62cSfgsch DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh)); 1430720f62cSfgsch 1440720f62cSfgsch tuple.mult = 2; 1450720f62cSfgsch 1460720f62cSfgsch longlink_present = 1; 1470720f62cSfgsch longlink_common = 1; 1480720f62cSfgsch longlink_addr = 0; 1490720f62cSfgsch 1500720f62cSfgsch mfc_count = 0; 1510720f62cSfgsch mfc_index = 0; 1520720f62cSfgsch 1530720f62cSfgsch DPRINTF(("%s: CIS tuple chain:\n", sc->dev.dv_xname)); 1540720f62cSfgsch 1550720f62cSfgsch while (1) { 1560720f62cSfgsch while (1) { 1570720f62cSfgsch /* get the tuple code */ 1580720f62cSfgsch 1590720f62cSfgsch tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr); 1600720f62cSfgsch 1610720f62cSfgsch /* two special-case tuples */ 1620720f62cSfgsch 1630720f62cSfgsch if (tuple.code == PCMCIA_CISTPL_NULL) { 1640720f62cSfgsch DPRINTF(("CISTPL_NONE\n 00\n")); 1650720f62cSfgsch tuple.ptr++; 1660720f62cSfgsch continue; 1670720f62cSfgsch } else if (tuple.code == PCMCIA_CISTPL_END) { 1680720f62cSfgsch DPRINTF(("CISTPL_END\n ff\n")); 1690720f62cSfgsch /* Call the function for the END tuple, since 1700720f62cSfgsch the CIS semantics depend on it */ 1710720f62cSfgsch if ((*fct) (&tuple, arg)) { 1720720f62cSfgsch pcmcia_chip_mem_unmap(pct, pch, 1730720f62cSfgsch window); 1740720f62cSfgsch ret = 1; 1750720f62cSfgsch goto done; 1760720f62cSfgsch } 1770720f62cSfgsch tuple.ptr++; 1780720f62cSfgsch break; 1790720f62cSfgsch } 1800720f62cSfgsch /* now all the normal tuples */ 1810720f62cSfgsch 1820720f62cSfgsch tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1); 1830720f62cSfgsch switch (tuple.code) { 1840720f62cSfgsch case PCMCIA_CISTPL_LONGLINK_A: 1850720f62cSfgsch case PCMCIA_CISTPL_LONGLINK_C: 1860720f62cSfgsch if (tuple.length < 4) { 1870720f62cSfgsch DPRINTF(("CISTPL_LONGLINK_%s too " 1880720f62cSfgsch "short %d\n", 1890720f62cSfgsch longlink_common ? "C" : "A", 1900720f62cSfgsch tuple.length)); 1910720f62cSfgsch break; 1920720f62cSfgsch } 1930720f62cSfgsch longlink_present = 1; 1940720f62cSfgsch longlink_common = (tuple.code == 1950720f62cSfgsch PCMCIA_CISTPL_LONGLINK_C) ? 1 : 0; 1960720f62cSfgsch longlink_addr = pcmcia_tuple_read_4(&tuple, 0); 1970720f62cSfgsch DPRINTF(("CISTPL_LONGLINK_%s %lx\n", 1980720f62cSfgsch longlink_common ? "C" : "A", 1990720f62cSfgsch longlink_addr)); 2000720f62cSfgsch break; 2010720f62cSfgsch case PCMCIA_CISTPL_NO_LINK: 2020720f62cSfgsch longlink_present = 0; 2030720f62cSfgsch DPRINTF(("CISTPL_NO_LINK\n")); 2040720f62cSfgsch break; 2050720f62cSfgsch case PCMCIA_CISTPL_CHECKSUM: 2060720f62cSfgsch if (tuple.length < 5) { 2070720f62cSfgsch DPRINTF(("CISTPL_CHECKSUM too " 2080720f62cSfgsch "short %d\n", tuple.length)); 2090720f62cSfgsch break; 2100720f62cSfgsch } { 2110720f62cSfgsch int16_t offset; 2120720f62cSfgsch u_long addr, length; 2130720f62cSfgsch u_int cksum, sum; 2140720f62cSfgsch int i; 2150720f62cSfgsch 2160720f62cSfgsch *((u_int16_t *) & offset) = 2170720f62cSfgsch pcmcia_tuple_read_2(&tuple, 0); 2180720f62cSfgsch length = pcmcia_tuple_read_2(&tuple, 2); 2190720f62cSfgsch cksum = pcmcia_tuple_read_1(&tuple, 4); 2200720f62cSfgsch 2210720f62cSfgsch addr = tuple.ptr + offset; 2220720f62cSfgsch 2230720f62cSfgsch DPRINTF(("CISTPL_CHECKSUM addr=%lx " 2240720f62cSfgsch "len=%lx cksum=%x", 2250720f62cSfgsch addr, length, cksum)); 2260720f62cSfgsch 2270720f62cSfgsch /* 2280720f62cSfgsch * XXX do more work to deal with 2290720f62cSfgsch * distant regions 2300720f62cSfgsch */ 2310720f62cSfgsch if ((addr >= PCMCIA_CIS_SIZE) || 2320720f62cSfgsch ((addr + length) < 0) || 2330720f62cSfgsch ((addr + length) >= 2340720f62cSfgsch PCMCIA_CIS_SIZE)) { 2350720f62cSfgsch DPRINTF((" skipped, " 2360720f62cSfgsch "too distant\n")); 2370720f62cSfgsch break; 2380720f62cSfgsch } 2390720f62cSfgsch sum = 0; 2400720f62cSfgsch for (i = 0; i < length; i++) 2410720f62cSfgsch sum += 2420720f62cSfgsch bus_space_read_1(tuple.memt, 2430720f62cSfgsch tuple.memh, 2440720f62cSfgsch addr + tuple.mult * i); 2450720f62cSfgsch if (cksum != (sum & 0xff)) { 2460720f62cSfgsch DPRINTF((" failed sum=%x\n", 2470720f62cSfgsch sum)); 2480720f62cSfgsch printf("%s: CIS checksum " 2490720f62cSfgsch "failed\n", 2500720f62cSfgsch sc->dev.dv_xname); 2510720f62cSfgsch #if 0 2520720f62cSfgsch /* 2530720f62cSfgsch * XXX Some working cards have 2540720f62cSfgsch * XXX bad checksums!! 2550720f62cSfgsch */ 2560720f62cSfgsch ret = -1; 2570720f62cSfgsch #endif 2580720f62cSfgsch } else { 2590720f62cSfgsch DPRINTF((" ok\n")); 2600720f62cSfgsch } 2610720f62cSfgsch } 2620720f62cSfgsch break; 2630720f62cSfgsch case PCMCIA_CISTPL_LONGLINK_MFC: 2648e9dce62Sfgsch if (tuple.length < 6) { 2650720f62cSfgsch DPRINTF(("CISTPL_LONGLINK_MFC too " 2660720f62cSfgsch "short %d\n", tuple.length)); 2670720f62cSfgsch break; 2680720f62cSfgsch } 2698e9dce62Sfgsch if (((tuple.length - 1) % 5) != 0) { 2708e9dce62Sfgsch DPRINTF(("CISTPL_LONGLINK_MFC bogus " 2718e9dce62Sfgsch "length %d\n", tuple.length)); 2728e9dce62Sfgsch break; 2738e9dce62Sfgsch } 2740720f62cSfgsch { 2750720f62cSfgsch int i; 2760720f62cSfgsch 2770720f62cSfgsch mfc_count = 2780720f62cSfgsch pcmcia_tuple_read_1(&tuple, 0); 2790720f62cSfgsch DPRINTF(("CISTPL_LONGLINK_MFC %d", 2800720f62cSfgsch mfc_count)); 2810720f62cSfgsch for (i = 0; i < mfc_count; i++) { 2820720f62cSfgsch mfc[i].common = 2830720f62cSfgsch (pcmcia_tuple_read_1(&tuple, 2840720f62cSfgsch 1 + 5 * i) == 2850720f62cSfgsch PCMCIA_MFC_MEM_COMMON) ? 2860720f62cSfgsch 1 : 0; 2870720f62cSfgsch mfc[i].addr = 2880720f62cSfgsch pcmcia_tuple_read_4(&tuple, 2890720f62cSfgsch 1 + 5 * i + 1); 2900720f62cSfgsch DPRINTF((" %s:%lx", 2910720f62cSfgsch mfc[i].common ? "common" : 2920720f62cSfgsch "attr", mfc[i].addr)); 2930720f62cSfgsch } 2940720f62cSfgsch DPRINTF(("\n")); 2950720f62cSfgsch } 2960720f62cSfgsch /* 2970720f62cSfgsch * for LONGLINK_MFC, fall through to the 2980720f62cSfgsch * function. This tuple has structural and 2990720f62cSfgsch * semantic content. 3000720f62cSfgsch */ 3010720f62cSfgsch default: 3020720f62cSfgsch { 3030720f62cSfgsch if ((*fct) (&tuple, arg)) { 3040720f62cSfgsch pcmcia_chip_mem_unmap(pct, 3050720f62cSfgsch pch, window); 3060720f62cSfgsch ret = 1; 3070720f62cSfgsch goto done; 3080720f62cSfgsch } 3090720f62cSfgsch } 3100720f62cSfgsch break; 3110720f62cSfgsch } /* switch */ 3120720f62cSfgsch #ifdef PCMCIACISDEBUG 3130720f62cSfgsch /* print the tuple */ 3140720f62cSfgsch { 3150720f62cSfgsch int i; 3160720f62cSfgsch 3170720f62cSfgsch DPRINTF((" %02x %02x", tuple.code, 3180720f62cSfgsch tuple.length)); 3190720f62cSfgsch 3200720f62cSfgsch for (i = 0; i < tuple.length; i++) { 3210720f62cSfgsch DPRINTF((" %02x", 3220720f62cSfgsch pcmcia_tuple_read_1(&tuple, i))); 3230720f62cSfgsch if ((i % 16) == 13) 3240720f62cSfgsch DPRINTF(("\n")); 3250720f62cSfgsch } 3260720f62cSfgsch if ((i % 16) != 14) 3270720f62cSfgsch DPRINTF(("\n")); 3280720f62cSfgsch } 3290720f62cSfgsch #endif 3300720f62cSfgsch /* skip to the next tuple */ 3310720f62cSfgsch tuple.ptr += 2 + tuple.length; 3320720f62cSfgsch } 333709e0656Sfgsch 3340720f62cSfgsch /* 3350720f62cSfgsch * the chain is done. Clean up and move onto the next one, 3360720f62cSfgsch * if any. The loop is here in the case that there is an MFC 3370720f62cSfgsch * card with no longlink (which defaults to existing, == 0). 3380720f62cSfgsch * In general, this means that if one pointer fails, it will 3390720f62cSfgsch * try the next one, instead of just bailing. 3400720f62cSfgsch */ 3410720f62cSfgsch 3420720f62cSfgsch while (1) { 3430720f62cSfgsch pcmcia_chip_mem_unmap(pct, pch, window); 3440720f62cSfgsch 3450720f62cSfgsch if (longlink_present) { 3460720f62cSfgsch /* 3470720f62cSfgsch * if the longlink is to attribute memory, 3480720f62cSfgsch * then it is unindexed. That is, if the 3490720f62cSfgsch * link value is 0x100, then the actual 3500720f62cSfgsch * memory address is 0x200. This means that 3510720f62cSfgsch * we need to multiply by 2 before calling 3520720f62cSfgsch * mem_map, and then divide the resulting ptr 3530720f62cSfgsch * by 2 after. 3540720f62cSfgsch */ 3550720f62cSfgsch 3560720f62cSfgsch if (!longlink_common) 3570720f62cSfgsch longlink_addr *= 2; 3580720f62cSfgsch 3590720f62cSfgsch pcmcia_chip_mem_map(pct, pch, longlink_common ? 3600720f62cSfgsch PCMCIA_MEM_COMMON : PCMCIA_MEM_ATTR, 3610720f62cSfgsch longlink_addr, PCMCIA_CIS_SIZE, 3620720f62cSfgsch &pcmh, &tuple.ptr, &window); 3630720f62cSfgsch 3640720f62cSfgsch if (!longlink_common) 3650720f62cSfgsch tuple.ptr /= 2; 3660720f62cSfgsch 3670720f62cSfgsch DPRINTF(("cis mem map %x\n", 3680720f62cSfgsch (unsigned int) tuple.memh)); 3690720f62cSfgsch 3700720f62cSfgsch tuple.mult = longlink_common ? 1 : 2; 3710720f62cSfgsch longlink_present = 0; 3720720f62cSfgsch longlink_common = 1; 3730720f62cSfgsch longlink_addr = 0; 3740720f62cSfgsch } else if (mfc_count && (mfc_index < mfc_count)) { 3750720f62cSfgsch if (!mfc[mfc_index].common) 3760720f62cSfgsch mfc[mfc_index].addr *= 2; 3770720f62cSfgsch 3780720f62cSfgsch pcmcia_chip_mem_map(pct, pch, 3790720f62cSfgsch mfc[mfc_index].common ? 3800720f62cSfgsch PCMCIA_MEM_COMMON : PCMCIA_MEM_ATTR, 3810720f62cSfgsch mfc[mfc_index].addr, PCMCIA_CIS_SIZE, 3820720f62cSfgsch &pcmh, &tuple.ptr, &window); 3830720f62cSfgsch 3840720f62cSfgsch if (!mfc[mfc_index].common) 3850720f62cSfgsch tuple.ptr /= 2; 3860720f62cSfgsch 3870720f62cSfgsch DPRINTF(("cis mem map %x\n", 3880720f62cSfgsch (unsigned int) tuple.memh)); 3890720f62cSfgsch 3900720f62cSfgsch /* set parse state, and point at the next one */ 3910720f62cSfgsch 3920720f62cSfgsch tuple.mult = mfc[mfc_index].common ? 1 : 2; 3930720f62cSfgsch 3940720f62cSfgsch mfc_index++; 3950720f62cSfgsch } else { 3960720f62cSfgsch goto done; 3970720f62cSfgsch } 3980720f62cSfgsch 3990720f62cSfgsch /* make sure that the link is valid */ 4000720f62cSfgsch tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr); 4010720f62cSfgsch if (tuple.code != PCMCIA_CISTPL_LINKTARGET) { 4020720f62cSfgsch DPRINTF(("CISTPL_LINKTARGET expected, " 4030720f62cSfgsch "code %02x observed\n", tuple.code)); 4040720f62cSfgsch continue; 4050720f62cSfgsch } 4060720f62cSfgsch tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1); 4070720f62cSfgsch if (tuple.length < 3) { 4080720f62cSfgsch DPRINTF(("CISTPL_LINKTARGET too short %d\n", 4090720f62cSfgsch tuple.length)); 4100720f62cSfgsch continue; 4110720f62cSfgsch } 4120720f62cSfgsch if ((pcmcia_tuple_read_1(&tuple, 0) != 'C') || 4130720f62cSfgsch (pcmcia_tuple_read_1(&tuple, 1) != 'I') || 4140720f62cSfgsch (pcmcia_tuple_read_1(&tuple, 2) != 'S')) { 4150720f62cSfgsch DPRINTF(("CISTPL_LINKTARGET magic " 4160720f62cSfgsch "%02x%02x%02x incorrect\n", 4170720f62cSfgsch pcmcia_tuple_read_1(&tuple, 0), 4180720f62cSfgsch pcmcia_tuple_read_1(&tuple, 1), 4190720f62cSfgsch pcmcia_tuple_read_1(&tuple, 2))); 4200720f62cSfgsch continue; 4210720f62cSfgsch } 4220720f62cSfgsch tuple.ptr += 2 + tuple.length; 4230720f62cSfgsch 4240720f62cSfgsch break; 4250720f62cSfgsch } 4260720f62cSfgsch } 4270720f62cSfgsch 4280720f62cSfgsch pcmcia_chip_mem_unmap(pct, pch, window); 4290720f62cSfgsch 4300720f62cSfgsch done: 4310720f62cSfgsch /* Last, free the allocated memory block */ 4320720f62cSfgsch pcmcia_chip_mem_free(pct, pch, &pcmh); 4330720f62cSfgsch 4340720f62cSfgsch return (ret); 4350720f62cSfgsch } 4360720f62cSfgsch 4370720f62cSfgsch /* XXX this is incredibly verbose. Not sure what trt is */ 4380720f62cSfgsch 4390720f62cSfgsch void 4400720f62cSfgsch pcmcia_print_cis(sc) 4410720f62cSfgsch struct pcmcia_softc *sc; 4420720f62cSfgsch { 4430720f62cSfgsch struct pcmcia_card *card = &sc->card; 4440720f62cSfgsch struct pcmcia_function *pf; 4450720f62cSfgsch struct pcmcia_config_entry *cfe; 4460720f62cSfgsch int i; 4470720f62cSfgsch 4480720f62cSfgsch printf("%s: CIS version ", sc->dev.dv_xname); 4490720f62cSfgsch if (card->cis1_major == 4) { 4500720f62cSfgsch if (card->cis1_minor == 0) 4510720f62cSfgsch printf("PCMCIA 1.0\n"); 4520720f62cSfgsch else if (card->cis1_minor == 1) 4530720f62cSfgsch printf("PCMCIA 2.0 or 2.1\n"); 4540720f62cSfgsch } else if (card->cis1_major >= 5) 4558e9dce62Sfgsch printf("PC Card Standard %d.%d\n", card->cis1_major, 4568e9dce62Sfgsch card->cis1_minor); 4570720f62cSfgsch else 4580720f62cSfgsch printf("unknown (major=%d, minor=%d)\n", 4590720f62cSfgsch card->cis1_major, card->cis1_minor); 4600720f62cSfgsch 4610720f62cSfgsch printf("%s: CIS info: ", sc->dev.dv_xname); 4620720f62cSfgsch for (i = 0; i < 4; i++) { 4630720f62cSfgsch if (card->cis1_info[i] == NULL) 4640720f62cSfgsch break; 4650720f62cSfgsch if (i) 4660720f62cSfgsch printf(", "); 4670720f62cSfgsch printf("%s", card->cis1_info[i]); 4680720f62cSfgsch } 4690720f62cSfgsch printf("\n"); 4700720f62cSfgsch 4710720f62cSfgsch printf("%s: Manufacturer code 0x%x, product 0x%x\n", 4720720f62cSfgsch sc->dev.dv_xname, card->manufacturer, card->product); 4730720f62cSfgsch 474*10412f8dSjason SIMPLEQ_FOREACH(pf, &card->pf_head, pf_list) { 4750720f62cSfgsch printf("%s: function %d: ", sc->dev.dv_xname, pf->number); 4760720f62cSfgsch 4770720f62cSfgsch switch (pf->function) { 4780720f62cSfgsch case PCMCIA_FUNCTION_UNSPEC: 4790720f62cSfgsch printf("unspecified"); 4800720f62cSfgsch break; 4810720f62cSfgsch case PCMCIA_FUNCTION_MULTIFUNCTION: 4820720f62cSfgsch printf("multi-function"); 4830720f62cSfgsch break; 4840720f62cSfgsch case PCMCIA_FUNCTION_MEMORY: 4850720f62cSfgsch printf("memory"); 4860720f62cSfgsch break; 4870720f62cSfgsch case PCMCIA_FUNCTION_SERIAL: 4880720f62cSfgsch printf("serial port"); 4890720f62cSfgsch break; 4900720f62cSfgsch case PCMCIA_FUNCTION_PARALLEL: 4910720f62cSfgsch printf("parallel port"); 4920720f62cSfgsch break; 4930720f62cSfgsch case PCMCIA_FUNCTION_DISK: 4940720f62cSfgsch printf("fixed disk"); 4950720f62cSfgsch break; 4960720f62cSfgsch case PCMCIA_FUNCTION_VIDEO: 4970720f62cSfgsch printf("video adapter"); 4980720f62cSfgsch break; 4990720f62cSfgsch case PCMCIA_FUNCTION_NETWORK: 5000720f62cSfgsch printf("network adapter"); 5010720f62cSfgsch break; 5020720f62cSfgsch case PCMCIA_FUNCTION_AIMS: 5030720f62cSfgsch printf("auto incrementing mass storage"); 5040720f62cSfgsch break; 5050720f62cSfgsch case PCMCIA_FUNCTION_SCSI: 5060720f62cSfgsch printf("SCSI bridge"); 5070720f62cSfgsch break; 5080720f62cSfgsch case PCMCIA_FUNCTION_SECURITY: 5090720f62cSfgsch printf("Security services"); 5100720f62cSfgsch break; 5110720f62cSfgsch case PCMCIA_FUNCTION_INSTRUMENT: 5120720f62cSfgsch printf("Instrument"); 5130720f62cSfgsch break; 5148e9dce62Sfgsch case PCMCIA_FUNCTION_IOBUS: 5158e9dce62Sfgsch printf("Serial I/O Bus Adapter"); 5168e9dce62Sfgsch break; 5170720f62cSfgsch default: 5180720f62cSfgsch printf("unknown (%d)", pf->function); 5190720f62cSfgsch break; 5200720f62cSfgsch } 5210720f62cSfgsch 5220720f62cSfgsch printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask); 5230720f62cSfgsch 524*10412f8dSjason SIMPLEQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 5250720f62cSfgsch printf("%s: function %d, config table entry %d: ", 5260720f62cSfgsch sc->dev.dv_xname, pf->number, cfe->number); 5270720f62cSfgsch 5280720f62cSfgsch switch (cfe->iftype) { 5290720f62cSfgsch case PCMCIA_IFTYPE_MEMORY: 5300720f62cSfgsch printf("memory card"); 5310720f62cSfgsch break; 5320720f62cSfgsch case PCMCIA_IFTYPE_IO: 5330720f62cSfgsch printf("I/O card"); 5340720f62cSfgsch break; 5350720f62cSfgsch default: 5360720f62cSfgsch printf("card type unknown"); 5370720f62cSfgsch break; 5380720f62cSfgsch } 5390720f62cSfgsch 5400720f62cSfgsch printf("; irq mask %x", cfe->irqmask); 5410720f62cSfgsch 5420720f62cSfgsch if (cfe->num_iospace) { 5430720f62cSfgsch printf("; iomask %lx, iospace", cfe->iomask); 5440720f62cSfgsch 5450720f62cSfgsch for (i = 0; i < cfe->num_iospace; i++) 5460720f62cSfgsch printf(" %lx%s%lx", 5470720f62cSfgsch cfe->iospace[i].start, 5480720f62cSfgsch cfe->iospace[i].length ? "-" : "", 5490720f62cSfgsch cfe->iospace[i].start + 5500720f62cSfgsch cfe->iospace[i].length - 1); 5510720f62cSfgsch } 5520720f62cSfgsch if (cfe->num_memspace) { 5530720f62cSfgsch printf("; memspace"); 5540720f62cSfgsch 5550720f62cSfgsch for (i = 0; i < cfe->num_memspace; i++) 5560720f62cSfgsch printf(" %lx%s%lx%s%lx", 5570720f62cSfgsch cfe->memspace[i].cardaddr, 5580720f62cSfgsch cfe->memspace[i].length ? "-" : "", 5590720f62cSfgsch cfe->memspace[i].cardaddr + 5600720f62cSfgsch cfe->memspace[i].length - 1, 5610720f62cSfgsch cfe->memspace[i].hostaddr ? 5620720f62cSfgsch "@" : "", 5630720f62cSfgsch cfe->memspace[i].hostaddr); 5640720f62cSfgsch } 5650720f62cSfgsch if (cfe->maxtwins) 5660720f62cSfgsch printf("; maxtwins %d", cfe->maxtwins); 5670720f62cSfgsch 5680720f62cSfgsch printf(";"); 5690720f62cSfgsch 5700720f62cSfgsch if (cfe->flags & PCMCIA_CFE_MWAIT_REQUIRED) 5710720f62cSfgsch printf(" mwait_required"); 5720720f62cSfgsch if (cfe->flags & PCMCIA_CFE_RDYBSY_ACTIVE) 5730720f62cSfgsch printf(" rdybsy_active"); 5740720f62cSfgsch if (cfe->flags & PCMCIA_CFE_WP_ACTIVE) 5750720f62cSfgsch printf(" wp_active"); 5760720f62cSfgsch if (cfe->flags & PCMCIA_CFE_BVD_ACTIVE) 5770720f62cSfgsch printf(" bvd_active"); 5780720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IO8) 5790720f62cSfgsch printf(" io8"); 5800720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IO16) 5810720f62cSfgsch printf(" io16"); 5820720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IRQSHARE) 5830720f62cSfgsch printf(" irqshare"); 5840720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IRQPULSE) 5850720f62cSfgsch printf(" irqpulse"); 5860720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IRQLEVEL) 5870720f62cSfgsch printf(" irqlevel"); 5880720f62cSfgsch if (cfe->flags & PCMCIA_CFE_POWERDOWN) 5890720f62cSfgsch printf(" powerdown"); 5900720f62cSfgsch if (cfe->flags & PCMCIA_CFE_READONLY) 5910720f62cSfgsch printf(" readonly"); 5920720f62cSfgsch if (cfe->flags & PCMCIA_CFE_AUDIO) 5930720f62cSfgsch printf(" audio"); 5940720f62cSfgsch 5950720f62cSfgsch printf("\n"); 5960720f62cSfgsch } 5970720f62cSfgsch } 5980720f62cSfgsch 5990720f62cSfgsch if (card->error) 6000720f62cSfgsch printf("%s: %d errors found while parsing CIS\n", 6010720f62cSfgsch sc->dev.dv_xname, card->error); 6020720f62cSfgsch } 6030720f62cSfgsch 6040720f62cSfgsch int 6050720f62cSfgsch pcmcia_parse_cis_tuple(tuple, arg) 6060720f62cSfgsch struct pcmcia_tuple *tuple; 6070720f62cSfgsch void *arg; 6080720f62cSfgsch { 6090720f62cSfgsch /* most of these are educated guesses */ 6100720f62cSfgsch static struct pcmcia_config_entry init_cfe = { 6110720f62cSfgsch -1, PCMCIA_CFE_RDYBSY_ACTIVE | PCMCIA_CFE_WP_ACTIVE | 6120720f62cSfgsch PCMCIA_CFE_BVD_ACTIVE, PCMCIA_IFTYPE_MEMORY, 6130720f62cSfgsch }; 6140720f62cSfgsch 6150720f62cSfgsch struct cis_state *state = arg; 6160720f62cSfgsch 6170720f62cSfgsch switch (tuple->code) { 6180720f62cSfgsch case PCMCIA_CISTPL_END: 619bd4ab2b6Sniklas /* 620bd4ab2b6Sniklas * If we've seen a LONGLINK_MFC, and this is the first 6210720f62cSfgsch * END after it, reset the function list. 6220720f62cSfgsch * 6230720f62cSfgsch * XXX This might also be the right place to start a 6240720f62cSfgsch * new function, but that assumes that a function 6250720f62cSfgsch * definition never crosses any longlink, and I'm not 6260720f62cSfgsch * sure about that. This is probably safe for MFC 6270720f62cSfgsch * cards, but what we have now isn't broken, so I'd 6280720f62cSfgsch * rather not change it. 6290720f62cSfgsch */ 6300720f62cSfgsch if (state->gotmfc == 1) { 6310720f62cSfgsch struct pcmcia_function *pf, *pfnext; 6320720f62cSfgsch 633*10412f8dSjason for (pf = SIMPLEQ_FIRST(&state->card->pf_head); 634*10412f8dSjason pf != NULL; pf = pfnext) { 635*10412f8dSjason pfnext = SIMPLEQ_NEXT(pf, pf_list); 6360720f62cSfgsch free(pf, M_DEVBUF); 6370720f62cSfgsch } 6380720f62cSfgsch 6390720f62cSfgsch SIMPLEQ_INIT(&state->card->pf_head); 6400720f62cSfgsch 6410720f62cSfgsch state->count = 0; 6420720f62cSfgsch state->gotmfc = 2; 6430720f62cSfgsch state->pf = NULL; 6440720f62cSfgsch } 6450720f62cSfgsch break; 646bd4ab2b6Sniklas 6470720f62cSfgsch case PCMCIA_CISTPL_LONGLINK_MFC: 6480720f62cSfgsch /* 649bd4ab2b6Sniklas * This tuple's structure was dealt with in scan_cis. here, 6500720f62cSfgsch * record the fact that the MFC tuple was seen, so that 6510720f62cSfgsch * functions declared before the MFC link can be cleaned 6520720f62cSfgsch * up. 6530720f62cSfgsch */ 6540720f62cSfgsch state->gotmfc = 1; 6550720f62cSfgsch break; 656bd4ab2b6Sniklas 6570720f62cSfgsch #ifdef PCMCIACISDEBUG 6580720f62cSfgsch case PCMCIA_CISTPL_DEVICE: 6590720f62cSfgsch case PCMCIA_CISTPL_DEVICE_A: 6600720f62cSfgsch { 6610720f62cSfgsch u_int reg, dtype, dspeed; 6620720f62cSfgsch 6630720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, 0); 6640720f62cSfgsch dtype = reg & PCMCIA_DTYPE_MASK; 6650720f62cSfgsch dspeed = reg & PCMCIA_DSPEED_MASK; 6660720f62cSfgsch 6670720f62cSfgsch DPRINTF(("CISTPL_DEVICE%s type=", 6680720f62cSfgsch (tuple->code == PCMCIA_CISTPL_DEVICE) ? "" : "_A")); 6690720f62cSfgsch switch (dtype) { 6700720f62cSfgsch case PCMCIA_DTYPE_NULL: 6710720f62cSfgsch DPRINTF(("null")); 6720720f62cSfgsch break; 6730720f62cSfgsch case PCMCIA_DTYPE_ROM: 6740720f62cSfgsch DPRINTF(("rom")); 6750720f62cSfgsch break; 6760720f62cSfgsch case PCMCIA_DTYPE_OTPROM: 6770720f62cSfgsch DPRINTF(("otprom")); 6780720f62cSfgsch break; 6790720f62cSfgsch case PCMCIA_DTYPE_EPROM: 6800720f62cSfgsch DPRINTF(("eprom")); 6810720f62cSfgsch break; 6820720f62cSfgsch case PCMCIA_DTYPE_EEPROM: 6830720f62cSfgsch DPRINTF(("eeprom")); 6840720f62cSfgsch break; 6850720f62cSfgsch case PCMCIA_DTYPE_FLASH: 6860720f62cSfgsch DPRINTF(("flash")); 6870720f62cSfgsch break; 6880720f62cSfgsch case PCMCIA_DTYPE_SRAM: 6890720f62cSfgsch DPRINTF(("sram")); 6900720f62cSfgsch break; 6910720f62cSfgsch case PCMCIA_DTYPE_DRAM: 6920720f62cSfgsch DPRINTF(("dram")); 6930720f62cSfgsch break; 6940720f62cSfgsch case PCMCIA_DTYPE_FUNCSPEC: 6950720f62cSfgsch DPRINTF(("funcspec")); 6960720f62cSfgsch break; 6970720f62cSfgsch case PCMCIA_DTYPE_EXTEND: 6980720f62cSfgsch DPRINTF(("extend")); 6990720f62cSfgsch break; 7000720f62cSfgsch default: 7010720f62cSfgsch DPRINTF(("reserved")); 7020720f62cSfgsch break; 7030720f62cSfgsch } 7040720f62cSfgsch DPRINTF((" speed=")); 7050720f62cSfgsch switch (dspeed) { 7060720f62cSfgsch case PCMCIA_DSPEED_NULL: 7070720f62cSfgsch DPRINTF(("null")); 7080720f62cSfgsch break; 7090720f62cSfgsch case PCMCIA_DSPEED_250NS: 7100720f62cSfgsch DPRINTF(("250ns")); 7110720f62cSfgsch break; 7120720f62cSfgsch case PCMCIA_DSPEED_200NS: 7130720f62cSfgsch DPRINTF(("200ns")); 7140720f62cSfgsch break; 7150720f62cSfgsch case PCMCIA_DSPEED_150NS: 7160720f62cSfgsch DPRINTF(("150ns")); 7170720f62cSfgsch break; 7180720f62cSfgsch case PCMCIA_DSPEED_100NS: 7190720f62cSfgsch DPRINTF(("100ns")); 7200720f62cSfgsch break; 7210720f62cSfgsch case PCMCIA_DSPEED_EXT: 7220720f62cSfgsch DPRINTF(("ext")); 7230720f62cSfgsch break; 7240720f62cSfgsch default: 7250720f62cSfgsch DPRINTF(("reserved")); 7260720f62cSfgsch break; 7270720f62cSfgsch } 7280720f62cSfgsch } 7290720f62cSfgsch DPRINTF(("\n")); 7300720f62cSfgsch break; 7310720f62cSfgsch #endif 732bd4ab2b6Sniklas 7330720f62cSfgsch case PCMCIA_CISTPL_VERS_1: 7340720f62cSfgsch if (tuple->length < 6) { 7350720f62cSfgsch DPRINTF(("CISTPL_VERS_1 too short %d\n", 7360720f62cSfgsch tuple->length)); 7370720f62cSfgsch break; 7380720f62cSfgsch } { 7390720f62cSfgsch int start, i, ch, count; 7400720f62cSfgsch 7410720f62cSfgsch state->card->cis1_major = pcmcia_tuple_read_1(tuple, 0); 7420720f62cSfgsch state->card->cis1_minor = pcmcia_tuple_read_1(tuple, 1); 7430720f62cSfgsch 7440720f62cSfgsch for (count = 0, start = 0, i = 0; 7450720f62cSfgsch (count < 4) && ((i + 4) < 256); i++) { 7460720f62cSfgsch ch = pcmcia_tuple_read_1(tuple, 2 + i); 7470720f62cSfgsch if (ch == 0xff) 7480720f62cSfgsch break; 7490720f62cSfgsch state->card->cis1_info_buf[i] = ch; 7500720f62cSfgsch if (ch == 0) { 7510720f62cSfgsch state->card->cis1_info[count] = 7520720f62cSfgsch state->card->cis1_info_buf + start; 7530720f62cSfgsch start = i + 1; 7540720f62cSfgsch count++; 7550720f62cSfgsch } 7560720f62cSfgsch } 7570720f62cSfgsch DPRINTF(("CISTPL_VERS_1\n")); 7580720f62cSfgsch } 7590720f62cSfgsch break; 760bd4ab2b6Sniklas 7610720f62cSfgsch case PCMCIA_CISTPL_MANFID: 7620720f62cSfgsch if (tuple->length < 4) { 7630720f62cSfgsch DPRINTF(("CISTPL_MANFID too short %d\n", 7640720f62cSfgsch tuple->length)); 7650720f62cSfgsch break; 7660720f62cSfgsch } 7670720f62cSfgsch state->card->manufacturer = pcmcia_tuple_read_2(tuple, 0); 7680720f62cSfgsch state->card->product = pcmcia_tuple_read_2(tuple, 2); 7690720f62cSfgsch DPRINTF(("CISTPL_MANFID\n")); 7700720f62cSfgsch break; 771bd4ab2b6Sniklas 7720720f62cSfgsch case PCMCIA_CISTPL_FUNCID: 7738e9dce62Sfgsch if (tuple->length < 2) { 7740720f62cSfgsch DPRINTF(("CISTPL_FUNCID too short %d\n", 7750720f62cSfgsch tuple->length)); 7760720f62cSfgsch break; 7770720f62cSfgsch } 778bd4ab2b6Sniklas 779bd4ab2b6Sniklas /* 780bd4ab2b6Sniklas * As far as I understand this, manufacturers do multifunction 781bd4ab2b6Sniklas * cards in various ways. Sadly enough I do not have the 782bd4ab2b6Sniklas * PC-Card standard (donate!) so I can only guess what can 783bd4ab2b6Sniklas * be done. 784bd4ab2b6Sniklas * The original code implies FUNCID nodes are above CONFIG 785bd4ab2b6Sniklas * nodes in the CIS tree, however Xircom does it the other 786bd4ab2b6Sniklas * way round, which of course makes things a bit hard. 787bd4ab2b6Sniklas * --niklas@openbsd.org 788bd4ab2b6Sniklas */ 789bd4ab2b6Sniklas if (state->pf) { 790bd4ab2b6Sniklas if (state->pf->function == PCMCIA_FUNCTION_UNSPEC) { 791bd4ab2b6Sniklas /* 792bd4ab2b6Sniklas * This looks like a opportunistic function 793bd4ab2b6Sniklas * created by a CONFIG tuple. Just keep it. 794bd4ab2b6Sniklas */ 795bd4ab2b6Sniklas } else { 796bd4ab2b6Sniklas /* 797bd4ab2b6Sniklas * A function is being defined, end it. 798bd4ab2b6Sniklas */ 799bd4ab2b6Sniklas state->pf = NULL; 800bd4ab2b6Sniklas } 801bd4ab2b6Sniklas } 802bd4ab2b6Sniklas if (state->pf == NULL) { 8030720f62cSfgsch state->pf = malloc(sizeof(*state->pf), M_DEVBUF, 8040720f62cSfgsch M_NOWAIT); 8058584d5e3Snordin if (state->pf == NULL) 8068584d5e3Snordin panic("pcmcia_parse_cis_tuple"); 8070720f62cSfgsch bzero(state->pf, sizeof(*state->pf)); 8080720f62cSfgsch state->pf->number = state->count++; 8090720f62cSfgsch state->pf->last_config_index = -1; 8100720f62cSfgsch SIMPLEQ_INIT(&state->pf->cfe_head); 8110720f62cSfgsch 8120720f62cSfgsch SIMPLEQ_INSERT_TAIL(&state->card->pf_head, state->pf, 8130720f62cSfgsch pf_list); 8140720f62cSfgsch } 8150720f62cSfgsch state->pf->function = pcmcia_tuple_read_1(tuple, 0); 8160720f62cSfgsch 8170720f62cSfgsch DPRINTF(("CISTPL_FUNCID\n")); 8180720f62cSfgsch break; 819bd4ab2b6Sniklas 8200720f62cSfgsch case PCMCIA_CISTPL_CONFIG: 8218e9dce62Sfgsch if (tuple->length < 5) { 8220720f62cSfgsch DPRINTF(("CISTPL_CONFIG too short %d\n", 8230720f62cSfgsch tuple->length)); 8240720f62cSfgsch break; 8250720f62cSfgsch } { 8260720f62cSfgsch u_int reg, rasz, rmsz, rfsz; 8270720f62cSfgsch int i; 8280720f62cSfgsch 8290720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, 0); 8300720f62cSfgsch rasz = 1 + ((reg & PCMCIA_TPCC_RASZ_MASK) >> 8310720f62cSfgsch PCMCIA_TPCC_RASZ_SHIFT); 8320720f62cSfgsch rmsz = 1 + ((reg & PCMCIA_TPCC_RMSZ_MASK) >> 8330720f62cSfgsch PCMCIA_TPCC_RMSZ_SHIFT); 8340720f62cSfgsch rfsz = ((reg & PCMCIA_TPCC_RFSZ_MASK) >> 8350720f62cSfgsch PCMCIA_TPCC_RFSZ_SHIFT); 8360720f62cSfgsch 8370720f62cSfgsch if (tuple->length < (rasz + rmsz + rfsz)) { 8380720f62cSfgsch DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too " 8390720f62cSfgsch "short %d\n", rasz, rmsz, rfsz, 8400720f62cSfgsch tuple->length)); 8410720f62cSfgsch break; 8420720f62cSfgsch } 8430720f62cSfgsch if (state->pf == NULL) { 8440720f62cSfgsch state->pf = malloc(sizeof(*state->pf), 8450720f62cSfgsch M_DEVBUF, M_NOWAIT); 8468584d5e3Snordin if (state->pf == NULL) 8478584d5e3Snordin panic("pcmcia_parse_cis_tuple"); 8480720f62cSfgsch bzero(state->pf, sizeof(*state->pf)); 8490720f62cSfgsch state->pf->number = state->count++; 8500720f62cSfgsch state->pf->last_config_index = -1; 8510720f62cSfgsch SIMPLEQ_INIT(&state->pf->cfe_head); 8520720f62cSfgsch 8530720f62cSfgsch SIMPLEQ_INSERT_TAIL(&state->card->pf_head, 8540720f62cSfgsch state->pf, pf_list); 8550720f62cSfgsch 8560720f62cSfgsch state->pf->function = PCMCIA_FUNCTION_UNSPEC; 8570720f62cSfgsch } 8580720f62cSfgsch state->pf->last_config_index = 8590720f62cSfgsch pcmcia_tuple_read_1(tuple, 1); 8600720f62cSfgsch 8610720f62cSfgsch state->pf->ccr_base = 0; 8620720f62cSfgsch for (i = 0; i < rasz; i++) 8630720f62cSfgsch state->pf->ccr_base |= 8640720f62cSfgsch ((pcmcia_tuple_read_1(tuple, 2 + i)) << 8650720f62cSfgsch (i * 8)); 8660720f62cSfgsch 8670720f62cSfgsch state->pf->ccr_mask = 0; 8680720f62cSfgsch for (i = 0; i < rmsz; i++) 8690720f62cSfgsch state->pf->ccr_mask |= 8700720f62cSfgsch ((pcmcia_tuple_read_1(tuple, 8710720f62cSfgsch 2 + rasz + i)) << (i * 8)); 8720720f62cSfgsch 8730720f62cSfgsch /* skip the reserved area and subtuples */ 8740720f62cSfgsch 8750720f62cSfgsch /* reset the default cfe for each cfe list */ 8760720f62cSfgsch state->temp_cfe = init_cfe; 8770720f62cSfgsch state->default_cfe = &state->temp_cfe; 8780720f62cSfgsch } 8790720f62cSfgsch DPRINTF(("CISTPL_CONFIG\n")); 8800720f62cSfgsch break; 881bd4ab2b6Sniklas 8820720f62cSfgsch case PCMCIA_CISTPL_CFTABLE_ENTRY: 8838e9dce62Sfgsch if (tuple->length < 2) { 8848e9dce62Sfgsch DPRINTF(("CISTPL_CFTABLE_ENTRY too short %d\n", 8858e9dce62Sfgsch tuple->length)); 8868e9dce62Sfgsch break; 8878e9dce62Sfgsch } { 8880720f62cSfgsch int idx, i, j; 8890720f62cSfgsch u_int reg, reg2; 8900720f62cSfgsch u_int intface, def, num; 8910720f62cSfgsch u_int power, timing, iospace, irq, memspace, misc; 8920720f62cSfgsch struct pcmcia_config_entry *cfe; 8930720f62cSfgsch 8940720f62cSfgsch idx = 0; 8950720f62cSfgsch 8960720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 8970720f62cSfgsch idx++; 8980720f62cSfgsch intface = reg & PCMCIA_TPCE_INDX_INTFACE; 8990720f62cSfgsch def = reg & PCMCIA_TPCE_INDX_DEFAULT; 9000720f62cSfgsch num = reg & PCMCIA_TPCE_INDX_NUM_MASK; 9010720f62cSfgsch 9020720f62cSfgsch /* 9030720f62cSfgsch * this is a little messy. Some cards have only a 9040720f62cSfgsch * cfentry with the default bit set. So, as we go 9050720f62cSfgsch * through the list, we add new indexes to the queue, 9060720f62cSfgsch * and keep a pointer to the last one with the 9070720f62cSfgsch * default bit set. if we see a record with the same 9080720f62cSfgsch * index, as the default, we stash the default and 9090720f62cSfgsch * replace the queue entry. otherwise, we just add 9100720f62cSfgsch * new entries to the queue, pointing the default ptr 9110720f62cSfgsch * at them if the default bit is set. if we get to 9120720f62cSfgsch * the end with the default pointer pointing at a 9130720f62cSfgsch * record which hasn't had a matching index, that's 9140720f62cSfgsch * ok; it just becomes a cfentry like any other. 9150720f62cSfgsch */ 9160720f62cSfgsch 9170720f62cSfgsch /* 9180720f62cSfgsch * if the index in the cis differs from the default 9190720f62cSfgsch * cis, create new entry in the queue and start it 9200720f62cSfgsch * with the current default 9210720f62cSfgsch */ 9220720f62cSfgsch if (num != state->default_cfe->number) { 9230720f62cSfgsch cfe = (struct pcmcia_config_entry *) 9240720f62cSfgsch malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 9258584d5e3Snordin if (cfe == NULL) 9268584d5e3Snordin panic("pcmcia_parse_cis_tuple"); 9270720f62cSfgsch 9280720f62cSfgsch *cfe = *state->default_cfe; 9290720f62cSfgsch 9300720f62cSfgsch SIMPLEQ_INSERT_TAIL(&state->pf->cfe_head, 9310720f62cSfgsch cfe, cfe_list); 9320720f62cSfgsch 9330720f62cSfgsch cfe->number = num; 9340720f62cSfgsch 9350720f62cSfgsch /* 9360720f62cSfgsch * if the default bit is set in the cis, then 9370720f62cSfgsch * point the new default at whatever is being 9380720f62cSfgsch * filled in 9390720f62cSfgsch */ 9400720f62cSfgsch if (def) 9410720f62cSfgsch state->default_cfe = cfe; 9420720f62cSfgsch } else { 9430720f62cSfgsch /* 9440720f62cSfgsch * the cis index matches the default index, 9450720f62cSfgsch * fill in the default cfentry. It is 9460720f62cSfgsch * assumed that the cfdefault index is in the 9470720f62cSfgsch * queue. For it to be otherwise, the cis 9480720f62cSfgsch * index would have to be -1 (initial 9490720f62cSfgsch * condition) which is not possible, or there 9500720f62cSfgsch * would have to be a preceding cis entry 9510720f62cSfgsch * which had the same cis index and had the 9520720f62cSfgsch * default bit unset. Neither condition 9530720f62cSfgsch * should happen. If it does, this cfentry 9540720f62cSfgsch * is lost (written into temp space), which 9550720f62cSfgsch * is an acceptable failure mode. 9560720f62cSfgsch */ 9570720f62cSfgsch 9580720f62cSfgsch cfe = state->default_cfe; 9590720f62cSfgsch 9600720f62cSfgsch /* 9610720f62cSfgsch * if the cis entry does not have the default 9620720f62cSfgsch * bit set, copy the default out of the way 9630720f62cSfgsch * first. 9640720f62cSfgsch */ 9650720f62cSfgsch if (!def) { 9660720f62cSfgsch state->temp_cfe = *state->default_cfe; 9670720f62cSfgsch state->default_cfe = &state->temp_cfe; 9680720f62cSfgsch } 9690720f62cSfgsch } 9700720f62cSfgsch 9710720f62cSfgsch if (intface) { 9720720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 9730720f62cSfgsch idx++; 9748e9dce62Sfgsch cfe->flags &= ~(PCMCIA_CFE_MWAIT_REQUIRED 9758e9dce62Sfgsch | PCMCIA_CFE_RDYBSY_ACTIVE 9768e9dce62Sfgsch | PCMCIA_CFE_WP_ACTIVE 9778e9dce62Sfgsch | PCMCIA_CFE_BVD_ACTIVE); 9780720f62cSfgsch if (reg & PCMCIA_TPCE_IF_MWAIT) 9790720f62cSfgsch cfe->flags |= PCMCIA_CFE_MWAIT_REQUIRED; 9800720f62cSfgsch if (reg & PCMCIA_TPCE_IF_RDYBSY) 9810720f62cSfgsch cfe->flags |= PCMCIA_CFE_RDYBSY_ACTIVE; 9820720f62cSfgsch if (reg & PCMCIA_TPCE_IF_WP) 9830720f62cSfgsch cfe->flags |= PCMCIA_CFE_WP_ACTIVE; 9840720f62cSfgsch if (reg & PCMCIA_TPCE_IF_BVD) 9850720f62cSfgsch cfe->flags |= PCMCIA_CFE_BVD_ACTIVE; 9860720f62cSfgsch cfe->iftype = reg & PCMCIA_TPCE_IF_IFTYPE; 9870720f62cSfgsch } 9880720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 9890720f62cSfgsch idx++; 9900720f62cSfgsch 9910720f62cSfgsch power = reg & PCMCIA_TPCE_FS_POWER_MASK; 9920720f62cSfgsch timing = reg & PCMCIA_TPCE_FS_TIMING; 9930720f62cSfgsch iospace = reg & PCMCIA_TPCE_FS_IOSPACE; 9940720f62cSfgsch irq = reg & PCMCIA_TPCE_FS_IRQ; 9950720f62cSfgsch memspace = reg & PCMCIA_TPCE_FS_MEMSPACE_MASK; 9960720f62cSfgsch misc = reg & PCMCIA_TPCE_FS_MISC; 9970720f62cSfgsch 9980720f62cSfgsch if (power) { 9990720f62cSfgsch /* skip over power, don't save */ 10000720f62cSfgsch /* for each parameter selection byte */ 10010720f62cSfgsch for (i = 0; i < power; i++) { 10020720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10030720f62cSfgsch idx++; 10040720f62cSfgsch /* for each bit */ 10050720f62cSfgsch for (j = 0; j < 7; j++) { 10060720f62cSfgsch /* if the bit is set */ 10070720f62cSfgsch if ((reg >> j) & 0x01) { 10080720f62cSfgsch /* skip over bytes */ 10090720f62cSfgsch do { 10100720f62cSfgsch reg2 = pcmcia_tuple_read_1(tuple, idx); 10110720f62cSfgsch idx++; 10120720f62cSfgsch /* 10130720f62cSfgsch * until 10140720f62cSfgsch * non-extensi 10150720f62cSfgsch * on byte 10160720f62cSfgsch */ 10170720f62cSfgsch } while (reg2 & 0x80); 10180720f62cSfgsch } 10190720f62cSfgsch } 10200720f62cSfgsch } 10210720f62cSfgsch } 10220720f62cSfgsch if (timing) { 10230720f62cSfgsch /* skip over timing, don't save */ 10240720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10250720f62cSfgsch idx++; 10260720f62cSfgsch 10270720f62cSfgsch if ((reg & PCMCIA_TPCE_TD_RESERVED_MASK) != 10280720f62cSfgsch PCMCIA_TPCE_TD_RESERVED_MASK) 10290720f62cSfgsch idx++; 10300720f62cSfgsch if ((reg & PCMCIA_TPCE_TD_RDYBSY_MASK) != 10310720f62cSfgsch PCMCIA_TPCE_TD_RDYBSY_MASK) 10320720f62cSfgsch idx++; 10330720f62cSfgsch if ((reg & PCMCIA_TPCE_TD_WAIT_MASK) != 10340720f62cSfgsch PCMCIA_TPCE_TD_WAIT_MASK) 10350720f62cSfgsch idx++; 10360720f62cSfgsch } 10370720f62cSfgsch if (iospace) { 1038709e0656Sfgsch if (tuple->length <= idx) { 1039709e0656Sfgsch DPRINTF(("ran out of space before TPCE_IO\n")); 1040709e0656Sfgsch 1041709e0656Sfgsch goto abort_cfe; 1042709e0656Sfgsch } 1043709e0656Sfgsch 10440720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10450720f62cSfgsch idx++; 10460720f62cSfgsch 1047ae2d8a60Sfgsch cfe->flags &= 1048ae2d8a60Sfgsch ~(PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16); 10490720f62cSfgsch if (reg & PCMCIA_TPCE_IO_BUSWIDTH_8BIT) 10500720f62cSfgsch cfe->flags |= PCMCIA_CFE_IO8; 10510720f62cSfgsch if (reg & PCMCIA_TPCE_IO_BUSWIDTH_16BIT) 10520720f62cSfgsch cfe->flags |= PCMCIA_CFE_IO16; 10530720f62cSfgsch cfe->iomask = 10540720f62cSfgsch reg & PCMCIA_TPCE_IO_IOADDRLINES_MASK; 10550720f62cSfgsch 10560720f62cSfgsch if (reg & PCMCIA_TPCE_IO_HASRANGE) { 10570720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10580720f62cSfgsch idx++; 10590720f62cSfgsch 10600720f62cSfgsch cfe->num_iospace = 1 + (reg & 10610720f62cSfgsch PCMCIA_TPCE_IO_RANGE_COUNT); 10620720f62cSfgsch 10630720f62cSfgsch if (cfe->num_iospace > 10640720f62cSfgsch (sizeof(cfe->iospace) / 10650720f62cSfgsch sizeof(cfe->iospace[0]))) { 10660720f62cSfgsch DPRINTF(("too many io " 10670720f62cSfgsch "spaces %d", 10680720f62cSfgsch cfe->num_iospace)); 10690720f62cSfgsch state->card->error++; 10700720f62cSfgsch break; 10710720f62cSfgsch } 10720720f62cSfgsch for (i = 0; i < cfe->num_iospace; i++) { 10730720f62cSfgsch switch (reg & PCMCIA_TPCE_IO_RANGE_ADDRSIZE_MASK) { 10740720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_ONE: 10750720f62cSfgsch cfe->iospace[i].start = 10760720f62cSfgsch pcmcia_tuple_read_1(tuple, idx); 10770720f62cSfgsch idx++; 10780720f62cSfgsch break; 10790720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_TWO: 10800720f62cSfgsch cfe->iospace[i].start = 10810720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 10820720f62cSfgsch idx += 2; 10830720f62cSfgsch break; 10840720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_FOUR: 10850720f62cSfgsch cfe->iospace[i].start = 10860720f62cSfgsch pcmcia_tuple_read_4(tuple, idx); 10870720f62cSfgsch idx += 4; 10880720f62cSfgsch break; 10890720f62cSfgsch } 10900720f62cSfgsch switch (reg & 10910720f62cSfgsch PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_MASK) { 10920720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_ONE: 10930720f62cSfgsch cfe->iospace[i].length = 10940720f62cSfgsch pcmcia_tuple_read_1(tuple, idx); 10950720f62cSfgsch idx++; 10960720f62cSfgsch break; 10970720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_TWO: 10980720f62cSfgsch cfe->iospace[i].length = 10990720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 11000720f62cSfgsch idx += 2; 11010720f62cSfgsch break; 11020720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_FOUR: 11030720f62cSfgsch cfe->iospace[i].length = 11040720f62cSfgsch pcmcia_tuple_read_4(tuple, idx); 11050720f62cSfgsch idx += 4; 11060720f62cSfgsch break; 11070720f62cSfgsch } 11080720f62cSfgsch cfe->iospace[i].length++; 11090720f62cSfgsch } 11100720f62cSfgsch } else { 11110720f62cSfgsch cfe->num_iospace = 1; 11120720f62cSfgsch cfe->iospace[0].start = 0; 11130720f62cSfgsch cfe->iospace[0].length = 11140720f62cSfgsch (1 << cfe->iomask); 11150720f62cSfgsch } 11160720f62cSfgsch } 1117bd4ab2b6Sniklas 11180720f62cSfgsch if (irq) { 1119709e0656Sfgsch if (tuple->length <= idx) { 1120709e0656Sfgsch DPRINTF(("ran out of space before TPCE_IR\n")); 1121709e0656Sfgsch 1122709e0656Sfgsch goto abort_cfe; 1123709e0656Sfgsch } 1124709e0656Sfgsch 11250720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 11260720f62cSfgsch idx++; 11270720f62cSfgsch 1128ae2d8a60Sfgsch cfe->flags &= ~(PCMCIA_CFE_IRQSHARE 1129ae2d8a60Sfgsch | PCMCIA_CFE_IRQPULSE 1130ae2d8a60Sfgsch | PCMCIA_CFE_IRQLEVEL); 11310720f62cSfgsch if (reg & PCMCIA_TPCE_IR_SHARE) 11320720f62cSfgsch cfe->flags |= PCMCIA_CFE_IRQSHARE; 11330720f62cSfgsch if (reg & PCMCIA_TPCE_IR_PULSE) 11340720f62cSfgsch cfe->flags |= PCMCIA_CFE_IRQPULSE; 11350720f62cSfgsch if (reg & PCMCIA_TPCE_IR_LEVEL) 11360720f62cSfgsch cfe->flags |= PCMCIA_CFE_IRQLEVEL; 11370720f62cSfgsch 11380720f62cSfgsch if (reg & PCMCIA_TPCE_IR_HASMASK) { 11390720f62cSfgsch /* 11400720f62cSfgsch * it's legal to ignore the 11410720f62cSfgsch * special-interrupt bits, so I will 11420720f62cSfgsch */ 11430720f62cSfgsch 11440720f62cSfgsch cfe->irqmask = 11450720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 11460720f62cSfgsch idx += 2; 11470720f62cSfgsch } else { 11480720f62cSfgsch cfe->irqmask = 11490720f62cSfgsch (1 << (reg & PCMCIA_TPCE_IR_IRQ)); 11500720f62cSfgsch } 11510720f62cSfgsch } 11520720f62cSfgsch if (memspace) { 1153709e0656Sfgsch if (tuple->length <= idx) { 1154709e0656Sfgsch DPRINTF(("ran out of space before TPCE_MS\n")); 1155709e0656Sfgsch goto abort_cfe; 1156709e0656Sfgsch } 1157709e0656Sfgsch 1158709e0656Sfgsch if (memspace == PCMCIA_TPCE_FS_MEMSPACE_NONE) { 1159709e0656Sfgsch cfe->num_memspace = 0; 1160709e0656Sfgsch } else if (memspace == PCMCIA_TPCE_FS_MEMSPACE_LENGTH) { 11610720f62cSfgsch cfe->num_memspace = 1; 11620720f62cSfgsch cfe->memspace[0].length = 256 * 11630720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 11640720f62cSfgsch idx += 2; 11650720f62cSfgsch cfe->memspace[0].cardaddr = 0; 11660720f62cSfgsch cfe->memspace[0].hostaddr = 0; 11670720f62cSfgsch } else if (memspace == 11680720f62cSfgsch PCMCIA_TPCE_FS_MEMSPACE_LENGTHADDR) { 11690720f62cSfgsch cfe->num_memspace = 1; 11700720f62cSfgsch cfe->memspace[0].length = 256 * 11710720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 11720720f62cSfgsch idx += 2; 11730720f62cSfgsch cfe->memspace[0].cardaddr = 256 * 11740720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 11750720f62cSfgsch idx += 2; 1176709e0656Sfgsch cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr; 11770720f62cSfgsch } else { 11780720f62cSfgsch int lengthsize; 11790720f62cSfgsch int cardaddrsize; 11800720f62cSfgsch int hostaddrsize; 11810720f62cSfgsch 11820720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 11830720f62cSfgsch idx++; 11840720f62cSfgsch 11858e9dce62Sfgsch cfe->num_memspace = (reg & 11868e9dce62Sfgsch PCMCIA_TPCE_MS_COUNT) + 1; 11870720f62cSfgsch 11880720f62cSfgsch if (cfe->num_memspace > 11890720f62cSfgsch (sizeof(cfe->memspace) / 11900720f62cSfgsch sizeof(cfe->memspace[0]))) { 11910720f62cSfgsch DPRINTF(("too many mem " 11920720f62cSfgsch "spaces %d", 11930720f62cSfgsch cfe->num_memspace)); 11940720f62cSfgsch state->card->error++; 11950720f62cSfgsch break; 11960720f62cSfgsch } 11970720f62cSfgsch lengthsize = 11980720f62cSfgsch ((reg & PCMCIA_TPCE_MS_LENGTH_SIZE_MASK) >> 11990720f62cSfgsch PCMCIA_TPCE_MS_LENGTH_SIZE_SHIFT); 12000720f62cSfgsch cardaddrsize = 12010720f62cSfgsch ((reg & PCMCIA_TPCE_MS_CARDADDR_SIZE_MASK) >> 12020720f62cSfgsch PCMCIA_TPCE_MS_CARDADDR_SIZE_SHIFT); 12030720f62cSfgsch hostaddrsize = 12040720f62cSfgsch (reg & PCMCIA_TPCE_MS_HOSTADDR) ? cardaddrsize : 0; 12050720f62cSfgsch 12060720f62cSfgsch if (lengthsize == 0) { 12070720f62cSfgsch DPRINTF(("cfe memspace " 12080720f62cSfgsch "lengthsize == 0")); 12090720f62cSfgsch state->card->error++; 12100720f62cSfgsch } 12110720f62cSfgsch for (i = 0; i < cfe->num_memspace; i++) { 12120720f62cSfgsch if (lengthsize) { 12130720f62cSfgsch cfe->memspace[i].length = 12140720f62cSfgsch 256 * pcmcia_tuple_read_n(tuple, lengthsize, 12150720f62cSfgsch idx); 12160720f62cSfgsch idx += lengthsize; 12170720f62cSfgsch } else { 12180720f62cSfgsch cfe->memspace[i].length = 0; 12190720f62cSfgsch } 12200720f62cSfgsch if (cfe->memspace[i].length == 0) { 12210720f62cSfgsch DPRINTF(("cfe->memspace[%d].length == 0", 12220720f62cSfgsch i)); 12230720f62cSfgsch state->card->error++; 12240720f62cSfgsch } 12250720f62cSfgsch if (cardaddrsize) { 12260720f62cSfgsch cfe->memspace[i].cardaddr = 12270720f62cSfgsch 256 * pcmcia_tuple_read_n(tuple, cardaddrsize, 12280720f62cSfgsch idx); 12290720f62cSfgsch idx += cardaddrsize; 12300720f62cSfgsch } else { 12310720f62cSfgsch cfe->memspace[i].cardaddr = 0; 12320720f62cSfgsch } 12330720f62cSfgsch if (hostaddrsize) { 12340720f62cSfgsch cfe->memspace[i].hostaddr = 12350720f62cSfgsch 256 * pcmcia_tuple_read_n(tuple, hostaddrsize, 12360720f62cSfgsch idx); 12370720f62cSfgsch idx += hostaddrsize; 12380720f62cSfgsch } else { 12390720f62cSfgsch cfe->memspace[i].hostaddr = 0; 12400720f62cSfgsch } 12410720f62cSfgsch } 12420720f62cSfgsch } 12430720f62cSfgsch } 12440720f62cSfgsch if (misc) { 1245709e0656Sfgsch if (tuple->length <= idx) { 1246709e0656Sfgsch DPRINTF(("ran out of space before TPCE_MI\n")); 1247709e0656Sfgsch 1248709e0656Sfgsch goto abort_cfe; 1249709e0656Sfgsch } 1250709e0656Sfgsch 12510720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 12520720f62cSfgsch idx++; 12530720f62cSfgsch 1254ae2d8a60Sfgsch cfe->flags &= ~(PCMCIA_CFE_POWERDOWN 1255ae2d8a60Sfgsch | PCMCIA_CFE_READONLY 1256ae2d8a60Sfgsch | PCMCIA_CFE_AUDIO); 12570720f62cSfgsch if (reg & PCMCIA_TPCE_MI_PWRDOWN) 1258ae2d8a60Sfgsch cfe->flags |= PCMCIA_CFE_POWERDOWN; 12590720f62cSfgsch if (reg & PCMCIA_TPCE_MI_READONLY) 1260ae2d8a60Sfgsch cfe->flags |= PCMCIA_CFE_READONLY; 12610720f62cSfgsch if (reg & PCMCIA_TPCE_MI_AUDIO) 1262ae2d8a60Sfgsch cfe->flags |= PCMCIA_CFE_AUDIO; 12630720f62cSfgsch cfe->maxtwins = reg & PCMCIA_TPCE_MI_MAXTWINS; 12640720f62cSfgsch 12650720f62cSfgsch while (reg & PCMCIA_TPCE_MI_EXT) { 12660720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 12670720f62cSfgsch idx++; 12680720f62cSfgsch } 12690720f62cSfgsch } 12700720f62cSfgsch /* skip all the subtuples */ 12710720f62cSfgsch } 1272709e0656Sfgsch 1273709e0656Sfgsch abort_cfe: 12740720f62cSfgsch DPRINTF(("CISTPL_CFTABLE_ENTRY\n")); 12750720f62cSfgsch break; 1276bd4ab2b6Sniklas 12770720f62cSfgsch default: 12780720f62cSfgsch DPRINTF(("unhandled CISTPL %x\n", tuple->code)); 12790720f62cSfgsch break; 12800720f62cSfgsch } 12810720f62cSfgsch 12820720f62cSfgsch return (0); 12830720f62cSfgsch } 1284