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 29struct 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 48static int btmrvl_open_generic(struct inode *inode, struct file *file) 49{ 50 file->private_data = inode->i_private; 51 return 0; 52} 53 54static ssize_t btmrvl_hscfgcmd_write(struct file *file, 55 const char __user *ubuf, size_t count, loff_t *ppos) 56{ 57 struct btmrvl_private *priv = file->private_data; 58 char buf[16]; 59 long result, ret; 60 61 memset(buf, 0, sizeof(buf)); 62 63 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 64 return -EFAULT; 65 66 ret = strict_strtol(buf, 10, &result); 67 68 priv->btmrvl_dev.hscfgcmd = result; 69 70 if (priv->btmrvl_dev.hscfgcmd) { 71 btmrvl_prepare_command(priv); 72 wake_up_interruptible(&priv->main_thread.wait_q); 73 } 74 75 return count; 76} 77 78static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf, 79 size_t count, loff_t *ppos) 80{ 81 struct btmrvl_private *priv = file->private_data; 82 char buf[16]; 83 int ret; 84 85 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", 86 priv->btmrvl_dev.hscfgcmd); 87 88 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 89} 90 91static const struct file_operations btmrvl_hscfgcmd_fops = { 92 .read = btmrvl_hscfgcmd_read, 93 .write = btmrvl_hscfgcmd_write, 94 .open = btmrvl_open_generic, 95}; 96 97static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, 98 size_t count, loff_t *ppos) 99{ 100 struct btmrvl_private *priv = file->private_data; 101 char buf[16]; 102 long result, ret; 103 104 memset(buf, 0, sizeof(buf)); 105 106 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 107 return -EFAULT; 108 109 ret = strict_strtol(buf, 10, &result); 110 111 priv->btmrvl_dev.psmode = result; 112 113 return count; 114} 115 116static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf, 117 size_t count, loff_t *ppos) 118{ 119 struct btmrvl_private *priv = file->private_data; 120 char buf[16]; 121 int ret; 122 123 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", 124 priv->btmrvl_dev.psmode); 125 126 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 127} 128 129static const struct file_operations btmrvl_psmode_fops = { 130 .read = btmrvl_psmode_read, 131 .write = btmrvl_psmode_write, 132 .open = btmrvl_open_generic, 133}; 134 135static 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 149 priv->btmrvl_dev.pscmd = result; 150 151 if (priv->btmrvl_dev.pscmd) { 152 btmrvl_prepare_command(priv); 153 wake_up_interruptible(&priv->main_thread.wait_q); 154 } 155 156 return count; 157 158} 159 160static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf, 161 size_t count, loff_t *ppos) 162{ 163 struct btmrvl_private *priv = file->private_data; 164 char buf[16]; 165 int ret; 166 167 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); 168 169 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 170} 171 172static const struct file_operations btmrvl_pscmd_fops = { 173 .read = btmrvl_pscmd_read, 174 .write = btmrvl_pscmd_write, 175 .open = btmrvl_open_generic, 176}; 177 178static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, 179 size_t count, loff_t *ppos) 180{ 181 struct btmrvl_private *priv = file->private_data; 182 char buf[16]; 183 long result, ret; 184 185 memset(buf, 0, sizeof(buf)); 186 187 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 188 return -EFAULT; 189 190 ret = strict_strtol(buf, 16, &result); 191 192 priv->btmrvl_dev.gpio_gap = result; 193 194 return count; 195} 196 197static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf, 198 size_t count, loff_t *ppos) 199{ 200 struct btmrvl_private *priv = file->private_data; 201 char buf[16]; 202 int ret; 203 204 ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n", 205 priv->btmrvl_dev.gpio_gap); 206 207 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 208} 209 210static const struct file_operations btmrvl_gpiogap_fops = { 211 .read = btmrvl_gpiogap_read, 212 .write = btmrvl_gpiogap_write, 213 .open = btmrvl_open_generic, 214}; 215 216static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, 217 size_t count, loff_t *ppos) 218{ 219 struct btmrvl_private *priv = file->private_data; 220 char buf[16]; 221 long result, ret; 222 223 memset(buf, 0, sizeof(buf)); 224 225 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 226 return -EFAULT; 227 228 ret = strict_strtol(buf, 10, &result); 229 230 priv->btmrvl_dev.hscmd = result; 231 if (priv->btmrvl_dev.hscmd) { 232 btmrvl_prepare_command(priv); 233 wake_up_interruptible(&priv->main_thread.wait_q); 234 } 235 236 return count; 237} 238 239static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf, 240 size_t count, loff_t *ppos) 241{ 242 struct btmrvl_private *priv = file->private_data; 243 char buf[16]; 244 int ret; 245 246 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); 247 248 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 249} 250 251static const struct file_operations btmrvl_hscmd_fops = { 252 .read = btmrvl_hscmd_read, 253 .write = btmrvl_hscmd_write, 254 .open = btmrvl_open_generic, 255}; 256 257static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, 258 size_t count, loff_t *ppos) 259{ 260 struct btmrvl_private *priv = file->private_data; 261 char buf[16]; 262 long result, ret; 263 264 memset(buf, 0, sizeof(buf)); 265 266 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 267 return -EFAULT; 268 269 ret = strict_strtol(buf, 10, &result); 270 271 priv->btmrvl_dev.hsmode = result; 272 273 return count; 274} 275 276static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, 277 size_t count, loff_t *ppos) 278{ 279 struct btmrvl_private *priv = file->private_data; 280 char buf[16]; 281 int ret; 282 283 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode); 284 285 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 286} 287 288static const struct file_operations btmrvl_hsmode_fops = { 289 .read = btmrvl_hsmode_read, 290 .write = btmrvl_hsmode_write, 291 .open = btmrvl_open_generic, 292}; 293 294static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, 295 size_t count, loff_t *ppos) 296{ 297 struct btmrvl_private *priv = file->private_data; 298 char buf[16]; 299 int ret; 300 301 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode); 302 303 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 304} 305 306static const struct file_operations btmrvl_curpsmode_fops = { 307 .read = btmrvl_curpsmode_read, 308 .open = btmrvl_open_generic, 309}; 310 311static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, 312 size_t count, loff_t *ppos) 313{ 314 struct btmrvl_private *priv = file->private_data; 315 char buf[16]; 316 int ret; 317 318 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state); 319 320 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 321} 322 323static const struct file_operations btmrvl_psstate_fops = { 324 .read = btmrvl_psstate_read, 325 .open = btmrvl_open_generic, 326}; 327 328static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, 329 size_t count, loff_t *ppos) 330{ 331 struct btmrvl_private *priv = file->private_data; 332 char buf[16]; 333 int ret; 334 335 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state); 336 337 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 338} 339 340static const struct file_operations btmrvl_hsstate_fops = { 341 .read = btmrvl_hsstate_read, 342 .open = btmrvl_open_generic, 343}; 344 345static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, 346 size_t count, loff_t *ppos) 347{ 348 struct btmrvl_private *priv = file->private_data; 349 char buf[16]; 350 int ret; 351 352 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", 353 priv->btmrvl_dev.tx_dnld_rdy); 354 355 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 356} 357 358static const struct file_operations btmrvl_txdnldready_fops = { 359 .read = btmrvl_txdnldready_read, 360 .open = btmrvl_open_generic, 361}; 362 363void btmrvl_debugfs_init(struct hci_dev *hdev) 364{ 365 struct btmrvl_private *priv = hdev->driver_data; 366 struct btmrvl_debugfs_data *dbg; 367 368 if (!hdev->debugfs) 369 return; 370 371 dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); 372 priv->debugfs_data = dbg; 373 374 if (!dbg) { 375 BT_ERR("Can not allocate memory for btmrvl_debugfs_data."); 376 return; 377 } 378 379 dbg->config_dir = debugfs_create_dir("config", hdev->debugfs); 380 381 dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, 382 hdev->driver_data, &btmrvl_psmode_fops); 383 dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, 384 hdev->driver_data, &btmrvl_pscmd_fops); 385 dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, 386 hdev->driver_data, &btmrvl_gpiogap_fops); 387 dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, 388 hdev->driver_data, &btmrvl_hsmode_fops); 389 dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, 390 hdev->driver_data, &btmrvl_hscmd_fops); 391 dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, 392 hdev->driver_data, &btmrvl_hscfgcmd_fops); 393 394 dbg->status_dir = debugfs_create_dir("status", hdev->debugfs); 395 dbg->curpsmode = debugfs_create_file("curpsmode", 0444, 396 dbg->status_dir, 397 hdev->driver_data, 398 &btmrvl_curpsmode_fops); 399 dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, 400 hdev->driver_data, &btmrvl_psstate_fops); 401 dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, 402 hdev->driver_data, &btmrvl_hsstate_fops); 403 dbg->txdnldready = debugfs_create_file("txdnldready", 0444, 404 dbg->status_dir, 405 hdev->driver_data, 406 &btmrvl_txdnldready_fops); 407} 408 409void btmrvl_debugfs_remove(struct hci_dev *hdev) 410{ 411 struct btmrvl_private *priv = hdev->driver_data; 412 struct btmrvl_debugfs_data *dbg = priv->debugfs_data; 413 414 if (!dbg) 415 return; 416 417 debugfs_remove(dbg->psmode); 418 debugfs_remove(dbg->pscmd); 419 debugfs_remove(dbg->gpiogap); 420 debugfs_remove(dbg->hsmode); 421 debugfs_remove(dbg->hscmd); 422 debugfs_remove(dbg->hscfgcmd); 423 debugfs_remove(dbg->config_dir); 424 425 debugfs_remove(dbg->curpsmode); 426 debugfs_remove(dbg->psstate); 427 debugfs_remove(dbg->hsstate); 428 debugfs_remove(dbg->txdnldready); 429 debugfs_remove(dbg->status_dir); 430 431 kfree(dbg); 432} 433