linux/drivers/nubus/nubus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *      Macintosh Nubus Interface Code
   4 *
   5 *      Originally by Alan Cox
   6 *
   7 *      Mostly rewritten by David Huggins-Daines, C. Scott Ananian,
   8 *      and others.
   9 */
  10
  11#include <linux/types.h>
  12#include <linux/kernel.h>
  13#include <linux/string.h>
  14#include <linux/nubus.h>
  15#include <linux/errno.h>
  16#include <linux/init.h>
  17#include <linux/module.h>
  18#include <linux/seq_file.h>
  19#include <linux/slab.h>
  20#include <asm/setup.h>
  21#include <asm/page.h>
  22#include <asm/hwtest.h>
  23
  24/* Constants */
  25
  26/* This is, of course, the size in bytelanes, rather than the size in
  27   actual bytes */
  28#define FORMAT_BLOCK_SIZE 20
  29#define ROM_DIR_OFFSET 0x24
  30
  31#define NUBUS_TEST_PATTERN 0x5A932BC7
  32
  33/* Globals */
  34
  35LIST_HEAD(nubus_func_rsrcs);
  36
  37/* Meaning of "bytelanes":
  38
  39   The card ROM may appear on any or all bytes of each long word in
  40   NuBus memory.  The low 4 bits of the "map" value found in the
  41   format block (at the top of the slot address space, as well as at
  42   the top of the MacOS ROM) tells us which bytelanes, i.e. which byte
  43   offsets within each longword, are valid.  Thus:
  44
  45   A map of 0x0f, as found in the MacOS ROM, means that all bytelanes
  46   are valid.
  47
  48   A map of 0xf0 means that no bytelanes are valid (We pray that we
  49   will never encounter this, but stranger things have happened)
  50
  51   A map of 0xe1 means that only the MSB of each long word is actually
  52   part of the card ROM.  (We hope to never encounter NuBus on a
  53   little-endian machine.  Again, stranger things have happened)
  54
  55   A map of 0x78 means that only the LSB of each long word is valid.
  56
  57   Etcetera, etcetera.  Hopefully this clears up some confusion over
  58   what the following code actually does.  */
  59
  60static inline int not_useful(void *p, int map)
  61{
  62        unsigned long pv = (unsigned long)p;
  63
  64        pv &= 3;
  65        if (map & (1 << pv))
  66                return 0;
  67        return 1;
  68}
  69
  70static unsigned long nubus_get_rom(unsigned char **ptr, int len, int map)
  71{
  72        /* This will hold the result */
  73        unsigned long v = 0;
  74        unsigned char *p = *ptr;
  75
  76        while (len) {
  77                v <<= 8;
  78                while (not_useful(p, map))
  79                        p++;
  80                v |= *p++;
  81                len--;
  82        }
  83        *ptr = p;
  84        return v;
  85}
  86
  87static void nubus_rewind(unsigned char **ptr, int len, int map)
  88{
  89        unsigned char *p = *ptr;
  90
  91        while (len) {
  92                do {
  93                        p--;
  94                } while (not_useful(p, map));
  95                len--;
  96        }
  97        *ptr = p;
  98}
  99
 100static void nubus_advance(unsigned char **ptr, int len, int map)
 101{
 102        unsigned char *p = *ptr;
 103
 104        while (len) {
 105                while (not_useful(p, map))
 106                        p++;
 107                p++;
 108                len--;
 109        }
 110        *ptr = p;
 111}
 112
 113static void nubus_move(unsigned char **ptr, int len, int map)
 114{
 115        unsigned long slot_space = (unsigned long)*ptr & 0xFF000000;
 116
 117        if (len > 0)
 118                nubus_advance(ptr, len, map);
 119        else if (len < 0)
 120                nubus_rewind(ptr, -len, map);
 121
 122        if (((unsigned long)*ptr & 0xFF000000) != slot_space)
 123                pr_err("%s: moved out of slot address space!\n", __func__);
 124}
 125
 126/* Now, functions to read the sResource tree */
 127
 128/* Each sResource entry consists of a 1-byte ID and a 3-byte data
 129   field.  If that data field contains an offset, then obviously we
 130   have to expand it from a 24-bit signed number to a 32-bit signed
 131   number. */
 132
 133static inline long nubus_expand32(long foo)
 134{
 135        if (foo & 0x00800000)   /* 24bit negative */
 136                foo |= 0xFF000000;
 137        return foo;
 138}
 139
 140static inline void *nubus_rom_addr(int slot)
 141{
 142        /*
 143         *      Returns the first byte after the card. We then walk
 144         *      backwards to get the lane register and the config
 145         */
 146        return (void *)(0xF1000000 + (slot << 24));
 147}
 148
 149unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
 150{
 151        unsigned char *p = nd->base;
 152
 153        /* Essentially, just step over the bytelanes using whatever
 154           offset we might have found */
 155        nubus_move(&p, nubus_expand32(nd->data), nd->mask);
 156        /* And return the value */
 157        return p;
 158}
 159
 160/* These two are for pulling resource data blocks (i.e. stuff that's
 161   pointed to with offsets) out of the card ROM. */
 162
 163void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
 164                        unsigned int len)
 165{
 166        unsigned char *t = (unsigned char *)dest;
 167        unsigned char *p = nubus_dirptr(dirent);
 168
 169        while (len) {
 170                *t++ = nubus_get_rom(&p, 1, dirent->mask);
 171                len--;
 172        }
 173}
 174EXPORT_SYMBOL(nubus_get_rsrc_mem);
 175
 176unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
 177                                unsigned int len)
 178{
 179        char *t = dest;
 180        unsigned char *p = nubus_dirptr(dirent);
 181
 182        while (len > 1) {
 183                unsigned char c = nubus_get_rom(&p, 1, dirent->mask);
 184
 185                if (!c)
 186                        break;
 187                *t++ = c;
 188                len--;
 189        }
 190        if (len > 0)
 191                *t = '\0';
 192        return t - dest;
 193}
 194EXPORT_SYMBOL(nubus_get_rsrc_str);
 195
 196void nubus_seq_write_rsrc_mem(struct seq_file *m,
 197                              const struct nubus_dirent *dirent,
 198                              unsigned int len)
 199{
 200        unsigned long buf[32];
 201        unsigned int buf_size = sizeof(buf);
 202        unsigned char *p = nubus_dirptr(dirent);
 203
 204        /* If possible, write out full buffers */
 205        while (len >= buf_size) {
 206                unsigned int i;
 207
 208                for (i = 0; i < ARRAY_SIZE(buf); i++)
 209                        buf[i] = nubus_get_rom(&p, sizeof(buf[0]),
 210                                               dirent->mask);
 211                seq_write(m, buf, buf_size);
 212                len -= buf_size;
 213        }
 214        /* If not, write out individual bytes */
 215        while (len--)
 216                seq_putc(m, nubus_get_rom(&p, 1, dirent->mask));
 217}
 218
 219int nubus_get_root_dir(const struct nubus_board *board,
 220                       struct nubus_dir *dir)
 221{
 222        dir->ptr = dir->base = board->directory;
 223        dir->done = 0;
 224        dir->mask = board->lanes;
 225        return 0;
 226}
 227EXPORT_SYMBOL(nubus_get_root_dir);
 228
 229/* This is a slyly renamed version of the above */
 230int nubus_get_func_dir(const struct nubus_rsrc *fres, struct nubus_dir *dir)
 231{
 232        dir->ptr = dir->base = fres->directory;
 233        dir->done = 0;
 234        dir->mask = fres->board->lanes;
 235        return 0;
 236}
 237EXPORT_SYMBOL(nubus_get_func_dir);
 238
 239int nubus_get_board_dir(const struct nubus_board *board,
 240                        struct nubus_dir *dir)
 241{
 242        struct nubus_dirent ent;
 243
 244        dir->ptr = dir->base = board->directory;
 245        dir->done = 0;
 246        dir->mask = board->lanes;
 247
 248        /* Now dereference it (the first directory is always the board
 249           directory) */
 250        if (nubus_readdir(dir, &ent) == -1)
 251                return -1;
 252        if (nubus_get_subdir(&ent, dir) == -1)
 253                return -1;
 254        return 0;
 255}
 256EXPORT_SYMBOL(nubus_get_board_dir);
 257
 258int nubus_get_subdir(const struct nubus_dirent *ent,
 259                     struct nubus_dir *dir)
 260{
 261        dir->ptr = dir->base = nubus_dirptr(ent);
 262        dir->done = 0;
 263        dir->mask = ent->mask;
 264        return 0;
 265}
 266EXPORT_SYMBOL(nubus_get_subdir);
 267
 268int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
 269{
 270        u32 resid;
 271
 272        if (nd->done)
 273                return -1;
 274
 275        /* Do this first, otherwise nubus_rewind & co are off by 4 */
 276        ent->base = nd->ptr;
 277
 278        /* This moves nd->ptr forward */
 279        resid = nubus_get_rom(&nd->ptr, 4, nd->mask);
 280
 281        /* EOL marker, as per the Apple docs */
 282        if ((resid & 0xff000000) == 0xff000000) {
 283                /* Mark it as done */
 284                nd->done = 1;
 285                return -1;
 286        }
 287
 288        /* First byte is the resource ID */
 289        ent->type = resid >> 24;
 290        /* Low 3 bytes might contain data (or might not) */
 291        ent->data = resid & 0xffffff;
 292        ent->mask = nd->mask;
 293        return 0;
 294}
 295EXPORT_SYMBOL(nubus_readdir);
 296
 297int nubus_rewinddir(struct nubus_dir *dir)
 298{
 299        dir->ptr = dir->base;
 300        dir->done = 0;
 301        return 0;
 302}
 303EXPORT_SYMBOL(nubus_rewinddir);
 304
 305/* Driver interface functions, more or less like in pci.c */
 306
 307struct nubus_rsrc *nubus_first_rsrc_or_null(void)
 308{
 309        return list_first_entry_or_null(&nubus_func_rsrcs, struct nubus_rsrc,
 310                                        list);
 311}
 312EXPORT_SYMBOL(nubus_first_rsrc_or_null);
 313
 314struct nubus_rsrc *nubus_next_rsrc_or_null(struct nubus_rsrc *from)
 315{
 316        if (list_is_last(&from->list, &nubus_func_rsrcs))
 317                return NULL;
 318        return list_next_entry(from, list);
 319}
 320EXPORT_SYMBOL(nubus_next_rsrc_or_null);
 321
 322int
 323nubus_find_rsrc(struct nubus_dir *dir, unsigned char rsrc_type,
 324                struct nubus_dirent *ent)
 325{
 326        while (nubus_readdir(dir, ent) != -1) {
 327                if (ent->type == rsrc_type)
 328                        return 0;
 329        }
 330        return -1;
 331}
 332EXPORT_SYMBOL(nubus_find_rsrc);
 333
 334/* Initialization functions - decide which slots contain stuff worth
 335   looking at, and print out lots and lots of information from the
 336   resource blocks. */
 337
 338static int __init nubus_get_block_rsrc_dir(struct nubus_board *board,
 339                                           struct proc_dir_entry *procdir,
 340                                           const struct nubus_dirent *parent)
 341{
 342        struct nubus_dir dir;
 343        struct nubus_dirent ent;
 344
 345        nubus_get_subdir(parent, &dir);
 346        dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
 347
 348        while (nubus_readdir(&dir, &ent) != -1) {
 349                u32 size;
 350
 351                nubus_get_rsrc_mem(&size, &ent, 4);
 352                pr_debug("        block (0x%x), size %d\n", ent.type, size);
 353                nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
 354        }
 355        return 0;
 356}
 357
 358static int __init nubus_get_display_vidmode(struct nubus_board *board,
 359                                            struct proc_dir_entry *procdir,
 360                                            const struct nubus_dirent *parent)
 361{
 362        struct nubus_dir dir;
 363        struct nubus_dirent ent;
 364
 365        nubus_get_subdir(parent, &dir);
 366        dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
 367
 368        while (nubus_readdir(&dir, &ent) != -1) {
 369                switch (ent.type) {
 370                case 1: /* mVidParams */
 371                case 2: /* mTable */
 372                {
 373                        u32 size;
 374
 375                        nubus_get_rsrc_mem(&size, &ent, 4);
 376                        pr_debug("        block (0x%x), size %d\n", ent.type,
 377                                size);
 378                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
 379                        break;
 380                }
 381                default:
 382                        pr_debug("        unknown resource 0x%02x, data 0x%06x\n",
 383                                ent.type, ent.data);
 384                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
 385                }
 386        }
 387        return 0;
 388}
 389
 390static int __init nubus_get_display_resource(struct nubus_rsrc *fres,
 391                                             struct proc_dir_entry *procdir,
 392                                             const struct nubus_dirent *ent)
 393{
 394        switch (ent->type) {
 395        case NUBUS_RESID_GAMMADIR:
 396                pr_debug("    gamma directory offset: 0x%06x\n", ent->data);
 397                nubus_get_block_rsrc_dir(fres->board, procdir, ent);
 398                break;
 399        case 0x0080 ... 0x0085:
 400                pr_debug("    mode 0x%02x info offset: 0x%06x\n",
 401                        ent->type, ent->data);
 402                nubus_get_display_vidmode(fres->board, procdir, ent);
 403                break;
 404        default:
 405                pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
 406                        ent->type, ent->data);
 407                nubus_proc_add_rsrc_mem(procdir, ent, 0);
 408        }
 409        return 0;
 410}
 411
 412static int __init nubus_get_network_resource(struct nubus_rsrc *fres,
 413                                             struct proc_dir_entry *procdir,
 414                                             const struct nubus_dirent *ent)
 415{
 416        switch (ent->type) {
 417        case NUBUS_RESID_MAC_ADDRESS:
 418        {
 419                char addr[6];
 420
 421                nubus_get_rsrc_mem(addr, ent, 6);
 422                pr_debug("    MAC address: %pM\n", addr);
 423                nubus_proc_add_rsrc_mem(procdir, ent, 6);
 424                break;
 425        }
 426        default:
 427                pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
 428                        ent->type, ent->data);
 429                nubus_proc_add_rsrc_mem(procdir, ent, 0);
 430        }
 431        return 0;
 432}
 433
 434static int __init nubus_get_cpu_resource(struct nubus_rsrc *fres,
 435                                         struct proc_dir_entry *procdir,
 436                                         const struct nubus_dirent *ent)
 437{
 438        switch (ent->type) {
 439        case NUBUS_RESID_MEMINFO:
 440        {
 441                unsigned long meminfo[2];
 442
 443                nubus_get_rsrc_mem(&meminfo, ent, 8);
 444                pr_debug("    memory: [ 0x%08lx 0x%08lx ]\n",
 445                        meminfo[0], meminfo[1]);
 446                nubus_proc_add_rsrc_mem(procdir, ent, 8);
 447                break;
 448        }
 449        case NUBUS_RESID_ROMINFO:
 450        {
 451                unsigned long rominfo[2];
 452
 453                nubus_get_rsrc_mem(&rominfo, ent, 8);
 454                pr_debug("    ROM:    [ 0x%08lx 0x%08lx ]\n",
 455                        rominfo[0], rominfo[1]);
 456                nubus_proc_add_rsrc_mem(procdir, ent, 8);
 457                break;
 458        }
 459        default:
 460                pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
 461                        ent->type, ent->data);
 462                nubus_proc_add_rsrc_mem(procdir, ent, 0);
 463        }
 464        return 0;
 465}
 466
 467static int __init nubus_get_private_resource(struct nubus_rsrc *fres,
 468                                             struct proc_dir_entry *procdir,
 469                                             const struct nubus_dirent *ent)
 470{
 471        switch (fres->category) {
 472        case NUBUS_CAT_DISPLAY:
 473                nubus_get_display_resource(fres, procdir, ent);
 474                break;
 475        case NUBUS_CAT_NETWORK:
 476                nubus_get_network_resource(fres, procdir, ent);
 477                break;
 478        case NUBUS_CAT_CPU:
 479                nubus_get_cpu_resource(fres, procdir, ent);
 480                break;
 481        default:
 482                pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
 483                        ent->type, ent->data);
 484                nubus_proc_add_rsrc_mem(procdir, ent, 0);
 485        }
 486        return 0;
 487}
 488
 489static struct nubus_rsrc * __init
 490nubus_get_functional_resource(struct nubus_board *board, int slot,
 491                              const struct nubus_dirent *parent)
 492{
 493        struct nubus_dir dir;
 494        struct nubus_dirent ent;
 495        struct nubus_rsrc *fres;
 496
 497        pr_debug("  Functional resource 0x%02x:\n", parent->type);
 498        nubus_get_subdir(parent, &dir);
 499        dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
 500
 501        /* Actually we should probably panic if this fails */
 502        fres = kzalloc(sizeof(*fres), GFP_ATOMIC);
 503        if (!fres)
 504                return NULL;
 505        fres->resid = parent->type;
 506        fres->directory = dir.base;
 507        fres->board = board;
 508
 509        while (nubus_readdir(&dir, &ent) != -1) {
 510                switch (ent.type) {
 511                case NUBUS_RESID_TYPE:
 512                {
 513                        unsigned short nbtdata[4];
 514
 515                        nubus_get_rsrc_mem(nbtdata, &ent, 8);
 516                        fres->category = nbtdata[0];
 517                        fres->type     = nbtdata[1];
 518                        fres->dr_sw    = nbtdata[2];
 519                        fres->dr_hw    = nbtdata[3];
 520                        pr_debug("    type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
 521                                nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
 522                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
 523                        break;
 524                }
 525                case NUBUS_RESID_NAME:
 526                {
 527                        char name[64];
 528                        unsigned int len;
 529
 530                        len = nubus_get_rsrc_str(name, &ent, sizeof(name));
 531                        pr_debug("    name: %s\n", name);
 532                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
 533                        break;
 534                }
 535                case NUBUS_RESID_DRVRDIR:
 536                {
 537                        /* MacOS driver.  If we were NetBSD we might
 538                           use this :-) */
 539                        pr_debug("    driver directory offset: 0x%06x\n",
 540                                ent.data);
 541                        nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
 542                        break;
 543                }
 544                case NUBUS_RESID_MINOR_BASEOS:
 545                {
 546                        /* We will need this in order to support
 547                           multiple framebuffers.  It might be handy
 548                           for Ethernet as well */
 549                        u32 base_offset;
 550
 551                        nubus_get_rsrc_mem(&base_offset, &ent, 4);
 552                        pr_debug("    memory offset: 0x%08x\n", base_offset);
 553                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
 554                        break;
 555                }
 556                case NUBUS_RESID_MINOR_LENGTH:
 557                {
 558                        /* Ditto */
 559                        u32 length;
 560
 561                        nubus_get_rsrc_mem(&length, &ent, 4);
 562                        pr_debug("    memory length: 0x%08x\n", length);
 563                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
 564                        break;
 565                }
 566                case NUBUS_RESID_FLAGS:
 567                        pr_debug("    flags: 0x%06x\n", ent.data);
 568                        nubus_proc_add_rsrc(dir.procdir, &ent);
 569                        break;
 570                case NUBUS_RESID_HWDEVID:
 571                        pr_debug("    hwdevid: 0x%06x\n", ent.data);
 572                        nubus_proc_add_rsrc(dir.procdir, &ent);
 573                        break;
 574                default:
 575                        /* Local/Private resources have their own
 576                           function */
 577                        nubus_get_private_resource(fres, dir.procdir, &ent);
 578                }
 579        }
 580
 581        return fres;
 582}
 583
 584/* This is *really* cool. */
 585static int __init nubus_get_icon(struct nubus_board *board,
 586                                 struct proc_dir_entry *procdir,
 587                                 const struct nubus_dirent *ent)
 588{
 589        /* Should be 32x32 if my memory serves me correctly */
 590        u32 icon[32];
 591        int i;
 592
 593        nubus_get_rsrc_mem(&icon, ent, 128);
 594        pr_debug("    icon:\n");
 595        for (i = 0; i < 8; i++)
 596                pr_debug("        %08x %08x %08x %08x\n",
 597                        icon[i * 4 + 0], icon[i * 4 + 1],
 598                        icon[i * 4 + 2], icon[i * 4 + 3]);
 599        nubus_proc_add_rsrc_mem(procdir, ent, 128);
 600
 601        return 0;
 602}
 603
 604static int __init nubus_get_vendorinfo(struct nubus_board *board,
 605                                       struct proc_dir_entry *procdir,
 606                                       const struct nubus_dirent *parent)
 607{
 608        struct nubus_dir dir;
 609        struct nubus_dirent ent;
 610        static char *vendor_fields[6] = { "ID", "serial", "revision",
 611                                          "part", "date", "unknown field" };
 612
 613        pr_debug("    vendor info:\n");
 614        nubus_get_subdir(parent, &dir);
 615        dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
 616
 617        while (nubus_readdir(&dir, &ent) != -1) {
 618                char name[64];
 619                unsigned int len;
 620
 621                /* These are all strings, we think */
 622                len = nubus_get_rsrc_str(name, &ent, sizeof(name));
 623                if (ent.type < 1 || ent.type > 5)
 624                        ent.type = 5;
 625                pr_debug("    %s: %s\n", vendor_fields[ent.type - 1], name);
 626                nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
 627        }
 628        return 0;
 629}
 630
 631static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
 632                                           const struct nubus_dirent *parent)
 633{
 634        struct nubus_dir dir;
 635        struct nubus_dirent ent;
 636
 637        pr_debug("  Board resource 0x%02x:\n", parent->type);
 638        nubus_get_subdir(parent, &dir);
 639        dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
 640
 641        while (nubus_readdir(&dir, &ent) != -1) {
 642                switch (ent.type) {
 643                case NUBUS_RESID_TYPE:
 644                {
 645                        unsigned short nbtdata[4];
 646                        /* This type is always the same, and is not
 647                           useful except insofar as it tells us that
 648                           we really are looking at a board resource. */
 649                        nubus_get_rsrc_mem(nbtdata, &ent, 8);
 650                        pr_debug("    type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
 651                                nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
 652                        if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
 653                            nbtdata[2] != 0 || nbtdata[3] != 0)
 654                                pr_err("Slot %X: sResource is not a board resource!\n",
 655                                       slot);
 656                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
 657                        break;
 658                }
 659                case NUBUS_RESID_NAME:
 660                {
 661                        unsigned int len;
 662
 663                        len = nubus_get_rsrc_str(board->name, &ent,
 664                                                 sizeof(board->name));
 665                        pr_debug("    name: %s\n", board->name);
 666                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
 667                        break;
 668                }
 669                case NUBUS_RESID_ICON:
 670                        nubus_get_icon(board, dir.procdir, &ent);
 671                        break;
 672                case NUBUS_RESID_BOARDID:
 673                        pr_debug("    board id: 0x%x\n", ent.data);
 674                        nubus_proc_add_rsrc(dir.procdir, &ent);
 675                        break;
 676                case NUBUS_RESID_PRIMARYINIT:
 677                        pr_debug("    primary init offset: 0x%06x\n", ent.data);
 678                        nubus_proc_add_rsrc(dir.procdir, &ent);
 679                        break;
 680                case NUBUS_RESID_VENDORINFO:
 681                        nubus_get_vendorinfo(board, dir.procdir, &ent);
 682                        break;
 683                case NUBUS_RESID_FLAGS:
 684                        pr_debug("    flags: 0x%06x\n", ent.data);
 685                        nubus_proc_add_rsrc(dir.procdir, &ent);
 686                        break;
 687                case NUBUS_RESID_HWDEVID:
 688                        pr_debug("    hwdevid: 0x%06x\n", ent.data);
 689                        nubus_proc_add_rsrc(dir.procdir, &ent);
 690                        break;
 691                case NUBUS_RESID_SECONDINIT:
 692                        pr_debug("    secondary init offset: 0x%06x\n",
 693                                 ent.data);
 694                        nubus_proc_add_rsrc(dir.procdir, &ent);
 695                        break;
 696                        /* WTF isn't this in the functional resources? */
 697                case NUBUS_RESID_VIDNAMES:
 698                        pr_debug("    vidnames directory offset: 0x%06x\n",
 699                                ent.data);
 700                        nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
 701                        break;
 702                        /* Same goes for this */
 703                case NUBUS_RESID_VIDMODES:
 704                        pr_debug("    video mode parameter directory offset: 0x%06x\n",
 705                                ent.data);
 706                        nubus_proc_add_rsrc(dir.procdir, &ent);
 707                        break;
 708                default:
 709                        pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
 710                                ent.type, ent.data);
 711                        nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
 712                }
 713        }
 714        return 0;
 715}
 716
 717static void __init nubus_add_board(int slot, int bytelanes)
 718{
 719        struct nubus_board *board;
 720        unsigned char *rp;
 721        unsigned long dpat;
 722        struct nubus_dir dir;
 723        struct nubus_dirent ent;
 724        int prev_resid = -1;
 725
 726        /* Move to the start of the format block */
 727        rp = nubus_rom_addr(slot);
 728        nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
 729
 730        /* Actually we should probably panic if this fails */
 731        if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
 732                return;
 733        board->fblock = rp;
 734
 735        /* Dump the format block for debugging purposes */
 736        pr_debug("Slot %X, format block at 0x%p:\n", slot, rp);
 737        pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
 738        pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
 739        pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
 740        pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
 741        pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
 742        pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
 743        pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
 744        pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
 745        rp = board->fblock;
 746
 747        board->slot = slot;
 748        board->slot_addr = (unsigned long)nubus_slot_addr(slot);
 749        board->doffset = nubus_get_rom(&rp, 4, bytelanes);
 750        /* rom_length is *supposed* to be the total length of the
 751         * ROM.  In practice it is the "amount of ROM used to compute
 752         * the CRC."  So some jokers decide to set it to zero and
 753         * set the crc to zero so they don't have to do any math.
 754         * See the Performa 460 ROM, for example.  Those Apple "engineers".
 755         */
 756        board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
 757        board->crc = nubus_get_rom(&rp, 4, bytelanes);
 758        board->rev = nubus_get_rom(&rp, 1, bytelanes);
 759        board->format = nubus_get_rom(&rp, 1, bytelanes);
 760        board->lanes = bytelanes;
 761
 762        /* Directory offset should be small and negative... */
 763        if (!(board->doffset & 0x00FF0000))
 764                pr_warn("Slot %X: Dodgy doffset!\n", slot);
 765        dpat = nubus_get_rom(&rp, 4, bytelanes);
 766        if (dpat != NUBUS_TEST_PATTERN)
 767                pr_warn("Slot %X: Wrong test pattern %08lx!\n", slot, dpat);
 768
 769        /*
 770         *      I wonder how the CRC is meant to work -
 771         *              any takers ?
 772         * CSA: According to MAC docs, not all cards pass the CRC anyway,
 773         * since the initial Macintosh ROM releases skipped the check.
 774         */
 775
 776        /* Set up the directory pointer */
 777        board->directory = board->fblock;
 778        nubus_move(&board->directory, nubus_expand32(board->doffset),
 779                   board->lanes);
 780
 781        nubus_get_root_dir(board, &dir);
 782
 783        /* We're ready to rock */
 784        pr_debug("Slot %X resources:\n", slot);
 785
 786        /* Each slot should have one board resource and any number of
 787         * functional resources.  So we'll fill in some fields in the
 788         * struct nubus_board from the board resource, then walk down
 789         * the list of functional resources, spinning out a nubus_rsrc
 790         * for each of them.
 791         */
 792        if (nubus_readdir(&dir, &ent) == -1) {
 793                /* We can't have this! */
 794                pr_err("Slot %X: Board resource not found!\n", slot);
 795                kfree(board);
 796                return;
 797        }
 798
 799        if (ent.type < 1 || ent.type > 127)
 800                pr_warn("Slot %X: Board resource ID is invalid!\n", slot);
 801
 802        board->procdir = nubus_proc_add_board(board);
 803
 804        nubus_get_board_resource(board, slot, &ent);
 805
 806        while (nubus_readdir(&dir, &ent) != -1) {
 807                struct nubus_rsrc *fres;
 808
 809                fres = nubus_get_functional_resource(board, slot, &ent);
 810                if (fres == NULL)
 811                        continue;
 812
 813                /* Resources should appear in ascending ID order. This sanity
 814                 * check prevents duplicate resource IDs.
 815                 */
 816                if (fres->resid <= prev_resid) {
 817                        kfree(fres);
 818                        continue;
 819                }
 820                prev_resid = fres->resid;
 821
 822                list_add_tail(&fres->list, &nubus_func_rsrcs);
 823        }
 824
 825        if (nubus_device_register(board))
 826                put_device(&board->dev);
 827}
 828
 829static void __init nubus_probe_slot(int slot)
 830{
 831        unsigned char dp;
 832        unsigned char *rp;
 833        int i;
 834
 835        rp = nubus_rom_addr(slot);
 836        for (i = 4; i; i--) {
 837                rp--;
 838                if (!hwreg_present(rp))
 839                        continue;
 840
 841                dp = *rp;
 842
 843                /* The last byte of the format block consists of two
 844                   nybbles which are "mirror images" of each other.
 845                   These show us the valid bytelanes */
 846                if ((((dp >> 4) ^ dp) & 0x0F) != 0x0F)
 847                        continue;
 848                /* Check that this value is actually *on* one of the
 849                   bytelanes it claims are valid! */
 850                if (not_useful(rp, dp))
 851                        continue;
 852
 853                /* Looks promising.  Let's put it on the list. */
 854                nubus_add_board(slot, dp);
 855
 856                return;
 857        }
 858}
 859
 860static void __init nubus_scan_bus(void)
 861{
 862        int slot;
 863
 864        pr_info("NuBus: Scanning NuBus slots.\n");
 865        for (slot = 9; slot < 15; slot++) {
 866                nubus_probe_slot(slot);
 867        }
 868}
 869
 870static int __init nubus_init(void)
 871{
 872        int err;
 873
 874        if (!MACH_IS_MAC)
 875                return 0;
 876
 877        nubus_proc_init();
 878        err = nubus_bus_register();
 879        if (err)
 880                return err;
 881        nubus_scan_bus();
 882        return 0;
 883}
 884
 885subsys_initcall(nubus_init);
 886