diff options
author | Finn Thain <fthain@telegraphics.com.au> | 2018-01-13 17:37:13 -0500 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2018-01-16 16:47:29 +0100 |
commit | 2f7dd07ecadac6bdc3d55c217d65efa2834ba1cb (patch) | |
tree | bd55d141cdf80fc39cb3aedb87f0621c9c1a51a1 /drivers/nubus/proc.c | |
parent | 883b8cb31a8546b9921c98b255d5f7779d1bc9f6 (diff) | |
download | linux-2f7dd07ecadac6bdc3d55c217d65efa2834ba1cb.tar.gz linux-2f7dd07ecadac6bdc3d55c217d65efa2834ba1cb.tar.bz2 linux-2f7dd07ecadac6bdc3d55c217d65efa2834ba1cb.zip |
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.c | 222 |
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(); } |