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