pccard_cis.c revision 93370
152506Simp/* $NetBSD: pcmcia_cis.c,v 1.10 1998/12/29 09:03:15 marc Exp $ */ 252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard_cis.c 93370 2002-03-29 08:05:39Z imp $ */ 352506Simp 452506Simp/* 552506Simp * Copyright (c) 1997 Marc Horowitz. All rights reserved. 652506Simp * 752506Simp * Redistribution and use in source and binary forms, with or without 852506Simp * modification, are permitted provided that the following conditions 952506Simp * are met: 1052506Simp * 1. Redistributions of source code must retain the above copyright 1152506Simp * notice, this list of conditions and the following disclaimer. 1252506Simp * 2. Redistributions in binary form must reproduce the above copyright 1352506Simp * notice, this list of conditions and the following disclaimer in the 1452506Simp * documentation and/or other materials provided with the distribution. 1552506Simp * 3. All advertising materials mentioning features or use of this software 1652506Simp * must display the following acknowledgement: 1752506Simp * This product includes software developed by Marc Horowitz. 1852506Simp * 4. The name of the author may not be used to endorse or promote products 1952506Simp * derived from this software without specific prior written permission. 2052506Simp * 2152506Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2252506Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2352506Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2452506Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2552506Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2652506Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2752506Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2852506Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2952506Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3052506Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3152506Simp */ 3252506Simp 3352506Simp#include <sys/param.h> 3452506Simp#include <sys/systm.h> 3552506Simp#include <sys/malloc.h> 3652506Simp#include <sys/module.h> 3752506Simp#include <sys/kernel.h> 3852506Simp#include <sys/queue.h> 3952506Simp#include <sys/types.h> 4052506Simp 4152506Simp#include <sys/bus.h> 4252506Simp#include <machine/bus.h> 4352506Simp#include <sys/rman.h> 4452506Simp#include <machine/resource.h> 4552506Simp 4652506Simp#include <dev/pccard/pccardreg.h> 4752506Simp#include <dev/pccard/pccardvar.h> 4852506Simp 4959193Simp#include "card_if.h" 5059193Simp 5191786Simpextern int pccard_cis_debug; 5291786Simp 5359193Simp#define PCCARDCISDEBUG 5452506Simp#ifdef PCCARDCISDEBUG 5591786Simp#define DPRINTF(arg) if (pccard_cis_debug) printf arg 5691786Simp#define DEVPRINTF(arg) if (pccard_cis_debug) device_printf arg 5752506Simp#else 5852506Simp#define DPRINTF(arg) 5955720Simp#define DEVPRINTF(arg) 6052506Simp#endif 6152506Simp 6252506Simp#define PCCARD_CIS_SIZE 1024 6352506Simp 6452506Simpstruct cis_state { 6552506Simp int count; 6652506Simp int gotmfc; 6752506Simp struct pccard_config_entry temp_cfe; 6852506Simp struct pccard_config_entry *default_cfe; 6952506Simp struct pccard_card *card; 7052506Simp struct pccard_function *pf; 7152506Simp}; 7252506Simp 7354250Simpint pccard_parse_cis_tuple(struct pccard_tuple *, void *); 7482781Sshibastatic int decode_funce(struct pccard_tuple *, struct pccard_function *); 7552506Simp 7652506Simpvoid 7755720Simppccard_read_cis(struct pccard_softc *sc) 7852506Simp{ 7952506Simp struct cis_state state; 8052506Simp 8152506Simp state.count = 0; 8252506Simp state.gotmfc = 0; 8352506Simp 8452506Simp state.card = &sc->card; 8552506Simp 8652506Simp state.card->error = 0; 8752506Simp state.card->cis1_major = -1; 8852506Simp state.card->cis1_minor = -1; 8952506Simp state.card->cis1_info[0] = NULL; 9052506Simp state.card->cis1_info[1] = NULL; 9152506Simp state.card->cis1_info[2] = NULL; 9252506Simp state.card->cis1_info[3] = NULL; 9386272Simp state.card->manufacturer = PCMCIA_VENDOR_INVALID; 9486272Simp state.card->product = PCMCIA_PRODUCT_INVALID; 9552506Simp STAILQ_INIT(&state.card->pf_head); 9652506Simp 9752506Simp state.pf = NULL; 9852506Simp 9958997Simp if (pccard_scan_cis(sc->dev, pccard_parse_cis_tuple, 10052506Simp &state) == -1) 10152506Simp state.card->error++; 10252506Simp} 10352506Simp 10452506Simpint 10555720Simppccard_scan_cis(device_t dev, int (*fct)(struct pccard_tuple *, void *), 10655720Simp void *arg) 10752506Simp{ 10855720Simp struct resource *res; 10955720Simp int rid; 11052506Simp struct pccard_tuple tuple; 11152506Simp int longlink_present; 11252506Simp int longlink_common; 11352506Simp u_long longlink_addr; 11452506Simp int mfc_count; 11552506Simp int mfc_index; 11652506Simp struct { 11752506Simp int common; 11852506Simp u_long addr; 11952506Simp } mfc[256 / 5]; 12052506Simp int ret; 12152506Simp 12252506Simp ret = 0; 12352506Simp 12452506Simp /* allocate some memory */ 12552506Simp 12655720Simp rid = 0; 12755720Simp res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 12859193Simp PCCARD_CIS_SIZE, RF_ACTIVE); 12955720Simp if (res == NULL) { 13055720Simp device_printf(dev, "can't alloc memory to read attributes\n"); 13152506Simp return -1; 13252506Simp } 13359193Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 13459193Simp rid, PCCARD_A_MEM_ATTR); 13555720Simp tuple.memt = rman_get_bustag(res); 13655720Simp tuple.memh = rman_get_bushandle(res); 13759389Simp tuple.ptr = 0; 13852506Simp 13952506Simp DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh)); 14055720Simp 14152506Simp tuple.mult = 2; 14252506Simp 14352506Simp longlink_present = 1; 14452506Simp longlink_common = 1; 14552506Simp longlink_addr = 0; 14652506Simp 14752506Simp mfc_count = 0; 14852506Simp mfc_index = 0; 14952506Simp 15055720Simp DEVPRINTF((dev, "CIS tuple chain:\n")); 15152506Simp 15252506Simp while (1) { 15352506Simp while (1) { 15452506Simp /* get the tuple code */ 15552506Simp 15652506Simp tuple.code = pccard_cis_read_1(&tuple, tuple.ptr); 15752506Simp 15852506Simp /* two special-case tuples */ 15952506Simp 16052506Simp if (tuple.code == PCCARD_CISTPL_NULL) { 16152506Simp DPRINTF(("CISTPL_NONE\n 00\n")); 16252506Simp tuple.ptr++; 16352506Simp continue; 16452506Simp } else if (tuple.code == PCCARD_CISTPL_END) { 16552506Simp DPRINTF(("CISTPL_END\n ff\n")); 16652506Simp /* Call the function for the END tuple, since 16752506Simp the CIS semantics depend on it */ 16852506Simp if ((*fct) (&tuple, arg)) { 16952506Simp ret = 1; 17052506Simp goto done; 17152506Simp } 17252506Simp tuple.ptr++; 17352506Simp break; 17452506Simp } 17552506Simp /* now all the normal tuples */ 17652506Simp 17752506Simp tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1); 17852506Simp switch (tuple.code) { 17952506Simp case PCCARD_CISTPL_LONGLINK_A: 18052506Simp case PCCARD_CISTPL_LONGLINK_C: 18152506Simp if (tuple.length < 4) { 18252506Simp DPRINTF(("CISTPL_LONGLINK_%s too " 18352506Simp "short %d\n", 18452506Simp longlink_common ? "C" : "A", 18552506Simp tuple.length)); 18652506Simp break; 18752506Simp } 18852506Simp longlink_present = 1; 18952506Simp longlink_common = (tuple.code == 19052506Simp PCCARD_CISTPL_LONGLINK_C) ? 1 : 0; 19152506Simp longlink_addr = pccard_tuple_read_4(&tuple, 0); 19252506Simp DPRINTF(("CISTPL_LONGLINK_%s %lx\n", 19352506Simp longlink_common ? "C" : "A", 19452506Simp longlink_addr)); 19552506Simp break; 19652506Simp case PCCARD_CISTPL_NO_LINK: 19752506Simp longlink_present = 0; 19852506Simp DPRINTF(("CISTPL_NO_LINK\n")); 19952506Simp break; 20052506Simp case PCCARD_CISTPL_CHECKSUM: 20152506Simp if (tuple.length < 5) { 20252506Simp DPRINTF(("CISTPL_CHECKSUM too " 20352506Simp "short %d\n", tuple.length)); 20452506Simp break; 20552506Simp } { 20652506Simp int16_t offset; 20752506Simp u_long addr, length; 20852506Simp u_int cksum, sum; 20952506Simp int i; 21052506Simp 21190896Simp offset = (uint16_t) 21252506Simp pccard_tuple_read_2(&tuple, 0); 21352506Simp length = pccard_tuple_read_2(&tuple, 2); 21452506Simp cksum = pccard_tuple_read_1(&tuple, 4); 21552506Simp 21652506Simp addr = tuple.ptr + offset; 21752506Simp 21852506Simp DPRINTF(("CISTPL_CHECKSUM addr=%lx " 21952506Simp "len=%lx cksum=%x", 22052506Simp addr, length, cksum)); 22152506Simp 22252506Simp /* 22352506Simp * XXX do more work to deal with 22452506Simp * distant regions 22552506Simp */ 22652506Simp if ((addr >= PCCARD_CIS_SIZE) || 22752506Simp ((addr + length) < 0) || 22852506Simp ((addr + length) >= 22952506Simp PCCARD_CIS_SIZE)) { 23052506Simp DPRINTF((" skipped, " 23152506Simp "too distant\n")); 23252506Simp break; 23352506Simp } 23452506Simp sum = 0; 23552506Simp for (i = 0; i < length; i++) 23652506Simp sum += 23752506Simp bus_space_read_1(tuple.memt, 23852506Simp tuple.memh, 23952506Simp addr + tuple.mult * i); 24052506Simp if (cksum != (sum & 0xff)) { 24152506Simp DPRINTF((" failed sum=%x\n", 24252506Simp sum)); 24355720Simp device_printf(dev, 24455720Simp "CIS checksum failed\n"); 24552506Simp#if 0 24652506Simp /* 24752506Simp * XXX Some working cards have 24852506Simp * XXX bad checksums!! 24952506Simp */ 25052506Simp ret = -1; 25152506Simp#endif 25252506Simp } else { 25352506Simp DPRINTF((" ok\n")); 25452506Simp } 25552506Simp } 25652506Simp break; 25752506Simp case PCCARD_CISTPL_LONGLINK_MFC: 25852506Simp if (tuple.length < 1) { 25952506Simp DPRINTF(("CISTPL_LONGLINK_MFC too " 26052506Simp "short %d\n", tuple.length)); 26152506Simp break; 26252506Simp } 26352506Simp /* 26452506Simp * this is kind of ad hoc, as I don't have 26552506Simp * any real documentation 26652506Simp */ 26752506Simp { 26852506Simp int i; 26952506Simp 27052506Simp mfc_count = 27152506Simp pccard_tuple_read_1(&tuple, 0); 27252506Simp DPRINTF(("CISTPL_LONGLINK_MFC %d", 27352506Simp mfc_count)); 27452506Simp for (i = 0; i < mfc_count; i++) { 27552506Simp mfc[i].common = 27652506Simp (pccard_tuple_read_1(&tuple, 27752506Simp 1 + 5 * i) == 27852506Simp PCCARD_MFC_MEM_COMMON) ? 27952506Simp 1 : 0; 28052506Simp mfc[i].addr = 28152506Simp pccard_tuple_read_4(&tuple, 28252506Simp 1 + 5 * i + 1); 28352506Simp DPRINTF((" %s:%lx", 28452506Simp mfc[i].common ? "common" : 28552506Simp "attr", mfc[i].addr)); 28652506Simp } 28752506Simp DPRINTF(("\n")); 28852506Simp } 28952506Simp /* 29052506Simp * for LONGLINK_MFC, fall through to the 29152506Simp * function. This tuple has structural and 29252506Simp * semantic content. 29352506Simp */ 29452506Simp default: 29552506Simp { 29652506Simp if ((*fct) (&tuple, arg)) { 29752506Simp ret = 1; 29852506Simp goto done; 29952506Simp } 30052506Simp } 30152506Simp break; 30252506Simp } /* switch */ 30352506Simp#ifdef PCCARDCISDEBUG 30452506Simp /* print the tuple */ 30552506Simp { 30652506Simp int i; 30752506Simp 30852506Simp DPRINTF((" %02x %02x", tuple.code, 30952506Simp tuple.length)); 31052506Simp 31152506Simp for (i = 0; i < tuple.length; i++) { 31252506Simp DPRINTF((" %02x", 31352506Simp pccard_tuple_read_1(&tuple, i))); 31452506Simp if ((i % 16) == 13) 31552506Simp DPRINTF(("\n")); 31652506Simp } 31787352Simp 31852506Simp if ((i % 16) != 14) 31952506Simp DPRINTF(("\n")); 32052506Simp } 32152506Simp#endif 32252506Simp /* skip to the next tuple */ 32352506Simp tuple.ptr += 2 + tuple.length; 32452506Simp } 32552506Simp 32652506Simp /* 32752506Simp * the chain is done. Clean up and move onto the next one, 32852506Simp * if any. The loop is here in the case that there is an MFC 32952506Simp * card with no longlink (which defaults to existing, == 0). 33052506Simp * In general, this means that if one pointer fails, it will 33152506Simp * try the next one, instead of just bailing. 33252506Simp */ 33352506Simp 33452506Simp while (1) { 33552506Simp if (longlink_present) { 33687352Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, 33787352Simp SYS_RES_MEMORY, rid, longlink_common ? 33893370Simp PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR); 33952506Simp DPRINTF(("cis mem map %x\n", 34052506Simp (unsigned int) tuple.memh)); 34152506Simp tuple.mult = longlink_common ? 1 : 2; 34293370Simp tuple.ptr = longlink_addr; 34352506Simp longlink_present = 0; 34452506Simp longlink_common = 1; 34552506Simp longlink_addr = 0; 34652506Simp } else if (mfc_count && (mfc_index < mfc_count)) { 34787352Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, 34887352Simp SYS_RES_MEMORY, rid, mfc[mfc_index].common 34993370Simp ? PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR); 35052506Simp DPRINTF(("cis mem map %x\n", 35152506Simp (unsigned int) tuple.memh)); 35252506Simp /* set parse state, and point at the next one */ 35352506Simp tuple.mult = mfc[mfc_index].common ? 1 : 2; 35493370Simp tuple.ptr = mfc[mfc_index].addr; 35552506Simp mfc_index++; 35652506Simp } else { 35752506Simp goto done; 35852506Simp } 35952506Simp 36052506Simp /* make sure that the link is valid */ 36152506Simp tuple.code = pccard_cis_read_1(&tuple, tuple.ptr); 36252506Simp if (tuple.code != PCCARD_CISTPL_LINKTARGET) { 36352506Simp DPRINTF(("CISTPL_LINKTARGET expected, " 36452506Simp "code %02x observed\n", tuple.code)); 36552506Simp continue; 36652506Simp } 36752506Simp tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1); 36852506Simp if (tuple.length < 3) { 36952506Simp DPRINTF(("CISTPL_LINKTARGET too short %d\n", 37052506Simp tuple.length)); 37152506Simp continue; 37252506Simp } 37352506Simp if ((pccard_tuple_read_1(&tuple, 0) != 'C') || 37452506Simp (pccard_tuple_read_1(&tuple, 1) != 'I') || 37552506Simp (pccard_tuple_read_1(&tuple, 2) != 'S')) { 37652506Simp DPRINTF(("CISTPL_LINKTARGET magic " 37752506Simp "%02x%02x%02x incorrect\n", 37852506Simp pccard_tuple_read_1(&tuple, 0), 37952506Simp pccard_tuple_read_1(&tuple, 1), 38052506Simp pccard_tuple_read_1(&tuple, 2))); 38152506Simp continue; 38252506Simp } 38352506Simp tuple.ptr += 2 + tuple.length; 38452506Simp break; 38552506Simp } 38652506Simp } 38752506Simp 38852506Simpdone: 38955720Simp bus_release_resource(dev, SYS_RES_MEMORY, rid, res); 39052506Simp 39152506Simp return (ret); 39252506Simp} 39352506Simp 39452506Simp/* XXX this is incredibly verbose. Not sure what trt is */ 39552506Simp 39652506Simpvoid 39752506Simppccard_print_cis(device_t dev) 39852506Simp{ 39964850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 40052506Simp struct pccard_card *card = &sc->card; 40152506Simp struct pccard_function *pf; 40252506Simp struct pccard_config_entry *cfe; 40352506Simp int i; 40452506Simp 40552506Simp device_printf(dev, "CIS version "); 40652506Simp if (card->cis1_major == 4) { 40752506Simp if (card->cis1_minor == 0) 40852506Simp printf("PCCARD 1.0\n"); 40952506Simp else if (card->cis1_minor == 1) 41052506Simp printf("PCCARD 2.0 or 2.1\n"); 41152506Simp } else if (card->cis1_major >= 5) 41252506Simp printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor); 41352506Simp else 41452506Simp printf("unknown (major=%d, minor=%d)\n", 41552506Simp card->cis1_major, card->cis1_minor); 41652506Simp 41752506Simp device_printf(dev, "CIS info: "); 41852506Simp for (i = 0; i < 4; i++) { 41952506Simp if (card->cis1_info[i] == NULL) 42052506Simp break; 42152506Simp if (i) 42252506Simp printf(", "); 42352506Simp printf("%s", card->cis1_info[i]); 42452506Simp } 42552506Simp printf("\n"); 42652506Simp 42752506Simp device_printf(dev, "Manufacturer code 0x%x, product 0x%x\n", 42852506Simp card->manufacturer, card->product); 42952506Simp 43052506Simp STAILQ_FOREACH(pf, &card->pf_head, pf_list) { 43152506Simp device_printf(dev, "function %d: ", pf->number); 43252506Simp 43352506Simp switch (pf->function) { 43452506Simp case PCCARD_FUNCTION_UNSPEC: 43552506Simp printf("unspecified"); 43652506Simp break; 43752506Simp case PCCARD_FUNCTION_MULTIFUNCTION: 43852506Simp printf("multi-function"); 43952506Simp break; 44052506Simp case PCCARD_FUNCTION_MEMORY: 44152506Simp printf("memory"); 44252506Simp break; 44352506Simp case PCCARD_FUNCTION_SERIAL: 44452506Simp printf("serial port"); 44552506Simp break; 44652506Simp case PCCARD_FUNCTION_PARALLEL: 44752506Simp printf("parallel port"); 44852506Simp break; 44952506Simp case PCCARD_FUNCTION_DISK: 45052506Simp printf("fixed disk"); 45152506Simp break; 45252506Simp case PCCARD_FUNCTION_VIDEO: 45352506Simp printf("video adapter"); 45452506Simp break; 45552506Simp case PCCARD_FUNCTION_NETWORK: 45652506Simp printf("network adapter"); 45752506Simp break; 45852506Simp case PCCARD_FUNCTION_AIMS: 45952506Simp printf("auto incrementing mass storage"); 46052506Simp break; 46152506Simp case PCCARD_FUNCTION_SCSI: 46252506Simp printf("SCSI bridge"); 46352506Simp break; 46452506Simp case PCCARD_FUNCTION_SECURITY: 46552506Simp printf("Security services"); 46652506Simp break; 46752506Simp case PCCARD_FUNCTION_INSTRUMENT: 46852506Simp printf("Instrument"); 46952506Simp break; 47052506Simp default: 47152506Simp printf("unknown (%d)", pf->function); 47252506Simp break; 47352506Simp } 47452506Simp 47552506Simp printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask); 47652506Simp 47752506Simp STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 47852506Simp device_printf(dev, "function %d, config table entry " 47952506Simp "%d: ", pf->number, cfe->number); 48052506Simp 48152506Simp switch (cfe->iftype) { 48252506Simp case PCCARD_IFTYPE_MEMORY: 48352506Simp printf("memory card"); 48452506Simp break; 48552506Simp case PCCARD_IFTYPE_IO: 48652506Simp printf("I/O card"); 48752506Simp break; 48852506Simp default: 48952506Simp printf("card type unknown"); 49052506Simp break; 49152506Simp } 49252506Simp 49352506Simp printf("; irq mask %x", cfe->irqmask); 49452506Simp 49552506Simp if (cfe->num_iospace) { 49652506Simp printf("; iomask %lx, iospace", cfe->iomask); 49752506Simp 49853813Simp for (i = 0; i < cfe->num_iospace; i++) { 49953813Simp printf(" %lx", cfe->iospace[i].start); 50053813Simp if (cfe->iospace[i].length) 50153813Simp printf("-%lx", 50253813Simp cfe->iospace[i].start + 50353813Simp cfe->iospace[i].length - 1); 50453813Simp } 50552506Simp } 50652506Simp if (cfe->num_memspace) { 50752506Simp printf("; memspace"); 50852506Simp 50953813Simp for (i = 0; i < cfe->num_memspace; i++) { 51053813Simp printf(" %lx", 51153813Simp cfe->memspace[i].cardaddr); 51253813Simp if (cfe->memspace[i].length) 51353813Simp printf("-%lx", 51453813Simp cfe->memspace[i].cardaddr + 51553813Simp cfe->memspace[i].length - 1); 51653813Simp if (cfe->memspace[i].hostaddr) 51753813Simp printf("@%lx", 51853813Simp cfe->memspace[i].hostaddr); 51953813Simp } 52052506Simp } 52152506Simp if (cfe->maxtwins) 52252506Simp printf("; maxtwins %d", cfe->maxtwins); 52352506Simp 52452506Simp printf(";"); 52552506Simp 52652506Simp if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED) 52752506Simp printf(" mwait_required"); 52852506Simp if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE) 52952506Simp printf(" rdybsy_active"); 53052506Simp if (cfe->flags & PCCARD_CFE_WP_ACTIVE) 53152506Simp printf(" wp_active"); 53252506Simp if (cfe->flags & PCCARD_CFE_BVD_ACTIVE) 53352506Simp printf(" bvd_active"); 53452506Simp if (cfe->flags & PCCARD_CFE_IO8) 53552506Simp printf(" io8"); 53652506Simp if (cfe->flags & PCCARD_CFE_IO16) 53752506Simp printf(" io16"); 53852506Simp if (cfe->flags & PCCARD_CFE_IRQSHARE) 53952506Simp printf(" irqshare"); 54052506Simp if (cfe->flags & PCCARD_CFE_IRQPULSE) 54152506Simp printf(" irqpulse"); 54252506Simp if (cfe->flags & PCCARD_CFE_IRQLEVEL) 54352506Simp printf(" irqlevel"); 54452506Simp if (cfe->flags & PCCARD_CFE_POWERDOWN) 54552506Simp printf(" powerdown"); 54652506Simp if (cfe->flags & PCCARD_CFE_READONLY) 54752506Simp printf(" readonly"); 54852506Simp if (cfe->flags & PCCARD_CFE_AUDIO) 54952506Simp printf(" audio"); 55052506Simp 55152506Simp printf("\n"); 55252506Simp } 55352506Simp } 55452506Simp 55552506Simp if (card->error) 55652506Simp device_printf(dev, "%d errors found while parsing CIS\n", 55752506Simp card->error); 55852506Simp} 55952506Simp 56052506Simpint 56155720Simppccard_parse_cis_tuple(struct pccard_tuple *tuple, void *arg) 56252506Simp{ 56352506Simp /* most of these are educated guesses */ 56452506Simp static struct pccard_config_entry init_cfe = { 56552506Simp -1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE | 56652506Simp PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY, 56752506Simp }; 56852506Simp 56952506Simp struct cis_state *state = arg; 57052506Simp 57152506Simp switch (tuple->code) { 57252506Simp case PCCARD_CISTPL_END: 57352506Simp /* if we've seen a LONGLINK_MFC, and this is the first 57452506Simp * END after it, reset the function list. 57552506Simp * 57652506Simp * XXX This might also be the right place to start a 57752506Simp * new function, but that assumes that a function 57852506Simp * definition never crosses any longlink, and I'm not 57952506Simp * sure about that. This is probably safe for MFC 58052506Simp * cards, but what we have now isn't broken, so I'd 58152506Simp * rather not change it. 58252506Simp */ 58352506Simp if (state->gotmfc == 1) { 58452506Simp struct pccard_function *pf, *pfnext; 58552506Simp 58652506Simp for (pf = STAILQ_FIRST(&state->card->pf_head); 58752506Simp pf != NULL; pf = pfnext) { 58852506Simp pfnext = STAILQ_NEXT(pf, pf_list); 58952506Simp free(pf, M_DEVBUF); 59052506Simp } 59152506Simp 59252506Simp STAILQ_INIT(&state->card->pf_head); 59352506Simp 59452506Simp state->count = 0; 59552506Simp state->gotmfc = 2; 59652506Simp state->pf = NULL; 59752506Simp } 59852506Simp break; 59952506Simp case PCCARD_CISTPL_LONGLINK_MFC: 60052506Simp /* 60152506Simp * this tuple's structure was dealt with in scan_cis. here, 60252506Simp * record the fact that the MFC tuple was seen, so that 60352506Simp * functions declared before the MFC link can be cleaned 60452506Simp * up. 60552506Simp */ 60652506Simp state->gotmfc = 1; 60752506Simp break; 60852506Simp#ifdef PCCARDCISDEBUG 60952506Simp case PCCARD_CISTPL_DEVICE: 61052506Simp case PCCARD_CISTPL_DEVICE_A: 61152506Simp { 61252506Simp u_int reg, dtype, dspeed; 61352506Simp 61452506Simp reg = pccard_tuple_read_1(tuple, 0); 61552506Simp dtype = reg & PCCARD_DTYPE_MASK; 61652506Simp dspeed = reg & PCCARD_DSPEED_MASK; 61752506Simp 61852506Simp DPRINTF(("CISTPL_DEVICE%s type=", 61952506Simp (tuple->code == PCCARD_CISTPL_DEVICE) ? "" : "_A")); 62052506Simp switch (dtype) { 62152506Simp case PCCARD_DTYPE_NULL: 62252506Simp DPRINTF(("null")); 62352506Simp break; 62452506Simp case PCCARD_DTYPE_ROM: 62552506Simp DPRINTF(("rom")); 62652506Simp break; 62752506Simp case PCCARD_DTYPE_OTPROM: 62852506Simp DPRINTF(("otprom")); 62952506Simp break; 63052506Simp case PCCARD_DTYPE_EPROM: 63152506Simp DPRINTF(("eprom")); 63252506Simp break; 63352506Simp case PCCARD_DTYPE_EEPROM: 63452506Simp DPRINTF(("eeprom")); 63552506Simp break; 63652506Simp case PCCARD_DTYPE_FLASH: 63752506Simp DPRINTF(("flash")); 63852506Simp break; 63952506Simp case PCCARD_DTYPE_SRAM: 64052506Simp DPRINTF(("sram")); 64152506Simp break; 64252506Simp case PCCARD_DTYPE_DRAM: 64352506Simp DPRINTF(("dram")); 64452506Simp break; 64552506Simp case PCCARD_DTYPE_FUNCSPEC: 64652506Simp DPRINTF(("funcspec")); 64752506Simp break; 64852506Simp case PCCARD_DTYPE_EXTEND: 64952506Simp DPRINTF(("extend")); 65052506Simp break; 65152506Simp default: 65252506Simp DPRINTF(("reserved")); 65352506Simp break; 65452506Simp } 65552506Simp DPRINTF((" speed=")); 65652506Simp switch (dspeed) { 65752506Simp case PCCARD_DSPEED_NULL: 65852506Simp DPRINTF(("null")); 65952506Simp break; 66052506Simp case PCCARD_DSPEED_250NS: 66152506Simp DPRINTF(("250ns")); 66252506Simp break; 66352506Simp case PCCARD_DSPEED_200NS: 66452506Simp DPRINTF(("200ns")); 66552506Simp break; 66652506Simp case PCCARD_DSPEED_150NS: 66752506Simp DPRINTF(("150ns")); 66852506Simp break; 66952506Simp case PCCARD_DSPEED_100NS: 67052506Simp DPRINTF(("100ns")); 67152506Simp break; 67252506Simp case PCCARD_DSPEED_EXT: 67352506Simp DPRINTF(("ext")); 67452506Simp break; 67552506Simp default: 67652506Simp DPRINTF(("reserved")); 67752506Simp break; 67852506Simp } 67952506Simp } 68052506Simp DPRINTF(("\n")); 68152506Simp break; 68252506Simp#endif 68352506Simp case PCCARD_CISTPL_VERS_1: 68452506Simp if (tuple->length < 6) { 68552506Simp DPRINTF(("CISTPL_VERS_1 too short %d\n", 68652506Simp tuple->length)); 68752506Simp break; 68852506Simp } { 68952506Simp int start, i, ch, count; 69052506Simp 69152506Simp state->card->cis1_major = pccard_tuple_read_1(tuple, 0); 69252506Simp state->card->cis1_minor = pccard_tuple_read_1(tuple, 1); 69352506Simp 69452506Simp for (count = 0, start = 0, i = 0; 69552506Simp (count < 4) && ((i + 4) < 256); i++) { 69652506Simp ch = pccard_tuple_read_1(tuple, 2 + i); 69752506Simp if (ch == 0xff) 69852506Simp break; 69952506Simp state->card->cis1_info_buf[i] = ch; 70052506Simp if (ch == 0) { 70152506Simp state->card->cis1_info[count] = 70252506Simp state->card->cis1_info_buf + start; 70352506Simp start = i + 1; 70452506Simp count++; 70552506Simp } 70652506Simp } 70752506Simp DPRINTF(("CISTPL_VERS_1\n")); 70852506Simp } 70952506Simp break; 71052506Simp case PCCARD_CISTPL_MANFID: 71152506Simp if (tuple->length < 4) { 71252506Simp DPRINTF(("CISTPL_MANFID too short %d\n", 71352506Simp tuple->length)); 71452506Simp break; 71552506Simp } 71652506Simp state->card->manufacturer = pccard_tuple_read_2(tuple, 0); 71752506Simp state->card->product = pccard_tuple_read_2(tuple, 2); 71890964Sshiba /* 71990964Sshiba * This is for xe driver. But not better. 72090964Sshiba * In PC Card Standard, 72190964Sshiba * Manufacturer ID: 2byte. 72290964Sshiba * Product ID: 2byte usually, but no limited. 72390964Sshiba */ 72490964Sshiba if (tuple->length == 5 ) { 72590964Sshiba state->card->prodext = pccard_tuple_read_1(tuple, 4); 72690964Sshiba } 72752506Simp DPRINTF(("CISTPL_MANFID\n")); 72852506Simp break; 72952506Simp case PCCARD_CISTPL_FUNCID: 73052506Simp if (tuple->length < 1) { 73152506Simp DPRINTF(("CISTPL_FUNCID too short %d\n", 73252506Simp tuple->length)); 73352506Simp break; 73452506Simp } 73552506Simp if ((state->pf == NULL) || (state->gotmfc == 2)) { 73652506Simp state->pf = malloc(sizeof(*state->pf), M_DEVBUF, 73767897Sdwmalone M_NOWAIT | M_ZERO); 73852506Simp state->pf->number = state->count++; 73952506Simp state->pf->last_config_index = -1; 74052506Simp STAILQ_INIT(&state->pf->cfe_head); 74152506Simp 74252506Simp STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf, 74352506Simp pf_list); 74452506Simp } 74552506Simp state->pf->function = pccard_tuple_read_1(tuple, 0); 74652506Simp 74752506Simp DPRINTF(("CISTPL_FUNCID\n")); 74852506Simp break; 74982781Sshiba case PCCARD_CISTPL_FUNCE: 75082781Sshiba if (state->pf == NULL || state->pf->function <= 0) { 75182781Sshiba DPRINTF(("CISTPL_FUNCE is not followed by " 75282781Sshiba "valid CISTPL_FUNCID\n")); 75382781Sshiba break; 75482781Sshiba } 75582781Sshiba if (tuple->length >= 2) { 75682781Sshiba decode_funce(tuple, state->pf); 75782781Sshiba } 75882781Sshiba DPRINTF(("CISTPL_FUNCE\n")); 75982781Sshiba break; 76052506Simp case PCCARD_CISTPL_CONFIG: 76152506Simp if (tuple->length < 3) { 76252506Simp DPRINTF(("CISTPL_CONFIG too short %d\n", 76352506Simp tuple->length)); 76452506Simp break; 76552506Simp } { 76652506Simp u_int reg, rasz, rmsz, rfsz; 76752506Simp int i; 76852506Simp 76952506Simp reg = pccard_tuple_read_1(tuple, 0); 77052506Simp rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >> 77152506Simp PCCARD_TPCC_RASZ_SHIFT); 77252506Simp rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >> 77352506Simp PCCARD_TPCC_RMSZ_SHIFT); 77452506Simp rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >> 77552506Simp PCCARD_TPCC_RFSZ_SHIFT); 77652506Simp 77752506Simp if (tuple->length < (rasz + rmsz + rfsz)) { 77852506Simp DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too " 77952506Simp "short %d\n", rasz, rmsz, rfsz, 78052506Simp tuple->length)); 78152506Simp break; 78252506Simp } 78352506Simp if (state->pf == NULL) { 78452506Simp state->pf = malloc(sizeof(*state->pf), 78567897Sdwmalone M_DEVBUF, M_NOWAIT | M_ZERO); 78652506Simp state->pf->number = state->count++; 78752506Simp state->pf->last_config_index = -1; 78852506Simp STAILQ_INIT(&state->pf->cfe_head); 78952506Simp 79052506Simp STAILQ_INSERT_TAIL(&state->card->pf_head, 79152506Simp state->pf, pf_list); 79252506Simp 79352506Simp state->pf->function = PCCARD_FUNCTION_UNSPEC; 79452506Simp } 79552506Simp state->pf->last_config_index = 79652506Simp pccard_tuple_read_1(tuple, 1); 79752506Simp 79852506Simp state->pf->ccr_base = 0; 79952506Simp for (i = 0; i < rasz; i++) 80052506Simp state->pf->ccr_base |= 80152506Simp ((pccard_tuple_read_1(tuple, 2 + i)) << 80252506Simp (i * 8)); 80352506Simp 80452506Simp state->pf->ccr_mask = 0; 80552506Simp for (i = 0; i < rmsz; i++) 80652506Simp state->pf->ccr_mask |= 80752506Simp ((pccard_tuple_read_1(tuple, 80852506Simp 2 + rasz + i)) << (i * 8)); 80952506Simp 81052506Simp /* skip the reserved area and subtuples */ 81152506Simp 81252506Simp /* reset the default cfe for each cfe list */ 81352506Simp state->temp_cfe = init_cfe; 81452506Simp state->default_cfe = &state->temp_cfe; 81552506Simp } 81652506Simp DPRINTF(("CISTPL_CONFIG\n")); 81752506Simp break; 81852506Simp case PCCARD_CISTPL_CFTABLE_ENTRY: 81952506Simp { 82052506Simp int idx, i, j; 82152506Simp u_int reg, reg2; 82252506Simp u_int intface, def, num; 82352506Simp u_int power, timing, iospace, irq, memspace, misc; 82452506Simp struct pccard_config_entry *cfe; 82552506Simp 82652506Simp idx = 0; 82752506Simp 82852506Simp reg = pccard_tuple_read_1(tuple, idx); 82952506Simp idx++; 83052506Simp intface = reg & PCCARD_TPCE_INDX_INTFACE; 83152506Simp def = reg & PCCARD_TPCE_INDX_DEFAULT; 83252506Simp num = reg & PCCARD_TPCE_INDX_NUM_MASK; 83352506Simp 83452506Simp /* 83552506Simp * this is a little messy. Some cards have only a 83652506Simp * cfentry with the default bit set. So, as we go 83752506Simp * through the list, we add new indexes to the queue, 83852506Simp * and keep a pointer to the last one with the 83952506Simp * default bit set. if we see a record with the same 84052506Simp * index, as the default, we stash the default and 84152506Simp * replace the queue entry. otherwise, we just add 84252506Simp * new entries to the queue, pointing the default ptr 84352506Simp * at them if the default bit is set. if we get to 84452506Simp * the end with the default pointer pointing at a 84552506Simp * record which hasn't had a matching index, that's 84652506Simp * ok; it just becomes a cfentry like any other. 84752506Simp */ 84852506Simp 84952506Simp /* 85052506Simp * if the index in the cis differs from the default 85152506Simp * cis, create new entry in the queue and start it 85252506Simp * with the current default 85352506Simp */ 85452506Simp if (num != state->default_cfe->number) { 85552506Simp cfe = (struct pccard_config_entry *) 85652506Simp malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 85752506Simp 85852506Simp *cfe = *state->default_cfe; 85952506Simp 86052506Simp STAILQ_INSERT_TAIL(&state->pf->cfe_head, 86152506Simp cfe, cfe_list); 86252506Simp 86352506Simp cfe->number = num; 86452506Simp 86552506Simp /* 86652506Simp * if the default bit is set in the cis, then 86752506Simp * point the new default at whatever is being 86852506Simp * filled in 86952506Simp */ 87052506Simp if (def) 87152506Simp state->default_cfe = cfe; 87252506Simp } else { 87352506Simp /* 87452506Simp * the cis index matches the default index, 87552506Simp * fill in the default cfentry. It is 87652506Simp * assumed that the cfdefault index is in the 87752506Simp * queue. For it to be otherwise, the cis 87852506Simp * index would have to be -1 (initial 87952506Simp * condition) which is not possible, or there 88052506Simp * would have to be a preceding cis entry 88152506Simp * which had the same cis index and had the 88252506Simp * default bit unset. Neither condition 88352506Simp * should happen. If it does, this cfentry 88452506Simp * is lost (written into temp space), which 88552506Simp * is an acceptable failure mode. 88652506Simp */ 88752506Simp 88852506Simp cfe = state->default_cfe; 88952506Simp 89052506Simp /* 89152506Simp * if the cis entry does not have the default 89252506Simp * bit set, copy the default out of the way 89352506Simp * first. 89452506Simp */ 89552506Simp if (!def) { 89652506Simp state->temp_cfe = *state->default_cfe; 89752506Simp state->default_cfe = &state->temp_cfe; 89852506Simp } 89952506Simp } 90052506Simp 90152506Simp if (intface) { 90252506Simp reg = pccard_tuple_read_1(tuple, idx); 90352506Simp idx++; 90452506Simp if (reg & PCCARD_TPCE_IF_MWAIT) 90552506Simp cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED; 90652506Simp if (reg & PCCARD_TPCE_IF_RDYBSY) 90752506Simp cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE; 90852506Simp if (reg & PCCARD_TPCE_IF_WP) 90952506Simp cfe->flags |= PCCARD_CFE_WP_ACTIVE; 91052506Simp if (reg & PCCARD_TPCE_IF_BVD) 91152506Simp cfe->flags |= PCCARD_CFE_BVD_ACTIVE; 91252506Simp cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE; 91352506Simp } 91452506Simp reg = pccard_tuple_read_1(tuple, idx); 91552506Simp idx++; 91652506Simp 91752506Simp power = reg & PCCARD_TPCE_FS_POWER_MASK; 91852506Simp timing = reg & PCCARD_TPCE_FS_TIMING; 91952506Simp iospace = reg & PCCARD_TPCE_FS_IOSPACE; 92052506Simp irq = reg & PCCARD_TPCE_FS_IRQ; 92152506Simp memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK; 92252506Simp misc = reg & PCCARD_TPCE_FS_MISC; 92352506Simp 92452506Simp if (power) { 92552506Simp /* skip over power, don't save */ 92652506Simp /* for each parameter selection byte */ 92752506Simp for (i = 0; i < power; i++) { 92852506Simp reg = pccard_tuple_read_1(tuple, idx); 92952506Simp idx++; 93052506Simp /* for each bit */ 93152506Simp for (j = 0; j < 7; j++) { 93252506Simp /* if the bit is set */ 93352506Simp if ((reg >> j) & 0x01) { 93452506Simp /* skip over bytes */ 93552506Simp do { 93652506Simp reg2 = pccard_tuple_read_1(tuple, idx); 93752506Simp idx++; 93852506Simp /* 93952506Simp * until 94052506Simp * non-extensi 94152506Simp * on byte 94252506Simp */ 94352506Simp } while (reg2 & 0x80); 94452506Simp } 94552506Simp } 94652506Simp } 94752506Simp } 94852506Simp if (timing) { 94952506Simp /* skip over timing, don't save */ 95052506Simp reg = pccard_tuple_read_1(tuple, idx); 95152506Simp idx++; 95252506Simp 95352506Simp if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) != 95452506Simp PCCARD_TPCE_TD_RESERVED_MASK) 95552506Simp idx++; 95652506Simp if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) != 95752506Simp PCCARD_TPCE_TD_RDYBSY_MASK) 95852506Simp idx++; 95952506Simp if ((reg & PCCARD_TPCE_TD_WAIT_MASK) != 96052506Simp PCCARD_TPCE_TD_WAIT_MASK) 96152506Simp idx++; 96252506Simp } 96352506Simp if (iospace) { 96452506Simp if (tuple->length <= idx) { 96552506Simp DPRINTF(("ran out of space before TCPE_IO\n")); 96652506Simp goto abort_cfe; 96752506Simp } 96852506Simp 96952506Simp reg = pccard_tuple_read_1(tuple, idx); 97052506Simp idx++; 97152506Simp 97252506Simp if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT) 97352506Simp cfe->flags |= PCCARD_CFE_IO8; 97452506Simp if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT) 97552506Simp cfe->flags |= PCCARD_CFE_IO16; 97652506Simp cfe->iomask = 97752506Simp reg & PCCARD_TPCE_IO_IOADDRLINES_MASK; 97852506Simp 97952506Simp if (reg & PCCARD_TPCE_IO_HASRANGE) { 98052506Simp reg = pccard_tuple_read_1(tuple, idx); 98152506Simp idx++; 98252506Simp 98352506Simp cfe->num_iospace = 1 + (reg & 98452506Simp PCCARD_TPCE_IO_RANGE_COUNT); 98552506Simp 98652506Simp if (cfe->num_iospace > 98752506Simp (sizeof(cfe->iospace) / 98852506Simp sizeof(cfe->iospace[0]))) { 98952506Simp DPRINTF(("too many io " 99052506Simp "spaces %d", 99152506Simp cfe->num_iospace)); 99252506Simp state->card->error++; 99352506Simp break; 99452506Simp } 99552506Simp for (i = 0; i < cfe->num_iospace; i++) { 99652506Simp switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) { 99752506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE: 99852506Simp cfe->iospace[i].start = 99952506Simp pccard_tuple_read_1(tuple, idx); 100052506Simp idx++; 100152506Simp break; 100252506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO: 100352506Simp cfe->iospace[i].start = 100452506Simp pccard_tuple_read_2(tuple, idx); 100552506Simp idx += 2; 100652506Simp break; 100752506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR: 100852506Simp cfe->iospace[i].start = 100952506Simp pccard_tuple_read_4(tuple, idx); 101052506Simp idx += 4; 101152506Simp break; 101252506Simp } 101352506Simp switch (reg & 101452506Simp PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) { 101552506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE: 101652506Simp cfe->iospace[i].length = 101752506Simp pccard_tuple_read_1(tuple, idx); 101852506Simp idx++; 101952506Simp break; 102052506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO: 102152506Simp cfe->iospace[i].length = 102252506Simp pccard_tuple_read_2(tuple, idx); 102352506Simp idx += 2; 102452506Simp break; 102552506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR: 102652506Simp cfe->iospace[i].length = 102752506Simp pccard_tuple_read_4(tuple, idx); 102852506Simp idx += 4; 102952506Simp break; 103052506Simp } 103152506Simp cfe->iospace[i].length++; 103252506Simp } 103352506Simp } else { 103452506Simp cfe->num_iospace = 1; 103552506Simp cfe->iospace[0].start = 0; 103652506Simp cfe->iospace[0].length = 103752506Simp (1 << cfe->iomask); 103852506Simp } 103952506Simp } 104052506Simp if (irq) { 104152506Simp if (tuple->length <= idx) { 104252506Simp DPRINTF(("ran out of space before TCPE_IR\n")); 104352506Simp goto abort_cfe; 104452506Simp } 104552506Simp 104652506Simp reg = pccard_tuple_read_1(tuple, idx); 104752506Simp idx++; 104852506Simp 104952506Simp if (reg & PCCARD_TPCE_IR_SHARE) 105052506Simp cfe->flags |= PCCARD_CFE_IRQSHARE; 105152506Simp if (reg & PCCARD_TPCE_IR_PULSE) 105252506Simp cfe->flags |= PCCARD_CFE_IRQPULSE; 105352506Simp if (reg & PCCARD_TPCE_IR_LEVEL) 105452506Simp cfe->flags |= PCCARD_CFE_IRQLEVEL; 105552506Simp 105652506Simp if (reg & PCCARD_TPCE_IR_HASMASK) { 105752506Simp /* 105852506Simp * it's legal to ignore the 105952506Simp * special-interrupt bits, so I will 106052506Simp */ 106152506Simp 106252506Simp cfe->irqmask = 106352506Simp pccard_tuple_read_2(tuple, idx); 106452506Simp idx += 2; 106552506Simp } else { 106652506Simp cfe->irqmask = 106752506Simp (1 << (reg & PCCARD_TPCE_IR_IRQ)); 106852506Simp } 106952506Simp } 107052506Simp if (memspace) { 107152506Simp if (tuple->length <= idx) { 107252506Simp DPRINTF(("ran out of space before TCPE_MS\n")); 107352506Simp goto abort_cfe; 107452506Simp } 107552506Simp 107652506Simp if (memspace == PCCARD_TPCE_FS_MEMSPACE_NONE) { 107752506Simp cfe->num_memspace = 0; 107852506Simp } else if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) { 107952506Simp cfe->num_memspace = 1; 108052506Simp cfe->memspace[0].length = 256 * 108152506Simp pccard_tuple_read_2(tuple, idx); 108252506Simp idx += 2; 108352506Simp cfe->memspace[0].cardaddr = 0; 108452506Simp cfe->memspace[0].hostaddr = 0; 108552506Simp } else if (memspace == 108652506Simp PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) { 108752506Simp cfe->num_memspace = 1; 108852506Simp cfe->memspace[0].length = 256 * 108952506Simp pccard_tuple_read_2(tuple, idx); 109052506Simp idx += 2; 109152506Simp cfe->memspace[0].cardaddr = 256 * 109252506Simp pccard_tuple_read_2(tuple, idx); 109352506Simp idx += 2; 109452506Simp cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr; 109552506Simp } else { 109652506Simp int lengthsize; 109752506Simp int cardaddrsize; 109852506Simp int hostaddrsize; 109952506Simp 110052506Simp reg = pccard_tuple_read_1(tuple, idx); 110152506Simp idx++; 110252506Simp 110353873Simp cfe->num_memspace = (reg & 110453873Simp PCCARD_TPCE_MS_COUNT) + 1; 110552506Simp 110652506Simp if (cfe->num_memspace > 110752506Simp (sizeof(cfe->memspace) / 110852506Simp sizeof(cfe->memspace[0]))) { 110952506Simp DPRINTF(("too many mem " 111052506Simp "spaces %d", 111152506Simp cfe->num_memspace)); 111252506Simp state->card->error++; 111352506Simp break; 111452506Simp } 111552506Simp lengthsize = 111652506Simp ((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >> 111752506Simp PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT); 111852506Simp cardaddrsize = 111952506Simp ((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >> 112052506Simp PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT); 112152506Simp hostaddrsize = 112252506Simp (reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0; 112352506Simp 112452506Simp if (lengthsize == 0) { 112552506Simp DPRINTF(("cfe memspace " 112652506Simp "lengthsize == 0")); 112752506Simp state->card->error++; 112852506Simp } 112952506Simp for (i = 0; i < cfe->num_memspace; i++) { 113052506Simp if (lengthsize) { 113152506Simp cfe->memspace[i].length = 113252506Simp 256 * pccard_tuple_read_n(tuple, lengthsize, 113352506Simp idx); 113452506Simp idx += lengthsize; 113552506Simp } else { 113652506Simp cfe->memspace[i].length = 0; 113752506Simp } 113852506Simp if (cfe->memspace[i].length == 0) { 113952506Simp DPRINTF(("cfe->memspace[%d].length == 0", 114052506Simp i)); 114152506Simp state->card->error++; 114252506Simp } 114352506Simp if (cardaddrsize) { 114452506Simp cfe->memspace[i].cardaddr = 114552506Simp 256 * pccard_tuple_read_n(tuple, cardaddrsize, 114652506Simp idx); 114752506Simp idx += cardaddrsize; 114852506Simp } else { 114952506Simp cfe->memspace[i].cardaddr = 0; 115052506Simp } 115152506Simp if (hostaddrsize) { 115252506Simp cfe->memspace[i].hostaddr = 115352506Simp 256 * pccard_tuple_read_n(tuple, hostaddrsize, 115452506Simp idx); 115552506Simp idx += hostaddrsize; 115652506Simp } else { 115752506Simp cfe->memspace[i].hostaddr = 0; 115852506Simp } 115952506Simp } 116052506Simp } 116152506Simp } 116252506Simp if (misc) { 116352506Simp if (tuple->length <= idx) { 116452506Simp DPRINTF(("ran out of space before TCPE_MI\n")); 116552506Simp goto abort_cfe; 116652506Simp } 116752506Simp 116852506Simp reg = pccard_tuple_read_1(tuple, idx); 116952506Simp idx++; 117052506Simp 117152506Simp if (reg & PCCARD_TPCE_MI_PWRDOWN) 117252506Simp cfe->flags = PCCARD_CFE_POWERDOWN; 117352506Simp if (reg & PCCARD_TPCE_MI_READONLY) 117452506Simp cfe->flags = PCCARD_CFE_READONLY; 117552506Simp if (reg & PCCARD_TPCE_MI_AUDIO) 117652506Simp cfe->flags = PCCARD_CFE_AUDIO; 117752506Simp cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS; 117852506Simp 117952506Simp while (reg & PCCARD_TPCE_MI_EXT) { 118052506Simp reg = pccard_tuple_read_1(tuple, idx); 118152506Simp idx++; 118252506Simp } 118352506Simp } 118452506Simp /* skip all the subtuples */ 118552506Simp } 118652506Simp 118752506Simp abort_cfe: 118852506Simp DPRINTF(("CISTPL_CFTABLE_ENTRY\n")); 118952506Simp break; 119052506Simp default: 119152506Simp DPRINTF(("unhandled CISTPL %x\n", tuple->code)); 119252506Simp break; 119352506Simp } 119452506Simp 119552506Simp return (0); 119652506Simp} 119782781Sshiba 119882781Sshibastatic int 119982781Sshibadecode_funce(struct pccard_tuple *tuple, struct pccard_function *pf) 120082781Sshiba{ 120182781Sshiba int type = pccard_tuple_read_1(tuple, 0); 120282781Sshiba 120382781Sshiba switch (pf->function) { 120482781Sshiba case PCCARD_FUNCTION_DISK: 120582781Sshiba if (type == PCCARD_TPLFE_TYPE_DISK_DEVICE_INTERFACE) { 120682781Sshiba pf->pf_funce_disk_interface 120782781Sshiba = pccard_tuple_read_1(tuple, 1); 120882781Sshiba } 120982781Sshiba break; 121082781Sshiba case PCCARD_FUNCTION_NETWORK: 121182781Sshiba if (type == PCCARD_TPLFE_TYPE_LAN_NID) { 121282781Sshiba int i; 121382781Sshiba int len = pccard_tuple_read_1(tuple, 1); 121482781Sshiba if (tuple->length < 2 + len || len > 8) { 121582781Sshiba /* tuple length not enough or nid too long */ 121682781Sshiba break; 121782781Sshiba } 121882781Sshiba for (i = 0; i < len; i++) { 121982781Sshiba pf->pf_funce_lan_nid[i] 122082781Sshiba = pccard_tuple_read_1(tuple, i + 2); 122182781Sshiba } 122282781Sshiba pf->pf_funce_lan_nidlen = len; 122382781Sshiba } 122482781Sshiba break; 122582781Sshiba default: 122682781Sshiba break; 122782781Sshiba } 122882781Sshiba return 0; 122982781Sshiba} 1230