📄 bcm43xx_debugfs.c
字号:
/* Broadcom BCM43xx wireless driver debugfs driver debugging code Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.*/#include <linux/fs.h>#include <linux/debugfs.h>#include <linux/slab.h>#include <linux/netdevice.h>#include <linux/pci.h>#include <asm/io.h>#include "bcm43xx.h"#include "bcm43xx_main.h"#include "bcm43xx_debugfs.h"#include "bcm43xx_dma.h"#include "bcm43xx_pio.h"#include "bcm43xx_xmit.h"#define REALLY_BIG_BUFFER_SIZE (1024*256)static struct bcm43xx_debugfs fs;static char really_big_buffer[REALLY_BIG_BUFFER_SIZE];static DECLARE_MUTEX(big_buffer_sem);static ssize_t write_file_dummy(struct file *file, const char __user *buf, size_t count, loff_t *ppos){ return count;}static int open_file_generic(struct inode *inode, struct file *file){ file->private_data = inode->i_private; return 0;}#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x)static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, size_t count, loff_t *ppos){ const size_t len = REALLY_BIG_BUFFER_SIZE; struct bcm43xx_private *bcm = file->private_data; char *buf = really_big_buffer; size_t pos = 0; ssize_t res; struct net_device *net_dev; struct pci_dev *pci_dev; unsigned long flags; u16 tmp16; int i; down(&big_buffer_sem); mutex_lock(&bcm->mutex); spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { fappend("Board not initialized.\n"); goto out; } net_dev = bcm->net_dev; pci_dev = bcm->pci_dev; /* This is where the information is written to the "devinfo" file */ fappend("*** %s devinfo ***\n", net_dev->name); fappend("vendor: 0x%04x device: 0x%04x\n", pci_dev->vendor, pci_dev->device); fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n", pci_dev->subsystem_vendor, pci_dev->subsystem_device); fappend("IRQ: %d\n", bcm->irq); fappend("mmio_addr: 0x%p\n", bcm->mmio_addr); fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev); if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16))) fappend("Radio disabled by hardware!\n"); if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4))) fappend("Radio disabled by hardware!\n"); fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor, bcm->board_type); fappend("\nCores:\n");#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \ "rev: 0x%02x, index: 0x%02x\n", \ (info).available \ ? "available" : "nonavailable", \ (info).enabled \ ? "enabled" : "disabled", \ (info).id, (info).rev, (info).index) fappend_core("CHIPCOMMON", bcm->core_chipcommon); fappend_core("PCI", bcm->core_pci); fappend_core("first 80211", bcm->core_80211[0]); fappend_core("second 80211", bcm->core_80211[1]);#undef fappend_core tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); fappend("LEDs: "); for (i = 0; i < BCM43xx_NR_LEDS; i++) fappend("%d ", !!(tmp16 & (1 << i))); fappend("\n");out: spin_unlock_irqrestore(&bcm->irq_lock, flags); mutex_unlock(&bcm->mutex); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res;}static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf, size_t count, loff_t *ppos){ const size_t len = REALLY_BIG_BUFFER_SIZE; char *buf = really_big_buffer; size_t pos = 0; ssize_t res; down(&big_buffer_sem); /* This is where the information is written to the "driver" file */ fappend(KBUILD_MODNAME " driver\n"); fappend("Compiled at: %s %s\n", __DATE__, __TIME__); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res;}static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, size_t count, loff_t *ppos){ const size_t len = REALLY_BIG_BUFFER_SIZE; struct bcm43xx_private *bcm = file->private_data; char *buf = really_big_buffer; size_t pos = 0; ssize_t res; unsigned long flags; down(&big_buffer_sem); mutex_lock(&bcm->mutex); spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { fappend("Board not initialized.\n"); goto out; } /* This is where the information is written to the "sprom_dump" file */ fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);out: spin_unlock_irqrestore(&bcm->irq_lock, flags); mutex_unlock(&bcm->mutex); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res;}static ssize_t tsf_read_file(struct file *file, char __user *userbuf, size_t count, loff_t *ppos){ const size_t len = REALLY_BIG_BUFFER_SIZE; struct bcm43xx_private *bcm = file->private_data; char *buf = really_big_buffer; size_t pos = 0; ssize_t res; unsigned long flags; u64 tsf; down(&big_buffer_sem); mutex_lock(&bcm->mutex); spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { fappend("Board not initialized.\n"); goto out; } bcm43xx_tsf_read(bcm, &tsf); fappend("0x%08x%08x\n", (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), (unsigned int)(tsf & 0xFFFFFFFFULL));out: spin_unlock_irqrestore(&bcm->irq_lock, flags); mutex_unlock(&bcm->mutex); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res;}static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos){ struct bcm43xx_private *bcm = file->private_data; char *buf = really_big_buffer; ssize_t buf_size; ssize_t res; unsigned long flags; u64 tsf; buf_size = min(count, sizeof (really_big_buffer) - 1); down(&big_buffer_sem); if (copy_from_user(buf, user_buf, buf_size)) { res = -EFAULT; goto out_up; } mutex_lock(&bcm->mutex); spin_lock_irqsave(&bcm->irq_lock, flags); if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) { printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); res = -EFAULT; goto out_unlock; } if (sscanf(buf, "%lli", &tsf) != 1) { printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n"); res = -EINVAL; goto out_unlock; } bcm43xx_tsf_write(bcm, tsf); mmiowb(); res = buf_size; out_unlock: spin_unlock_irqrestore(&bcm->irq_lock, flags); mutex_unlock(&bcm->mutex);out_up: up(&big_buffer_sem); return res;}static ssize_t txstat_read_file(struct file *file, char __user *userbuf, size_t count, loff_t *ppos){ const size_t len = REALLY_BIG_BUFFER_SIZE; struct bcm43xx_private *bcm = file->private_data; char *buf = really_big_buffer; size_t pos = 0; ssize_t res; unsigned long flags; struct bcm43xx_dfsentry *e; struct bcm43xx_xmitstatus *status; int i, cnt, j = 0; down(&big_buffer_sem); mutex_lock(&bcm->mutex); spin_lock_irqsave(&bcm->irq_lock, flags); fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", BCM43xx_NR_LOGGED_XMITSTATUS); e = bcm->dfsentry; if (e->xmitstatus_printing == 0) { /* At the beginning, make a copy of all data to avoid * concurrency, as this function is called multiple * times for big logs. Without copying, the data might * change between reads. This would result in total trash.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -