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 34 static ssize_t btmrvl_hscfgcmd_write(struct file *file, 35 const char __user *ubuf, size_t count, loff_t *ppos) 36 { 37 struct btmrvl_private *priv = file->private_data; 38 long result, ret; 39 40 ret = kstrtol_from_user(ubuf, count, 10, &result); 41 if (ret) 42 return ret; 43 44 priv->btmrvl_dev.hscfgcmd = result; 45 46 if (priv->btmrvl_dev.hscfgcmd) { 47 btmrvl_prepare_command(priv); 48 wake_up_interruptible(&priv->main_thread.wait_q); 49 } 50 51 return count; 52 } 53 54 static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf, 55 size_t count, loff_t *ppos) 56 { 57 struct btmrvl_private *priv = file->private_data; 58 char buf[16]; 59 int ret; 60 61 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", 62 priv->btmrvl_dev.hscfgcmd); 63 64 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 65 } 66 67 static const struct file_operations btmrvl_hscfgcmd_fops = { 68 .read = btmrvl_hscfgcmd_read, 69 .write = btmrvl_hscfgcmd_write, 70 .open = simple_open, 71 .llseek = default_llseek, 72 }; 73 74 static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, 75 size_t count, loff_t *ppos) 76 { 77 struct btmrvl_private *priv = file->private_data; 78 long result, ret; 79 80 ret = kstrtol_from_user(ubuf, count, 10, &result); 81 if (ret) 82 return ret; 83 84 priv->btmrvl_dev.pscmd = result; 85 86 if (priv->btmrvl_dev.pscmd) { 87 btmrvl_prepare_command(priv); 88 wake_up_interruptible(&priv->main_thread.wait_q); 89 } 90 91 return count; 92 93 } 94 95 static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf, 96 size_t count, loff_t *ppos) 97 { 98 struct btmrvl_private *priv = file->private_data; 99 char buf[16]; 100 int ret; 101 102 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); 103 104 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 105 } 106 107 static const struct file_operations btmrvl_pscmd_fops = { 108 .read = btmrvl_pscmd_read, 109 .write = btmrvl_pscmd_write, 110 .open = simple_open, 111 .llseek = default_llseek, 112 }; 113 114 static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, 115 size_t count, loff_t *ppos) 116 { 117 struct btmrvl_private *priv = file->private_data; 118 long result, ret; 119 120 ret = kstrtol_from_user(ubuf, count, 10, &result); 121 if (ret) 122 return ret; 123 124 priv->btmrvl_dev.hscmd = result; 125 if (priv->btmrvl_dev.hscmd) { 126 btmrvl_prepare_command(priv); 127 wake_up_interruptible(&priv->main_thread.wait_q); 128 } 129 130 return count; 131 } 132 133 static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf, 134 size_t count, loff_t *ppos) 135 { 136 struct btmrvl_private *priv = file->private_data; 137 char buf[16]; 138 int ret; 139 140 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); 141 142 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 143 } 144 145 static const struct file_operations btmrvl_hscmd_fops = { 146 .read = btmrvl_hscmd_read, 147 .write = btmrvl_hscmd_write, 148 .open = simple_open, 149 .llseek = default_llseek, 150 }; 151 152 void btmrvl_debugfs_init(struct hci_dev *hdev) 153 { 154 struct btmrvl_private *priv = hci_get_drvdata(hdev); 155 struct btmrvl_debugfs_data *dbg; 156 157 if (!hdev->debugfs) 158 return; 159 160 dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); 161 priv->debugfs_data = dbg; 162 163 if (!dbg) { 164 BT_ERR("Can not allocate memory for btmrvl_debugfs_data."); 165 return; 166 } 167 168 dbg->config_dir = debugfs_create_dir("config", hdev->debugfs); 169 170 debugfs_create_u8("psmode", 0644, dbg->config_dir, 171 &priv->btmrvl_dev.psmode); 172 debugfs_create_file("pscmd", 0644, dbg->config_dir, 173 priv, &btmrvl_pscmd_fops); 174 debugfs_create_x16("gpiogap", 0644, dbg->config_dir, 175 &priv->btmrvl_dev.gpio_gap); 176 debugfs_create_u8("hsmode", 0644, dbg->config_dir, 177 &priv->btmrvl_dev.hsmode); 178 debugfs_create_file("hscmd", 0644, dbg->config_dir, 179 priv, &btmrvl_hscmd_fops); 180 debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, 181 priv, &btmrvl_hscfgcmd_fops); 182 183 dbg->status_dir = debugfs_create_dir("status", hdev->debugfs); 184 debugfs_create_u8("curpsmode", 0444, dbg->status_dir, 185 &priv->adapter->psmode); 186 debugfs_create_u8("psstate", 0444, dbg->status_dir, 187 &priv->adapter->ps_state); 188 debugfs_create_u8("hsstate", 0444, dbg->status_dir, 189 &priv->adapter->hs_state); 190 debugfs_create_u8("txdnldready", 0444, dbg->status_dir, 191 &priv->btmrvl_dev.tx_dnld_rdy); 192 } 193 194 void btmrvl_debugfs_remove(struct hci_dev *hdev) 195 { 196 struct btmrvl_private *priv = hci_get_drvdata(hdev); 197 struct btmrvl_debugfs_data *dbg = priv->debugfs_data; 198 199 if (!dbg) 200 return; 201 202 debugfs_remove_recursive(dbg->config_dir); 203 debugfs_remove_recursive(dbg->status_dir); 204 205 kfree(dbg); 206 } 207