1*4882a593Smuzhiyun /**
2*4882a593Smuzhiyun * Marvell Bluetooth driver: debugfs related functions
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2009, Marvell International Ltd.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This software file (the "File") is distributed by Marvell International
7*4882a593Smuzhiyun * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8*4882a593Smuzhiyun * (the "License"). You may use, redistribute and/or modify this File in
9*4882a593Smuzhiyun * accordance with the terms and conditions of the License, a copy of which
10*4882a593Smuzhiyun * is available by writing to the Free Software Foundation, Inc.,
11*4882a593Smuzhiyun * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12*4882a593Smuzhiyun * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16*4882a593Smuzhiyun * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17*4882a593Smuzhiyun * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18*4882a593Smuzhiyun * this warranty disclaimer.
19*4882a593Smuzhiyun **/
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/debugfs.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include <net/bluetooth/bluetooth.h>
25*4882a593Smuzhiyun #include <net/bluetooth/hci_core.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "btmrvl_drv.h"
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun struct btmrvl_debugfs_data {
30*4882a593Smuzhiyun struct dentry *config_dir;
31*4882a593Smuzhiyun struct dentry *status_dir;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
btmrvl_hscfgcmd_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)34*4882a593Smuzhiyun static ssize_t btmrvl_hscfgcmd_write(struct file *file,
35*4882a593Smuzhiyun const char __user *ubuf, size_t count, loff_t *ppos)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun struct btmrvl_private *priv = file->private_data;
38*4882a593Smuzhiyun long result, ret;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun ret = kstrtol_from_user(ubuf, count, 10, &result);
41*4882a593Smuzhiyun if (ret)
42*4882a593Smuzhiyun return ret;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun priv->btmrvl_dev.hscfgcmd = result;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun if (priv->btmrvl_dev.hscfgcmd) {
47*4882a593Smuzhiyun btmrvl_prepare_command(priv);
48*4882a593Smuzhiyun wake_up_interruptible(&priv->main_thread.wait_q);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun return count;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
btmrvl_hscfgcmd_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)54*4882a593Smuzhiyun static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf,
55*4882a593Smuzhiyun size_t count, loff_t *ppos)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun struct btmrvl_private *priv = file->private_data;
58*4882a593Smuzhiyun char buf[16];
59*4882a593Smuzhiyun int ret;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
62*4882a593Smuzhiyun priv->btmrvl_dev.hscfgcmd);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun static const struct file_operations btmrvl_hscfgcmd_fops = {
68*4882a593Smuzhiyun .read = btmrvl_hscfgcmd_read,
69*4882a593Smuzhiyun .write = btmrvl_hscfgcmd_write,
70*4882a593Smuzhiyun .open = simple_open,
71*4882a593Smuzhiyun .llseek = default_llseek,
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun
btmrvl_pscmd_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)74*4882a593Smuzhiyun static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
75*4882a593Smuzhiyun size_t count, loff_t *ppos)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun struct btmrvl_private *priv = file->private_data;
78*4882a593Smuzhiyun long result, ret;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun ret = kstrtol_from_user(ubuf, count, 10, &result);
81*4882a593Smuzhiyun if (ret)
82*4882a593Smuzhiyun return ret;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun priv->btmrvl_dev.pscmd = result;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun if (priv->btmrvl_dev.pscmd) {
87*4882a593Smuzhiyun btmrvl_prepare_command(priv);
88*4882a593Smuzhiyun wake_up_interruptible(&priv->main_thread.wait_q);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun return count;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
btmrvl_pscmd_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)95*4882a593Smuzhiyun static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf,
96*4882a593Smuzhiyun size_t count, loff_t *ppos)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun struct btmrvl_private *priv = file->private_data;
99*4882a593Smuzhiyun char buf[16];
100*4882a593Smuzhiyun int ret;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun static const struct file_operations btmrvl_pscmd_fops = {
108*4882a593Smuzhiyun .read = btmrvl_pscmd_read,
109*4882a593Smuzhiyun .write = btmrvl_pscmd_write,
110*4882a593Smuzhiyun .open = simple_open,
111*4882a593Smuzhiyun .llseek = default_llseek,
112*4882a593Smuzhiyun };
113*4882a593Smuzhiyun
btmrvl_hscmd_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)114*4882a593Smuzhiyun static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
115*4882a593Smuzhiyun size_t count, loff_t *ppos)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun struct btmrvl_private *priv = file->private_data;
118*4882a593Smuzhiyun long result, ret;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun ret = kstrtol_from_user(ubuf, count, 10, &result);
121*4882a593Smuzhiyun if (ret)
122*4882a593Smuzhiyun return ret;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun priv->btmrvl_dev.hscmd = result;
125*4882a593Smuzhiyun if (priv->btmrvl_dev.hscmd) {
126*4882a593Smuzhiyun btmrvl_prepare_command(priv);
127*4882a593Smuzhiyun wake_up_interruptible(&priv->main_thread.wait_q);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun return count;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
btmrvl_hscmd_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)133*4882a593Smuzhiyun static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf,
134*4882a593Smuzhiyun size_t count, loff_t *ppos)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun struct btmrvl_private *priv = file->private_data;
137*4882a593Smuzhiyun char buf[16];
138*4882a593Smuzhiyun int ret;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun static const struct file_operations btmrvl_hscmd_fops = {
146*4882a593Smuzhiyun .read = btmrvl_hscmd_read,
147*4882a593Smuzhiyun .write = btmrvl_hscmd_write,
148*4882a593Smuzhiyun .open = simple_open,
149*4882a593Smuzhiyun .llseek = default_llseek,
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun
btmrvl_debugfs_init(struct hci_dev * hdev)152*4882a593Smuzhiyun void btmrvl_debugfs_init(struct hci_dev *hdev)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun struct btmrvl_private *priv = hci_get_drvdata(hdev);
155*4882a593Smuzhiyun struct btmrvl_debugfs_data *dbg;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if (!hdev->debugfs)
158*4882a593Smuzhiyun return;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
161*4882a593Smuzhiyun priv->debugfs_data = dbg;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (!dbg) {
164*4882a593Smuzhiyun BT_ERR("Can not allocate memory for btmrvl_debugfs_data.");
165*4882a593Smuzhiyun return;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun debugfs_create_u8("psmode", 0644, dbg->config_dir,
171*4882a593Smuzhiyun &priv->btmrvl_dev.psmode);
172*4882a593Smuzhiyun debugfs_create_file("pscmd", 0644, dbg->config_dir,
173*4882a593Smuzhiyun priv, &btmrvl_pscmd_fops);
174*4882a593Smuzhiyun debugfs_create_x16("gpiogap", 0644, dbg->config_dir,
175*4882a593Smuzhiyun &priv->btmrvl_dev.gpio_gap);
176*4882a593Smuzhiyun debugfs_create_u8("hsmode", 0644, dbg->config_dir,
177*4882a593Smuzhiyun &priv->btmrvl_dev.hsmode);
178*4882a593Smuzhiyun debugfs_create_file("hscmd", 0644, dbg->config_dir,
179*4882a593Smuzhiyun priv, &btmrvl_hscmd_fops);
180*4882a593Smuzhiyun debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
181*4882a593Smuzhiyun priv, &btmrvl_hscfgcmd_fops);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
184*4882a593Smuzhiyun debugfs_create_u8("curpsmode", 0444, dbg->status_dir,
185*4882a593Smuzhiyun &priv->adapter->psmode);
186*4882a593Smuzhiyun debugfs_create_u8("psstate", 0444, dbg->status_dir,
187*4882a593Smuzhiyun &priv->adapter->ps_state);
188*4882a593Smuzhiyun debugfs_create_u8("hsstate", 0444, dbg->status_dir,
189*4882a593Smuzhiyun &priv->adapter->hs_state);
190*4882a593Smuzhiyun debugfs_create_u8("txdnldready", 0444, dbg->status_dir,
191*4882a593Smuzhiyun &priv->btmrvl_dev.tx_dnld_rdy);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
btmrvl_debugfs_remove(struct hci_dev * hdev)194*4882a593Smuzhiyun void btmrvl_debugfs_remove(struct hci_dev *hdev)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun struct btmrvl_private *priv = hci_get_drvdata(hdev);
197*4882a593Smuzhiyun struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (!dbg)
200*4882a593Smuzhiyun return;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun debugfs_remove_recursive(dbg->config_dir);
203*4882a593Smuzhiyun debugfs_remove_recursive(dbg->status_dir);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun kfree(dbg);
206*4882a593Smuzhiyun }
207