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