1
linux/drivers/bluetooth/btmrvl_debugfs.c
Marcel Holtmann b914a250e7 Bluetooth: Convert Marvell driver to use per adapter debugfs
The debugfs support of the Marvell driver is buggy. It is limited to one
controller per system. Fix this by using the controller specific debugfs
directory as parent.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
2010-02-27 14:05:38 +01:00

432 lines
11 KiB
C

/**
* Marvell Bluetooth driver: debugfs related functions
*
* Copyright (C) 2009, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
**/
#include <linux/debugfs.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "btmrvl_drv.h"
struct btmrvl_debugfs_data {
struct dentry *config_dir;
struct dentry *status_dir;
/* config */
struct dentry *psmode;
struct dentry *pscmd;
struct dentry *hsmode;
struct dentry *hscmd;
struct dentry *gpiogap;
struct dentry *hscfgcmd;
/* status */
struct dentry *curpsmode;
struct dentry *hsstate;
struct dentry *psstate;
struct dentry *txdnldready;
};
static int btmrvl_open_generic(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t btmrvl_hscfgcmd_write(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
long result, ret;
memset(buf, 0, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
ret = strict_strtol(buf, 10, &result);
priv->btmrvl_dev.hscfgcmd = result;
if (priv->btmrvl_dev.hscfgcmd) {
btmrvl_prepare_command(priv);
wake_up_interruptible(&priv->main_thread.wait_q);
}
return count;
}
static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
priv->btmrvl_dev.hscfgcmd);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_hscfgcmd_fops = {
.read = btmrvl_hscfgcmd_read,
.write = btmrvl_hscfgcmd_write,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
long result, ret;
memset(buf, 0, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
ret = strict_strtol(buf, 10, &result);
priv->btmrvl_dev.psmode = result;
return count;
}
static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
priv->btmrvl_dev.psmode);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_psmode_fops = {
.read = btmrvl_psmode_read,
.write = btmrvl_psmode_write,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
long result, ret;
memset(buf, 0, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
ret = strict_strtol(buf, 10, &result);
priv->btmrvl_dev.pscmd = result;
if (priv->btmrvl_dev.pscmd) {
btmrvl_prepare_command(priv);
wake_up_interruptible(&priv->main_thread.wait_q);
}
return count;
}
static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_pscmd_fops = {
.read = btmrvl_pscmd_read,
.write = btmrvl_pscmd_write,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
long result, ret;
memset(buf, 0, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
ret = strict_strtol(buf, 16, &result);
priv->btmrvl_dev.gpio_gap = result;
return count;
}
static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n",
priv->btmrvl_dev.gpio_gap);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_gpiogap_fops = {
.read = btmrvl_gpiogap_read,
.write = btmrvl_gpiogap_write,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data;
char buf[16];
long result, ret;
memset(buf, 0, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
ret = strict_strtol(buf, 10, &result);
priv->btmrvl_dev.hscmd = result;
if (priv->btmrvl_dev.hscmd) {
btmrvl_prepare_command(priv);
wake_up_interruptible(&priv->main_thread.wait_q);
}
return count;
}
static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_hscmd_fops = {
.read = btmrvl_hscmd_read,
.write = btmrvl_hscmd_write,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
long result, ret;
memset(buf, 0, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
ret = strict_strtol(buf, 10, &result);
priv->btmrvl_dev.hsmode = result;
return count;
}
static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_hsmode_fops = {
.read = btmrvl_hsmode_read,
.write = btmrvl_hsmode_write,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_curpsmode_fops = {
.read = btmrvl_curpsmode_read,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_psstate_fops = {
.read = btmrvl_psstate_read,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_hsstate_fops = {
.read = btmrvl_hsstate_read,
.open = btmrvl_open_generic,
};
static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct btmrvl_private *priv = file->private_data;
char buf[16];
int ret;
ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
priv->btmrvl_dev.tx_dnld_rdy);
return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}
static const struct file_operations btmrvl_txdnldready_fops = {
.read = btmrvl_txdnldready_read,
.open = btmrvl_open_generic,
};
void btmrvl_debugfs_init(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hdev->driver_data;
struct btmrvl_debugfs_data *dbg;
if (!hdev->debugfs)
return;
dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
priv->debugfs_data = dbg;
if (!dbg) {
BT_ERR("Can not allocate memory for btmrvl_debugfs_data.");
return;
}
dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
hdev->driver_data, &btmrvl_psmode_fops);
dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
hdev->driver_data, &btmrvl_pscmd_fops);
dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
hdev->driver_data, &btmrvl_gpiogap_fops);
dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir,
hdev->driver_data, &btmrvl_hsmode_fops);
dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
hdev->driver_data, &btmrvl_hscmd_fops);
dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
hdev->driver_data, &btmrvl_hscfgcmd_fops);
dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
dbg->status_dir,
hdev->driver_data,
&btmrvl_curpsmode_fops);
dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
hdev->driver_data, &btmrvl_psstate_fops);
dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
hdev->driver_data, &btmrvl_hsstate_fops);
dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
dbg->status_dir,
hdev->driver_data,
&btmrvl_txdnldready_fops);
}
void btmrvl_debugfs_remove(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hdev->driver_data;
struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
if (!dbg)
return;
debugfs_remove(dbg->psmode);
debugfs_remove(dbg->pscmd);
debugfs_remove(dbg->gpiogap);
debugfs_remove(dbg->hsmode);
debugfs_remove(dbg->hscmd);
debugfs_remove(dbg->hscfgcmd);
debugfs_remove(dbg->config_dir);
debugfs_remove(dbg->curpsmode);
debugfs_remove(dbg->psstate);
debugfs_remove(dbg->hsstate);
debugfs_remove(dbg->txdnldready);
debugfs_remove(dbg->status_dir);
kfree(dbg);
}