Commit 2f7dd07e authored by Finn Thain's avatar Finn Thain Committed by Geert Uytterhoeven
Browse files

nubus: Rework /proc/bus/nubus/s/ implementation



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: default avatarStan Johnson <userm57@yahoo.com>
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
parent 883b8cb3
Loading
Loading
Loading
Loading
+91 −23
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <asm/setup.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/page.h>
@@ -146,7 +147,7 @@ static inline void *nubus_rom_addr(int slot)
	return (void *)(0xF1000000 + (slot << 24));
	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;
	unsigned char *p = nd->base;


@@ -173,7 +174,7 @@ void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
}
}
EXPORT_SYMBOL(nubus_get_rsrc_mem);
EXPORT_SYMBOL(nubus_get_rsrc_mem);


void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
				unsigned int len)
				unsigned int len)
{
{
	char *t = dest;
	char *t = dest;
@@ -189,9 +190,33 @@ void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
	}
	}
	if (len > 0)
	if (len > 0)
		*t = '\0';
		*t = '\0';
	return t - dest;
}
}
EXPORT_SYMBOL(nubus_get_rsrc_str);
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,
int nubus_get_root_dir(const struct nubus_board *board,
		       struct nubus_dir *dir)
		       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
   looking at, and print out lots and lots of information from the
   resource blocks. */
   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,
static int __init nubus_get_block_rsrc_dir(struct nubus_board *board,
					   struct proc_dir_entry *procdir,
					   const struct nubus_dirent *parent)
					   const struct nubus_dirent *parent)
{
{
	struct nubus_dir dir;
	struct nubus_dir dir;
	struct nubus_dirent ent;
	struct nubus_dirent ent;


	nubus_get_subdir(parent, &dir);
	nubus_get_subdir(parent, &dir);
	dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);


	while (nubus_readdir(&dir, &ent) != -1) {
	while (nubus_readdir(&dir, &ent) != -1) {
		u32 size;
		u32 size;


		nubus_get_rsrc_mem(&size, &ent, 4);
		nubus_get_rsrc_mem(&size, &ent, 4);
		pr_debug("        block (0x%x), size %d\n", ent.type, size);
		pr_debug("        block (0x%x), size %d\n", ent.type, size);
		nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
	}
	}
	return 0;
	return 0;
}
}


static int __init nubus_get_display_vidmode(struct nubus_board *board,
static int __init nubus_get_display_vidmode(struct nubus_board *board,
					    struct proc_dir_entry *procdir,
					    const struct nubus_dirent *parent)
					    const struct nubus_dirent *parent)
{
{
	struct nubus_dir dir;
	struct nubus_dir dir;
	struct nubus_dirent ent;
	struct nubus_dirent ent;


	nubus_get_subdir(parent, &dir);
	nubus_get_subdir(parent, &dir);
	dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);


	while (nubus_readdir(&dir, &ent) != -1) {
	while (nubus_readdir(&dir, &ent) != -1) {
		switch (ent.type) {
		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);
			nubus_get_rsrc_mem(&size, &ent, 4);
			pr_debug("        block (0x%x), size %d\n", ent.type,
			pr_debug("        block (0x%x), size %d\n", ent.type,
				size);
				size);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, size);
			break;
			break;
		}
		}
		default:
		default:
			pr_debug("        unknown resource 0x%02x, data 0x%06x\n",
			pr_debug("        unknown resource 0x%02x, data 0x%06x\n",
				ent.type, ent.data);
				ent.type, ent.data);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
		}
		}
	}
	}
	return 0;
	return 0;
}
}


static int __init nubus_get_display_resource(struct nubus_dev *dev,
static int __init nubus_get_display_resource(struct nubus_dev *dev,
					     struct proc_dir_entry *procdir,
					     const struct nubus_dirent *ent)
					     const struct nubus_dirent *ent)
{
{
	switch (ent->type) {
	switch (ent->type) {
	case NUBUS_RESID_GAMMADIR:
	case NUBUS_RESID_GAMMADIR:
		pr_debug("    gamma directory offset: 0x%06x\n", ent->data);
		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;
		break;
	case 0x0080 ... 0x0085:
	case 0x0080 ... 0x0085:
		pr_debug("    mode 0x%02x info offset: 0x%06x\n",
		pr_debug("    mode 0x%02x info offset: 0x%06x\n",
			ent->type, ent->data);
			ent->type, ent->data);
		nubus_get_display_vidmode(dev->board, ent);
		nubus_get_display_vidmode(dev->board, procdir, ent);
		break;
		break;
	default:
	default:
		pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
		pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
			ent->type, ent->data);
			ent->type, ent->data);
		nubus_proc_add_rsrc_mem(procdir, ent, 0);
	}
	}
	return 0;
	return 0;
}
}


static int __init nubus_get_network_resource(struct nubus_dev *dev,
static int __init nubus_get_network_resource(struct nubus_dev *dev,
					     struct proc_dir_entry *procdir,
					     const struct nubus_dirent *ent)
					     const struct nubus_dirent *ent)
{
{
	switch (ent->type) {
	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);
		nubus_get_rsrc_mem(addr, ent, 6);
		pr_debug("    MAC address: %pM\n", addr);
		pr_debug("    MAC address: %pM\n", addr);
		nubus_proc_add_rsrc_mem(procdir, ent, 6);
		break;
		break;
	}
	}
	default:
	default:
		pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
		pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
			ent->type, ent->data);
			ent->type, ent->data);
		nubus_proc_add_rsrc_mem(procdir, ent, 0);
	}
	}
	return 0;
	return 0;
}
}


static int __init nubus_get_cpu_resource(struct nubus_dev *dev,
static int __init nubus_get_cpu_resource(struct nubus_dev *dev,
					 struct proc_dir_entry *procdir,
					 const struct nubus_dirent *ent)
					 const struct nubus_dirent *ent)
{
{
	switch (ent->type) {
	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);
		nubus_get_rsrc_mem(&meminfo, ent, 8);
		pr_debug("    memory: [ 0x%08lx 0x%08lx ]\n",
		pr_debug("    memory: [ 0x%08lx 0x%08lx ]\n",
			meminfo[0], meminfo[1]);
			meminfo[0], meminfo[1]);
		nubus_proc_add_rsrc_mem(procdir, ent, 8);
		break;
		break;
	}
	}
	case NUBUS_RESID_ROMINFO:
	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);
		nubus_get_rsrc_mem(&rominfo, ent, 8);
		pr_debug("    ROM:    [ 0x%08lx 0x%08lx ]\n",
		pr_debug("    ROM:    [ 0x%08lx 0x%08lx ]\n",
			rominfo[0], rominfo[1]);
			rominfo[0], rominfo[1]);
		nubus_proc_add_rsrc_mem(procdir, ent, 8);
		break;
		break;
	}
	}
	default:
	default:
		pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
		pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
			ent->type, ent->data);
			ent->type, ent->data);
		nubus_proc_add_rsrc_mem(procdir, ent, 0);
	}
	}
	return 0;
	return 0;
}
}


static int __init nubus_get_private_resource(struct nubus_dev *dev,
static int __init nubus_get_private_resource(struct nubus_dev *dev,
					     struct proc_dir_entry *procdir,
					     const struct nubus_dirent *ent)
					     const struct nubus_dirent *ent)
{
{
	switch (dev->category) {
	switch (dev->category) {
	case NUBUS_CAT_DISPLAY:
	case NUBUS_CAT_DISPLAY:
		nubus_get_display_resource(dev, ent);
		nubus_get_display_resource(dev, procdir, ent);
		break;
		break;
	case NUBUS_CAT_NETWORK:
	case NUBUS_CAT_NETWORK:
		nubus_get_network_resource(dev, ent);
		nubus_get_network_resource(dev, procdir, ent);
		break;
		break;
	case NUBUS_CAT_CPU:
	case NUBUS_CAT_CPU:
		nubus_get_cpu_resource(dev, ent);
		nubus_get_cpu_resource(dev, procdir, ent);
		break;
		break;
	default:
	default:
		pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
		pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
			ent->type, ent->data);
			ent->type, ent->data);
		nubus_proc_add_rsrc_mem(procdir, ent, 0);
	}
	}
	return 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);
	pr_debug("  Functional resource 0x%02x:\n", parent->type);
	nubus_get_subdir(parent, &dir);
	nubus_get_subdir(parent, &dir);
	dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);


	/* Actually we should probably panic if this fails */
	/* Actually we should probably panic if this fails */
	if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
	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];
			dev->dr_hw    = nbtdata[3];
			pr_debug("    type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
			pr_debug("    type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n",
				nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
				nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
			break;
			break;
		}
		}
		case NUBUS_RESID_NAME:
		case NUBUS_RESID_NAME:
		{
		{
			char name[64];
			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);
			pr_debug("    name: %s\n", name);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
			break;
			break;
		}
		}
		case NUBUS_RESID_DRVRDIR:
		case NUBUS_RESID_DRVRDIR:
@@ -511,7 +553,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot,
			   use this :-) */
			   use this :-) */
			pr_debug("    driver directory offset: 0x%06x\n",
			pr_debug("    driver directory offset: 0x%06x\n",
				ent.data);
				ent.data);
			nubus_get_block_rsrc_dir(board, &ent);
			nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
			break;
			break;
		}
		}
		case NUBUS_RESID_MINOR_BASEOS:
		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);
			nubus_get_rsrc_mem(&base_offset, &ent, 4);
			pr_debug("    memory offset: 0x%08x\n", base_offset);
			pr_debug("    memory offset: 0x%08x\n", base_offset);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
			break;
			break;
		}
		}
		case NUBUS_RESID_MINOR_LENGTH:
		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);
			nubus_get_rsrc_mem(&length, &ent, 4);
			pr_debug("    memory length: 0x%08x\n", length);
			pr_debug("    memory length: 0x%08x\n", length);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4);
			break;
			break;
		}
		}
		case NUBUS_RESID_FLAGS:
		case NUBUS_RESID_FLAGS:
			pr_debug("    flags: 0x%06x\n", ent.data);
			pr_debug("    flags: 0x%06x\n", ent.data);
			nubus_proc_add_rsrc(dir.procdir, &ent);
			break;
			break;
		case NUBUS_RESID_HWDEVID:
		case NUBUS_RESID_HWDEVID:
			pr_debug("    hwdevid: 0x%06x\n", ent.data);
			pr_debug("    hwdevid: 0x%06x\n", ent.data);
			nubus_proc_add_rsrc(dir.procdir, &ent);
			break;
			break;
		default:
		default:
			/* Local/Private resources have their own
			/* Local/Private resources have their own
			   function */
			   function */
			nubus_get_private_resource(dev, &ent);
			nubus_get_private_resource(dev, dir.procdir, &ent);
		}
		}
	}
	}


@@ -552,6 +598,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot,


/* This is *really* cool. */
/* This is *really* cool. */
static int __init nubus_get_icon(struct nubus_board *board,
static int __init nubus_get_icon(struct nubus_board *board,
				 struct proc_dir_entry *procdir,
				 const struct nubus_dirent *ent)
				 const struct nubus_dirent *ent)
{
{
	/* Should be 32x32 if my memory serves me correctly */
	/* Should be 32x32 if my memory serves me correctly */
@@ -564,11 +611,13 @@ static int __init nubus_get_icon(struct nubus_board *board,
		pr_debug("        %08x %08x %08x %08x\n",
		pr_debug("        %08x %08x %08x %08x\n",
			icon[i * 4 + 0], icon[i * 4 + 1],
			icon[i * 4 + 0], icon[i * 4 + 1],
			icon[i * 4 + 2], icon[i * 4 + 3]);
			icon[i * 4 + 2], icon[i * 4 + 3]);
	nubus_proc_add_rsrc_mem(procdir, ent, 128);


	return 0;
	return 0;
}
}


static int __init nubus_get_vendorinfo(struct nubus_board *board,
static int __init nubus_get_vendorinfo(struct nubus_board *board,
				       struct proc_dir_entry *procdir,
				       const struct nubus_dirent *parent)
				       const struct nubus_dirent *parent)
{
{
	struct nubus_dir dir;
	struct nubus_dir dir;
@@ -578,15 +627,18 @@ static int __init nubus_get_vendorinfo(struct nubus_board *board,


	pr_debug("    vendor info:\n");
	pr_debug("    vendor info:\n");
	nubus_get_subdir(parent, &dir);
	nubus_get_subdir(parent, &dir);
	dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board);


	while (nubus_readdir(&dir, &ent) != -1) {
	while (nubus_readdir(&dir, &ent) != -1) {
		char name[64];
		char name[64];
		unsigned int len;


		/* These are all strings, we think */
		/* 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)
		if (ent.type < 1 || ent.type > 5)
			ent.type = 5;
			ent.type = 5;
		pr_debug("    %s: %s\n", vendor_fields[ent.type - 1], name);
		pr_debug("    %s: %s\n", vendor_fields[ent.type - 1], name);
		nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
	}
	}
	return 0;
	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);
	pr_debug("  Board resource 0x%02x:\n", parent->type);
	nubus_get_subdir(parent, &dir);
	nubus_get_subdir(parent, &dir);
	dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board);


	while (nubus_readdir(&dir, &ent) != -1) {
	while (nubus_readdir(&dir, &ent) != -1) {
		switch (ent.type) {
		switch (ent.type) {
@@ -615,49 +668,62 @@ static int __init nubus_get_board_resource(struct nubus_board *board, int slot,
			    nbtdata[2] != 0 || nbtdata[3] != 0)
			    nbtdata[2] != 0 || nbtdata[3] != 0)
				pr_err("Slot %X: sResource is not a board resource!\n",
				pr_err("Slot %X: sResource is not a board resource!\n",
				       slot);
				       slot);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8);
			break;
			break;
		}
		}
		case NUBUS_RESID_NAME:
		case NUBUS_RESID_NAME:
			nubus_get_rsrc_str(board->name, &ent,
		{
			unsigned int len;

			len = nubus_get_rsrc_str(board->name, &ent,
						 sizeof(board->name));
						 sizeof(board->name));
			pr_debug("    name: %s\n", board->name);
			pr_debug("    name: %s\n", board->name);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1);
			break;
			break;
		}
		case NUBUS_RESID_ICON:
		case NUBUS_RESID_ICON:
			nubus_get_icon(board, &ent);
			nubus_get_icon(board, dir.procdir, &ent);
			break;
			break;
		case NUBUS_RESID_BOARDID:
		case NUBUS_RESID_BOARDID:
			pr_debug("    board id: 0x%x\n", ent.data);
			pr_debug("    board id: 0x%x\n", ent.data);
			nubus_proc_add_rsrc(dir.procdir, &ent);
			break;
			break;
		case NUBUS_RESID_PRIMARYINIT:
		case NUBUS_RESID_PRIMARYINIT:
			pr_debug("    primary init offset: 0x%06x\n", ent.data);
			pr_debug("    primary init offset: 0x%06x\n", ent.data);
			nubus_proc_add_rsrc(dir.procdir, &ent);
			break;
			break;
		case NUBUS_RESID_VENDORINFO:
		case NUBUS_RESID_VENDORINFO:
			nubus_get_vendorinfo(board, &ent);
			nubus_get_vendorinfo(board, dir.procdir, &ent);
			break;
			break;
		case NUBUS_RESID_FLAGS:
		case NUBUS_RESID_FLAGS:
			pr_debug("    flags: 0x%06x\n", ent.data);
			pr_debug("    flags: 0x%06x\n", ent.data);
			nubus_proc_add_rsrc(dir.procdir, &ent);
			break;
			break;
		case NUBUS_RESID_HWDEVID:
		case NUBUS_RESID_HWDEVID:
			pr_debug("    hwdevid: 0x%06x\n", ent.data);
			pr_debug("    hwdevid: 0x%06x\n", ent.data);
			nubus_proc_add_rsrc(dir.procdir, &ent);
			break;
			break;
		case NUBUS_RESID_SECONDINIT:
		case NUBUS_RESID_SECONDINIT:
			pr_debug("    secondary init offset: 0x%06x\n",
			pr_debug("    secondary init offset: 0x%06x\n",
				 ent.data);
				 ent.data);
			nubus_proc_add_rsrc(dir.procdir, &ent);
			break;
			break;
			/* WTF isn't this in the functional resources? */
			/* WTF isn't this in the functional resources? */
		case NUBUS_RESID_VIDNAMES:
		case NUBUS_RESID_VIDNAMES:
			pr_debug("    vidnames directory offset: 0x%06x\n",
			pr_debug("    vidnames directory offset: 0x%06x\n",
				ent.data);
				ent.data);
			nubus_get_block_rsrc_dir(board, &ent);
			nubus_get_block_rsrc_dir(board, dir.procdir, &ent);
			break;
			break;
			/* Same goes for this */
			/* Same goes for this */
		case NUBUS_RESID_VIDMODES:
		case NUBUS_RESID_VIDMODES:
			pr_debug("    video mode parameter directory offset: 0x%06x\n",
			pr_debug("    video mode parameter directory offset: 0x%06x\n",
				ent.data);
				ent.data);
			nubus_proc_add_rsrc(dir.procdir, &ent);
			break;
			break;
		default:
		default:
			pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
			pr_debug("    unknown resource 0x%02x, data 0x%06x\n",
				ent.type, ent.data);
				ent.type, ent.data);
			nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0);
		}
		}
	}
	}
	return 0;
	return 0;
@@ -748,6 +814,8 @@ static struct nubus_board * __init nubus_add_board(int slot, int bytelanes)
	if (ent.type < 1 || ent.type > 127)
	if (ent.type < 1 || ent.type > 127)
		pr_warn("Slot %X: Board resource ID is invalid!\n", slot);
		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);
	nubus_get_board_resource(board, slot, &ent);


	while (nubus_readdir(&dir, &ent) != -1) {
	while (nubus_readdir(&dir, &ent) != -1) {
@@ -835,8 +903,8 @@ static int __init nubus_init(void)
	if (!MACH_IS_MAC)
	if (!MACH_IS_MAC)
		return 0;
		return 0;


	nubus_scan_bus();
	nubus_proc_init();
	nubus_proc_init();
	nubus_scan_bus();
	return 0;
	return 0;
}
}


+132 −90
Original line number Original line Diff line number Diff line
@@ -11,24 +11,28 @@
   structure in /proc analogous to the structure of the NuBus ROM
   structure in /proc analogous to the structure of the NuBus ROM
   resources.
   resources.


   Therefore each NuBus device is in fact a directory, which may in
   Therefore each board function gets a directory, which may in turn
   turn contain subdirectories.  The "files" correspond to NuBus
   contain subdirectories.  Each slot resource is a file.  Unrecognized
   resource records.  For those types of records which we know how to
   resources are empty files, since every resource ID requires a special
   convert to formats that are meaningful to userspace (mostly just
   case (e.g. if the resource ID implies a directory or block, then its
   icons) these files will provide "cooked" data.  Otherwise they will
   value has to be interpreted as a slot ROM pointer etc.).
   simply provide raw access (read-only of course) to the ROM.  */
 */


#include <linux/types.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/nubus.h>
#include <linux/nubus.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>

#include <linux/uaccess.h>
#include <linux/uaccess.h>
#include <asm/byteorder.h>
#include <asm/byteorder.h>


/*
 * /proc/bus/nubus/devices stuff
 */

static int
static int
nubus_devices_proc_show(struct seq_file *m, void *v)
nubus_devices_proc_show(struct seq_file *m, void *v)
{
{
@@ -61,96 +65,141 @@ static const struct file_operations nubus_devices_proc_fops = {


static struct proc_dir_entry *proc_bus_nubus_dir;
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
};
 */


static void nubus_proc_subdir(struct nubus_dev* dev,
struct proc_dir_entry *nubus_proc_add_board(struct nubus_board *board)
			      struct proc_dir_entry* parent,
			      struct nubus_dir* dir)
{
{
	struct nubus_dirent ent;
	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 any directory under /proc/bus/nubus/x/
 * is the bytelanes value for the board in slot x.
 */


	/* Some of these are directories, others aren't */
struct proc_dir_entry *nubus_proc_add_rsrc_dir(struct proc_dir_entry *procdir,
	while (nubus_readdir(dir, &ent) != -1) {
					       const struct nubus_dirent *ent,
					       struct nubus_board *board)
{
	char name[9];
	char name[9];
		struct proc_dir_entry* e;
	int lanes = board->lanes;


		snprintf(name, sizeof(name), "%x", ent.type);
	if (!procdir)
		e = proc_create(name, S_IFREG | S_IRUGO | S_IWUSR, parent,
		return NULL;
				&nubus_proc_subdir_fops);
	snprintf(name, sizeof(name), "%x", ent->type);
		if (!e)
	return proc_mkdir_data(name, 0555, procdir, (void *)lanes);
			return;
}
}

/* 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, this integer value is stored directly and size is set to 0.
 * A NULL private data pointer indicates an unrecognized resource.
 */

struct nubus_proc_pde_data {
	unsigned char *res_ptr;
	unsigned int res_size;
};

static struct nubus_proc_pde_data *
nubus_proc_alloc_pde_data(unsigned char *ptr, unsigned int size)
{
	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;
	return pde_data;
}
}


/* Can't do this recursively since the root directory is structured
static int nubus_proc_rsrc_show(struct seq_file *m, void *v)
   somewhat differently from the subdirectories */
static void nubus_proc_populate(struct nubus_dev* dev,
				struct proc_dir_entry* parent,
				struct nubus_dir* root)
{
{
	struct inode *inode = m->private;
	struct nubus_proc_pde_data *pde_data;

	pde_data = PDE_DATA(inode);
	if (!pde_data)
		return 0;

	if (pde_data->res_size > m->size)
		return -EFBIG;

	if (pde_data->res_size) {
		int lanes = (int)proc_get_parent_data(inode);
		struct nubus_dirent ent;
		struct nubus_dirent ent;


	/* We know these are all directories (board resource + one or
		if (!lanes)
	   more functional resources) */
			return 0;
	while (nubus_readdir(root, &ent) != -1) {

		char name[9];
		ent.mask = lanes;
		struct proc_dir_entry* e;
		ent.base = pde_data->res_ptr;
		struct nubus_dir dir;
		ent.data = 0;
		
		nubus_seq_write_rsrc_mem(m, &ent, pde_data->res_size);
		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 {
	} else {
			nubus_proc_subdir(dev, e, &dir);
		unsigned int data = (unsigned int)pde_data->res_ptr;

		seq_putc(m, data >> 16);
		seq_putc(m, data >> 8);
		seq_putc(m, data >> 0);
	}
	}
	return 0;
}
}

static int nubus_proc_rsrc_open(struct inode *inode, struct file *file)
{
	return single_open(file, nubus_proc_rsrc_show, inode);
}
}


int nubus_proc_attach_device(struct nubus_dev *dev)
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];
	char name[9];
	struct nubus_proc_pde_data *pde_data;


	if (dev == NULL) {
	if (!procdir)
		printk(KERN_ERR
		return;
		       "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n");
		return -1;
	}


	if (dev->board == NULL) {
	snprintf(name, sizeof(name), "%x", ent->type);
		printk(KERN_ERR
	if (size)
		       "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n");
		pde_data = nubus_proc_alloc_pde_data(nubus_dirptr(ent), size);
		printk("dev = %p, dev->board = %p\n", dev, dev->board);
	else
		return -1;
		pde_data = NULL;
	proc_create_data(name, S_IFREG | 0444, procdir,
			 &nubus_proc_rsrc_fops, pde_data);
}
}


	if (dev->board->procdir)
void nubus_proc_add_rsrc(struct proc_dir_entry *procdir,
		return 0;
			 const struct nubus_dirent *ent)

{
	/* Create a directory */
	char name[9];
	snprintf(name, sizeof(name), "%x", dev->board->slot);
	unsigned char *data = (unsigned char *)ent->data;
	e = proc_mkdir(name, proc_bus_nubus_dir);
	dev->board->procdir = e;
	if (!e)
		return -ENOMEM;


	/* Now recursively populate it with files */
	if (!procdir)
	nubus_get_root_dir(dev->board, &root);
		return;
	nubus_proc_populate(dev, e, &root);


	return 0;
	snprintf(name, sizeof(name), "%x", ent->type);
	proc_create_data(name, S_IFREG | 0444, procdir,
			 &nubus_proc_rsrc_fops,
			 nubus_proc_alloc_pde_data(data, 0));
}
}
EXPORT_SYMBOL(nubus_proc_attach_device);


/*
/*
 * /proc/nubus stuff
 * /proc/nubus stuff
@@ -219,18 +268,11 @@ static const struct file_operations nubus_proc_fops = {
	.release	= seq_release,
	.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)
void __init nubus_proc_init(void)
{
{
	proc_create("nubus", 0, NULL, &nubus_proc_fops);
	proc_create("nubus", 0, NULL, &nubus_proc_fops);
	proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL);
	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_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops);
	proc_bus_nubus_add_devices();
}
}
+33 −4
Original line number Original line Diff line number Diff line
@@ -13,11 +13,15 @@
#include <asm/nubus.h>
#include <asm/nubus.h>
#include <uapi/linux/nubus.h>
#include <uapi/linux/nubus.h>


struct proc_dir_entry;
struct seq_file;

struct nubus_dir {
struct nubus_dir {
	unsigned char *base;
	unsigned char *base;
	unsigned char *ptr;
	unsigned char *ptr;
	int done;
	int done;
	int mask;
	int mask;
	struct proc_dir_entry *procdir;
};
};


struct nubus_dirent {
struct nubus_dirent {
@@ -84,12 +88,33 @@ extern struct nubus_board *nubus_boards;


/* Generic NuBus interface functions, modelled after the PCI interface */
/* Generic NuBus interface functions, modelled after the PCI interface */
#ifdef CONFIG_PROC_FS
#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
#else
static inline void nubus_proc_init(void) {}
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
#endif


int nubus_proc_attach_device(struct nubus_dev *dev);
/* If we need more precision we can add some more of these */
/* If we need more precision we can add some more of these */
struct nubus_dev *nubus_find_type(unsigned short category,
struct nubus_dev *nubus_find_type(unsigned short category,
				  unsigned short type,
				  unsigned short type,
@@ -125,8 +150,12 @@ int nubus_get_subdir(const struct nubus_dirent *ent,
		     struct nubus_dir *dir);
		     struct nubus_dir *dir);
void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent,
			unsigned int len);
			unsigned int len);
void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent,
			unsigned int maxlen);
				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. */
/* Returns a pointer to the "standard" slot space. */
static inline void *nubus_slot_addr(int slot)
static inline void *nubus_slot_addr(int slot)