]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/nubus/nubus.c
UBUNTU: Ubuntu-4.15.0-96.97
[mirror_ubuntu-bionic-kernel.git] / drivers / nubus / nubus.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
1da177e4
LT
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
1da177e4
LT
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>
99ffab81 17#include <linux/module.h>
5a0e3ad6 18#include <linux/slab.h>
1da177e4 19#include <asm/setup.h>
1da177e4
LT
20#include <asm/page.h>
21#include <asm/hwtest.h>
1da177e4
LT
22
23/* Constants */
24
25/* This is, of course, the size in bytelanes, rather than the size in
26 actual bytes */
27#define FORMAT_BLOCK_SIZE 20
28#define ROM_DIR_OFFSET 0x24
29
30#define NUBUS_TEST_PATTERN 0x5A932BC7
31
1da177e4
LT
32/* Globals */
33
f42e5550
FT
34struct nubus_dev *nubus_devices;
35struct nubus_board *nubus_boards;
1da177e4
LT
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. */
f42e5550 59
1da177e4
LT
60static inline int not_useful(void *p, int map)
61{
f42e5550
FT
62 unsigned long pv = (unsigned long)p;
63
1da177e4 64 pv &= 3;
f42e5550 65 if (map & (1 << pv))
1da177e4
LT
66 return 0;
67 return 1;
68}
f42e5550 69
1da177e4
LT
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
f42e5550 76 while (len) {
1da177e4 77 v <<= 8;
f42e5550 78 while (not_useful(p, map))
1da177e4
LT
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{
f42e5550 89 unsigned char *p = *ptr;
1da177e4 90
f42e5550
FT
91 while (len) {
92 do {
1da177e4 93 p--;
f42e5550 94 } while (not_useful(p, map));
1da177e4
LT
95 len--;
96 }
f42e5550 97 *ptr = p;
1da177e4
LT
98}
99
100static void nubus_advance(unsigned char **ptr, int len, int map)
101{
102 unsigned char *p = *ptr;
f42e5550 103
f42e5550
FT
104 while (len) {
105 while (not_useful(p, map))
1da177e4 106 p++;
2e0eb731 107 p++;
1da177e4
LT
108 len--;
109 }
110 *ptr = p;
111}
112
113static void nubus_move(unsigned char **ptr, int len, int map)
114{
85cc313a
FT
115 unsigned long slot_space = (unsigned long)*ptr & 0xFF000000;
116
f42e5550 117 if (len > 0)
1da177e4 118 nubus_advance(ptr, len, map);
f42e5550 119 else if (len < 0)
1da177e4 120 nubus_rewind(ptr, -len, map);
85cc313a
FT
121
122 if (((unsigned long)*ptr & 0xFF000000) != slot_space)
123 pr_err("%s: moved out of slot address space!\n", __func__);
1da177e4
LT
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{
f42e5550 135 if (foo & 0x00800000) /* 24bit negative */
1da177e4
LT
136 foo |= 0xFF000000;
137 return foo;
138}
139
140static inline void *nubus_rom_addr(int slot)
f42e5550 141{
1da177e4
LT
142 /*
143 * Returns the first byte after the card. We then walk
144 * backwards to get the lane register and the config
145 */
f42e5550 146 return (void *)(0xF1000000 + (slot << 24));
1da177e4
LT
147}
148
149static unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
150{
151 unsigned char *p = nd->base;
f42e5550 152
1da177e4
LT
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
f42e5550 163void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
1da177e4
LT
164 int len)
165{
166 unsigned char *t = (unsigned char *)dest;
167 unsigned char *p = nubus_dirptr(dirent);
f42e5550
FT
168
169 while (len) {
1da177e4
LT
170 *t++ = nubus_get_rom(&p, 1, dirent->mask);
171 len--;
172 }
173}
99ffab81 174EXPORT_SYMBOL(nubus_get_rsrc_mem);
1da177e4 175
f42e5550 176void nubus_get_rsrc_str(void *dest, const struct nubus_dirent *dirent,
1da177e4
LT
177 int len)
178{
f42e5550 179 unsigned char *t = (unsigned char *)dest;
1da177e4 180 unsigned char *p = nubus_dirptr(dirent);
f42e5550
FT
181
182 while (len) {
1da177e4 183 *t = nubus_get_rom(&p, 1, dirent->mask);
f42e5550 184 if (!*t++)
1da177e4
LT
185 break;
186 len--;
187 }
188}
99ffab81 189EXPORT_SYMBOL(nubus_get_rsrc_str);
1da177e4 190
f42e5550
FT
191int nubus_get_root_dir(const struct nubus_board *board,
192 struct nubus_dir *dir)
1da177e4
LT
193{
194 dir->ptr = dir->base = board->directory;
195 dir->done = 0;
196 dir->mask = board->lanes;
197 return 0;
198}
99ffab81 199EXPORT_SYMBOL(nubus_get_root_dir);
1da177e4
LT
200
201/* This is a slyly renamed version of the above */
f42e5550
FT
202int nubus_get_func_dir(const struct nubus_dev *dev,
203 struct nubus_dir *dir)
1da177e4
LT
204{
205 dir->ptr = dir->base = dev->directory;
206 dir->done = 0;
207 dir->mask = dev->board->lanes;
208 return 0;
209}
99ffab81 210EXPORT_SYMBOL(nubus_get_func_dir);
1da177e4 211
f42e5550
FT
212int nubus_get_board_dir(const struct nubus_board *board,
213 struct nubus_dir *dir)
1da177e4
LT
214{
215 struct nubus_dirent ent;
f42e5550 216
1da177e4
LT
217 dir->ptr = dir->base = board->directory;
218 dir->done = 0;
219 dir->mask = board->lanes;
220
221 /* Now dereference it (the first directory is always the board
222 directory) */
223 if (nubus_readdir(dir, &ent) == -1)
224 return -1;
225 if (nubus_get_subdir(&ent, dir) == -1)
226 return -1;
227 return 0;
228}
99ffab81 229EXPORT_SYMBOL(nubus_get_board_dir);
1da177e4
LT
230
231int nubus_get_subdir(const struct nubus_dirent *ent,
232 struct nubus_dir *dir)
233{
234 dir->ptr = dir->base = nubus_dirptr(ent);
235 dir->done = 0;
236 dir->mask = ent->mask;
237 return 0;
238}
99ffab81 239EXPORT_SYMBOL(nubus_get_subdir);
1da177e4
LT
240
241int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
242{
243 u32 resid;
f42e5550 244
1da177e4
LT
245 if (nd->done)
246 return -1;
247
248 /* Do this first, otherwise nubus_rewind & co are off by 4 */
249 ent->base = nd->ptr;
250
251 /* This moves nd->ptr forward */
252 resid = nubus_get_rom(&nd->ptr, 4, nd->mask);
253
254 /* EOL marker, as per the Apple docs */
f42e5550 255 if ((resid & 0xff000000) == 0xff000000) {
1da177e4
LT
256 /* Mark it as done */
257 nd->done = 1;
258 return -1;
259 }
260
261 /* First byte is the resource ID */
f42e5550 262 ent->type = resid >> 24;
1da177e4
LT
263 /* Low 3 bytes might contain data (or might not) */
264 ent->data = resid & 0xffffff;
f42e5550 265 ent->mask = nd->mask;
1da177e4
LT
266 return 0;
267}
99ffab81 268EXPORT_SYMBOL(nubus_readdir);
1da177e4 269
f42e5550 270int nubus_rewinddir(struct nubus_dir *dir)
1da177e4
LT
271{
272 dir->ptr = dir->base;
e36b9913 273 dir->done = 0;
1da177e4
LT
274 return 0;
275}
99ffab81 276EXPORT_SYMBOL(nubus_rewinddir);
1da177e4
LT
277
278/* Driver interface functions, more or less like in pci.c */
279
280struct nubus_dev*
f42e5550
FT
281nubus_find_device(unsigned short category, unsigned short type,
282 unsigned short dr_hw, unsigned short dr_sw,
283 const struct nubus_dev *from)
1da177e4 284{
f42e5550 285 struct nubus_dev *itor = from ? from->next : nubus_devices;
1da177e4
LT
286
287 while (itor) {
f42e5550
FT
288 if (itor->category == category && itor->type == type &&
289 itor->dr_hw == dr_hw && itor->dr_sw == dr_sw)
1da177e4
LT
290 return itor;
291 itor = itor->next;
292 }
293 return NULL;
294}
99ffab81 295EXPORT_SYMBOL(nubus_find_device);
1da177e4
LT
296
297struct nubus_dev*
f42e5550
FT
298nubus_find_type(unsigned short category, unsigned short type,
299 const struct nubus_dev *from)
1da177e4 300{
f42e5550 301 struct nubus_dev *itor = from ? from->next : nubus_devices;
1da177e4
LT
302
303 while (itor) {
f42e5550 304 if (itor->category == category && itor->type == type)
1da177e4
LT
305 return itor;
306 itor = itor->next;
307 }
308 return NULL;
309}
99ffab81 310EXPORT_SYMBOL(nubus_find_type);
1da177e4
LT
311
312struct nubus_dev*
f42e5550 313nubus_find_slot(unsigned int slot, const struct nubus_dev *from)
1da177e4 314{
f42e5550
FT
315 struct nubus_dev *itor = from ? from->next : nubus_devices;
316
1da177e4
LT
317 while (itor) {
318 if (itor->board->slot == slot)
319 return itor;
320 itor = itor->next;
321 }
322 return NULL;
323}
99ffab81 324EXPORT_SYMBOL(nubus_find_slot);
1da177e4
LT
325
326int
f42e5550
FT
327nubus_find_rsrc(struct nubus_dir *dir, unsigned char rsrc_type,
328 struct nubus_dirent *ent)
1da177e4
LT
329{
330 while (nubus_readdir(dir, ent) != -1) {
331 if (ent->type == rsrc_type)
332 return 0;
f42e5550 333 }
1da177e4
LT
334 return -1;
335}
99ffab81 336EXPORT_SYMBOL(nubus_find_rsrc);
1da177e4
LT
337
338/* Initialization functions - decide which slots contain stuff worth
339 looking at, and print out lots and lots of information from the
340 resource blocks. */
341
342/* FIXME: A lot of this stuff will eventually be useful after
081985ac 343 initialization, for intelligently probing Ethernet and video chips,
1da177e4
LT
344 among other things. The rest of it should go in the /proc code.
345 For now, we just use it to give verbose boot logs. */
346
f42e5550
FT
347static int __init nubus_show_display_resource(struct nubus_dev *dev,
348 const struct nubus_dirent *ent)
1da177e4
LT
349{
350 switch (ent->type) {
351 case NUBUS_RESID_GAMMADIR:
71ae40e4 352 pr_info(" gamma directory offset: 0x%06x\n", ent->data);
1da177e4
LT
353 break;
354 case 0x0080 ... 0x0085:
71ae40e4 355 pr_info(" mode %02X info offset: 0x%06x\n",
1da177e4
LT
356 ent->type, ent->data);
357 break;
358 default:
71ae40e4 359 pr_info(" unknown resource %02X, data 0x%06x\n",
1da177e4
LT
360 ent->type, ent->data);
361 }
362 return 0;
363}
364
f42e5550
FT
365static int __init nubus_show_network_resource(struct nubus_dev *dev,
366 const struct nubus_dirent *ent)
1da177e4
LT
367{
368 switch (ent->type) {
369 case NUBUS_RESID_MAC_ADDRESS:
370 {
371 char addr[6];
f42e5550 372
1da177e4 373 nubus_get_rsrc_mem(addr, ent, 6);
71ae40e4 374 pr_info(" MAC address: %pM\n", addr);
1da177e4
LT
375 break;
376 }
377 default:
71ae40e4 378 pr_info(" unknown resource %02X, data 0x%06x\n",
1da177e4
LT
379 ent->type, ent->data);
380 }
381 return 0;
382}
383
f42e5550
FT
384static int __init nubus_show_cpu_resource(struct nubus_dev *dev,
385 const struct nubus_dirent *ent)
1da177e4
LT
386{
387 switch (ent->type) {
388 case NUBUS_RESID_MEMINFO:
389 {
390 unsigned long meminfo[2];
f42e5550 391
1da177e4 392 nubus_get_rsrc_mem(&meminfo, ent, 8);
71ae40e4 393 pr_info(" memory: [ 0x%08lx 0x%08lx ]\n",
1da177e4
LT
394 meminfo[0], meminfo[1]);
395 break;
396 }
397 case NUBUS_RESID_ROMINFO:
398 {
399 unsigned long rominfo[2];
f42e5550 400
1da177e4 401 nubus_get_rsrc_mem(&rominfo, ent, 8);
71ae40e4 402 pr_info(" ROM: [ 0x%08lx 0x%08lx ]\n",
1da177e4
LT
403 rominfo[0], rominfo[1]);
404 break;
405 }
406 default:
71ae40e4 407 pr_info(" unknown resource %02X, data 0x%06x\n",
1da177e4
LT
408 ent->type, ent->data);
409 }
410 return 0;
411}
412
f42e5550
FT
413static int __init nubus_show_private_resource(struct nubus_dev *dev,
414 const struct nubus_dirent *ent)
1da177e4
LT
415{
416 switch (dev->category) {
417 case NUBUS_CAT_DISPLAY:
418 nubus_show_display_resource(dev, ent);
419 break;
420 case NUBUS_CAT_NETWORK:
421 nubus_show_network_resource(dev, ent);
422 break;
423 case NUBUS_CAT_CPU:
424 nubus_show_cpu_resource(dev, ent);
425 break;
426 default:
71ae40e4 427 pr_info(" unknown resource %02X, data 0x%06x\n",
1da177e4
LT
428 ent->type, ent->data);
429 }
430 return 0;
431}
432
f42e5550
FT
433static struct nubus_dev * __init
434nubus_get_functional_resource(struct nubus_board *board, int slot,
435 const struct nubus_dirent *parent)
1da177e4 436{
f42e5550 437 struct nubus_dir dir;
1da177e4 438 struct nubus_dirent ent;
f42e5550
FT
439 struct nubus_dev *dev;
440
71ae40e4 441 pr_info(" Function 0x%02x:\n", parent->type);
1da177e4
LT
442 nubus_get_subdir(parent, &dir);
443
71ae40e4
DHD
444 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
445 __func__, parent->base, dir.base);
1da177e4
LT
446
447 /* Actually we should probably panic if this fails */
dd00cc48 448 if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
f42e5550 449 return NULL;
1da177e4
LT
450 dev->resid = parent->type;
451 dev->directory = dir.base;
452 dev->board = board;
f42e5550
FT
453
454 while (nubus_readdir(&dir, &ent) != -1) {
455 switch (ent.type) {
1da177e4
LT
456 case NUBUS_RESID_TYPE:
457 {
458 unsigned short nbtdata[4];
f42e5550 459
1da177e4
LT
460 nubus_get_rsrc_mem(nbtdata, &ent, 8);
461 dev->category = nbtdata[0];
462 dev->type = nbtdata[1];
463 dev->dr_sw = nbtdata[2];
464 dev->dr_hw = nbtdata[3];
71ae40e4
DHD
465 pr_info(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
466 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
1da177e4
LT
467 break;
468 }
469 case NUBUS_RESID_NAME:
470 {
471 nubus_get_rsrc_str(dev->name, &ent, 64);
71ae40e4 472 pr_info(" name: %s\n", dev->name);
1da177e4
LT
473 break;
474 }
475 case NUBUS_RESID_DRVRDIR:
476 {
477 /* MacOS driver. If we were NetBSD we might
478 use this :-) */
479 struct nubus_dir drvr_dir;
480 struct nubus_dirent drvr_ent;
f42e5550 481
1da177e4
LT
482 nubus_get_subdir(&ent, &drvr_dir);
483 nubus_readdir(&drvr_dir, &drvr_ent);
484 dev->driver = nubus_dirptr(&drvr_ent);
71ae40e4 485 pr_info(" driver at: 0x%p\n", dev->driver);
1da177e4
LT
486 break;
487 }
488 case NUBUS_RESID_MINOR_BASEOS:
489 /* We will need this in order to support
490 multiple framebuffers. It might be handy
491 for Ethernet as well */
492 nubus_get_rsrc_mem(&dev->iobase, &ent, 4);
71ae40e4 493 pr_info(" memory offset: 0x%08lx\n", dev->iobase);
1da177e4
LT
494 break;
495 case NUBUS_RESID_MINOR_LENGTH:
496 /* Ditto */
497 nubus_get_rsrc_mem(&dev->iosize, &ent, 4);
71ae40e4 498 pr_info(" memory length: 0x%08lx\n", dev->iosize);
f42e5550 499 break;
1da177e4
LT
500 case NUBUS_RESID_FLAGS:
501 dev->flags = ent.data;
71ae40e4 502 pr_info(" flags: 0x%06x\n", dev->flags);
1da177e4
LT
503 break;
504 case NUBUS_RESID_HWDEVID:
505 dev->hwdevid = ent.data;
71ae40e4 506 pr_info(" hwdevid: 0x%06x\n", dev->hwdevid);
1da177e4
LT
507 break;
508 default:
509 /* Local/Private resources have their own
510 function */
511 nubus_show_private_resource(dev, &ent);
512 }
513 }
f42e5550 514
1da177e4
LT
515 return dev;
516}
517
518/* This is cool. */
f42e5550
FT
519static int __init nubus_get_vidnames(struct nubus_board *board,
520 const struct nubus_dirent *parent)
1da177e4 521{
f42e5550 522 struct nubus_dir dir;
1da177e4 523 struct nubus_dirent ent;
f42e5550 524
1da177e4
LT
525 /* FIXME: obviously we want to put this in a header file soon */
526 struct vidmode {
527 u32 size;
528 /* Don't know what this is yet */
529 u16 id;
530 /* Longest one I've seen so far is 26 characters */
531 char name[32];
532 };
533
71ae40e4 534 pr_info(" video modes supported:\n");
1da177e4 535 nubus_get_subdir(parent, &dir);
71ae40e4
DHD
536 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
537 __func__, parent->base, dir.base);
1da177e4 538
f42e5550 539 while (nubus_readdir(&dir, &ent) != -1) {
1da177e4
LT
540 struct vidmode mode;
541 u32 size;
542
543 /* First get the length */
544 nubus_get_rsrc_mem(&size, &ent, 4);
f42e5550 545
1da177e4
LT
546 /* Now clobber the whole thing */
547 if (size > sizeof(mode) - 1)
548 size = sizeof(mode) - 1;
549 memset(&mode, 0, sizeof(mode));
550 nubus_get_rsrc_mem(&mode, &ent, size);
71ae40e4 551 pr_info(" %02X: (%02X) %s\n", ent.type,
1da177e4
LT
552 mode.id, mode.name);
553 }
554 return 0;
555}
556
557/* This is *really* cool. */
f42e5550
FT
558static int __init nubus_get_icon(struct nubus_board *board,
559 const struct nubus_dirent *ent)
1da177e4
LT
560{
561 /* Should be 32x32 if my memory serves me correctly */
562 unsigned char icon[128];
563 int x, y;
f42e5550 564
1da177e4 565 nubus_get_rsrc_mem(&icon, ent, 128);
71ae40e4 566 pr_info(" icon:\n");
1da177e4
LT
567
568 /* We should actually plot these somewhere in the framebuffer
569 init. This is just to demonstrate that they do, in fact,
570 exist */
571 for (y = 0; y < 32; y++) {
71ae40e4 572 pr_info(" ");
1da177e4 573 for (x = 0; x < 32; x++) {
f42e5550 574 if (icon[y * 4 + x / 8] & (0x80 >> (x % 8)))
71ae40e4 575 pr_cont("*");
1da177e4 576 else
71ae40e4 577 pr_cont(" ");
1da177e4 578 }
71ae40e4 579 pr_cont("\n");
1da177e4
LT
580 }
581 return 0;
582}
583
f42e5550
FT
584static int __init nubus_get_vendorinfo(struct nubus_board *board,
585 const struct nubus_dirent *parent)
1da177e4 586{
f42e5550 587 struct nubus_dir dir;
1da177e4 588 struct nubus_dirent ent;
f42e5550
FT
589 static char *vendor_fields[6] = { "ID", "serial", "revision",
590 "part", "date", "unknown field" };
1da177e4 591
71ae40e4 592 pr_info(" vendor info:\n");
1da177e4 593 nubus_get_subdir(parent, &dir);
71ae40e4
DHD
594 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
595 __func__, parent->base, dir.base);
1da177e4 596
f42e5550 597 while (nubus_readdir(&dir, &ent) != -1) {
1da177e4 598 char name[64];
f42e5550 599
1da177e4
LT
600 /* These are all strings, we think */
601 nubus_get_rsrc_str(name, &ent, 64);
602 if (ent.type > 5)
603 ent.type = 5;
71ae40e4 604 pr_info(" %s: %s\n", vendor_fields[ent.type - 1], name);
1da177e4
LT
605 }
606 return 0;
607}
608
f42e5550
FT
609static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
610 const struct nubus_dirent *parent)
1da177e4 611{
f42e5550 612 struct nubus_dir dir;
1da177e4 613 struct nubus_dirent ent;
f42e5550 614
1da177e4 615 nubus_get_subdir(parent, &dir);
71ae40e4
DHD
616 pr_debug("%s: parent is 0x%p, dir is 0x%p\n",
617 __func__, parent->base, dir.base);
1da177e4 618
f42e5550 619 while (nubus_readdir(&dir, &ent) != -1) {
1da177e4
LT
620 switch (ent.type) {
621 case NUBUS_RESID_TYPE:
622 {
623 unsigned short nbtdata[4];
624 /* This type is always the same, and is not
625 useful except insofar as it tells us that
626 we really are looking at a board resource. */
627 nubus_get_rsrc_mem(nbtdata, &ent, 8);
71ae40e4
DHD
628 pr_info(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
629 nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
1da177e4
LT
630 if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
631 nbtdata[2] != 0 || nbtdata[3] != 0)
71ae40e4 632 pr_err("this sResource is not a board resource!\n");
1da177e4
LT
633 break;
634 }
635 case NUBUS_RESID_NAME:
636 nubus_get_rsrc_str(board->name, &ent, 64);
71ae40e4 637 pr_info(" name: %s\n", board->name);
1da177e4
LT
638 break;
639 case NUBUS_RESID_ICON:
640 nubus_get_icon(board, &ent);
641 break;
642 case NUBUS_RESID_BOARDID:
71ae40e4 643 pr_info(" board id: 0x%x\n", ent.data);
1da177e4
LT
644 break;
645 case NUBUS_RESID_PRIMARYINIT:
71ae40e4 646 pr_info(" primary init offset: 0x%06x\n", ent.data);
1da177e4
LT
647 break;
648 case NUBUS_RESID_VENDORINFO:
649 nubus_get_vendorinfo(board, &ent);
650 break;
651 case NUBUS_RESID_FLAGS:
71ae40e4 652 pr_info(" flags: 0x%06x\n", ent.data);
1da177e4
LT
653 break;
654 case NUBUS_RESID_HWDEVID:
71ae40e4 655 pr_info(" hwdevid: 0x%06x\n", ent.data);
1da177e4
LT
656 break;
657 case NUBUS_RESID_SECONDINIT:
71ae40e4 658 pr_info(" secondary init offset: 0x%06x\n", ent.data);
1da177e4 659 break;
f42e5550 660 /* WTF isn't this in the functional resources? */
1da177e4
LT
661 case NUBUS_RESID_VIDNAMES:
662 nubus_get_vidnames(board, &ent);
663 break;
664 /* Same goes for this */
665 case NUBUS_RESID_VIDMODES:
71ae40e4 666 pr_info(" video mode parameter directory offset: 0x%06x\n",
1da177e4 667 ent.data);
f42e5550 668 break;
1da177e4 669 default:
71ae40e4 670 pr_info(" unknown resource %02X, data 0x%06x\n",
1da177e4
LT
671 ent.type, ent.data);
672 }
673 }
674 return 0;
675}
676
1da177e4 677/* Add a board (might be many devices) to the list */
f42e5550 678static struct nubus_board * __init nubus_add_board(int slot, int bytelanes)
1da177e4 679{
f42e5550
FT
680 struct nubus_board *board;
681 struct nubus_board **boardp;
1da177e4
LT
682 unsigned char *rp;
683 unsigned long dpat;
684 struct nubus_dir dir;
685 struct nubus_dirent ent;
686
687 /* Move to the start of the format block */
f42e5550 688 rp = nubus_rom_addr(slot);
1da177e4
LT
689 nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
690
691 /* Actually we should probably panic if this fails */
dd00cc48 692 if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
f42e5550 693 return NULL;
1da177e4
LT
694 board->fblock = rp;
695
696 /* Dump the format block for debugging purposes */
71ae40e4
DHD
697 pr_debug("Slot %X, format block at 0x%p:\n", slot, rp);
698 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
699 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
700 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
701 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
702 pr_debug("%02lx\n", nubus_get_rom(&rp, 1, bytelanes));
703 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
704 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
705 pr_debug("%08lx\n", nubus_get_rom(&rp, 4, bytelanes));
706 rp = board->fblock;
707
1da177e4 708 board->slot = slot;
f42e5550 709 board->slot_addr = (unsigned long)nubus_slot_addr(slot);
1da177e4
LT
710 board->doffset = nubus_get_rom(&rp, 4, bytelanes);
711 /* rom_length is *supposed* to be the total length of the
712 * ROM. In practice it is the "amount of ROM used to compute
713 * the CRC." So some jokers decide to set it to zero and
714 * set the crc to zero so they don't have to do any math.
715 * See the Performa 460 ROM, for example. Those Apple "engineers".
716 */
717 board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
718 board->crc = nubus_get_rom(&rp, 4, bytelanes);
719 board->rev = nubus_get_rom(&rp, 1, bytelanes);
f42e5550 720 board->format = nubus_get_rom(&rp, 1, bytelanes);
1da177e4
LT
721 board->lanes = bytelanes;
722
723 /* Directory offset should be small and negative... */
f42e5550 724 if (!(board->doffset & 0x00FF0000))
71ae40e4 725 pr_warn("Dodgy doffset!\n");
1da177e4 726 dpat = nubus_get_rom(&rp, 4, bytelanes);
f42e5550 727 if (dpat != NUBUS_TEST_PATTERN)
71ae40e4 728 pr_warn("Wrong test pattern %08lx!\n", dpat);
f42e5550 729
1da177e4
LT
730 /*
731 * I wonder how the CRC is meant to work -
732 * any takers ?
733 * CSA: According to MAC docs, not all cards pass the CRC anyway,
734 * since the initial Macintosh ROM releases skipped the check.
735 */
736
475e6e15
DHD
737 /* Set up the directory pointer */
738 board->directory = board->fblock;
739 nubus_move(&board->directory, nubus_expand32(board->doffset),
740 board->lanes);
741
f42e5550 742 nubus_get_root_dir(board, &dir);
1da177e4
LT
743
744 /* We're ready to rock */
71ae40e4 745 pr_info("Slot %X:\n", slot);
1da177e4
LT
746
747 /* Each slot should have one board resource and any number of
748 functional resources. So we'll fill in some fields in the
749 struct nubus_board from the board resource, then walk down
750 the list of functional resources, spinning out a nubus_dev
751 for each of them. */
752 if (nubus_readdir(&dir, &ent) == -1) {
753 /* We can't have this! */
71ae40e4 754 pr_err("Board resource not found!\n");
1da177e4
LT
755 return NULL;
756 } else {
71ae40e4 757 pr_info(" Board resource:\n");
1da177e4
LT
758 nubus_get_board_resource(board, slot, &ent);
759 }
760
1da177e4 761 while (nubus_readdir(&dir, &ent) != -1) {
f42e5550
FT
762 struct nubus_dev *dev;
763 struct nubus_dev **devp;
764
1da177e4
LT
765 dev = nubus_get_functional_resource(board, slot, &ent);
766 if (dev == NULL)
767 continue;
768
769 /* We zeroed this out above */
770 if (board->first_dev == NULL)
771 board->first_dev = dev;
f42e5550 772
1da177e4 773 /* Put it on the global NuBus device chain. Keep entries in order. */
f42e5550
FT
774 for (devp = &nubus_devices; *devp != NULL;
775 devp = &((*devp)->next))
1da177e4
LT
776 /* spin */;
777 *devp = dev;
f42e5550 778 dev->next = NULL;
1da177e4
LT
779 }
780
781 /* Put it on the global NuBus board chain. Keep entries in order. */
f42e5550
FT
782 for (boardp = &nubus_boards; *boardp != NULL;
783 boardp = &((*boardp)->next))
1da177e4
LT
784 /* spin */;
785 *boardp = board;
786 board->next = NULL;
f42e5550 787
1da177e4
LT
788 return board;
789}
790
791void __init nubus_probe_slot(int slot)
792{
793 unsigned char dp;
f42e5550 794 unsigned char *rp;
1da177e4
LT
795 int i;
796
f42e5550
FT
797 rp = nubus_rom_addr(slot);
798 for (i = 4; i; i--) {
1da177e4
LT
799 int card_present;
800
801 rp--;
1da177e4 802 card_present = hwreg_present(rp);
1da177e4
LT
803 if (!card_present)
804 continue;
805
1da177e4 806 dp = *rp;
1da177e4
LT
807
808 /* The last byte of the format block consists of two
809 nybbles which are "mirror images" of each other.
810 These show us the valid bytelanes */
f42e5550 811 if ((((dp >> 4) ^ dp) & 0x0F) != 0x0F)
1da177e4
LT
812 continue;
813 /* Check that this value is actually *on* one of the
814 bytelanes it claims are valid! */
85cc313a 815 if (not_useful(rp, dp))
1da177e4
LT
816 continue;
817
818 /* Looks promising. Let's put it on the list. */
819 nubus_add_board(slot, dp);
820
821 return;
822 }
823}
824
1da177e4
LT
825void __init nubus_scan_bus(void)
826{
827 int slot;
f42e5550 828
f42e5550 829 for (slot = 9; slot < 15; slot++) {
1da177e4
LT
830 nubus_probe_slot(slot);
831 }
832}
833
834static int __init nubus_init(void)
835{
f42e5550 836 if (!MACH_IS_MAC)
1da177e4
LT
837 return 0;
838
71ae40e4 839 pr_info("NuBus: Scanning NuBus slots.\n");
1da177e4 840 nubus_devices = NULL;
f42e5550 841 nubus_boards = NULL;
1da177e4 842 nubus_scan_bus();
1da177e4 843 nubus_proc_init();
1da177e4
LT
844 return 0;
845}
846
847subsys_initcall(nubus_init);