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