Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
0011  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
0013  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
0014  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
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 /* CONFIG_WCN36XX_DEBUGFS */