1107492Sobrien/* $NetBSD: pcmcia_cis.c,v 1.17 2000/02/10 09:01:52 chopps Exp $ */ 2107492Sobrien/* $FreeBSD$ */ 3107492Sobrien 4107492Sobrien/*- 5107492Sobrien * Copyright (c) 1997 Marc Horowitz. All rights reserved. 6107492Sobrien * 7107492Sobrien * Redistribution and use in source and binary forms, with or without 8107492Sobrien * modification, are permitted provided that the following conditions 9107492Sobrien * are met: 10107492Sobrien * 1. Redistributions of source code must retain the above copyright 11107492Sobrien * notice, this list of conditions and the following disclaimer. 12107492Sobrien * 2. Redistributions in binary form must reproduce the above copyright 13107492Sobrien * notice, this list of conditions and the following disclaimer in the 14107492Sobrien * documentation and/or other materials provided with the distribution. 15107492Sobrien * 3. All advertising materials mentioning features or use of this software 16107492Sobrien * must display the following acknowledgement: 17107492Sobrien * This product includes software developed by Marc Horowitz. 18107492Sobrien * 4. The name of the author may not be used to endorse or promote products 19107492Sobrien * derived from this software without specific prior written permission. 20107492Sobrien * 21107492Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22107492Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23107492Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24107492Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25107492Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26107492Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27107492Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28107492Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29107492Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30107492Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31107492Sobrien */ 32107492Sobrien 33107492Sobrien#include <sys/param.h> 34107492Sobrien#include <sys/systm.h> 35107492Sobrien#include <sys/malloc.h> 36107492Sobrien#include <sys/module.h> 37107492Sobrien#include <sys/kernel.h> 38107492Sobrien#include <sys/queue.h> 39107492Sobrien#include <sys/types.h> 40107492Sobrien 41107492Sobrien#include <sys/bus.h> 42107492Sobrien#include <machine/bus.h> 43107492Sobrien#include <sys/rman.h> 44107492Sobrien#include <machine/resource.h> 45107492Sobrien 46107492Sobrien#include <dev/pccard/pccardreg.h> 47107492Sobrien#include <dev/pccard/pccardvar.h> 48107492Sobrien#include <dev/pccard/pccardvarp.h> 49107492Sobrien#include <dev/pccard/pccard_cis.h> 50107492Sobrien 51107492Sobrien#include "card_if.h" 52107492Sobrien 53107492Sobrienextern int pccard_cis_debug; 54107492Sobrien 55107492Sobrien#define PCCARDCISDEBUG 56107492Sobrien#ifdef PCCARDCISDEBUG 57107492Sobrien#define DPRINTF(arg) do { if (pccard_cis_debug) printf arg; } while (0) 58107492Sobrien#define DEVPRINTF(arg) do { if (pccard_cis_debug) device_printf arg; } while (0) 59107492Sobrien#else 60107492Sobrien#define DPRINTF(arg) 61107492Sobrien#define DEVPRINTF(arg) 62107492Sobrien#endif 63107492Sobrien 64107492Sobrien#define PCCARD_CIS_SIZE 4096 65107492Sobrien 66107492Sobrienstruct cis_state { 67107492Sobrien int count; 68107492Sobrien int gotmfc; 69107492Sobrien struct pccard_config_entry temp_cfe; 70107492Sobrien struct pccard_config_entry *default_cfe; 71107492Sobrien struct pccard_card *card; 72107492Sobrien struct pccard_function *pf; 73107492Sobrien}; 74107492Sobrien 75107492Sobrienstatic int pccard_parse_cis_tuple(const struct pccard_tuple *, void *); 76107492Sobrienstatic int decode_funce(const struct pccard_tuple *, struct pccard_function *); 77107492Sobrien 78107492Sobrienvoid 79107492Sobrienpccard_read_cis(struct pccard_softc *sc) 80107492Sobrien{ 81107492Sobrien struct cis_state state; 82107492Sobrien 83107492Sobrien bzero(&state, sizeof state); 84107492Sobrien state.card = &sc->card; 85107492Sobrien state.card->error = 0; 86107492Sobrien state.card->cis1_major = -1; 87107492Sobrien state.card->cis1_minor = -1; 88107492Sobrien state.card->cis1_info[0] = NULL; 89104834Sobrien state.card->cis1_info[1] = NULL; 90104834Sobrien state.card->cis1_info[2] = NULL; 91104834Sobrien state.card->cis1_info[3] = NULL; 92104834Sobrien state.card->manufacturer = PCMCIA_VENDOR_INVALID; 93104834Sobrien state.card->product = PCMCIA_PRODUCT_INVALID; 94104834Sobrien STAILQ_INIT(&state.card->pf_head); 95104834Sobrien state.pf = NULL; 96104834Sobrien 97104834Sobrien /* 98104834Sobrien * XXX The following shouldn't be needed, but some slow cards 99104834Sobrien * XXX seem to need it still. Need to investigate if there's 100104834Sobrien * XXX a way to tell if the card is 'ready' or not rather than 101104834Sobrien * XXX sleeping like this. We're called just after the power 102104834Sobrien * XXX up of the socket. The standard timing diagrams don't 103104834Sobrien * XXX seem to indicate that a delay is required. The old 104104834Sobrien * XXX delay was 1s. This delay is .1s. 105104834Sobrien */ 106104834Sobrien pause("pccard", hz / 10); 107104834Sobrien if (pccard_scan_cis(device_get_parent(sc->dev), sc->dev, 108104834Sobrien pccard_parse_cis_tuple, &state) == -1) 109104834Sobrien state.card->error++; 110104834Sobrien} 111104834Sobrien 112104834Sobrienint 113104834Sobrienpccard_scan_cis(device_t bus, device_t dev, pccard_scan_t fct, void *arg) 114104834Sobrien{ 115104834Sobrien struct resource *res; 116104834Sobrien int rid; 117104834Sobrien struct pccard_tuple tuple; 118104834Sobrien int longlink_present; 119104834Sobrien int longlink_common; 120104834Sobrien u_long longlink_addr; /* Type suspect */ 121104834Sobrien int mfc_count; 122104834Sobrien int mfc_index; 123104834Sobrien#ifdef PCCARDCISDEBUG 124104834Sobrien int cis_none_cnt = 10; /* Only report 10 CIS_NONEs */ 125104834Sobrien#endif 126104834Sobrien struct { 127104834Sobrien int common; 128104834Sobrien u_long addr; 129104834Sobrien } mfc[256 / 5]; 130104834Sobrien int ret; 131104834Sobrien 132104834Sobrien ret = 0; 133104834Sobrien 134104834Sobrien /* allocate some memory */ 135104834Sobrien 136104834Sobrien /* 137104834Sobrien * Some reports from the field suggest that a 64k memory boundary 138104834Sobrien * helps card CIS being able to be read. Try it here and see what 139104834Sobrien * the results actually are. I'm not sure I understand why this 140104834Sobrien * would make cards work better, but it is easy enough to test. 141104834Sobrien */ 142104834Sobrien rid = 0; 143104834Sobrien res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 144104834Sobrien PCCARD_CIS_SIZE, RF_ACTIVE | rman_make_alignment_flags(64*1024)); 145104834Sobrien if (res == NULL) { 146104834Sobrien device_printf(dev, "can't alloc memory to read attributes\n"); 147104834Sobrien return -1; 148104834Sobrien } 149104834Sobrien CARD_SET_RES_FLAGS(bus, dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 150104834Sobrien tuple.memt = rman_get_bustag(res); 151104834Sobrien tuple.memh = rman_get_bushandle(res); 152104834Sobrien tuple.ptr = 0; 153104834Sobrien 154104834Sobrien DPRINTF(("cis mem map %#x (resource: %#lx)\n", 155104834Sobrien (unsigned int) tuple.memh, rman_get_start(res))); 156104834Sobrien 157104834Sobrien tuple.mult = 2; 158104834Sobrien 159104834Sobrien longlink_present = 1; 160104834Sobrien longlink_common = 1; 161104834Sobrien longlink_addr = 0; 162104834Sobrien 163104834Sobrien mfc_count = 0; 164104834Sobrien mfc_index = 0; 165104834Sobrien 166104834Sobrien DEVPRINTF((dev, "CIS tuple chain:\n")); 167104834Sobrien 168104834Sobrien while (1) { 169104834Sobrien while (1) { 170104834Sobrien /* 171104834Sobrien * Perform boundary check for insane cards. 172104834Sobrien * If CIS is too long, simulate CIS end. 173104834Sobrien * (This check may not be sufficient for 174104834Sobrien * malicious cards.) 175104834Sobrien */ 176104834Sobrien if (tuple.mult * tuple.ptr >= PCCARD_CIS_SIZE - 1 177104834Sobrien - 32 /* ad hoc value */ ) { 178104834Sobrien printf("CIS is too long -- truncating\n"); 179104834Sobrien tuple.code = CISTPL_END; 180104834Sobrien } else { 181104834Sobrien /* get the tuple code */ 182104834Sobrien tuple.code = pccard_cis_read_1(&tuple, tuple.ptr); 183104834Sobrien } 184104834Sobrien 185104834Sobrien /* two special-case tuples */ 186104834Sobrien 187104834Sobrien if (tuple.code == CISTPL_NULL) { 188104834Sobrien#ifdef PCCARDCISDEBUG 189104834Sobrien if (cis_none_cnt > 0) 190104834Sobrien DPRINTF(("CISTPL_NONE\n 00\n")); 191104834Sobrien else if (cis_none_cnt == 0) 192104834Sobrien DPRINTF(("TOO MANY CIS_NONE\n")); 193104834Sobrien cis_none_cnt--; 194104834Sobrien#endif 195104834Sobrien if ((*fct)(&tuple, arg)) { 196104834Sobrien ret = 1; 197104834Sobrien goto done; 198104834Sobrien } 199104834Sobrien tuple.ptr++; 200104834Sobrien continue; 201104834Sobrien } else if (tuple.code == CISTPL_END) { 202104834Sobrien DPRINTF(("CISTPL_END\n ff\n")); 203104834Sobrien /* Call the function for the END tuple, since 204104834Sobrien the CIS semantics depend on it */ 205104834Sobrien if ((*fct)(&tuple, arg)) { 206104834Sobrien ret = 1; 207104834Sobrien goto done; 208104834Sobrien } 209104834Sobrien tuple.ptr++; 210104834Sobrien break; 211104834Sobrien } 212104834Sobrien /* now all the normal tuples */ 213104834Sobrien 214104834Sobrien tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1); 215104834Sobrien switch (tuple.code) { 216104834Sobrien case CISTPL_LONGLINK_A: 217104834Sobrien case CISTPL_LONGLINK_C: 218104834Sobrien if ((*fct)(&tuple, arg)) { 219104834Sobrien ret = 1; 220104834Sobrien goto done; 221104834Sobrien } 222104834Sobrien if (tuple.length < 4) { 223104834Sobrien DPRINTF(("CISTPL_LONGLINK_%s too " 224104834Sobrien "short %d\n", 225104834Sobrien longlink_common ? "C" : "A", 226104834Sobrien tuple.length)); 227104834Sobrien break; 228104834Sobrien } 229104834Sobrien longlink_present = 1; 230104834Sobrien longlink_common = (tuple.code == 231104834Sobrien CISTPL_LONGLINK_C) ? 1 : 0; 232104834Sobrien longlink_addr = pccard_tuple_read_4(&tuple, 0); 233104834Sobrien DPRINTF(("CISTPL_LONGLINK_%s %#lx\n", 234104834Sobrien longlink_common ? "C" : "A", 235104834Sobrien longlink_addr)); 236104834Sobrien break; 237104834Sobrien case CISTPL_NO_LINK: 238104834Sobrien if ((*fct)(&tuple, arg)) { 239104834Sobrien ret = 1; 240104834Sobrien goto done; 241104834Sobrien } 242104834Sobrien longlink_present = 0; 243104834Sobrien DPRINTF(("CISTPL_NO_LINK\n")); 244104834Sobrien break; 245104834Sobrien case CISTPL_CHECKSUM: 246104834Sobrien if ((*fct)(&tuple, arg)) { 247104834Sobrien ret = 1; 248104834Sobrien goto done; 249104834Sobrien } 250104834Sobrien if (tuple.length < 5) { 251104834Sobrien DPRINTF(("CISTPL_CHECKSUM too " 252104834Sobrien "short %d\n", tuple.length)); 253104834Sobrien break; 254104834Sobrien } { 255104834Sobrien int16_t offset; 256104834Sobrien u_long addr, length; 257104834Sobrien u_int cksum, sum; 258104834Sobrien int i; 259104834Sobrien 260104834Sobrien offset = (uint16_t) 261104834Sobrien pccard_tuple_read_2(&tuple, 0); 262104834Sobrien length = pccard_tuple_read_2(&tuple, 2); 263104834Sobrien cksum = pccard_tuple_read_1(&tuple, 4); 264104834Sobrien 265104834Sobrien addr = tuple.ptr + offset; 266104834Sobrien 267104834Sobrien DPRINTF(("CISTPL_CHECKSUM addr=%#lx " 268104834Sobrien "len=%#lx cksum=%#x", 269104834Sobrien addr, length, cksum)); 270104834Sobrien 271104834Sobrien /* 272104834Sobrien * XXX do more work to deal with 273104834Sobrien * distant regions 274104834Sobrien */ 275104834Sobrien if ((addr >= PCCARD_CIS_SIZE) || 276104834Sobrien ((addr + length) >= 277104834Sobrien PCCARD_CIS_SIZE)) { 278104834Sobrien DPRINTF((" skipped, " 279104834Sobrien "too distant\n")); 280104834Sobrien break; 281104834Sobrien } 282104834Sobrien sum = 0; 283104834Sobrien for (i = 0; i < length; i++) 284104834Sobrien sum += 285104834Sobrien bus_space_read_1(tuple.memt, 286104834Sobrien tuple.memh, 287104834Sobrien addr + tuple.mult * i); 288104834Sobrien if (cksum != (sum & 0xff)) { 289104834Sobrien DPRINTF((" failed sum=%#x\n", 290104834Sobrien sum)); 291104834Sobrien device_printf(dev, 292104834Sobrien "CIS checksum failed\n"); 293104834Sobrien#if 0 294104834Sobrien /* 295104834Sobrien * XXX Some working cards have 296104834Sobrien * XXX bad checksums!! 297104834Sobrien */ 298104834Sobrien ret = -1; 299104834Sobrien#endif 300104834Sobrien } else { 301104834Sobrien DPRINTF((" ok\n")); 302104834Sobrien } 303104834Sobrien } 304104834Sobrien break; 305104834Sobrien case CISTPL_LONGLINK_MFC: 306104834Sobrien if (tuple.length < 1) { 307104834Sobrien DPRINTF(("CISTPL_LONGLINK_MFC too " 308104834Sobrien "short %d\n", tuple.length)); 309104834Sobrien break; 310104834Sobrien } 311104834Sobrien if (((tuple.length - 1) % 5) != 0) { 312104834Sobrien DPRINTF(("CISTPL_LONGLINK_MFC bogus " 313104834Sobrien "length %d\n", tuple.length)); 314104834Sobrien break; 315104834Sobrien } 316104834Sobrien /* 317104834Sobrien * this is kind of ad hoc, as I don't have 318104834Sobrien * any real documentation 319104834Sobrien */ 320104834Sobrien { 321104834Sobrien int i, tmp_count; 322104834Sobrien 323104834Sobrien /* 324104834Sobrien * put count into tmp var so that 325104834Sobrien * if we have to bail (because it's 326104834Sobrien * a bogus count) it won't be 327104834Sobrien * remembered for later use. 328104834Sobrien */ 329104834Sobrien tmp_count = 330104834Sobrien pccard_tuple_read_1(&tuple, 0); 331104834Sobrien 332104834Sobrien DPRINTF(("CISTPL_LONGLINK_MFC %d", 333104834Sobrien tmp_count)); 334104834Sobrien 335104834Sobrien /* 336104834Sobrien * make _sure_ it's the right size; 337104834Sobrien * if too short, it may be a weird 338104834Sobrien * (unknown/undefined) format 339104834Sobrien */ 340104834Sobrien if (tuple.length != (tmp_count*5 + 1)) { 341104834Sobrien DPRINTF((" bogus length %d\n", 342104834Sobrien tuple.length)); 343104834Sobrien break; 344104834Sobrien } 345104834Sobrien /* 346104834Sobrien * sanity check for a programming 347104834Sobrien * error which is difficult to find 348104834Sobrien * when debugging. 349104834Sobrien */ 350104834Sobrien if (tmp_count > 351104834Sobrien howmany(sizeof mfc, sizeof mfc[0])) 352104834Sobrien panic("CISTPL_LONGLINK_MFC mfc " 353104834Sobrien "count would blow stack"); 354104834Sobrien mfc_count = tmp_count; 355104834Sobrien for (i = 0; i < mfc_count; i++) { 356104834Sobrien mfc[i].common = 357104834Sobrien (pccard_tuple_read_1(&tuple, 358104834Sobrien 1 + 5 * i) == 359104834Sobrien PCCARD_MFC_MEM_COMMON) ? 360104834Sobrien 1 : 0; 361104834Sobrien mfc[i].addr = 362104834Sobrien pccard_tuple_read_4(&tuple, 363104834Sobrien 1 + 5 * i + 1); 364104834Sobrien DPRINTF((" %s:%#lx", 365104834Sobrien mfc[i].common ? "common" : 366104834Sobrien "attr", mfc[i].addr)); 367104834Sobrien } 368104834Sobrien DPRINTF(("\n")); 369104834Sobrien } 370104834Sobrien /* 371104834Sobrien * for LONGLINK_MFC, fall through to the 372104834Sobrien * function. This tuple has structural and 373104834Sobrien * semantic content. 374104834Sobrien */ 375104834Sobrien default: 376104834Sobrien { 377104834Sobrien if ((*fct)(&tuple, arg)) { 378104834Sobrien ret = 1; 379104834Sobrien goto done; 380104834Sobrien } 381104834Sobrien } 382104834Sobrien break; 383104834Sobrien } /* switch */ 384104834Sobrien#ifdef PCCARDCISDEBUG 385104834Sobrien /* print the tuple */ 386104834Sobrien { 387104834Sobrien int i; 388104834Sobrien 389104834Sobrien DPRINTF((" %#02x %#02x", tuple.code, 390104834Sobrien tuple.length)); 391104834Sobrien 392104834Sobrien for (i = 0; i < tuple.length; i++) { 393104834Sobrien DPRINTF((" %#02x", 394104834Sobrien pccard_tuple_read_1(&tuple, i))); 395104834Sobrien if ((i % 16) == 13) 396104834Sobrien DPRINTF(("\n")); 397104834Sobrien } 398104834Sobrien 399104834Sobrien if ((i % 16) != 14) 400104834Sobrien DPRINTF(("\n")); 401104834Sobrien } 402104834Sobrien#endif 403104834Sobrien /* skip to the next tuple */ 404104834Sobrien tuple.ptr += 2 + tuple.length; 405104834Sobrien } 406104834Sobrien 407104834Sobrien /* 408104834Sobrien * the chain is done. Clean up and move onto the next one, 409104834Sobrien * if any. The loop is here in the case that there is an MFC 410104834Sobrien * card with no longlink (which defaults to existing, == 0). 411104834Sobrien * In general, this means that if one pointer fails, it will 412104834Sobrien * try the next one, instead of just bailing. 413104834Sobrien */ 414104834Sobrien while (1) { 415104834Sobrien if (longlink_present) { 416104834Sobrien CARD_SET_RES_FLAGS(bus, dev, SYS_RES_MEMORY, 417104834Sobrien rid, longlink_common ? 418104834Sobrien PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR); 419104834Sobrien DPRINTF(("cis mem map %#x\n", 420104834Sobrien (unsigned int) tuple.memh)); 421104834Sobrien tuple.mult = longlink_common ? 1 : 2; 422104834Sobrien tuple.ptr = longlink_addr; 423104834Sobrien longlink_present = 0; 424104834Sobrien longlink_common = 1; 425104834Sobrien longlink_addr = 0; 426104834Sobrien } else if (mfc_count && (mfc_index < mfc_count)) { 427104834Sobrien CARD_SET_RES_FLAGS(bus, dev, SYS_RES_MEMORY, 428104834Sobrien rid, mfc[mfc_index].common ? 429104834Sobrien PCCARD_A_MEM_COM : PCCARD_A_MEM_ATTR); 430104834Sobrien DPRINTF(("cis mem map %#x\n", 431104834Sobrien (unsigned int) tuple.memh)); 432104834Sobrien /* set parse state, and point at the next one */ 433104834Sobrien tuple.mult = mfc[mfc_index].common ? 1 : 2; 434104834Sobrien tuple.ptr = mfc[mfc_index].addr; 435104834Sobrien mfc_index++; 436104834Sobrien } else { 437104834Sobrien goto done; 438104834Sobrien } 439104834Sobrien 440104834Sobrien /* make sure that the link is valid */ 441104834Sobrien tuple.code = pccard_cis_read_1(&tuple, tuple.ptr); 442104834Sobrien if (tuple.code != CISTPL_LINKTARGET) { 443104834Sobrien DPRINTF(("CISTPL_LINKTARGET expected, " 444104834Sobrien "code %#02x observed\n", tuple.code)); 445104834Sobrien continue; 446104834Sobrien } 447104834Sobrien tuple.length = pccard_cis_read_1(&tuple, tuple.ptr + 1); 448104834Sobrien if (tuple.length < 3) { 449104834Sobrien DPRINTF(("CISTPL_LINKTARGET too short %d\n", 450104834Sobrien tuple.length)); 451104834Sobrien continue; 452104834Sobrien } 453104834Sobrien if ((pccard_tuple_read_1(&tuple, 0) != 'C') || 454104834Sobrien (pccard_tuple_read_1(&tuple, 1) != 'I') || 455104834Sobrien (pccard_tuple_read_1(&tuple, 2) != 'S')) { 456104834Sobrien DPRINTF(("CISTPL_LINKTARGET magic " 457104834Sobrien "%02x%02x%02x incorrect\n", 458104834Sobrien pccard_tuple_read_1(&tuple, 0), 459104834Sobrien pccard_tuple_read_1(&tuple, 1), 460104834Sobrien pccard_tuple_read_1(&tuple, 2))); 461104834Sobrien continue; 462104834Sobrien } 463104834Sobrien tuple.ptr += 2 + tuple.length; 464104834Sobrien break; 465104834Sobrien } 466104834Sobrien } 467104834Sobrien 468104834Sobriendone: 469104834Sobrien bus_release_resource(dev, SYS_RES_MEMORY, rid, res); 470104834Sobrien 471104834Sobrien return (ret); 472104834Sobrien} 473104834Sobrien 474104834Sobrien/* XXX this is incredibly verbose. Not sure what trt is */ 475104834Sobrien 476104834Sobrienvoid 477104834Sobrienpccard_print_cis(device_t dev) 478104834Sobrien{ 479104834Sobrien struct pccard_softc *sc = PCCARD_SOFTC(dev); 480104834Sobrien struct pccard_card *card = &sc->card; 481104834Sobrien struct pccard_function *pf; 482104834Sobrien struct pccard_config_entry *cfe; 483104834Sobrien int i; 484104834Sobrien 485104834Sobrien device_printf(dev, "CIS version "); 486104834Sobrien if (card->cis1_major == 4) { 487104834Sobrien if (card->cis1_minor == 0) 488104834Sobrien printf("PCCARD 1.0\n"); 489104834Sobrien else if (card->cis1_minor == 1) 490104834Sobrien printf("PCCARD 2.0 or 2.1\n"); 491104834Sobrien } else if (card->cis1_major >= 5) 492104834Sobrien printf("PC Card Standard %d.%d\n", card->cis1_major, card->cis1_minor); 493104834Sobrien else 494104834Sobrien printf("unknown (major=%d, minor=%d)\n", 495104834Sobrien card->cis1_major, card->cis1_minor); 496104834Sobrien 497104834Sobrien device_printf(dev, "CIS info: "); 498104834Sobrien for (i = 0; i < 4; i++) { 499104834Sobrien if (card->cis1_info[i] == NULL) 500104834Sobrien break; 501104834Sobrien if (i) 502104834Sobrien printf(", "); 503104834Sobrien printf("%s", card->cis1_info[i]); 504104834Sobrien } 505104834Sobrien printf("\n"); 506104834Sobrien 507104834Sobrien device_printf(dev, "Manufacturer code %#x, product %#x\n", 508104834Sobrien card->manufacturer, card->product); 509104834Sobrien 510104834Sobrien STAILQ_FOREACH(pf, &card->pf_head, pf_list) { 511104834Sobrien device_printf(dev, "function %d: ", pf->number); 512104834Sobrien 513104834Sobrien switch (pf->function) { 514104834Sobrien case PCCARD_FUNCTION_UNSPEC: 515104834Sobrien printf("unspecified"); 516104834Sobrien break; 517104834Sobrien case PCCARD_FUNCTION_MULTIFUNCTION: 518104834Sobrien printf("multi-function"); 519104834Sobrien break; 520104834Sobrien case PCCARD_FUNCTION_MEMORY: 521104834Sobrien printf("memory"); 522104834Sobrien break; 523104834Sobrien case PCCARD_FUNCTION_SERIAL: 524104834Sobrien printf("serial port"); 525104834Sobrien break; 526104834Sobrien case PCCARD_FUNCTION_PARALLEL: 527104834Sobrien printf("parallel port"); 528104834Sobrien break; 529104834Sobrien case PCCARD_FUNCTION_DISK: 530104834Sobrien printf("fixed disk"); 531104834Sobrien break; 532104834Sobrien case PCCARD_FUNCTION_VIDEO: 533104834Sobrien printf("video adapter"); 534104834Sobrien break; 535104834Sobrien case PCCARD_FUNCTION_NETWORK: 536104834Sobrien printf("network adapter"); 537104834Sobrien break; 538104834Sobrien case PCCARD_FUNCTION_AIMS: 539104834Sobrien printf("auto incrementing mass storage"); 540104834Sobrien break; 541104834Sobrien case PCCARD_FUNCTION_SCSI: 542104834Sobrien printf("SCSI bridge"); 543104834Sobrien break; 544104834Sobrien case PCCARD_FUNCTION_SECURITY: 545104834Sobrien printf("Security services"); 546104834Sobrien break; 547104834Sobrien case PCCARD_FUNCTION_INSTRUMENT: 548104834Sobrien printf("Instrument"); 549104834Sobrien break; 550104834Sobrien default: 551104834Sobrien printf("unknown (%d)", pf->function); 552104834Sobrien break; 553104834Sobrien } 554104834Sobrien 555104834Sobrien printf(", ccr addr %#x mask %#x\n", pf->ccr_base, pf->ccr_mask); 556104834Sobrien 557104834Sobrien STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) { 558104834Sobrien device_printf(dev, "function %d, config table entry " 559104834Sobrien "%d: ", pf->number, cfe->number); 560104834Sobrien 561104834Sobrien switch (cfe->iftype) { 562104834Sobrien case PCCARD_IFTYPE_MEMORY: 563104834Sobrien printf("memory card"); 564104834Sobrien break; 565104834Sobrien case PCCARD_IFTYPE_IO: 566104834Sobrien printf("I/O card"); 567104834Sobrien break; 568104834Sobrien default: 569104834Sobrien printf("card type unknown"); 570104834Sobrien break; 571104834Sobrien } 572104834Sobrien 573104834Sobrien printf("; irq mask %#x", cfe->irqmask); 574104834Sobrien 575104834Sobrien if (cfe->num_iospace) { 576104834Sobrien printf("; iomask %#lx, iospace", cfe->iomask); 577104834Sobrien 578104834Sobrien for (i = 0; i < cfe->num_iospace; i++) { 579104834Sobrien printf(" %#lx", cfe->iospace[i].start); 580104834Sobrien if (cfe->iospace[i].length) 581104834Sobrien printf("-%#lx", 582104834Sobrien cfe->iospace[i].start + 583104834Sobrien cfe->iospace[i].length - 1); 584104834Sobrien } 585104834Sobrien } 586104834Sobrien if (cfe->num_memspace) { 587104834Sobrien printf("; memspace"); 588104834Sobrien 589104834Sobrien for (i = 0; i < cfe->num_memspace; i++) { 590104834Sobrien printf(" %#lx", 591104834Sobrien cfe->memspace[i].cardaddr); 592104834Sobrien if (cfe->memspace[i].length) 593104834Sobrien printf("-%#lx", 594104834Sobrien cfe->memspace[i].cardaddr + 595104834Sobrien cfe->memspace[i].length - 1); 596104834Sobrien if (cfe->memspace[i].hostaddr) 597104834Sobrien printf("@%#lx", 598104834Sobrien cfe->memspace[i].hostaddr); 599104834Sobrien } 600104834Sobrien } 601104834Sobrien if (cfe->maxtwins) 602104834Sobrien printf("; maxtwins %d", cfe->maxtwins); 603104834Sobrien 604104834Sobrien printf(";"); 605104834Sobrien 606104834Sobrien if (cfe->flags & PCCARD_CFE_MWAIT_REQUIRED) 607104834Sobrien printf(" mwait_required"); 608104834Sobrien if (cfe->flags & PCCARD_CFE_RDYBSY_ACTIVE) 609104834Sobrien printf(" rdybsy_active"); 610104834Sobrien if (cfe->flags & PCCARD_CFE_WP_ACTIVE) 611104834Sobrien printf(" wp_active"); 612104834Sobrien if (cfe->flags & PCCARD_CFE_BVD_ACTIVE) 613104834Sobrien printf(" bvd_active"); 614104834Sobrien if (cfe->flags & PCCARD_CFE_IO8) 615104834Sobrien printf(" io8"); 616104834Sobrien if (cfe->flags & PCCARD_CFE_IO16) 617104834Sobrien printf(" io16"); 618104834Sobrien if (cfe->flags & PCCARD_CFE_IRQSHARE) 619104834Sobrien printf(" irqshare"); 620104834Sobrien if (cfe->flags & PCCARD_CFE_IRQPULSE) 621104834Sobrien printf(" irqpulse"); 622104834Sobrien if (cfe->flags & PCCARD_CFE_IRQLEVEL) 623104834Sobrien printf(" irqlevel"); 624104834Sobrien if (cfe->flags & PCCARD_CFE_POWERDOWN) 625104834Sobrien printf(" powerdown"); 626104834Sobrien if (cfe->flags & PCCARD_CFE_READONLY) 627104834Sobrien printf(" readonly"); 628104834Sobrien if (cfe->flags & PCCARD_CFE_AUDIO) 629104834Sobrien printf(" audio"); 630104834Sobrien 631104834Sobrien printf("\n"); 632104834Sobrien } 633104834Sobrien } 634104834Sobrien 635104834Sobrien if (card->error) 636104834Sobrien device_printf(dev, "%d errors found while parsing CIS\n", 637104834Sobrien card->error); 638104834Sobrien} 639104834Sobrien 640104834Sobrienstatic int 641104834Sobrienpccard_parse_cis_tuple(const struct pccard_tuple *tuple, void *arg) 642104834Sobrien{ 643104834Sobrien /* most of these are educated guesses */ 644104834Sobrien static struct pccard_config_entry init_cfe = { 645104834Sobrien -1, PCCARD_CFE_RDYBSY_ACTIVE | PCCARD_CFE_WP_ACTIVE | 646104834Sobrien PCCARD_CFE_BVD_ACTIVE, PCCARD_IFTYPE_MEMORY, 647104834Sobrien }; 648104834Sobrien 649104834Sobrien struct cis_state *state = arg; 650104834Sobrien 651104834Sobrien switch (tuple->code) { 652104834Sobrien case CISTPL_END: 653104834Sobrien /* if we've seen a LONGLINK_MFC, and this is the first 654104834Sobrien * END after it, reset the function list. 655104834Sobrien * 656104834Sobrien * XXX This might also be the right place to start a 657104834Sobrien * new function, but that assumes that a function 658104834Sobrien * definition never crosses any longlink, and I'm not 659104834Sobrien * sure about that. This is probably safe for MFC 660104834Sobrien * cards, but what we have now isn't broken, so I'd 661104834Sobrien * rather not change it. 662104834Sobrien */ 663104834Sobrien if (state->gotmfc == 1) { 664104834Sobrien struct pccard_function *pf, *pfnext; 665104834Sobrien 666104834Sobrien for (pf = STAILQ_FIRST(&state->card->pf_head); 667104834Sobrien pf != NULL; pf = pfnext) { 668104834Sobrien pfnext = STAILQ_NEXT(pf, pf_list); 669104834Sobrien free(pf, M_DEVBUF); 670104834Sobrien } 671104834Sobrien 672104834Sobrien STAILQ_INIT(&state->card->pf_head); 673104834Sobrien 674104834Sobrien state->count = 0; 675104834Sobrien state->gotmfc = 2; 676104834Sobrien state->pf = NULL; 677104834Sobrien } 678104834Sobrien break; 679104834Sobrien case CISTPL_LONGLINK_MFC: 680104834Sobrien /* 681104834Sobrien * this tuple's structure was dealt with in scan_cis. here, 682104834Sobrien * record the fact that the MFC tuple was seen, so that 683104834Sobrien * functions declared before the MFC link can be cleaned 684104834Sobrien * up. 685104834Sobrien */ 686104834Sobrien state->gotmfc = 1; 687104834Sobrien break; 688104834Sobrien#ifdef PCCARDCISDEBUG 689104834Sobrien case CISTPL_DEVICE: 690104834Sobrien case CISTPL_DEVICE_A: 691104834Sobrien { 692104834Sobrien u_int reg, dtype, dspeed; 693104834Sobrien 694104834Sobrien reg = pccard_tuple_read_1(tuple, 0); 695104834Sobrien dtype = reg & PCCARD_DTYPE_MASK; 696104834Sobrien dspeed = reg & PCCARD_DSPEED_MASK; 697104834Sobrien 698104834Sobrien DPRINTF(("CISTPL_DEVICE%s type=", 699104834Sobrien (tuple->code == CISTPL_DEVICE) ? "" : "_A")); 700104834Sobrien switch (dtype) { 701104834Sobrien case PCCARD_DTYPE_NULL: 702104834Sobrien DPRINTF(("null")); 703104834Sobrien break; 704104834Sobrien case PCCARD_DTYPE_ROM: 705104834Sobrien DPRINTF(("rom")); 706104834Sobrien break; 707104834Sobrien case PCCARD_DTYPE_OTPROM: 708104834Sobrien DPRINTF(("otprom")); 709104834Sobrien break; 710104834Sobrien case PCCARD_DTYPE_EPROM: 711104834Sobrien DPRINTF(("eprom")); 712104834Sobrien break; 713104834Sobrien case PCCARD_DTYPE_EEPROM: 714104834Sobrien DPRINTF(("eeprom")); 715104834Sobrien break; 716104834Sobrien case PCCARD_DTYPE_FLASH: 717104834Sobrien DPRINTF(("flash")); 718104834Sobrien break; 719104834Sobrien case PCCARD_DTYPE_SRAM: 720104834Sobrien DPRINTF(("sram")); 721104834Sobrien break; 722104834Sobrien case PCCARD_DTYPE_DRAM: 723104834Sobrien DPRINTF(("dram")); 724104834Sobrien break; 725104834Sobrien case PCCARD_DTYPE_FUNCSPEC: 726104834Sobrien DPRINTF(("funcspec")); 727104834Sobrien break; 728104834Sobrien case PCCARD_DTYPE_EXTEND: 729104834Sobrien DPRINTF(("extend")); 730104834Sobrien break; 731104834Sobrien default: 732104834Sobrien DPRINTF(("reserved")); 733104834Sobrien break; 734104834Sobrien } 735104834Sobrien DPRINTF((" speed=")); 736104834Sobrien switch (dspeed) { 737104834Sobrien case PCCARD_DSPEED_NULL: 738104834Sobrien DPRINTF(("null")); 739104834Sobrien break; 740104834Sobrien case PCCARD_DSPEED_250NS: 741104834Sobrien DPRINTF(("250ns")); 742104834Sobrien break; 743104834Sobrien case PCCARD_DSPEED_200NS: 744104834Sobrien DPRINTF(("200ns")); 745104834Sobrien break; 746104834Sobrien case PCCARD_DSPEED_150NS: 747104834Sobrien DPRINTF(("150ns")); 748104834Sobrien break; 749104834Sobrien case PCCARD_DSPEED_100NS: 750104834Sobrien DPRINTF(("100ns")); 751104834Sobrien break; 752104834Sobrien case PCCARD_DSPEED_EXT: 753104834Sobrien DPRINTF(("ext")); 754104834Sobrien break; 755104834Sobrien default: 756104834Sobrien DPRINTF(("reserved")); 757104834Sobrien break; 758104834Sobrien } 759104834Sobrien } 760104834Sobrien DPRINTF(("\n")); 761104834Sobrien break; 762104834Sobrien#endif 763104834Sobrien case CISTPL_VERS_1: 764104834Sobrien if (tuple->length < 6) { 765104834Sobrien DPRINTF(("CISTPL_VERS_1 too short %d\n", 766104834Sobrien tuple->length)); 767104834Sobrien break; 768104834Sobrien } { 769104834Sobrien int start, i, ch, count; 770104834Sobrien 771104834Sobrien state->card->cis1_major = pccard_tuple_read_1(tuple, 0); 772104834Sobrien state->card->cis1_minor = pccard_tuple_read_1(tuple, 1); 773104834Sobrien 774104834Sobrien for (count = 0, start = 0, i = 0; 775104834Sobrien (count < 4) && ((i + 4) < 256); i++) { 776104834Sobrien ch = pccard_tuple_read_1(tuple, 2 + i); 777104834Sobrien if (ch == 0xff) 778104834Sobrien break; 779104834Sobrien state->card->cis1_info_buf[i] = ch; 780104834Sobrien if (ch == 0) { 781104834Sobrien state->card->cis1_info[count] = 782104834Sobrien state->card->cis1_info_buf + start; 783104834Sobrien start = i + 1; 784104834Sobrien count++; 785104834Sobrien } 786104834Sobrien } 787104834Sobrien DPRINTF(("CISTPL_VERS_1\n")); 788104834Sobrien } 789104834Sobrien break; 790104834Sobrien case CISTPL_MANFID: 791104834Sobrien if (tuple->length < 4) { 792104834Sobrien DPRINTF(("CISTPL_MANFID too short %d\n", 793104834Sobrien tuple->length)); 794104834Sobrien break; 795104834Sobrien } 796104834Sobrien state->card->manufacturer = pccard_tuple_read_2(tuple, 0); 797104834Sobrien state->card->product = pccard_tuple_read_2(tuple, 2); 798104834Sobrien /* 799104834Sobrien * This is for xe driver. But not limited to that driver. 800104834Sobrien * In PC Card Standard, 801104834Sobrien * Manufacturer ID: 2byte. 802104834Sobrien * Product ID: typically 2bytes, but there's no limit on its 803104834Sobrien * size. prodext is a two byte field, so maybe we should 804104834Sobrien * also handle the '6' case. So far no cards have surfaced 805104834Sobrien * with a length of '6'. 806104834Sobrien */ 807104834Sobrien if (tuple->length == 5 ) 808104834Sobrien state->card->prodext = pccard_tuple_read_1(tuple, 4); 809104834Sobrien DPRINTF(("CISTPL_MANFID\n")); 810104834Sobrien break; 811104834Sobrien case CISTPL_FUNCID: 812104834Sobrien if (tuple->length < 1) { 813104834Sobrien DPRINTF(("CISTPL_FUNCID too short %d\n", 814104834Sobrien tuple->length)); 815104834Sobrien break; 816104834Sobrien } 817104834Sobrien if ((state->pf == NULL) || (state->gotmfc == 2)) { 818104834Sobrien state->pf = malloc(sizeof(*state->pf), M_DEVBUF, 819104834Sobrien M_NOWAIT | M_ZERO); 820104834Sobrien state->pf->number = state->count++; 821104834Sobrien state->pf->last_config_index = -1; 822104834Sobrien STAILQ_INIT(&state->pf->cfe_head); 823104834Sobrien 824104834Sobrien STAILQ_INSERT_TAIL(&state->card->pf_head, state->pf, 825104834Sobrien pf_list); 826104834Sobrien } 827104834Sobrien state->pf->function = pccard_tuple_read_1(tuple, 0); 828104834Sobrien 829104834Sobrien DPRINTF(("CISTPL_FUNCID\n")); 830104834Sobrien break; 831104834Sobrien case CISTPL_FUNCE: 832104834Sobrien if (state->pf == NULL || state->pf->function <= 0) { 833104834Sobrien DPRINTF(("CISTPL_FUNCE is not followed by " 834104834Sobrien "valid CISTPL_FUNCID\n")); 835104834Sobrien break; 836104834Sobrien } 837104834Sobrien if (tuple->length >= 2) 838104834Sobrien decode_funce(tuple, state->pf); 839104834Sobrien DPRINTF(("CISTPL_FUNCE\n")); 840104834Sobrien break; 841104834Sobrien case CISTPL_CONFIG: 842104834Sobrien if (tuple->length < 3) { 843104834Sobrien DPRINTF(("CISTPL_CONFIG too short %d\n", 844104834Sobrien tuple->length)); 845104834Sobrien break; 846104834Sobrien } { 847104834Sobrien u_int reg, rasz, rmsz, rfsz; 848104834Sobrien int i; 849104834Sobrien 850104834Sobrien reg = pccard_tuple_read_1(tuple, 0); 851104834Sobrien rasz = 1 + ((reg & PCCARD_TPCC_RASZ_MASK) >> 852104834Sobrien PCCARD_TPCC_RASZ_SHIFT); 853104834Sobrien rmsz = 1 + ((reg & PCCARD_TPCC_RMSZ_MASK) >> 854104834Sobrien PCCARD_TPCC_RMSZ_SHIFT); 855104834Sobrien rfsz = ((reg & PCCARD_TPCC_RFSZ_MASK) >> 856104834Sobrien PCCARD_TPCC_RFSZ_SHIFT); 857104834Sobrien 858104834Sobrien if (tuple->length < (rasz + rmsz + rfsz)) { 859104834Sobrien DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too " 860104834Sobrien "short %d\n", rasz, rmsz, rfsz, 861104834Sobrien tuple->length)); 862104834Sobrien break; 863104834Sobrien } 864104834Sobrien if (state->pf == NULL) { 865104834Sobrien state->pf = malloc(sizeof(*state->pf), 866104834Sobrien M_DEVBUF, M_NOWAIT | M_ZERO); 867104834Sobrien state->pf->number = state->count++; 868104834Sobrien state->pf->last_config_index = -1; 869104834Sobrien STAILQ_INIT(&state->pf->cfe_head); 870104834Sobrien 871104834Sobrien STAILQ_INSERT_TAIL(&state->card->pf_head, 872104834Sobrien state->pf, pf_list); 873104834Sobrien 874104834Sobrien state->pf->function = PCCARD_FUNCTION_UNSPEC; 875104834Sobrien } 876104834Sobrien state->pf->last_config_index = 877104834Sobrien pccard_tuple_read_1(tuple, 1); 878104834Sobrien 879104834Sobrien state->pf->ccr_base = 0; 880104834Sobrien for (i = 0; i < rasz; i++) 881104834Sobrien state->pf->ccr_base |= 882104834Sobrien ((pccard_tuple_read_1(tuple, 2 + i)) << 883104834Sobrien (i * 8)); 884104834Sobrien 885104834Sobrien state->pf->ccr_mask = 0; 886104834Sobrien for (i = 0; i < rmsz; i++) 887104834Sobrien state->pf->ccr_mask |= 888104834Sobrien ((pccard_tuple_read_1(tuple, 889104834Sobrien 2 + rasz + i)) << (i * 8)); 890104834Sobrien 891104834Sobrien /* skip the reserved area and subtuples */ 892104834Sobrien 893104834Sobrien /* reset the default cfe for each cfe list */ 894104834Sobrien state->temp_cfe = init_cfe; 895104834Sobrien state->default_cfe = &state->temp_cfe; 896104834Sobrien } 897104834Sobrien DPRINTF(("CISTPL_CONFIG\n")); 898104834Sobrien break; 899104834Sobrien case CISTPL_CFTABLE_ENTRY: 900104834Sobrien { 901104834Sobrien int idx, i; 902104834Sobrien u_int reg, reg2; 903104834Sobrien u_int intface, def, num; 904104834Sobrien u_int power, timing, iospace, irq, memspace, misc; 905104834Sobrien struct pccard_config_entry *cfe; 906104834Sobrien 907104834Sobrien idx = 0; 908104834Sobrien 909104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 910104834Sobrien intface = reg & PCCARD_TPCE_INDX_INTFACE; 911104834Sobrien def = reg & PCCARD_TPCE_INDX_DEFAULT; 912104834Sobrien num = reg & PCCARD_TPCE_INDX_NUM_MASK; 913104834Sobrien 914104834Sobrien /* 915104834Sobrien * this is a little messy. Some cards have only a 916104834Sobrien * cfentry with the default bit set. So, as we go 917104834Sobrien * through the list, we add new indexes to the queue, 918104834Sobrien * and keep a pointer to the last one with the 919104834Sobrien * default bit set. if we see a record with the same 920104834Sobrien * index, as the default, we stash the default and 921104834Sobrien * replace the queue entry. otherwise, we just add 922104834Sobrien * new entries to the queue, pointing the default ptr 923104834Sobrien * at them if the default bit is set. if we get to 924104834Sobrien * the end with the default pointer pointing at a 925104834Sobrien * record which hasn't had a matching index, that's 926104834Sobrien * ok; it just becomes a cfentry like any other. 927104834Sobrien */ 928104834Sobrien 929104834Sobrien /* 930104834Sobrien * if the index in the cis differs from the default 931104834Sobrien * cis, create new entry in the queue and start it 932104834Sobrien * with the current default 933104834Sobrien */ 934104834Sobrien if (num != state->default_cfe->number) { 935104834Sobrien cfe = (struct pccard_config_entry *) 936104834Sobrien malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT); 937104834Sobrien if (cfe == NULL) { 938104834Sobrien DPRINTF(("no memory for config entry\n")); 939104834Sobrien goto abort_cfe; 940104834Sobrien } 941104834Sobrien *cfe = *state->default_cfe; 942104834Sobrien 943104834Sobrien STAILQ_INSERT_TAIL(&state->pf->cfe_head, 944104834Sobrien cfe, cfe_list); 945104834Sobrien 946104834Sobrien cfe->number = num; 947104834Sobrien 948104834Sobrien /* 949104834Sobrien * if the default bit is set in the cis, then 950104834Sobrien * point the new default at whatever is being 951104834Sobrien * filled in 952104834Sobrien */ 953104834Sobrien if (def) 954104834Sobrien state->default_cfe = cfe; 955104834Sobrien } else { 956104834Sobrien /* 957104834Sobrien * the cis index matches the default index, 958104834Sobrien * fill in the default cfentry. It is 959104834Sobrien * assumed that the cfdefault index is in the 960104834Sobrien * queue. For it to be otherwise, the cis 961104834Sobrien * index would have to be -1 (initial 962104834Sobrien * condition) which is not possible, or there 963104834Sobrien * would have to be a preceding cis entry 964104834Sobrien * which had the same cis index and had the 965104834Sobrien * default bit unset. Neither condition 966104834Sobrien * should happen. If it does, this cfentry 967104834Sobrien * is lost (written into temp space), which 968104834Sobrien * is an acceptable failure mode. 969104834Sobrien */ 970104834Sobrien 971104834Sobrien cfe = state->default_cfe; 972104834Sobrien 973104834Sobrien /* 974104834Sobrien * if the cis entry does not have the default 975104834Sobrien * bit set, copy the default out of the way 976104834Sobrien * first. 977104834Sobrien */ 978104834Sobrien if (!def) { 979104834Sobrien state->temp_cfe = *state->default_cfe; 980104834Sobrien state->default_cfe = &state->temp_cfe; 981104834Sobrien } 982104834Sobrien } 983104834Sobrien 984104834Sobrien if (intface) { 985104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 986104834Sobrien cfe->flags &= ~(PCCARD_CFE_MWAIT_REQUIRED 987104834Sobrien | PCCARD_CFE_RDYBSY_ACTIVE 988104834Sobrien | PCCARD_CFE_WP_ACTIVE 989104834Sobrien | PCCARD_CFE_BVD_ACTIVE); 990104834Sobrien if (reg & PCCARD_TPCE_IF_MWAIT) 991104834Sobrien cfe->flags |= PCCARD_CFE_MWAIT_REQUIRED; 992104834Sobrien if (reg & PCCARD_TPCE_IF_RDYBSY) 993104834Sobrien cfe->flags |= PCCARD_CFE_RDYBSY_ACTIVE; 994104834Sobrien if (reg & PCCARD_TPCE_IF_WP) 995104834Sobrien cfe->flags |= PCCARD_CFE_WP_ACTIVE; 996104834Sobrien if (reg & PCCARD_TPCE_IF_BVD) 997104834Sobrien cfe->flags |= PCCARD_CFE_BVD_ACTIVE; 998104834Sobrien cfe->iftype = reg & PCCARD_TPCE_IF_IFTYPE; 999104834Sobrien } 1000104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 1001104834Sobrien 1002104834Sobrien power = reg & PCCARD_TPCE_FS_POWER_MASK; 1003104834Sobrien timing = reg & PCCARD_TPCE_FS_TIMING; 1004104834Sobrien iospace = reg & PCCARD_TPCE_FS_IOSPACE; 1005104834Sobrien irq = reg & PCCARD_TPCE_FS_IRQ; 1006104834Sobrien memspace = reg & PCCARD_TPCE_FS_MEMSPACE_MASK; 1007104834Sobrien misc = reg & PCCARD_TPCE_FS_MISC; 1008104834Sobrien 1009104834Sobrien if (power) { 1010104834Sobrien /* skip over power, don't save */ 1011104834Sobrien /* for each parameter selection byte */ 1012104834Sobrien for (i = 0; i < power; i++) { 1013104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 1014104834Sobrien for (; reg; reg >>= 1) 1015104834Sobrien { 1016104834Sobrien /* set bit -> read */ 101799461Sobrien if ((reg & 1) == 0) 101899461Sobrien continue; 1019104834Sobrien /* skip over bytes */ 1020104834Sobrien do { 1021104834Sobrien reg2 = pccard_tuple_read_1(tuple, idx++); 1022104834Sobrien /* 1023104834Sobrien * until non-extension 1024104834Sobrien * byte 102599461Sobrien */ 102699461Sobrien } while (reg2 & 0x80); 102799461Sobrien } 1028104834Sobrien } 1029104834Sobrien } 1030104834Sobrien if (timing) { 1031104834Sobrien /* skip over timing, don't save */ 103299461Sobrien reg = pccard_tuple_read_1(tuple, idx++); 103399461Sobrien 103499461Sobrien if ((reg & PCCARD_TPCE_TD_RESERVED_MASK) != 103599461Sobrien PCCARD_TPCE_TD_RESERVED_MASK) 103699461Sobrien idx++; 103799461Sobrien if ((reg & PCCARD_TPCE_TD_RDYBSY_MASK) != 103899461Sobrien PCCARD_TPCE_TD_RDYBSY_MASK) 103999461Sobrien idx++; 104099461Sobrien if ((reg & PCCARD_TPCE_TD_WAIT_MASK) != 104199461Sobrien PCCARD_TPCE_TD_WAIT_MASK) 104299461Sobrien idx++; 104399461Sobrien } 104499461Sobrien if (iospace) { 1045104834Sobrien if (tuple->length <= idx) { 1046104834Sobrien DPRINTF(("ran out of space before TCPE_IO\n")); 1047104834Sobrien goto abort_cfe; 1048104834Sobrien } 1049104834Sobrien 1050104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 1051104834Sobrien cfe->flags &= 1052104834Sobrien ~(PCCARD_CFE_IO8 | PCCARD_CFE_IO16); 1053104834Sobrien if (reg & PCCARD_TPCE_IO_BUSWIDTH_8BIT) 1054104834Sobrien cfe->flags |= PCCARD_CFE_IO8; 1055104834Sobrien if (reg & PCCARD_TPCE_IO_BUSWIDTH_16BIT) 1056104834Sobrien cfe->flags |= PCCARD_CFE_IO16; 1057104834Sobrien cfe->iomask = 1058104834Sobrien reg & PCCARD_TPCE_IO_IOADDRLINES_MASK; 1059104834Sobrien 1060104834Sobrien if (reg & PCCARD_TPCE_IO_HASRANGE) { 1061104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 1062104834Sobrien cfe->num_iospace = 1 + (reg & 1063104834Sobrien PCCARD_TPCE_IO_RANGE_COUNT); 1064104834Sobrien 1065104834Sobrien if (cfe->num_iospace > 1066104834Sobrien (sizeof(cfe->iospace) / 1067104834Sobrien sizeof(cfe->iospace[0]))) { 1068104834Sobrien DPRINTF(("too many io " 1069104834Sobrien "spaces %d", 1070104834Sobrien cfe->num_iospace)); 1071104834Sobrien state->card->error++; 1072104834Sobrien break; 1073104834Sobrien } 1074104834Sobrien for (i = 0; i < cfe->num_iospace; i++) { 1075104834Sobrien switch (reg & PCCARD_TPCE_IO_RANGE_ADDRSIZE_MASK) { 1076104834Sobrien case PCCARD_TPCE_IO_RANGE_ADDRSIZE_ONE: 107799461Sobrien cfe->iospace[i].start = 107899461Sobrien pccard_tuple_read_1(tuple, idx++); 107999461Sobrien break; 108099461Sobrien case PCCARD_TPCE_IO_RANGE_ADDRSIZE_TWO: 108199461Sobrien cfe->iospace[i].start = 1082104834Sobrien pccard_tuple_read_2(tuple, idx); 1083104834Sobrien idx += 2; 108499461Sobrien break; 108599461Sobrien case PCCARD_TPCE_IO_RANGE_ADDRSIZE_FOUR: 108699461Sobrien cfe->iospace[i].start = 1087104834Sobrien pccard_tuple_read_4(tuple, idx); 108899461Sobrien idx += 4; 1089104834Sobrien break; 1090104834Sobrien } 109199461Sobrien switch (reg & 1092104834Sobrien PCCARD_TPCE_IO_RANGE_LENGTHSIZE_MASK) { 109399461Sobrien case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_ONE: 1094104834Sobrien cfe->iospace[i].length = 1095104834Sobrien pccard_tuple_read_1(tuple, idx++); 1096104834Sobrien break; 1097104834Sobrien case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_TWO: 1098104834Sobrien cfe->iospace[i].length = 1099104834Sobrien pccard_tuple_read_2(tuple, idx); 1100104834Sobrien idx += 2; 1101104834Sobrien break; 1102104834Sobrien case PCCARD_TPCE_IO_RANGE_LENGTHSIZE_FOUR: 1103104834Sobrien cfe->iospace[i].length = 1104104834Sobrien pccard_tuple_read_4(tuple, idx); 1105104834Sobrien idx += 4; 1106104834Sobrien break; 1107104834Sobrien } 1108104834Sobrien cfe->iospace[i].length++; 1109104834Sobrien } 1110104834Sobrien } else { 1111104834Sobrien cfe->num_iospace = 1; 1112104834Sobrien cfe->iospace[0].start = 0; 1113104834Sobrien cfe->iospace[0].length = 1114104834Sobrien (1 << cfe->iomask); 1115104834Sobrien } 111699461Sobrien } 111799461Sobrien if (irq) { 111899461Sobrien if (tuple->length <= idx) { 111999461Sobrien DPRINTF(("ran out of space before TCPE_IR\n")); 112099461Sobrien goto abort_cfe; 1121104834Sobrien } 1122104834Sobrien 1123104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 1124104834Sobrien cfe->flags &= ~(PCCARD_CFE_IRQSHARE 1125104834Sobrien | PCCARD_CFE_IRQPULSE 1126104834Sobrien | PCCARD_CFE_IRQLEVEL); 1127104834Sobrien if (reg & PCCARD_TPCE_IR_SHARE) 1128104834Sobrien cfe->flags |= PCCARD_CFE_IRQSHARE; 1129104834Sobrien if (reg & PCCARD_TPCE_IR_PULSE) 1130104834Sobrien cfe->flags |= PCCARD_CFE_IRQPULSE; 1131104834Sobrien if (reg & PCCARD_TPCE_IR_LEVEL) 1132104834Sobrien cfe->flags |= PCCARD_CFE_IRQLEVEL; 1133104834Sobrien 1134104834Sobrien if (reg & PCCARD_TPCE_IR_HASMASK) { 1135104834Sobrien /* 1136104834Sobrien * it's legal to ignore the 1137104834Sobrien * special-interrupt bits, so I will 1138104834Sobrien */ 1139104834Sobrien 1140104834Sobrien cfe->irqmask = 1141104834Sobrien pccard_tuple_read_2(tuple, idx); 1142104834Sobrien idx += 2; 1143104834Sobrien } else { 114499461Sobrien cfe->irqmask = 114599461Sobrien (1 << (reg & PCCARD_TPCE_IR_IRQ)); 114699461Sobrien } 114799461Sobrien } else { 114899461Sobrien cfe->irqmask = 0xffff; 1149104834Sobrien } 115099461Sobrien if (memspace) { 1151104834Sobrien if (tuple->length <= idx) { 1152104834Sobrien DPRINTF(("ran out of space before TCPE_MS\n")); 115399461Sobrien goto abort_cfe; 1154104834Sobrien } 115599461Sobrien 1156104834Sobrien if (memspace == PCCARD_TPCE_FS_MEMSPACE_LENGTH) { 115799461Sobrien cfe->num_memspace = 1; 1158104834Sobrien cfe->memspace[0].length = 256 * 115999461Sobrien pccard_tuple_read_2(tuple, idx); 1160104834Sobrien idx += 2; 1161104834Sobrien cfe->memspace[0].cardaddr = 0; 116299461Sobrien cfe->memspace[0].hostaddr = 0; 1163104834Sobrien } else if (memspace == 1164104834Sobrien PCCARD_TPCE_FS_MEMSPACE_LENGTHADDR) { 1165104834Sobrien cfe->num_memspace = 1; 1166104834Sobrien cfe->memspace[0].length = 256 * 1167104834Sobrien pccard_tuple_read_2(tuple, idx); 1168104834Sobrien idx += 2; 1169104834Sobrien cfe->memspace[0].cardaddr = 256 * 1170104834Sobrien pccard_tuple_read_2(tuple, idx); 1171104834Sobrien idx += 2; 1172104834Sobrien cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr; 1173104834Sobrien } else { 1174104834Sobrien int lengthsize; 1175104834Sobrien int cardaddrsize; 1176104834Sobrien int hostaddrsize; 1177104834Sobrien 1178104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 1179104834Sobrien cfe->num_memspace = (reg & 1180104834Sobrien PCCARD_TPCE_MS_COUNT) + 1; 1181104834Sobrien if (cfe->num_memspace > 1182104834Sobrien (sizeof(cfe->memspace) / 1183104834Sobrien sizeof(cfe->memspace[0]))) { 1184104834Sobrien DPRINTF(("too many mem " 1185104834Sobrien "spaces %d", 1186104834Sobrien cfe->num_memspace)); 118799461Sobrien state->card->error++; 118899461Sobrien break; 118999461Sobrien } 119099461Sobrien lengthsize = 119199461Sobrien ((reg & PCCARD_TPCE_MS_LENGTH_SIZE_MASK) >> 119299461Sobrien PCCARD_TPCE_MS_LENGTH_SIZE_SHIFT); 119399461Sobrien cardaddrsize = 119499461Sobrien ((reg & PCCARD_TPCE_MS_CARDADDR_SIZE_MASK) >> 1195104834Sobrien PCCARD_TPCE_MS_CARDADDR_SIZE_SHIFT); 1196104834Sobrien hostaddrsize = 1197104834Sobrien (reg & PCCARD_TPCE_MS_HOSTADDR) ? cardaddrsize : 0; 1198104834Sobrien 1199104834Sobrien if (lengthsize == 0) { 1200104834Sobrien DPRINTF(("cfe memspace " 1201104834Sobrien "lengthsize == 0\n")); 1202104834Sobrien } 1203104834Sobrien for (i = 0; i < cfe->num_memspace; i++) { 1204104834Sobrien if (lengthsize) { 1205104834Sobrien cfe->memspace[i].length = 1206104834Sobrien 256 * pccard_tuple_read_n(tuple, lengthsize, 1207104834Sobrien idx); 1208104834Sobrien idx += lengthsize; 1209104834Sobrien } else { 1210104834Sobrien cfe->memspace[i].length = 0; 1211104834Sobrien } 1212104834Sobrien if (cfe->memspace[i].length == 0) { 1213104834Sobrien DPRINTF(("cfe->memspace[%d].length == 0\n", 1214104834Sobrien i)); 1215104834Sobrien } 1216104834Sobrien if (cardaddrsize) { 1217104834Sobrien cfe->memspace[i].cardaddr = 1218104834Sobrien 256 * pccard_tuple_read_n(tuple, cardaddrsize, 1219104834Sobrien idx); 1220104834Sobrien idx += cardaddrsize; 1221104834Sobrien } else { 1222104834Sobrien cfe->memspace[i].cardaddr = 0; 1223104834Sobrien } 1224104834Sobrien if (hostaddrsize) { 1225104834Sobrien cfe->memspace[i].hostaddr = 1226104834Sobrien 256 * pccard_tuple_read_n(tuple, hostaddrsize, 1227104834Sobrien idx); 1228104834Sobrien idx += hostaddrsize; 1229104834Sobrien } else { 1230104834Sobrien cfe->memspace[i].hostaddr = 0; 123194536Sobrien } 123294536Sobrien } 123394536Sobrien } 123494536Sobrien } else 123594536Sobrien cfe->num_memspace = 0; 123694536Sobrien if (misc) { 1237104834Sobrien if (tuple->length <= idx) { 1238104834Sobrien DPRINTF(("ran out of space before TCPE_MI\n")); 1239104834Sobrien goto abort_cfe; 1240104834Sobrien } 1241104834Sobrien 1242104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 1243104834Sobrien cfe->flags &= ~(PCCARD_CFE_POWERDOWN 1244104834Sobrien | PCCARD_CFE_READONLY 124594536Sobrien | PCCARD_CFE_AUDIO); 124694536Sobrien if (reg & PCCARD_TPCE_MI_PWRDOWN) 124794536Sobrien cfe->flags |= PCCARD_CFE_POWERDOWN; 124894536Sobrien if (reg & PCCARD_TPCE_MI_READONLY) 124994536Sobrien cfe->flags |= PCCARD_CFE_READONLY; 125094536Sobrien if (reg & PCCARD_TPCE_MI_AUDIO) 125194536Sobrien cfe->flags |= PCCARD_CFE_AUDIO; 1252104834Sobrien cfe->maxtwins = reg & PCCARD_TPCE_MI_MAXTWINS; 1253104834Sobrien 1254104834Sobrien while (reg & PCCARD_TPCE_MI_EXT) { 1255104834Sobrien reg = pccard_tuple_read_1(tuple, idx++); 1256104834Sobrien } 1257104834Sobrien } 1258104834Sobrien /* skip all the subtuples */ 1259104834Sobrien } 1260104834Sobrien 1261104834Sobrien abort_cfe: 1262104834Sobrien DPRINTF(("CISTPL_CFTABLE_ENTRY\n")); 1263104834Sobrien break; 1264104834Sobrien default: 1265104834Sobrien DPRINTF(("unhandled CISTPL %#x\n", tuple->code)); 1266104834Sobrien break; 1267104834Sobrien } 1268104834Sobrien 1269104834Sobrien return (0); 1270104834Sobrien} 1271104834Sobrien 1272104834Sobrienstatic int 1273104834Sobriendecode_funce(const struct pccard_tuple *tuple, struct pccard_function *pf) 1274104834Sobrien{ 1275104834Sobrien int i; 1276104834Sobrien int len; 1277104834Sobrien int type = pccard_tuple_read_1(tuple, 0); 1278104834Sobrien 1279104834Sobrien switch (pf->function) { 1280104834Sobrien case PCCARD_FUNCTION_DISK: 1281104834Sobrien if (type == PCCARD_TPLFE_TYPE_DISK_DEVICE_INTERFACE) { 1282104834Sobrien pf->pf_funce_disk_interface 1283104834Sobrien = pccard_tuple_read_1(tuple, 1); 1284104834Sobrien pf->pf_funce_disk_power 1285104834Sobrien = pccard_tuple_read_1(tuple, 2); 1286104834Sobrien } 1287104834Sobrien break; 1288104834Sobrien case PCCARD_FUNCTION_NETWORK: 1289104834Sobrien if (type == PCCARD_TPLFE_TYPE_LAN_NID) { 1290104834Sobrien len = pccard_tuple_read_1(tuple, 1); 1291104834Sobrien if (tuple->length < 2 + len || len > 8) { 1292104834Sobrien /* tuple length not enough or nid too long */ 1293104834Sobrien break; 1294104834Sobrien } 1295104834Sobrien for (i = 0; i < len; i++) { 1296104834Sobrien pf->pf_funce_lan_nid[i] 1297104834Sobrien = pccard_tuple_read_1(tuple, i + 2); 1298104834Sobrien } 1299104834Sobrien pf->pf_funce_lan_nidlen = len; 130094536Sobrien } 130194536Sobrien break; 130294536Sobrien default: 130394536Sobrien break; 130494536Sobrien } 1305104834Sobrien return 0; 130694536Sobrien} 1307104834Sobrien