1*109be09cSfgsch /* $OpenBSD: pcmcia_cis.c,v 1.14 2007/09/07 18:21:40 fgsch 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 6805460420Sbrad memset(&state, 0, sizeof state); 690720f62cSfgsch 700720f62cSfgsch state.card = &sc->card; 710720f62cSfgsch 720720f62cSfgsch state.card->error = 0; 730720f62cSfgsch state.card->cis1_major = -1; 740720f62cSfgsch state.card->cis1_minor = -1; 750720f62cSfgsch state.card->cis1_info[0] = NULL; 760720f62cSfgsch state.card->cis1_info[1] = NULL; 770720f62cSfgsch state.card->cis1_info[2] = NULL; 780720f62cSfgsch state.card->cis1_info[3] = NULL; 790720f62cSfgsch state.card->manufacturer = PCMCIA_VENDOR_INVALID; 800720f62cSfgsch state.card->product = PCMCIA_PRODUCT_INVALID; 810720f62cSfgsch SIMPLEQ_INIT(&state.card->pf_head); 820720f62cSfgsch 830720f62cSfgsch state.pf = NULL; 840720f62cSfgsch 850720f62cSfgsch if (pcmcia_scan_cis((struct device *)sc, pcmcia_parse_cis_tuple, 860720f62cSfgsch &state) == -1) 870720f62cSfgsch state.card->error++; 880720f62cSfgsch } 890720f62cSfgsch 900720f62cSfgsch int 910720f62cSfgsch pcmcia_scan_cis(dev, fct, arg) 920720f62cSfgsch struct device *dev; 93c4071fd1Smillert int (*fct)(struct pcmcia_tuple *, void *); 940720f62cSfgsch void *arg; 950720f62cSfgsch { 960720f62cSfgsch struct pcmcia_softc *sc = (struct pcmcia_softc *) dev; 970720f62cSfgsch pcmcia_chipset_tag_t pct; 980720f62cSfgsch pcmcia_chipset_handle_t pch; 990720f62cSfgsch int window; 1000720f62cSfgsch struct pcmcia_mem_handle pcmh; 1010720f62cSfgsch struct pcmcia_tuple tuple; 1020720f62cSfgsch int longlink_present; 1030720f62cSfgsch int longlink_common; 1040720f62cSfgsch u_long longlink_addr; 1050720f62cSfgsch int mfc_count; 1060720f62cSfgsch int mfc_index; 1070720f62cSfgsch struct { 1080720f62cSfgsch int common; 1090720f62cSfgsch u_long addr; 1100720f62cSfgsch } mfc[256 / 5]; 1110720f62cSfgsch int ret; 1120720f62cSfgsch 1130720f62cSfgsch ret = 0; 1140720f62cSfgsch 1150720f62cSfgsch pct = sc->pct; 1160720f62cSfgsch pch = sc->pch; 1170720f62cSfgsch 1180720f62cSfgsch /* allocate some memory */ 1190720f62cSfgsch 1200720f62cSfgsch if (pcmcia_chip_mem_alloc(pct, pch, PCMCIA_CIS_SIZE, &pcmh)) { 1210720f62cSfgsch #ifdef DIAGNOSTIC 1220720f62cSfgsch printf("%s: can't alloc memory to read attributes\n", 1230720f62cSfgsch sc->dev.dv_xname); 1240720f62cSfgsch #endif 1250720f62cSfgsch return -1; 1260720f62cSfgsch } 1270720f62cSfgsch 1280720f62cSfgsch /* initialize state for the primary tuple chain */ 1290720f62cSfgsch if (pcmcia_chip_mem_map(pct, pch, PCMCIA_MEM_ATTR, 0, 1300720f62cSfgsch PCMCIA_CIS_SIZE, &pcmh, &tuple.ptr, &window)) { 1310720f62cSfgsch pcmcia_chip_mem_free(pct, pch, &pcmh); 1320720f62cSfgsch #ifdef DIAGNOSTIC 1330720f62cSfgsch printf("%s: can't map memory to read attributes\n", 1340720f62cSfgsch sc->dev.dv_xname); 1350720f62cSfgsch #endif 1360720f62cSfgsch return -1; 1370720f62cSfgsch } 138c773fb73Sfgsch tuple.memt = pcmh.memt; 139c773fb73Sfgsch tuple.memh = pcmh.memh; 140c773fb73Sfgsch 1410720f62cSfgsch DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh)); 1420720f62cSfgsch 1430720f62cSfgsch tuple.mult = 2; 1440720f62cSfgsch 1450720f62cSfgsch longlink_present = 1; 1460720f62cSfgsch longlink_common = 1; 1470720f62cSfgsch longlink_addr = 0; 1480720f62cSfgsch 1490720f62cSfgsch mfc_count = 0; 1500720f62cSfgsch mfc_index = 0; 1510720f62cSfgsch 1520720f62cSfgsch DPRINTF(("%s: CIS tuple chain:\n", sc->dev.dv_xname)); 1530720f62cSfgsch 1540720f62cSfgsch while (1) { 1550720f62cSfgsch while (1) { 15605460420Sbrad /* 15705460420Sbrad * Perform boundary check for insane cards. 15805460420Sbrad * If CIS is too long, simulate CIS end. 15905460420Sbrad * (This check may not be sufficient for 16005460420Sbrad * malicious cards.) 16105460420Sbrad */ 16205460420Sbrad if (tuple.mult * tuple.ptr >= PCMCIA_CIS_SIZE - 1 16305460420Sbrad - 32 /* ad hoc value */ ) { 16405460420Sbrad DPRINTF(("CISTPL_END (too long CIS)\n")); 165e41a3487Shenning tuple.code = PCMCIA_CISTPL_END; 16605460420Sbrad goto cis_end; 16705460420Sbrad } 16805460420Sbrad 16905460420Sbrad /* get the tuple code */ 17005460420Sbrad 17105460420Sbrad tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr); 1720720f62cSfgsch 1730720f62cSfgsch /* two special-case tuples */ 1740720f62cSfgsch 1750720f62cSfgsch if (tuple.code == PCMCIA_CISTPL_NULL) { 1760720f62cSfgsch DPRINTF(("CISTPL_NONE\n 00\n")); 1770720f62cSfgsch tuple.ptr++; 1780720f62cSfgsch continue; 1790720f62cSfgsch } else if (tuple.code == PCMCIA_CISTPL_END) { 1800720f62cSfgsch DPRINTF(("CISTPL_END\n ff\n")); 18105460420Sbrad cis_end: 1820720f62cSfgsch /* Call the function for the END tuple, since 1830720f62cSfgsch the CIS semantics depend on it */ 1840720f62cSfgsch if ((*fct) (&tuple, arg)) { 1850720f62cSfgsch pcmcia_chip_mem_unmap(pct, pch, 1860720f62cSfgsch window); 1870720f62cSfgsch ret = 1; 1880720f62cSfgsch goto done; 1890720f62cSfgsch } 1900720f62cSfgsch tuple.ptr++; 1910720f62cSfgsch break; 1920720f62cSfgsch } 1930720f62cSfgsch /* now all the normal tuples */ 1940720f62cSfgsch 1950720f62cSfgsch tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1); 1960720f62cSfgsch switch (tuple.code) { 1970720f62cSfgsch case PCMCIA_CISTPL_LONGLINK_A: 1980720f62cSfgsch case PCMCIA_CISTPL_LONGLINK_C: 1990720f62cSfgsch if (tuple.length < 4) { 2000720f62cSfgsch DPRINTF(("CISTPL_LONGLINK_%s too " 2010720f62cSfgsch "short %d\n", 2020720f62cSfgsch longlink_common ? "C" : "A", 2030720f62cSfgsch tuple.length)); 2040720f62cSfgsch break; 2050720f62cSfgsch } 2060720f62cSfgsch longlink_present = 1; 2070720f62cSfgsch longlink_common = (tuple.code == 2080720f62cSfgsch PCMCIA_CISTPL_LONGLINK_C) ? 1 : 0; 2090720f62cSfgsch longlink_addr = pcmcia_tuple_read_4(&tuple, 0); 2100720f62cSfgsch DPRINTF(("CISTPL_LONGLINK_%s %lx\n", 2110720f62cSfgsch longlink_common ? "C" : "A", 2120720f62cSfgsch longlink_addr)); 2130720f62cSfgsch break; 2140720f62cSfgsch case PCMCIA_CISTPL_NO_LINK: 2150720f62cSfgsch longlink_present = 0; 2160720f62cSfgsch DPRINTF(("CISTPL_NO_LINK\n")); 2170720f62cSfgsch break; 2180720f62cSfgsch case PCMCIA_CISTPL_CHECKSUM: 2190720f62cSfgsch if (tuple.length < 5) { 2200720f62cSfgsch DPRINTF(("CISTPL_CHECKSUM too " 2210720f62cSfgsch "short %d\n", tuple.length)); 2220720f62cSfgsch break; 2230720f62cSfgsch } { 2240720f62cSfgsch int16_t offset; 2250720f62cSfgsch u_long addr, length; 2260720f62cSfgsch u_int cksum, sum; 2270720f62cSfgsch int i; 2280720f62cSfgsch 2290720f62cSfgsch *((u_int16_t *) & offset) = 2300720f62cSfgsch pcmcia_tuple_read_2(&tuple, 0); 2310720f62cSfgsch length = pcmcia_tuple_read_2(&tuple, 2); 2320720f62cSfgsch cksum = pcmcia_tuple_read_1(&tuple, 4); 2330720f62cSfgsch 2340720f62cSfgsch addr = tuple.ptr + offset; 2350720f62cSfgsch 2360720f62cSfgsch DPRINTF(("CISTPL_CHECKSUM addr=%lx " 2370720f62cSfgsch "len=%lx cksum=%x", 2380720f62cSfgsch addr, length, cksum)); 2390720f62cSfgsch 2400720f62cSfgsch /* 2410720f62cSfgsch * XXX do more work to deal with 2420720f62cSfgsch * distant regions 2430720f62cSfgsch */ 2440720f62cSfgsch if ((addr >= PCMCIA_CIS_SIZE) || 2450720f62cSfgsch ((addr + length) < 0) || 2460720f62cSfgsch ((addr + length) >= 2470720f62cSfgsch PCMCIA_CIS_SIZE)) { 2480720f62cSfgsch DPRINTF((" skipped, " 2490720f62cSfgsch "too distant\n")); 2500720f62cSfgsch break; 2510720f62cSfgsch } 2520720f62cSfgsch sum = 0; 2530720f62cSfgsch for (i = 0; i < length; i++) 2540720f62cSfgsch sum += 2550720f62cSfgsch bus_space_read_1(tuple.memt, 2560720f62cSfgsch tuple.memh, 2570720f62cSfgsch addr + tuple.mult * i); 2580720f62cSfgsch if (cksum != (sum & 0xff)) { 2590720f62cSfgsch DPRINTF((" failed sum=%x\n", 2600720f62cSfgsch sum)); 2610720f62cSfgsch printf("%s: CIS checksum " 2620720f62cSfgsch "failed\n", 2630720f62cSfgsch sc->dev.dv_xname); 2640720f62cSfgsch #if 0 2650720f62cSfgsch /* 2660720f62cSfgsch * XXX Some working cards have 2670720f62cSfgsch * XXX bad checksums!! 2680720f62cSfgsch */ 2690720f62cSfgsch ret = -1; 2700720f62cSfgsch #endif 2710720f62cSfgsch } else { 2720720f62cSfgsch DPRINTF((" ok\n")); 2730720f62cSfgsch } 2740720f62cSfgsch } 2750720f62cSfgsch break; 2760720f62cSfgsch case PCMCIA_CISTPL_LONGLINK_MFC: 2778e9dce62Sfgsch if (tuple.length < 6) { 2780720f62cSfgsch DPRINTF(("CISTPL_LONGLINK_MFC too " 2790720f62cSfgsch "short %d\n", tuple.length)); 2800720f62cSfgsch break; 2810720f62cSfgsch } 2828e9dce62Sfgsch if (((tuple.length - 1) % 5) != 0) { 2838e9dce62Sfgsch DPRINTF(("CISTPL_LONGLINK_MFC bogus " 2848e9dce62Sfgsch "length %d\n", tuple.length)); 2858e9dce62Sfgsch break; 2868e9dce62Sfgsch } 2870720f62cSfgsch { 28805460420Sbrad int i, tmp_count; 2890720f62cSfgsch 29005460420Sbrad /* 29105460420Sbrad * put count into tmp var so that 29205460420Sbrad * if we have to bail (because it's 29305460420Sbrad * a bogus count) it won't be 29405460420Sbrad * remembered for later use. 29505460420Sbrad */ 29605460420Sbrad tmp_count = 2970720f62cSfgsch pcmcia_tuple_read_1(&tuple, 0); 2980720f62cSfgsch DPRINTF(("CISTPL_LONGLINK_MFC %d", 29905460420Sbrad tmp_count)); 30005460420Sbrad 30105460420Sbrad /* 30205460420Sbrad * make _sure_ it's the right size; 30305460420Sbrad * if too short, it may be a weird 30405460420Sbrad * (unknown/undefined) format 30505460420Sbrad */ 30605460420Sbrad if (tuple.length != (tmp_count*5 + 1)) { 30705460420Sbrad DPRINTF((" bogus length %d\n", 30805460420Sbrad tuple.length)); 30905460420Sbrad break; 31005460420Sbrad } 31105460420Sbrad 31205460420Sbrad #ifdef PCMCIACISDEBUG /* maybe enable all the time? */ 31305460420Sbrad /* 31405460420Sbrad * sanity check for a programming 31505460420Sbrad * error which is difficult to find 31605460420Sbrad * when debugging. 31705460420Sbrad */ 31805460420Sbrad if (tmp_count > 31905460420Sbrad howmany(sizeof mfc, sizeof mfc[0])) 32005460420Sbrad panic("CISTPL_LONGLINK_MFC mfc " 32105460420Sbrad "count would blow stack"); 32205460420Sbrad #endif 32305460420Sbrad 32405460420Sbrad mfc_count = tmp_count; 3250720f62cSfgsch for (i = 0; i < mfc_count; i++) { 3260720f62cSfgsch mfc[i].common = 3270720f62cSfgsch (pcmcia_tuple_read_1(&tuple, 3280720f62cSfgsch 1 + 5 * i) == 3290720f62cSfgsch PCMCIA_MFC_MEM_COMMON) ? 3300720f62cSfgsch 1 : 0; 3310720f62cSfgsch mfc[i].addr = 3320720f62cSfgsch pcmcia_tuple_read_4(&tuple, 3330720f62cSfgsch 1 + 5 * i + 1); 3340720f62cSfgsch DPRINTF((" %s:%lx", 3350720f62cSfgsch mfc[i].common ? "common" : 3360720f62cSfgsch "attr", mfc[i].addr)); 3370720f62cSfgsch } 3380720f62cSfgsch DPRINTF(("\n")); 3390720f62cSfgsch } 3400720f62cSfgsch /* 3410720f62cSfgsch * for LONGLINK_MFC, fall through to the 3420720f62cSfgsch * function. This tuple has structural and 3430720f62cSfgsch * semantic content. 3440720f62cSfgsch */ 3450720f62cSfgsch default: 3460720f62cSfgsch { 3470720f62cSfgsch if ((*fct) (&tuple, arg)) { 3480720f62cSfgsch pcmcia_chip_mem_unmap(pct, 3490720f62cSfgsch pch, window); 3500720f62cSfgsch ret = 1; 3510720f62cSfgsch goto done; 3520720f62cSfgsch } 3530720f62cSfgsch } 3540720f62cSfgsch break; 3550720f62cSfgsch } /* switch */ 3560720f62cSfgsch #ifdef PCMCIACISDEBUG 3570720f62cSfgsch /* print the tuple */ 3580720f62cSfgsch { 3590720f62cSfgsch int i; 3600720f62cSfgsch 3610720f62cSfgsch DPRINTF((" %02x %02x", tuple.code, 3620720f62cSfgsch tuple.length)); 3630720f62cSfgsch 3640720f62cSfgsch for (i = 0; i < tuple.length; i++) { 3650720f62cSfgsch DPRINTF((" %02x", 3660720f62cSfgsch pcmcia_tuple_read_1(&tuple, i))); 3670720f62cSfgsch if ((i % 16) == 13) 3680720f62cSfgsch DPRINTF(("\n")); 3690720f62cSfgsch } 3700720f62cSfgsch if ((i % 16) != 14) 3710720f62cSfgsch DPRINTF(("\n")); 3720720f62cSfgsch } 3730720f62cSfgsch #endif 3740720f62cSfgsch /* skip to the next tuple */ 3750720f62cSfgsch tuple.ptr += 2 + tuple.length; 3760720f62cSfgsch } 377709e0656Sfgsch 3780720f62cSfgsch /* 3790720f62cSfgsch * the chain is done. Clean up and move onto the next one, 3800720f62cSfgsch * if any. The loop is here in the case that there is an MFC 3810720f62cSfgsch * card with no longlink (which defaults to existing, == 0). 3820720f62cSfgsch * In general, this means that if one pointer fails, it will 3830720f62cSfgsch * try the next one, instead of just bailing. 3840720f62cSfgsch */ 3850720f62cSfgsch 3860720f62cSfgsch while (1) { 3870720f62cSfgsch pcmcia_chip_mem_unmap(pct, pch, window); 3880720f62cSfgsch 3890720f62cSfgsch if (longlink_present) { 3900720f62cSfgsch /* 3910720f62cSfgsch * if the longlink is to attribute memory, 3920720f62cSfgsch * then it is unindexed. That is, if the 3930720f62cSfgsch * link value is 0x100, then the actual 3940720f62cSfgsch * memory address is 0x200. This means that 3950720f62cSfgsch * we need to multiply by 2 before calling 3960720f62cSfgsch * mem_map, and then divide the resulting ptr 3970720f62cSfgsch * by 2 after. 3980720f62cSfgsch */ 3990720f62cSfgsch 4000720f62cSfgsch if (!longlink_common) 4010720f62cSfgsch longlink_addr *= 2; 4020720f62cSfgsch 4030720f62cSfgsch pcmcia_chip_mem_map(pct, pch, longlink_common ? 4040720f62cSfgsch PCMCIA_MEM_COMMON : PCMCIA_MEM_ATTR, 4050720f62cSfgsch longlink_addr, PCMCIA_CIS_SIZE, 4060720f62cSfgsch &pcmh, &tuple.ptr, &window); 4070720f62cSfgsch 4080720f62cSfgsch if (!longlink_common) 4090720f62cSfgsch tuple.ptr /= 2; 4100720f62cSfgsch 4110720f62cSfgsch DPRINTF(("cis mem map %x\n", 4120720f62cSfgsch (unsigned int) tuple.memh)); 4130720f62cSfgsch 4140720f62cSfgsch tuple.mult = longlink_common ? 1 : 2; 4150720f62cSfgsch longlink_present = 0; 4160720f62cSfgsch longlink_common = 1; 4170720f62cSfgsch longlink_addr = 0; 4180720f62cSfgsch } else if (mfc_count && (mfc_index < mfc_count)) { 4190720f62cSfgsch if (!mfc[mfc_index].common) 4200720f62cSfgsch mfc[mfc_index].addr *= 2; 4210720f62cSfgsch 4220720f62cSfgsch pcmcia_chip_mem_map(pct, pch, 4230720f62cSfgsch mfc[mfc_index].common ? 4240720f62cSfgsch PCMCIA_MEM_COMMON : PCMCIA_MEM_ATTR, 4250720f62cSfgsch mfc[mfc_index].addr, PCMCIA_CIS_SIZE, 4260720f62cSfgsch &pcmh, &tuple.ptr, &window); 4270720f62cSfgsch 4280720f62cSfgsch if (!mfc[mfc_index].common) 4290720f62cSfgsch tuple.ptr /= 2; 4300720f62cSfgsch 4310720f62cSfgsch DPRINTF(("cis mem map %x\n", 4320720f62cSfgsch (unsigned int) tuple.memh)); 4330720f62cSfgsch 4340720f62cSfgsch /* set parse state, and point at the next one */ 4350720f62cSfgsch 4360720f62cSfgsch tuple.mult = mfc[mfc_index].common ? 1 : 2; 4370720f62cSfgsch 4380720f62cSfgsch mfc_index++; 4390720f62cSfgsch } else { 4400720f62cSfgsch goto done; 4410720f62cSfgsch } 4420720f62cSfgsch 4430720f62cSfgsch /* make sure that the link is valid */ 4440720f62cSfgsch tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr); 4450720f62cSfgsch if (tuple.code != PCMCIA_CISTPL_LINKTARGET) { 4460720f62cSfgsch DPRINTF(("CISTPL_LINKTARGET expected, " 4470720f62cSfgsch "code %02x observed\n", tuple.code)); 4480720f62cSfgsch continue; 4490720f62cSfgsch } 4500720f62cSfgsch tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1); 4510720f62cSfgsch if (tuple.length < 3) { 4520720f62cSfgsch DPRINTF(("CISTPL_LINKTARGET too short %d\n", 4530720f62cSfgsch tuple.length)); 4540720f62cSfgsch continue; 4550720f62cSfgsch } 4560720f62cSfgsch if ((pcmcia_tuple_read_1(&tuple, 0) != 'C') || 4570720f62cSfgsch (pcmcia_tuple_read_1(&tuple, 1) != 'I') || 4580720f62cSfgsch (pcmcia_tuple_read_1(&tuple, 2) != 'S')) { 4590720f62cSfgsch DPRINTF(("CISTPL_LINKTARGET magic " 4600720f62cSfgsch "%02x%02x%02x incorrect\n", 4610720f62cSfgsch pcmcia_tuple_read_1(&tuple, 0), 4620720f62cSfgsch pcmcia_tuple_read_1(&tuple, 1), 4630720f62cSfgsch pcmcia_tuple_read_1(&tuple, 2))); 4640720f62cSfgsch continue; 4650720f62cSfgsch } 4660720f62cSfgsch tuple.ptr += 2 + tuple.length; 4670720f62cSfgsch 4680720f62cSfgsch break; 4690720f62cSfgsch } 4700720f62cSfgsch } 4710720f62cSfgsch 4720720f62cSfgsch pcmcia_chip_mem_unmap(pct, pch, window); 4730720f62cSfgsch 4740720f62cSfgsch done: 4750720f62cSfgsch /* Last, free the allocated memory block */ 4760720f62cSfgsch pcmcia_chip_mem_free(pct, pch, &pcmh); 4770720f62cSfgsch 4780720f62cSfgsch return (ret); 4790720f62cSfgsch } 4800720f62cSfgsch 4810720f62cSfgsch /* XXX this is incredibly verbose. Not sure what trt is */ 4820720f62cSfgsch 4830720f62cSfgsch void 4840720f62cSfgsch pcmcia_print_cis(sc) 4850720f62cSfgsch struct pcmcia_softc *sc; 4860720f62cSfgsch { 4870720f62cSfgsch struct pcmcia_card *card = &sc->card; 4880720f62cSfgsch struct pcmcia_function *pf; 4890720f62cSfgsch struct pcmcia_config_entry *cfe; 4900720f62cSfgsch int i; 4910720f62cSfgsch 4920720f62cSfgsch printf("%s: CIS version ", sc->dev.dv_xname); 4930720f62cSfgsch if (card->cis1_major == 4) { 4940720f62cSfgsch if (card->cis1_minor == 0) 4950720f62cSfgsch printf("PCMCIA 1.0\n"); 4960720f62cSfgsch else if (card->cis1_minor == 1) 4970720f62cSfgsch printf("PCMCIA 2.0 or 2.1\n"); 4980720f62cSfgsch } else if (card->cis1_major >= 5) 4998e9dce62Sfgsch printf("PC Card Standard %d.%d\n", card->cis1_major, 5008e9dce62Sfgsch card->cis1_minor); 5010720f62cSfgsch else 5020720f62cSfgsch printf("unknown (major=%d, minor=%d)\n", 5030720f62cSfgsch card->cis1_major, card->cis1_minor); 5040720f62cSfgsch 5050720f62cSfgsch printf("%s: CIS info: ", sc->dev.dv_xname); 5060720f62cSfgsch for (i = 0; i < 4; i++) { 5070720f62cSfgsch if (card->cis1_info[i] == NULL) 5080720f62cSfgsch break; 5090720f62cSfgsch if (i) 5100720f62cSfgsch printf(", "); 5110720f62cSfgsch printf("%s", card->cis1_info[i]); 5120720f62cSfgsch } 5130720f62cSfgsch printf("\n"); 5140720f62cSfgsch 5150720f62cSfgsch printf("%s: Manufacturer code 0x%x, product 0x%x\n", 5160720f62cSfgsch sc->dev.dv_xname, card->manufacturer, card->product); 5170720f62cSfgsch 51810412f8dSjason SIMPLEQ_FOREACH(pf, &card->pf_head, pf_list) { 5190720f62cSfgsch printf("%s: function %d: ", sc->dev.dv_xname, pf->number); 5200720f62cSfgsch 5210720f62cSfgsch switch (pf->function) { 5220720f62cSfgsch case PCMCIA_FUNCTION_UNSPEC: 5230720f62cSfgsch printf("unspecified"); 5240720f62cSfgsch break; 5250720f62cSfgsch case PCMCIA_FUNCTION_MULTIFUNCTION: 5260720f62cSfgsch printf("multi-function"); 5270720f62cSfgsch break; 5280720f62cSfgsch case PCMCIA_FUNCTION_MEMORY: 5290720f62cSfgsch printf("memory"); 5300720f62cSfgsch break; 5310720f62cSfgsch case PCMCIA_FUNCTION_SERIAL: 5320720f62cSfgsch printf("serial port"); 5330720f62cSfgsch break; 5340720f62cSfgsch case PCMCIA_FUNCTION_PARALLEL: 5350720f62cSfgsch printf("parallel port"); 5360720f62cSfgsch break; 5370720f62cSfgsch case PCMCIA_FUNCTION_DISK: 5380720f62cSfgsch printf("fixed disk"); 5390720f62cSfgsch break; 5400720f62cSfgsch case PCMCIA_FUNCTION_VIDEO: 5410720f62cSfgsch printf("video adapter"); 5420720f62cSfgsch break; 5430720f62cSfgsch case PCMCIA_FUNCTION_NETWORK: 5440720f62cSfgsch printf("network adapter"); 5450720f62cSfgsch break; 5460720f62cSfgsch case PCMCIA_FUNCTION_AIMS: 5470720f62cSfgsch printf("auto incrementing mass storage"); 5480720f62cSfgsch break; 5490720f62cSfgsch case PCMCIA_FUNCTION_SCSI: 5500720f62cSfgsch printf("SCSI bridge"); 5510720f62cSfgsch break; 5520720f62cSfgsch case PCMCIA_FUNCTION_SECURITY: 5530720f62cSfgsch printf("Security services"); 5540720f62cSfgsch break; 5550720f62cSfgsch case PCMCIA_FUNCTION_INSTRUMENT: 5560720f62cSfgsch printf("Instrument"); 5570720f62cSfgsch break; 5588e9dce62Sfgsch case PCMCIA_FUNCTION_IOBUS: 5598e9dce62Sfgsch printf("Serial I/O Bus Adapter"); 5608e9dce62Sfgsch break; 5610720f62cSfgsch default: 5620720f62cSfgsch printf("unknown (%d)", pf->function); 5630720f62cSfgsch break; 5640720f62cSfgsch } 5650720f62cSfgsch 5660720f62cSfgsch printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask); 5670720f62cSfgsch 56810412f8dSjason SIMPLEQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 5690720f62cSfgsch printf("%s: function %d, config table entry %d: ", 5700720f62cSfgsch sc->dev.dv_xname, pf->number, cfe->number); 5710720f62cSfgsch 5720720f62cSfgsch switch (cfe->iftype) { 5730720f62cSfgsch case PCMCIA_IFTYPE_MEMORY: 5740720f62cSfgsch printf("memory card"); 5750720f62cSfgsch break; 5760720f62cSfgsch case PCMCIA_IFTYPE_IO: 5770720f62cSfgsch printf("I/O card"); 5780720f62cSfgsch break; 5790720f62cSfgsch default: 5800720f62cSfgsch printf("card type unknown"); 5810720f62cSfgsch break; 5820720f62cSfgsch } 5830720f62cSfgsch 5840720f62cSfgsch printf("; irq mask %x", cfe->irqmask); 5850720f62cSfgsch 5860720f62cSfgsch if (cfe->num_iospace) { 5870720f62cSfgsch printf("; iomask %lx, iospace", cfe->iomask); 5880720f62cSfgsch 5890720f62cSfgsch for (i = 0; i < cfe->num_iospace; i++) 5900720f62cSfgsch printf(" %lx%s%lx", 5910720f62cSfgsch cfe->iospace[i].start, 5920720f62cSfgsch cfe->iospace[i].length ? "-" : "", 5930720f62cSfgsch cfe->iospace[i].start + 5940720f62cSfgsch cfe->iospace[i].length - 1); 5950720f62cSfgsch } 5960720f62cSfgsch if (cfe->num_memspace) { 5970720f62cSfgsch printf("; memspace"); 5980720f62cSfgsch 5990720f62cSfgsch for (i = 0; i < cfe->num_memspace; i++) 6000720f62cSfgsch printf(" %lx%s%lx%s%lx", 6010720f62cSfgsch cfe->memspace[i].cardaddr, 6020720f62cSfgsch cfe->memspace[i].length ? "-" : "", 6030720f62cSfgsch cfe->memspace[i].cardaddr + 6040720f62cSfgsch cfe->memspace[i].length - 1, 6050720f62cSfgsch cfe->memspace[i].hostaddr ? 6060720f62cSfgsch "@" : "", 6070720f62cSfgsch cfe->memspace[i].hostaddr); 6080720f62cSfgsch } 6090720f62cSfgsch if (cfe->maxtwins) 6100720f62cSfgsch printf("; maxtwins %d", cfe->maxtwins); 6110720f62cSfgsch 6120720f62cSfgsch printf(";"); 6130720f62cSfgsch 6140720f62cSfgsch if (cfe->flags & PCMCIA_CFE_MWAIT_REQUIRED) 6150720f62cSfgsch printf(" mwait_required"); 6160720f62cSfgsch if (cfe->flags & PCMCIA_CFE_RDYBSY_ACTIVE) 6170720f62cSfgsch printf(" rdybsy_active"); 6180720f62cSfgsch if (cfe->flags & PCMCIA_CFE_WP_ACTIVE) 6190720f62cSfgsch printf(" wp_active"); 6200720f62cSfgsch if (cfe->flags & PCMCIA_CFE_BVD_ACTIVE) 6210720f62cSfgsch printf(" bvd_active"); 6220720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IO8) 6230720f62cSfgsch printf(" io8"); 6240720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IO16) 6250720f62cSfgsch printf(" io16"); 6260720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IRQSHARE) 6270720f62cSfgsch printf(" irqshare"); 6280720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IRQPULSE) 6290720f62cSfgsch printf(" irqpulse"); 6300720f62cSfgsch if (cfe->flags & PCMCIA_CFE_IRQLEVEL) 6310720f62cSfgsch printf(" irqlevel"); 6320720f62cSfgsch if (cfe->flags & PCMCIA_CFE_POWERDOWN) 6330720f62cSfgsch printf(" powerdown"); 6340720f62cSfgsch if (cfe->flags & PCMCIA_CFE_READONLY) 6350720f62cSfgsch printf(" readonly"); 6360720f62cSfgsch if (cfe->flags & PCMCIA_CFE_AUDIO) 6370720f62cSfgsch printf(" audio"); 6380720f62cSfgsch 6390720f62cSfgsch printf("\n"); 6400720f62cSfgsch } 6410720f62cSfgsch } 6420720f62cSfgsch 6430720f62cSfgsch if (card->error) 6440720f62cSfgsch printf("%s: %d errors found while parsing CIS\n", 6450720f62cSfgsch sc->dev.dv_xname, card->error); 6460720f62cSfgsch } 6470720f62cSfgsch 6480720f62cSfgsch int 6490720f62cSfgsch pcmcia_parse_cis_tuple(tuple, arg) 6500720f62cSfgsch struct pcmcia_tuple *tuple; 6510720f62cSfgsch void *arg; 6520720f62cSfgsch { 6530720f62cSfgsch /* most of these are educated guesses */ 6540720f62cSfgsch static struct pcmcia_config_entry init_cfe = { 6550720f62cSfgsch -1, PCMCIA_CFE_RDYBSY_ACTIVE | PCMCIA_CFE_WP_ACTIVE | 6560720f62cSfgsch PCMCIA_CFE_BVD_ACTIVE, PCMCIA_IFTYPE_MEMORY, 6570720f62cSfgsch }; 6580720f62cSfgsch 6590720f62cSfgsch struct cis_state *state = arg; 6600720f62cSfgsch 6610720f62cSfgsch switch (tuple->code) { 6620720f62cSfgsch case PCMCIA_CISTPL_END: 663bd4ab2b6Sniklas /* 664bd4ab2b6Sniklas * If we've seen a LONGLINK_MFC, and this is the first 6650720f62cSfgsch * END after it, reset the function list. 6660720f62cSfgsch * 6670720f62cSfgsch * XXX This might also be the right place to start a 6680720f62cSfgsch * new function, but that assumes that a function 6690720f62cSfgsch * definition never crosses any longlink, and I'm not 6700720f62cSfgsch * sure about that. This is probably safe for MFC 6710720f62cSfgsch * cards, but what we have now isn't broken, so I'd 6720720f62cSfgsch * rather not change it. 6730720f62cSfgsch */ 6740720f62cSfgsch if (state->gotmfc == 1) { 6750720f62cSfgsch struct pcmcia_function *pf, *pfnext; 6760720f62cSfgsch 67710412f8dSjason for (pf = SIMPLEQ_FIRST(&state->card->pf_head); 67810412f8dSjason pf != NULL; pf = pfnext) { 67910412f8dSjason pfnext = SIMPLEQ_NEXT(pf, pf_list); 6800720f62cSfgsch free(pf, M_DEVBUF); 6810720f62cSfgsch } 6820720f62cSfgsch 6830720f62cSfgsch SIMPLEQ_INIT(&state->card->pf_head); 6840720f62cSfgsch 6850720f62cSfgsch state->count = 0; 6860720f62cSfgsch state->gotmfc = 2; 6870720f62cSfgsch state->pf = NULL; 6880720f62cSfgsch } 6890720f62cSfgsch break; 690bd4ab2b6Sniklas 6910720f62cSfgsch case PCMCIA_CISTPL_LONGLINK_MFC: 6920720f62cSfgsch /* 693bd4ab2b6Sniklas * This tuple's structure was dealt with in scan_cis. here, 6940720f62cSfgsch * record the fact that the MFC tuple was seen, so that 6950720f62cSfgsch * functions declared before the MFC link can be cleaned 6960720f62cSfgsch * up. 6970720f62cSfgsch */ 6980720f62cSfgsch state->gotmfc = 1; 6990720f62cSfgsch break; 700bd4ab2b6Sniklas 7010720f62cSfgsch #ifdef PCMCIACISDEBUG 7020720f62cSfgsch case PCMCIA_CISTPL_DEVICE: 7030720f62cSfgsch case PCMCIA_CISTPL_DEVICE_A: 7040720f62cSfgsch { 7050720f62cSfgsch u_int reg, dtype, dspeed; 7060720f62cSfgsch 7070720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, 0); 7080720f62cSfgsch dtype = reg & PCMCIA_DTYPE_MASK; 7090720f62cSfgsch dspeed = reg & PCMCIA_DSPEED_MASK; 7100720f62cSfgsch 7110720f62cSfgsch DPRINTF(("CISTPL_DEVICE%s type=", 7120720f62cSfgsch (tuple->code == PCMCIA_CISTPL_DEVICE) ? "" : "_A")); 7130720f62cSfgsch switch (dtype) { 7140720f62cSfgsch case PCMCIA_DTYPE_NULL: 7150720f62cSfgsch DPRINTF(("null")); 7160720f62cSfgsch break; 7170720f62cSfgsch case PCMCIA_DTYPE_ROM: 7180720f62cSfgsch DPRINTF(("rom")); 7190720f62cSfgsch break; 7200720f62cSfgsch case PCMCIA_DTYPE_OTPROM: 7210720f62cSfgsch DPRINTF(("otprom")); 7220720f62cSfgsch break; 7230720f62cSfgsch case PCMCIA_DTYPE_EPROM: 7240720f62cSfgsch DPRINTF(("eprom")); 7250720f62cSfgsch break; 7260720f62cSfgsch case PCMCIA_DTYPE_EEPROM: 7270720f62cSfgsch DPRINTF(("eeprom")); 7280720f62cSfgsch break; 7290720f62cSfgsch case PCMCIA_DTYPE_FLASH: 7300720f62cSfgsch DPRINTF(("flash")); 7310720f62cSfgsch break; 7320720f62cSfgsch case PCMCIA_DTYPE_SRAM: 7330720f62cSfgsch DPRINTF(("sram")); 7340720f62cSfgsch break; 7350720f62cSfgsch case PCMCIA_DTYPE_DRAM: 7360720f62cSfgsch DPRINTF(("dram")); 7370720f62cSfgsch break; 7380720f62cSfgsch case PCMCIA_DTYPE_FUNCSPEC: 7390720f62cSfgsch DPRINTF(("funcspec")); 7400720f62cSfgsch break; 7410720f62cSfgsch case PCMCIA_DTYPE_EXTEND: 7420720f62cSfgsch DPRINTF(("extend")); 7430720f62cSfgsch break; 7440720f62cSfgsch default: 7450720f62cSfgsch DPRINTF(("reserved")); 7460720f62cSfgsch break; 7470720f62cSfgsch } 7480720f62cSfgsch DPRINTF((" speed=")); 7490720f62cSfgsch switch (dspeed) { 7500720f62cSfgsch case PCMCIA_DSPEED_NULL: 7510720f62cSfgsch DPRINTF(("null")); 7520720f62cSfgsch break; 7530720f62cSfgsch case PCMCIA_DSPEED_250NS: 7540720f62cSfgsch DPRINTF(("250ns")); 7550720f62cSfgsch break; 7560720f62cSfgsch case PCMCIA_DSPEED_200NS: 7570720f62cSfgsch DPRINTF(("200ns")); 7580720f62cSfgsch break; 7590720f62cSfgsch case PCMCIA_DSPEED_150NS: 7600720f62cSfgsch DPRINTF(("150ns")); 7610720f62cSfgsch break; 7620720f62cSfgsch case PCMCIA_DSPEED_100NS: 7630720f62cSfgsch DPRINTF(("100ns")); 7640720f62cSfgsch break; 7650720f62cSfgsch case PCMCIA_DSPEED_EXT: 7660720f62cSfgsch DPRINTF(("ext")); 7670720f62cSfgsch break; 7680720f62cSfgsch default: 7690720f62cSfgsch DPRINTF(("reserved")); 7700720f62cSfgsch break; 7710720f62cSfgsch } 7720720f62cSfgsch } 7730720f62cSfgsch DPRINTF(("\n")); 7740720f62cSfgsch break; 7750720f62cSfgsch #endif 776bd4ab2b6Sniklas 7770720f62cSfgsch case PCMCIA_CISTPL_VERS_1: 7780720f62cSfgsch if (tuple->length < 6) { 7790720f62cSfgsch DPRINTF(("CISTPL_VERS_1 too short %d\n", 7800720f62cSfgsch tuple->length)); 7810720f62cSfgsch break; 7820720f62cSfgsch } { 7830720f62cSfgsch int start, i, ch, count; 7840720f62cSfgsch 7850720f62cSfgsch state->card->cis1_major = pcmcia_tuple_read_1(tuple, 0); 7860720f62cSfgsch state->card->cis1_minor = pcmcia_tuple_read_1(tuple, 1); 7870720f62cSfgsch 7880720f62cSfgsch for (count = 0, start = 0, i = 0; 7890720f62cSfgsch (count < 4) && ((i + 4) < 256); i++) { 7900720f62cSfgsch ch = pcmcia_tuple_read_1(tuple, 2 + i); 7910720f62cSfgsch if (ch == 0xff) 7920720f62cSfgsch break; 7930720f62cSfgsch state->card->cis1_info_buf[i] = ch; 7940720f62cSfgsch if (ch == 0) { 7950720f62cSfgsch state->card->cis1_info[count] = 7960720f62cSfgsch state->card->cis1_info_buf + start; 7970720f62cSfgsch start = i + 1; 7980720f62cSfgsch count++; 7990720f62cSfgsch } 8000720f62cSfgsch } 8010720f62cSfgsch DPRINTF(("CISTPL_VERS_1\n")); 8020720f62cSfgsch } 8030720f62cSfgsch break; 804bd4ab2b6Sniklas 8050720f62cSfgsch case PCMCIA_CISTPL_MANFID: 8060720f62cSfgsch if (tuple->length < 4) { 8070720f62cSfgsch DPRINTF(("CISTPL_MANFID too short %d\n", 8080720f62cSfgsch tuple->length)); 8090720f62cSfgsch break; 8100720f62cSfgsch } 8110720f62cSfgsch state->card->manufacturer = pcmcia_tuple_read_2(tuple, 0); 8120720f62cSfgsch state->card->product = pcmcia_tuple_read_2(tuple, 2); 8130720f62cSfgsch DPRINTF(("CISTPL_MANFID\n")); 8140720f62cSfgsch break; 815bd4ab2b6Sniklas 8160720f62cSfgsch case PCMCIA_CISTPL_FUNCID: 8178e9dce62Sfgsch if (tuple->length < 2) { 8180720f62cSfgsch DPRINTF(("CISTPL_FUNCID too short %d\n", 8190720f62cSfgsch tuple->length)); 8200720f62cSfgsch break; 8210720f62cSfgsch } 822bd4ab2b6Sniklas 823bd4ab2b6Sniklas /* 824bd4ab2b6Sniklas * As far as I understand this, manufacturers do multifunction 825bd4ab2b6Sniklas * cards in various ways. Sadly enough I do not have the 826bd4ab2b6Sniklas * PC-Card standard (donate!) so I can only guess what can 827bd4ab2b6Sniklas * be done. 828bd4ab2b6Sniklas * The original code implies FUNCID nodes are above CONFIG 829bd4ab2b6Sniklas * nodes in the CIS tree, however Xircom does it the other 830bd4ab2b6Sniklas * way round, which of course makes things a bit hard. 831bd4ab2b6Sniklas * --niklas@openbsd.org 832bd4ab2b6Sniklas */ 833bd4ab2b6Sniklas if (state->pf) { 834bd4ab2b6Sniklas if (state->pf->function == PCMCIA_FUNCTION_UNSPEC) { 835bd4ab2b6Sniklas /* 836bd4ab2b6Sniklas * This looks like a opportunistic function 837bd4ab2b6Sniklas * created by a CONFIG tuple. Just keep it. 838bd4ab2b6Sniklas */ 839bd4ab2b6Sniklas } else { 840bd4ab2b6Sniklas /* 841bd4ab2b6Sniklas * A function is being defined, end it. 842bd4ab2b6Sniklas */ 843bd4ab2b6Sniklas state->pf = NULL; 844bd4ab2b6Sniklas } 845bd4ab2b6Sniklas } 846bd4ab2b6Sniklas if (state->pf == NULL) { 8470720f62cSfgsch state->pf = malloc(sizeof(*state->pf), M_DEVBUF, 848*109be09cSfgsch M_NOWAIT|M_ZERO); 8498584d5e3Snordin if (state->pf == NULL) 8508584d5e3Snordin panic("pcmcia_parse_cis_tuple"); 8510720f62cSfgsch state->pf->number = state->count++; 8520720f62cSfgsch state->pf->last_config_index = -1; 8530720f62cSfgsch SIMPLEQ_INIT(&state->pf->cfe_head); 8540720f62cSfgsch 8550720f62cSfgsch SIMPLEQ_INSERT_TAIL(&state->card->pf_head, state->pf, 8560720f62cSfgsch pf_list); 8570720f62cSfgsch } 8580720f62cSfgsch state->pf->function = pcmcia_tuple_read_1(tuple, 0); 8590720f62cSfgsch 8600720f62cSfgsch DPRINTF(("CISTPL_FUNCID\n")); 8610720f62cSfgsch break; 862bd4ab2b6Sniklas 8630720f62cSfgsch case PCMCIA_CISTPL_CONFIG: 8647bbf5fc9Sfgsch if (tuple->length < 3) { 8650720f62cSfgsch DPRINTF(("CISTPL_CONFIG too short %d\n", 8660720f62cSfgsch tuple->length)); 8670720f62cSfgsch break; 8680720f62cSfgsch } { 8690720f62cSfgsch u_int reg, rasz, rmsz, rfsz; 8700720f62cSfgsch int i; 8710720f62cSfgsch 8720720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, 0); 8730720f62cSfgsch rasz = 1 + ((reg & PCMCIA_TPCC_RASZ_MASK) >> 8740720f62cSfgsch PCMCIA_TPCC_RASZ_SHIFT); 8750720f62cSfgsch rmsz = 1 + ((reg & PCMCIA_TPCC_RMSZ_MASK) >> 8760720f62cSfgsch PCMCIA_TPCC_RMSZ_SHIFT); 8770720f62cSfgsch rfsz = ((reg & PCMCIA_TPCC_RFSZ_MASK) >> 8780720f62cSfgsch PCMCIA_TPCC_RFSZ_SHIFT); 8790720f62cSfgsch 8800720f62cSfgsch if (tuple->length < (rasz + rmsz + rfsz)) { 8810720f62cSfgsch DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too " 8820720f62cSfgsch "short %d\n", rasz, rmsz, rfsz, 8830720f62cSfgsch tuple->length)); 8840720f62cSfgsch break; 8850720f62cSfgsch } 8860720f62cSfgsch if (state->pf == NULL) { 8870720f62cSfgsch state->pf = malloc(sizeof(*state->pf), 888*109be09cSfgsch M_DEVBUF, M_NOWAIT|M_ZERO); 8898584d5e3Snordin if (state->pf == NULL) 8908584d5e3Snordin panic("pcmcia_parse_cis_tuple"); 8910720f62cSfgsch state->pf->number = state->count++; 8920720f62cSfgsch state->pf->last_config_index = -1; 8930720f62cSfgsch SIMPLEQ_INIT(&state->pf->cfe_head); 8940720f62cSfgsch 8950720f62cSfgsch SIMPLEQ_INSERT_TAIL(&state->card->pf_head, 8960720f62cSfgsch state->pf, pf_list); 8970720f62cSfgsch 8980720f62cSfgsch state->pf->function = PCMCIA_FUNCTION_UNSPEC; 8990720f62cSfgsch } 9000720f62cSfgsch state->pf->last_config_index = 9010720f62cSfgsch pcmcia_tuple_read_1(tuple, 1); 9020720f62cSfgsch 9030720f62cSfgsch state->pf->ccr_base = 0; 9040720f62cSfgsch for (i = 0; i < rasz; i++) 9050720f62cSfgsch state->pf->ccr_base |= 9060720f62cSfgsch ((pcmcia_tuple_read_1(tuple, 2 + i)) << 9070720f62cSfgsch (i * 8)); 9080720f62cSfgsch 9090720f62cSfgsch state->pf->ccr_mask = 0; 9100720f62cSfgsch for (i = 0; i < rmsz; i++) 9110720f62cSfgsch state->pf->ccr_mask |= 9120720f62cSfgsch ((pcmcia_tuple_read_1(tuple, 9130720f62cSfgsch 2 + rasz + i)) << (i * 8)); 9140720f62cSfgsch 9150720f62cSfgsch /* skip the reserved area and subtuples */ 9160720f62cSfgsch 9170720f62cSfgsch /* reset the default cfe for each cfe list */ 9180720f62cSfgsch state->temp_cfe = init_cfe; 9190720f62cSfgsch state->default_cfe = &state->temp_cfe; 9200720f62cSfgsch } 9210720f62cSfgsch DPRINTF(("CISTPL_CONFIG\n")); 9220720f62cSfgsch break; 923bd4ab2b6Sniklas 9240720f62cSfgsch case PCMCIA_CISTPL_CFTABLE_ENTRY: 9258e9dce62Sfgsch if (tuple->length < 2) { 9268e9dce62Sfgsch DPRINTF(("CISTPL_CFTABLE_ENTRY too short %d\n", 9278e9dce62Sfgsch tuple->length)); 9288e9dce62Sfgsch break; 9298e9dce62Sfgsch } { 9300720f62cSfgsch int idx, i, j; 9310720f62cSfgsch u_int reg, reg2; 9320720f62cSfgsch u_int intface, def, num; 9330720f62cSfgsch u_int power, timing, iospace, irq, memspace, misc; 9340720f62cSfgsch struct pcmcia_config_entry *cfe; 9350720f62cSfgsch 9360720f62cSfgsch idx = 0; 9370720f62cSfgsch 9380720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 9390720f62cSfgsch idx++; 9400720f62cSfgsch intface = reg & PCMCIA_TPCE_INDX_INTFACE; 9410720f62cSfgsch def = reg & PCMCIA_TPCE_INDX_DEFAULT; 9420720f62cSfgsch num = reg & PCMCIA_TPCE_INDX_NUM_MASK; 9430720f62cSfgsch 9440720f62cSfgsch /* 9450720f62cSfgsch * this is a little messy. Some cards have only a 9460720f62cSfgsch * cfentry with the default bit set. So, as we go 9470720f62cSfgsch * through the list, we add new indexes to the queue, 9480720f62cSfgsch * and keep a pointer to the last one with the 9490720f62cSfgsch * default bit set. if we see a record with the same 9500720f62cSfgsch * index, as the default, we stash the default and 9510720f62cSfgsch * replace the queue entry. otherwise, we just add 9520720f62cSfgsch * new entries to the queue, pointing the default ptr 9530720f62cSfgsch * at them if the default bit is set. if we get to 9540720f62cSfgsch * the end with the default pointer pointing at a 9550720f62cSfgsch * record which hasn't had a matching index, that's 9560720f62cSfgsch * ok; it just becomes a cfentry like any other. 9570720f62cSfgsch */ 9580720f62cSfgsch 9590720f62cSfgsch /* 9600720f62cSfgsch * if the index in the cis differs from the default 9610720f62cSfgsch * cis, create new entry in the queue and start it 9620720f62cSfgsch * with the current default 9630720f62cSfgsch */ 96405460420Sbrad if (state->default_cfe == NULL) { 96505460420Sbrad DPRINTF(("CISTPL_CFTABLE_ENTRY with no " 96605460420Sbrad "default\n")); 96705460420Sbrad break; 96805460420Sbrad } 9690720f62cSfgsch if (num != state->default_cfe->number) { 9700720f62cSfgsch cfe = (struct pcmcia_config_entry *) 9710720f62cSfgsch malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 9728584d5e3Snordin if (cfe == NULL) 9738584d5e3Snordin panic("pcmcia_parse_cis_tuple"); 9740720f62cSfgsch 9750720f62cSfgsch *cfe = *state->default_cfe; 9760720f62cSfgsch 9770720f62cSfgsch SIMPLEQ_INSERT_TAIL(&state->pf->cfe_head, 9780720f62cSfgsch cfe, cfe_list); 9790720f62cSfgsch 9800720f62cSfgsch cfe->number = num; 9810720f62cSfgsch 9820720f62cSfgsch /* 9830720f62cSfgsch * if the default bit is set in the cis, then 9840720f62cSfgsch * point the new default at whatever is being 9850720f62cSfgsch * filled in 9860720f62cSfgsch */ 9870720f62cSfgsch if (def) 9880720f62cSfgsch state->default_cfe = cfe; 9890720f62cSfgsch } else { 9900720f62cSfgsch /* 9910720f62cSfgsch * the cis index matches the default index, 9920720f62cSfgsch * fill in the default cfentry. It is 9930720f62cSfgsch * assumed that the cfdefault index is in the 9940720f62cSfgsch * queue. For it to be otherwise, the cis 9950720f62cSfgsch * index would have to be -1 (initial 9960720f62cSfgsch * condition) which is not possible, or there 9970720f62cSfgsch * would have to be a preceding cis entry 9980720f62cSfgsch * which had the same cis index and had the 9990720f62cSfgsch * default bit unset. Neither condition 10000720f62cSfgsch * should happen. If it does, this cfentry 10010720f62cSfgsch * is lost (written into temp space), which 10020720f62cSfgsch * is an acceptable failure mode. 10030720f62cSfgsch */ 10040720f62cSfgsch 10050720f62cSfgsch cfe = state->default_cfe; 10060720f62cSfgsch 10070720f62cSfgsch /* 10080720f62cSfgsch * if the cis entry does not have the default 10090720f62cSfgsch * bit set, copy the default out of the way 10100720f62cSfgsch * first. 10110720f62cSfgsch */ 10120720f62cSfgsch if (!def) { 10130720f62cSfgsch state->temp_cfe = *state->default_cfe; 10140720f62cSfgsch state->default_cfe = &state->temp_cfe; 10150720f62cSfgsch } 10160720f62cSfgsch } 10170720f62cSfgsch 10180720f62cSfgsch if (intface) { 10190720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10200720f62cSfgsch idx++; 10218e9dce62Sfgsch cfe->flags &= ~(PCMCIA_CFE_MWAIT_REQUIRED 10228e9dce62Sfgsch | PCMCIA_CFE_RDYBSY_ACTIVE 10238e9dce62Sfgsch | PCMCIA_CFE_WP_ACTIVE 10248e9dce62Sfgsch | PCMCIA_CFE_BVD_ACTIVE); 10250720f62cSfgsch if (reg & PCMCIA_TPCE_IF_MWAIT) 10260720f62cSfgsch cfe->flags |= PCMCIA_CFE_MWAIT_REQUIRED; 10270720f62cSfgsch if (reg & PCMCIA_TPCE_IF_RDYBSY) 10280720f62cSfgsch cfe->flags |= PCMCIA_CFE_RDYBSY_ACTIVE; 10290720f62cSfgsch if (reg & PCMCIA_TPCE_IF_WP) 10300720f62cSfgsch cfe->flags |= PCMCIA_CFE_WP_ACTIVE; 10310720f62cSfgsch if (reg & PCMCIA_TPCE_IF_BVD) 10320720f62cSfgsch cfe->flags |= PCMCIA_CFE_BVD_ACTIVE; 10330720f62cSfgsch cfe->iftype = reg & PCMCIA_TPCE_IF_IFTYPE; 10340720f62cSfgsch } 10350720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10360720f62cSfgsch idx++; 10370720f62cSfgsch 10380720f62cSfgsch power = reg & PCMCIA_TPCE_FS_POWER_MASK; 10390720f62cSfgsch timing = reg & PCMCIA_TPCE_FS_TIMING; 10400720f62cSfgsch iospace = reg & PCMCIA_TPCE_FS_IOSPACE; 10410720f62cSfgsch irq = reg & PCMCIA_TPCE_FS_IRQ; 10420720f62cSfgsch memspace = reg & PCMCIA_TPCE_FS_MEMSPACE_MASK; 10430720f62cSfgsch misc = reg & PCMCIA_TPCE_FS_MISC; 10440720f62cSfgsch 10450720f62cSfgsch if (power) { 10460720f62cSfgsch /* skip over power, don't save */ 10470720f62cSfgsch /* for each parameter selection byte */ 10480720f62cSfgsch for (i = 0; i < power; i++) { 10490720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10500720f62cSfgsch idx++; 10510720f62cSfgsch /* for each bit */ 10520720f62cSfgsch for (j = 0; j < 7; j++) { 10530720f62cSfgsch /* if the bit is set */ 10540720f62cSfgsch if ((reg >> j) & 0x01) { 10550720f62cSfgsch /* skip over bytes */ 10560720f62cSfgsch do { 10570720f62cSfgsch reg2 = pcmcia_tuple_read_1(tuple, idx); 10580720f62cSfgsch idx++; 10590720f62cSfgsch /* 10600720f62cSfgsch * until 10612ba33ebbSjmc * non- 10622ba33ebbSjmc * extension 10632ba33ebbSjmc * byte 10640720f62cSfgsch */ 10650720f62cSfgsch } while (reg2 & 0x80); 10660720f62cSfgsch } 10670720f62cSfgsch } 10680720f62cSfgsch } 10690720f62cSfgsch } 10700720f62cSfgsch if (timing) { 10710720f62cSfgsch /* skip over timing, don't save */ 10720720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10730720f62cSfgsch idx++; 10740720f62cSfgsch 10750720f62cSfgsch if ((reg & PCMCIA_TPCE_TD_RESERVED_MASK) != 10760720f62cSfgsch PCMCIA_TPCE_TD_RESERVED_MASK) 10770720f62cSfgsch idx++; 10780720f62cSfgsch if ((reg & PCMCIA_TPCE_TD_RDYBSY_MASK) != 10790720f62cSfgsch PCMCIA_TPCE_TD_RDYBSY_MASK) 10800720f62cSfgsch idx++; 10810720f62cSfgsch if ((reg & PCMCIA_TPCE_TD_WAIT_MASK) != 10820720f62cSfgsch PCMCIA_TPCE_TD_WAIT_MASK) 10830720f62cSfgsch idx++; 10840720f62cSfgsch } 10850720f62cSfgsch if (iospace) { 1086709e0656Sfgsch if (tuple->length <= idx) { 1087709e0656Sfgsch DPRINTF(("ran out of space before TPCE_IO\n")); 1088709e0656Sfgsch 1089709e0656Sfgsch goto abort_cfe; 1090709e0656Sfgsch } 1091709e0656Sfgsch 10920720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 10930720f62cSfgsch idx++; 10940720f62cSfgsch 1095ae2d8a60Sfgsch cfe->flags &= 1096ae2d8a60Sfgsch ~(PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16); 10970720f62cSfgsch if (reg & PCMCIA_TPCE_IO_BUSWIDTH_8BIT) 10980720f62cSfgsch cfe->flags |= PCMCIA_CFE_IO8; 10990720f62cSfgsch if (reg & PCMCIA_TPCE_IO_BUSWIDTH_16BIT) 11000720f62cSfgsch cfe->flags |= PCMCIA_CFE_IO16; 11010720f62cSfgsch cfe->iomask = 11020720f62cSfgsch reg & PCMCIA_TPCE_IO_IOADDRLINES_MASK; 11030720f62cSfgsch 11040720f62cSfgsch if (reg & PCMCIA_TPCE_IO_HASRANGE) { 11050720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 11060720f62cSfgsch idx++; 11070720f62cSfgsch 11080720f62cSfgsch cfe->num_iospace = 1 + (reg & 11090720f62cSfgsch PCMCIA_TPCE_IO_RANGE_COUNT); 11100720f62cSfgsch 11110720f62cSfgsch if (cfe->num_iospace > 11120720f62cSfgsch (sizeof(cfe->iospace) / 11130720f62cSfgsch sizeof(cfe->iospace[0]))) { 11140720f62cSfgsch DPRINTF(("too many io " 11150720f62cSfgsch "spaces %d", 11160720f62cSfgsch cfe->num_iospace)); 11170720f62cSfgsch state->card->error++; 11180720f62cSfgsch break; 11190720f62cSfgsch } 11200720f62cSfgsch for (i = 0; i < cfe->num_iospace; i++) { 11210720f62cSfgsch switch (reg & PCMCIA_TPCE_IO_RANGE_ADDRSIZE_MASK) { 11220720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_ONE: 11230720f62cSfgsch cfe->iospace[i].start = 11240720f62cSfgsch pcmcia_tuple_read_1(tuple, idx); 11250720f62cSfgsch idx++; 11260720f62cSfgsch break; 11270720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_TWO: 11280720f62cSfgsch cfe->iospace[i].start = 11290720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 11300720f62cSfgsch idx += 2; 11310720f62cSfgsch break; 11320720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_FOUR: 11330720f62cSfgsch cfe->iospace[i].start = 11340720f62cSfgsch pcmcia_tuple_read_4(tuple, idx); 11350720f62cSfgsch idx += 4; 11360720f62cSfgsch break; 11370720f62cSfgsch } 11380720f62cSfgsch switch (reg & 11390720f62cSfgsch PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_MASK) { 11400720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_ONE: 11410720f62cSfgsch cfe->iospace[i].length = 11420720f62cSfgsch pcmcia_tuple_read_1(tuple, idx); 11430720f62cSfgsch idx++; 11440720f62cSfgsch break; 11450720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_TWO: 11460720f62cSfgsch cfe->iospace[i].length = 11470720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 11480720f62cSfgsch idx += 2; 11490720f62cSfgsch break; 11500720f62cSfgsch case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_FOUR: 11510720f62cSfgsch cfe->iospace[i].length = 11520720f62cSfgsch pcmcia_tuple_read_4(tuple, idx); 11530720f62cSfgsch idx += 4; 11540720f62cSfgsch break; 11550720f62cSfgsch } 11560720f62cSfgsch cfe->iospace[i].length++; 11570720f62cSfgsch } 11580720f62cSfgsch } else { 11590720f62cSfgsch cfe->num_iospace = 1; 11600720f62cSfgsch cfe->iospace[0].start = 0; 11610720f62cSfgsch cfe->iospace[0].length = 11620720f62cSfgsch (1 << cfe->iomask); 11630720f62cSfgsch } 11640720f62cSfgsch } 1165bd4ab2b6Sniklas 11660720f62cSfgsch if (irq) { 1167709e0656Sfgsch if (tuple->length <= idx) { 1168709e0656Sfgsch DPRINTF(("ran out of space before TPCE_IR\n")); 1169709e0656Sfgsch 1170709e0656Sfgsch goto abort_cfe; 1171709e0656Sfgsch } 1172709e0656Sfgsch 11730720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 11740720f62cSfgsch idx++; 11750720f62cSfgsch 1176ae2d8a60Sfgsch cfe->flags &= ~(PCMCIA_CFE_IRQSHARE 1177ae2d8a60Sfgsch | PCMCIA_CFE_IRQPULSE 1178ae2d8a60Sfgsch | PCMCIA_CFE_IRQLEVEL); 11790720f62cSfgsch if (reg & PCMCIA_TPCE_IR_SHARE) 11800720f62cSfgsch cfe->flags |= PCMCIA_CFE_IRQSHARE; 11810720f62cSfgsch if (reg & PCMCIA_TPCE_IR_PULSE) 11820720f62cSfgsch cfe->flags |= PCMCIA_CFE_IRQPULSE; 11830720f62cSfgsch if (reg & PCMCIA_TPCE_IR_LEVEL) 11840720f62cSfgsch cfe->flags |= PCMCIA_CFE_IRQLEVEL; 11850720f62cSfgsch 11860720f62cSfgsch if (reg & PCMCIA_TPCE_IR_HASMASK) { 11870720f62cSfgsch /* 11880720f62cSfgsch * it's legal to ignore the 11890720f62cSfgsch * special-interrupt bits, so I will 11900720f62cSfgsch */ 11910720f62cSfgsch 11920720f62cSfgsch cfe->irqmask = 11930720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 11940720f62cSfgsch idx += 2; 11950720f62cSfgsch } else { 11960720f62cSfgsch cfe->irqmask = 11970720f62cSfgsch (1 << (reg & PCMCIA_TPCE_IR_IRQ)); 11980720f62cSfgsch } 11990720f62cSfgsch } 12000720f62cSfgsch if (memspace) { 1201709e0656Sfgsch if (tuple->length <= idx) { 1202709e0656Sfgsch DPRINTF(("ran out of space before TPCE_MS\n")); 1203709e0656Sfgsch goto abort_cfe; 1204709e0656Sfgsch } 1205709e0656Sfgsch 1206709e0656Sfgsch if (memspace == PCMCIA_TPCE_FS_MEMSPACE_NONE) { 1207709e0656Sfgsch cfe->num_memspace = 0; 1208709e0656Sfgsch } else if (memspace == PCMCIA_TPCE_FS_MEMSPACE_LENGTH) { 12090720f62cSfgsch cfe->num_memspace = 1; 12100720f62cSfgsch cfe->memspace[0].length = 256 * 12110720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 12120720f62cSfgsch idx += 2; 12130720f62cSfgsch cfe->memspace[0].cardaddr = 0; 12140720f62cSfgsch cfe->memspace[0].hostaddr = 0; 12150720f62cSfgsch } else if (memspace == 12160720f62cSfgsch PCMCIA_TPCE_FS_MEMSPACE_LENGTHADDR) { 12170720f62cSfgsch cfe->num_memspace = 1; 12180720f62cSfgsch cfe->memspace[0].length = 256 * 12190720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 12200720f62cSfgsch idx += 2; 12210720f62cSfgsch cfe->memspace[0].cardaddr = 256 * 12220720f62cSfgsch pcmcia_tuple_read_2(tuple, idx); 12230720f62cSfgsch idx += 2; 1224709e0656Sfgsch cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr; 12250720f62cSfgsch } else { 12260720f62cSfgsch int lengthsize; 12270720f62cSfgsch int cardaddrsize; 12280720f62cSfgsch int hostaddrsize; 12290720f62cSfgsch 12300720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 12310720f62cSfgsch idx++; 12320720f62cSfgsch 12338e9dce62Sfgsch cfe->num_memspace = (reg & 12348e9dce62Sfgsch PCMCIA_TPCE_MS_COUNT) + 1; 12350720f62cSfgsch 12360720f62cSfgsch if (cfe->num_memspace > 12370720f62cSfgsch (sizeof(cfe->memspace) / 12380720f62cSfgsch sizeof(cfe->memspace[0]))) { 12390720f62cSfgsch DPRINTF(("too many mem " 12400720f62cSfgsch "spaces %d", 12410720f62cSfgsch cfe->num_memspace)); 12420720f62cSfgsch state->card->error++; 12430720f62cSfgsch break; 12440720f62cSfgsch } 12450720f62cSfgsch lengthsize = 12460720f62cSfgsch ((reg & PCMCIA_TPCE_MS_LENGTH_SIZE_MASK) >> 12470720f62cSfgsch PCMCIA_TPCE_MS_LENGTH_SIZE_SHIFT); 12480720f62cSfgsch cardaddrsize = 12490720f62cSfgsch ((reg & PCMCIA_TPCE_MS_CARDADDR_SIZE_MASK) >> 12500720f62cSfgsch PCMCIA_TPCE_MS_CARDADDR_SIZE_SHIFT); 12510720f62cSfgsch hostaddrsize = 12520720f62cSfgsch (reg & PCMCIA_TPCE_MS_HOSTADDR) ? cardaddrsize : 0; 12530720f62cSfgsch 12540720f62cSfgsch if (lengthsize == 0) { 12550720f62cSfgsch DPRINTF(("cfe memspace " 12560720f62cSfgsch "lengthsize == 0")); 12570720f62cSfgsch state->card->error++; 12580720f62cSfgsch } 12590720f62cSfgsch for (i = 0; i < cfe->num_memspace; i++) { 12600720f62cSfgsch if (lengthsize) { 12610720f62cSfgsch cfe->memspace[i].length = 12620720f62cSfgsch 256 * pcmcia_tuple_read_n(tuple, lengthsize, 12630720f62cSfgsch idx); 12640720f62cSfgsch idx += lengthsize; 12650720f62cSfgsch } else { 12660720f62cSfgsch cfe->memspace[i].length = 0; 12670720f62cSfgsch } 12680720f62cSfgsch if (cfe->memspace[i].length == 0) { 12690720f62cSfgsch DPRINTF(("cfe->memspace[%d].length == 0", 12700720f62cSfgsch i)); 12710720f62cSfgsch state->card->error++; 12720720f62cSfgsch } 12730720f62cSfgsch if (cardaddrsize) { 12740720f62cSfgsch cfe->memspace[i].cardaddr = 12750720f62cSfgsch 256 * pcmcia_tuple_read_n(tuple, cardaddrsize, 12760720f62cSfgsch idx); 12770720f62cSfgsch idx += cardaddrsize; 12780720f62cSfgsch } else { 12790720f62cSfgsch cfe->memspace[i].cardaddr = 0; 12800720f62cSfgsch } 12810720f62cSfgsch if (hostaddrsize) { 12820720f62cSfgsch cfe->memspace[i].hostaddr = 12830720f62cSfgsch 256 * pcmcia_tuple_read_n(tuple, hostaddrsize, 12840720f62cSfgsch idx); 12850720f62cSfgsch idx += hostaddrsize; 12860720f62cSfgsch } else { 12870720f62cSfgsch cfe->memspace[i].hostaddr = 0; 12880720f62cSfgsch } 12890720f62cSfgsch } 12900720f62cSfgsch } 12910720f62cSfgsch } 12920720f62cSfgsch if (misc) { 1293709e0656Sfgsch if (tuple->length <= idx) { 1294709e0656Sfgsch DPRINTF(("ran out of space before TPCE_MI\n")); 1295709e0656Sfgsch 1296709e0656Sfgsch goto abort_cfe; 1297709e0656Sfgsch } 1298709e0656Sfgsch 12990720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 13000720f62cSfgsch idx++; 13010720f62cSfgsch 1302ae2d8a60Sfgsch cfe->flags &= ~(PCMCIA_CFE_POWERDOWN 1303ae2d8a60Sfgsch | PCMCIA_CFE_READONLY 1304ae2d8a60Sfgsch | PCMCIA_CFE_AUDIO); 13050720f62cSfgsch if (reg & PCMCIA_TPCE_MI_PWRDOWN) 1306ae2d8a60Sfgsch cfe->flags |= PCMCIA_CFE_POWERDOWN; 13070720f62cSfgsch if (reg & PCMCIA_TPCE_MI_READONLY) 1308ae2d8a60Sfgsch cfe->flags |= PCMCIA_CFE_READONLY; 13090720f62cSfgsch if (reg & PCMCIA_TPCE_MI_AUDIO) 1310ae2d8a60Sfgsch cfe->flags |= PCMCIA_CFE_AUDIO; 13110720f62cSfgsch cfe->maxtwins = reg & PCMCIA_TPCE_MI_MAXTWINS; 13120720f62cSfgsch 13130720f62cSfgsch while (reg & PCMCIA_TPCE_MI_EXT) { 13140720f62cSfgsch reg = pcmcia_tuple_read_1(tuple, idx); 13150720f62cSfgsch idx++; 13160720f62cSfgsch } 13170720f62cSfgsch } 13180720f62cSfgsch /* skip all the subtuples */ 13190720f62cSfgsch } 1320709e0656Sfgsch 1321709e0656Sfgsch abort_cfe: 13220720f62cSfgsch DPRINTF(("CISTPL_CFTABLE_ENTRY\n")); 13230720f62cSfgsch break; 1324bd4ab2b6Sniklas 13250720f62cSfgsch default: 13260720f62cSfgsch DPRINTF(("unhandled CISTPL %x\n", tuple->code)); 13270720f62cSfgsch break; 13280720f62cSfgsch } 13290720f62cSfgsch 13300720f62cSfgsch return (0); 13310720f62cSfgsch } 1332