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> 24076ec04bSAlexey Dobriyan #include <linux/seq_file.h> 251da177e4SLinus Torvalds #include <linux/init.h> 2699ffab81SAdrian Bunk #include <linux/module.h> 2799ffab81SAdrian Bunk 287c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 291da177e4SLinus Torvalds #include <asm/byteorder.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds static int 32076ec04bSAlexey Dobriyan nubus_devices_proc_show(struct seq_file *m, void *v) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds struct nubus_dev *dev = nubus_devices; 351da177e4SLinus Torvalds 36076ec04bSAlexey Dobriyan while (dev) { 37076ec04bSAlexey Dobriyan seq_printf(m, "%x\t%04x %04x %04x %04x", 381da177e4SLinus Torvalds dev->board->slot, 391da177e4SLinus Torvalds dev->category, 401da177e4SLinus Torvalds dev->type, 411da177e4SLinus Torvalds dev->dr_sw, 421da177e4SLinus Torvalds dev->dr_hw); 43076ec04bSAlexey Dobriyan seq_printf(m, "\t%08lx\n", dev->board->slot_addr); 441da177e4SLinus Torvalds dev = dev->next; 451da177e4SLinus Torvalds } 46076ec04bSAlexey Dobriyan return 0; 471da177e4SLinus Torvalds } 481da177e4SLinus Torvalds 49076ec04bSAlexey Dobriyan static int nubus_devices_proc_open(struct inode *inode, struct file *file) 50076ec04bSAlexey Dobriyan { 51076ec04bSAlexey Dobriyan return single_open(file, nubus_devices_proc_show, NULL); 52076ec04bSAlexey Dobriyan } 53076ec04bSAlexey Dobriyan 54076ec04bSAlexey Dobriyan static const struct file_operations nubus_devices_proc_fops = { 55076ec04bSAlexey Dobriyan .open = nubus_devices_proc_open, 56076ec04bSAlexey Dobriyan .read = seq_read, 57076ec04bSAlexey Dobriyan .llseek = seq_lseek, 58076ec04bSAlexey Dobriyan .release = single_release, 59076ec04bSAlexey Dobriyan }; 60076ec04bSAlexey Dobriyan 611da177e4SLinus Torvalds static struct proc_dir_entry *proc_bus_nubus_dir; 621da177e4SLinus Torvalds 6311db656aSDavid Howells static const struct file_operations nubus_proc_subdir_fops = { 6411db656aSDavid Howells #warning Need to set some I/O handlers here 6511db656aSDavid Howells }; 6611db656aSDavid Howells 671da177e4SLinus Torvalds static void nubus_proc_subdir(struct nubus_dev* dev, 681da177e4SLinus Torvalds struct proc_dir_entry* parent, 691da177e4SLinus Torvalds struct nubus_dir* dir) 701da177e4SLinus Torvalds { 711da177e4SLinus Torvalds struct nubus_dirent ent; 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /* Some of these are directories, others aren't */ 741da177e4SLinus Torvalds while (nubus_readdir(dir, &ent) != -1) { 751da177e4SLinus Torvalds char name[8]; 761da177e4SLinus Torvalds struct proc_dir_entry* e; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds sprintf(name, "%x", ent.type); 7911db656aSDavid Howells e = proc_create(name, S_IFREG | S_IRUGO | S_IWUSR, parent, 8011db656aSDavid Howells &nubus_proc_subdir_fops); 8111db656aSDavid Howells if (!e) 8211db656aSDavid Howells return; 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* Can't do this recursively since the root directory is structured 871da177e4SLinus Torvalds somewhat differently from the subdirectories */ 881da177e4SLinus Torvalds static void nubus_proc_populate(struct nubus_dev* dev, 891da177e4SLinus Torvalds struct proc_dir_entry* parent, 901da177e4SLinus Torvalds struct nubus_dir* root) 911da177e4SLinus Torvalds { 921da177e4SLinus Torvalds struct nubus_dirent ent; 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds /* We know these are all directories (board resource + one or 951da177e4SLinus Torvalds more functional resources) */ 961da177e4SLinus Torvalds while (nubus_readdir(root, &ent) != -1) { 971da177e4SLinus Torvalds char name[8]; 981da177e4SLinus Torvalds struct proc_dir_entry* e; 991da177e4SLinus Torvalds struct nubus_dir dir; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds sprintf(name, "%x", ent.type); 1021da177e4SLinus Torvalds e = proc_mkdir(name, parent); 1031da177e4SLinus Torvalds if (!e) return; 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* And descend */ 1061da177e4SLinus Torvalds if (nubus_get_subdir(&ent, &dir) == -1) { 1071da177e4SLinus Torvalds /* This shouldn't happen */ 1081da177e4SLinus Torvalds printk(KERN_ERR "NuBus root directory node %x:%x has no subdir!\n", 1091da177e4SLinus Torvalds dev->board->slot, ent.type); 1101da177e4SLinus Torvalds continue; 1111da177e4SLinus Torvalds } else { 1121da177e4SLinus Torvalds nubus_proc_subdir(dev, e, &dir); 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds int nubus_proc_attach_device(struct nubus_dev *dev) 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds struct proc_dir_entry *e; 1201da177e4SLinus Torvalds struct nubus_dir root; 1211da177e4SLinus Torvalds char name[8]; 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds if (dev == NULL) { 1241da177e4SLinus Torvalds printk(KERN_ERR 1251da177e4SLinus Torvalds "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); 1261da177e4SLinus Torvalds return -1; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds if (dev->board == NULL) { 1301da177e4SLinus Torvalds printk(KERN_ERR 1311da177e4SLinus Torvalds "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); 1321da177e4SLinus Torvalds printk("dev = %p, dev->board = %p\n", dev, dev->board); 1331da177e4SLinus Torvalds return -1; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds /* Create a directory */ 1371da177e4SLinus Torvalds sprintf(name, "%x", dev->board->slot); 1381da177e4SLinus Torvalds e = dev->procdir = proc_mkdir(name, proc_bus_nubus_dir); 1391da177e4SLinus Torvalds if (!e) 1401da177e4SLinus Torvalds return -ENOMEM; 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds /* Now recursively populate it with files */ 1431da177e4SLinus Torvalds nubus_get_root_dir(dev->board, &root); 1441da177e4SLinus Torvalds nubus_proc_populate(dev, e, &root); 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds return 0; 1471da177e4SLinus Torvalds } 14899ffab81SAdrian Bunk EXPORT_SYMBOL(nubus_proc_attach_device); 1491da177e4SLinus Torvalds 15011db656aSDavid Howells /* 15111db656aSDavid Howells * /proc/nubus stuff 15211db656aSDavid Howells */ 15311db656aSDavid Howells static int nubus_proc_show(struct seq_file *m, void *v) 15411db656aSDavid Howells { 15511db656aSDavid Howells const struct nubus_board *board = v; 15611db656aSDavid Howells 15711db656aSDavid Howells /* Display header on line 1 */ 15811db656aSDavid Howells if (v == SEQ_START_TOKEN) 15911db656aSDavid Howells seq_puts(m, "Nubus devices found:\n"); 16011db656aSDavid Howells else 16111db656aSDavid Howells seq_printf(m, "Slot %X: %s\n", board->slot, board->name); 16211db656aSDavid Howells return 0; 16311db656aSDavid Howells } 16411db656aSDavid Howells 16511db656aSDavid Howells static void *nubus_proc_start(struct seq_file *m, loff_t *_pos) 16611db656aSDavid Howells { 16711db656aSDavid Howells struct nubus_board *board; 16811db656aSDavid Howells unsigned pos; 16911db656aSDavid Howells 17011db656aSDavid Howells if (*_pos > LONG_MAX) 17111db656aSDavid Howells return NULL; 17211db656aSDavid Howells pos = *_pos; 17311db656aSDavid Howells if (pos == 0) 17411db656aSDavid Howells return SEQ_START_TOKEN; 17511db656aSDavid Howells for (board = nubus_boards; board; board = board->next) 17611db656aSDavid Howells if (--pos == 0) 17711db656aSDavid Howells break; 17811db656aSDavid Howells return board; 17911db656aSDavid Howells } 18011db656aSDavid Howells 18111db656aSDavid Howells static void *nubus_proc_next(struct seq_file *p, void *v, loff_t *_pos) 18211db656aSDavid Howells { 18311db656aSDavid Howells /* Walk the list of NuBus boards */ 18411db656aSDavid Howells struct nubus_board *board = v; 18511db656aSDavid Howells 18611db656aSDavid Howells ++*_pos; 18711db656aSDavid Howells if (v == SEQ_START_TOKEN) 18811db656aSDavid Howells board = nubus_boards; 18911db656aSDavid Howells else if (board) 19011db656aSDavid Howells board = board->next; 19111db656aSDavid Howells return board; 19211db656aSDavid Howells } 19311db656aSDavid Howells 19411db656aSDavid Howells static void nubus_proc_stop(struct seq_file *p, void *v) 19511db656aSDavid Howells { 19611db656aSDavid Howells } 19711db656aSDavid Howells 19811db656aSDavid Howells static const struct seq_operations nubus_proc_seqops = { 19911db656aSDavid Howells .start = nubus_proc_start, 20011db656aSDavid Howells .next = nubus_proc_next, 20111db656aSDavid Howells .stop = nubus_proc_stop, 20211db656aSDavid Howells .show = nubus_proc_show, 20311db656aSDavid Howells }; 20411db656aSDavid Howells 20511db656aSDavid Howells static int nubus_proc_open(struct inode *inode, struct file *file) 20611db656aSDavid Howells { 20711db656aSDavid Howells return seq_open(file, &nubus_proc_seqops); 20811db656aSDavid Howells } 20911db656aSDavid Howells 21011db656aSDavid Howells static const struct file_operations nubus_proc_fops = { 21111db656aSDavid Howells .open = nubus_proc_open, 21211db656aSDavid Howells .read = seq_read, 21311db656aSDavid Howells .llseek = seq_lseek, 21411db656aSDavid Howells .release = seq_release, 21511db656aSDavid Howells }; 21611db656aSDavid Howells 2171da177e4SLinus Torvalds void __init proc_bus_nubus_add_devices(void) 2181da177e4SLinus Torvalds { 2191da177e4SLinus Torvalds struct nubus_dev *dev; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds for(dev = nubus_devices; dev; dev = dev->next) 2221da177e4SLinus Torvalds nubus_proc_attach_device(dev); 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds void __init nubus_proc_init(void) 2261da177e4SLinus Torvalds { 22711db656aSDavid Howells proc_create("nubus", 0, NULL, &nubus_proc_fops); 2281da177e4SLinus Torvalds if (!MACH_IS_MAC) 2291da177e4SLinus Torvalds return; 2309c37066dSAlexey Dobriyan proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); 231076ec04bSAlexey Dobriyan proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops); 2321da177e4SLinus Torvalds proc_bus_nubus_add_devices(); 2331da177e4SLinus Torvalds } 234