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