1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Marvell Bluetooth driver: debugfs related functions 4 * 5 * Copyright (C) 2009, Marvell International Ltd. 6 **/ 7 8 #include <linux/debugfs.h> 9 #include <linux/slab.h> 10 11 #include <net/bluetooth/bluetooth.h> 12 #include <net/bluetooth/hci_core.h> 13 14 #include "btmrvl_drv.h" 15 16 struct btmrvl_debugfs_data { 17 struct dentry *config_dir; 18 struct dentry *status_dir; 19 }; 20 21 static ssize_t btmrvl_hscfgcmd_write(struct file *file, 22 const char __user *ubuf, size_t count, loff_t *ppos) 23 { 24 struct btmrvl_private *priv = file->private_data; 25 long result, ret; 26 27 ret = kstrtol_from_user(ubuf, count, 10, &result); 28 if (ret) 29 return ret; 30 31 priv->btmrvl_dev.hscfgcmd = result; 32 33 if (priv->btmrvl_dev.hscfgcmd) { 34 btmrvl_prepare_command(priv); 35 wake_up_interruptible(&priv->main_thread.wait_q); 36 } 37 38 return count; 39 } 40 41 static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf, 42 size_t count, loff_t *ppos) 43 { 44 struct btmrvl_private *priv = file->private_data; 45 char buf[16]; 46 int ret; 47 48 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", 49 priv->btmrvl_dev.hscfgcmd); 50 51 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 52 } 53 54 static const struct file_operations btmrvl_hscfgcmd_fops = { 55 .read = btmrvl_hscfgcmd_read, 56 .write = btmrvl_hscfgcmd_write, 57 .open = simple_open, 58 .llseek = default_llseek, 59 }; 60 61 static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, 62 size_t count, loff_t *ppos) 63 { 64 struct btmrvl_private *priv = file->private_data; 65 long result, ret; 66 67 ret = kstrtol_from_user(ubuf, count, 10, &result); 68 if (ret) 69 return ret; 70 71 priv->btmrvl_dev.pscmd = result; 72 73 if (priv->btmrvl_dev.pscmd) { 74 btmrvl_prepare_command(priv); 75 wake_up_interruptible(&priv->main_thread.wait_q); 76 } 77 78 return count; 79 80 } 81 82 static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf, 83 size_t count, loff_t *ppos) 84 { 85 struct btmrvl_private *priv = file->private_data; 86 char buf[16]; 87 int ret; 88 89 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); 90 91 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 92 } 93 94 static const struct file_operations btmrvl_pscmd_fops = { 95 .read = btmrvl_pscmd_read, 96 .write = btmrvl_pscmd_write, 97 .open = simple_open, 98 .llseek = default_llseek, 99 }; 100 101 static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, 102 size_t count, loff_t *ppos) 103 { 104 struct btmrvl_private *priv = file->private_data; 105 long result, ret; 106 107 ret = kstrtol_from_user(ubuf, count, 10, &result); 108 if (ret) 109 return ret; 110 111 priv->btmrvl_dev.hscmd = result; 112 if (priv->btmrvl_dev.hscmd) { 113 btmrvl_prepare_command(priv); 114 wake_up_interruptible(&priv->main_thread.wait_q); 115 } 116 117 return count; 118 } 119 120 static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf, 121 size_t count, loff_t *ppos) 122 { 123 struct btmrvl_private *priv = file->private_data; 124 char buf[16]; 125 int ret; 126 127 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); 128 129 return simple_read_from_buffer(userbuf, count, ppos, buf, ret); 130 } 131 132 static const struct file_operations btmrvl_hscmd_fops = { 133 .read = btmrvl_hscmd_read, 134 .write = btmrvl_hscmd_write, 135 .open = simple_open, 136 .llseek = default_llseek, 137 }; 138 139 void btmrvl_debugfs_init(struct hci_dev *hdev) 140 { 141 struct btmrvl_private *priv = hci_get_drvdata(hdev); 142 struct btmrvl_debugfs_data *dbg; 143 144 if (!hdev->debugfs) 145 return; 146 147 dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); 148 priv->debugfs_data = dbg; 149 150 if (!dbg) { 151 BT_ERR("Can not allocate memory for btmrvl_debugfs_data."); 152 return; 153 } 154 155 dbg->config_dir = debugfs_create_dir("config", hdev->debugfs); 156 157 debugfs_create_u8("psmode", 0644, dbg->config_dir, 158 &priv->btmrvl_dev.psmode); 159 debugfs_create_file("pscmd", 0644, dbg->config_dir, 160 priv, &btmrvl_pscmd_fops); 161 debugfs_create_x16("gpiogap", 0644, dbg->config_dir, 162 &priv->btmrvl_dev.gpio_gap); 163 debugfs_create_u8("hsmode", 0644, dbg->config_dir, 164 &priv->btmrvl_dev.hsmode); 165 debugfs_create_file("hscmd", 0644, dbg->config_dir, 166 priv, &btmrvl_hscmd_fops); 167 debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, 168 priv, &btmrvl_hscfgcmd_fops); 169 170 dbg->status_dir = debugfs_create_dir("status", hdev->debugfs); 171 debugfs_create_u8("curpsmode", 0444, dbg->status_dir, 172 &priv->adapter->psmode); 173 debugfs_create_u8("psstate", 0444, dbg->status_dir, 174 &priv->adapter->ps_state); 175 debugfs_create_u8("hsstate", 0444, dbg->status_dir, 176 &priv->adapter->hs_state); 177 debugfs_create_u8("txdnldready", 0444, dbg->status_dir, 178 &priv->btmrvl_dev.tx_dnld_rdy); 179 } 180 181 void btmrvl_debugfs_remove(struct hci_dev *hdev) 182 { 183 struct btmrvl_private *priv = hci_get_drvdata(hdev); 184 struct btmrvl_debugfs_data *dbg = priv->debugfs_data; 185 186 if (!dbg) 187 return; 188 189 debugfs_remove_recursive(dbg->config_dir); 190 debugfs_remove_recursive(dbg->status_dir); 191 192 kfree(dbg); 193 } 194