11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drivers/nubus/proc.c: Proc FS interface for NuBus.
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   By David Huggins-Daines <dhd@debian.org>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Much code and many ideas from drivers/pci/proc.c:
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Copyright (c) 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This is initially based on the Zorro and PCI interfaces.  However,
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it works somewhat differently.  The intent is to provide a
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   structure in /proc analogous to the structure of the NuBus ROM
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   resources.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Therefore each NuBus device is in fact a directory, which may in
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   turn contain subdirectories.  The "files" correspond to NuBus
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   resource records.  For those types of records which we know how to
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   convert to formats that are meaningful to userspace (mostly just
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   icons) these files will provide "cooked" data.  Otherwise they will
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   simply provide raw access (read-only of course) to the ROM.  */
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/nubus.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
24076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan#include <linux/seq_file.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
2699ffab81071b7088ddebd4be9bbf1ad03c2a9e98Adrian Bunk#include <linux/module.h>
2799ffab81071b7088ddebd4be9bbf1ad03c2a9e98Adrian Bunk
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
32076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyannubus_devices_proc_show(struct seq_file *m, void *v)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nubus_dev *dev = nubus_devices;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
36076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	while (dev) {
37076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan		seq_printf(m, "%x\t%04x %04x %04x %04x",
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      dev->board->slot,
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      dev->category,
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      dev->type,
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      dev->dr_sw,
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      dev->dr_hw);
43076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan		seq_printf(m, "\t%08lx\n", dev->board->slot_addr);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev = dev->next;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
46076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	return 0;
47076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan}
48076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan
49076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyanstatic int nubus_devices_proc_open(struct inode *inode, struct file *file)
50076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan{
51076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	return single_open(file, nubus_devices_proc_show, NULL);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyanstatic const struct file_operations nubus_devices_proc_fops = {
55076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	.owner		= THIS_MODULE,
56076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	.open		= nubus_devices_proc_open,
57076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	.read		= seq_read,
58076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	.llseek		= seq_lseek,
59076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	.release	= single_release,
60076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan};
61076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct proc_dir_entry *proc_bus_nubus_dir;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nubus_proc_subdir(struct nubus_dev* dev,
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct proc_dir_entry* parent,
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      struct nubus_dir* dir)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nubus_dirent ent;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Some of these are directories, others aren't */
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (nubus_readdir(dir, &ent) != -1) {
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char name[8];
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct proc_dir_entry* e;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(name, "%x", ent.type);
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		e = create_proc_entry(name, S_IFREG | S_IRUGO |
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      S_IWUSR, parent);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!e) return;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Can't do this recursively since the root directory is structured
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   somewhat differently from the subdirectories */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void nubus_proc_populate(struct nubus_dev* dev,
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct proc_dir_entry* parent,
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				struct nubus_dir* root)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nubus_dirent ent;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We know these are all directories (board resource + one or
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   more functional resources) */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (nubus_readdir(root, &ent) != -1) {
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		char name[8];
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct proc_dir_entry* e;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct nubus_dir dir;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(name, "%x", ent.type);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		e = proc_mkdir(name, parent);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!e) return;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* And descend */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (nubus_get_subdir(&ent, &dir) == -1) {
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* This shouldn't happen */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "NuBus root directory node %x:%x has no subdir!\n",
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       dev->board->slot, ent.type);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			nubus_proc_subdir(dev, e, &dir);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint nubus_proc_attach_device(struct nubus_dev *dev)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct proc_dir_entry *e;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nubus_dir root;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char name[8];
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev == NULL) {
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n");
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->board == NULL) {
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n");
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("dev = %p, dev->board = %p\n", dev, dev->board);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Create a directory */
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sprintf(name, "%x", dev->board->slot);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	e = dev->procdir = proc_mkdir(name, proc_bus_nubus_dir);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!e)
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now recursively populate it with files */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nubus_get_root_dir(dev->board, &root);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nubus_proc_populate(dev, e, &root);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
14499ffab81071b7088ddebd4be9bbf1ad03c2a9e98Adrian BunkEXPORT_SYMBOL(nubus_proc_attach_device);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* FIXME: this is certainly broken! */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint nubus_proc_detach_device(struct nubus_dev *dev)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct proc_dir_entry *e;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((e = dev->procdir)) {
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (atomic_read(&e->count))
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EBUSY;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		remove_proc_entry(e->name, proc_bus_nubus_dir);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->procdir = NULL;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
15999ffab81071b7088ddebd4be9bbf1ad03c2a9e98Adrian BunkEXPORT_SYMBOL(nubus_proc_detach_device);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init proc_bus_nubus_add_devices(void)
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct nubus_dev *dev;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(dev = nubus_devices; dev; dev = dev->next)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		nubus_proc_attach_device(dev);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init nubus_proc_init(void)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!MACH_IS_MAC)
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1739c37066d888bf6e1b96ad12304971b3ddeabbad0Alexey Dobriyan	proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL);
174076ec04b8ac84a04df67840f15f36218d7519510Alexey Dobriyan	proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	proc_bus_nubus_add_devices();
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
177