pccard_cis.c revision 147962
1104640Simp/* $NetBSD: pcmcia_cis.c,v 1.17 2000/02/10 09:01:52 chopps Exp $ */ 252506Simp/* $FreeBSD: head/sys/dev/pccard/pccard_cis.c 147962 2005-07-13 14:59:06Z imp $ */ 352506Simp 4139749Simp/*- 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> 48120868Simp#include <dev/pccard/pccard_cis.h> 4952506Simp 5059193Simp#include "card_if.h" 5159193Simp 5291786Simpextern int pccard_cis_debug; 5391786Simp 5459193Simp#define PCCARDCISDEBUG 5552506Simp#ifdef PCCARDCISDEBUG 56119161Simp#define DPRINTF(arg) do { if (pccard_cis_debug) printf arg; } while (0) 57119161Simp#define DEVPRINTF(arg) do { if (pccard_cis_debug) device_printf arg; } while (0) 5852506Simp#else 5952506Simp#define DPRINTF(arg) 6055720Simp#define DEVPRINTF(arg) 6152506Simp#endif 6252506Simp 63128169Simp#define PCCARD_CIS_SIZE 4096 6452506Simp 6552506Simpstruct cis_state { 6652506Simp int count; 6752506Simp int gotmfc; 6852506Simp struct pccard_config_entry temp_cfe; 6952506Simp struct pccard_config_entry *default_cfe; 7052506Simp struct pccard_card *card; 7152506Simp struct pccard_function *pf; 7252506Simp}; 7352506Simp 74147729Simpstatic int pccard_parse_cis_tuple(const struct pccard_tuple *, void *); 75147729Simpstatic int decode_funce(const struct pccard_tuple *, struct pccard_function *); 7652506Simp 7752506Simpvoid 7855720Simppccard_read_cis(struct pccard_softc *sc) 7952506Simp{ 8052506Simp struct cis_state state; 8152506Simp 82104640Simp bzero(&state, sizeof state); 8352506Simp state.card = &sc->card; 8452506Simp state.card->error = 0; 8552506Simp state.card->cis1_major = -1; 8652506Simp state.card->cis1_minor = -1; 8752506Simp state.card->cis1_info[0] = NULL; 8852506Simp state.card->cis1_info[1] = NULL; 8952506Simp state.card->cis1_info[2] = NULL; 9052506Simp state.card->cis1_info[3] = NULL; 9186272Simp state.card->manufacturer = PCMCIA_VENDOR_INVALID; 9286272Simp state.card->product = PCMCIA_PRODUCT_INVALID; 9352506Simp STAILQ_INIT(&state.card->pf_head); 9452506Simp state.pf = NULL; 9552506Simp 96128169Simp tsleep(&state, 0, "pccard", hz); 9758997Simp if (pccard_scan_cis(sc->dev, pccard_parse_cis_tuple, 9852506Simp &state) == -1) 9952506Simp state.card->error++; 10052506Simp} 10152506Simp 10252506Simpint 103147711Simppccard_scan_cis(device_t dev, pccard_scan_t fct, void *arg) 10452506Simp{ 10555720Simp struct resource *res; 10655720Simp int rid; 10752506Simp struct pccard_tuple tuple; 10852506Simp int longlink_present; 10952506Simp int longlink_common; 110112358Simp u_long longlink_addr; /* Type suspect */ 11152506Simp int mfc_count; 11252506Simp int mfc_index; 113119161Simp#ifdef PCCARDCISDEBUG 114119161Simp int cis_none_cnt = 10; /* Only report 10 CIS_NONEs */ 115119161Simp#endif 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 126128169Simp /* 127128169Simp * Some reports from the field suggest that a 64k memory boundary 128128169Simp * helps card CIS being able to be read. Try it here and see what 129128169Simp * the results actually are. I'm not sure I understand why this 130128169Simp * would make cards work better, but it is easy enough to test. 131128169Simp */ 13255720Simp rid = 0; 133128169Simp res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 134128169Simp PCCARD_CIS_SIZE, RF_ACTIVE | rman_make_alignment_flags(64*1024)); 13555720Simp if (res == NULL) { 13655720Simp device_printf(dev, "can't alloc memory to read attributes\n"); 13752506Simp return -1; 13852506Simp } 13959193Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, 14059193Simp rid, PCCARD_A_MEM_ATTR); 14155720Simp tuple.memt = rman_get_bustag(res); 14255720Simp tuple.memh = rman_get_bushandle(res); 14359389Simp tuple.ptr = 0; 14452506Simp 145119060Simp DPRINTF(("cis mem map 0x%x (resource: 0x%lx)\n", 146119060Simp (unsigned int) tuple.memh, rman_get_start(res))); 14755720Simp 14852506Simp tuple.mult = 2; 14952506Simp 15052506Simp longlink_present = 1; 15152506Simp longlink_common = 1; 15252506Simp longlink_addr = 0; 15352506Simp 15452506Simp mfc_count = 0; 15552506Simp mfc_index = 0; 15652506Simp 15755720Simp DEVPRINTF((dev, "CIS tuple chain:\n")); 15852506Simp 15952506Simp while (1) { 16052506Simp while (1) { 161119060Simp /* 162119060Simp * Perform boundary check for insane cards. 163119060Simp * If CIS is too long, simulate CIS end. 164119060Simp * (This check may not be sufficient for 165119060Simp * malicious cards.) 166119060Simp */ 167119060Simp if (tuple.mult * tuple.ptr >= PCCARD_CIS_SIZE - 1 168119060Simp - 32 /* ad hoc value */ ) { 169119060Simp printf("CIS is too long -- truncating\n"); 170120868Simp tuple.code = CISTPL_END; 171119060Simp } else { 172119060Simp /* get the tuple code */ 173119060Simp tuple.code = pccard_cis_read_1(&tuple, tuple.ptr); 174119060Simp } 17552506Simp 17652506Simp /* two special-case tuples */ 17752506Simp 178120868Simp if (tuple.code == CISTPL_NULL) { 179119161Simp#ifdef PCCARDCISDEBUG 180119161Simp if (cis_none_cnt > 0) 181119161Simp DPRINTF(("CISTPL_NONE\n 00\n")); 182119161Simp else if (cis_none_cnt == 0) 183119161Simp DPRINTF(("TOO MANY CIS_NONE\n")); 184119161Simp cis_none_cnt--; 185119161Simp#endif 18652506Simp tuple.ptr++; 18752506Simp continue; 188120868Simp } else if (tuple.code == CISTPL_END) { 18952506Simp DPRINTF(("CISTPL_END\n ff\n")); 19052506Simp /* Call the function for the END tuple, since 19152506Simp the CIS semantics depend on it */ 192147711Simp if ((*fct)(&tuple, arg)) { 19352506Simp ret = 1; 19452506Simp goto done; 19552506Simp } 19652506Simp tuple.ptr++; 19752506Simp break; 19852506Simp } 19952506Simp /* now all the normal tuples */ 20052506Simp 20152506Simp tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1); 20252506Simp switch (tuple.code) { 203120868Simp case CISTPL_LONGLINK_A: 204120868Simp case CISTPL_LONGLINK_C: 20552506Simp if (tuple.length < 4) { 20652506Simp DPRINTF(("CISTPL_LONGLINK_%s too " 20752506Simp "short %d\n", 20852506Simp longlink_common ? "C" : "A", 20952506Simp tuple.length)); 21052506Simp break; 21152506Simp } 21252506Simp longlink_present = 1; 21352506Simp longlink_common = (tuple.code == 214120868Simp CISTPL_LONGLINK_C) ? 1 : 0; 21552506Simp longlink_addr = pccard_tuple_read_4(&tuple, 0); 21652506Simp DPRINTF(("CISTPL_LONGLINK_%s %lx\n", 21752506Simp longlink_common ? "C" : "A", 21852506Simp longlink_addr)); 21952506Simp break; 220120868Simp case CISTPL_NO_LINK: 22152506Simp longlink_present = 0; 22252506Simp DPRINTF(("CISTPL_NO_LINK\n")); 22352506Simp break; 224120868Simp case CISTPL_CHECKSUM: 22552506Simp if (tuple.length < 5) { 22652506Simp DPRINTF(("CISTPL_CHECKSUM too " 22752506Simp "short %d\n", tuple.length)); 22852506Simp break; 22952506Simp } { 23052506Simp int16_t offset; 23152506Simp u_long addr, length; 23252506Simp u_int cksum, sum; 23352506Simp int i; 23452506Simp 23590896Simp offset = (uint16_t) 23652506Simp pccard_tuple_read_2(&tuple, 0); 23752506Simp length = pccard_tuple_read_2(&tuple, 2); 23852506Simp cksum = pccard_tuple_read_1(&tuple, 4); 23952506Simp 24052506Simp addr = tuple.ptr + offset; 24152506Simp 24252506Simp DPRINTF(("CISTPL_CHECKSUM addr=%lx " 24352506Simp "len=%lx cksum=%x", 24452506Simp addr, length, cksum)); 24552506Simp 24652506Simp /* 24752506Simp * XXX do more work to deal with 24852506Simp * distant regions 24952506Simp */ 25052506Simp if ((addr >= PCCARD_CIS_SIZE) || 25152506Simp ((addr + length) >= 252104640Simp PCCARD_CIS_SIZE)) { 25352506Simp DPRINTF((" skipped, " 25452506Simp "too distant\n")); 25552506Simp break; 25652506Simp } 25752506Simp sum = 0; 25852506Simp for (i = 0; i < length; i++) 25952506Simp sum += 26052506Simp bus_space_read_1(tuple.memt, 26152506Simp tuple.memh, 26252506Simp addr + tuple.mult * i); 26352506Simp if (cksum != (sum & 0xff)) { 26452506Simp DPRINTF((" failed sum=%x\n", 26552506Simp sum)); 26655720Simp device_printf(dev, 26755720Simp "CIS checksum failed\n"); 26852506Simp#if 0 26952506Simp /* 27052506Simp * XXX Some working cards have 27152506Simp * XXX bad checksums!! 27252506Simp */ 27352506Simp ret = -1; 27452506Simp#endif 27552506Simp } else { 27652506Simp DPRINTF((" ok\n")); 27752506Simp } 27852506Simp } 27952506Simp break; 280120868Simp case CISTPL_LONGLINK_MFC: 28152506Simp if (tuple.length < 1) { 28252506Simp DPRINTF(("CISTPL_LONGLINK_MFC too " 28352506Simp "short %d\n", tuple.length)); 28452506Simp break; 28552506Simp } 286104640Simp if (((tuple.length - 1) % 5) != 0) { 287104640Simp DPRINTF(("CISTPL_LONGLINK_MFC bogus " 288104640Simp "length %d\n", tuple.length)); 289104640Simp break; 290104640Simp } 29152506Simp /* 29252506Simp * this is kind of ad hoc, as I don't have 29352506Simp * any real documentation 29452506Simp */ 29552506Simp { 296104640Simp int i, tmp_count; 29752506Simp 298104640Simp /* 299104640Simp * put count into tmp var so that 300104640Simp * if we have to bail (because it's 301104640Simp * a bogus count) it won't be 302104640Simp * remembered for later use. 303104640Simp */ 304104640Simp tmp_count = 30552506Simp pccard_tuple_read_1(&tuple, 0); 306104640Simp 30752506Simp DPRINTF(("CISTPL_LONGLINK_MFC %d", 308104640Simp tmp_count)); 309104640Simp 310104640Simp /* 311104640Simp * make _sure_ it's the right size; 312104640Simp * if too short, it may be a weird 313104640Simp * (unknown/undefined) format 314104640Simp */ 315104640Simp if (tuple.length != (tmp_count*5 + 1)) { 316104640Simp DPRINTF((" bogus length %d\n", 317104640Simp tuple.length)); 318104640Simp break; 319104640Simp } 320104640Simp /* 321104640Simp * sanity check for a programming 322104640Simp * error which is difficult to find 323104640Simp * when debugging. 324104640Simp */ 325104640Simp if (tmp_count > 326104640Simp howmany(sizeof mfc, sizeof mfc[0])) 327104640Simp panic("CISTPL_LONGLINK_MFC mfc " 328104640Simp "count would blow stack"); 329104640Simp mfc_count = tmp_count; 33052506Simp for (i = 0; i < mfc_count; i++) { 33152506Simp mfc[i].common = 33252506Simp (pccard_tuple_read_1(&tuple, 33352506Simp 1 + 5 * i) == 33452506Simp PCCARD_MFC_MEM_COMMON) ? 33552506Simp 1 : 0; 33652506Simp mfc[i].addr = 33752506Simp pccard_tuple_read_4(&tuple, 33852506Simp 1 + 5 * i + 1); 33952506Simp DPRINTF((" %s:%lx", 34052506Simp mfc[i].common ? "common" : 34152506Simp "attr", mfc[i].addr)); 34252506Simp } 34352506Simp DPRINTF(("\n")); 34452506Simp } 34552506Simp /* 34652506Simp * for LONGLINK_MFC, fall through to the 34752506Simp * function. This tuple has structural and 34852506Simp * semantic content. 34952506Simp */ 35052506Simp default: 35152506Simp { 352147711Simp if ((*fct)(&tuple, arg)) { 35352506Simp ret = 1; 35452506Simp goto done; 35552506Simp } 35652506Simp } 35752506Simp break; 35852506Simp } /* switch */ 35952506Simp#ifdef PCCARDCISDEBUG 36052506Simp /* print the tuple */ 36152506Simp { 36252506Simp int i; 36352506Simp 36452506Simp DPRINTF((" %02x %02x", tuple.code, 36552506Simp tuple.length)); 36652506Simp 36752506Simp for (i = 0; i < tuple.length; i++) { 36852506Simp DPRINTF((" %02x", 36952506Simp pccard_tuple_read_1(&tuple, i))); 37052506Simp if ((i % 16) == 13) 37152506Simp DPRINTF(("\n")); 37252506Simp } 37387352Simp 37452506Simp if ((i % 16) != 14) 37552506Simp DPRINTF(("\n")); 37652506Simp } 37752506Simp#endif 37852506Simp /* skip to the next tuple */ 37952506Simp tuple.ptr += 2 + tuple.length; 38052506Simp } 38152506Simp 38252506Simp /* 38352506Simp * the chain is done. Clean up and move onto the next one, 38452506Simp * if any. The loop is here in the case that there is an MFC 38552506Simp * card with no longlink (which defaults to existing, == 0). 38652506Simp * In general, this means that if one pointer fails, it will 38752506Simp * try the next one, instead of just bailing. 38852506Simp */ 38952506Simp while (1) { 39052506Simp if (longlink_present) { 39187352Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, 39287352Simp SYS_RES_MEMORY, rid, longlink_common ? 39393370Simp PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR); 39452506Simp DPRINTF(("cis mem map %x\n", 39552506Simp (unsigned int) tuple.memh)); 39652506Simp tuple.mult = longlink_common ? 1 : 2; 39793370Simp tuple.ptr = longlink_addr; 39852506Simp longlink_present = 0; 39952506Simp longlink_common = 1; 40052506Simp longlink_addr = 0; 40152506Simp } else if (mfc_count && (mfc_index < mfc_count)) { 40287352Simp CARD_SET_RES_FLAGS(device_get_parent(dev), dev, 40387352Simp SYS_RES_MEMORY, rid, mfc[mfc_index].common 40493370Simp ? PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR); 40552506Simp DPRINTF(("cis mem map %x\n", 40652506Simp (unsigned int) tuple.memh)); 40752506Simp /* set parse state, and point at the next one */ 40852506Simp tuple.mult = mfc[mfc_index].common ? 1 : 2; 40993370Simp tuple.ptr = mfc[mfc_index].addr; 41052506Simp mfc_index++; 41152506Simp } else { 41252506Simp goto done; 41352506Simp } 41452506Simp 41552506Simp /* make sure that the link is valid */ 41652506Simp tuple.code = pccard_cis_read_1(&tuple, tuple.ptr); 417120868Simp if (tuple.code != CISTPL_LINKTARGET) { 41852506Simp DPRINTF(("CISTPL_LINKTARGET expected, " 41952506Simp "code %02x observed\n", tuple.code)); 42052506Simp continue; 42152506Simp } 42252506Simp tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1); 42352506Simp if (tuple.length < 3) { 42452506Simp DPRINTF(("CISTPL_LINKTARGET too short %d\n", 42552506Simp tuple.length)); 42652506Simp continue; 42752506Simp } 42852506Simp if ((pccard_tuple_read_1(&tuple, 0) != 'C') || 42952506Simp (pccard_tuple_read_1(&tuple, 1) != 'I') || 43052506Simp (pccard_tuple_read_1(&tuple, 2) != 'S')) { 43152506Simp DPRINTF(("CISTPL_LINKTARGET magic " 43252506Simp "%02x%02x%02x incorrect\n", 43352506Simp pccard_tuple_read_1(&tuple, 0), 43452506Simp pccard_tuple_read_1(&tuple, 1), 43552506Simp pccard_tuple_read_1(&tuple, 2))); 43652506Simp continue; 43752506Simp } 43852506Simp tuple.ptr += 2 + tuple.length; 43952506Simp break; 44052506Simp } 44152506Simp } 44252506Simp 44352506Simpdone: 44455720Simp bus_release_resource(dev, SYS_RES_MEMORY, rid, res); 44552506Simp 44652506Simp return (ret); 44752506Simp} 44852506Simp 44952506Simp/* XXX this is incredibly verbose. Not sure what trt is */ 45052506Simp 45152506Simpvoid 45252506Simppccard_print_cis(device_t dev) 45352506Simp{ 45464850Simp struct pccard_softc *sc = PCCARD_SOFTC(dev); 45552506Simp struct pccard_card *card = &sc->card; 45652506Simp struct pccard_function *pf; 45752506Simp struct pccard_config_entry *cfe; 45852506Simp int i; 45952506Simp 46052506Simp device_printf(dev, "CIS version "); 46152506Simp if (card->cis1_major == 4) { 46252506Simp if (card->cis1_minor == 0) 46352506Simp printf("PCCARD 1.0\n"); 46452506Simp else if (card->cis1_minor == 1) 46552506Simp printf("PCCARD 2.0 or 2.1\n"); 46652506Simp } else if (card->cis1_major >= 5) 46752506Simp printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor); 46852506Simp else 46952506Simp printf("unknown (major=%d, minor=%d)\n", 47052506Simp card->cis1_major, card->cis1_minor); 47152506Simp 47252506Simp device_printf(dev, "CIS info: "); 47352506Simp for (i = 0; i < 4; i++) { 47452506Simp if (card->cis1_info[i] == NULL) 47552506Simp break; 47652506Simp if (i) 47752506Simp printf(", "); 47852506Simp printf("%s", card->cis1_info[i]); 47952506Simp } 48052506Simp printf("\n"); 48152506Simp 48252506Simp device_printf(dev, "Manufacturer code 0x%x, product 0x%x\n", 48352506Simp card->manufacturer, card->product); 48452506Simp 48552506Simp STAILQ_FOREACH(pf, &card->pf_head, pf_list) { 48652506Simp device_printf(dev, "function %d: ", pf->number); 48752506Simp 48852506Simp switch (pf->function) { 48952506Simp case PCCARD_FUNCTION_UNSPEC: 49052506Simp printf("unspecified"); 49152506Simp break; 49252506Simp case PCCARD_FUNCTION_MULTIFUNCTION: 49352506Simp printf("multi-function"); 49452506Simp break; 49552506Simp case PCCARD_FUNCTION_MEMORY: 49652506Simp printf("memory"); 49752506Simp break; 49852506Simp case PCCARD_FUNCTION_SERIAL: 49952506Simp printf("serial port"); 50052506Simp break; 50152506Simp case PCCARD_FUNCTION_PARALLEL: 50252506Simp printf("parallel port"); 50352506Simp break; 50452506Simp case PCCARD_FUNCTION_DISK: 50552506Simp printf("fixed disk"); 50652506Simp break; 50752506Simp case PCCARD_FUNCTION_VIDEO: 50852506Simp printf("video adapter"); 50952506Simp break; 51052506Simp case PCCARD_FUNCTION_NETWORK: 51152506Simp printf("network adapter"); 51252506Simp break; 51352506Simp case PCCARD_FUNCTION_AIMS: 51452506Simp printf("auto incrementing mass storage"); 51552506Simp break; 51652506Simp case PCCARD_FUNCTION_SCSI: 51752506Simp printf("SCSI bridge"); 51852506Simp break; 51952506Simp case PCCARD_FUNCTION_SECURITY: 52052506Simp printf("Security services"); 52152506Simp break; 52252506Simp case PCCARD_FUNCTION_INSTRUMENT: 52352506Simp printf("Instrument"); 52452506Simp break; 52552506Simp default: 52652506Simp printf("unknown (%d)", pf->function); 52752506Simp break; 52852506Simp } 52952506Simp 530106914Smux printf(", ccr addr %x mask %x\n", pf->ccr_base, pf->ccr_mask); 53152506Simp 53252506Simp STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 53352506Simp device_printf(dev, "function %d, config table entry " 53452506Simp "%d: ", pf->number, cfe->number); 53552506Simp 53652506Simp switch (cfe->iftype) { 53752506Simp case PCCARD_IFTYPE_MEMORY: 53852506Simp printf("memory card"); 53952506Simp break; 54052506Simp case PCCARD_IFTYPE_IO: 54152506Simp printf("I/O card"); 54252506Simp break; 54352506Simp default: 54452506Simp printf("card type unknown"); 54552506Simp break; 54652506Simp } 54752506Simp 54852506Simp printf("; irq mask %x", cfe->irqmask); 54952506Simp 55052506Simp if (cfe->num_iospace) { 55152506Simp printf("; iomask %lx, iospace", cfe->iomask); 55252506Simp 55353813Simp for (i = 0; i < cfe->num_iospace; i++) { 55453813Simp printf(" %lx", cfe->iospace[i].start); 55553813Simp if (cfe->iospace[i].length) 55653813Simp printf("-%lx", 55753813Simp cfe->iospace[i].start + 55853813Simp cfe->iospace[i].length - 1); 55953813Simp } 56052506Simp } 56152506Simp if (cfe->num_memspace) { 56252506Simp printf("; memspace"); 56352506Simp 56453813Simp for (i = 0; i < cfe->num_memspace; i++) { 56553813Simp printf(" %lx", 56653813Simp cfe->memspace[i].cardaddr); 56753813Simp if (cfe->memspace[i].length) 56853813Simp printf("-%lx", 56953813Simp cfe->memspace[i].cardaddr + 57053813Simp cfe->memspace[i].length - 1); 57153813Simp if (cfe->memspace[i].hostaddr) 57253813Simp printf("@%lx", 57353813Simp cfe->memspace[i].hostaddr); 57453813Simp } 57552506Simp } 57652506Simp if (cfe->maxtwins) 57752506Simp printf("; maxtwins %d", cfe->maxtwins); 57852506Simp 57952506Simp printf(";"); 58052506Simp 58152506Simp if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED) 58252506Simp printf(" mwait_required"); 58352506Simp if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE) 58452506Simp printf(" rdybsy_active"); 58552506Simp if (cfe->flags & PCCARD_CFE_WP_ACTIVE) 58652506Simp printf(" wp_active"); 58752506Simp if (cfe->flags & PCCARD_CFE_BVD_ACTIVE) 58852506Simp printf(" bvd_active"); 58952506Simp if (cfe->flags & PCCARD_CFE_IO8) 59052506Simp printf(" io8"); 59152506Simp if (cfe->flags & PCCARD_CFE_IO16) 59252506Simp printf(" io16"); 59352506Simp if (cfe->flags & PCCARD_CFE_IRQSHARE) 59452506Simp printf(" irqshare"); 59552506Simp if (cfe->flags & PCCARD_CFE_IRQPULSE) 59652506Simp printf(" irqpulse"); 59752506Simp if (cfe->flags & PCCARD_CFE_IRQLEVEL) 59852506Simp printf(" irqlevel"); 59952506Simp if (cfe->flags & PCCARD_CFE_POWERDOWN) 60052506Simp printf(" powerdown"); 60152506Simp if (cfe->flags & PCCARD_CFE_READONLY) 60252506Simp printf(" readonly"); 60352506Simp if (cfe->flags & PCCARD_CFE_AUDIO) 60452506Simp printf(" audio"); 60552506Simp 60652506Simp printf("\n"); 60752506Simp } 60852506Simp } 60952506Simp 61052506Simp if (card->error) 61152506Simp device_printf(dev, "%d errors found while parsing CIS\n", 61252506Simp card->error); 61352506Simp} 61452506Simp 615147711Simpstatic int 616147729Simppccard_parse_cis_tuple(const struct pccard_tuple *tuple, void *arg) 61752506Simp{ 61852506Simp /* most of these are educated guesses */ 61952506Simp static struct pccard_config_entry init_cfe = { 62052506Simp -1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE | 62152506Simp PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY, 62252506Simp }; 62352506Simp 62452506Simp struct cis_state *state = arg; 62552506Simp 62652506Simp switch (tuple->code) { 627120868Simp case CISTPL_END: 62852506Simp /* if we've seen a LONGLINK_MFC, and this is the first 62952506Simp * END after it, reset the function list. 63052506Simp * 63152506Simp * XXX This might also be the right place to start a 63252506Simp * new function, but that assumes that a function 63352506Simp * definition never crosses any longlink, and I'm not 63452506Simp * sure about that. This is probably safe for MFC 63552506Simp * cards, but what we have now isn't broken, so I'd 63652506Simp * rather not change it. 63752506Simp */ 63852506Simp if (state->gotmfc == 1) { 63952506Simp struct pccard_function *pf, *pfnext; 64052506Simp 64152506Simp for (pf = STAILQ_FIRST(&state->card->pf_head); 64252506Simp pf != NULL; pf = pfnext) { 64352506Simp pfnext = STAILQ_NEXT(pf, pf_list); 64452506Simp free(pf, M_DEVBUF); 64552506Simp } 64652506Simp 64752506Simp STAILQ_INIT(&state->card->pf_head); 64852506Simp 64952506Simp state->count = 0; 65052506Simp state->gotmfc = 2; 65152506Simp state->pf = NULL; 65252506Simp } 65352506Simp break; 654120868Simp case CISTPL_LONGLINK_MFC: 65552506Simp /* 65652506Simp * this tuple's structure was dealt with in scan_cis. here, 65752506Simp * record the fact that the MFC tuple was seen, so that 65852506Simp * functions declared before the MFC link can be cleaned 65952506Simp * up. 66052506Simp */ 66152506Simp state->gotmfc = 1; 66252506Simp break; 66352506Simp#ifdef PCCARDCISDEBUG 664120868Simp case CISTPL_DEVICE: 665120868Simp case CISTPL_DEVICE_A: 66652506Simp { 66752506Simp u_int reg, dtype, dspeed; 66852506Simp 66952506Simp reg = pccard_tuple_read_1(tuple, 0); 67052506Simp dtype = reg & PCCARD_DTYPE_MASK; 67152506Simp dspeed = reg & PCCARD_DSPEED_MASK; 67252506Simp 67352506Simp DPRINTF(("CISTPL_DEVICE%s type=", 674120868Simp (tuple->code == CISTPL_DEVICE) ? "" : "_A")); 67552506Simp switch (dtype) { 67652506Simp case PCCARD_DTYPE_NULL: 67752506Simp DPRINTF(("null")); 67852506Simp break; 67952506Simp case PCCARD_DTYPE_ROM: 68052506Simp DPRINTF(("rom")); 68152506Simp break; 68252506Simp case PCCARD_DTYPE_OTPROM: 68352506Simp DPRINTF(("otprom")); 68452506Simp break; 68552506Simp case PCCARD_DTYPE_EPROM: 68652506Simp DPRINTF(("eprom")); 68752506Simp break; 68852506Simp case PCCARD_DTYPE_EEPROM: 68952506Simp DPRINTF(("eeprom")); 69052506Simp break; 69152506Simp case PCCARD_DTYPE_FLASH: 69252506Simp DPRINTF(("flash")); 69352506Simp break; 69452506Simp case PCCARD_DTYPE_SRAM: 69552506Simp DPRINTF(("sram")); 69652506Simp break; 69752506Simp case PCCARD_DTYPE_DRAM: 69852506Simp DPRINTF(("dram")); 69952506Simp break; 70052506Simp case PCCARD_DTYPE_FUNCSPEC: 70152506Simp DPRINTF(("funcspec")); 70252506Simp break; 70352506Simp case PCCARD_DTYPE_EXTEND: 70452506Simp DPRINTF(("extend")); 70552506Simp break; 70652506Simp default: 70752506Simp DPRINTF(("reserved")); 70852506Simp break; 70952506Simp } 71052506Simp DPRINTF((" speed=")); 71152506Simp switch (dspeed) { 71252506Simp case PCCARD_DSPEED_NULL: 71352506Simp DPRINTF(("null")); 71452506Simp break; 71552506Simp case PCCARD_DSPEED_250NS: 71652506Simp DPRINTF(("250ns")); 71752506Simp break; 71852506Simp case PCCARD_DSPEED_200NS: 71952506Simp DPRINTF(("200ns")); 72052506Simp break; 72152506Simp case PCCARD_DSPEED_150NS: 72252506Simp DPRINTF(("150ns")); 72352506Simp break; 72452506Simp case PCCARD_DSPEED_100NS: 72552506Simp DPRINTF(("100ns")); 72652506Simp break; 72752506Simp case PCCARD_DSPEED_EXT: 72852506Simp DPRINTF(("ext")); 72952506Simp break; 73052506Simp default: 73152506Simp DPRINTF(("reserved")); 73252506Simp break; 73352506Simp } 73452506Simp } 73552506Simp DPRINTF(("\n")); 73652506Simp break; 73752506Simp#endif 738120868Simp case CISTPL_VERS_1: 73952506Simp if (tuple->length < 6) { 74052506Simp DPRINTF(("CISTPL_VERS_1 too short %d\n", 74152506Simp tuple->length)); 74252506Simp break; 74352506Simp } { 74452506Simp int start, i, ch, count; 74552506Simp 74652506Simp state->card->cis1_major = pccard_tuple_read_1(tuple, 0); 74752506Simp state->card->cis1_minor = pccard_tuple_read_1(tuple, 1); 74852506Simp 74952506Simp for (count = 0, start = 0, i = 0; 75052506Simp (count < 4) && ((i + 4) < 256); i++) { 75152506Simp ch = pccard_tuple_read_1(tuple, 2 + i); 75252506Simp if (ch == 0xff) 75352506Simp break; 75452506Simp state->card->cis1_info_buf[i] = ch; 75552506Simp if (ch == 0) { 75652506Simp state->card->cis1_info[count] = 75752506Simp state->card->cis1_info_buf + start; 75852506Simp start = i + 1; 75952506Simp count++; 76052506Simp } 76152506Simp } 76252506Simp DPRINTF(("CISTPL_VERS_1\n")); 76352506Simp } 76452506Simp break; 765120868Simp case CISTPL_MANFID: 76652506Simp if (tuple->length < 4) { 76752506Simp DPRINTF(("CISTPL_MANFID too short %d\n", 76852506Simp tuple->length)); 76952506Simp break; 77052506Simp } 77152506Simp state->card->manufacturer = pccard_tuple_read_2(tuple, 0); 77252506Simp state->card->product = pccard_tuple_read_2(tuple, 2); 77390964Sshiba /* 774104604Simp * This is for xe driver. But not limited to that driver. 77590964Sshiba * In PC Card Standard, 77690964Sshiba * Manufacturer ID: 2byte. 777104604Simp * Product ID: typically 2bytes, but there's no limit on its 778104604Simp * size. prodext is a two byte field, so maybe we should 779104604Simp * also handle the '6' case. So far no cards have surfaced 780104604Simp * with a length of '6'. 78190964Sshiba */ 782147962Simp if (tuple->length == 5 ) 78390964Sshiba state->card->prodext = pccard_tuple_read_1(tuple, 4); 78452506Simp DPRINTF(("CISTPL_MANFID\n")); 78552506Simp break; 786120868Simp case CISTPL_FUNCID: 78752506Simp if (tuple->length < 1) { 78852506Simp DPRINTF(("CISTPL_FUNCID too short %d\n", 78952506Simp tuple->length)); 79052506Simp break; 79152506Simp } 79252506Simp if ((state->pf == NULL) || (state->gotmfc == 2)) { 79352506Simp state->pf = malloc(sizeof(*state->pf), M_DEVBUF, 79467897Sdwmalone M_NOWAIT | M_ZERO); 79552506Simp state->pf->number = state->count++; 79652506Simp state->pf->last_config_index = -1; 79752506Simp STAILQ_INIT(&state->pf->cfe_head); 79852506Simp 79952506Simp STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf, 80052506Simp pf_list); 80152506Simp } 80252506Simp state->pf->function = pccard_tuple_read_1(tuple, 0); 80352506Simp 80452506Simp DPRINTF(("CISTPL_FUNCID\n")); 80552506Simp break; 806120868Simp case CISTPL_FUNCE: 80782781Sshiba if (state->pf == NULL || state->pf->function <= 0) { 80882781Sshiba DPRINTF(("CISTPL_FUNCE is not followed by " 80982781Sshiba "valid CISTPL_FUNCID\n")); 81082781Sshiba break; 81182781Sshiba } 812147729Simp if (tuple->length >= 2) 81382781Sshiba decode_funce(tuple, state->pf); 81482781Sshiba DPRINTF(("CISTPL_FUNCE\n")); 81582781Sshiba break; 816120868Simp case CISTPL_CONFIG: 81752506Simp if (tuple->length < 3) { 81852506Simp DPRINTF(("CISTPL_CONFIG too short %d\n", 81952506Simp tuple->length)); 82052506Simp break; 82152506Simp } { 82252506Simp u_int reg, rasz, rmsz, rfsz; 82352506Simp int i; 82452506Simp 82552506Simp reg = pccard_tuple_read_1(tuple, 0); 82652506Simp rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >> 82752506Simp PCCARD_TPCC_RASZ_SHIFT); 82852506Simp rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >> 82952506Simp PCCARD_TPCC_RMSZ_SHIFT); 83052506Simp rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >> 83152506Simp PCCARD_TPCC_RFSZ_SHIFT); 83252506Simp 83352506Simp if (tuple->length < (rasz + rmsz + rfsz)) { 83452506Simp DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too " 83552506Simp "short %d\n", rasz, rmsz, rfsz, 83652506Simp tuple->length)); 83752506Simp break; 83852506Simp } 83952506Simp if (state->pf == NULL) { 84052506Simp state->pf = malloc(sizeof(*state->pf), 84167897Sdwmalone M_DEVBUF, M_NOWAIT | M_ZERO); 84252506Simp state->pf->number = state->count++; 84352506Simp state->pf->last_config_index = -1; 84452506Simp STAILQ_INIT(&state->pf->cfe_head); 84552506Simp 84652506Simp STAILQ_INSERT_TAIL(&state->card->pf_head, 84752506Simp state->pf, pf_list); 84852506Simp 84952506Simp state->pf->function = PCCARD_FUNCTION_UNSPEC; 85052506Simp } 85152506Simp state->pf->last_config_index = 85252506Simp pccard_tuple_read_1(tuple, 1); 85352506Simp 85452506Simp state->pf->ccr_base = 0; 85552506Simp for (i = 0; i < rasz; i++) 85652506Simp state->pf->ccr_base |= 85752506Simp ((pccard_tuple_read_1(tuple, 2 + i)) << 85852506Simp (i * 8)); 85952506Simp 86052506Simp state->pf->ccr_mask = 0; 86152506Simp for (i = 0; i < rmsz; i++) 86252506Simp state->pf->ccr_mask |= 86352506Simp ((pccard_tuple_read_1(tuple, 86452506Simp 2 + rasz + i)) << (i * 8)); 86552506Simp 86652506Simp /* skip the reserved area and subtuples */ 86752506Simp 86852506Simp /* reset the default cfe for each cfe list */ 86952506Simp state->temp_cfe = init_cfe; 87052506Simp state->default_cfe = &state->temp_cfe; 87152506Simp } 87252506Simp DPRINTF(("CISTPL_CONFIG\n")); 87352506Simp break; 874120868Simp case CISTPL_CFTABLE_ENTRY: 87552506Simp { 87652506Simp int idx, i, j; 87752506Simp u_int reg, reg2; 87852506Simp u_int intface, def, num; 87952506Simp u_int power, timing, iospace, irq, memspace, misc; 88052506Simp struct pccard_config_entry *cfe; 88152506Simp 88252506Simp idx = 0; 88352506Simp 88452506Simp reg = pccard_tuple_read_1(tuple, idx); 88552506Simp idx++; 88652506Simp intface = reg & PCCARD_TPCE_INDX_INTFACE; 88752506Simp def = reg & PCCARD_TPCE_INDX_DEFAULT; 88852506Simp num = reg & PCCARD_TPCE_INDX_NUM_MASK; 88952506Simp 89052506Simp /* 89152506Simp * this is a little messy. Some cards have only a 89252506Simp * cfentry with the default bit set. So, as we go 89352506Simp * through the list, we add new indexes to the queue, 89452506Simp * and keep a pointer to the last one with the 89552506Simp * default bit set. if we see a record with the same 89652506Simp * index, as the default, we stash the default and 89752506Simp * replace the queue entry. otherwise, we just add 89852506Simp * new entries to the queue, pointing the default ptr 89952506Simp * at them if the default bit is set. if we get to 90052506Simp * the end with the default pointer pointing at a 90152506Simp * record which hasn't had a matching index, that's 90252506Simp * ok; it just becomes a cfentry like any other. 90352506Simp */ 90452506Simp 90552506Simp /* 90652506Simp * if the index in the cis differs from the default 90752506Simp * cis, create new entry in the queue and start it 90852506Simp * with the current default 90952506Simp */ 91052506Simp if (num != state->default_cfe->number) { 91152506Simp cfe = (struct pccard_config_entry *) 91252506Simp malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 913144159Ssam if (cfe == NULL) { 914144159Ssam DPRINTF(("no memory for config entry\n")); 915144159Ssam goto abort_cfe; 916144159Ssam } 91752506Simp *cfe = *state->default_cfe; 91852506Simp 91952506Simp STAILQ_INSERT_TAIL(&state->pf->cfe_head, 92052506Simp cfe, cfe_list); 92152506Simp 92252506Simp cfe->number = num; 92352506Simp 92452506Simp /* 92552506Simp * if the default bit is set in the cis, then 92652506Simp * point the new default at whatever is being 92752506Simp * filled in 92852506Simp */ 92952506Simp if (def) 93052506Simp state->default_cfe = cfe; 93152506Simp } else { 93252506Simp /* 93352506Simp * the cis index matches the default index, 93452506Simp * fill in the default cfentry. It is 93552506Simp * assumed that the cfdefault index is in the 93652506Simp * queue. For it to be otherwise, the cis 93752506Simp * index would have to be -1 (initial 93852506Simp * condition) which is not possible, or there 93952506Simp * would have to be a preceding cis entry 94052506Simp * which had the same cis index and had the 94152506Simp * default bit unset. Neither condition 94252506Simp * should happen. If it does, this cfentry 94352506Simp * is lost (written into temp space), which 94452506Simp * is an acceptable failure mode. 94552506Simp */ 94652506Simp 94752506Simp cfe = state->default_cfe; 94852506Simp 94952506Simp /* 95052506Simp * if the cis entry does not have the default 95152506Simp * bit set, copy the default out of the way 95252506Simp * first. 95352506Simp */ 95452506Simp if (!def) { 95552506Simp state->temp_cfe = *state->default_cfe; 95652506Simp state->default_cfe = &state->temp_cfe; 95752506Simp } 95852506Simp } 95952506Simp 96052506Simp if (intface) { 96152506Simp reg = pccard_tuple_read_1(tuple, idx); 96252506Simp idx++; 963104640Simp cfe->flags &= ~(PCCARD_CFE_MWAIT_REQUIRED 964104640Simp | PCCARD_CFE_RDYBSY_ACTIVE 965104640Simp | PCCARD_CFE_WP_ACTIVE 966104640Simp | PCCARD_CFE_BVD_ACTIVE); 96752506Simp if (reg & PCCARD_TPCE_IF_MWAIT) 96852506Simp cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED; 96952506Simp if (reg & PCCARD_TPCE_IF_RDYBSY) 97052506Simp cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE; 97152506Simp if (reg & PCCARD_TPCE_IF_WP) 97252506Simp cfe->flags |= PCCARD_CFE_WP_ACTIVE; 97352506Simp if (reg & PCCARD_TPCE_IF_BVD) 97452506Simp cfe->flags |= PCCARD_CFE_BVD_ACTIVE; 97552506Simp cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE; 97652506Simp } 97752506Simp reg = pccard_tuple_read_1(tuple, idx); 97852506Simp idx++; 97952506Simp 98052506Simp power = reg & PCCARD_TPCE_FS_POWER_MASK; 98152506Simp timing = reg & PCCARD_TPCE_FS_TIMING; 98252506Simp iospace = reg & PCCARD_TPCE_FS_IOSPACE; 98352506Simp irq = reg & PCCARD_TPCE_FS_IRQ; 98452506Simp memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK; 98552506Simp misc = reg & PCCARD_TPCE_FS_MISC; 98652506Simp 98752506Simp if (power) { 98852506Simp /* skip over power, don't save */ 98952506Simp /* for each parameter selection byte */ 99052506Simp for (i = 0; i < power; i++) { 99152506Simp reg = pccard_tuple_read_1(tuple, idx); 99252506Simp idx++; 99352506Simp /* for each bit */ 99452506Simp for (j = 0; j < 7; j++) { 99552506Simp /* if the bit is set */ 99652506Simp if ((reg >> j) & 0x01) { 99752506Simp /* skip over bytes */ 99852506Simp do { 99952506Simp reg2 = pccard_tuple_read_1(tuple, idx); 100052506Simp idx++; 100152506Simp /* 100252506Simp * until 100352506Simp * non-extensi 100452506Simp * on byte 100552506Simp */ 100652506Simp } while (reg2 & 0x80); 100752506Simp } 100852506Simp } 100952506Simp } 101052506Simp } 101152506Simp if (timing) { 101252506Simp /* skip over timing, don't save */ 101352506Simp reg = pccard_tuple_read_1(tuple, idx); 101452506Simp idx++; 101552506Simp 101652506Simp if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) != 101752506Simp PCCARD_TPCE_TD_RESERVED_MASK) 101852506Simp idx++; 101952506Simp if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) != 102052506Simp PCCARD_TPCE_TD_RDYBSY_MASK) 102152506Simp idx++; 102252506Simp if ((reg & PCCARD_TPCE_TD_WAIT_MASK) != 102352506Simp PCCARD_TPCE_TD_WAIT_MASK) 102452506Simp idx++; 102552506Simp } 102652506Simp if (iospace) { 102752506Simp if (tuple->length <= idx) { 102852506Simp DPRINTF(("ran out of space before TCPE_IO\n")); 102952506Simp goto abort_cfe; 103052506Simp } 103152506Simp 103252506Simp reg = pccard_tuple_read_1(tuple, idx); 103352506Simp idx++; 1034104640Simp cfe->flags &= 1035104640Simp ~(PCCARD_CFE_IO8 | PCCARD_CFE_IO16); 103652506Simp if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT) 103752506Simp cfe->flags |= PCCARD_CFE_IO8; 103852506Simp if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT) 103952506Simp cfe->flags |= PCCARD_CFE_IO16; 104052506Simp cfe->iomask = 104152506Simp reg & PCCARD_TPCE_IO_IOADDRLINES_MASK; 104252506Simp 104352506Simp if (reg & PCCARD_TPCE_IO_HASRANGE) { 104452506Simp reg = pccard_tuple_read_1(tuple, idx); 104552506Simp idx++; 104652506Simp 104752506Simp cfe->num_iospace = 1 + (reg & 104852506Simp PCCARD_TPCE_IO_RANGE_COUNT); 104952506Simp 105052506Simp if (cfe->num_iospace > 105152506Simp (sizeof(cfe->iospace) / 105252506Simp sizeof(cfe->iospace[0]))) { 105352506Simp DPRINTF(("too many io " 105452506Simp "spaces %d", 105552506Simp cfe->num_iospace)); 105652506Simp state->card->error++; 105752506Simp break; 105852506Simp } 105952506Simp for (i = 0; i < cfe->num_iospace; i++) { 106052506Simp switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) { 106152506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE: 106252506Simp cfe->iospace[i].start = 106352506Simp pccard_tuple_read_1(tuple, idx); 106452506Simp idx++; 106552506Simp break; 106652506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO: 106752506Simp cfe->iospace[i].start = 106852506Simp pccard_tuple_read_2(tuple, idx); 106952506Simp idx += 2; 107052506Simp break; 107152506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR: 107252506Simp cfe->iospace[i].start = 107352506Simp pccard_tuple_read_4(tuple, idx); 107452506Simp idx += 4; 107552506Simp break; 107652506Simp } 107752506Simp switch (reg & 107852506Simp PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) { 107952506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE: 108052506Simp cfe->iospace[i].length = 108152506Simp pccard_tuple_read_1(tuple, idx); 108252506Simp idx++; 108352506Simp break; 108452506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO: 108552506Simp cfe->iospace[i].length = 108652506Simp pccard_tuple_read_2(tuple, idx); 108752506Simp idx += 2; 108852506Simp break; 108952506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR: 109052506Simp cfe->iospace[i].length = 109152506Simp pccard_tuple_read_4(tuple, idx); 109252506Simp idx += 4; 109352506Simp break; 109452506Simp } 109552506Simp cfe->iospace[i].length++; 109652506Simp } 109752506Simp } else { 109852506Simp cfe->num_iospace = 1; 109952506Simp cfe->iospace[0].start = 0; 110052506Simp cfe->iospace[0].length = 110152506Simp (1 << cfe->iomask); 110252506Simp } 110352506Simp } 110452506Simp if (irq) { 110552506Simp if (tuple->length <= idx) { 110652506Simp DPRINTF(("ran out of space before TCPE_IR\n")); 110752506Simp goto abort_cfe; 110852506Simp } 110952506Simp 111052506Simp reg = pccard_tuple_read_1(tuple, idx); 111152506Simp idx++; 1112104640Simp cfe->flags &= ~(PCCARD_CFE_IRQSHARE 1113104640Simp | PCCARD_CFE_IRQPULSE 1114104640Simp | PCCARD_CFE_IRQLEVEL); 111552506Simp if (reg & PCCARD_TPCE_IR_SHARE) 111652506Simp cfe->flags |= PCCARD_CFE_IRQSHARE; 111752506Simp if (reg & PCCARD_TPCE_IR_PULSE) 111852506Simp cfe->flags |= PCCARD_CFE_IRQPULSE; 111952506Simp if (reg & PCCARD_TPCE_IR_LEVEL) 112052506Simp cfe->flags |= PCCARD_CFE_IRQLEVEL; 112152506Simp 112252506Simp if (reg & PCCARD_TPCE_IR_HASMASK) { 112352506Simp /* 112452506Simp * it's legal to ignore the 112552506Simp * special-interrupt bits, so I will 112652506Simp */ 112752506Simp 112852506Simp cfe->irqmask = 112952506Simp pccard_tuple_read_2(tuple, idx); 113052506Simp idx += 2; 113152506Simp } else { 113252506Simp cfe->irqmask = 113352506Simp (1 << (reg & PCCARD_TPCE_IR_IRQ)); 113452506Simp } 113552506Simp } 113652506Simp if (memspace) { 113752506Simp if (tuple->length <= idx) { 113852506Simp DPRINTF(("ran out of space before TCPE_MS\n")); 113952506Simp goto abort_cfe; 114052506Simp } 114152506Simp 1142142027Simp if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) { 114352506Simp cfe->num_memspace = 1; 114452506Simp cfe->memspace[0].length = 256 * 114552506Simp pccard_tuple_read_2(tuple, idx); 114652506Simp idx += 2; 114752506Simp cfe->memspace[0].cardaddr = 0; 114852506Simp cfe->memspace[0].hostaddr = 0; 114952506Simp } else if (memspace == 115052506Simp PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) { 115152506Simp cfe->num_memspace = 1; 115252506Simp cfe->memspace[0].length = 256 * 115352506Simp pccard_tuple_read_2(tuple, idx); 115452506Simp idx += 2; 115552506Simp cfe->memspace[0].cardaddr = 256 * 115652506Simp pccard_tuple_read_2(tuple, idx); 115752506Simp idx += 2; 115852506Simp cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr; 115952506Simp } else { 116052506Simp int lengthsize; 116152506Simp int cardaddrsize; 116252506Simp int hostaddrsize; 116352506Simp 116452506Simp reg = pccard_tuple_read_1(tuple, idx); 116552506Simp idx++; 116652506Simp 116753873Simp cfe->num_memspace = (reg & 116853873Simp PCCARD_TPCE_MS_COUNT) + 1; 116952506Simp 117052506Simp if (cfe->num_memspace > 117152506Simp (sizeof(cfe->memspace) / 117252506Simp sizeof(cfe->memspace[0]))) { 117352506Simp DPRINTF(("too many mem " 117452506Simp "spaces %d", 117552506Simp cfe->num_memspace)); 117652506Simp state->card->error++; 117752506Simp break; 117852506Simp } 117952506Simp lengthsize = 118052506Simp ((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >> 118152506Simp PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT); 118252506Simp cardaddrsize = 118352506Simp ((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >> 118452506Simp PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT); 118552506Simp hostaddrsize = 118652506Simp (reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0; 118752506Simp 118852506Simp if (lengthsize == 0) { 118952506Simp DPRINTF(("cfe memspace " 119052506Simp "lengthsize == 0")); 119152506Simp state->card->error++; 119252506Simp } 119352506Simp for (i = 0; i < cfe->num_memspace; i++) { 119452506Simp if (lengthsize) { 119552506Simp cfe->memspace[i].length = 119652506Simp 256 * pccard_tuple_read_n(tuple, lengthsize, 119752506Simp idx); 119852506Simp idx += lengthsize; 119952506Simp } else { 120052506Simp cfe->memspace[i].length = 0; 120152506Simp } 120252506Simp if (cfe->memspace[i].length == 0) { 120352506Simp DPRINTF(("cfe->memspace[%d].length == 0", 120452506Simp i)); 120552506Simp state->card->error++; 120652506Simp } 120752506Simp if (cardaddrsize) { 120852506Simp cfe->memspace[i].cardaddr = 120952506Simp 256 * pccard_tuple_read_n(tuple, cardaddrsize, 121052506Simp idx); 121152506Simp idx += cardaddrsize; 121252506Simp } else { 121352506Simp cfe->memspace[i].cardaddr = 0; 121452506Simp } 121552506Simp if (hostaddrsize) { 121652506Simp cfe->memspace[i].hostaddr = 121752506Simp 256 * pccard_tuple_read_n(tuple, hostaddrsize, 121852506Simp idx); 121952506Simp idx += hostaddrsize; 122052506Simp } else { 122152506Simp cfe->memspace[i].hostaddr = 0; 122252506Simp } 122352506Simp } 122452506Simp } 1225142027Simp } else 1226142027Simp cfe->num_memspace = 0; 122752506Simp if (misc) { 122852506Simp if (tuple->length <= idx) { 122952506Simp DPRINTF(("ran out of space before TCPE_MI\n")); 123052506Simp goto abort_cfe; 123152506Simp } 123252506Simp 123352506Simp reg = pccard_tuple_read_1(tuple, idx); 123452506Simp idx++; 1235104640Simp cfe->flags &= ~(PCCARD_CFE_POWERDOWN 1236104640Simp | PCCARD_CFE_READONLY 1237104640Simp | PCCARD_CFE_AUDIO); 123852506Simp if (reg & PCCARD_TPCE_MI_PWRDOWN) 1239104640Simp cfe->flags |= PCCARD_CFE_POWERDOWN; 124052506Simp if (reg & PCCARD_TPCE_MI_READONLY) 1241104640Simp cfe->flags |= PCCARD_CFE_READONLY; 124252506Simp if (reg & PCCARD_TPCE_MI_AUDIO) 1243104640Simp cfe->flags |= PCCARD_CFE_AUDIO; 124452506Simp cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS; 124552506Simp 124652506Simp while (reg & PCCARD_TPCE_MI_EXT) { 124752506Simp reg = pccard_tuple_read_1(tuple, idx); 124852506Simp idx++; 124952506Simp } 125052506Simp } 125152506Simp /* skip all the subtuples */ 125252506Simp } 125352506Simp 125452506Simp abort_cfe: 125552506Simp DPRINTF(("CISTPL_CFTABLE_ENTRY\n")); 125652506Simp break; 125752506Simp default: 125852506Simp DPRINTF(("unhandled CISTPL %x\n", tuple->code)); 125952506Simp break; 126052506Simp } 126152506Simp 126252506Simp return (0); 126352506Simp} 126482781Sshiba 126582781Sshibastatic int 1266147729Simpdecode_funce(const struct pccard_tuple *tuple, struct pccard_function *pf) 126782781Sshiba{ 1268140542Simp int i; 1269140542Simp int len; 127082781Sshiba int type = pccard_tuple_read_1(tuple, 0); 127182781Sshiba 127282781Sshiba switch (pf->function) { 127382781Sshiba case PCCARD_FUNCTION_DISK: 127482781Sshiba if (type == PCCARD_TPLFE_TYPE_DISK_DEVICE_INTERFACE) { 127582781Sshiba pf->pf_funce_disk_interface 127682781Sshiba = pccard_tuple_read_1(tuple, 1); 127782781Sshiba } 127882781Sshiba break; 127982781Sshiba case PCCARD_FUNCTION_NETWORK: 128082781Sshiba if (type == PCCARD_TPLFE_TYPE_LAN_NID) { 1281140542Simp len = pccard_tuple_read_1(tuple, 1); 128282781Sshiba if (tuple->length < 2 + len || len > 8) { 128382781Sshiba /* tuple length not enough or nid too long */ 128482781Sshiba break; 128582781Sshiba } 128682781Sshiba for (i = 0; i < len; i++) { 128782781Sshiba pf->pf_funce_lan_nid[i] 128882781Sshiba = pccard_tuple_read_1(tuple, i + 2); 128982781Sshiba } 129082781Sshiba pf->pf_funce_lan_nidlen = len; 129182781Sshiba } 129282781Sshiba break; 129382781Sshiba default: 129482781Sshiba break; 129582781Sshiba } 129682781Sshiba return 0; 129782781Sshiba} 1298