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