1 /* $NetBSD: nubus.c,v 1.57 2003/07/15 02:43:24 lukem 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.57 2003/07/15 02:43:24 lukem 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