1 /*-
2 * Copyright (c) 2000,2001 Jonathan Chen.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: releng/6.0/sys/dev/cardbus/cardbus_cis.c 142144 2005-02-20 20:36:16Z imp $");
29
30 /*
31 * CIS Handling for the Cardbus Bus
32 */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38
39 #include <sys/bus.h>
40 #include <machine/bus.h>
41 #include <machine/resource.h>
42 #include <sys/rman.h>
43 #include <sys/endian.h>
44
45 #include <sys/pciio.h>
46 #include <dev/pci/pcivar.h>
47 #include <dev/pci/pcireg.h>
48
49 #include <dev/pccard/pccardvar.h>
50 #include <dev/pccard/pccard_cis.h>
51
52 #include <dev/cardbus/cardbusreg.h>
53 #include <dev/cardbus/cardbusvar.h>
54 #include <dev/cardbus/cardbus_cis.h>
55
56 extern int cardbus_cis_debug;
57
58 #define DPRINTF(a) if (cardbus_cis_debug) printf a
59 #define DEVPRINTF(x) if (cardbus_cis_debug) device_printf x
60
61 struct tuple_callbacks;
62
63 typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
64 uint8_t *tupledata, uint32_t start, uint32_t *off,
65 struct tuple_callbacks *info);
66
67 struct tuple_callbacks {
68 int id;
69 char *name;
70 tuple_cb *func;
71 };
72
73 static int decode_tuple_generic(device_t cbdev, device_t child, int id,
74 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
75 struct tuple_callbacks *info);
76 static int decode_tuple_linktarget(device_t cbdev, device_t child, int id,
77 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
78 struct tuple_callbacks *info);
79 static int decode_tuple_vers_1(device_t cbdev, device_t child, int id,
80 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
81 struct tuple_callbacks *info);
82 static int decode_tuple_funcid(device_t cbdev, device_t child, int id,
83 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
84 struct tuple_callbacks *info);
85 static int decode_tuple_manfid(device_t cbdev, device_t child, int id,
86 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
87 struct tuple_callbacks *info);
88 static int decode_tuple_funce(device_t cbdev, device_t child, int id,
89 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
90 struct tuple_callbacks *info);
91 static int decode_tuple_bar(device_t cbdev, device_t child, int id,
92 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
93 struct tuple_callbacks *info);
94 static int decode_tuple_unhandled(device_t cbdev, device_t child, int id,
95 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
96 struct tuple_callbacks *info);
97 static int decode_tuple_end(device_t cbdev, device_t child, int id,
98 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
99 struct tuple_callbacks *info);
100
101 static int cardbus_read_tuple_conf(device_t cbdev, device_t child,
102 uint32_t start, uint32_t *off, int *tupleid, int *len,
103 uint8_t *tupledata);
104 static int cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
105 uint32_t start, uint32_t *off, int *tupleid, int *len,
106 uint8_t *tupledata);
107 static int cardbus_read_tuple(device_t cbdev, device_t child,
108 struct resource *res, uint32_t start, uint32_t *off,
109 int *tupleid, int *len, uint8_t *tupledata);
110 static void cardbus_read_tuple_finish(device_t cbdev, device_t child,
111 int rid, struct resource *res);
112 static struct resource *cardbus_read_tuple_init(device_t cbdev, device_t child,
113 uint32_t *start, int *rid);
114 static int decode_tuple(device_t cbdev, device_t child, int tupleid,
115 int len, uint8_t *tupledata, uint32_t start,
116 uint32_t *off, struct tuple_callbacks *callbacks);
117 static int cardbus_parse_cis(device_t cbdev, device_t child,
118 struct tuple_callbacks *callbacks);
119
120 #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
121
122 static char *funcnames[] = {
123 "Multi-Functioned",
124 "Memory",
125 "Serial Port",
126 "Parallel Port",
127 "Fixed Disk",
128 "Video Adaptor",
129 "Network Adaptor",
130 "AIMS",
131 "SCSI",
132 "Security"
133 };
134
135 /*
136 * Handler functions for various CIS tuples
137 */
138
139 static int
140 decode_tuple_generic(device_t cbdev, device_t child, int id,
141 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
142 struct tuple_callbacks *info)
143 {
144 int i;
145
146 if (cardbus_cis_debug) {
147 if (info)
148 printf("TUPLE: %s [%d]:", info->name, len);
149 else
150 printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
151
152 for (i = 0; i < len; i++) {
153 if (i % 0x10 == 0 && len > 0x10)
154 printf("\n 0x%02x:", i);
155 printf(" %02x", tupledata[i]);
156 }
157 printf("\n");
158 }
159 return (0);
160 }
161
162 static int
163 decode_tuple_linktarget(device_t cbdev, device_t child, int id,
164 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
165 struct tuple_callbacks *info)
166 {
167 int i;
168
169 if (cardbus_cis_debug) {
170 printf("TUPLE: %s [%d]:", info->name, len);
171
172 for (i = 0; i < len; i++) {
173 if (i % 0x10 == 0 && len > 0x10)
174 printf("\n 0x%02x:", i);
175 printf(" %02x", tupledata[i]);
176 }
177 printf("\n");
178 }
179 if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
180 tupledata[2] != 'S') {
181 printf("Invalid data for CIS Link Target!\n");
182 decode_tuple_generic(cbdev, child, id, len, tupledata,
183 start, off, info);
184 return (EINVAL);
185 }
186 return (0);
187 }
188
189 static int
190 decode_tuple_vers_1(device_t cbdev, device_t child, int id,
191 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
192 struct tuple_callbacks *info)
193 {
194 int i;
195
196 if (cardbus_cis_debug) {
197 printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
198 printf("Product name: ");
199 for (i = 2; i < len; i++) {
200 if (tupledata[i] == '\0')
201 printf(" | ");
202 else if (tupledata[i] == 0xff)
203 break;
204 else
205 printf("%c", tupledata[i]);
206 }
207 printf("\n");
208 }
209 return (0);
210 }
211
212 static int
213 decode_tuple_funcid(device_t cbdev, device_t child, int id,
214 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
215 struct tuple_callbacks *info)
216 {
217 struct cardbus_devinfo *dinfo = device_get_ivars(child);
218 int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
219 int i;
220
221 if (cardbus_cis_debug) {
222 printf("Functions: ");
223 for (i = 0; i < len; i++) {
224 if (tupledata[i] < numnames)
225 printf("%s", funcnames[tupledata[i]]);
226 else
227 printf("Unknown(%d)", tupledata[i]);
228 if (i < len-1)
229 printf(", ");
230 }
231 printf("\n");
232 }
233 if (len > 0)
234 dinfo->funcid = tupledata[0]; /* use first in list */
235 return (0);
236 }
237
238 static int
239 decode_tuple_manfid(device_t cbdev, device_t child, int id,
240 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
241 struct tuple_callbacks *info)
242 {
243 struct cardbus_devinfo *dinfo = device_get_ivars(child);
244 int i;
245
246 if (cardbus_cis_debug) {
247 printf("Manufacturer ID: ");
248 for (i = 0; i < len; i++)
249 printf("%02x", tupledata[i]);
250 printf("\n");
251 }
252
253 if (len == 5) {
254 dinfo->mfrid = tupledata[1] | (tupledata[2] << 8);
255 dinfo->prodid = tupledata[3] | (tupledata[4] << 8);
256 }
257 return (0);
258 }
259
260 static int
261 decode_tuple_funce(device_t cbdev, device_t child, int id,
262 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
263 struct tuple_callbacks *info)
264 {
265 struct cardbus_devinfo *dinfo = device_get_ivars(child);
266 int type, i;
267
268 if (cardbus_cis_debug) {
269 printf("Function Extension: ");
270 for (i = 0; i < len; i++)
271 printf("%02x", tupledata[i]);
272 printf("\n");
273 }
274 if (len < 2) /* too short */
275 return (0);
276 type = tupledata[0]; /* XXX <32 always? */
277 switch (dinfo->funcid) {
278 case PCCARD_FUNCTION_NETWORK:
279 switch (type) {
280 case PCCARD_TPLFE_TYPE_LAN_NID:
281 if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) {
282 /* ignore, warning? */
283 return (0);
284 }
285 bcopy(tupledata + 2, dinfo->funce.lan.nid,
286 tupledata[1]);
287 break;
288 }
289 dinfo->fepresent |= 1<<type;
290 break;
291 }
292 return (0);
293 }
294
295 static int
296 decode_tuple_bar(device_t cbdev, device_t child, int id,
297 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
298 struct tuple_callbacks *info)
299 {
300 struct cardbus_devinfo *dinfo = device_get_ivars(child);
301 int type;
302 uint8_t reg;
303 uint32_t bar, pci_bar;
304
305 if (len != 6) {
306 device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len);
307 return (EINVAL);
308 }
309
310 reg = *tupledata;
311 len = le32toh(*(uint32_t*)(tupledata + 2));
312 if (reg & TPL_BAR_REG_AS) {
313 type = SYS_RES_IOPORT;
314 } else {
315 type = SYS_RES_MEMORY;
316 }
317
318 bar = reg & TPL_BAR_REG_ASI_MASK;
319 if (bar == 0) {
320 device_printf(cbdev, "Invalid BAR type 0 in CIS\n");
321 return (EINVAL); /* XXX Return an error? */
322 } else if (bar == 7) {
323 /* XXX Should we try to map in Option ROMs? */
324 return (0);
325 }
326
327 /* Convert from BAR type to BAR offset */
328 bar = CARDBUS_BASE0_REG + (bar - 1) * 4;
329
330 if (type == SYS_RES_MEMORY) {
331 if (reg & TPL_BAR_REG_PREFETCHABLE)
332 dinfo->mprefetchable |= BARBIT(bar);
333 #if 0
334 /*
335 * XXX: It appears from a careful reading of the spec
336 * that we're not supposed to honor this when the bridge
337 * is not on the main system bus. PCI spec doesn't appear
338 * to allow for memory ranges not listed in the bridge's
339 * decode range to be decoded. The PC Card spec seems to
340 * indicate that this should only be done on x86 based
341 * machines, which seems to imply that on non-x86 machines
342 * the adddresses can be anywhere. This further implies that
343 * since the hardware can do it on non-x86 machines, it should
344 * be able to do it on x86 machines. Therefore, we can and
345 * should ignore this hint. Furthermore, the PC Card spec
346 * recommends always allocating memory above 1MB, contradicting
347 * the other part of the PC Card spec.
348 *
349 * NetBSD ignores this bit, but it also ignores the
350 * prefetchable bit too, so that's not an indication of
351 * correctness.
352 */
353 if (reg & TPL_BAR_REG_BELOW1MB)
354 dinfo->mbelow1mb |= BARBIT(bar);
355 #endif
356 }
357
358 /*
359 * Sanity check the BAR length reported in the CIS with the length
360 * encoded in the PCI BAR. The latter seems to be more reliable.
361 * XXX - This probably belongs elsewhere.
362 */
363 pci_write_config(child, bar, 0xffffffff, 4);
364 pci_bar = pci_read_config(child, bar, 4);
365 if ((pci_bar != 0x0) && (pci_bar != 0xffffffff)) {
366 if (type == SYS_RES_MEMORY) {
367 pci_bar &= ~0xf;
368 } else {
369 pci_bar &= ~0x3;
370 }
371 len = 1 << (ffs(pci_bar) - 1);
372 }
373
374 DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
375 (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
376 (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
377 " (Prefetchable)" : "", type == SYS_RES_MEMORY ?
378 ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") : ""));
379
380 resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len);
381
382 /*
383 * Mark the appropriate bit in the PCI command register so that
384 * device drivers will know which type of BARs can be used.
385 */
386 pci_enable_io(child, type);
387 return (0);
388 }
389
390 static int
391 decode_tuple_unhandled(device_t cbdev, device_t child, int id,
392 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
393 struct tuple_callbacks *info)
394 {
395 /* Make this message suck less XXX */
396 printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
397 return (-1);
398 }
399
400 static int
401 decode_tuple_end(device_t cbdev, device_t child, int id,
402 int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
403 struct tuple_callbacks *info)
404 {
405 if (cardbus_cis_debug)
406 printf("CIS reading done\n");
407 return (0);
408 }
409
410 /*
411 * Functions to read the a tuple from the card
412 */
413
414 static int
415 cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start,
416 uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
417 {
418 int i, j;
419 uint32_t e;
420 uint32_t loc;
421
422 loc = start + *off;
423
424 e = pci_read_config(child, loc - loc % 4, 4);
425 for (j = loc % 4; j > 0; j--)
426 e >>= 8;
427 *len = 0;
428 for (i = loc, j = -2; j < *len; j++, i++) {
429 if (i % 4 == 0)
430 e = pci_read_config(child, i, 4);
431 if (j == -2)
432 *tupleid = 0xff & e;
433 else if (j == -1)
434 *len = 0xff & e;
435 else
436 tupledata[j] = 0xff & e;
437 e >>= 8;
438 }
439 *off += *len + 2;
440 return (0);
441 }
442
443 static int
444 cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start,
445 uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
446 {
447 bus_space_tag_t bt;
448 bus_space_handle_t bh;
449 int ret;
450
451 bt = rman_get_bustag(res);
452 bh = rman_get_bushandle(res);
453
454 *tupleid = bus_space_read_1(bt, bh, start + *off);
455 *len = bus_space_read_1(bt, bh, start + *off + 1);
456 bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
457 ret = 0;
458 *off += *len + 2;
459 return (ret);
460 }
461
462 static int
463 cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
464 uint32_t start, uint32_t *off, int *tupleid, int *len,
465 uint8_t *tupledata)
466 {
467 if (res == (struct resource*)~0UL) {
468 return (cardbus_read_tuple_conf(cbdev, child, start, off,
469 tupleid, len, tupledata));
470 } else {
471 return (cardbus_read_tuple_mem(cbdev, res, start, off,
472 tupleid, len, tupledata));
473 }
474 }
475
476 static void
477 cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
478 struct resource *res)
479 {
480 if (res != (struct resource*)~0UL) {
481 bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
482 pci_write_config(child, rid, 0, 4);
483 PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
484 }
485 }
486
487 static struct resource *
488 cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
489 int *rid)
490 {
491 uint32_t testval;
492 uint32_t size;
493 struct resource *res;
494
495 switch (CARDBUS_CIS_SPACE(*start)) {
496 case CARDBUS_CIS_ASI_TUPLE:
497 /* CIS in PCI config space need no initialization */
498 return ((struct resource*)~0UL);
499 case CARDBUS_CIS_ASI_BAR0:
500 case CARDBUS_CIS_ASI_BAR1:
501 case CARDBUS_CIS_ASI_BAR2:
502 case CARDBUS_CIS_ASI_BAR3:
503 case CARDBUS_CIS_ASI_BAR4:
504 case CARDBUS_CIS_ASI_BAR5:
505 *rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
506 break;
507 case CARDBUS_CIS_ASI_ROM:
508 *rid = CARDBUS_ROM_REG;
509 #if 0
510 /*
511 * This mask doesn't contain the bit that actually enables
512 * the Option ROM.
513 */
514 pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4);
515 #endif
516 break;
517 default:
518 device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
519 CARDBUS_CIS_SPACE(*start));
520 return (NULL);
521 }
522
523 /* figure out how much space we need */
524 pci_write_config(child, *rid, 0xffffffff, 4);
525 testval = pci_read_config(child, *rid, 4);
526
527 /*
528 * This bit has a different meaning depending if we are dealing
529 * with a normal BAR or an Option ROM BAR.
530 */
531 if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) {
532 device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
533 return (NULL);
534 }
535
536 size = CARDBUS_MAPREG_MEM_SIZE(testval);
537 /* XXX Is this some kind of hack? */
538 if (size < 4096)
539 size = 4096;
540 /* allocate the memory space to read CIS */
541 res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size,
542 rman_make_alignment_flags(size) | RF_ACTIVE);
543 if (res == NULL) {
544 device_printf(cbdev, "Unable to allocate resource "
545 "to read CIS.\n");
546 return (NULL);
547 }
548 pci_write_config(child, *rid,
549 rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)?
550 CARDBUS_ROM_ENABLE : 0),
551 4);
552 PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY);
553
554 /* Flip to the right ROM image if CIS is in ROM */
555 if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
556 bus_space_tag_t bt;
557 bus_space_handle_t bh;
558 uint32_t imagesize;
559 uint32_t imagebase = 0;
560 uint32_t pcidata;
561 uint16_t romsig;
562 int romnum = 0;
563 int imagenum;
564
565 bt = rman_get_bustag(res);
566 bh = rman_get_bushandle(res);
567
568 imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
569 for (romnum = 0;; romnum++) {
570 romsig = bus_space_read_2(bt, bh,
571 imagebase + CARDBUS_EXROM_SIGNATURE);
572 if (romsig != 0xaa55) {
573 device_printf(cbdev, "Bad header in rom %d: "
574 "[%x] %04x\n", romnum, imagebase +
575 CARDBUS_EXROM_SIGNATURE, romsig);
576 bus_release_resource(cbdev, SYS_RES_MEMORY,
577 *rid, res);
578 *rid = 0;
579 return (NULL);
580 }
581
582 /*
583 * If this was the Option ROM image that we were
584 * looking for, then we are done.
585 */
586 if (romnum == imagenum)
587 break;
588
589 /* Find out where the next Option ROM image is */
590 pcidata = imagebase + bus_space_read_2(bt, bh,
591 imagebase + CARDBUS_EXROM_DATA_PTR);
592 imagesize = bus_space_read_2(bt, bh,
593 pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
594
595 if (imagesize == 0) {
596 /*
597 * XXX some ROMs seem to have this as zero,
598 * can we assume this means 1 block?
599 */
600 device_printf(cbdev, "Warning, size of Option "
601 "ROM image %d is 0 bytes, assuming 512 "
602 "bytes.\n", romnum);
603 imagesize = 1;
604 }
605
606 /* Image size is in 512 byte units */
607 imagesize <<= 9;
608
609 if ((bus_space_read_1(bt, bh, pcidata +
610 CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
611 device_printf(cbdev, "Cannot find CIS in "
612 "Option ROM\n");
613 bus_release_resource(cbdev, SYS_RES_MEMORY,
614 *rid, res);
615 *rid = 0;
616 return (NULL);
617 }
618 imagebase += imagesize;
619 }
620 *start = imagebase + CARDBUS_CIS_ADDR(*start);
621 } else {
622 *start = CARDBUS_CIS_ADDR(*start);
623 }
624
625 return (res);
626 }
627
628 /*
629 * Dispatch the right handler function per tuple
630 */
631
632 static int
633 decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
634 uint8_t *tupledata, uint32_t start, uint32_t *off,
635 struct tuple_callbacks *callbacks)
636 {
637 int i;
638 for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
639 if (tupleid == callbacks[i].id)
640 return (callbacks[i].func(cbdev, child, tupleid, len,
641 tupledata, start, off, &callbacks[i]));
642 }
643 return (callbacks[i].func(cbdev, child, tupleid, len,
644 tupledata, start, off, NULL));
645 }
646
647 static int
648 cardbus_parse_cis(device_t cbdev, device_t child,
649 struct tuple_callbacks *callbacks)
650 {
651 uint8_t tupledata[MAXTUPLESIZE];
652 int tupleid;
653 int len;
654 int expect_linktarget;
655 uint32_t start, off;
656 struct resource *res;
657 int rid;
658
659 bzero(tupledata, MAXTUPLESIZE);
660 expect_linktarget = TRUE;
661 if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0) {
662 device_printf(cbdev, "CIS pointer is 0!\n");
663 return (ENXIO);
664 }
665 off = 0;
666 res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
667 if (res == NULL) {
668 device_printf(cbdev, "Unable to allocate resources for CIS\n");
669 return (ENXIO);
670 }
671
672 do {
673 if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
674 &tupleid, &len, tupledata)) {
675 device_printf(cbdev, "Failed to read CIS.\n");
676 cardbus_read_tuple_finish(cbdev, child, rid, res);
677 return (ENXIO);
678 }
679
680 if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
681 device_printf(cbdev, "Expecting link target, got 0x%x\n",
682 tupleid);
683 cardbus_read_tuple_finish(cbdev, child, rid, res);
684 return (EINVAL);
685 }
686 expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
687 tupledata, start, &off, callbacks);
688 if (expect_linktarget != 0) {
689 device_printf(cbdev, "Parsing failed with %d\n",
690 expect_linktarget);
691 cardbus_read_tuple_finish(cbdev, child, rid, res);
692 return (expect_linktarget);
693 }
694 } while (tupleid != CISTPL_END);
695 cardbus_read_tuple_finish(cbdev, child, rid, res);
696 return (0);
697 }
698
699 int
700 cardbus_do_cis(device_t cbdev, device_t child)
701 {
702 int ret;
703 struct tuple_callbacks init_callbacks[] = {
704 MAKETUPLE(LONGLINK_CB, unhandled),
705 MAKETUPLE(INDIRECT, unhandled),
706 MAKETUPLE(LONGLINK_MFC, unhandled),
707 MAKETUPLE(BAR, bar),
708 MAKETUPLE(LONGLINK_A, unhandled),
709 MAKETUPLE(LONGLINK_C, unhandled),
710 MAKETUPLE(LINKTARGET, linktarget),
711 MAKETUPLE(VERS_1, vers_1),
712 MAKETUPLE(MANFID, manfid),
713 MAKETUPLE(FUNCID, funcid),
714 MAKETUPLE(FUNCE, funce),
715 MAKETUPLE(END, end),
716 MAKETUPLE(GENERIC, generic),
717 };
718
719 ret = cardbus_parse_cis(cbdev, child, init_callbacks);
720 if (ret < 0)
721 return (ret);
722 return 0;
723 }
Cache object: 03fb08670e99d3c20b0a8a352beced84
|