1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* drivers/nubus/proc.c: Proc FS interface for NuBus. 31da177e4SLinus Torvalds 41da177e4SLinus Torvalds By David Huggins-Daines <dhd@debian.org> 51da177e4SLinus Torvalds 61da177e4SLinus Torvalds Much code and many ideas from drivers/pci/proc.c: 71da177e4SLinus Torvalds Copyright (c) 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz> 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds This is initially based on the Zorro and PCI interfaces. However, 101da177e4SLinus Torvalds it works somewhat differently. The intent is to provide a 111da177e4SLinus Torvalds structure in /proc analogous to the structure of the NuBus ROM 121da177e4SLinus Torvalds resources. 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds Therefore each NuBus device is in fact a directory, which may in 151da177e4SLinus Torvalds turn contain subdirectories. The "files" correspond to NuBus 161da177e4SLinus Torvalds resource records. For those types of records which we know how to 171da177e4SLinus Torvalds convert to formats that are meaningful to userspace (mostly just 181da177e4SLinus Torvalds icons) these files will provide "cooked" data. Otherwise they will 191da177e4SLinus Torvalds simply provide raw access (read-only of course) to the ROM. */ 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include <linux/types.h> 221da177e4SLinus Torvalds #include <linux/kernel.h> 231da177e4SLinus Torvalds #include <linux/nubus.h> 241da177e4SLinus Torvalds #include <linux/proc_fs.h> 25076ec04bSAlexey Dobriyan #include <linux/seq_file.h> 261da177e4SLinus Torvalds #include <linux/init.h> 2799ffab81SAdrian Bunk #include <linux/module.h> 2899ffab81SAdrian Bunk 297c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 301da177e4SLinus Torvalds #include <asm/byteorder.h> 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds static int 33076ec04bSAlexey Dobriyan nubus_devices_proc_show(struct seq_file *m, void *v) 341da177e4SLinus Torvalds { 351da177e4SLinus Torvalds struct nubus_dev *dev = nubus_devices; 361da177e4SLinus Torvalds 37076ec04bSAlexey Dobriyan while (dev) { 38076ec04bSAlexey Dobriyan seq_printf(m, "%x\t%04x %04x %04x %04x", 391da177e4SLinus Torvalds dev->board->slot, 401da177e4SLinus Torvalds dev->category, 411da177e4SLinus Torvalds dev->type, 421da177e4SLinus Torvalds dev->dr_sw, 431da177e4SLinus Torvalds dev->dr_hw); 44076ec04bSAlexey Dobriyan seq_printf(m, "\t%08lx\n", dev->board->slot_addr); 451da177e4SLinus Torvalds dev = dev->next; 461da177e4SLinus Torvalds } 47076ec04bSAlexey Dobriyan return 0; 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds 50076ec04bSAlexey Dobriyan static int nubus_devices_proc_open(struct inode *inode, struct file *file) 51076ec04bSAlexey Dobriyan { 52076ec04bSAlexey Dobriyan return single_open(file, nubus_devices_proc_show, NULL); 53076ec04bSAlexey Dobriyan } 54076ec04bSAlexey Dobriyan 55076ec04bSAlexey Dobriyan static const struct file_operations nubus_devices_proc_fops = { 56076ec04bSAlexey Dobriyan .open = nubus_devices_proc_open, 57076ec04bSAlexey Dobriyan .read = seq_read, 58076ec04bSAlexey Dobriyan .llseek = seq_lseek, 59076ec04bSAlexey Dobriyan .release = single_release, 60076ec04bSAlexey Dobriyan }; 61076ec04bSAlexey Dobriyan 621da177e4SLinus Torvalds static struct proc_dir_entry *proc_bus_nubus_dir; 631da177e4SLinus Torvalds 6411db656aSDavid Howells static const struct file_operations nubus_proc_subdir_fops = { 6511db656aSDavid Howells #warning Need to set some I/O handlers here 6611db656aSDavid Howells }; 6711db656aSDavid Howells 681da177e4SLinus Torvalds static void nubus_proc_subdir(struct nubus_dev* dev, 691da177e4SLinus Torvalds struct proc_dir_entry* parent, 701da177e4SLinus Torvalds struct nubus_dir* dir) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds struct nubus_dirent ent; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /* Some of these are directories, others aren't */ 751da177e4SLinus Torvalds while (nubus_readdir(dir, &ent) != -1) { 761da177e4SLinus Torvalds char name[8]; 771da177e4SLinus Torvalds struct proc_dir_entry* e; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds sprintf(name, "%x", ent.type); 8011db656aSDavid Howells e = proc_create(name, S_IFREG | S_IRUGO | S_IWUSR, parent, 8111db656aSDavid Howells &nubus_proc_subdir_fops); 8211db656aSDavid Howells if (!e) 8311db656aSDavid Howells return; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* Can't do this recursively since the root directory is structured 881da177e4SLinus Torvalds somewhat differently from the subdirectories */ 891da177e4SLinus Torvalds static void nubus_proc_populate(struct nubus_dev* dev, 901da177e4SLinus Torvalds struct proc_dir_entry* parent, 911da177e4SLinus Torvalds struct nubus_dir* root) 921da177e4SLinus Torvalds { 931da177e4SLinus Torvalds struct nubus_dirent ent; 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* We know these are all directories (board resource + one or 961da177e4SLinus Torvalds more functional resources) */ 971da177e4SLinus Torvalds while (nubus_readdir(root, &ent) != -1) { 981da177e4SLinus Torvalds char name[8]; 991da177e4SLinus Torvalds struct proc_dir_entry* e; 1001da177e4SLinus Torvalds struct nubus_dir dir; 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds sprintf(name, "%x", ent.type); 1031da177e4SLinus Torvalds e = proc_mkdir(name, parent); 1041da177e4SLinus Torvalds if (!e) return; 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /* And descend */ 1071da177e4SLinus Torvalds if (nubus_get_subdir(&ent, &dir) == -1) { 1081da177e4SLinus Torvalds /* This shouldn't happen */ 1091da177e4SLinus Torvalds printk(KERN_ERR "NuBus root directory node %x:%x has no subdir!\n", 1101da177e4SLinus Torvalds dev->board->slot, ent.type); 1111da177e4SLinus Torvalds continue; 1121da177e4SLinus Torvalds } else { 1131da177e4SLinus Torvalds nubus_proc_subdir(dev, e, &dir); 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds int nubus_proc_attach_device(struct nubus_dev *dev) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds struct proc_dir_entry *e; 1211da177e4SLinus Torvalds struct nubus_dir root; 1221da177e4SLinus Torvalds char name[8]; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds if (dev == NULL) { 1251da177e4SLinus Torvalds printk(KERN_ERR 1261da177e4SLinus Torvalds "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); 1271da177e4SLinus Torvalds return -1; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds if (dev->board == NULL) { 1311da177e4SLinus Torvalds printk(KERN_ERR 1321da177e4SLinus Torvalds "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); 1331da177e4SLinus Torvalds printk("dev = %p, dev->board = %p\n", dev, dev->board); 1341da177e4SLinus Torvalds return -1; 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds /* Create a directory */ 1381da177e4SLinus Torvalds sprintf(name, "%x", dev->board->slot); 1391da177e4SLinus Torvalds e = dev->procdir = proc_mkdir(name, proc_bus_nubus_dir); 1401da177e4SLinus Torvalds if (!e) 1411da177e4SLinus Torvalds return -ENOMEM; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds /* Now recursively populate it with files */ 1441da177e4SLinus Torvalds nubus_get_root_dir(dev->board, &root); 1451da177e4SLinus Torvalds nubus_proc_populate(dev, e, &root); 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds return 0; 1481da177e4SLinus Torvalds } 14999ffab81SAdrian Bunk EXPORT_SYMBOL(nubus_proc_attach_device); 1501da177e4SLinus Torvalds 15111db656aSDavid Howells /* 15211db656aSDavid Howells * /proc/nubus stuff 15311db656aSDavid Howells */ 15411db656aSDavid Howells static int nubus_proc_show(struct seq_file *m, void *v) 15511db656aSDavid Howells { 15611db656aSDavid Howells const struct nubus_board *board = v; 15711db656aSDavid Howells 15811db656aSDavid Howells /* Display header on line 1 */ 15911db656aSDavid Howells if (v == SEQ_START_TOKEN) 16011db656aSDavid Howells seq_puts(m, "Nubus devices found:\n"); 16111db656aSDavid Howells else 16211db656aSDavid Howells seq_printf(m, "Slot %X: %s\n", board->slot, board->name); 16311db656aSDavid Howells return 0; 16411db656aSDavid Howells } 16511db656aSDavid Howells 16611db656aSDavid Howells static void *nubus_proc_start(struct seq_file *m, loff_t *_pos) 16711db656aSDavid Howells { 16811db656aSDavid Howells struct nubus_board *board; 16911db656aSDavid Howells unsigned pos; 17011db656aSDavid Howells 17111db656aSDavid Howells if (*_pos > LONG_MAX) 17211db656aSDavid Howells return NULL; 17311db656aSDavid Howells pos = *_pos; 17411db656aSDavid Howells if (pos == 0) 17511db656aSDavid Howells return SEQ_START_TOKEN; 17611db656aSDavid Howells for (board = nubus_boards; board; board = board->next) 17711db656aSDavid Howells if (--pos == 0) 17811db656aSDavid Howells break; 17911db656aSDavid Howells return board; 18011db656aSDavid Howells } 18111db656aSDavid Howells 18211db656aSDavid Howells static void *nubus_proc_next(struct seq_file *p, void *v, loff_t *_pos) 18311db656aSDavid Howells { 18411db656aSDavid Howells /* Walk the list of NuBus boards */ 18511db656aSDavid Howells struct nubus_board *board = v; 18611db656aSDavid Howells 18711db656aSDavid Howells ++*_pos; 18811db656aSDavid Howells if (v == SEQ_START_TOKEN) 18911db656aSDavid Howells board = nubus_boards; 19011db656aSDavid Howells else if (board) 19111db656aSDavid Howells board = board->next; 19211db656aSDavid Howells return board; 19311db656aSDavid Howells } 19411db656aSDavid Howells 19511db656aSDavid Howells static void nubus_proc_stop(struct seq_file *p, void *v) 19611db656aSDavid Howells { 19711db656aSDavid Howells } 19811db656aSDavid Howells 19911db656aSDavid Howells static const struct seq_operations nubus_proc_seqops = { 20011db656aSDavid Howells .start = nubus_proc_start, 20111db656aSDavid Howells .next = nubus_proc_next, 20211db656aSDavid Howells .stop = nubus_proc_stop, 20311db656aSDavid Howells .show = nubus_proc_show, 20411db656aSDavid Howells }; 20511db656aSDavid Howells 20611db656aSDavid Howells static int nubus_proc_open(struct inode *inode, struct file *file) 20711db656aSDavid Howells { 20811db656aSDavid Howells return seq_open(file, &nubus_proc_seqops); 20911db656aSDavid Howells } 21011db656aSDavid Howells 21111db656aSDavid Howells static const struct file_operations nubus_proc_fops = { 21211db656aSDavid Howells .open = nubus_proc_open, 21311db656aSDavid Howells .read = seq_read, 21411db656aSDavid Howells .llseek = seq_lseek, 21511db656aSDavid Howells .release = seq_release, 21611db656aSDavid Howells }; 21711db656aSDavid Howells 2181da177e4SLinus Torvalds void __init proc_bus_nubus_add_devices(void) 2191da177e4SLinus Torvalds { 2201da177e4SLinus Torvalds struct nubus_dev *dev; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds for(dev = nubus_devices; dev; dev = dev->next) 2231da177e4SLinus Torvalds nubus_proc_attach_device(dev); 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds void __init nubus_proc_init(void) 2271da177e4SLinus Torvalds { 22811db656aSDavid Howells proc_create("nubus", 0, NULL, &nubus_proc_fops); 2291da177e4SLinus Torvalds if (!MACH_IS_MAC) 2301da177e4SLinus Torvalds return; 2319c37066dSAlexey Dobriyan proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); 232076ec04bSAlexey Dobriyan proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops); 2331da177e4SLinus Torvalds proc_bus_nubus_add_devices(); 2341da177e4SLinus Torvalds } 235