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