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