The /proc/bus/nubus/s/ directory tree for any slot s is missing a lot
of information. The struct file_operations methods have long been left
unimplemented (hence the familiar compile-time warning, "Need to set
some I/O handlers here").

Slot resources have a complex structure which varies depending on board
function. The logic for interpreting these ROM data structures is found
in nubus.c. Let's not duplicate that logic in proc.c.

Create the /proc/bus/nubus/s/ inodes while scanning slot s. During
descent through slot resource subdirectories, call the new
nubus_proc_add_foo() functions to create the procfs inodes.

Also add a new function, nubus_seq_write_rsrc_mem(), to write the
contents of a particular slot resource to a given seq_file. This is
used by the procfs file_operations methods, to finally give userspace
access to slot ROM information, such as the available video modes.

Tested-by: Stan Johnson <user...@yahoo.com>
Signed-off-by: Finn Thain <fth...@telegraphics.com.au>
---
 drivers/nubus/nubus.c | 118 +++++++++++++++++++++------
 drivers/nubus/proc.c  | 218 +++++++++++++++++++++++++++++---------------------
 include/linux/nubus.h |  37 ++++++++-
 3 files changed, 254 insertions(+), 119 deletions(-)

diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index 0ca8a7a9be2b..c61327325553 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -146,7 +147,7 @@ static inline void *nubus_rom_addr(int slot)
        return (void *)(0xF1000000 + (slot << 24));
 }
 
-static unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
+unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
 {
        unsigned char *p = nd->base;
 
@@ -173,8 +174,8 @@ void nubus_get_rsrc_mem(void *dest, const struct 
nubus_dirent *dirent,
 }
 EXPORT_SYMBOL(nubus_get_rsrc_mem);
 
-void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
-                        unsigned int len)
+unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
+                                unsigned int len)
 {
        char *t = dest;
        unsigned char *p = nubus_dirptr(dirent);
@@ -189,9 +190,33 @@ void nubus_get_rsrc_str(char *dest, const struct 
nubus_dirent *dirent,
        }
        if (len > 0)
                *t = '\0';
+       return t - dest;
 }
 EXPORT_SYMBOL(nubus_get_rsrc_str);
 
+void nubus_seq_write_rsrc_mem(struct seq_file *m,
+                              const struct nubus_dirent *dirent,
+                              unsigned int len)
+{
+       unsigned long buf[32];
+       unsigned int buf_size = sizeof(buf);
+       unsigned char *p = nubus_dirptr(dirent);
+
+       /* If possible, write out full buffers */
+       while (len >= buf_size) {
+               unsigned int i;
+
+               for (i = 0; i < ARRAY_SIZE(buf); i++)
+                       buf[i] = nubus_get_rom(&p, sizeof(buf[0]),
+                                              dirent->mask);
+               seq_write(m, buf, buf_size);
+               len -= buf_size;
+       }
+       /* If not, write out individual bytes */
+       while (len--)
+               seq_putc(m, nubus_get_rom(&p, 1, dirent->mask));
+}
+
 int nubus_get_root_dir(const struct nubus_board *board,
                       struct nubus_dir *dir)
 {
@@ -326,35 +351,35 @@ EXPORT_SYMBOL(nubus_find_rsrc);
    looking at, and print out lots and lots of information from the
    resource blocks. */
 
-/* FIXME: A lot of this stuff will eventually be useful after
-   initialization, for intelligently probing Ethernet and video chips,
-   among other things.  The rest of it should go in the /proc code.
-   For now, we just use it to give verbose boot logs. */
-
 static int __init nubus_get_block_rsrc_dir(struct nubus_board *board,
+                                           struct proc_dir_entry *procdir,
                                            const struct nubus_dirent *parent)
 {
        struct nubus_dir dir;
        struct nubus_dirent ent;
 
        nubus_get_subdir(parent, &dir);
+       dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
 
        while (nubus_readdir(&dir, &ent) != -1) {
                u32 size;
 
                nubus_get_rsrc_mem(&size, &ent, 4);
                pr_debug("        block (0x%x), size %d\n", ent.type, size);
+               nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
        }
        return 0;
 }
 
 static int __init nubus_get_display_vidmode(struct nubus_board *board,
+                                            struct proc_dir_entry *procdir,
                                             const struct nubus_dirent *parent)
 {
        struct nubus_dir dir;
        struct nubus_dirent ent;
 
        nubus_get_subdir(parent, &dir);
+       dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
 
        while (nubus_readdir(&dir, &ent) != -1) {
                switch (ent.type) {
@@ -366,37 +391,42 @@ static int __init nubus_get_display_vidmode(struct 
nubus_board *board,
                        nubus_get_rsrc_mem(&size, &ent, 4);
                        pr_debug("        block (0x%x), size %d\n", ent.type,
                                size);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
                        break;
                }
                default:
                        pr_debug("        unknown resource 0x%02x, data 
0x%06x\n",
                                ent.type, ent.data);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
                }
        }
        return 0;
 }
 
 static int __init nubus_get_display_resource(struct nubus_dev *dev,
+                                             struct proc_dir_entry *procdir,
                                              const struct nubus_dirent *ent)
 {
        switch (ent->type) {
        case NUBUS_RESID_GAMMADIR:
                pr_debug("    gamma directory offset: 0x%06x\n", ent->data);
-               nubus_get_block_rsrc_dir(dev->board, ent);
+               nubus_get_block_rsrc_dir(dev->board, procdir, ent);
                break;
        case 0x0080 ... 0x0085:
                pr_debug("    mode 0x%02x info offset: 0x%06x\n",
                        ent->type, ent->data);
-               nubus_get_display_vidmode(dev->board, ent);
+               nubus_get_display_vidmode(dev->board, procdir, ent);
                break;
        default:
                pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
                        ent->type, ent->data);
+               nubus_proc_add_rsrc_mem(procdir, ent, 0);
        }
        return 0;
 }
 
 static int __init nubus_get_network_resource(struct nubus_dev *dev,
+                                             struct proc_dir_entry *procdir,
                                              const struct nubus_dirent *ent)
 {
        switch (ent->type) {
@@ -406,16 +436,19 @@ static int __init nubus_get_network_resource(struct 
nubus_dev *dev,
 
                nubus_get_rsrc_mem(addr, ent, 6);
                pr_debug("    MAC address: %pM\n", addr);
+               nubus_proc_add_rsrc_mem(procdir, ent, 6);
                break;
        }
        default:
                pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
                        ent->type, ent->data);
+               nubus_proc_add_rsrc_mem(procdir, ent, 0);
        }
        return 0;
 }
 
 static int __init nubus_get_cpu_resource(struct nubus_dev *dev,
+                                         struct proc_dir_entry *procdir,
                                          const struct nubus_dirent *ent)
 {
        switch (ent->type) {
@@ -426,6 +459,7 @@ static int __init nubus_get_cpu_resource(struct nubus_dev 
*dev,
                nubus_get_rsrc_mem(&meminfo, ent, 8);
                pr_debug("    memory: [ 0x%08lx 0x%08lx ]\n",
                        meminfo[0], meminfo[1]);
+               nubus_proc_add_rsrc_mem(procdir, ent, 8);
                break;
        }
        case NUBUS_RESID_ROMINFO:
@@ -435,31 +469,35 @@ static int __init nubus_get_cpu_resource(struct nubus_dev 
*dev,
                nubus_get_rsrc_mem(&rominfo, ent, 8);
                pr_debug("    ROM:    [ 0x%08lx 0x%08lx ]\n",
                        rominfo[0], rominfo[1]);
+               nubus_proc_add_rsrc_mem(procdir, ent, 8);
                break;
        }
        default:
                pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
                        ent->type, ent->data);
+               nubus_proc_add_rsrc_mem(procdir, ent, 0);
        }
        return 0;
 }
 
 static int __init nubus_get_private_resource(struct nubus_dev *dev,
+                                             struct proc_dir_entry *procdir,
                                              const struct nubus_dirent *ent)
 {
        switch (dev->category) {
        case NUBUS_CAT_DISPLAY:
-               nubus_get_display_resource(dev, ent);
+               nubus_get_display_resource(dev, procdir, ent);
                break;
        case NUBUS_CAT_NETWORK:
-               nubus_get_network_resource(dev, ent);
+               nubus_get_network_resource(dev, procdir, ent);
                break;
        case NUBUS_CAT_CPU:
-               nubus_get_cpu_resource(dev, ent);
+               nubus_get_cpu_resource(dev, procdir, ent);
                break;
        default:
                pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
                        ent->type, ent->data);
+               nubus_proc_add_rsrc_mem(procdir, ent, 0);
        }
        return 0;
 }
@@ -474,6 +512,7 @@ nubus_get_functional_resource(struct nubus_board *board, 
int slot,
 
        pr_debug("  Functional resource 0x%02x:\n", parent->type);
        nubus_get_subdir(parent, &dir);
+       dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
 
        /* Actually we should probably panic if this fails */
        if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
@@ -495,14 +534,17 @@ nubus_get_functional_resource(struct nubus_board *board, 
int slot,
                        dev->dr_hw    = nbtdata[3];
                        pr_debug("    type: [cat 0x%x type 0x%x sw 0x%x hw 
0x%x]\n",
                                nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
                        break;
                }
                case NUBUS_RESID_NAME:
                {
                        char name[64];
+                       unsigned int len;
 
-                       nubus_get_rsrc_str(name, &ent, sizeof(name));
+                       len = nubus_get_rsrc_str(name, &ent, sizeof(name));
                        pr_debug("    name: %s\n", name);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, len);
                        break;
                }
                case NUBUS_RESID_DRVRDIR:
@@ -511,7 +553,7 @@ nubus_get_functional_resource(struct nubus_board *board, 
int slot,
                           use this :-) */
                        pr_debug("    driver directory offset: 0x%06x\n",
                                ent.data);
-                       nubus_get_block_rsrc_dir(board, &ent);
+                       nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
                        break;
                }
                case NUBUS_RESID_MINOR_BASEOS:
@@ -523,6 +565,7 @@ nubus_get_functional_resource(struct nubus_board *board, 
int slot,
 
                        nubus_get_rsrc_mem(&base_offset, &ent, 4);
                        pr_debug("    memory offset: 0x%08x\n", base_offset);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
                        break;
                }
                case NUBUS_RESID_MINOR_LENGTH:
@@ -532,18 +575,21 @@ nubus_get_functional_resource(struct nubus_board *board, 
int slot,
 
                        nubus_get_rsrc_mem(&length, &ent, 4);
                        pr_debug("    memory length: 0x%08x\n", length);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
                        break;
                }
                case NUBUS_RESID_FLAGS:
                        pr_debug("    flags: 0x%06x\n", ent.data);
+                       nubus_proc_add_rsrc(dir.procdir, &ent);
                        break;
                case NUBUS_RESID_HWDEVID:
                        pr_debug("    hwdevid: 0x%06x\n", ent.data);
+                       nubus_proc_add_rsrc(dir.procdir, &ent);
                        break;
                default:
                        /* Local/Private resources have their own
                           function */
-                       nubus_get_private_resource(dev, &ent);
+                       nubus_get_private_resource(dev, dir.procdir, &ent);
                }
        }
 
@@ -552,7 +598,8 @@ nubus_get_functional_resource(struct nubus_board *board, 
int slot,
 
 /* This is *really* cool. */
 static int __init nubus_get_icon(struct nubus_board *board,
-                                const struct nubus_dirent *ent)
+                                 struct proc_dir_entry *procdir,
+                                 const struct nubus_dirent *ent)
 {
        /* Should be 32x32 if my memory serves me correctly */
        u32 icon[32];
@@ -564,12 +611,14 @@ static int __init nubus_get_icon(struct nubus_board 
*board,
                pr_debug("        %08x %08x %08x %08x\n",
                        icon[i * 4 + 0], icon[i * 4 + 1],
                        icon[i * 4 + 2], icon[i * 4 + 3]);
+       nubus_proc_add_rsrc_mem(procdir, ent, 128);
 
        return 0;
 }
 
 static int __init nubus_get_vendorinfo(struct nubus_board *board,
-                                      const struct nubus_dirent *parent)
+                                       struct proc_dir_entry *procdir,
+                                       const struct nubus_dirent *parent)
 {
        struct nubus_dir dir;
        struct nubus_dirent ent;
@@ -578,15 +627,18 @@ static int __init nubus_get_vendorinfo(struct nubus_board 
*board,
 
        pr_debug("    vendor info:\n");
        nubus_get_subdir(parent, &dir);
+       dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);
 
        while (nubus_readdir(&dir, &ent) != -1) {
                char name[64];
+               unsigned int len;
 
                /* These are all strings, we think */
-               nubus_get_rsrc_str(name, &ent, sizeof(name));
+               len = nubus_get_rsrc_str(name, &ent, sizeof(name));
                if (ent.type < 1 || ent.type > 5)
                        ent.type = 5;
                pr_debug("    %s: %s\n", vendor_fields[ent.type - 1], name);
+               nubus_proc_add_rsrc_mem(dir.procdir, &ent, len);
        }
        return 0;
 }
@@ -599,6 +651,7 @@ static int __init nubus_get_board_resource(struct 
nubus_board *board, int slot,
 
        pr_debug("  Board resource 0x%02x:\n", parent->type);
        nubus_get_subdir(parent, &dir);
+       dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);
 
        while (nubus_readdir(&dir, &ent) != -1) {
                switch (ent.type) {
@@ -614,48 +667,61 @@ static int __init nubus_get_board_resource(struct 
nubus_board *board, int slot,
                        if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
                            nbtdata[2] != 0 || nbtdata[3] != 0)
                                pr_err("Slot %X: sResource is not a board 
resource!\n", slot);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
                        break;
                }
                case NUBUS_RESID_NAME:
-                       nubus_get_rsrc_str(board->name, &ent,
-                                          sizeof(board->name));
+               {
+                       unsigned int len;
+
+                       len = nubus_get_rsrc_str(board->name, &ent,
+                                                sizeof(board->name));
                        pr_debug("    name: %s\n", board->name);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, len);
                        break;
+               }
                case NUBUS_RESID_ICON:
-                       nubus_get_icon(board, &ent);
+                       nubus_get_icon(board, dir.procdir, &ent);
                        break;
                case NUBUS_RESID_BOARDID:
                        pr_debug("    board id: 0x%x\n", ent.data);
+                       nubus_proc_add_rsrc(dir.procdir, &ent);
                        break;
                case NUBUS_RESID_PRIMARYINIT:
                        pr_debug("    primary init offset: 0x%06x\n", ent.data);
+                       nubus_proc_add_rsrc(dir.procdir, &ent);
                        break;
                case NUBUS_RESID_VENDORINFO:
-                       nubus_get_vendorinfo(board, &ent);
+                       nubus_get_vendorinfo(board, dir.procdir, &ent);
                        break;
                case NUBUS_RESID_FLAGS:
                        pr_debug("    flags: 0x%06x\n", ent.data);
+                       nubus_proc_add_rsrc(dir.procdir, &ent);
                        break;
                case NUBUS_RESID_HWDEVID:
                        pr_debug("    hwdevid: 0x%06x\n", ent.data);
+                       nubus_proc_add_rsrc(dir.procdir, &ent);
                        break;
                case NUBUS_RESID_SECONDINIT:
                        pr_debug("    secondary init offset: 0x%06x\n", 
ent.data);
+                       nubus_proc_add_rsrc(dir.procdir, &ent);
                        break;
                        /* WTF isn't this in the functional resources? */
                case NUBUS_RESID_VIDNAMES:
                        pr_debug("    vidnames directory offset: 0x%06x\n",
                                ent.data);
-                       nubus_get_block_rsrc_dir(board, &ent);
+                       nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
                        break;
                        /* Same goes for this */
                case NUBUS_RESID_VIDMODES:
                        pr_debug("    video mode parameter directory offset: 
0x%06x\n",
                               ent.data);
+                       nubus_proc_add_rsrc(dir.procdir, &ent);
                        break;
                default:
                        pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
                               ent.type, ent.data);
+                       nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
                }
        }
        return 0;
@@ -746,6 +812,8 @@ static struct nubus_board * __init nubus_add_board(int 
slot, int bytelanes)
        if (ent.type < 1 || ent.type > 127)
                pr_warn("Slot %X: Board resource ID is invalid!\n", slot);
 
+       board->procdir = nubus_proc_add_board(board);
+
        nubus_get_board_resource(board, slot, &ent);
 
        while (nubus_readdir(&dir, &ent) != -1) {
@@ -836,8 +904,8 @@ static int __init nubus_init(void)
        if (!MACH_IS_MAC)
                return 0;
 
-       nubus_scan_bus();
        nubus_proc_init();
+       nubus_scan_bus();
        return 0;
 }
 
diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c
index 41ec859bdd8b..69c505795c30 100644
--- a/drivers/nubus/proc.c
+++ b/drivers/nubus/proc.c
@@ -11,24 +11,28 @@
    structure in /proc analogous to the structure of the NuBus ROM
    resources.
 
-   Therefore each NuBus device is in fact a directory, which may in
-   turn contain subdirectories.  The "files" correspond to NuBus
-   resource records.  For those types of records which we know how to
-   convert to formats that are meaningful to userspace (mostly just
-   icons) these files will provide "cooked" data.  Otherwise they will
-   simply provide raw access (read-only of course) to the ROM.  */
+   Therefore each board function gets a directory, which may in turn
+   contain subdirectories.  Each slot resource is a file.  Unrecognized
+   resources are empty files, since every resource ID requires a special
+   case (e.g. if the resource ID implies a directory or block, then its
+   value has to be interpreted as a slot ROM pointer etc.).
+ */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/nubus.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
-
 #include <linux/uaccess.h>
 #include <asm/byteorder.h>
 
+/*
+ * /proc/bus/nubus/devices stuff
+ */
+
 static int
 nubus_devices_proc_show(struct seq_file *m, void *v)
 {
@@ -61,96 +65,137 @@ static const struct file_operations 
nubus_devices_proc_fops = {
 
 static struct proc_dir_entry *proc_bus_nubus_dir;
 
-static const struct file_operations nubus_proc_subdir_fops = {
-#warning Need to set some I/O handlers here
+/*
+ * /proc/bus/nubus/x/ stuff
+ */
+
+struct proc_dir_entry *nubus_proc_add_board(struct nubus_board *board)
+{
+       char name[2];
+
+       if (!proc_bus_nubus_dir)
+               return NULL;
+       snprintf(name, sizeof(name), "%x", board->slot);
+       return proc_mkdir(name, proc_bus_nubus_dir);
+}
+
+/* The PDE private data for every directory under /proc/bus/nubus/x/
+ * is a pointer to the struct nubus_board for slot x.
+ */
+
+struct proc_dir_entry *nubus_proc_add_rsrc_dir(struct proc_dir_entry *procdir,
+                                               const struct nubus_dirent *ent,
+                                               struct nubus_board *board)
+{
+       char name[9];
+
+       if (!procdir)
+               return NULL;
+       snprintf(name, sizeof(name), "%x", ent->type);
+       return proc_mkdir_data(name, S_IRUGO | S_IXUGO, procdir, board);
+}
+
+/* The PDE private data for a file under /proc/bus/nubus/x/ is a pointer to
+ * an instance of the following structure, which gives the location and size
+ * of the resource data in the slot ROM. For slot resources which hold only
+ * a small integer, the integer value is stored directly and ptr is NULL.
+ */
+
+struct nubus_proc_pde_data {
+       unsigned char *res_ptr;
+       unsigned int res_size;
+       unsigned int res_data;
 };
 
-static void nubus_proc_subdir(struct nubus_dev* dev,
-                             struct proc_dir_entry* parent,
-                             struct nubus_dir* dir)
+static struct nubus_proc_pde_data *
+nubus_proc_alloc_pde_data(unsigned char *ptr, unsigned int size,
+                          unsigned int data)
 {
-       struct nubus_dirent ent;
-
-       /* Some of these are directories, others aren't */
-       while (nubus_readdir(dir, &ent) != -1) {
-               char name[9];
-               struct proc_dir_entry* e;
-               
-               snprintf(name, sizeof(name), "%x", ent.type);
-               e = proc_create(name, S_IFREG | S_IRUGO | S_IWUSR, parent,
-                               &nubus_proc_subdir_fops);
-               if (!e)
-                       return;
-       }
+       struct nubus_proc_pde_data *pde_data;
+
+       pde_data = kmalloc(sizeof(*pde_data), GFP_KERNEL);
+       if (!pde_data)
+               return NULL;
+
+       pde_data->res_ptr = ptr;
+       pde_data->res_size = size;
+       pde_data->res_data = data;
+
+       return pde_data;
 }
 
-/* Can't do this recursively since the root directory is structured
-   somewhat differently from the subdirectories */
-static void nubus_proc_populate(struct nubus_dev* dev,
-                               struct proc_dir_entry* parent,
-                               struct nubus_dir* root)
+static int nubus_proc_rsrc_show(struct seq_file *m, void *v)
 {
-       struct nubus_dirent ent;
-
-       /* We know these are all directories (board resource + one or
-          more functional resources) */
-       while (nubus_readdir(root, &ent) != -1) {
-               char name[9];
-               struct proc_dir_entry* e;
-               struct nubus_dir dir;
-               
-               snprintf(name, sizeof(name), "%x", ent.type);
-               e = proc_mkdir(name, parent);
-               if (!e) return;
-
-               /* And descend */
-               if (nubus_get_subdir(&ent, &dir) == -1) {
-                       /* This shouldn't happen */
-                       printk(KERN_ERR "NuBus root directory node %x:%x has no 
subdir!\n",
-                              dev->board->slot, ent.type);
-                       continue;
-               } else {
-                       nubus_proc_subdir(dev, e, &dir);
-               }
+       struct inode *inode = m->private;
+       struct nubus_board *board;
+       struct nubus_proc_pde_data *pde_data;
+
+       board = proc_get_parent_data(inode);
+       if (!board)
+               return 0;
+
+       pde_data = PDE_DATA(inode);
+       if (!pde_data)
+               return 0;
+
+       if (pde_data->res_size > m->size)
+               return -EFBIG;
+
+       if (pde_data->res_ptr) {
+               struct nubus_dirent ent;
+
+               ent.mask = board->lanes;
+               ent.base = pde_data->res_ptr;
+               ent.data = 0;
+               nubus_seq_write_rsrc_mem(m, &ent, pde_data->res_size);
+       } else {
+               seq_putc(m, pde_data->res_data >> 16);
+               seq_putc(m, pde_data->res_data >> 8);
+               seq_putc(m, pde_data->res_data >> 0);
        }
+       return 0;
 }
 
-int nubus_proc_attach_device(struct nubus_dev *dev)
+static int nubus_proc_rsrc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, nubus_proc_rsrc_show, inode);
+}
+
+static const struct file_operations nubus_proc_rsrc_fops = {
+       .open           = nubus_proc_rsrc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+void nubus_proc_add_rsrc_mem(struct proc_dir_entry *procdir,
+                             const struct nubus_dirent *ent,
+                             unsigned int size)
 {
-       struct proc_dir_entry *e;
-       struct nubus_dir root;
        char name[9];
 
-       if (dev == NULL) {
-               printk(KERN_ERR
-                      "NULL pointer in nubus_proc_attach_device, shoot the 
programmer!\n");
-               return -1;
-       }
-               
-       if (dev->board == NULL) {
-               printk(KERN_ERR
-                      "NULL pointer in nubus_proc_attach_device, shoot the 
programmer!\n");
-               printk("dev = %p, dev->board = %p\n", dev, dev->board);
-               return -1;
-       }
-               
-       if (dev->board->procdir)
-               return 0;
+       if (!procdir)
+               return;
+
+       snprintf(name, sizeof(name), "%x", ent->type);
+       proc_create_data(name, S_IFREG | S_IRUGO, procdir,
+                        &nubus_proc_rsrc_fops,
+                        nubus_proc_alloc_pde_data(nubus_dirptr(ent), size, 0));
+}
 
-       /* Create a directory */
-       snprintf(name, sizeof(name), "%x", dev->board->slot);
-       e = proc_mkdir(name, proc_bus_nubus_dir);
-       dev->board->procdir = e;
-       if (!e)
-               return -ENOMEM;
+void nubus_proc_add_rsrc(struct proc_dir_entry *procdir,
+                         const struct nubus_dirent *ent)
+{
+       char name[9];
 
-       /* Now recursively populate it with files */
-       nubus_get_root_dir(dev->board, &root);
-       nubus_proc_populate(dev, e, &root);
+       if (!procdir)
+               return;
 
-       return 0;
+       snprintf(name, sizeof(name), "%x", ent->type);
+       proc_create_data(name, S_IFREG | S_IRUGO, procdir,
+                        &nubus_proc_rsrc_fops,
+                        nubus_proc_alloc_pde_data(NULL, 3, ent->data));
 }
-EXPORT_SYMBOL(nubus_proc_attach_device);
 
 /*
  * /proc/nubus stuff
@@ -219,18 +264,11 @@ static const struct file_operations nubus_proc_fops = {
        .release        = seq_release,
 };
 
-void __init proc_bus_nubus_add_devices(void)
-{
-       struct nubus_dev *dev;
-       
-       for(dev = nubus_devices; dev; dev = dev->next)
-               nubus_proc_attach_device(dev);
-}
-
 void __init nubus_proc_init(void)
 {
        proc_create("nubus", 0, NULL, &nubus_proc_fops);
        proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL);
+       if (!proc_bus_nubus_dir)
+               return;
        proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops);
-       proc_bus_nubus_add_devices();
 }
diff --git a/include/linux/nubus.h b/include/linux/nubus.h
index 84f2e0fa1898..0e40c9d6b977 100644
--- a/include/linux/nubus.h
+++ b/include/linux/nubus.h
@@ -13,11 +13,15 @@
 #include <asm/nubus.h>
 #include <uapi/linux/nubus.h>
 
+struct proc_dir_entry;
+struct seq_file;
+
 struct nubus_dir {
        unsigned char *base;
        unsigned char *ptr;
        int done;
        int mask;
+       struct proc_dir_entry *procdir;
 };
 
 struct nubus_dirent {
@@ -84,12 +88,33 @@ extern struct nubus_board *nubus_boards;
 
 /* Generic NuBus interface functions, modelled after the PCI interface */
 #ifdef CONFIG_PROC_FS
-extern void nubus_proc_init(void);
+void nubus_proc_init(void);
+struct proc_dir_entry *nubus_proc_add_board(struct nubus_board *board);
+struct proc_dir_entry *nubus_proc_add_rsrc_dir(struct proc_dir_entry *procdir,
+                                               const struct nubus_dirent *ent,
+                                               struct nubus_board *board);
+void nubus_proc_add_rsrc_mem(struct proc_dir_entry *procdir,
+                             const struct nubus_dirent *ent,
+                             unsigned int size);
+void nubus_proc_add_rsrc(struct proc_dir_entry *procdir,
+                         const struct nubus_dirent *ent);
 #else
 static inline void nubus_proc_init(void) {}
+static inline
+struct proc_dir_entry *nubus_proc_add_board(struct nubus_board *board)
+{ return NULL; }
+static inline
+struct proc_dir_entry *nubus_proc_add_rsrc_dir(struct proc_dir_entry *procdir,
+                                               const struct nubus_dirent *ent,
+                                               struct nubus_board *board)
+{ return NULL; }
+static inline void nubus_proc_add_rsrc_mem(struct proc_dir_entry *procdir,
+                                           const struct nubus_dirent *ent,
+                                           unsigned int size) {}
+static inline void nubus_proc_add_rsrc(struct proc_dir_entry *procdir,
+                                       const struct nubus_dirent *ent) {}
 #endif
 
-int nubus_proc_attach_device(struct nubus_dev *dev);
 /* If we need more precision we can add some more of these */
 struct nubus_dev *nubus_find_type(unsigned short category,
                                  unsigned short type,
@@ -125,8 +150,12 @@ int nubus_get_subdir(const struct nubus_dirent *ent,
                     struct nubus_dir *dir);
 void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
                         unsigned int len);
-void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
-                        unsigned int maxlen);
+unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
+                                unsigned int len);
+void nubus_seq_write_rsrc_mem(struct seq_file *m,
+                              const struct nubus_dirent *dirent,
+                              unsigned int len);
+unsigned char *nubus_dirptr(const struct nubus_dirent *nd);
 
 /* Returns a pointer to the "standard" slot space. */
 static inline void *nubus_slot_addr(int slot)
-- 
2.13.6

Reply via email to