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