forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
4.6 KiB
186 lines
4.6 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* drivers/nubus/proc.c: Proc FS interface for NuBus. |
|
|
|
By David Huggins-Daines <[email protected]> |
|
|
|
Much code and many ideas from drivers/pci/proc.c: |
|
Copyright (c) 1997, 1998 Martin Mares <[email protected]> |
|
|
|
This is initially based on the Zorro and PCI interfaces. However, |
|
it works somewhat differently. The intent is to provide a |
|
structure in /proc analogous to the structure of the NuBus ROM |
|
resources. |
|
|
|
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) |
|
{ |
|
struct nubus_rsrc *fres; |
|
|
|
for_each_func_rsrc(fres) |
|
seq_printf(m, "%x\t%04x %04x %04x %04x\t%08lx\n", |
|
fres->board->slot, fres->category, fres->type, |
|
fres->dr_sw, fres->dr_hw, fres->board->slot_addr); |
|
return 0; |
|
} |
|
|
|
static struct proc_dir_entry *proc_bus_nubus_dir; |
|
|
|
/* |
|
* /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 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; |
|
} |
|
|
|
static int nubus_proc_rsrc_show(struct seq_file *m, void *v) |
|
{ |
|
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; |
|
} |
|
|
|
void nubus_proc_add_rsrc_mem(struct proc_dir_entry *procdir, |
|
const struct nubus_dirent *ent, |
|
unsigned int size) |
|
{ |
|
char name[9]; |
|
struct nubus_proc_pde_data *pde_data; |
|
|
|
if (!procdir) |
|
return; |
|
|
|
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_single_data(name, S_IFREG | 0444, procdir, |
|
nubus_proc_rsrc_show, pde_data); |
|
} |
|
|
|
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; |
|
|
|
if (!procdir) |
|
return; |
|
|
|
snprintf(name, sizeof(name), "%x", ent->type); |
|
proc_create_single_data(name, S_IFREG | 0444, procdir, |
|
nubus_proc_rsrc_show, |
|
nubus_proc_alloc_pde_data(data, 0)); |
|
} |
|
|
|
/* |
|
* /proc/nubus stuff |
|
*/ |
|
|
|
void __init nubus_proc_init(void) |
|
{ |
|
proc_create_single("nubus", 0, NULL, nubus_proc_show); |
|
proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); |
|
if (!proc_bus_nubus_dir) |
|
return; |
|
proc_create_single("devices", 0, proc_bus_nubus_dir, |
|
nubus_devices_proc_show); |
|
}
|
|
|