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