0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0018
0019 #include <linux/debugfs.h>
0020 #include <linux/uaccess.h>
0021 #include "wcn36xx.h"
0022 #include "debug.h"
0023 #include "pmc.h"
0024 #include "firmware.h"
0025
0026 #ifdef CONFIG_WCN36XX_DEBUGFS
0027
0028 static ssize_t read_file_bool_bmps(struct file *file, char __user *user_buf,
0029 size_t count, loff_t *ppos)
0030 {
0031 struct wcn36xx *wcn = file->private_data;
0032 struct wcn36xx_vif *vif_priv = NULL;
0033 struct ieee80211_vif *vif = NULL;
0034 char buf[3];
0035
0036 list_for_each_entry(vif_priv, &wcn->vif_list, list) {
0037 vif = wcn36xx_priv_to_vif(vif_priv);
0038 if (NL80211_IFTYPE_STATION == vif->type) {
0039 if (vif_priv->pw_state == WCN36XX_BMPS)
0040 buf[0] = '1';
0041 else
0042 buf[0] = '0';
0043 break;
0044 }
0045 }
0046 buf[1] = '\n';
0047 buf[2] = 0x00;
0048
0049 return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
0050 }
0051
0052 static ssize_t write_file_bool_bmps(struct file *file,
0053 const char __user *user_buf,
0054 size_t count, loff_t *ppos)
0055 {
0056 struct wcn36xx *wcn = file->private_data;
0057 struct wcn36xx_vif *vif_priv = NULL;
0058 struct ieee80211_vif *vif = NULL;
0059
0060 char buf[32];
0061 int buf_size;
0062
0063 buf_size = min(count, (sizeof(buf)-1));
0064 if (copy_from_user(buf, user_buf, buf_size))
0065 return -EFAULT;
0066
0067 switch (buf[0]) {
0068 case 'y':
0069 case 'Y':
0070 case '1':
0071 list_for_each_entry(vif_priv, &wcn->vif_list, list) {
0072 vif = wcn36xx_priv_to_vif(vif_priv);
0073 if (NL80211_IFTYPE_STATION == vif->type) {
0074 wcn36xx_enable_keep_alive_null_packet(wcn, vif);
0075 wcn36xx_pmc_enter_bmps_state(wcn, vif);
0076 }
0077 }
0078 break;
0079 case 'n':
0080 case 'N':
0081 case '0':
0082 list_for_each_entry(vif_priv, &wcn->vif_list, list) {
0083 vif = wcn36xx_priv_to_vif(vif_priv);
0084 if (NL80211_IFTYPE_STATION == vif->type)
0085 wcn36xx_pmc_exit_bmps_state(wcn, vif);
0086 }
0087 break;
0088 }
0089
0090 return count;
0091 }
0092
0093 static const struct file_operations fops_wcn36xx_bmps = {
0094 .open = simple_open,
0095 .read = read_file_bool_bmps,
0096 .write = write_file_bool_bmps,
0097 };
0098
0099 static ssize_t write_file_dump(struct file *file,
0100 const char __user *user_buf,
0101 size_t count, loff_t *ppos)
0102 {
0103 struct wcn36xx *wcn = file->private_data;
0104 char buf[255], *tmp;
0105 int buf_size;
0106 u32 arg[WCN36xx_MAX_DUMP_ARGS];
0107 int i;
0108
0109 memset(buf, 0, sizeof(buf));
0110 memset(arg, 0, sizeof(arg));
0111
0112 buf_size = min(count, (sizeof(buf) - 1));
0113 if (copy_from_user(buf, user_buf, buf_size))
0114 return -EFAULT;
0115
0116 tmp = buf;
0117
0118 for (i = 0; i < WCN36xx_MAX_DUMP_ARGS; i++) {
0119 char *begin;
0120 begin = strsep(&tmp, " ");
0121 if (begin == NULL)
0122 break;
0123
0124 if (kstrtos32(begin, 0, &arg[i]) != 0)
0125 break;
0126 }
0127
0128 wcn36xx_info("DUMP args is %d %d %d %d %d\n", arg[0], arg[1], arg[2],
0129 arg[3], arg[4]);
0130 wcn36xx_smd_dump_cmd_req(wcn, arg[0], arg[1], arg[2], arg[3], arg[4]);
0131
0132 return count;
0133 }
0134
0135 static const struct file_operations fops_wcn36xx_dump = {
0136 .open = simple_open,
0137 .write = write_file_dump,
0138 };
0139
0140 static ssize_t read_file_firmware_feature_caps(struct file *file,
0141 char __user *user_buf,
0142 size_t count, loff_t *ppos)
0143 {
0144 struct wcn36xx *wcn = file->private_data;
0145 size_t len = 0, buf_len = 2048;
0146 char *buf;
0147 int i;
0148 int ret;
0149
0150 buf = kzalloc(buf_len, GFP_KERNEL);
0151 if (!buf)
0152 return -ENOMEM;
0153
0154 mutex_lock(&wcn->hal_mutex);
0155 for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
0156 if (wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, i)) {
0157 len += scnprintf(buf + len, buf_len - len, "%s\n",
0158 wcn36xx_firmware_get_cap_name(i));
0159 }
0160 if (len >= buf_len)
0161 break;
0162 }
0163 mutex_unlock(&wcn->hal_mutex);
0164
0165 ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
0166 kfree(buf);
0167
0168 return ret;
0169 }
0170
0171 static const struct file_operations fops_wcn36xx_firmware_feat_caps = {
0172 .open = simple_open,
0173 .read = read_file_firmware_feature_caps,
0174 };
0175
0176 #define ADD_FILE(name, mode, fop, priv_data) \
0177 do { \
0178 struct dentry *d; \
0179 d = debugfs_create_file(__stringify(name), \
0180 mode, dfs->rootdir, \
0181 priv_data, fop); \
0182 dfs->file_##name.dentry = d; \
0183 if (IS_ERR(d)) { \
0184 wcn36xx_warn("Create the debugfs entry failed");\
0185 dfs->file_##name.dentry = NULL; \
0186 } \
0187 } while (0)
0188
0189
0190 void wcn36xx_debugfs_init(struct wcn36xx *wcn)
0191 {
0192 struct wcn36xx_dfs_entry *dfs = &wcn->dfs;
0193
0194 dfs->rootdir = debugfs_create_dir(KBUILD_MODNAME,
0195 wcn->hw->wiphy->debugfsdir);
0196 if (IS_ERR(dfs->rootdir)) {
0197 wcn36xx_warn("Create the debugfs failed\n");
0198 dfs->rootdir = NULL;
0199 }
0200
0201 ADD_FILE(bmps_switcher, 0600, &fops_wcn36xx_bmps, wcn);
0202 ADD_FILE(dump, 0200, &fops_wcn36xx_dump, wcn);
0203 ADD_FILE(firmware_feat_caps, 0200,
0204 &fops_wcn36xx_firmware_feat_caps, wcn);
0205 }
0206
0207 void wcn36xx_debugfs_exit(struct wcn36xx *wcn)
0208 {
0209 struct wcn36xx_dfs_entry *dfs = &wcn->dfs;
0210 debugfs_remove_recursive(dfs->rootdir);
0211 }
0212
0213 #endif