Linux Audio

Check our new training course

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