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