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