xref: /openbmc/linux/drivers/nubus/proc.c (revision 9c37066d)
11da177e4SLinus Torvalds /* drivers/nubus/proc.c: Proc FS interface for NuBus.
21da177e4SLinus Torvalds 
31da177e4SLinus Torvalds    By David Huggins-Daines <dhd@debian.org>
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds    Much code and many ideas from drivers/pci/proc.c:
61da177e4SLinus Torvalds    Copyright (c) 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds    This is initially based on the Zorro and PCI interfaces.  However,
91da177e4SLinus Torvalds    it works somewhat differently.  The intent is to provide a
101da177e4SLinus Torvalds    structure in /proc analogous to the structure of the NuBus ROM
111da177e4SLinus Torvalds    resources.
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds    Therefore each NuBus device is in fact a directory, which may in
141da177e4SLinus Torvalds    turn contain subdirectories.  The "files" correspond to NuBus
151da177e4SLinus Torvalds    resource records.  For those types of records which we know how to
161da177e4SLinus Torvalds    convert to formats that are meaningful to userspace (mostly just
171da177e4SLinus Torvalds    icons) these files will provide "cooked" data.  Otherwise they will
181da177e4SLinus Torvalds    simply provide raw access (read-only of course) to the ROM.  */
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <linux/types.h>
211da177e4SLinus Torvalds #include <linux/kernel.h>
221da177e4SLinus Torvalds #include <linux/nubus.h>
231da177e4SLinus Torvalds #include <linux/proc_fs.h>
241da177e4SLinus Torvalds #include <linux/init.h>
2599ffab81SAdrian Bunk #include <linux/module.h>
2699ffab81SAdrian Bunk 
271da177e4SLinus Torvalds #include <asm/uaccess.h>
281da177e4SLinus Torvalds #include <asm/byteorder.h>
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds static int
311da177e4SLinus Torvalds get_nubus_dev_info(char *buf, char **start, off_t pos, int count)
321da177e4SLinus Torvalds {
331da177e4SLinus Torvalds 	struct nubus_dev *dev = nubus_devices;
341da177e4SLinus Torvalds 	off_t at = 0;
351da177e4SLinus Torvalds 	int len, cnt;
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 	cnt = 0;
381da177e4SLinus Torvalds 	while (dev && count > cnt) {
391da177e4SLinus Torvalds 		len = sprintf(buf, "%x\t%04x %04x %04x %04x",
401da177e4SLinus Torvalds 			      dev->board->slot,
411da177e4SLinus Torvalds 			      dev->category,
421da177e4SLinus Torvalds 			      dev->type,
431da177e4SLinus Torvalds 			      dev->dr_sw,
441da177e4SLinus Torvalds 			      dev->dr_hw);
451da177e4SLinus Torvalds 		len += sprintf(buf+len,
461da177e4SLinus Torvalds 			       "\t%08lx",
471da177e4SLinus Torvalds 			       dev->board->slot_addr);
481da177e4SLinus Torvalds 		buf[len++] = '\n';
491da177e4SLinus Torvalds 		at += len;
501da177e4SLinus Torvalds 		if (at >= pos) {
511da177e4SLinus Torvalds 			if (!*start) {
521da177e4SLinus Torvalds 				*start = buf + (pos - (at - len));
531da177e4SLinus Torvalds 				cnt = at - pos;
541da177e4SLinus Torvalds 			} else
551da177e4SLinus Torvalds 				cnt += len;
561da177e4SLinus Torvalds 			buf += len;
571da177e4SLinus Torvalds 		}
581da177e4SLinus Torvalds 		dev = dev->next;
591da177e4SLinus Torvalds 	}
601da177e4SLinus Torvalds 	return (count > cnt) ? cnt : count;
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds static struct proc_dir_entry *proc_bus_nubus_dir;
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds static void nubus_proc_subdir(struct nubus_dev* dev,
661da177e4SLinus Torvalds 			      struct proc_dir_entry* parent,
671da177e4SLinus Torvalds 			      struct nubus_dir* dir)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds 	struct nubus_dirent ent;
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	/* Some of these are directories, others aren't */
721da177e4SLinus Torvalds 	while (nubus_readdir(dir, &ent) != -1) {
731da177e4SLinus Torvalds 		char name[8];
741da177e4SLinus Torvalds 		struct proc_dir_entry* e;
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 		sprintf(name, "%x", ent.type);
771da177e4SLinus Torvalds 		e = create_proc_entry(name, S_IFREG | S_IRUGO |
781da177e4SLinus Torvalds 				      S_IWUSR, parent);
791da177e4SLinus Torvalds 		if (!e) return;
801da177e4SLinus Torvalds 	}
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds /* Can't do this recursively since the root directory is structured
841da177e4SLinus Torvalds    somewhat differently from the subdirectories */
851da177e4SLinus Torvalds static void nubus_proc_populate(struct nubus_dev* dev,
861da177e4SLinus Torvalds 				struct proc_dir_entry* parent,
871da177e4SLinus Torvalds 				struct nubus_dir* root)
881da177e4SLinus Torvalds {
891da177e4SLinus Torvalds 	struct nubus_dirent ent;
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	/* We know these are all directories (board resource + one or
921da177e4SLinus Torvalds 	   more functional resources) */
931da177e4SLinus Torvalds 	while (nubus_readdir(root, &ent) != -1) {
941da177e4SLinus Torvalds 		char name[8];
951da177e4SLinus Torvalds 		struct proc_dir_entry* e;
961da177e4SLinus Torvalds 		struct nubus_dir dir;
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds 		sprintf(name, "%x", ent.type);
991da177e4SLinus Torvalds 		e = proc_mkdir(name, parent);
1001da177e4SLinus Torvalds 		if (!e) return;
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 		/* And descend */
1031da177e4SLinus Torvalds 		if (nubus_get_subdir(&ent, &dir) == -1) {
1041da177e4SLinus Torvalds 			/* This shouldn't happen */
1051da177e4SLinus Torvalds 			printk(KERN_ERR "NuBus root directory node %x:%x has no subdir!\n",
1061da177e4SLinus Torvalds 			       dev->board->slot, ent.type);
1071da177e4SLinus Torvalds 			continue;
1081da177e4SLinus Torvalds 		} else {
1091da177e4SLinus Torvalds 			nubus_proc_subdir(dev, e, &dir);
1101da177e4SLinus Torvalds 		}
1111da177e4SLinus Torvalds 	}
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds int nubus_proc_attach_device(struct nubus_dev *dev)
1151da177e4SLinus Torvalds {
1161da177e4SLinus Torvalds 	struct proc_dir_entry *e;
1171da177e4SLinus Torvalds 	struct nubus_dir root;
1181da177e4SLinus Torvalds 	char name[8];
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 	if (dev == NULL) {
1211da177e4SLinus Torvalds 		printk(KERN_ERR
1221da177e4SLinus Torvalds 		       "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n");
1231da177e4SLinus Torvalds 		return -1;
1241da177e4SLinus Torvalds 	}
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds 	if (dev->board == NULL) {
1271da177e4SLinus Torvalds 		printk(KERN_ERR
1281da177e4SLinus Torvalds 		       "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n");
1291da177e4SLinus Torvalds 		printk("dev = %p, dev->board = %p\n", dev, dev->board);
1301da177e4SLinus Torvalds 		return -1;
1311da177e4SLinus Torvalds 	}
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds 	/* Create a directory */
1341da177e4SLinus Torvalds 	sprintf(name, "%x", dev->board->slot);
1351da177e4SLinus Torvalds 	e = dev->procdir = proc_mkdir(name, proc_bus_nubus_dir);
1361da177e4SLinus Torvalds 	if (!e)
1371da177e4SLinus Torvalds 		return -ENOMEM;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	/* Now recursively populate it with files */
1401da177e4SLinus Torvalds 	nubus_get_root_dir(dev->board, &root);
1411da177e4SLinus Torvalds 	nubus_proc_populate(dev, e, &root);
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	return 0;
1441da177e4SLinus Torvalds }
14599ffab81SAdrian Bunk EXPORT_SYMBOL(nubus_proc_attach_device);
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds /* FIXME: this is certainly broken! */
1481da177e4SLinus Torvalds int nubus_proc_detach_device(struct nubus_dev *dev)
1491da177e4SLinus Torvalds {
1501da177e4SLinus Torvalds 	struct proc_dir_entry *e;
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 	if ((e = dev->procdir)) {
1531da177e4SLinus Torvalds 		if (atomic_read(&e->count))
1541da177e4SLinus Torvalds 			return -EBUSY;
1551da177e4SLinus Torvalds 		remove_proc_entry(e->name, proc_bus_nubus_dir);
1561da177e4SLinus Torvalds 		dev->procdir = NULL;
1571da177e4SLinus Torvalds 	}
1581da177e4SLinus Torvalds 	return 0;
1591da177e4SLinus Torvalds }
16099ffab81SAdrian Bunk EXPORT_SYMBOL(nubus_proc_detach_device);
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds void __init proc_bus_nubus_add_devices(void)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds 	struct nubus_dev *dev;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	for(dev = nubus_devices; dev; dev = dev->next)
1671da177e4SLinus Torvalds 		nubus_proc_attach_device(dev);
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds void __init nubus_proc_init(void)
1711da177e4SLinus Torvalds {
1721da177e4SLinus Torvalds 	if (!MACH_IS_MAC)
1731da177e4SLinus Torvalds 		return;
1749c37066dSAlexey Dobriyan 	proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL);
1751da177e4SLinus Torvalds 	create_proc_info_entry("devices", 0, proc_bus_nubus_dir,
1761da177e4SLinus Torvalds 				get_nubus_dev_info);
1771da177e4SLinus Torvalds 	proc_bus_nubus_add_devices();
1781da177e4SLinus Torvalds }
179