Annotation of sys/dev/pcmcia/pcmcia_cis.c, Revision 1.1.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