/*
Broadcom B43 wireless driver
debugfs driver debugging code
Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.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 <linux/mutex.h>
#include "b43.h"
#include "main.h"
#include "debugfs.h"
#include "dma.h"
#include "xmit.h"
/* The root directory. */
static struct dentry *rootdir;
struct b43_debugfs_fops {
ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
struct file_operations fops;
/* Offset of struct b43_dfs_file in struct b43_dfsentry */
size_t file_struct_offset;
/* Take wl->irq_lock before calling read/write? */
bool take_irqlock;
};
static inline
struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
const struct b43_debugfs_fops *dfops)
{
void *p;
p = dev->dfsentry;
p += dfops->file_struct_offset;
return p;
}
#define fappend(fmt, x...) \
do { \
if (bufsize - count) \
count += snprintf(buf + count, \
bufsize - count, \
fmt , ##x); \
else \
printk(KERN_ERR "b43: fappend overflow\n"); \
} while (0)
/* The biggest address values for SHM access from the debugfs files. */
#define B43_MAX_SHM_ROUTING 4
#define B43_MAX_SHM_ADDR 0xFFFF
static ssize_t shm16read__read_file(struct b43_wldev *dev,
char *buf, size_t bufsize)
{
ssize_t count = 0;
unsigned int routing, addr;
u16 val;
routing = dev->dfsentry->shm16read_routing_next;
addr = dev->dfsentry->shm16read_addr_next;
if ((routing > B43_MAX_SHM_ROUTING) ||
(addr > B43_MAX_SHM_ADDR))
return -EDESTADDRREQ;
val = b43_shm_read16(dev, routing, addr);
fappend("0x%04X\n", val);
return count;
}
static int shm16read__write_file(struct b43_wldev *dev,
const char *buf, size_t count)
{
unsigned int routing, addr;
int res;
res = sscanf(buf, "0x%X 0x%X", &routing, &addr);
if (res != 2)
return -EINVAL;
if (routing > B43_MAX_SHM_ROUTING)
return -EADDRNOTAVAIL;
if (addr > B43_MAX_SHM_ADDR)
return -EADDRNOTAVAIL;
if (routing == B43_SHM_SHARED) {
if ((addr % 2) != 0)
return -EADDRNOTAVAIL;
}
dev->dfsentry->shm16read_routing_next = routing;
dev->dfsentry->shm16read_addr_next = addr;
return 0;
}
static int shm16write__write_file(struct b43_wldev *dev,
const char *buf, size_t count)
{
unsigned int routing, addr, mask, set;
u16 val;
int res;
unsigned long flags;
res = sscanf(buf, "0x%X 0x%X 0x%X 0x%X",
&routing, &addr, &mask, &set);
if (res != 4)
return -EINVAL;
if (routing > B43_MAX_SHM_ROUTING)
return -EADDRNOTAVAIL;
if (addr > B43_MAX_SHM_ADDR)
return -EADDRNOTAVAIL;
if (routing == B43_SHM_SHARED) {
if ((addr % 2) != 0)
return -EADDRNOTAVAIL;
}
if ((mask > 0xFFFF) || (set > 0xFFFF))
return -E2BIG;
spin_lock_irqsave(&dev->wl->shm_lock, flags);
if (mask == 0)
val = 0;
else
val = __b43_shm_read16(dev, routing, addr);
val &= mask;
val |= set;
__b43_shm_write16(dev, routing, addr, val);
spin_unlock_irqrestore(&dev->wl->shm_lock, flags);
return 0;
}
static ssize_t shm32read__read_file(struct b43_wldev *dev,
char *buf, size_t bufsize)
{
ssize_t count = 0;
unsigned int routing, addr;
u32 val;
routing = dev->dfsentry->shm32read_routing_next;
addr = dev->dfsentry->shm32read_addr_next;
if ((routing > B43_MAX_SHM_ROUTING) ||
(addr > B43_MAX_SHM_ADDR))
return -EDESTADDRREQ;
val = b43_shm_read32(dev, routing, addr);
fappend("0x%08X\n", val);
return count;
}
static int shm32read__write_file(struct b43_wldev *dev,
const char *buf, size_t count)
{
unsigned int routing,