summary refs log tree commit diff
path: root/drivers/nubus/proc.c
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2018-01-13 17:37:13 -0500
committerGeert Uytterhoeven <geert@linux-m68k.org>2018-01-16 16:47:29 +0100
commit2f7dd07ecadac6bdc3d55c217d65efa2834ba1cb (patch)
treebd55d141cdf80fc39cb3aedb87f0621c9c1a51a1 /drivers/nubus/proc.c
parent883b8cb31a8546b9921c98b255d5f7779d1bc9f6 (diff)
downloadlinux-2f7dd07ecadac6bdc3d55c217d65efa2834ba1cb.tar.gz
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: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'drivers/nubus/proc.c')
-rw-r--r--drivers/nubus/proc.c222
1 files changed, 132 insertions, 90 deletions
diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c
index 41ec859bdd8b..f47d90924ab4 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,141 @@ 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 any directory under /proc/bus/nubus/x/
+ * is the bytelanes value for the board in 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];
+	int lanes = board->lanes;
+
+	if (!procdir)
+		return NULL;
+	snprintf(name, sizeof(name), "%x", ent->type);
+	return proc_mkdir_data(name, 0555, procdir, (void *)lanes);
+}
+
+/* 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 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)
 {
-	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;
+	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_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;
+
+		if (!lanes)
+			return 0;
+
+		ent.mask = lanes;
+		ent.base = pde_data->res_ptr;
+		ent.data = 0;
+		nubus_seq_write_rsrc_mem(m, &ent, pde_data->res_size);
+	} else {
+		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;
 }
 
-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];
+	struct nubus_proc_pde_data *pde_data;
 
-	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;
 
-	/* 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;
+	snprintf(name, sizeof(name), "%x", ent->type);
+	if (size)
+		pde_data = nubus_proc_alloc_pde_data(nubus_dirptr(ent), size);
+	else
+		pde_data = NULL;
+	proc_create_data(name, S_IFREG | 0444, procdir,
+			 &nubus_proc_rsrc_fops, pde_data);
+}
 
-	/* Now recursively populate it with files */
-	nubus_get_root_dir(dev->board, &root);
-	nubus_proc_populate(dev, e, &root);
+void nubus_proc_add_rsrc(struct proc_dir_entry *procdir,
+			 const struct nubus_dirent *ent)
+{
+	char name[9];
+	unsigned char *data = (unsigned char *)ent->data;
 
-	return 0;
+	if (!procdir)
+		return;
+
+	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
@@ -219,18 +268,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();
 }