pccard_cis.c revision 58997
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 58997 2000-04-04 04:12:43Z 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/pccardchip.h> 4852506Simp#include <dev/pccard/pccardvar.h> 4952506Simp 5052506Simp#ifdef PCCARDCISDEBUG 5152506Simpint pccardcis_debug = 0; 5252506Simp#define DPRINTF(arg) if (pccardcis_debug) printf arg 5355720Simp#define DEVPRINTF(arg) if (pccardcis_debug) device_printf arg 5452506Simp#else 5552506Simp#define DPRINTF(arg) 5655720Simp#define DEVPRINTF(arg) 5752506Simp#endif 5852506Simp 5952506Simp#define PCCARD_CIS_SIZE 1024 6052506Simp 6152506Simpstruct cis_state { 6252506Simp int count; 6352506Simp int gotmfc; 6452506Simp struct pccard_config_entry temp_cfe; 6552506Simp struct pccard_config_entry *default_cfe; 6652506Simp struct pccard_card *card; 6752506Simp struct pccard_function *pf; 6852506Simp}; 6952506Simp 7054250Simpint pccard_parse_cis_tuple(struct pccard_tuple *, void *); 7152506Simp 7252506Simpvoid 7355720Simppccard_read_cis(struct pccard_softc *sc) 7452506Simp{ 7552506Simp struct cis_state state; 7652506Simp 7752506Simp state.count = 0; 7852506Simp state.gotmfc = 0; 7952506Simp 8052506Simp state.card = &sc->card; 8152506Simp 8252506Simp state.card->error = 0; 8352506Simp state.card->cis1_major = -1; 8452506Simp state.card->cis1_minor = -1; 8552506Simp state.card->cis1_info[0] = NULL; 8652506Simp state.card->cis1_info[1] = NULL; 8752506Simp state.card->cis1_info[2] = NULL; 8852506Simp state.card->cis1_info[3] = NULL; 8952506Simp state.card->manufacturer = PCCARD_VENDOR_INVALID; 9052506Simp state.card->product = PCCARD_PRODUCT_INVALID; 9152506Simp STAILQ_INIT(&state.card->pf_head); 9252506Simp 9352506Simp state.pf = NULL; 9452506Simp 9558997Simp if (pccard_scan_cis(sc->dev, pccard_parse_cis_tuple, 9652506Simp &state) == -1) 9752506Simp state.card->error++; 9852506Simp} 9952506Simp 10052506Simpint 10155720Simppccard_scan_cis(device_t dev, int (*fct)(struct pccard_tuple *, void *), 10255720Simp void *arg) 10352506Simp{ 10455720Simp struct resource *res; 10555720Simp int rid; 10652506Simp struct pccard_tuple tuple; 10752506Simp int longlink_present; 10852506Simp int longlink_common; 10952506Simp u_long longlink_addr; 11052506Simp int mfc_count; 11152506Simp int mfc_index; 11252506Simp struct { 11352506Simp int common; 11452506Simp u_long addr; 11552506Simp } mfc[256 / 5]; 11652506Simp int ret; 11752506Simp 11852506Simp ret = 0; 11952506Simp 12052506Simp /* allocate some memory */ 12152506Simp 12255720Simp rid = 0; 12355720Simp res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 12458581Simp PCCARD_CIS_SIZE, RF_ACTIVE /* | RF_PCCARD_ATTR */); 12555720Simp if (res == NULL) { 12652506Simp#ifdef DIAGNOSTIC 12755720Simp device_printf(dev, "can't alloc memory to read attributes\n"); 12852506Simp#endif 12952506Simp return -1; 13052506Simp } 13155720Simp tuple.memt = rman_get_bustag(res); 13255720Simp tuple.memh = rman_get_bushandle(res); 13352506Simp 13452506Simp DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh)); 13555720Simp 13652506Simp tuple.mult = 2; 13752506Simp 13852506Simp longlink_present = 1; 13952506Simp longlink_common = 1; 14052506Simp longlink_addr = 0; 14152506Simp 14252506Simp mfc_count = 0; 14352506Simp mfc_index = 0; 14452506Simp 14555720Simp DEVPRINTF((dev, "CIS tuple chain:\n")); 14652506Simp 14752506Simp while (1) { 14852506Simp while (1) { 14952506Simp /* get the tuple code */ 15052506Simp 15152506Simp tuple.code = pccard_cis_read_1(&tuple, tuple.ptr); 15252506Simp 15352506Simp /* two special-case tuples */ 15452506Simp 15552506Simp if (tuple.code == PCCARD_CISTPL_NULL) { 15652506Simp DPRINTF(("CISTPL_NONE\n 00\n")); 15752506Simp tuple.ptr++; 15852506Simp continue; 15952506Simp } else if (tuple.code == PCCARD_CISTPL_END) { 16052506Simp DPRINTF(("CISTPL_END\n ff\n")); 16152506Simp /* Call the function for the END tuple, since 16252506Simp the CIS semantics depend on it */ 16352506Simp if ((*fct) (&tuple, arg)) { 16452506Simp ret = 1; 16552506Simp goto done; 16652506Simp } 16752506Simp tuple.ptr++; 16852506Simp break; 16952506Simp } 17052506Simp /* now all the normal tuples */ 17152506Simp 17252506Simp tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1); 17352506Simp switch (tuple.code) { 17452506Simp case PCCARD_CISTPL_LONGLINK_A: 17552506Simp case PCCARD_CISTPL_LONGLINK_C: 17652506Simp if (tuple.length < 4) { 17752506Simp DPRINTF(("CISTPL_LONGLINK_%s too " 17852506Simp "short %d\n", 17952506Simp longlink_common ? "C" : "A", 18052506Simp tuple.length)); 18152506Simp break; 18252506Simp } 18352506Simp longlink_present = 1; 18452506Simp longlink_common = (tuple.code == 18552506Simp PCCARD_CISTPL_LONGLINK_C) ? 1 : 0; 18652506Simp longlink_addr = pccard_tuple_read_4(&tuple, 0); 18752506Simp DPRINTF(("CISTPL_LONGLINK_%s %lx\n", 18852506Simp longlink_common ? "C" : "A", 18952506Simp longlink_addr)); 19052506Simp break; 19152506Simp case PCCARD_CISTPL_NO_LINK: 19252506Simp longlink_present = 0; 19352506Simp DPRINTF(("CISTPL_NO_LINK\n")); 19452506Simp break; 19552506Simp case PCCARD_CISTPL_CHECKSUM: 19652506Simp if (tuple.length < 5) { 19752506Simp DPRINTF(("CISTPL_CHECKSUM too " 19852506Simp "short %d\n", tuple.length)); 19952506Simp break; 20052506Simp } { 20152506Simp int16_t offset; 20252506Simp u_long addr, length; 20352506Simp u_int cksum, sum; 20452506Simp int i; 20552506Simp 20652506Simp *((u_int16_t *) & offset) = 20752506Simp pccard_tuple_read_2(&tuple, 0); 20852506Simp length = pccard_tuple_read_2(&tuple, 2); 20952506Simp cksum = pccard_tuple_read_1(&tuple, 4); 21052506Simp 21152506Simp addr = tuple.ptr + offset; 21252506Simp 21352506Simp DPRINTF(("CISTPL_CHECKSUM addr=%lx " 21452506Simp "len=%lx cksum=%x", 21552506Simp addr, length, cksum)); 21652506Simp 21752506Simp /* 21852506Simp * XXX do more work to deal with 21952506Simp * distant regions 22052506Simp */ 22152506Simp if ((addr >= PCCARD_CIS_SIZE) || 22252506Simp ((addr + length) < 0) || 22352506Simp ((addr + length) >= 22452506Simp PCCARD_CIS_SIZE)) { 22552506Simp DPRINTF((" skipped, " 22652506Simp "too distant\n")); 22752506Simp break; 22852506Simp } 22952506Simp sum = 0; 23052506Simp for (i = 0; i < length; i++) 23152506Simp sum += 23252506Simp bus_space_read_1(tuple.memt, 23352506Simp tuple.memh, 23452506Simp addr + tuple.mult * i); 23552506Simp if (cksum != (sum & 0xff)) { 23652506Simp DPRINTF((" failed sum=%x\n", 23752506Simp sum)); 23855720Simp device_printf(dev, 23955720Simp "CIS checksum failed\n"); 24052506Simp#if 0 24152506Simp /* 24252506Simp * XXX Some working cards have 24352506Simp * XXX bad checksums!! 24452506Simp */ 24552506Simp ret = -1; 24652506Simp#endif 24752506Simp } else { 24852506Simp DPRINTF((" ok\n")); 24952506Simp } 25052506Simp } 25152506Simp break; 25252506Simp case PCCARD_CISTPL_LONGLINK_MFC: 25352506Simp if (tuple.length < 1) { 25452506Simp DPRINTF(("CISTPL_LONGLINK_MFC too " 25552506Simp "short %d\n", tuple.length)); 25652506Simp break; 25752506Simp } 25852506Simp /* 25952506Simp * this is kind of ad hoc, as I don't have 26052506Simp * any real documentation 26152506Simp */ 26252506Simp { 26352506Simp int i; 26452506Simp 26552506Simp mfc_count = 26652506Simp pccard_tuple_read_1(&tuple, 0); 26752506Simp DPRINTF(("CISTPL_LONGLINK_MFC %d", 26852506Simp mfc_count)); 26952506Simp for (i = 0; i < mfc_count; i++) { 27052506Simp mfc[i].common = 27152506Simp (pccard_tuple_read_1(&tuple, 27252506Simp 1 + 5 * i) == 27352506Simp PCCARD_MFC_MEM_COMMON) ? 27452506Simp 1 : 0; 27552506Simp mfc[i].addr = 27652506Simp pccard_tuple_read_4(&tuple, 27752506Simp 1 + 5 * i + 1); 27852506Simp DPRINTF((" %s:%lx", 27952506Simp mfc[i].common ? "common" : 28052506Simp "attr", mfc[i].addr)); 28152506Simp } 28252506Simp DPRINTF(("\n")); 28352506Simp } 28452506Simp /* 28552506Simp * for LONGLINK_MFC, fall through to the 28652506Simp * function. This tuple has structural and 28752506Simp * semantic content. 28852506Simp */ 28952506Simp default: 29052506Simp { 29152506Simp if ((*fct) (&tuple, arg)) { 29252506Simp ret = 1; 29352506Simp goto done; 29452506Simp } 29552506Simp } 29652506Simp break; 29752506Simp } /* switch */ 29852506Simp#ifdef PCCARDCISDEBUG 29952506Simp /* print the tuple */ 30052506Simp { 30152506Simp int i; 30252506Simp 30352506Simp DPRINTF((" %02x %02x", tuple.code, 30452506Simp tuple.length)); 30552506Simp 30652506Simp for (i = 0; i < tuple.length; i++) { 30752506Simp DPRINTF((" %02x", 30852506Simp pccard_tuple_read_1(&tuple, i))); 30952506Simp if ((i % 16) == 13) 31052506Simp DPRINTF(("\n")); 31152506Simp } 31252506Simp if ((i % 16) != 14) 31352506Simp DPRINTF(("\n")); 31452506Simp } 31552506Simp#endif 31652506Simp /* skip to the next tuple */ 31752506Simp tuple.ptr += 2 + tuple.length; 31852506Simp } 31952506Simp 32055720Simp#ifdef XXX /* I'm not up to this tonight, need to implement new API */ 32155720Simp /* to deal with moving windows and such. At least that's */ 32255720Simp /* what it appears at this instant */ 32355720Simp 32452506Simp /* 32552506Simp * the chain is done. Clean up and move onto the next one, 32652506Simp * if any. The loop is here in the case that there is an MFC 32752506Simp * card with no longlink (which defaults to existing, == 0). 32852506Simp * In general, this means that if one pointer fails, it will 32952506Simp * try the next one, instead of just bailing. 33052506Simp */ 33152506Simp 33252506Simp while (1) { 33352506Simp pccard_chip_mem_unmap(pct, pch, window); 33452506Simp 33552506Simp if (longlink_present) { 33652506Simp /* 33752506Simp * if the longlink is to attribute memory, 33852506Simp * then it is unindexed. That is, if the 33952506Simp * link value is 0x100, then the actual 34052506Simp * memory address is 0x200. This means that 34152506Simp * we need to multiply by 2 before calling 34252506Simp * mem_map, and then divide the resulting ptr 34352506Simp * by 2 after. 34452506Simp */ 34552506Simp 34652506Simp if (!longlink_common) 34752506Simp longlink_addr *= 2; 34852506Simp 34952506Simp pccard_chip_mem_map(pct, pch, longlink_common ? 35052506Simp PCCARD_MEM_COMMON : PCCARD_MEM_ATTR, 35152506Simp longlink_addr, PCCARD_CIS_SIZE, 35252506Simp &pcmh, &tuple.ptr, &window); 35352506Simp 35452506Simp if (!longlink_common) 35552506Simp tuple.ptr /= 2; 35652506Simp DPRINTF(("cis mem map %x\n", 35752506Simp (unsigned int) tuple.memh)); 35852506Simp tuple.mult = longlink_common ? 1 : 2; 35952506Simp longlink_present = 0; 36052506Simp longlink_common = 1; 36152506Simp longlink_addr = 0; 36252506Simp } else if (mfc_count && (mfc_index < mfc_count)) { 36352506Simp if (!mfc[mfc_index].common) 36452506Simp mfc[mfc_index].addr *= 2; 36552506Simp 36652506Simp pccard_chip_mem_map(pct, pch, 36752506Simp mfc[mfc_index].common ? 36852506Simp PCCARD_MEM_COMMON : PCCARD_MEM_ATTR, 36952506Simp mfc[mfc_index].addr, PCCARD_CIS_SIZE, 37052506Simp &pcmh, &tuple.ptr, &window); 37152506Simp 37252506Simp if (!mfc[mfc_index].common) 37352506Simp tuple.ptr /= 2; 37452506Simp DPRINTF(("cis mem map %x\n", 37552506Simp (unsigned int) tuple.memh)); 37652506Simp /* set parse state, and point at the next one */ 37752506Simp 37852506Simp tuple.mult = mfc[mfc_index].common ? 1 : 2; 37952506Simp 38052506Simp mfc_index++; 38152506Simp } else { 38252506Simp goto done; 38352506Simp } 38452506Simp 38552506Simp /* make sure that the link is valid */ 38652506Simp tuple.code = pccard_cis_read_1(&tuple, tuple.ptr); 38752506Simp if (tuple.code != PCCARD_CISTPL_LINKTARGET) { 38852506Simp DPRINTF(("CISTPL_LINKTARGET expected, " 38952506Simp "code %02x observed\n", tuple.code)); 39052506Simp continue; 39152506Simp } 39252506Simp tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1); 39352506Simp if (tuple.length < 3) { 39452506Simp DPRINTF(("CISTPL_LINKTARGET too short %d\n", 39552506Simp tuple.length)); 39652506Simp continue; 39752506Simp } 39852506Simp if ((pccard_tuple_read_1(&tuple, 0) != 'C') || 39952506Simp (pccard_tuple_read_1(&tuple, 1) != 'I') || 40052506Simp (pccard_tuple_read_1(&tuple, 2) != 'S')) { 40152506Simp DPRINTF(("CISTPL_LINKTARGET magic " 40252506Simp "%02x%02x%02x incorrect\n", 40352506Simp pccard_tuple_read_1(&tuple, 0), 40452506Simp pccard_tuple_read_1(&tuple, 1), 40552506Simp pccard_tuple_read_1(&tuple, 2))); 40652506Simp continue; 40752506Simp } 40852506Simp tuple.ptr += 2 + tuple.length; 40952506Simp 41052506Simp break; 41152506Simp } 41255720Simp#endif /* XXX */ 41352506Simp } 41452506Simp 41552506Simpdone: 41655720Simp bus_release_resource(dev, SYS_RES_MEMORY, rid, res); 41752506Simp 41852506Simp return (ret); 41952506Simp} 42052506Simp 42152506Simp/* XXX this is incredibly verbose. Not sure what trt is */ 42252506Simp 42352506Simpvoid 42452506Simppccard_print_cis(device_t dev) 42552506Simp{ 42652506Simp struct pccard_softc *sc = (struct pccard_softc *) device_get_softc(dev); 42752506Simp struct pccard_card *card = &sc->card; 42852506Simp struct pccard_function *pf; 42952506Simp struct pccard_config_entry *cfe; 43052506Simp int i; 43152506Simp 43252506Simp device_printf(dev, "CIS version "); 43352506Simp if (card->cis1_major == 4) { 43452506Simp if (card->cis1_minor == 0) 43552506Simp printf("PCCARD 1.0\n"); 43652506Simp else if (card->cis1_minor == 1) 43752506Simp printf("PCCARD 2.0 or 2.1\n"); 43852506Simp } else if (card->cis1_major >= 5) 43952506Simp printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor); 44052506Simp else 44152506Simp printf("unknown (major=%d, minor=%d)\n", 44252506Simp card->cis1_major, card->cis1_minor); 44352506Simp 44452506Simp device_printf(dev, "CIS info: "); 44552506Simp for (i = 0; i < 4; i++) { 44652506Simp if (card->cis1_info[i] == NULL) 44752506Simp break; 44852506Simp if (i) 44952506Simp printf(", "); 45052506Simp printf("%s", card->cis1_info[i]); 45152506Simp } 45252506Simp printf("\n"); 45352506Simp 45452506Simp device_printf(dev, "Manufacturer code 0x%x, product 0x%x\n", 45552506Simp card->manufacturer, card->product); 45652506Simp 45752506Simp STAILQ_FOREACH(pf, &card->pf_head, pf_list) { 45852506Simp device_printf(dev, "function %d: ", pf->number); 45952506Simp 46052506Simp switch (pf->function) { 46152506Simp case PCCARD_FUNCTION_UNSPEC: 46252506Simp printf("unspecified"); 46352506Simp break; 46452506Simp case PCCARD_FUNCTION_MULTIFUNCTION: 46552506Simp printf("multi-function"); 46652506Simp break; 46752506Simp case PCCARD_FUNCTION_MEMORY: 46852506Simp printf("memory"); 46952506Simp break; 47052506Simp case PCCARD_FUNCTION_SERIAL: 47152506Simp printf("serial port"); 47252506Simp break; 47352506Simp case PCCARD_FUNCTION_PARALLEL: 47452506Simp printf("parallel port"); 47552506Simp break; 47652506Simp case PCCARD_FUNCTION_DISK: 47752506Simp printf("fixed disk"); 47852506Simp break; 47952506Simp case PCCARD_FUNCTION_VIDEO: 48052506Simp printf("video adapter"); 48152506Simp break; 48252506Simp case PCCARD_FUNCTION_NETWORK: 48352506Simp printf("network adapter"); 48452506Simp break; 48552506Simp case PCCARD_FUNCTION_AIMS: 48652506Simp printf("auto incrementing mass storage"); 48752506Simp break; 48852506Simp case PCCARD_FUNCTION_SCSI: 48952506Simp printf("SCSI bridge"); 49052506Simp break; 49152506Simp case PCCARD_FUNCTION_SECURITY: 49252506Simp printf("Security services"); 49352506Simp break; 49452506Simp case PCCARD_FUNCTION_INSTRUMENT: 49552506Simp printf("Instrument"); 49652506Simp break; 49752506Simp default: 49852506Simp printf("unknown (%d)", pf->function); 49952506Simp break; 50052506Simp } 50152506Simp 50252506Simp printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask); 50352506Simp 50452506Simp STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 50552506Simp device_printf(dev, "function %d, config table entry " 50652506Simp "%d: ", pf->number, cfe->number); 50752506Simp 50852506Simp switch (cfe->iftype) { 50952506Simp case PCCARD_IFTYPE_MEMORY: 51052506Simp printf("memory card"); 51152506Simp break; 51252506Simp case PCCARD_IFTYPE_IO: 51352506Simp printf("I/O card"); 51452506Simp break; 51552506Simp default: 51652506Simp printf("card type unknown"); 51752506Simp break; 51852506Simp } 51952506Simp 52052506Simp printf("; irq mask %x", cfe->irqmask); 52152506Simp 52252506Simp if (cfe->num_iospace) { 52352506Simp printf("; iomask %lx, iospace", cfe->iomask); 52452506Simp 52553813Simp for (i = 0; i < cfe->num_iospace; i++) { 52653813Simp printf(" %lx", cfe->iospace[i].start); 52753813Simp if (cfe->iospace[i].length) 52853813Simp printf("-%lx", 52953813Simp cfe->iospace[i].start + 53053813Simp cfe->iospace[i].length - 1); 53153813Simp } 53252506Simp } 53352506Simp if (cfe->num_memspace) { 53452506Simp printf("; memspace"); 53552506Simp 53653813Simp for (i = 0; i < cfe->num_memspace; i++) { 53753813Simp printf(" %lx", 53853813Simp cfe->memspace[i].cardaddr); 53953813Simp if (cfe->memspace[i].length) 54053813Simp printf("-%lx", 54153813Simp cfe->memspace[i].cardaddr + 54253813Simp cfe->memspace[i].length - 1); 54353813Simp if (cfe->memspace[i].hostaddr) 54453813Simp printf("@%lx", 54553813Simp cfe->memspace[i].hostaddr); 54653813Simp } 54752506Simp } 54852506Simp if (cfe->maxtwins) 54952506Simp printf("; maxtwins %d", cfe->maxtwins); 55052506Simp 55152506Simp printf(";"); 55252506Simp 55352506Simp if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED) 55452506Simp printf(" mwait_required"); 55552506Simp if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE) 55652506Simp printf(" rdybsy_active"); 55752506Simp if (cfe->flags & PCCARD_CFE_WP_ACTIVE) 55852506Simp printf(" wp_active"); 55952506Simp if (cfe->flags & PCCARD_CFE_BVD_ACTIVE) 56052506Simp printf(" bvd_active"); 56152506Simp if (cfe->flags & PCCARD_CFE_IO8) 56252506Simp printf(" io8"); 56352506Simp if (cfe->flags & PCCARD_CFE_IO16) 56452506Simp printf(" io16"); 56552506Simp if (cfe->flags & PCCARD_CFE_IRQSHARE) 56652506Simp printf(" irqshare"); 56752506Simp if (cfe->flags & PCCARD_CFE_IRQPULSE) 56852506Simp printf(" irqpulse"); 56952506Simp if (cfe->flags & PCCARD_CFE_IRQLEVEL) 57052506Simp printf(" irqlevel"); 57152506Simp if (cfe->flags & PCCARD_CFE_POWERDOWN) 57252506Simp printf(" powerdown"); 57352506Simp if (cfe->flags & PCCARD_CFE_READONLY) 57452506Simp printf(" readonly"); 57552506Simp if (cfe->flags & PCCARD_CFE_AUDIO) 57652506Simp printf(" audio"); 57752506Simp 57852506Simp printf("\n"); 57952506Simp } 58052506Simp } 58152506Simp 58252506Simp if (card->error) 58352506Simp device_printf(dev, "%d errors found while parsing CIS\n", 58452506Simp card->error); 58552506Simp} 58652506Simp 58752506Simpint 58855720Simppccard_parse_cis_tuple(struct pccard_tuple *tuple, void *arg) 58952506Simp{ 59052506Simp /* most of these are educated guesses */ 59152506Simp static struct pccard_config_entry init_cfe = { 59252506Simp -1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE | 59352506Simp PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY, 59452506Simp }; 59552506Simp 59652506Simp struct cis_state *state = arg; 59752506Simp 59852506Simp switch (tuple->code) { 59952506Simp case PCCARD_CISTPL_END: 60052506Simp /* if we've seen a LONGLINK_MFC, and this is the first 60152506Simp * END after it, reset the function list. 60252506Simp * 60352506Simp * XXX This might also be the right place to start a 60452506Simp * new function, but that assumes that a function 60552506Simp * definition never crosses any longlink, and I'm not 60652506Simp * sure about that. This is probably safe for MFC 60752506Simp * cards, but what we have now isn't broken, so I'd 60852506Simp * rather not change it. 60952506Simp */ 61052506Simp if (state->gotmfc == 1) { 61152506Simp struct pccard_function *pf, *pfnext; 61252506Simp 61352506Simp for (pf = STAILQ_FIRST(&state->card->pf_head); 61452506Simp pf != NULL; pf = pfnext) { 61552506Simp pfnext = STAILQ_NEXT(pf, pf_list); 61652506Simp free(pf, M_DEVBUF); 61752506Simp } 61852506Simp 61952506Simp STAILQ_INIT(&state->card->pf_head); 62052506Simp 62152506Simp state->count = 0; 62252506Simp state->gotmfc = 2; 62352506Simp state->pf = NULL; 62452506Simp } 62552506Simp break; 62652506Simp case PCCARD_CISTPL_LONGLINK_MFC: 62752506Simp /* 62852506Simp * this tuple's structure was dealt with in scan_cis. here, 62952506Simp * record the fact that the MFC tuple was seen, so that 63052506Simp * functions declared before the MFC link can be cleaned 63152506Simp * up. 63252506Simp */ 63352506Simp state->gotmfc = 1; 63452506Simp break; 63552506Simp#ifdef PCCARDCISDEBUG 63652506Simp case PCCARD_CISTPL_DEVICE: 63752506Simp case PCCARD_CISTPL_DEVICE_A: 63852506Simp { 63952506Simp u_int reg, dtype, dspeed; 64052506Simp 64152506Simp reg = pccard_tuple_read_1(tuple, 0); 64252506Simp dtype = reg & PCCARD_DTYPE_MASK; 64352506Simp dspeed = reg & PCCARD_DSPEED_MASK; 64452506Simp 64552506Simp DPRINTF(("CISTPL_DEVICE%s type=", 64652506Simp (tuple->code == PCCARD_CISTPL_DEVICE) ? "" : "_A")); 64752506Simp switch (dtype) { 64852506Simp case PCCARD_DTYPE_NULL: 64952506Simp DPRINTF(("null")); 65052506Simp break; 65152506Simp case PCCARD_DTYPE_ROM: 65252506Simp DPRINTF(("rom")); 65352506Simp break; 65452506Simp case PCCARD_DTYPE_OTPROM: 65552506Simp DPRINTF(("otprom")); 65652506Simp break; 65752506Simp case PCCARD_DTYPE_EPROM: 65852506Simp DPRINTF(("eprom")); 65952506Simp break; 66052506Simp case PCCARD_DTYPE_EEPROM: 66152506Simp DPRINTF(("eeprom")); 66252506Simp break; 66352506Simp case PCCARD_DTYPE_FLASH: 66452506Simp DPRINTF(("flash")); 66552506Simp break; 66652506Simp case PCCARD_DTYPE_SRAM: 66752506Simp DPRINTF(("sram")); 66852506Simp break; 66952506Simp case PCCARD_DTYPE_DRAM: 67052506Simp DPRINTF(("dram")); 67152506Simp break; 67252506Simp case PCCARD_DTYPE_FUNCSPEC: 67352506Simp DPRINTF(("funcspec")); 67452506Simp break; 67552506Simp case PCCARD_DTYPE_EXTEND: 67652506Simp DPRINTF(("extend")); 67752506Simp break; 67852506Simp default: 67952506Simp DPRINTF(("reserved")); 68052506Simp break; 68152506Simp } 68252506Simp DPRINTF((" speed=")); 68352506Simp switch (dspeed) { 68452506Simp case PCCARD_DSPEED_NULL: 68552506Simp DPRINTF(("null")); 68652506Simp break; 68752506Simp case PCCARD_DSPEED_250NS: 68852506Simp DPRINTF(("250ns")); 68952506Simp break; 69052506Simp case PCCARD_DSPEED_200NS: 69152506Simp DPRINTF(("200ns")); 69252506Simp break; 69352506Simp case PCCARD_DSPEED_150NS: 69452506Simp DPRINTF(("150ns")); 69552506Simp break; 69652506Simp case PCCARD_DSPEED_100NS: 69752506Simp DPRINTF(("100ns")); 69852506Simp break; 69952506Simp case PCCARD_DSPEED_EXT: 70052506Simp DPRINTF(("ext")); 70152506Simp break; 70252506Simp default: 70352506Simp DPRINTF(("reserved")); 70452506Simp break; 70552506Simp } 70652506Simp } 70752506Simp DPRINTF(("\n")); 70852506Simp break; 70952506Simp#endif 71052506Simp case PCCARD_CISTPL_VERS_1: 71152506Simp if (tuple->length < 6) { 71252506Simp DPRINTF(("CISTPL_VERS_1 too short %d\n", 71352506Simp tuple->length)); 71452506Simp break; 71552506Simp } { 71652506Simp int start, i, ch, count; 71752506Simp 71852506Simp state->card->cis1_major = pccard_tuple_read_1(tuple, 0); 71952506Simp state->card->cis1_minor = pccard_tuple_read_1(tuple, 1); 72052506Simp 72152506Simp for (count = 0, start = 0, i = 0; 72252506Simp (count < 4) && ((i + 4) < 256); i++) { 72352506Simp ch = pccard_tuple_read_1(tuple, 2 + i); 72452506Simp if (ch == 0xff) 72552506Simp break; 72652506Simp state->card->cis1_info_buf[i] = ch; 72752506Simp if (ch == 0) { 72852506Simp state->card->cis1_info[count] = 72952506Simp state->card->cis1_info_buf + start; 73052506Simp start = i + 1; 73152506Simp count++; 73252506Simp } 73352506Simp } 73452506Simp DPRINTF(("CISTPL_VERS_1\n")); 73552506Simp } 73652506Simp break; 73752506Simp case PCCARD_CISTPL_MANFID: 73852506Simp if (tuple->length < 4) { 73952506Simp DPRINTF(("CISTPL_MANFID too short %d\n", 74052506Simp tuple->length)); 74152506Simp break; 74252506Simp } 74352506Simp state->card->manufacturer = pccard_tuple_read_2(tuple, 0); 74452506Simp state->card->product = pccard_tuple_read_2(tuple, 2); 74552506Simp DPRINTF(("CISTPL_MANFID\n")); 74652506Simp break; 74752506Simp case PCCARD_CISTPL_FUNCID: 74852506Simp if (tuple->length < 1) { 74952506Simp DPRINTF(("CISTPL_FUNCID too short %d\n", 75052506Simp tuple->length)); 75152506Simp break; 75252506Simp } 75352506Simp if ((state->pf == NULL) || (state->gotmfc == 2)) { 75452506Simp state->pf = malloc(sizeof(*state->pf), M_DEVBUF, 75552506Simp M_NOWAIT); 75652506Simp bzero(state->pf, sizeof(*state->pf)); 75752506Simp state->pf->number = state->count++; 75852506Simp state->pf->last_config_index = -1; 75952506Simp STAILQ_INIT(&state->pf->cfe_head); 76052506Simp 76152506Simp STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf, 76252506Simp pf_list); 76352506Simp } 76452506Simp state->pf->function = pccard_tuple_read_1(tuple, 0); 76552506Simp 76652506Simp DPRINTF(("CISTPL_FUNCID\n")); 76752506Simp break; 76852506Simp case PCCARD_CISTPL_CONFIG: 76952506Simp if (tuple->length < 3) { 77052506Simp DPRINTF(("CISTPL_CONFIG too short %d\n", 77152506Simp tuple->length)); 77252506Simp break; 77352506Simp } { 77452506Simp u_int reg, rasz, rmsz, rfsz; 77552506Simp int i; 77652506Simp 77752506Simp reg = pccard_tuple_read_1(tuple, 0); 77852506Simp rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >> 77952506Simp PCCARD_TPCC_RASZ_SHIFT); 78052506Simp rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >> 78152506Simp PCCARD_TPCC_RMSZ_SHIFT); 78252506Simp rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >> 78352506Simp PCCARD_TPCC_RFSZ_SHIFT); 78452506Simp 78552506Simp if (tuple->length < (rasz + rmsz + rfsz)) { 78652506Simp DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too " 78752506Simp "short %d\n", rasz, rmsz, rfsz, 78852506Simp tuple->length)); 78952506Simp break; 79052506Simp } 79152506Simp if (state->pf == NULL) { 79252506Simp state->pf = malloc(sizeof(*state->pf), 79352506Simp M_DEVBUF, M_NOWAIT); 79452506Simp bzero(state->pf, sizeof(*state->pf)); 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, 80052506Simp state->pf, pf_list); 80152506Simp 80252506Simp state->pf->function = PCCARD_FUNCTION_UNSPEC; 80352506Simp } 80452506Simp state->pf->last_config_index = 80552506Simp pccard_tuple_read_1(tuple, 1); 80652506Simp 80752506Simp state->pf->ccr_base = 0; 80852506Simp for (i = 0; i < rasz; i++) 80952506Simp state->pf->ccr_base |= 81052506Simp ((pccard_tuple_read_1(tuple, 2 + i)) << 81152506Simp (i * 8)); 81252506Simp 81352506Simp state->pf->ccr_mask = 0; 81452506Simp for (i = 0; i < rmsz; i++) 81552506Simp state->pf->ccr_mask |= 81652506Simp ((pccard_tuple_read_1(tuple, 81752506Simp 2 + rasz + i)) << (i * 8)); 81852506Simp 81952506Simp /* skip the reserved area and subtuples */ 82052506Simp 82152506Simp /* reset the default cfe for each cfe list */ 82252506Simp state->temp_cfe = init_cfe; 82352506Simp state->default_cfe = &state->temp_cfe; 82452506Simp } 82552506Simp DPRINTF(("CISTPL_CONFIG\n")); 82652506Simp break; 82752506Simp case PCCARD_CISTPL_CFTABLE_ENTRY: 82852506Simp { 82952506Simp int idx, i, j; 83052506Simp u_int reg, reg2; 83152506Simp u_int intface, def, num; 83252506Simp u_int power, timing, iospace, irq, memspace, misc; 83352506Simp struct pccard_config_entry *cfe; 83452506Simp 83552506Simp idx = 0; 83652506Simp 83752506Simp reg = pccard_tuple_read_1(tuple, idx); 83852506Simp idx++; 83952506Simp intface = reg & PCCARD_TPCE_INDX_INTFACE; 84052506Simp def = reg & PCCARD_TPCE_INDX_DEFAULT; 84152506Simp num = reg & PCCARD_TPCE_INDX_NUM_MASK; 84252506Simp 84352506Simp /* 84452506Simp * this is a little messy. Some cards have only a 84552506Simp * cfentry with the default bit set. So, as we go 84652506Simp * through the list, we add new indexes to the queue, 84752506Simp * and keep a pointer to the last one with the 84852506Simp * default bit set. if we see a record with the same 84952506Simp * index, as the default, we stash the default and 85052506Simp * replace the queue entry. otherwise, we just add 85152506Simp * new entries to the queue, pointing the default ptr 85252506Simp * at them if the default bit is set. if we get to 85352506Simp * the end with the default pointer pointing at a 85452506Simp * record which hasn't had a matching index, that's 85552506Simp * ok; it just becomes a cfentry like any other. 85652506Simp */ 85752506Simp 85852506Simp /* 85952506Simp * if the index in the cis differs from the default 86052506Simp * cis, create new entry in the queue and start it 86152506Simp * with the current default 86252506Simp */ 86352506Simp if (num != state->default_cfe->number) { 86452506Simp cfe = (struct pccard_config_entry *) 86552506Simp malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 86652506Simp 86752506Simp *cfe = *state->default_cfe; 86852506Simp 86952506Simp STAILQ_INSERT_TAIL(&state->pf->cfe_head, 87052506Simp cfe, cfe_list); 87152506Simp 87252506Simp cfe->number = num; 87352506Simp 87452506Simp /* 87552506Simp * if the default bit is set in the cis, then 87652506Simp * point the new default at whatever is being 87752506Simp * filled in 87852506Simp */ 87952506Simp if (def) 88052506Simp state->default_cfe = cfe; 88152506Simp } else { 88252506Simp /* 88352506Simp * the cis index matches the default index, 88452506Simp * fill in the default cfentry. It is 88552506Simp * assumed that the cfdefault index is in the 88652506Simp * queue. For it to be otherwise, the cis 88752506Simp * index would have to be -1 (initial 88852506Simp * condition) which is not possible, or there 88952506Simp * would have to be a preceding cis entry 89052506Simp * which had the same cis index and had the 89152506Simp * default bit unset. Neither condition 89252506Simp * should happen. If it does, this cfentry 89352506Simp * is lost (written into temp space), which 89452506Simp * is an acceptable failure mode. 89552506Simp */ 89652506Simp 89752506Simp cfe = state->default_cfe; 89852506Simp 89952506Simp /* 90052506Simp * if the cis entry does not have the default 90152506Simp * bit set, copy the default out of the way 90252506Simp * first. 90352506Simp */ 90452506Simp if (!def) { 90552506Simp state->temp_cfe = *state->default_cfe; 90652506Simp state->default_cfe = &state->temp_cfe; 90752506Simp } 90852506Simp } 90952506Simp 91052506Simp if (intface) { 91152506Simp reg = pccard_tuple_read_1(tuple, idx); 91252506Simp idx++; 91352506Simp if (reg & PCCARD_TPCE_IF_MWAIT) 91452506Simp cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED; 91552506Simp if (reg & PCCARD_TPCE_IF_RDYBSY) 91652506Simp cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE; 91752506Simp if (reg & PCCARD_TPCE_IF_WP) 91852506Simp cfe->flags |= PCCARD_CFE_WP_ACTIVE; 91952506Simp if (reg & PCCARD_TPCE_IF_BVD) 92052506Simp cfe->flags |= PCCARD_CFE_BVD_ACTIVE; 92152506Simp cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE; 92252506Simp } 92352506Simp reg = pccard_tuple_read_1(tuple, idx); 92452506Simp idx++; 92552506Simp 92652506Simp power = reg & PCCARD_TPCE_FS_POWER_MASK; 92752506Simp timing = reg & PCCARD_TPCE_FS_TIMING; 92852506Simp iospace = reg & PCCARD_TPCE_FS_IOSPACE; 92952506Simp irq = reg & PCCARD_TPCE_FS_IRQ; 93052506Simp memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK; 93152506Simp misc = reg & PCCARD_TPCE_FS_MISC; 93252506Simp 93352506Simp if (power) { 93452506Simp /* skip over power, don't save */ 93552506Simp /* for each parameter selection byte */ 93652506Simp for (i = 0; i < power; i++) { 93752506Simp reg = pccard_tuple_read_1(tuple, idx); 93852506Simp idx++; 93952506Simp /* for each bit */ 94052506Simp for (j = 0; j < 7; j++) { 94152506Simp /* if the bit is set */ 94252506Simp if ((reg >> j) & 0x01) { 94352506Simp /* skip over bytes */ 94452506Simp do { 94552506Simp reg2 = pccard_tuple_read_1(tuple, idx); 94652506Simp idx++; 94752506Simp /* 94852506Simp * until 94952506Simp * non-extensi 95052506Simp * on byte 95152506Simp */ 95252506Simp } while (reg2 & 0x80); 95352506Simp } 95452506Simp } 95552506Simp } 95652506Simp } 95752506Simp if (timing) { 95852506Simp /* skip over timing, don't save */ 95952506Simp reg = pccard_tuple_read_1(tuple, idx); 96052506Simp idx++; 96152506Simp 96252506Simp if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) != 96352506Simp PCCARD_TPCE_TD_RESERVED_MASK) 96452506Simp idx++; 96552506Simp if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) != 96652506Simp PCCARD_TPCE_TD_RDYBSY_MASK) 96752506Simp idx++; 96852506Simp if ((reg & PCCARD_TPCE_TD_WAIT_MASK) != 96952506Simp PCCARD_TPCE_TD_WAIT_MASK) 97052506Simp idx++; 97152506Simp } 97252506Simp if (iospace) { 97352506Simp if (tuple->length <= idx) { 97452506Simp DPRINTF(("ran out of space before TCPE_IO\n")); 97552506Simp goto abort_cfe; 97652506Simp } 97752506Simp 97852506Simp reg = pccard_tuple_read_1(tuple, idx); 97952506Simp idx++; 98052506Simp 98152506Simp if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT) 98252506Simp cfe->flags |= PCCARD_CFE_IO8; 98352506Simp if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT) 98452506Simp cfe->flags |= PCCARD_CFE_IO16; 98552506Simp cfe->iomask = 98652506Simp reg & PCCARD_TPCE_IO_IOADDRLINES_MASK; 98752506Simp 98852506Simp if (reg & PCCARD_TPCE_IO_HASRANGE) { 98952506Simp reg = pccard_tuple_read_1(tuple, idx); 99052506Simp idx++; 99152506Simp 99252506Simp cfe->num_iospace = 1 + (reg & 99352506Simp PCCARD_TPCE_IO_RANGE_COUNT); 99452506Simp 99552506Simp if (cfe->num_iospace > 99652506Simp (sizeof(cfe->iospace) / 99752506Simp sizeof(cfe->iospace[0]))) { 99852506Simp DPRINTF(("too many io " 99952506Simp "spaces %d", 100052506Simp cfe->num_iospace)); 100152506Simp state->card->error++; 100252506Simp break; 100352506Simp } 100452506Simp for (i = 0; i < cfe->num_iospace; i++) { 100552506Simp switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) { 100652506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE: 100752506Simp cfe->iospace[i].start = 100852506Simp pccard_tuple_read_1(tuple, idx); 100952506Simp idx++; 101052506Simp break; 101152506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO: 101252506Simp cfe->iospace[i].start = 101352506Simp pccard_tuple_read_2(tuple, idx); 101452506Simp idx += 2; 101552506Simp break; 101652506Simp case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR: 101752506Simp cfe->iospace[i].start = 101852506Simp pccard_tuple_read_4(tuple, idx); 101952506Simp idx += 4; 102052506Simp break; 102152506Simp } 102252506Simp switch (reg & 102352506Simp PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) { 102452506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE: 102552506Simp cfe->iospace[i].length = 102652506Simp pccard_tuple_read_1(tuple, idx); 102752506Simp idx++; 102852506Simp break; 102952506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO: 103052506Simp cfe->iospace[i].length = 103152506Simp pccard_tuple_read_2(tuple, idx); 103252506Simp idx += 2; 103352506Simp break; 103452506Simp case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR: 103552506Simp cfe->iospace[i].length = 103652506Simp pccard_tuple_read_4(tuple, idx); 103752506Simp idx += 4; 103852506Simp break; 103952506Simp } 104052506Simp cfe->iospace[i].length++; 104152506Simp } 104252506Simp } else { 104352506Simp cfe->num_iospace = 1; 104452506Simp cfe->iospace[0].start = 0; 104552506Simp cfe->iospace[0].length = 104652506Simp (1 << cfe->iomask); 104752506Simp } 104852506Simp } 104952506Simp if (irq) { 105052506Simp if (tuple->length <= idx) { 105152506Simp DPRINTF(("ran out of space before TCPE_IR\n")); 105252506Simp goto abort_cfe; 105352506Simp } 105452506Simp 105552506Simp reg = pccard_tuple_read_1(tuple, idx); 105652506Simp idx++; 105752506Simp 105852506Simp if (reg & PCCARD_TPCE_IR_SHARE) 105952506Simp cfe->flags |= PCCARD_CFE_IRQSHARE; 106052506Simp if (reg & PCCARD_TPCE_IR_PULSE) 106152506Simp cfe->flags |= PCCARD_CFE_IRQPULSE; 106252506Simp if (reg & PCCARD_TPCE_IR_LEVEL) 106352506Simp cfe->flags |= PCCARD_CFE_IRQLEVEL; 106452506Simp 106552506Simp if (reg & PCCARD_TPCE_IR_HASMASK) { 106652506Simp /* 106752506Simp * it's legal to ignore the 106852506Simp * special-interrupt bits, so I will 106952506Simp */ 107052506Simp 107152506Simp cfe->irqmask = 107252506Simp pccard_tuple_read_2(tuple, idx); 107352506Simp idx += 2; 107452506Simp } else { 107552506Simp cfe->irqmask = 107652506Simp (1 << (reg & PCCARD_TPCE_IR_IRQ)); 107752506Simp } 107852506Simp } 107952506Simp if (memspace) { 108052506Simp if (tuple->length <= idx) { 108152506Simp DPRINTF(("ran out of space before TCPE_MS\n")); 108252506Simp goto abort_cfe; 108352506Simp } 108452506Simp 108552506Simp if (memspace == PCCARD_TPCE_FS_MEMSPACE_NONE) { 108652506Simp cfe->num_memspace = 0; 108752506Simp } else if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) { 108852506Simp cfe->num_memspace = 1; 108952506Simp cfe->memspace[0].length = 256 * 109052506Simp pccard_tuple_read_2(tuple, idx); 109152506Simp idx += 2; 109252506Simp cfe->memspace[0].cardaddr = 0; 109352506Simp cfe->memspace[0].hostaddr = 0; 109452506Simp } else if (memspace == 109552506Simp PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) { 109652506Simp cfe->num_memspace = 1; 109752506Simp cfe->memspace[0].length = 256 * 109852506Simp pccard_tuple_read_2(tuple, idx); 109952506Simp idx += 2; 110052506Simp cfe->memspace[0].cardaddr = 256 * 110152506Simp pccard_tuple_read_2(tuple, idx); 110252506Simp idx += 2; 110352506Simp cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr; 110452506Simp } else { 110552506Simp int lengthsize; 110652506Simp int cardaddrsize; 110752506Simp int hostaddrsize; 110852506Simp 110952506Simp reg = pccard_tuple_read_1(tuple, idx); 111052506Simp idx++; 111152506Simp 111253873Simp cfe->num_memspace = (reg & 111353873Simp PCCARD_TPCE_MS_COUNT) + 1; 111452506Simp 111552506Simp if (cfe->num_memspace > 111652506Simp (sizeof(cfe->memspace) / 111752506Simp sizeof(cfe->memspace[0]))) { 111852506Simp DPRINTF(("too many mem " 111952506Simp "spaces %d", 112052506Simp cfe->num_memspace)); 112152506Simp state->card->error++; 112252506Simp break; 112352506Simp } 112452506Simp lengthsize = 112552506Simp ((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >> 112652506Simp PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT); 112752506Simp cardaddrsize = 112852506Simp ((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >> 112952506Simp PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT); 113052506Simp hostaddrsize = 113152506Simp (reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0; 113252506Simp 113352506Simp if (lengthsize == 0) { 113452506Simp DPRINTF(("cfe memspace " 113552506Simp "lengthsize == 0")); 113652506Simp state->card->error++; 113752506Simp } 113852506Simp for (i = 0; i < cfe->num_memspace; i++) { 113952506Simp if (lengthsize) { 114052506Simp cfe->memspace[i].length = 114152506Simp 256 * pccard_tuple_read_n(tuple, lengthsize, 114252506Simp idx); 114352506Simp idx += lengthsize; 114452506Simp } else { 114552506Simp cfe->memspace[i].length = 0; 114652506Simp } 114752506Simp if (cfe->memspace[i].length == 0) { 114852506Simp DPRINTF(("cfe->memspace[%d].length == 0", 114952506Simp i)); 115052506Simp state->card->error++; 115152506Simp } 115252506Simp if (cardaddrsize) { 115352506Simp cfe->memspace[i].cardaddr = 115452506Simp 256 * pccard_tuple_read_n(tuple, cardaddrsize, 115552506Simp idx); 115652506Simp idx += cardaddrsize; 115752506Simp } else { 115852506Simp cfe->memspace[i].cardaddr = 0; 115952506Simp } 116052506Simp if (hostaddrsize) { 116152506Simp cfe->memspace[i].hostaddr = 116252506Simp 256 * pccard_tuple_read_n(tuple, hostaddrsize, 116352506Simp idx); 116452506Simp idx += hostaddrsize; 116552506Simp } else { 116652506Simp cfe->memspace[i].hostaddr = 0; 116752506Simp } 116852506Simp } 116952506Simp } 117052506Simp } 117152506Simp if (misc) { 117252506Simp if (tuple->length <= idx) { 117352506Simp DPRINTF(("ran out of space before TCPE_MI\n")); 117452506Simp goto abort_cfe; 117552506Simp } 117652506Simp 117752506Simp reg = pccard_tuple_read_1(tuple, idx); 117852506Simp idx++; 117952506Simp 118052506Simp if (reg & PCCARD_TPCE_MI_PWRDOWN) 118152506Simp cfe->flags = PCCARD_CFE_POWERDOWN; 118252506Simp if (reg & PCCARD_TPCE_MI_READONLY) 118352506Simp cfe->flags = PCCARD_CFE_READONLY; 118452506Simp if (reg & PCCARD_TPCE_MI_AUDIO) 118552506Simp cfe->flags = PCCARD_CFE_AUDIO; 118652506Simp cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS; 118752506Simp 118852506Simp while (reg & PCCARD_TPCE_MI_EXT) { 118952506Simp reg = pccard_tuple_read_1(tuple, idx); 119052506Simp idx++; 119152506Simp } 119252506Simp } 119352506Simp /* skip all the subtuples */ 119452506Simp } 119552506Simp 119652506Simp abort_cfe: 119752506Simp DPRINTF(("CISTPL_CFTABLE_ENTRY\n")); 119852506Simp break; 119952506Simp default: 120052506Simp DPRINTF(("unhandled CISTPL %x\n", tuple->code)); 120152506Simp break; 120252506Simp } 120352506Simp 120452506Simp return (0); 120552506Simp} 1206