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