nubus.c revision 1.56.2.2 1 /* $NetBSD: nubus.c,v 1.56.2.2 2004/09/18 14:36:56 skrll Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996 Allen Briggs. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Allen Briggs.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: nubus.c,v 1.56.2.2 2004/09/18 14:36:56 skrll Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/device.h>
39 #include <sys/buf.h>
40 #include <sys/conf.h>
41
42 #include <uvm/uvm_extern.h>
43
44 #include <machine/autoconf.h>
45 #include <machine/vmparam.h>
46 #include <machine/param.h>
47 #include <machine/cpu.h>
48 #include <machine/pte.h>
49 #include <machine/viareg.h>
50
51 #include <mac68k/nubus/nubus.h>
52
53 #ifdef DEBUG
54 #define NDB_PROBE 0x1
55 #define NDB_FOLLOW 0x2
56 #define NDB_ARITH 0x4
57 static int nubus_debug = 0 /* | NDB_PROBE | NDB_FOLLOW | NDB_ARITH */ ;
58 #endif
59
60 static int nubus_print __P((void *, const char *));
61 static int nubus_match __P((struct device *, struct cfdata *, void *));
62 static void nubus_attach __P((struct device *, struct device *, void *));
63 static int nubus_video_resource __P((int));
64
65 static int nubus_probe_slot __P((bus_space_tag_t, bus_space_handle_t,
66 int, nubus_slot *));
67 static u_int32_t nubus_calc_CRC __P((bus_space_tag_t, bus_space_handle_t,
68 nubus_slot *));
69
70 static u_long nubus_adjust_ptr __P((u_int8_t, u_long, long));
71 static u_int8_t nubus_read_1 __P((bus_space_tag_t, bus_space_handle_t,
72 u_int8_t, u_long));
73 #ifdef notyet
74 static u_int16_t nubus_read_2 __P((bus_space_tag_t, bus_space_handle_t,
75 u_int8_t, u_long));
76 #endif
77 static u_int32_t nubus_read_4 __P((bus_space_tag_t, bus_space_handle_t,
78 u_int8_t, u_long));
79
80 CFATTACH_DECL(nubus, sizeof(struct nubus_softc),
81 nubus_match, nubus_attach, NULL, NULL);
82
83 static int
84 nubus_match(parent, cf, aux)
85 struct device *parent;
86 struct cfdata *cf;
87 void *aux;
88 {
89 static int nubus_matched = 0;
90
91 /* Allow only one instance. */
92 if (nubus_matched)
93 return (0);
94
95 nubus_matched = 1;
96 return (1);
97 }
98
99 static void
100 nubus_attach(parent, self, aux)
101 struct device *parent, *self;
102 void *aux;
103 {
104 struct nubus_attach_args na_args;
105 struct mainbus_attach_args *mba;
106 bus_space_tag_t bst;
107 bus_space_handle_t bsh;
108 nubus_slot fmtblock;
109 nubus_dir dir;
110 nubus_dirent dirent;
111 nubus_type slottype;
112 u_long entry;
113 int i, rsrcid;
114 u_int8_t lanes;
115
116 mba = aux;
117 KASSERT(NULL != mba->mba_dmat);
118
119 printf("\n");
120
121 for (i = NUBUS_MIN_SLOT; i <= NUBUS_MAX_SLOT; i++) {
122 na_args.slot = i;
123 na_args.na_tag = bst = mba->mba_bst;
124 na_args.na_dmat = mba->mba_dmat;
125
126 if (bus_space_map(bst,
127 NUBUS_SLOT2PA(na_args.slot), NBMEMSIZE, 0, &bsh)) {
128 #ifdef DEBUG
129 if (nubus_debug & NDB_PROBE)
130 printf("%s: failed to map slot %x, "
131 "address %p (in use?)\n",
132 self->dv_xname, i,
133 (void *)NUBUS_SLOT2PA(i));
134 #endif
135 continue;
136 }
137
138 if (nubus_probe_slot(bst, bsh, i, &fmtblock) <= 0) {
139 notfound:
140 bus_space_unmap(bst, bsh, NBMEMSIZE);
141 continue;
142 }
143
144 rsrcid = 0x80;
145 lanes = fmtblock.bytelanes;
146
147 nubus_get_main_dir(&fmtblock, &dir);
148
149 /*
150 * Get the resource for the first function on the card.
151 * This is assumed to be at resource ID 0x80. If we can
152 * not find this entry (as we can not on some video cards),
153 * check to see if we can get a different ID from the list
154 * of video resources given to us by the booter. If that
155 * doesn't work either, take the first resource following
156 * the board resource.
157 * If we only find a board resource, report that.
158 * There are cards that do not have anything else; their
159 * driver then has to match on the board resource and
160 * the card name.
161 */
162 if (nubus_find_rsrc(bst, bsh,
163 &fmtblock, &dir, rsrcid, &dirent) <= 0) {
164 if ((rsrcid = nubus_video_resource(i)) == -1) {
165 int has_board_rsrc = 0;
166
167 /*
168 * Since nubus_find_rsrc failed, the directory
169 * is back at its base.
170 */
171 entry = dir.curr_ent;
172
173 /*
174 * All nubus cards should have a board
175 * resource, but be sure that's what it
176 * is before we skip it, and note the fact.
177 */
178 rsrcid = nubus_read_1(bst, bsh,
179 lanes, entry);
180 if (rsrcid == 0x1) {
181 has_board_rsrc = 1;
182 entry = nubus_adjust_ptr(lanes,
183 dir.curr_ent, 4);
184 }
185 rsrcid = nubus_read_1(bst, bsh, lanes, entry);
186 /* end of chain? */
187 if (rsrcid == 0xff) {
188 if (!has_board_rsrc)
189 goto notfound;
190 else
191 rsrcid = 0x01;
192 }
193 #ifdef DEBUG
194 if (nubus_debug & NDB_FOLLOW)
195 printf("\tUsing rsrc 0x%x.\n", rsrcid);
196 #endif
197 }
198 /*
199 * Try to find the resource passed by the booter
200 * or the one we just tracked down.
201 */
202 if (nubus_find_rsrc(bst, bsh,
203 &fmtblock, &dir, rsrcid, &dirent) <= 0)
204 goto notfound;
205 }
206
207 nubus_get_dir_from_rsrc(&fmtblock, &dirent, &dir);
208
209 if (nubus_find_rsrc(bst, bsh,
210 &fmtblock, &dir, NUBUS_RSRC_TYPE, &dirent) <= 0)
211 goto notfound;
212
213 if (nubus_get_ind_data(bst, bsh, &fmtblock, &dirent,
214 (caddr_t)&slottype, sizeof(nubus_type)) <= 0)
215 goto notfound;
216
217 /*
218 * If this is a display card, try to pull out the correct
219 * display mode as passed by the booter.
220 */
221 if (slottype.category == NUBUS_CATEGORY_DISPLAY) {
222 int r;
223
224 if ((r = nubus_video_resource(i)) != -1) {
225
226 nubus_get_main_dir(&fmtblock, &dir);
227
228 if (nubus_find_rsrc(bst, bsh,
229 &fmtblock, &dir, r, &dirent) <= 0)
230 goto notfound;
231
232 nubus_get_dir_from_rsrc(&fmtblock,
233 &dirent, &dir);
234
235 if (nubus_find_rsrc(bst, bsh, &fmtblock, &dir,
236 NUBUS_RSRC_TYPE, &dirent) <= 0)
237 goto notfound;
238
239 if (nubus_get_ind_data(bst, bsh,
240 &fmtblock, &dirent, (caddr_t)&slottype,
241 sizeof(nubus_type)) <= 0)
242 goto notfound;
243
244 rsrcid = r;
245 }
246 }
247
248 na_args.slot = i;
249 na_args.rsrcid = rsrcid;
250 na_args.category = slottype.category;
251 na_args.type = slottype.type;
252 na_args.drsw = slottype.drsw;
253 na_args.drhw = slottype.drhw;
254 na_args.fmt = &fmtblock;
255
256 bus_space_unmap(bst, bsh, NBMEMSIZE);
257
258 config_found(self, &na_args, nubus_print);
259 }
260
261 enable_nubus_intr();
262 }
263
264 static int
265 nubus_print(aux, pnp)
266 void *aux;
267 const char *pnp;
268 {
269 struct nubus_attach_args *na = (struct nubus_attach_args *)aux;
270 bus_space_tag_t bst = na->na_tag;
271 bus_space_handle_t bsh;
272
273 if (pnp) {
274 aprint_normal("%s slot %x", pnp, na->slot);
275 if (bus_space_map(bst,
276 NUBUS_SLOT2PA(na->slot), NBMEMSIZE, 0, &bsh) == 0) {
277 aprint_normal(": %s",
278 nubus_get_card_name(bst, bsh, na->fmt));
279 aprint_normal(" (Vendor: %s,",
280 nubus_get_vendor(bst, bsh,
281 na->fmt, NUBUS_RSRC_VEND_ID));
282 aprint_normal(" Part: %s)", nubus_get_vendor(bst, bsh,
283 na->fmt, NUBUS_RSRC_VEND_PART));
284 bus_space_unmap(bst, bsh, NBMEMSIZE);
285 }
286 #ifdef DIAGNOSTIC
287 else
288 aprint_normal(":");
289 aprint_normal(" Type: %04x %04x %04x %04x",
290 na->category, na->type, na->drsw, na->drhw);
291 #endif
292 } else {
293 aprint_normal(" slot %x", na->slot);
294 }
295 return (UNCONF);
296 }
297
298 static int
299 nubus_video_resource(slot)
300 int slot;
301 {
302 extern u_int16_t mac68k_vrsrc_vec[];
303 int i;
304
305 for (i = 0 ; i < 6 ; i++)
306 if ((mac68k_vrsrc_vec[i] & 0xff) == slot)
307 return ((mac68k_vrsrc_vec[i] >> 8) & 0xff);
308 return (-1);
309 }
310
311 /*
312 * Probe a given nubus slot. If a card is there and we can get the
313 * format block from it's clutching decl. ROMs, fill the format block
314 * and return non-zero. If we can't find a card there with a valid
315 * decl. ROM, return 0.
316 *
317 * First, we check to see if we can access the memory at the tail
318 * end of the slot. If so, then we check for a bytelanes byte. We
319 * could probably just return a failure status if we bus error on
320 * the first try, but there really is little reason not to go ahead
321 * and check the other three locations in case there's a weird card
322 * out there.
323 *
324 * Checking for a card involves locating the "bytelanes" byte which
325 * tells us how to interpret the declaration ROM's data. The format
326 * block is at the top of the card's standard memory space and the
327 * bytelanes byte is at the end of that block.
328 *
329 * After some inspection of the bytelanes byte, it appears that it
330 * takes the form 0xXY where Y is a bitmask of the bytelanes in use
331 * and X is a bitmask of the lanes to ignore. Hence, (X ^ Y) == 0
332 * and (less obviously), Y will have the upper N bits clear if it is
333 * found N bytes from the last possible location. Both that and
334 * the exclusive-or check are made.
335 *
336 * If a valid
337 */
338 static u_int8_t nbits[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
339 static int
340 nubus_probe_slot(bst, bsh, slot, fmt)
341 bus_space_tag_t bst;
342 bus_space_handle_t bsh;
343 int slot;
344 nubus_slot *fmt;
345 {
346 u_long ofs, hdr;
347 int i, j, found, hdr_size;
348 u_int8_t lanes;
349
350 #ifdef DEBUG
351 if (nubus_debug & NDB_PROBE)
352 printf("probing slot %x\n", slot);
353 #endif
354
355 /*
356 * The idea behind this glorious work of art is to probe for only
357 * valid bytelanes values at appropriate locations (see DC&D p. 159
358 * for a list). Note the pattern: the first 8 values are at offset
359 * 0xffffff in the slot's space; the next 4 values at 0xfffffe; the
360 * next 2 values at 0xfffffd; and the last one at 0xfffffc.
361 *
362 * The nested loops implement an efficient search of this space,
363 * probing first for a valid address, then checking for each of the
364 * valid bytelanes values at that address.
365 */
366 ofs = NBMEMSIZE;
367 lanes = 0xf;
368
369 for (j = 8, found = 0; j > 0 && !found; j >>= 1) {
370 ofs--;
371 for (i = j; i > 0; i--, lanes--) {
372 if (!mac68k_bus_space_probe(bst, bsh, ofs, 1)) {
373 lanes -= i;
374 break;
375 }
376 if (bus_space_read_1(bst, bsh, ofs) ==
377 (((~lanes & 0xf) << 4) | lanes)) {
378 found = 1;
379 break;
380 }
381 }
382 }
383
384 if (!found) {
385 #ifdef DEBUG
386 if (nubus_debug & NDB_PROBE)
387 printf("bytelanes not found for slot %x\n", slot);
388 #endif
389 return 0;
390 }
391
392 fmt->bytelanes = lanes;
393 fmt->step = nbits[(lanes & 0x0f)];
394 fmt->slot = slot; /* XXX redundant; get rid of this someday */
395
396 #ifdef DEBUG
397 if (nubus_debug & NDB_PROBE)
398 printf("bytelanes of 0x%x found for slot 0x%x.\n",
399 fmt->bytelanes, slot);
400 #endif
401
402 /*
403 * Go ahead and attempt to load format header.
404 * First, we need to find the first byte beyond memory that
405 * would be valid. This is necessary for NUBUS_ROM_offset()
406 * to work.
407 */
408 hdr = NBMEMSIZE;
409 hdr_size = 20;
410
411 i = 0x10 | (lanes & 0x0f);
412 while ((i & 1) == 0) {
413 hdr++;
414 i >>= 1;
415 }
416 fmt->top = hdr;
417 hdr = nubus_adjust_ptr(lanes, hdr, -hdr_size);
418 #ifdef DEBUG
419 if (nubus_debug & NDB_PROBE)
420 printf("fmt->top is 0x%lx, that minus 0x%x puts us at 0x%lx.\n",
421 fmt->top, hdr_size, hdr);
422 if (nubus_debug & NDB_ARITH)
423 for (i = 1 ; i < 8 ; i++)
424 printf("0x%lx - 0x%x = 0x%lx, + 0x%x = 0x%lx.\n",
425 hdr, i, nubus_adjust_ptr(lanes, hdr, -i),
426 i, nubus_adjust_ptr(lanes, hdr, i));
427 #endif
428
429 fmt->directory_offset =
430 0xff000000 | nubus_read_4(bst, bsh, lanes, hdr);
431 hdr = nubus_adjust_ptr(lanes, hdr, 4);
432 fmt->length = nubus_read_4(bst, bsh, lanes, hdr);
433 hdr = nubus_adjust_ptr(lanes, hdr, 4);
434 fmt->crc = nubus_read_4(bst, bsh, lanes, hdr);
435 hdr = nubus_adjust_ptr(lanes, hdr, 4);
436 fmt->revision_level = nubus_read_1(bst, bsh, lanes, hdr);
437 hdr = nubus_adjust_ptr(lanes, hdr, 1);
438 fmt->format = nubus_read_1(bst, bsh, lanes, hdr);
439 hdr = nubus_adjust_ptr(lanes, hdr, 1);
440 fmt->test_pattern = nubus_read_4(bst, bsh, lanes, hdr);
441
442 #ifdef DEBUG
443 if (nubus_debug & NDB_PROBE) {
444 printf("Directory offset 0x%x\t", fmt->directory_offset);
445 printf("Length 0x%x\t", fmt->length);
446 printf("CRC 0x%x\n", fmt->crc);
447 printf("Revision level 0x%x\t", fmt->revision_level);
448 printf("Format 0x%x\t", fmt->format);
449 printf("Test Pattern 0x%x\n", fmt->test_pattern);
450 }
451 #endif
452
453 if ((fmt->directory_offset & 0x00ff0000) == 0) {
454 printf("Invalid looking directory offset (0x%x)!\n",
455 fmt->directory_offset);
456 return 0;
457 }
458 if (fmt->test_pattern != NUBUS_ROM_TEST_PATTERN) {
459 printf("Nubus--test pattern invalid:\n");
460 printf(" slot 0x%x, bytelanes 0x%x?\n", fmt->slot, lanes);
461 printf(" read test 0x%x, compare with 0x%x.\n",
462 fmt->test_pattern, NUBUS_ROM_TEST_PATTERN);
463 return 0;
464 }
465
466 /* Perform CRC */
467 if (fmt->crc != nubus_calc_CRC(bst, bsh, fmt)) {
468 printf("Nubus--crc check failed, slot 0x%x.\n", fmt->slot);
469 return 0;
470 }
471
472 return 1;
473 }
474
475 static u_int32_t
476 nubus_calc_CRC(bst, bsh, fmt)
477 bus_space_tag_t bst;
478 bus_space_handle_t bsh;
479 nubus_slot *fmt;
480 {
481 #if 0
482 u_long base, ptr, crc_loc;
483 u_int32_t sum;
484 u_int8_t lanes = fmt->bytelanes;
485
486 base = fmt->top;
487 crc_loc = NUBUS_ROM_offset(fmt, base, -12);
488 ptr = NUBUS_ROM_offset(fmt, base, -fmt->length);
489
490 sum = 0;
491 while (ptr < base)
492 roll #1, sum
493 if (ptr == crc_loc) {
494 roll #3, sum
495 ptr = nubus_adjust_ptr(lanes, ptr, 3);
496 } else {
497 sum += nubus_read_1(bst, bsh, lanes, ptr);
498 }
499 ptr = nubus_adjust_ptr(lanes, ptr, 1);
500 }
501
502 return sum;
503 #endif
504 return fmt->crc;
505 }
506
507 /*
508 * Compute byte offset on card, taking into account bytelanes.
509 * Base must be on a valid bytelane for this function to work.
510 * Return the new address.
511 *
512 * XXX -- There has GOT to be a better way to do this.
513 */
514 static u_long
515 nubus_adjust_ptr(lanes, base, amt)
516 u_int8_t lanes;
517 u_long base;
518 long amt;
519 {
520 u_int8_t b, t;
521
522 if (!amt)
523 return base;
524
525 if (amt < 0) {
526 amt = -amt;
527 b = lanes;
528 t = (b << 4);
529 b <<= (3 - (base & 0x3));
530 while (amt) {
531 b <<= 1;
532 if (b == t)
533 b = lanes;
534 if (b & 0x08)
535 amt--;
536 base--;
537 }
538 return base;
539 }
540
541 t = (lanes & 0xf) | 0x10;
542 b = t >> (base & 0x3);
543 while (amt) {
544 b >>= 1;
545 if (b == 1)
546 b = t;
547 if (b & 1)
548 amt--;
549 base++;
550 }
551
552 return base;
553 }
554
555 static u_int8_t
556 nubus_read_1(bst, bsh, lanes, ofs)
557 bus_space_tag_t bst;
558 bus_space_handle_t bsh;
559 u_int8_t lanes;
560 u_long ofs;
561 {
562 return bus_space_read_1(bst, bsh, ofs);
563 }
564
565 #ifdef notyet
566 /* Nothing uses this, yet */
567 static u_int16_t
568 nubus_read_2(bst, bsh, lanes, ofs)
569 bus_space_tag_t bst;
570 bus_space_handle_t bsh;
571 u_int8_t lanes;
572 u_long ofs;
573 {
574 u_int16_t s;
575
576 s = (nubus_read_1(bst, bsh, lanes, ofs) << 8);
577 ofs = nubus_adjust_ptr(lanes, ofs, 1);
578 s |= nubus_read_1(bst, bsh, lanes, ofs);
579 return s;
580 }
581 #endif
582
583 static u_int32_t
584 nubus_read_4(bst, bsh, lanes, ofs)
585 bus_space_tag_t bst;
586 bus_space_handle_t bsh;
587 u_int8_t lanes;
588 u_long ofs;
589 {
590 u_int32_t l;
591 int i;
592
593 l = 0;
594 for (i = 0; i < 4; i++) {
595 l = (l << 8) | nubus_read_1(bst, bsh, lanes, ofs);
596 ofs = nubus_adjust_ptr(lanes, ofs, 1);
597 }
598 return l;
599 }
600
601 void
602 nubus_get_main_dir(fmt, dir_return)
603 nubus_slot *fmt;
604 nubus_dir *dir_return;
605 {
606 #ifdef DEBUG
607 if (nubus_debug & NDB_FOLLOW)
608 printf("nubus_get_main_dir(%p, %p)\n",
609 fmt, dir_return);
610 #endif
611 dir_return->dirbase = nubus_adjust_ptr(fmt->bytelanes, fmt->top,
612 fmt->directory_offset - 20);
613 dir_return->curr_ent = dir_return->dirbase;
614 }
615
616 void
617 nubus_get_dir_from_rsrc(fmt, dirent, dir_return)
618 nubus_slot *fmt;
619 nubus_dirent *dirent;
620 nubus_dir *dir_return;
621 {
622 u_long loc;
623
624 #ifdef DEBUG
625 if (nubus_debug & NDB_FOLLOW)
626 printf("nubus_get_dir_from_rsrc(%p, %p, %p).\n",
627 fmt, dirent, dir_return);
628 #endif
629 if ((loc = dirent->offset) & 0x800000) {
630 loc |= 0xff000000;
631 }
632 dir_return->dirbase =
633 nubus_adjust_ptr(fmt->bytelanes, dirent->myloc, loc);
634 dir_return->curr_ent = dir_return->dirbase;
635 }
636
637 int
638 nubus_find_rsrc(bst, bsh, fmt, dir, rsrcid, dirent_return)
639 bus_space_tag_t bst;
640 bus_space_handle_t bsh;
641 nubus_slot *fmt;
642 nubus_dir *dir;
643 u_int8_t rsrcid;
644 nubus_dirent *dirent_return;
645 {
646 u_long entry;
647 u_int8_t byte, lanes = fmt->bytelanes;
648
649 #ifdef DEBUG
650 if (nubus_debug & NDB_FOLLOW)
651 printf("nubus_find_rsrc(%p, %p, 0x%x, %p)\n",
652 fmt, dir, rsrcid, dirent_return);
653 #endif
654 if (fmt->test_pattern != NUBUS_ROM_TEST_PATTERN)
655 return -1;
656
657 entry = dir->curr_ent;
658 do {
659 byte = nubus_read_1(bst, bsh, lanes, entry);
660 #ifdef DEBUG
661 if (nubus_debug & NDB_FOLLOW)
662 printf("\tFound rsrc 0x%x.\n", byte);
663 #endif
664 if (byte == rsrcid) {
665 dirent_return->myloc = entry;
666 dirent_return->rsrc_id = rsrcid;
667 entry = nubus_read_4(bst, bsh, lanes, entry);
668 dirent_return->offset = (entry & 0x00ffffff);
669 return 1;
670 }
671 if (byte == 0xff) {
672 entry = dir->dirbase;
673 } else {
674 entry = nubus_adjust_ptr(lanes, entry, 4);
675 }
676 } while (entry != (u_long)dir->curr_ent);
677 return 0;
678 }
679
680 int
681 nubus_get_ind_data(bst, bsh, fmt, dirent, data_return, nbytes)
682 bus_space_tag_t bst;
683 bus_space_handle_t bsh;
684 nubus_slot *fmt;
685 nubus_dirent *dirent;
686 caddr_t data_return;
687 int nbytes;
688 {
689 u_long loc;
690 u_int8_t lanes = fmt->bytelanes;
691
692 #ifdef DEBUG
693 if (nubus_debug & NDB_FOLLOW)
694 printf("nubus_get_ind_data(%p, %p, %p, %d).\n",
695 fmt, dirent, data_return, nbytes);
696 #endif
697 if ((loc = dirent->offset) & 0x800000) {
698 loc |= 0xff000000;
699 }
700 loc = nubus_adjust_ptr(lanes, dirent->myloc, loc);
701
702 while (nbytes--) {
703 *data_return++ = nubus_read_1(bst, bsh, lanes, loc);
704 loc = nubus_adjust_ptr(lanes, loc, 1);
705 }
706 return 1;
707 }
708
709 int
710 nubus_get_c_string(bst, bsh, fmt, dirent, data_return, max_bytes)
711 bus_space_tag_t bst;
712 bus_space_handle_t bsh;
713 nubus_slot *fmt;
714 nubus_dirent *dirent;
715 caddr_t data_return;
716 int max_bytes;
717 {
718 u_long loc;
719 u_int8_t lanes = fmt->bytelanes;
720
721 #ifdef DEBUG
722 if (nubus_debug & NDB_FOLLOW)
723 printf("nubus_get_c_string(%p, %p, %p, %d).\n",
724 fmt, dirent, data_return, max_bytes);
725 #endif
726 if ((loc = dirent->offset) & 0x800000)
727 loc |= 0xff000000;
728
729 loc = nubus_adjust_ptr(lanes, dirent->myloc, loc);
730
731 *data_return = '\0';
732 while (max_bytes--) {
733 if ((*data_return++ =
734 nubus_read_1(bst, bsh, lanes, loc)) == 0)
735 return 1;
736 loc = nubus_adjust_ptr(lanes, loc, 1);
737 }
738 *(data_return-1) = '\0';
739 return 0;
740 }
741
742 /*
743 * Get list of address ranges for an sMemory resource
744 * -> DC&D, p.171
745 */
746 int
747 nubus_get_smem_addr_rangelist(bst, bsh, fmt, dirent, data_return)
748 bus_space_tag_t bst;
749 bus_space_handle_t bsh;
750 nubus_slot *fmt;
751 nubus_dirent *dirent;
752 caddr_t data_return;
753 {
754 u_long loc;
755 u_int8_t lanes = fmt->bytelanes;
756 long blocklen;
757 caddr_t blocklist;
758
759 #ifdef DEBUG
760 if (nubus_debug & NDB_FOLLOW)
761 printf("nubus_get_smem_addr_rangelist(%p, %p, %p).\n",
762 fmt, dirent, data_return);
763 #endif
764 if ((loc = dirent->offset) & 0x800000) {
765 loc |= 0xff000000;
766 }
767 loc = nubus_adjust_ptr(lanes, dirent->myloc, loc);
768
769 /* Obtain the block length from the head of the list */
770 blocklen = nubus_read_4(bst, bsh, lanes, loc);
771
772 /*
773 * malloc a block of (blocklen) bytes
774 * caller must recycle block after use
775 */
776 MALLOC(blocklist,caddr_t,blocklen,M_TEMP,M_WAITOK);
777
778 /* read ((blocklen - 4) / 8) (length,offset) pairs into block */
779 nubus_get_ind_data(bst, bsh, fmt, dirent, blocklist, blocklen);
780 #ifdef DEBUG
781 if (nubus_debug & NDB_FOLLOW) {
782 int ii;
783 nubus_smem_rangelist *rlist;
784
785 rlist = (nubus_smem_rangelist *)blocklist;
786 printf("\tblock@%p, len 0x0%X\n", rlist, rlist->length);
787
788 for (ii=0; ii < ((blocklen - 4) / 8); ii++) {
789 printf("\tRange %d: base addr 0x%X [0x%X]\n", ii,
790 rlist->range[ii].offset, rlist->range[ii].length);
791 }
792 }
793 #endif
794 *(caddr_t *)data_return = blocklist;
795
796 return 1;
797 }
798
799 static char *huh = "???";
800
801 char *
802 nubus_get_vendor(bst, bsh, fmt, rsrc)
803 bus_space_tag_t bst;
804 bus_space_handle_t bsh;
805 nubus_slot *fmt;
806 int rsrc;
807 {
808 static char str_ret[64];
809 nubus_dir dir;
810 nubus_dirent ent;
811
812 #ifdef DEBUG
813 if (nubus_debug & NDB_FOLLOW)
814 printf("nubus_get_vendor(%p, 0x%x).\n", fmt, rsrc);
815 #endif
816 nubus_get_main_dir(fmt, &dir);
817 if (nubus_find_rsrc(bst, bsh, fmt, &dir, 1, &ent) <= 0)
818 return huh;
819 nubus_get_dir_from_rsrc(fmt, &ent, &dir);
820
821 if (nubus_find_rsrc(bst, bsh, fmt, &dir, NUBUS_RSRC_VENDORINFO, &ent)
822 <= 0)
823 return huh;
824 nubus_get_dir_from_rsrc(fmt, &ent, &dir);
825
826 if (nubus_find_rsrc(bst, bsh, fmt, &dir, rsrc, &ent) <= 0)
827 return huh;
828
829 nubus_get_c_string(bst, bsh, fmt, &ent, str_ret, 64);
830
831 return str_ret;
832 }
833
834 char *
835 nubus_get_card_name(bst, bsh, fmt)
836 bus_space_tag_t bst;
837 bus_space_handle_t bsh;
838 nubus_slot *fmt;
839 {
840 static char name_ret[64];
841 nubus_dir dir;
842 nubus_dirent ent;
843
844 #ifdef DEBUG
845 if (nubus_debug & NDB_FOLLOW)
846 printf("nubus_get_card_name(%p).\n", fmt);
847 #endif
848 nubus_get_main_dir(fmt, &dir);
849
850 if (nubus_find_rsrc(bst, bsh, fmt, &dir, 1, &ent) <= 0)
851 return huh;
852
853 nubus_get_dir_from_rsrc(fmt, &ent, &dir);
854
855 if (nubus_find_rsrc(bst, bsh, fmt, &dir, NUBUS_RSRC_NAME, &ent) <= 0)
856 return huh;
857
858 nubus_get_c_string(bst, bsh, fmt, &ent, name_ret, 64);
859
860 return name_ret;
861 }
862
863 #ifdef DEBUG
864 void
865 nubus_scan_slot(bst, slotno)
866 bus_space_tag_t bst;
867 int slotno;
868 {
869 int i=0, state=0;
870 char twirl[] = "-\\|/";
871 bus_space_handle_t sc_bsh;
872
873 if (bus_space_map(bst, NUBUS_SLOT2PA(slotno), NBMEMSIZE, 0, &sc_bsh)) {
874 printf("nubus_scan_slot: failed to map slot %x\n", slotno);
875 return;
876 }
877
878 printf("Scanning slot %c for accessible regions:\n",
879 slotno == 9 ? '9' : slotno - 10 + 'A');
880 for (i=0 ; i<NBMEMSIZE; i++) {
881 if (mac68k_bus_space_probe(bst, sc_bsh, i, 1)) {
882 if (state == 0) {
883 printf("\t0x%x-", i);
884 state = 1;
885 }
886 } else {
887 if (state) {
888 printf("0x%x\n", i);
889 state = 0;
890 }
891 }
892 if (i%100 == 0) {
893 printf("%c\b", twirl[(i/100)%4]);
894 }
895 }
896 if (state) {
897 printf("0x%x\n", i);
898 }
899 return;
900 }
901 #endif
902