1 /**
2  * Marvell Bluetooth driver: debugfs related functions
3  *
4  * Copyright (C) 2009, Marvell International Ltd.
5  *
6  * This software file (the "File") is distributed by Marvell International
7  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8  * (the "License").  You may use, redistribute and/or modify this File in
9  * accordance with the terms and conditions of the License, a copy of which
10  * is available by writing to the Free Software Foundation, Inc.,
11  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13  *
14  *
15  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
18  * this warranty disclaimer.
19  **/
20 
21 #include <linux/debugfs.h>
22 #include <linux/slab.h>
23 
24 #include <net/bluetooth/bluetooth.h>
25 #include <net/bluetooth/hci_core.h>
26 
27 #include "btmrvl_drv.h"
28 
29 struct btmrvl_debugfs_data {
30 	struct dentry *config_dir;
31 	struct dentry *status_dir;
32 
33 	/* config */
34 	struct dentry *psmode;
35 	struct dentry *pscmd;
36 	struct dentry *hsmode;
37 	struct dentry *hscmd;
38 	struct dentry *gpiogap;
39 	struct dentry *hscfgcmd;
40 
41 	/* status */
42 	struct dentry *curpsmode;
43 	struct dentry *hsstate;
44 	struct dentry *psstate;
45 	struct dentry *txdnldready;
46 };
47 
48 static ssize_t btmrvl_hscfgcmd_write(struct file *file,
49 			const char __user *ubuf, size_t count, loff_t *ppos)
50 {
51 	struct btmrvl_private *priv = file->private_data;
52 	char buf[16];
53 	long result, ret;
54 
55 	memset(buf, 0, sizeof(buf));
56 
57 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
58 		return -EFAULT;
59 
60 	ret = strict_strtol(buf, 10, &result);
61 	if (ret)
62 		return ret;
63 
64 	priv->btmrvl_dev.hscfgcmd = result;
65 
66 	if (priv->btmrvl_dev.hscfgcmd) {
67 		btmrvl_prepare_command(priv);
68 		wake_up_interruptible(&priv->main_thread.wait_q);
69 	}
70 
71 	return count;
72 }
73 
74 static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf,
75 						size_t count, loff_t *ppos)
76 {
77 	struct btmrvl_private *priv = file->private_data;
78 	char buf[16];
79 	int ret;
80 
81 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
82 						priv->btmrvl_dev.hscfgcmd);
83 
84 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
85 }
86 
87 static const struct file_operations btmrvl_hscfgcmd_fops = {
88 	.read	= btmrvl_hscfgcmd_read,
89 	.write	= btmrvl_hscfgcmd_write,
90 	.open	= simple_open,
91 	.llseek = default_llseek,
92 };
93 
94 static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
95 						size_t count, loff_t *ppos)
96 {
97 	struct btmrvl_private *priv = file->private_data;
98 	char buf[16];
99 	long result, ret;
100 
101 	memset(buf, 0, sizeof(buf));
102 
103 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
104 		return -EFAULT;
105 
106 	ret = strict_strtol(buf, 10, &result);
107 	if (ret)
108 		return ret;
109 
110 	priv->btmrvl_dev.psmode = result;
111 
112 	return count;
113 }
114 
115 static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf,
116 						size_t count, loff_t *ppos)
117 {
118 	struct btmrvl_private *priv = file->private_data;
119 	char buf[16];
120 	int ret;
121 
122 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
123 						priv->btmrvl_dev.psmode);
124 
125 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
126 }
127 
128 static const struct file_operations btmrvl_psmode_fops = {
129 	.read	= btmrvl_psmode_read,
130 	.write	= btmrvl_psmode_write,
131 	.open	= simple_open,
132 	.llseek = default_llseek,
133 };
134 
135 static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
136 						size_t count, loff_t *ppos)
137 {
138 	struct btmrvl_private *priv = file->private_data;
139 	char buf[16];
140 	long result, ret;
141 
142 	memset(buf, 0, sizeof(buf));
143 
144 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
145 		return -EFAULT;
146 
147 	ret = strict_strtol(buf, 10, &result);
148 	if (ret)
149 		return ret;
150 
151 	priv->btmrvl_dev.pscmd = result;
152 
153 	if (priv->btmrvl_dev.pscmd) {
154 		btmrvl_prepare_command(priv);
155 		wake_up_interruptible(&priv->main_thread.wait_q);
156 	}
157 
158 	return count;
159 
160 }
161 
162 static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf,
163 						size_t count, loff_t *ppos)
164 {
165 	struct btmrvl_private *priv = file->private_data;
166 	char buf[16];
167 	int ret;
168 
169 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd);
170 
171 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
172 }
173 
174 static const struct file_operations btmrvl_pscmd_fops = {
175 	.read = btmrvl_pscmd_read,
176 	.write = btmrvl_pscmd_write,
177 	.open = simple_open,
178 	.llseek = default_llseek,
179 };
180 
181 static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
182 						size_t count, loff_t *ppos)
183 {
184 	struct btmrvl_private *priv = file->private_data;
185 	char buf[16];
186 	long result, ret;
187 
188 	memset(buf, 0, sizeof(buf));
189 
190 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
191 		return -EFAULT;
192 
193 	ret = strict_strtol(buf, 16, &result);
194 	if (ret)
195 		return ret;
196 
197 	priv->btmrvl_dev.gpio_gap = result;
198 
199 	return count;
200 }
201 
202 static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf,
203 						size_t count, loff_t *ppos)
204 {
205 	struct btmrvl_private *priv = file->private_data;
206 	char buf[16];
207 	int ret;
208 
209 	ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n",
210 						priv->btmrvl_dev.gpio_gap);
211 
212 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
213 }
214 
215 static const struct file_operations btmrvl_gpiogap_fops = {
216 	.read	= btmrvl_gpiogap_read,
217 	.write	= btmrvl_gpiogap_write,
218 	.open	= simple_open,
219 	.llseek = default_llseek,
220 };
221 
222 static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
223 						size_t count, loff_t *ppos)
224 {
225 	struct btmrvl_private *priv = file->private_data;
226 	char buf[16];
227 	long result, ret;
228 
229 	memset(buf, 0, sizeof(buf));
230 
231 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
232 		return -EFAULT;
233 
234 	ret = strict_strtol(buf, 10, &result);
235 	if (ret)
236 		return ret;
237 
238 	priv->btmrvl_dev.hscmd = result;
239 	if (priv->btmrvl_dev.hscmd) {
240 		btmrvl_prepare_command(priv);
241 		wake_up_interruptible(&priv->main_thread.wait_q);
242 	}
243 
244 	return count;
245 }
246 
247 static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf,
248 						size_t count, loff_t *ppos)
249 {
250 	struct btmrvl_private *priv = file->private_data;
251 	char buf[16];
252 	int ret;
253 
254 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd);
255 
256 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
257 }
258 
259 static const struct file_operations btmrvl_hscmd_fops = {
260 	.read	= btmrvl_hscmd_read,
261 	.write	= btmrvl_hscmd_write,
262 	.open	= simple_open,
263 	.llseek = default_llseek,
264 };
265 
266 static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
267 						size_t count, loff_t *ppos)
268 {
269 	struct btmrvl_private *priv = file->private_data;
270 	char buf[16];
271 	long result, ret;
272 
273 	memset(buf, 0, sizeof(buf));
274 
275 	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
276 		return -EFAULT;
277 
278 	ret = strict_strtol(buf, 10, &result);
279 	if (ret)
280 		return ret;
281 
282 	priv->btmrvl_dev.hsmode = result;
283 
284 	return count;
285 }
286 
287 static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf,
288 						size_t count, loff_t *ppos)
289 {
290 	struct btmrvl_private *priv = file->private_data;
291 	char buf[16];
292 	int ret;
293 
294 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode);
295 
296 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
297 }
298 
299 static const struct file_operations btmrvl_hsmode_fops = {
300 	.read	= btmrvl_hsmode_read,
301 	.write	= btmrvl_hsmode_write,
302 	.open	= simple_open,
303 	.llseek = default_llseek,
304 };
305 
306 static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf,
307 						size_t count, loff_t *ppos)
308 {
309 	struct btmrvl_private *priv = file->private_data;
310 	char buf[16];
311 	int ret;
312 
313 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode);
314 
315 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
316 }
317 
318 static const struct file_operations btmrvl_curpsmode_fops = {
319 	.read	= btmrvl_curpsmode_read,
320 	.open	= simple_open,
321 	.llseek = default_llseek,
322 };
323 
324 static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf,
325 						size_t count, loff_t *ppos)
326 {
327 	struct btmrvl_private *priv = file->private_data;
328 	char buf[16];
329 	int ret;
330 
331 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state);
332 
333 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
334 }
335 
336 static const struct file_operations btmrvl_psstate_fops = {
337 	.read	= btmrvl_psstate_read,
338 	.open	= simple_open,
339 	.llseek = default_llseek,
340 };
341 
342 static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf,
343 						size_t count, loff_t *ppos)
344 {
345 	struct btmrvl_private *priv = file->private_data;
346 	char buf[16];
347 	int ret;
348 
349 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state);
350 
351 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
352 }
353 
354 static const struct file_operations btmrvl_hsstate_fops = {
355 	.read	= btmrvl_hsstate_read,
356 	.open	= simple_open,
357 	.llseek = default_llseek,
358 };
359 
360 static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf,
361 						size_t count, loff_t *ppos)
362 {
363 	struct btmrvl_private *priv = file->private_data;
364 	char buf[16];
365 	int ret;
366 
367 	ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
368 					priv->btmrvl_dev.tx_dnld_rdy);
369 
370 	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
371 }
372 
373 static const struct file_operations btmrvl_txdnldready_fops = {
374 	.read	= btmrvl_txdnldready_read,
375 	.open	= simple_open,
376 	.llseek = default_llseek,
377 };
378 
379 void btmrvl_debugfs_init(struct hci_dev *hdev)
380 {
381 	struct btmrvl_private *priv = hci_get_drvdata(hdev);
382 	struct btmrvl_debugfs_data *dbg;
383 
384 	if (!hdev->debugfs)
385 		return;
386 
387 	dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
388 	priv->debugfs_data = dbg;
389 
390 	if (!dbg) {
391 		BT_ERR("Can not allocate memory for btmrvl_debugfs_data.");
392 		return;
393 	}
394 
395 	dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
396 
397 	dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
398 					  priv, &btmrvl_psmode_fops);
399 	dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
400 					 priv, &btmrvl_pscmd_fops);
401 	dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
402 					   priv, &btmrvl_gpiogap_fops);
403 	dbg->hsmode =  debugfs_create_file("hsmode", 0644, dbg->config_dir,
404 					   priv, &btmrvl_hsmode_fops);
405 	dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
406 					 priv, &btmrvl_hscmd_fops);
407 	dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
408 					    priv, &btmrvl_hscfgcmd_fops);
409 
410 	dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
411 	dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
412 					     dbg->status_dir, priv,
413 					     &btmrvl_curpsmode_fops);
414 	dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
415 					   priv, &btmrvl_psstate_fops);
416 	dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
417 					   priv, &btmrvl_hsstate_fops);
418 	dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
419 					       dbg->status_dir, priv,
420 					       &btmrvl_txdnldready_fops);
421 }
422 
423 void btmrvl_debugfs_remove(struct hci_dev *hdev)
424 {
425 	struct btmrvl_private *priv = hci_get_drvdata(hdev);
426 	struct btmrvl_debugfs_data *dbg = priv->debugfs_data;
427 
428 	if (!dbg)
429 		return;
430 
431 	debugfs_remove(dbg->psmode);
432 	debugfs_remove(dbg->pscmd);
433 	debugfs_remove(dbg->gpiogap);
434 	debugfs_remove(dbg->hsmode);
435 	debugfs_remove(dbg->hscmd);
436 	debugfs_remove(dbg->hscfgcmd);
437 	debugfs_remove(dbg->config_dir);
438 
439 	debugfs_remove(dbg->curpsmode);
440 	debugfs_remove(dbg->psstate);
441 	debugfs_remove(dbg->hsstate);
442 	debugfs_remove(dbg->txdnldready);
443 	debugfs_remove(dbg->status_dir);
444 
445 	kfree(dbg);
446 }
447