Annotation of sys/dev/pcmcia/pcmcia_cis.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pcmcia_cis.c,v 1.13 2005/08/01 21:58:01 fgsch Exp $ */
! 2: /* $NetBSD: pcmcia_cis.c,v 1.9 1998/08/22 23:41:48 msaitoh Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1997 Marc Horowitz. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. All advertising materials mentioning features or use of this software
! 16: * must display the following acknowledgement:
! 17: * This product includes software developed by Marc Horowitz.
! 18: * 4. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: */
! 32:
! 33: #include <sys/types.h>
! 34: #include <sys/param.h>
! 35: #include <sys/systm.h>
! 36: #include <sys/device.h>
! 37: #include <sys/malloc.h>
! 38:
! 39: #include <dev/pcmcia/pcmciareg.h>
! 40: #include <dev/pcmcia/pcmciachip.h>
! 41: #include <dev/pcmcia/pcmciavar.h>
! 42:
! 43: #ifdef PCMCIACISDEBUG
! 44: #define DPRINTF(arg) printf arg
! 45: #else
! 46: #define DPRINTF(arg)
! 47: #endif
! 48:
! 49: #define PCMCIA_CIS_SIZE 1024
! 50:
! 51: struct cis_state {
! 52: int count;
! 53: int gotmfc;
! 54: struct pcmcia_config_entry temp_cfe;
! 55: struct pcmcia_config_entry *default_cfe;
! 56: struct pcmcia_card *card;
! 57: struct pcmcia_function *pf;
! 58: };
! 59:
! 60: int pcmcia_parse_cis_tuple(struct pcmcia_tuple *, void *);
! 61:
! 62: void
! 63: pcmcia_read_cis(sc)
! 64: struct pcmcia_softc *sc;
! 65: {
! 66: struct cis_state state;
! 67:
! 68: memset(&state, 0, sizeof state);
! 69:
! 70: state.card = &sc->card;
! 71:
! 72: state.card->error = 0;
! 73: state.card->cis1_major = -1;
! 74: state.card->cis1_minor = -1;
! 75: state.card->cis1_info[0] = NULL;
! 76: state.card->cis1_info[1] = NULL;
! 77: state.card->cis1_info[2] = NULL;
! 78: state.card->cis1_info[3] = NULL;
! 79: state.card->manufacturer = PCMCIA_VENDOR_INVALID;
! 80: state.card->product = PCMCIA_PRODUCT_INVALID;
! 81: SIMPLEQ_INIT(&state.card->pf_head);
! 82:
! 83: state.pf = NULL;
! 84:
! 85: if (pcmcia_scan_cis((struct device *)sc, pcmcia_parse_cis_tuple,
! 86: &state) == -1)
! 87: state.card->error++;
! 88: }
! 89:
! 90: int
! 91: pcmcia_scan_cis(dev, fct, arg)
! 92: struct device *dev;
! 93: int (*fct)(struct pcmcia_tuple *, void *);
! 94: void *arg;
! 95: {
! 96: struct pcmcia_softc *sc = (struct pcmcia_softc *) dev;
! 97: pcmcia_chipset_tag_t pct;
! 98: pcmcia_chipset_handle_t pch;
! 99: int window;
! 100: struct pcmcia_mem_handle pcmh;
! 101: struct pcmcia_tuple tuple;
! 102: int longlink_present;
! 103: int longlink_common;
! 104: u_long longlink_addr;
! 105: int mfc_count;
! 106: int mfc_index;
! 107: struct {
! 108: int common;
! 109: u_long addr;
! 110: } mfc[256 / 5];
! 111: int ret;
! 112:
! 113: ret = 0;
! 114:
! 115: pct = sc->pct;
! 116: pch = sc->pch;
! 117:
! 118: /* allocate some memory */
! 119:
! 120: if (pcmcia_chip_mem_alloc(pct, pch, PCMCIA_CIS_SIZE, &pcmh)) {
! 121: #ifdef DIAGNOSTIC
! 122: printf("%s: can't alloc memory to read attributes\n",
! 123: sc->dev.dv_xname);
! 124: #endif
! 125: return -1;
! 126: }
! 127:
! 128: /* initialize state for the primary tuple chain */
! 129: if (pcmcia_chip_mem_map(pct, pch, PCMCIA_MEM_ATTR, 0,
! 130: PCMCIA_CIS_SIZE, &pcmh, &tuple.ptr, &window)) {
! 131: pcmcia_chip_mem_free(pct, pch, &pcmh);
! 132: #ifdef DIAGNOSTIC
! 133: printf("%s: can't map memory to read attributes\n",
! 134: sc->dev.dv_xname);
! 135: #endif
! 136: return -1;
! 137: }
! 138: tuple.memt = pcmh.memt;
! 139: tuple.memh = pcmh.memh;
! 140:
! 141: DPRINTF(("cis mem map %x\n", (unsigned int) tuple.memh));
! 142:
! 143: tuple.mult = 2;
! 144:
! 145: longlink_present = 1;
! 146: longlink_common = 1;
! 147: longlink_addr = 0;
! 148:
! 149: mfc_count = 0;
! 150: mfc_index = 0;
! 151:
! 152: DPRINTF(("%s: CIS tuple chain:\n", sc->dev.dv_xname));
! 153:
! 154: while (1) {
! 155: while (1) {
! 156: /*
! 157: * Perform boundary check for insane cards.
! 158: * If CIS is too long, simulate CIS end.
! 159: * (This check may not be sufficient for
! 160: * malicious cards.)
! 161: */
! 162: if (tuple.mult * tuple.ptr >= PCMCIA_CIS_SIZE - 1
! 163: - 32 /* ad hoc value */ ) {
! 164: DPRINTF(("CISTPL_END (too long CIS)\n"));
! 165: tuple.code = PCMCIA_CISTPL_END;
! 166: goto cis_end;
! 167: }
! 168:
! 169: /* get the tuple code */
! 170:
! 171: tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr);
! 172:
! 173: /* two special-case tuples */
! 174:
! 175: if (tuple.code == PCMCIA_CISTPL_NULL) {
! 176: DPRINTF(("CISTPL_NONE\n 00\n"));
! 177: tuple.ptr++;
! 178: continue;
! 179: } else if (tuple.code == PCMCIA_CISTPL_END) {
! 180: DPRINTF(("CISTPL_END\n ff\n"));
! 181: cis_end:
! 182: /* Call the function for the END tuple, since
! 183: the CIS semantics depend on it */
! 184: if ((*fct) (&tuple, arg)) {
! 185: pcmcia_chip_mem_unmap(pct, pch,
! 186: window);
! 187: ret = 1;
! 188: goto done;
! 189: }
! 190: tuple.ptr++;
! 191: break;
! 192: }
! 193: /* now all the normal tuples */
! 194:
! 195: tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1);
! 196: switch (tuple.code) {
! 197: case PCMCIA_CISTPL_LONGLINK_A:
! 198: case PCMCIA_CISTPL_LONGLINK_C:
! 199: if (tuple.length < 4) {
! 200: DPRINTF(("CISTPL_LONGLINK_%s too "
! 201: "short %d\n",
! 202: longlink_common ? "C" : "A",
! 203: tuple.length));
! 204: break;
! 205: }
! 206: longlink_present = 1;
! 207: longlink_common = (tuple.code ==
! 208: PCMCIA_CISTPL_LONGLINK_C) ? 1 : 0;
! 209: longlink_addr = pcmcia_tuple_read_4(&tuple, 0);
! 210: DPRINTF(("CISTPL_LONGLINK_%s %lx\n",
! 211: longlink_common ? "C" : "A",
! 212: longlink_addr));
! 213: break;
! 214: case PCMCIA_CISTPL_NO_LINK:
! 215: longlink_present = 0;
! 216: DPRINTF(("CISTPL_NO_LINK\n"));
! 217: break;
! 218: case PCMCIA_CISTPL_CHECKSUM:
! 219: if (tuple.length < 5) {
! 220: DPRINTF(("CISTPL_CHECKSUM too "
! 221: "short %d\n", tuple.length));
! 222: break;
! 223: } {
! 224: int16_t offset;
! 225: u_long addr, length;
! 226: u_int cksum, sum;
! 227: int i;
! 228:
! 229: *((u_int16_t *) & offset) =
! 230: pcmcia_tuple_read_2(&tuple, 0);
! 231: length = pcmcia_tuple_read_2(&tuple, 2);
! 232: cksum = pcmcia_tuple_read_1(&tuple, 4);
! 233:
! 234: addr = tuple.ptr + offset;
! 235:
! 236: DPRINTF(("CISTPL_CHECKSUM addr=%lx "
! 237: "len=%lx cksum=%x",
! 238: addr, length, cksum));
! 239:
! 240: /*
! 241: * XXX do more work to deal with
! 242: * distant regions
! 243: */
! 244: if ((addr >= PCMCIA_CIS_SIZE) ||
! 245: ((addr + length) < 0) ||
! 246: ((addr + length) >=
! 247: PCMCIA_CIS_SIZE)) {
! 248: DPRINTF((" skipped, "
! 249: "too distant\n"));
! 250: break;
! 251: }
! 252: sum = 0;
! 253: for (i = 0; i < length; i++)
! 254: sum +=
! 255: bus_space_read_1(tuple.memt,
! 256: tuple.memh,
! 257: addr + tuple.mult * i);
! 258: if (cksum != (sum & 0xff)) {
! 259: DPRINTF((" failed sum=%x\n",
! 260: sum));
! 261: printf("%s: CIS checksum "
! 262: "failed\n",
! 263: sc->dev.dv_xname);
! 264: #if 0
! 265: /*
! 266: * XXX Some working cards have
! 267: * XXX bad checksums!!
! 268: */
! 269: ret = -1;
! 270: #endif
! 271: } else {
! 272: DPRINTF((" ok\n"));
! 273: }
! 274: }
! 275: break;
! 276: case PCMCIA_CISTPL_LONGLINK_MFC:
! 277: if (tuple.length < 6) {
! 278: DPRINTF(("CISTPL_LONGLINK_MFC too "
! 279: "short %d\n", tuple.length));
! 280: break;
! 281: }
! 282: if (((tuple.length - 1) % 5) != 0) {
! 283: DPRINTF(("CISTPL_LONGLINK_MFC bogus "
! 284: "length %d\n", tuple.length));
! 285: break;
! 286: }
! 287: {
! 288: int i, tmp_count;
! 289:
! 290: /*
! 291: * put count into tmp var so that
! 292: * if we have to bail (because it's
! 293: * a bogus count) it won't be
! 294: * remembered for later use.
! 295: */
! 296: tmp_count =
! 297: pcmcia_tuple_read_1(&tuple, 0);
! 298: DPRINTF(("CISTPL_LONGLINK_MFC %d",
! 299: tmp_count));
! 300:
! 301: /*
! 302: * make _sure_ it's the right size;
! 303: * if too short, it may be a weird
! 304: * (unknown/undefined) format
! 305: */
! 306: if (tuple.length != (tmp_count*5 + 1)) {
! 307: DPRINTF((" bogus length %d\n",
! 308: tuple.length));
! 309: break;
! 310: }
! 311:
! 312: #ifdef PCMCIACISDEBUG /* maybe enable all the time? */
! 313: /*
! 314: * sanity check for a programming
! 315: * error which is difficult to find
! 316: * when debugging.
! 317: */
! 318: if (tmp_count >
! 319: howmany(sizeof mfc, sizeof mfc[0]))
! 320: panic("CISTPL_LONGLINK_MFC mfc "
! 321: "count would blow stack");
! 322: #endif
! 323:
! 324: mfc_count = tmp_count;
! 325: for (i = 0; i < mfc_count; i++) {
! 326: mfc[i].common =
! 327: (pcmcia_tuple_read_1(&tuple,
! 328: 1 + 5 * i) ==
! 329: PCMCIA_MFC_MEM_COMMON) ?
! 330: 1 : 0;
! 331: mfc[i].addr =
! 332: pcmcia_tuple_read_4(&tuple,
! 333: 1 + 5 * i + 1);
! 334: DPRINTF((" %s:%lx",
! 335: mfc[i].common ? "common" :
! 336: "attr", mfc[i].addr));
! 337: }
! 338: DPRINTF(("\n"));
! 339: }
! 340: /*
! 341: * for LONGLINK_MFC, fall through to the
! 342: * function. This tuple has structural and
! 343: * semantic content.
! 344: */
! 345: default:
! 346: {
! 347: if ((*fct) (&tuple, arg)) {
! 348: pcmcia_chip_mem_unmap(pct,
! 349: pch, window);
! 350: ret = 1;
! 351: goto done;
! 352: }
! 353: }
! 354: break;
! 355: } /* switch */
! 356: #ifdef PCMCIACISDEBUG
! 357: /* print the tuple */
! 358: {
! 359: int i;
! 360:
! 361: DPRINTF((" %02x %02x", tuple.code,
! 362: tuple.length));
! 363:
! 364: for (i = 0; i < tuple.length; i++) {
! 365: DPRINTF((" %02x",
! 366: pcmcia_tuple_read_1(&tuple, i)));
! 367: if ((i % 16) == 13)
! 368: DPRINTF(("\n"));
! 369: }
! 370: if ((i % 16) != 14)
! 371: DPRINTF(("\n"));
! 372: }
! 373: #endif
! 374: /* skip to the next tuple */
! 375: tuple.ptr += 2 + tuple.length;
! 376: }
! 377:
! 378: /*
! 379: * the chain is done. Clean up and move onto the next one,
! 380: * if any. The loop is here in the case that there is an MFC
! 381: * card with no longlink (which defaults to existing, == 0).
! 382: * In general, this means that if one pointer fails, it will
! 383: * try the next one, instead of just bailing.
! 384: */
! 385:
! 386: while (1) {
! 387: pcmcia_chip_mem_unmap(pct, pch, window);
! 388:
! 389: if (longlink_present) {
! 390: /*
! 391: * if the longlink is to attribute memory,
! 392: * then it is unindexed. That is, if the
! 393: * link value is 0x100, then the actual
! 394: * memory address is 0x200. This means that
! 395: * we need to multiply by 2 before calling
! 396: * mem_map, and then divide the resulting ptr
! 397: * by 2 after.
! 398: */
! 399:
! 400: if (!longlink_common)
! 401: longlink_addr *= 2;
! 402:
! 403: pcmcia_chip_mem_map(pct, pch, longlink_common ?
! 404: PCMCIA_MEM_COMMON : PCMCIA_MEM_ATTR,
! 405: longlink_addr, PCMCIA_CIS_SIZE,
! 406: &pcmh, &tuple.ptr, &window);
! 407:
! 408: if (!longlink_common)
! 409: tuple.ptr /= 2;
! 410:
! 411: DPRINTF(("cis mem map %x\n",
! 412: (unsigned int) tuple.memh));
! 413:
! 414: tuple.mult = longlink_common ? 1 : 2;
! 415: longlink_present = 0;
! 416: longlink_common = 1;
! 417: longlink_addr = 0;
! 418: } else if (mfc_count && (mfc_index < mfc_count)) {
! 419: if (!mfc[mfc_index].common)
! 420: mfc[mfc_index].addr *= 2;
! 421:
! 422: pcmcia_chip_mem_map(pct, pch,
! 423: mfc[mfc_index].common ?
! 424: PCMCIA_MEM_COMMON : PCMCIA_MEM_ATTR,
! 425: mfc[mfc_index].addr, PCMCIA_CIS_SIZE,
! 426: &pcmh, &tuple.ptr, &window);
! 427:
! 428: if (!mfc[mfc_index].common)
! 429: tuple.ptr /= 2;
! 430:
! 431: DPRINTF(("cis mem map %x\n",
! 432: (unsigned int) tuple.memh));
! 433:
! 434: /* set parse state, and point at the next one */
! 435:
! 436: tuple.mult = mfc[mfc_index].common ? 1 : 2;
! 437:
! 438: mfc_index++;
! 439: } else {
! 440: goto done;
! 441: }
! 442:
! 443: /* make sure that the link is valid */
! 444: tuple.code = pcmcia_cis_read_1(&tuple, tuple.ptr);
! 445: if (tuple.code != PCMCIA_CISTPL_LINKTARGET) {
! 446: DPRINTF(("CISTPL_LINKTARGET expected, "
! 447: "code %02x observed\n", tuple.code));
! 448: continue;
! 449: }
! 450: tuple.length = pcmcia_cis_read_1(&tuple, tuple.ptr + 1);
! 451: if (tuple.length < 3) {
! 452: DPRINTF(("CISTPL_LINKTARGET too short %d\n",
! 453: tuple.length));
! 454: continue;
! 455: }
! 456: if ((pcmcia_tuple_read_1(&tuple, 0) != 'C') ||
! 457: (pcmcia_tuple_read_1(&tuple, 1) != 'I') ||
! 458: (pcmcia_tuple_read_1(&tuple, 2) != 'S')) {
! 459: DPRINTF(("CISTPL_LINKTARGET magic "
! 460: "%02x%02x%02x incorrect\n",
! 461: pcmcia_tuple_read_1(&tuple, 0),
! 462: pcmcia_tuple_read_1(&tuple, 1),
! 463: pcmcia_tuple_read_1(&tuple, 2)));
! 464: continue;
! 465: }
! 466: tuple.ptr += 2 + tuple.length;
! 467:
! 468: break;
! 469: }
! 470: }
! 471:
! 472: pcmcia_chip_mem_unmap(pct, pch, window);
! 473:
! 474: done:
! 475: /* Last, free the allocated memory block */
! 476: pcmcia_chip_mem_free(pct, pch, &pcmh);
! 477:
! 478: return (ret);
! 479: }
! 480:
! 481: /* XXX this is incredibly verbose. Not sure what trt is */
! 482:
! 483: void
! 484: pcmcia_print_cis(sc)
! 485: struct pcmcia_softc *sc;
! 486: {
! 487: struct pcmcia_card *card = &sc->card;
! 488: struct pcmcia_function *pf;
! 489: struct pcmcia_config_entry *cfe;
! 490: int i;
! 491:
! 492: printf("%s: CIS version ", sc->dev.dv_xname);
! 493: if (card->cis1_major == 4) {
! 494: if (card->cis1_minor == 0)
! 495: printf("PCMCIA 1.0\n");
! 496: else if (card->cis1_minor == 1)
! 497: printf("PCMCIA 2.0 or 2.1\n");
! 498: } else if (card->cis1_major >= 5)
! 499: printf("PC Card Standard %d.%d\n", card->cis1_major,
! 500: card->cis1_minor);
! 501: else
! 502: printf("unknown (major=%d, minor=%d)\n",
! 503: card->cis1_major, card->cis1_minor);
! 504:
! 505: printf("%s: CIS info: ", sc->dev.dv_xname);
! 506: for (i = 0; i < 4; i++) {
! 507: if (card->cis1_info[i] == NULL)
! 508: break;
! 509: if (i)
! 510: printf(", ");
! 511: printf("%s", card->cis1_info[i]);
! 512: }
! 513: printf("\n");
! 514:
! 515: printf("%s: Manufacturer code 0x%x, product 0x%x\n",
! 516: sc->dev.dv_xname, card->manufacturer, card->product);
! 517:
! 518: SIMPLEQ_FOREACH(pf, &card->pf_head, pf_list) {
! 519: printf("%s: function %d: ", sc->dev.dv_xname, pf->number);
! 520:
! 521: switch (pf->function) {
! 522: case PCMCIA_FUNCTION_UNSPEC:
! 523: printf("unspecified");
! 524: break;
! 525: case PCMCIA_FUNCTION_MULTIFUNCTION:
! 526: printf("multi-function");
! 527: break;
! 528: case PCMCIA_FUNCTION_MEMORY:
! 529: printf("memory");
! 530: break;
! 531: case PCMCIA_FUNCTION_SERIAL:
! 532: printf("serial port");
! 533: break;
! 534: case PCMCIA_FUNCTION_PARALLEL:
! 535: printf("parallel port");
! 536: break;
! 537: case PCMCIA_FUNCTION_DISK:
! 538: printf("fixed disk");
! 539: break;
! 540: case PCMCIA_FUNCTION_VIDEO:
! 541: printf("video adapter");
! 542: break;
! 543: case PCMCIA_FUNCTION_NETWORK:
! 544: printf("network adapter");
! 545: break;
! 546: case PCMCIA_FUNCTION_AIMS:
! 547: printf("auto incrementing mass storage");
! 548: break;
! 549: case PCMCIA_FUNCTION_SCSI:
! 550: printf("SCSI bridge");
! 551: break;
! 552: case PCMCIA_FUNCTION_SECURITY:
! 553: printf("Security services");
! 554: break;
! 555: case PCMCIA_FUNCTION_INSTRUMENT:
! 556: printf("Instrument");
! 557: break;
! 558: case PCMCIA_FUNCTION_IOBUS:
! 559: printf("Serial I/O Bus Adapter");
! 560: break;
! 561: default:
! 562: printf("unknown (%d)", pf->function);
! 563: break;
! 564: }
! 565:
! 566: printf(", ccr addr %lx mask %lx\n", pf->ccr_base, pf->ccr_mask);
! 567:
! 568: SIMPLEQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
! 569: printf("%s: function %d, config table entry %d: ",
! 570: sc->dev.dv_xname, pf->number, cfe->number);
! 571:
! 572: switch (cfe->iftype) {
! 573: case PCMCIA_IFTYPE_MEMORY:
! 574: printf("memory card");
! 575: break;
! 576: case PCMCIA_IFTYPE_IO:
! 577: printf("I/O card");
! 578: break;
! 579: default:
! 580: printf("card type unknown");
! 581: break;
! 582: }
! 583:
! 584: printf("; irq mask %x", cfe->irqmask);
! 585:
! 586: if (cfe->num_iospace) {
! 587: printf("; iomask %lx, iospace", cfe->iomask);
! 588:
! 589: for (i = 0; i < cfe->num_iospace; i++)
! 590: printf(" %lx%s%lx",
! 591: cfe->iospace[i].start,
! 592: cfe->iospace[i].length ? "-" : "",
! 593: cfe->iospace[i].start +
! 594: cfe->iospace[i].length - 1);
! 595: }
! 596: if (cfe->num_memspace) {
! 597: printf("; memspace");
! 598:
! 599: for (i = 0; i < cfe->num_memspace; i++)
! 600: printf(" %lx%s%lx%s%lx",
! 601: cfe->memspace[i].cardaddr,
! 602: cfe->memspace[i].length ? "-" : "",
! 603: cfe->memspace[i].cardaddr +
! 604: cfe->memspace[i].length - 1,
! 605: cfe->memspace[i].hostaddr ?
! 606: "@" : "",
! 607: cfe->memspace[i].hostaddr);
! 608: }
! 609: if (cfe->maxtwins)
! 610: printf("; maxtwins %d", cfe->maxtwins);
! 611:
! 612: printf(";");
! 613:
! 614: if (cfe->flags & PCMCIA_CFE_MWAIT_REQUIRED)
! 615: printf(" mwait_required");
! 616: if (cfe->flags & PCMCIA_CFE_RDYBSY_ACTIVE)
! 617: printf(" rdybsy_active");
! 618: if (cfe->flags & PCMCIA_CFE_WP_ACTIVE)
! 619: printf(" wp_active");
! 620: if (cfe->flags & PCMCIA_CFE_BVD_ACTIVE)
! 621: printf(" bvd_active");
! 622: if (cfe->flags & PCMCIA_CFE_IO8)
! 623: printf(" io8");
! 624: if (cfe->flags & PCMCIA_CFE_IO16)
! 625: printf(" io16");
! 626: if (cfe->flags & PCMCIA_CFE_IRQSHARE)
! 627: printf(" irqshare");
! 628: if (cfe->flags & PCMCIA_CFE_IRQPULSE)
! 629: printf(" irqpulse");
! 630: if (cfe->flags & PCMCIA_CFE_IRQLEVEL)
! 631: printf(" irqlevel");
! 632: if (cfe->flags & PCMCIA_CFE_POWERDOWN)
! 633: printf(" powerdown");
! 634: if (cfe->flags & PCMCIA_CFE_READONLY)
! 635: printf(" readonly");
! 636: if (cfe->flags & PCMCIA_CFE_AUDIO)
! 637: printf(" audio");
! 638:
! 639: printf("\n");
! 640: }
! 641: }
! 642:
! 643: if (card->error)
! 644: printf("%s: %d errors found while parsing CIS\n",
! 645: sc->dev.dv_xname, card->error);
! 646: }
! 647:
! 648: int
! 649: pcmcia_parse_cis_tuple(tuple, arg)
! 650: struct pcmcia_tuple *tuple;
! 651: void *arg;
! 652: {
! 653: /* most of these are educated guesses */
! 654: static struct pcmcia_config_entry init_cfe = {
! 655: -1, PCMCIA_CFE_RDYBSY_ACTIVE | PCMCIA_CFE_WP_ACTIVE |
! 656: PCMCIA_CFE_BVD_ACTIVE, PCMCIA_IFTYPE_MEMORY,
! 657: };
! 658:
! 659: struct cis_state *state = arg;
! 660:
! 661: switch (tuple->code) {
! 662: case PCMCIA_CISTPL_END:
! 663: /*
! 664: * If we've seen a LONGLINK_MFC, and this is the first
! 665: * END after it, reset the function list.
! 666: *
! 667: * XXX This might also be the right place to start a
! 668: * new function, but that assumes that a function
! 669: * definition never crosses any longlink, and I'm not
! 670: * sure about that. This is probably safe for MFC
! 671: * cards, but what we have now isn't broken, so I'd
! 672: * rather not change it.
! 673: */
! 674: if (state->gotmfc == 1) {
! 675: struct pcmcia_function *pf, *pfnext;
! 676:
! 677: for (pf = SIMPLEQ_FIRST(&state->card->pf_head);
! 678: pf != NULL; pf = pfnext) {
! 679: pfnext = SIMPLEQ_NEXT(pf, pf_list);
! 680: free(pf, M_DEVBUF);
! 681: }
! 682:
! 683: SIMPLEQ_INIT(&state->card->pf_head);
! 684:
! 685: state->count = 0;
! 686: state->gotmfc = 2;
! 687: state->pf = NULL;
! 688: }
! 689: break;
! 690:
! 691: case PCMCIA_CISTPL_LONGLINK_MFC:
! 692: /*
! 693: * This tuple's structure was dealt with in scan_cis. here,
! 694: * record the fact that the MFC tuple was seen, so that
! 695: * functions declared before the MFC link can be cleaned
! 696: * up.
! 697: */
! 698: state->gotmfc = 1;
! 699: break;
! 700:
! 701: #ifdef PCMCIACISDEBUG
! 702: case PCMCIA_CISTPL_DEVICE:
! 703: case PCMCIA_CISTPL_DEVICE_A:
! 704: {
! 705: u_int reg, dtype, dspeed;
! 706:
! 707: reg = pcmcia_tuple_read_1(tuple, 0);
! 708: dtype = reg & PCMCIA_DTYPE_MASK;
! 709: dspeed = reg & PCMCIA_DSPEED_MASK;
! 710:
! 711: DPRINTF(("CISTPL_DEVICE%s type=",
! 712: (tuple->code == PCMCIA_CISTPL_DEVICE) ? "" : "_A"));
! 713: switch (dtype) {
! 714: case PCMCIA_DTYPE_NULL:
! 715: DPRINTF(("null"));
! 716: break;
! 717: case PCMCIA_DTYPE_ROM:
! 718: DPRINTF(("rom"));
! 719: break;
! 720: case PCMCIA_DTYPE_OTPROM:
! 721: DPRINTF(("otprom"));
! 722: break;
! 723: case PCMCIA_DTYPE_EPROM:
! 724: DPRINTF(("eprom"));
! 725: break;
! 726: case PCMCIA_DTYPE_EEPROM:
! 727: DPRINTF(("eeprom"));
! 728: break;
! 729: case PCMCIA_DTYPE_FLASH:
! 730: DPRINTF(("flash"));
! 731: break;
! 732: case PCMCIA_DTYPE_SRAM:
! 733: DPRINTF(("sram"));
! 734: break;
! 735: case PCMCIA_DTYPE_DRAM:
! 736: DPRINTF(("dram"));
! 737: break;
! 738: case PCMCIA_DTYPE_FUNCSPEC:
! 739: DPRINTF(("funcspec"));
! 740: break;
! 741: case PCMCIA_DTYPE_EXTEND:
! 742: DPRINTF(("extend"));
! 743: break;
! 744: default:
! 745: DPRINTF(("reserved"));
! 746: break;
! 747: }
! 748: DPRINTF((" speed="));
! 749: switch (dspeed) {
! 750: case PCMCIA_DSPEED_NULL:
! 751: DPRINTF(("null"));
! 752: break;
! 753: case PCMCIA_DSPEED_250NS:
! 754: DPRINTF(("250ns"));
! 755: break;
! 756: case PCMCIA_DSPEED_200NS:
! 757: DPRINTF(("200ns"));
! 758: break;
! 759: case PCMCIA_DSPEED_150NS:
! 760: DPRINTF(("150ns"));
! 761: break;
! 762: case PCMCIA_DSPEED_100NS:
! 763: DPRINTF(("100ns"));
! 764: break;
! 765: case PCMCIA_DSPEED_EXT:
! 766: DPRINTF(("ext"));
! 767: break;
! 768: default:
! 769: DPRINTF(("reserved"));
! 770: break;
! 771: }
! 772: }
! 773: DPRINTF(("\n"));
! 774: break;
! 775: #endif
! 776:
! 777: case PCMCIA_CISTPL_VERS_1:
! 778: if (tuple->length < 6) {
! 779: DPRINTF(("CISTPL_VERS_1 too short %d\n",
! 780: tuple->length));
! 781: break;
! 782: } {
! 783: int start, i, ch, count;
! 784:
! 785: state->card->cis1_major = pcmcia_tuple_read_1(tuple, 0);
! 786: state->card->cis1_minor = pcmcia_tuple_read_1(tuple, 1);
! 787:
! 788: for (count = 0, start = 0, i = 0;
! 789: (count < 4) && ((i + 4) < 256); i++) {
! 790: ch = pcmcia_tuple_read_1(tuple, 2 + i);
! 791: if (ch == 0xff)
! 792: break;
! 793: state->card->cis1_info_buf[i] = ch;
! 794: if (ch == 0) {
! 795: state->card->cis1_info[count] =
! 796: state->card->cis1_info_buf + start;
! 797: start = i + 1;
! 798: count++;
! 799: }
! 800: }
! 801: DPRINTF(("CISTPL_VERS_1\n"));
! 802: }
! 803: break;
! 804:
! 805: case PCMCIA_CISTPL_MANFID:
! 806: if (tuple->length < 4) {
! 807: DPRINTF(("CISTPL_MANFID too short %d\n",
! 808: tuple->length));
! 809: break;
! 810: }
! 811: state->card->manufacturer = pcmcia_tuple_read_2(tuple, 0);
! 812: state->card->product = pcmcia_tuple_read_2(tuple, 2);
! 813: DPRINTF(("CISTPL_MANFID\n"));
! 814: break;
! 815:
! 816: case PCMCIA_CISTPL_FUNCID:
! 817: if (tuple->length < 2) {
! 818: DPRINTF(("CISTPL_FUNCID too short %d\n",
! 819: tuple->length));
! 820: break;
! 821: }
! 822:
! 823: /*
! 824: * As far as I understand this, manufacturers do multifunction
! 825: * cards in various ways. Sadly enough I do not have the
! 826: * PC-Card standard (donate!) so I can only guess what can
! 827: * be done.
! 828: * The original code implies FUNCID nodes are above CONFIG
! 829: * nodes in the CIS tree, however Xircom does it the other
! 830: * way round, which of course makes things a bit hard.
! 831: * --niklas@openbsd.org
! 832: */
! 833: if (state->pf) {
! 834: if (state->pf->function == PCMCIA_FUNCTION_UNSPEC) {
! 835: /*
! 836: * This looks like a opportunistic function
! 837: * created by a CONFIG tuple. Just keep it.
! 838: */
! 839: } else {
! 840: /*
! 841: * A function is being defined, end it.
! 842: */
! 843: state->pf = NULL;
! 844: }
! 845: }
! 846: if (state->pf == NULL) {
! 847: state->pf = malloc(sizeof(*state->pf), M_DEVBUF,
! 848: M_NOWAIT);
! 849: if (state->pf == NULL)
! 850: panic("pcmcia_parse_cis_tuple");
! 851: bzero(state->pf, sizeof(*state->pf));
! 852: state->pf->number = state->count++;
! 853: state->pf->last_config_index = -1;
! 854: SIMPLEQ_INIT(&state->pf->cfe_head);
! 855:
! 856: SIMPLEQ_INSERT_TAIL(&state->card->pf_head, state->pf,
! 857: pf_list);
! 858: }
! 859: state->pf->function = pcmcia_tuple_read_1(tuple, 0);
! 860:
! 861: DPRINTF(("CISTPL_FUNCID\n"));
! 862: break;
! 863:
! 864: case PCMCIA_CISTPL_CONFIG:
! 865: if (tuple->length < 3) {
! 866: DPRINTF(("CISTPL_CONFIG too short %d\n",
! 867: tuple->length));
! 868: break;
! 869: } {
! 870: u_int reg, rasz, rmsz, rfsz;
! 871: int i;
! 872:
! 873: reg = pcmcia_tuple_read_1(tuple, 0);
! 874: rasz = 1 + ((reg & PCMCIA_TPCC_RASZ_MASK) >>
! 875: PCMCIA_TPCC_RASZ_SHIFT);
! 876: rmsz = 1 + ((reg & PCMCIA_TPCC_RMSZ_MASK) >>
! 877: PCMCIA_TPCC_RMSZ_SHIFT);
! 878: rfsz = ((reg & PCMCIA_TPCC_RFSZ_MASK) >>
! 879: PCMCIA_TPCC_RFSZ_SHIFT);
! 880:
! 881: if (tuple->length < (rasz + rmsz + rfsz)) {
! 882: DPRINTF(("CISTPL_CONFIG (%d,%d,%d) too "
! 883: "short %d\n", rasz, rmsz, rfsz,
! 884: tuple->length));
! 885: break;
! 886: }
! 887: if (state->pf == NULL) {
! 888: state->pf = malloc(sizeof(*state->pf),
! 889: M_DEVBUF, M_NOWAIT);
! 890: if (state->pf == NULL)
! 891: panic("pcmcia_parse_cis_tuple");
! 892: bzero(state->pf, sizeof(*state->pf));
! 893: state->pf->number = state->count++;
! 894: state->pf->last_config_index = -1;
! 895: SIMPLEQ_INIT(&state->pf->cfe_head);
! 896:
! 897: SIMPLEQ_INSERT_TAIL(&state->card->pf_head,
! 898: state->pf, pf_list);
! 899:
! 900: state->pf->function = PCMCIA_FUNCTION_UNSPEC;
! 901: }
! 902: state->pf->last_config_index =
! 903: pcmcia_tuple_read_1(tuple, 1);
! 904:
! 905: state->pf->ccr_base = 0;
! 906: for (i = 0; i < rasz; i++)
! 907: state->pf->ccr_base |=
! 908: ((pcmcia_tuple_read_1(tuple, 2 + i)) <<
! 909: (i * 8));
! 910:
! 911: state->pf->ccr_mask = 0;
! 912: for (i = 0; i < rmsz; i++)
! 913: state->pf->ccr_mask |=
! 914: ((pcmcia_tuple_read_1(tuple,
! 915: 2 + rasz + i)) << (i * 8));
! 916:
! 917: /* skip the reserved area and subtuples */
! 918:
! 919: /* reset the default cfe for each cfe list */
! 920: state->temp_cfe = init_cfe;
! 921: state->default_cfe = &state->temp_cfe;
! 922: }
! 923: DPRINTF(("CISTPL_CONFIG\n"));
! 924: break;
! 925:
! 926: case PCMCIA_CISTPL_CFTABLE_ENTRY:
! 927: if (tuple->length < 2) {
! 928: DPRINTF(("CISTPL_CFTABLE_ENTRY too short %d\n",
! 929: tuple->length));
! 930: break;
! 931: } {
! 932: int idx, i, j;
! 933: u_int reg, reg2;
! 934: u_int intface, def, num;
! 935: u_int power, timing, iospace, irq, memspace, misc;
! 936: struct pcmcia_config_entry *cfe;
! 937:
! 938: idx = 0;
! 939:
! 940: reg = pcmcia_tuple_read_1(tuple, idx);
! 941: idx++;
! 942: intface = reg & PCMCIA_TPCE_INDX_INTFACE;
! 943: def = reg & PCMCIA_TPCE_INDX_DEFAULT;
! 944: num = reg & PCMCIA_TPCE_INDX_NUM_MASK;
! 945:
! 946: /*
! 947: * this is a little messy. Some cards have only a
! 948: * cfentry with the default bit set. So, as we go
! 949: * through the list, we add new indexes to the queue,
! 950: * and keep a pointer to the last one with the
! 951: * default bit set. if we see a record with the same
! 952: * index, as the default, we stash the default and
! 953: * replace the queue entry. otherwise, we just add
! 954: * new entries to the queue, pointing the default ptr
! 955: * at them if the default bit is set. if we get to
! 956: * the end with the default pointer pointing at a
! 957: * record which hasn't had a matching index, that's
! 958: * ok; it just becomes a cfentry like any other.
! 959: */
! 960:
! 961: /*
! 962: * if the index in the cis differs from the default
! 963: * cis, create new entry in the queue and start it
! 964: * with the current default
! 965: */
! 966: if (state->default_cfe == NULL) {
! 967: DPRINTF(("CISTPL_CFTABLE_ENTRY with no "
! 968: "default\n"));
! 969: break;
! 970: }
! 971: if (num != state->default_cfe->number) {
! 972: cfe = (struct pcmcia_config_entry *)
! 973: malloc(sizeof(*cfe), M_DEVBUF, M_NOWAIT);
! 974: if (cfe == NULL)
! 975: panic("pcmcia_parse_cis_tuple");
! 976:
! 977: *cfe = *state->default_cfe;
! 978:
! 979: SIMPLEQ_INSERT_TAIL(&state->pf->cfe_head,
! 980: cfe, cfe_list);
! 981:
! 982: cfe->number = num;
! 983:
! 984: /*
! 985: * if the default bit is set in the cis, then
! 986: * point the new default at whatever is being
! 987: * filled in
! 988: */
! 989: if (def)
! 990: state->default_cfe = cfe;
! 991: } else {
! 992: /*
! 993: * the cis index matches the default index,
! 994: * fill in the default cfentry. It is
! 995: * assumed that the cfdefault index is in the
! 996: * queue. For it to be otherwise, the cis
! 997: * index would have to be -1 (initial
! 998: * condition) which is not possible, or there
! 999: * would have to be a preceding cis entry
! 1000: * which had the same cis index and had the
! 1001: * default bit unset. Neither condition
! 1002: * should happen. If it does, this cfentry
! 1003: * is lost (written into temp space), which
! 1004: * is an acceptable failure mode.
! 1005: */
! 1006:
! 1007: cfe = state->default_cfe;
! 1008:
! 1009: /*
! 1010: * if the cis entry does not have the default
! 1011: * bit set, copy the default out of the way
! 1012: * first.
! 1013: */
! 1014: if (!def) {
! 1015: state->temp_cfe = *state->default_cfe;
! 1016: state->default_cfe = &state->temp_cfe;
! 1017: }
! 1018: }
! 1019:
! 1020: if (intface) {
! 1021: reg = pcmcia_tuple_read_1(tuple, idx);
! 1022: idx++;
! 1023: cfe->flags &= ~(PCMCIA_CFE_MWAIT_REQUIRED
! 1024: | PCMCIA_CFE_RDYBSY_ACTIVE
! 1025: | PCMCIA_CFE_WP_ACTIVE
! 1026: | PCMCIA_CFE_BVD_ACTIVE);
! 1027: if (reg & PCMCIA_TPCE_IF_MWAIT)
! 1028: cfe->flags |= PCMCIA_CFE_MWAIT_REQUIRED;
! 1029: if (reg & PCMCIA_TPCE_IF_RDYBSY)
! 1030: cfe->flags |= PCMCIA_CFE_RDYBSY_ACTIVE;
! 1031: if (reg & PCMCIA_TPCE_IF_WP)
! 1032: cfe->flags |= PCMCIA_CFE_WP_ACTIVE;
! 1033: if (reg & PCMCIA_TPCE_IF_BVD)
! 1034: cfe->flags |= PCMCIA_CFE_BVD_ACTIVE;
! 1035: cfe->iftype = reg & PCMCIA_TPCE_IF_IFTYPE;
! 1036: }
! 1037: reg = pcmcia_tuple_read_1(tuple, idx);
! 1038: idx++;
! 1039:
! 1040: power = reg & PCMCIA_TPCE_FS_POWER_MASK;
! 1041: timing = reg & PCMCIA_TPCE_FS_TIMING;
! 1042: iospace = reg & PCMCIA_TPCE_FS_IOSPACE;
! 1043: irq = reg & PCMCIA_TPCE_FS_IRQ;
! 1044: memspace = reg & PCMCIA_TPCE_FS_MEMSPACE_MASK;
! 1045: misc = reg & PCMCIA_TPCE_FS_MISC;
! 1046:
! 1047: if (power) {
! 1048: /* skip over power, don't save */
! 1049: /* for each parameter selection byte */
! 1050: for (i = 0; i < power; i++) {
! 1051: reg = pcmcia_tuple_read_1(tuple, idx);
! 1052: idx++;
! 1053: /* for each bit */
! 1054: for (j = 0; j < 7; j++) {
! 1055: /* if the bit is set */
! 1056: if ((reg >> j) & 0x01) {
! 1057: /* skip over bytes */
! 1058: do {
! 1059: reg2 = pcmcia_tuple_read_1(tuple, idx);
! 1060: idx++;
! 1061: /*
! 1062: * until
! 1063: * non-
! 1064: * extension
! 1065: * byte
! 1066: */
! 1067: } while (reg2 & 0x80);
! 1068: }
! 1069: }
! 1070: }
! 1071: }
! 1072: if (timing) {
! 1073: /* skip over timing, don't save */
! 1074: reg = pcmcia_tuple_read_1(tuple, idx);
! 1075: idx++;
! 1076:
! 1077: if ((reg & PCMCIA_TPCE_TD_RESERVED_MASK) !=
! 1078: PCMCIA_TPCE_TD_RESERVED_MASK)
! 1079: idx++;
! 1080: if ((reg & PCMCIA_TPCE_TD_RDYBSY_MASK) !=
! 1081: PCMCIA_TPCE_TD_RDYBSY_MASK)
! 1082: idx++;
! 1083: if ((reg & PCMCIA_TPCE_TD_WAIT_MASK) !=
! 1084: PCMCIA_TPCE_TD_WAIT_MASK)
! 1085: idx++;
! 1086: }
! 1087: if (iospace) {
! 1088: if (tuple->length <= idx) {
! 1089: DPRINTF(("ran out of space before TPCE_IO\n"));
! 1090:
! 1091: goto abort_cfe;
! 1092: }
! 1093:
! 1094: reg = pcmcia_tuple_read_1(tuple, idx);
! 1095: idx++;
! 1096:
! 1097: cfe->flags &=
! 1098: ~(PCMCIA_CFE_IO8 | PCMCIA_CFE_IO16);
! 1099: if (reg & PCMCIA_TPCE_IO_BUSWIDTH_8BIT)
! 1100: cfe->flags |= PCMCIA_CFE_IO8;
! 1101: if (reg & PCMCIA_TPCE_IO_BUSWIDTH_16BIT)
! 1102: cfe->flags |= PCMCIA_CFE_IO16;
! 1103: cfe->iomask =
! 1104: reg & PCMCIA_TPCE_IO_IOADDRLINES_MASK;
! 1105:
! 1106: if (reg & PCMCIA_TPCE_IO_HASRANGE) {
! 1107: reg = pcmcia_tuple_read_1(tuple, idx);
! 1108: idx++;
! 1109:
! 1110: cfe->num_iospace = 1 + (reg &
! 1111: PCMCIA_TPCE_IO_RANGE_COUNT);
! 1112:
! 1113: if (cfe->num_iospace >
! 1114: (sizeof(cfe->iospace) /
! 1115: sizeof(cfe->iospace[0]))) {
! 1116: DPRINTF(("too many io "
! 1117: "spaces %d",
! 1118: cfe->num_iospace));
! 1119: state->card->error++;
! 1120: break;
! 1121: }
! 1122: for (i = 0; i < cfe->num_iospace; i++) {
! 1123: switch (reg & PCMCIA_TPCE_IO_RANGE_ADDRSIZE_MASK) {
! 1124: case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_ONE:
! 1125: cfe->iospace[i].start =
! 1126: pcmcia_tuple_read_1(tuple, idx);
! 1127: idx++;
! 1128: break;
! 1129: case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_TWO:
! 1130: cfe->iospace[i].start =
! 1131: pcmcia_tuple_read_2(tuple, idx);
! 1132: idx += 2;
! 1133: break;
! 1134: case PCMCIA_TPCE_IO_RANGE_ADDRSIZE_FOUR:
! 1135: cfe->iospace[i].start =
! 1136: pcmcia_tuple_read_4(tuple, idx);
! 1137: idx += 4;
! 1138: break;
! 1139: }
! 1140: switch (reg &
! 1141: PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_MASK) {
! 1142: case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_ONE:
! 1143: cfe->iospace[i].length =
! 1144: pcmcia_tuple_read_1(tuple, idx);
! 1145: idx++;
! 1146: break;
! 1147: case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_TWO:
! 1148: cfe->iospace[i].length =
! 1149: pcmcia_tuple_read_2(tuple, idx);
! 1150: idx += 2;
! 1151: break;
! 1152: case PCMCIA_TPCE_IO_RANGE_LENGTHSIZE_FOUR:
! 1153: cfe->iospace[i].length =
! 1154: pcmcia_tuple_read_4(tuple, idx);
! 1155: idx += 4;
! 1156: break;
! 1157: }
! 1158: cfe->iospace[i].length++;
! 1159: }
! 1160: } else {
! 1161: cfe->num_iospace = 1;
! 1162: cfe->iospace[0].start = 0;
! 1163: cfe->iospace[0].length =
! 1164: (1 << cfe->iomask);
! 1165: }
! 1166: }
! 1167:
! 1168: if (irq) {
! 1169: if (tuple->length <= idx) {
! 1170: DPRINTF(("ran out of space before TPCE_IR\n"));
! 1171:
! 1172: goto abort_cfe;
! 1173: }
! 1174:
! 1175: reg = pcmcia_tuple_read_1(tuple, idx);
! 1176: idx++;
! 1177:
! 1178: cfe->flags &= ~(PCMCIA_CFE_IRQSHARE
! 1179: | PCMCIA_CFE_IRQPULSE
! 1180: | PCMCIA_CFE_IRQLEVEL);
! 1181: if (reg & PCMCIA_TPCE_IR_SHARE)
! 1182: cfe->flags |= PCMCIA_CFE_IRQSHARE;
! 1183: if (reg & PCMCIA_TPCE_IR_PULSE)
! 1184: cfe->flags |= PCMCIA_CFE_IRQPULSE;
! 1185: if (reg & PCMCIA_TPCE_IR_LEVEL)
! 1186: cfe->flags |= PCMCIA_CFE_IRQLEVEL;
! 1187:
! 1188: if (reg & PCMCIA_TPCE_IR_HASMASK) {
! 1189: /*
! 1190: * it's legal to ignore the
! 1191: * special-interrupt bits, so I will
! 1192: */
! 1193:
! 1194: cfe->irqmask =
! 1195: pcmcia_tuple_read_2(tuple, idx);
! 1196: idx += 2;
! 1197: } else {
! 1198: cfe->irqmask =
! 1199: (1 << (reg & PCMCIA_TPCE_IR_IRQ));
! 1200: }
! 1201: }
! 1202: if (memspace) {
! 1203: if (tuple->length <= idx) {
! 1204: DPRINTF(("ran out of space before TPCE_MS\n"));
! 1205: goto abort_cfe;
! 1206: }
! 1207:
! 1208: if (memspace == PCMCIA_TPCE_FS_MEMSPACE_NONE) {
! 1209: cfe->num_memspace = 0;
! 1210: } else if (memspace == PCMCIA_TPCE_FS_MEMSPACE_LENGTH) {
! 1211: cfe->num_memspace = 1;
! 1212: cfe->memspace[0].length = 256 *
! 1213: pcmcia_tuple_read_2(tuple, idx);
! 1214: idx += 2;
! 1215: cfe->memspace[0].cardaddr = 0;
! 1216: cfe->memspace[0].hostaddr = 0;
! 1217: } else if (memspace ==
! 1218: PCMCIA_TPCE_FS_MEMSPACE_LENGTHADDR) {
! 1219: cfe->num_memspace = 1;
! 1220: cfe->memspace[0].length = 256 *
! 1221: pcmcia_tuple_read_2(tuple, idx);
! 1222: idx += 2;
! 1223: cfe->memspace[0].cardaddr = 256 *
! 1224: pcmcia_tuple_read_2(tuple, idx);
! 1225: idx += 2;
! 1226: cfe->memspace[0].hostaddr = cfe->memspace[0].cardaddr;
! 1227: } else {
! 1228: int lengthsize;
! 1229: int cardaddrsize;
! 1230: int hostaddrsize;
! 1231:
! 1232: reg = pcmcia_tuple_read_1(tuple, idx);
! 1233: idx++;
! 1234:
! 1235: cfe->num_memspace = (reg &
! 1236: PCMCIA_TPCE_MS_COUNT) + 1;
! 1237:
! 1238: if (cfe->num_memspace >
! 1239: (sizeof(cfe->memspace) /
! 1240: sizeof(cfe->memspace[0]))) {
! 1241: DPRINTF(("too many mem "
! 1242: "spaces %d",
! 1243: cfe->num_memspace));
! 1244: state->card->error++;
! 1245: break;
! 1246: }
! 1247: lengthsize =
! 1248: ((reg & PCMCIA_TPCE_MS_LENGTH_SIZE_MASK) >>
! 1249: PCMCIA_TPCE_MS_LENGTH_SIZE_SHIFT);
! 1250: cardaddrsize =
! 1251: ((reg & PCMCIA_TPCE_MS_CARDADDR_SIZE_MASK) >>
! 1252: PCMCIA_TPCE_MS_CARDADDR_SIZE_SHIFT);
! 1253: hostaddrsize =
! 1254: (reg & PCMCIA_TPCE_MS_HOSTADDR) ? cardaddrsize : 0;
! 1255:
! 1256: if (lengthsize == 0) {
! 1257: DPRINTF(("cfe memspace "
! 1258: "lengthsize == 0"));
! 1259: state->card->error++;
! 1260: }
! 1261: for (i = 0; i < cfe->num_memspace; i++) {
! 1262: if (lengthsize) {
! 1263: cfe->memspace[i].length =
! 1264: 256 * pcmcia_tuple_read_n(tuple, lengthsize,
! 1265: idx);
! 1266: idx += lengthsize;
! 1267: } else {
! 1268: cfe->memspace[i].length = 0;
! 1269: }
! 1270: if (cfe->memspace[i].length == 0) {
! 1271: DPRINTF(("cfe->memspace[%d].length == 0",
! 1272: i));
! 1273: state->card->error++;
! 1274: }
! 1275: if (cardaddrsize) {
! 1276: cfe->memspace[i].cardaddr =
! 1277: 256 * pcmcia_tuple_read_n(tuple, cardaddrsize,
! 1278: idx);
! 1279: idx += cardaddrsize;
! 1280: } else {
! 1281: cfe->memspace[i].cardaddr = 0;
! 1282: }
! 1283: if (hostaddrsize) {
! 1284: cfe->memspace[i].hostaddr =
! 1285: 256 * pcmcia_tuple_read_n(tuple, hostaddrsize,
! 1286: idx);
! 1287: idx += hostaddrsize;
! 1288: } else {
! 1289: cfe->memspace[i].hostaddr = 0;
! 1290: }
! 1291: }
! 1292: }
! 1293: }
! 1294: if (misc) {
! 1295: if (tuple->length <= idx) {
! 1296: DPRINTF(("ran out of space before TPCE_MI\n"));
! 1297:
! 1298: goto abort_cfe;
! 1299: }
! 1300:
! 1301: reg = pcmcia_tuple_read_1(tuple, idx);
! 1302: idx++;
! 1303:
! 1304: cfe->flags &= ~(PCMCIA_CFE_POWERDOWN
! 1305: | PCMCIA_CFE_READONLY
! 1306: | PCMCIA_CFE_AUDIO);
! 1307: if (reg & PCMCIA_TPCE_MI_PWRDOWN)
! 1308: cfe->flags |= PCMCIA_CFE_POWERDOWN;
! 1309: if (reg & PCMCIA_TPCE_MI_READONLY)
! 1310: cfe->flags |= PCMCIA_CFE_READONLY;
! 1311: if (reg & PCMCIA_TPCE_MI_AUDIO)
! 1312: cfe->flags |= PCMCIA_CFE_AUDIO;
! 1313: cfe->maxtwins = reg & PCMCIA_TPCE_MI_MAXTWINS;
! 1314:
! 1315: while (reg & PCMCIA_TPCE_MI_EXT) {
! 1316: reg = pcmcia_tuple_read_1(tuple, idx);
! 1317: idx++;
! 1318: }
! 1319: }
! 1320: /* skip all the subtuples */
! 1321: }
! 1322:
! 1323: abort_cfe:
! 1324: DPRINTF(("CISTPL_CFTABLE_ENTRY\n"));
! 1325: break;
! 1326:
! 1327: default:
! 1328: DPRINTF(("unhandled CISTPL %x\n", tuple->code));
! 1329: break;
! 1330: }
! 1331:
! 1332: return (0);
! 1333: }
CVSweb