1/* 2 * Copyright (c) 2012 Broadcom Corporation 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16#include <linux/debugfs.h> 17#include <linux/netdevice.h> 18#include <linux/module.h> 19 20#include <brcmu_wifi.h> 21#include <brcmu_utils.h> 22#include "core.h" 23#include "bus.h" 24#include "debug.h" 25 26static struct dentry *root_folder; 27 28void brcmf_debugfs_init(void) 29{ 30 root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL); 31 if (IS_ERR(root_folder)) 32 root_folder = NULL; 33} 34 35void brcmf_debugfs_exit(void) 36{ 37 if (!root_folder) 38 return; 39 40 debugfs_remove_recursive(root_folder); 41 root_folder = NULL; 42} 43 44static int brcmf_debugfs_chipinfo_read(struct seq_file *seq, void *data) 45{ 46 struct brcmf_bus *bus = dev_get_drvdata(seq->private); 47 48 seq_printf(seq, "chip: %x(%u) rev %u\n", 49 bus->chip, bus->chip, bus->chiprev); 50 return 0; 51} 52 53int brcmf_debugfs_attach(struct brcmf_pub *drvr) 54{ 55 struct device *dev = drvr->bus_if->dev; 56 57 if (!root_folder) 58 return -ENODEV; 59 60 drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); 61 brcmf_debugfs_add_entry(drvr, "chipinfo", brcmf_debugfs_chipinfo_read); 62 63 return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); 64} 65 66void brcmf_debugfs_detach(struct brcmf_pub *drvr) 67{ 68 if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) 69 debugfs_remove_recursive(drvr->dbgfs_dir); 70} 71 72struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr) 73{ 74 return drvr->dbgfs_dir; 75} 76 77struct brcmf_debugfs_entry { 78 int (*read)(struct seq_file *seq, void *data); 79 struct brcmf_pub *drvr; 80}; 81 82static int brcmf_debugfs_entry_open(struct inode *inode, struct file *f) 83{ 84 struct brcmf_debugfs_entry *entry = inode->i_private; 85 86 return single_open(f, entry->read, entry->drvr->bus_if->dev); 87} 88 89static const struct file_operations brcmf_debugfs_def_ops = { 90 .owner = THIS_MODULE, 91 .open = brcmf_debugfs_entry_open, 92 .release = single_release, 93 .read = seq_read, 94 .llseek = seq_lseek 95}; 96 97int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, 98 int (*read_fn)(struct seq_file *seq, void *data)) 99{ 100 struct dentry *dentry = drvr->dbgfs_dir; 101 struct brcmf_debugfs_entry *entry; 102 103 if (IS_ERR_OR_NULL(dentry)) 104 return -ENOENT; 105 106 entry = devm_kzalloc(drvr->bus_if->dev, sizeof(*entry), GFP_KERNEL); 107 if (!entry) 108 return -ENOMEM; 109 110 entry->read = read_fn; 111 entry->drvr = drvr; 112 113 dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry, 114 &brcmf_debugfs_def_ops); 115 116 return PTR_ERR_OR_ZERO(dentry); 117} 118