Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.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>
2f7dd07e 18#include <linux/seq_file.h>
5a0e3ad6 19#include <linux/slab.h>
1da177e4 20#include <asm/setup.h>
1da177e4
LT
21#include <asm/page.h>
22#include <asm/hwtest.h>
1da177e4
LT
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
1da177e4
LT
33/* Globals */
34
41b84816 35LIST_HEAD(nubus_func_rsrcs);
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
2f7dd07e 149unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
1da177e4
LT
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,
2f828fb2 164 unsigned int len)
1da177e4 165{
51b67a6e 166 unsigned char *t = dest;
1da177e4 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
2f7dd07e
FT
176unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
177 unsigned int len)
1da177e4 178{
2f828fb2 179 char *t = dest;
1da177e4 180 unsigned char *p = nubus_dirptr(dirent);
f42e5550 181
2f828fb2
FT
182 while (len > 1) {
183 unsigned char c = nubus_get_rom(&p, 1, dirent->mask);
184
185 if (!c)
1da177e4 186 break;
2f828fb2 187 *t++ = c;
1da177e4
LT
188 len--;
189 }
2f828fb2
FT
190 if (len > 0)
191 *t = '\0';
2f7dd07e 192 return t - dest;
1da177e4 193}
99ffab81 194EXPORT_SYMBOL(nubus_get_rsrc_str);
1da177e4 195
2f7dd07e
FT
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
f42e5550
FT
219int nubus_get_root_dir(const struct nubus_board *board,
220 struct nubus_dir *dir)
1da177e4
LT
221{
222 dir->ptr = dir->base = board->directory;
223 dir->done = 0;
224 dir->mask = board->lanes;
225 return 0;
226}
99ffab81 227EXPORT_SYMBOL(nubus_get_root_dir);
1da177e4
LT
228
229/* This is a slyly renamed version of the above */
189e19e8 230int nubus_get_func_dir(const struct nubus_rsrc *fres, struct nubus_dir *dir)
1da177e4 231{
189e19e8 232 dir->ptr = dir->base = fres->directory;
1da177e4 233 dir->done = 0;
189e19e8 234 dir->mask = fres->board->lanes;
1da177e4
LT
235 return 0;
236}
99ffab81 237EXPORT_SYMBOL(nubus_get_func_dir);
1da177e4 238
f42e5550
FT
239int nubus_get_board_dir(const struct nubus_board *board,
240 struct nubus_dir *dir)
1da177e4
LT
241{
242 struct nubus_dirent ent;
f42e5550 243
1da177e4
LT
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}
99ffab81 256EXPORT_SYMBOL(nubus_get_board_dir);
1da177e4
LT
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}
99ffab81 266EXPORT_SYMBOL(nubus_get_subdir);
1da177e4
LT
267
268int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
269{
270 u32 resid;
f42e5550 271
1da177e4
LT
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 */
f42e5550 282 if ((resid & 0xff000000) == 0xff000000) {
1da177e4
LT
283 /* Mark it as done */
284 nd->done = 1;
285 return -1;
286 }
287
288 /* First byte is the resource ID */
f42e5550 289 ent->type = resid >> 24;
1da177e4
LT
290 /* Low 3 bytes might contain data (or might not) */
291 ent->data = resid & 0xffffff;
f42e5550 292 ent->mask = nd->mask;
1da177e4
LT
293 return 0;
294}
99ffab81 295EXPORT_SYMBOL(nubus_readdir);
1da177e4 296
f42e5550 297int nubus_rewinddir(struct nubus_dir *dir)
1da177e4
LT
298{
299 dir->ptr = dir->base;
e36b9913 300 dir->done = 0;
1da177e4
LT
301 return 0;
302}
99ffab81 303EXPORT_SYMBOL(nubus_rewinddir);
1da177e4
LT
304
305/* Driver interface functions, more or less like in pci.c */
306
41b84816 307struct nubus_rsrc *nubus_first_rsrc_or_null(void)
1da177e4 308{
41b84816
FT
309 return list_first_entry_or_null(&nubus_func_rsrcs, struct nubus_rsrc,
310 list);
1da177e4 311}
41b84816 312EXPORT_SYMBOL(nubus_first_rsrc_or_null);
1da177e4 313
41b84816 314struct nubus_rsrc *nubus_next_rsrc_or_null(struct nubus_rsrc *from)
1da177e4 315{
41b84816
FT
316 if (list_is_last(&from->list, &nubus_func_rsrcs))
317 return NULL;
318 return list_next_entry(from, list);
1da177e4 319}
41b84816 320EXPORT_SYMBOL(nubus_next_rsrc_or_null);
1da177e4
LT
321
322int
f42e5550
FT
323nubus_find_rsrc(struct nubus_dir *dir, unsigned char rsrc_type,
324 struct nubus_dirent *ent)
1da177e4
LT
325{
326 while (nubus_readdir(dir, ent) != -1) {
327 if (ent->type == rsrc_type)
328 return 0;
f42e5550 329 }
1da177e4
LT
330 return -1;
331}
99ffab81 332EXPORT_SYMBOL(nubus_find_rsrc);
1da177e4
LT
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
883b8cb3 338static int __init nubus_get_block_rsrc_dir(struct nubus_board *board,
2f7dd07e 339 struct proc_dir_entry *procdir,
883b8cb3
FT
340 const struct nubus_dirent *parent)
341{
342 struct nubus_dir dir;
343 struct nubus_dirent ent;
344
345 nubus_get_subdir(parent, &dir);
2f7dd07e 346 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
883b8cb3
FT
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);
2f7dd07e 353 nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
883b8cb3
FT
354 }
355 return 0;
356}
357
358static int __init nubus_get_display_vidmode(struct nubus_board *board,
2f7dd07e 359 struct proc_dir_entry *procdir,
883b8cb3
FT
360 const struct nubus_dirent *parent)
361{
362 struct nubus_dir dir;
363 struct nubus_dirent ent;
364
365 nubus_get_subdir(parent, &dir);
2f7dd07e 366 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
883b8cb3
FT
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);
2f7dd07e 378 nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
883b8cb3
FT
379 break;
380 }
381 default:
382 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
383 ent.type, ent.data);
2f7dd07e 384 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
883b8cb3
FT
385 }
386 }
387 return 0;
388}
389
189e19e8 390static int __init nubus_get_display_resource(struct nubus_rsrc *fres,
2f7dd07e 391 struct proc_dir_entry *procdir,
883b8cb3 392 const struct nubus_dirent *ent)
1da177e4
LT
393{
394 switch (ent->type) {
395 case NUBUS_RESID_GAMMADIR:
f53bad08 396 pr_debug(" gamma directory offset: 0x%06x\n", ent->data);
189e19e8 397 nubus_get_block_rsrc_dir(fres->board, procdir, ent);
1da177e4
LT
398 break;
399 case 0x0080 ... 0x0085:
f53bad08
FT
400 pr_debug(" mode 0x%02x info offset: 0x%06x\n",
401 ent->type, ent->data);
189e19e8 402 nubus_get_display_vidmode(fres->board, procdir, ent);
1da177e4
LT
403 break;
404 default:
f53bad08
FT
405 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
406 ent->type, ent->data);
2f7dd07e 407 nubus_proc_add_rsrc_mem(procdir, ent, 0);
1da177e4
LT
408 }
409 return 0;
410}
411
189e19e8 412static int __init nubus_get_network_resource(struct nubus_rsrc *fres,
2f7dd07e 413 struct proc_dir_entry *procdir,
883b8cb3 414 const struct nubus_dirent *ent)
1da177e4
LT
415{
416 switch (ent->type) {
417 case NUBUS_RESID_MAC_ADDRESS:
418 {
419 char addr[6];
f42e5550 420
1da177e4 421 nubus_get_rsrc_mem(addr, ent, 6);
f53bad08 422 pr_debug(" MAC address: %pM\n", addr);
2f7dd07e 423 nubus_proc_add_rsrc_mem(procdir, ent, 6);
1da177e4
LT
424 break;
425 }
426 default:
f53bad08
FT
427 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
428 ent->type, ent->data);
2f7dd07e 429 nubus_proc_add_rsrc_mem(procdir, ent, 0);
1da177e4
LT
430 }
431 return 0;
432}
433
189e19e8 434static int __init nubus_get_cpu_resource(struct nubus_rsrc *fres,
2f7dd07e 435 struct proc_dir_entry *procdir,
883b8cb3 436 const struct nubus_dirent *ent)
1da177e4
LT
437{
438 switch (ent->type) {
439 case NUBUS_RESID_MEMINFO:
440 {
441 unsigned long meminfo[2];
f42e5550 442
1da177e4 443 nubus_get_rsrc_mem(&meminfo, ent, 8);
f53bad08
FT
444 pr_debug(" memory: [ 0x%08lx 0x%08lx ]\n",
445 meminfo[0], meminfo[1]);
2f7dd07e 446 nubus_proc_add_rsrc_mem(procdir, ent, 8);
1da177e4
LT
447 break;
448 }
449 case NUBUS_RESID_ROMINFO:
450 {
451 unsigned long rominfo[2];
f42e5550 452
1da177e4 453 nubus_get_rsrc_mem(&rominfo, ent, 8);
f53bad08
FT
454 pr_debug(" ROM: [ 0x%08lx 0x%08lx ]\n",
455 rominfo[0], rominfo[1]);
2f7dd07e 456 nubus_proc_add_rsrc_mem(procdir, ent, 8);
1da177e4
LT
457 break;
458 }
459 default:
f53bad08
FT
460 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
461 ent->type, ent->data);
2f7dd07e 462 nubus_proc_add_rsrc_mem(procdir, ent, 0);
1da177e4
LT
463 }
464 return 0;
465}
466
189e19e8 467static int __init nubus_get_private_resource(struct nubus_rsrc *fres,
2f7dd07e 468 struct proc_dir_entry *procdir,
883b8cb3 469 const struct nubus_dirent *ent)
1da177e4 470{
189e19e8 471 switch (fres->category) {
1da177e4 472 case NUBUS_CAT_DISPLAY:
189e19e8 473 nubus_get_display_resource(fres, procdir, ent);
1da177e4
LT
474 break;
475 case NUBUS_CAT_NETWORK:
189e19e8 476 nubus_get_network_resource(fres, procdir, ent);
1da177e4
LT
477 break;
478 case NUBUS_CAT_CPU:
189e19e8 479 nubus_get_cpu_resource(fres, procdir, ent);
1da177e4
LT
480 break;
481 default:
f53bad08
FT
482 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
483 ent->type, ent->data);
2f7dd07e 484 nubus_proc_add_rsrc_mem(procdir, ent, 0);
1da177e4
LT
485 }
486 return 0;
487}
488
189e19e8 489static struct nubus_rsrc * __init
f42e5550
FT
490nubus_get_functional_resource(struct nubus_board *board, int slot,
491 const struct nubus_dirent *parent)
1da177e4 492{
f42e5550 493 struct nubus_dir dir;
1da177e4 494 struct nubus_dirent ent;
189e19e8 495 struct nubus_rsrc *fres;
f42e5550 496
f53bad08 497 pr_debug(" Functional resource 0x%02x:\n", parent->type);
1da177e4 498 nubus_get_subdir(parent, &dir);
2f7dd07e 499 dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
1da177e4 500
1da177e4 501 /* Actually we should probably panic if this fails */
189e19e8
FT
502 fres = kzalloc(sizeof(*fres), GFP_ATOMIC);
503 if (!fres)
f42e5550 504 return NULL;
189e19e8
FT
505 fres->resid = parent->type;
506 fres->directory = dir.base;
507 fres->board = board;
f42e5550
FT
508
509 while (nubus_readdir(&dir, &ent) != -1) {
510 switch (ent.type) {
1da177e4
LT
511 case NUBUS_RESID_TYPE:
512 {
513 unsigned short nbtdata[4];
f42e5550 514
1da177e4 515 nubus_get_rsrc_mem(nbtdata, &ent, 8);
189e19e8
FT
516 fres->category = nbtdata[0];
517 fres->type = nbtdata[1];
518 fres->dr_sw = nbtdata[2];
519 fres->dr_hw = nbtdata[3];
f53bad08
FT
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]);
2f7dd07e 522 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
1da177e4
LT
523 break;
524 }
525 case NUBUS_RESID_NAME:
526 {
9f97977d 527 char name[64];
2f7dd07e 528 unsigned int len;
9f97977d 529
2f7dd07e 530 len = nubus_get_rsrc_str(name, &ent, sizeof(name));
9f97977d 531 pr_debug(" name: %s\n", name);
2f7dd07e 532 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
1da177e4
LT
533 break;
534 }
535 case NUBUS_RESID_DRVRDIR:
536 {
537 /* MacOS driver. If we were NetBSD we might
538 use this :-) */
883b8cb3
FT
539 pr_debug(" driver directory offset: 0x%06x\n",
540 ent.data);
2f7dd07e 541 nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
1da177e4
LT
542 break;
543 }
544 case NUBUS_RESID_MINOR_BASEOS:
9f97977d 545 {
1da177e4
LT
546 /* We will need this in order to support
547 multiple framebuffers. It might be handy
548 for Ethernet as well */
9f97977d
FT
549 u32 base_offset;
550
551 nubus_get_rsrc_mem(&base_offset, &ent, 4);
552 pr_debug(" memory offset: 0x%08x\n", base_offset);
2f7dd07e 553 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
1da177e4 554 break;
9f97977d 555 }
1da177e4 556 case NUBUS_RESID_MINOR_LENGTH:
9f97977d 557 {
1da177e4 558 /* Ditto */
9f97977d
FT
559 u32 length;
560
561 nubus_get_rsrc_mem(&length, &ent, 4);
562 pr_debug(" memory length: 0x%08x\n", length);
2f7dd07e 563 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
f42e5550 564 break;
9f97977d 565 }
1da177e4 566 case NUBUS_RESID_FLAGS:
9f97977d 567 pr_debug(" flags: 0x%06x\n", ent.data);
2f7dd07e 568 nubus_proc_add_rsrc(dir.procdir, &ent);
1da177e4
LT
569 break;
570 case NUBUS_RESID_HWDEVID:
9f97977d 571 pr_debug(" hwdevid: 0x%06x\n", ent.data);
2f7dd07e 572 nubus_proc_add_rsrc(dir.procdir, &ent);
1da177e4
LT
573 break;
574 default:
575 /* Local/Private resources have their own
576 function */
189e19e8 577 nubus_get_private_resource(fres, dir.procdir, &ent);
1da177e4
LT
578 }
579 }
f42e5550 580
189e19e8 581 return fres;
1da177e4
LT
582}
583
1da177e4 584/* This is *really* cool. */
f42e5550 585static int __init nubus_get_icon(struct nubus_board *board,
2f7dd07e 586 struct proc_dir_entry *procdir,
f42e5550 587 const struct nubus_dirent *ent)
1da177e4
LT
588{
589 /* Should be 32x32 if my memory serves me correctly */
f53bad08
FT
590 u32 icon[32];
591 int i;
f42e5550 592
1da177e4 593 nubus_get_rsrc_mem(&icon, ent, 128);
f53bad08
FT
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]);
2f7dd07e 599 nubus_proc_add_rsrc_mem(procdir, ent, 128);
f53bad08 600
1da177e4
LT
601 return 0;
602}
603
f42e5550 604static int __init nubus_get_vendorinfo(struct nubus_board *board,
2f7dd07e 605 struct proc_dir_entry *procdir,
f42e5550 606 const struct nubus_dirent *parent)
1da177e4 607{
f42e5550 608 struct nubus_dir dir;
1da177e4 609 struct nubus_dirent ent;
f42e5550
FT
610 static char *vendor_fields[6] = { "ID", "serial", "revision",
611 "part", "date", "unknown field" };
1da177e4 612
f53bad08 613 pr_debug(" vendor info:\n");
1da177e4 614 nubus_get_subdir(parent, &dir);
2f7dd07e 615 dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
1da177e4 616
f42e5550 617 while (nubus_readdir(&dir, &ent) != -1) {
1da177e4 618 char name[64];
2f7dd07e 619 unsigned int len;
f42e5550 620
1da177e4 621 /* These are all strings, we think */
2f7dd07e 622 len = nubus_get_rsrc_str(name, &ent, sizeof(name));
2f828fb2 623 if (ent.type < 1 || ent.type > 5)
1da177e4 624 ent.type = 5;
f53bad08 625 pr_debug(" %s: %s\n", vendor_fields[ent.type - 1], name);
2f7dd07e 626 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
1da177e4
LT
627 }
628 return 0;
629}
630
f42e5550
FT
631static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
632 const struct nubus_dirent *parent)
1da177e4 633{
f42e5550 634 struct nubus_dir dir;
1da177e4 635 struct nubus_dirent ent;
f42e5550 636
f53bad08 637 pr_debug(" Board resource 0x%02x:\n", parent->type);
1da177e4 638 nubus_get_subdir(parent, &dir);
2f7dd07e 639 dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
1da177e4 640
f42e5550 641 while (nubus_readdir(&dir, &ent) != -1) {
1da177e4
LT
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);
f53bad08
FT
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]);
1da177e4
LT
652 if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
653 nbtdata[2] != 0 || nbtdata[3] != 0)
d7811a36
FT
654 pr_err("Slot %X: sResource is not a board resource!\n",
655 slot);
2f7dd07e 656 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
1da177e4
LT
657 break;
658 }
659 case NUBUS_RESID_NAME:
2f7dd07e
FT
660 {
661 unsigned int len;
662
663 len = nubus_get_rsrc_str(board->name, &ent,
664 sizeof(board->name));
f53bad08 665 pr_debug(" name: %s\n", board->name);
2f7dd07e 666 nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
1da177e4 667 break;
2f7dd07e 668 }
1da177e4 669 case NUBUS_RESID_ICON:
2f7dd07e 670 nubus_get_icon(board, dir.procdir, &ent);
1da177e4
LT
671 break;
672 case NUBUS_RESID_BOARDID:
f53bad08 673 pr_debug(" board id: 0x%x\n", ent.data);
2f7dd07e 674 nubus_proc_add_rsrc(dir.procdir, &ent);
1da177e4
LT
675 break;
676 case NUBUS_RESID_PRIMARYINIT:
f53bad08 677 pr_debug(" primary init offset: 0x%06x\n", ent.data);
2f7dd07e 678 nubus_proc_add_rsrc(dir.procdir, &ent);
1da177e4
LT
679 break;
680 case NUBUS_RESID_VENDORINFO:
2f7dd07e 681 nubus_get_vendorinfo(board, dir.procdir, &ent);
1da177e4
LT
682 break;
683 case NUBUS_RESID_FLAGS:
f53bad08 684 pr_debug(" flags: 0x%06x\n", ent.data);
2f7dd07e 685 nubus_proc_add_rsrc(dir.procdir, &ent);
1da177e4
LT
686 break;
687 case NUBUS_RESID_HWDEVID:
f53bad08 688 pr_debug(" hwdevid: 0x%06x\n", ent.data);
2f7dd07e 689 nubus_proc_add_rsrc(dir.procdir, &ent);
1da177e4
LT
690 break;
691 case NUBUS_RESID_SECONDINIT:
f53bad08
FT
692 pr_debug(" secondary init offset: 0x%06x\n",
693 ent.data);
2f7dd07e 694 nubus_proc_add_rsrc(dir.procdir, &ent);
1da177e4 695 break;
f42e5550 696 /* WTF isn't this in the functional resources? */
1da177e4 697 case NUBUS_RESID_VIDNAMES:
883b8cb3
FT
698 pr_debug(" vidnames directory offset: 0x%06x\n",
699 ent.data);
2f7dd07e 700 nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
1da177e4
LT
701 break;
702 /* Same goes for this */
703 case NUBUS_RESID_VIDMODES:
f53bad08
FT
704 pr_debug(" video mode parameter directory offset: 0x%06x\n",
705 ent.data);
2f7dd07e 706 nubus_proc_add_rsrc(dir.procdir, &ent);
f42e5550 707 break;
1da177e4 708 default:
f53bad08
FT
709 pr_debug(" unknown resource 0x%02x, data 0x%06x\n",
710 ent.type, ent.data);
2f7dd07e 711 nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
1da177e4
LT
712 }
713 }
714 return 0;
715}
716
7f86c765 717static void __init nubus_add_board(int slot, int bytelanes)
1da177e4 718{
f42e5550 719 struct nubus_board *board;
1da177e4
LT
720 unsigned char *rp;
721 unsigned long dpat;
722 struct nubus_dir dir;
723 struct nubus_dirent ent;
d7811a36 724 int prev_resid = -1;
1da177e4
LT
725
726 /* Move to the start of the format block */
f42e5550 727 rp = nubus_rom_addr(slot);
1da177e4
LT
728 nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
729
730 /* Actually we should probably panic if this fails */
dd00cc48 731 if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
7f86c765 732 return;
1da177e4
LT
733 board->fblock = rp;
734
735 /* Dump the format block for debugging purposes */
71ae40e4 736 pr_debug("Slot %X, format block at 0x%p:\n", slot, rp);
f53bad08
FT
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));
71ae40e4
DHD
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));
71ae40e4
DHD
745 rp = board->fblock;
746
1da177e4 747 board->slot = slot;
f42e5550 748 board->slot_addr = (unsigned long)nubus_slot_addr(slot);
1da177e4
LT
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);
f42e5550 759 board->format = nubus_get_rom(&rp, 1, bytelanes);
1da177e4
LT
760 board->lanes = bytelanes;
761
762 /* Directory offset should be small and negative... */
f42e5550 763 if (!(board->doffset & 0x00FF0000))
d7811a36 764 pr_warn("Slot %X: Dodgy doffset!\n", slot);
1da177e4 765 dpat = nubus_get_rom(&rp, 4, bytelanes);
f42e5550 766 if (dpat != NUBUS_TEST_PATTERN)
d7811a36 767 pr_warn("Slot %X: Wrong test pattern %08lx!\n", slot, dpat);
f42e5550 768
1da177e4
LT
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
475e6e15
DHD
776 /* Set up the directory pointer */
777 board->directory = board->fblock;
778 nubus_move(&board->directory, nubus_expand32(board->doffset),
779 board->lanes);
780
f42e5550 781 nubus_get_root_dir(board, &dir);
1da177e4
LT
782
783 /* We're ready to rock */
f53bad08 784 pr_debug("Slot %X resources:\n", slot);
1da177e4
LT
785
786 /* Each slot should have one board resource and any number of
189e19e8
FT
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 */
1da177e4
LT
792 if (nubus_readdir(&dir, &ent) == -1) {
793 /* We can't have this! */
d7811a36 794 pr_err("Slot %X: Board resource not found!\n", slot);
7f86c765
FT
795 kfree(board);
796 return;
1da177e4
LT
797 }
798
d7811a36
FT
799 if (ent.type < 1 || ent.type > 127)
800 pr_warn("Slot %X: Board resource ID is invalid!\n", slot);
801
2f7dd07e
FT
802 board->procdir = nubus_proc_add_board(board);
803
d7811a36
FT
804 nubus_get_board_resource(board, slot, &ent);
805
1da177e4 806 while (nubus_readdir(&dir, &ent) != -1) {
189e19e8 807 struct nubus_rsrc *fres;
f42e5550 808
189e19e8
FT
809 fres = nubus_get_functional_resource(board, slot, &ent);
810 if (fres == NULL)
1da177e4
LT
811 continue;
812
d7811a36
FT
813 /* Resources should appear in ascending ID order. This sanity
814 * check prevents duplicate resource IDs.
815 */
189e19e8
FT
816 if (fres->resid <= prev_resid) {
817 kfree(fres);
d7811a36
FT
818 continue;
819 }
189e19e8 820 prev_resid = fres->resid;
d7811a36 821
41b84816 822 list_add_tail(&fres->list, &nubus_func_rsrcs);
1da177e4
LT
823 }
824
7f86c765
FT
825 if (nubus_device_register(board))
826 put_device(&board->dev);
1da177e4
LT
827}
828
460cf95e 829static void __init nubus_probe_slot(int slot)
1da177e4
LT
830{
831 unsigned char dp;
f42e5550 832 unsigned char *rp;
1da177e4
LT
833 int i;
834
f42e5550
FT
835 rp = nubus_rom_addr(slot);
836 for (i = 4; i; i--) {
1da177e4 837 rp--;
9f97977d 838 if (!hwreg_present(rp))
1da177e4
LT
839 continue;
840
1da177e4 841 dp = *rp;
1da177e4
LT
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 */
f42e5550 846 if ((((dp >> 4) ^ dp) & 0x0F) != 0x0F)
1da177e4
LT
847 continue;
848 /* Check that this value is actually *on* one of the
849 bytelanes it claims are valid! */
85cc313a 850 if (not_useful(rp, dp))
1da177e4
LT
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
460cf95e 860static void __init nubus_scan_bus(void)
1da177e4
LT
861{
862 int slot;
f42e5550 863
f53bad08 864 pr_info("NuBus: Scanning NuBus slots.\n");
f42e5550 865 for (slot = 9; slot < 15; slot++) {
1da177e4
LT
866 nubus_probe_slot(slot);
867 }
868}
869
870static int __init nubus_init(void)
871{
7f86c765
FT
872 int err;
873
f42e5550 874 if (!MACH_IS_MAC)
1da177e4
LT
875 return 0;
876
1da177e4 877 nubus_proc_init();
bdeeed09 878 err = nubus_parent_device_register();
7f86c765
FT
879 if (err)
880 return err;
2f7dd07e 881 nubus_scan_bus();
1da177e4
LT
882 return 0;
883}
884
885subsys_initcall(nubus_init);