xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/ssv6xxx/ssvdevice/ssvdevice.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
3  * Copyright (c) 2015 iComm Corporation
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU General Public License for more details.
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18 #include <linux/kernel.h>
19 #include <linux/version.h>
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/slab.h>
23 #include <linux/proc_fs.h>
24 #include <linux/uaccess.h>
25 #include <linux/errno.h>
26 #ifdef CONFIG_DEBUG_FS
27 #include <linux/debugfs.h>
28 #endif
29 #include "ssv_cmd.h"
30 #include "ssv_cfg.h"
31 #include <linux/fs.h>
32 #include <asm/segment.h>
33 #include <linux/uaccess.h>
34 #include <linux/buffer_head.h>
35 #include <linux/ctype.h>
36 MODULE_AUTHOR("iComm Semiconductor Co., Ltd");
37 MODULE_DESCRIPTION("Shared library for SSV wireless LAN cards.");
38 MODULE_LICENSE("Dual BSD/GPL");
39 static char *stacfgpath = NULL;
40 EXPORT_SYMBOL(stacfgpath);
41 module_param(stacfgpath, charp, 0000);
42 MODULE_PARM_DESC(stacfgpath, "Get path of sta cfg");
43 char *cfgfirmwarepath = NULL;
44 EXPORT_SYMBOL(cfgfirmwarepath);
45 module_param(cfgfirmwarepath, charp, 0000);
46 MODULE_PARM_DESC(cfgfirmwarepath, "Get firmware path");
47 char* ssv_initmac = NULL;
48 EXPORT_SYMBOL(ssv_initmac);
49 module_param(ssv_initmac, charp, 0644);
50 MODULE_PARM_DESC(ssv_initmac, "Wi-Fi MAC address");
51 u32 ssv_devicetype = 0;
52 EXPORT_SYMBOL(ssv_devicetype);
53 #ifdef CONFIG_DEBUG_FS
54 static struct dentry *debugfs;
55 #endif
56 struct proc_dir_entry *procfs;
57 static char *ssv6xxx_cmd_buf;
58 char *ssv6xxx_result_buf;
59 extern struct ssv6xxx_cfg_cmd_table cfg_cmds[];
60 extern struct ssv6xxx_cfg ssv_cfg;
61 char DEFAULT_CFG_PATH[] = "/vendor/etc/firmware/ssv6051-wifi.cfg";
ssv6xxx_dbg_open(struct inode * inode,struct file * filp)62 static int ssv6xxx_dbg_open(struct inode *inode, struct file *filp)
63 {
64     filp->private_data = inode->i_private;
65     return 0;
66 }
ssv6xxx_dbg_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)67 static ssize_t ssv6xxx_dbg_read(struct file *filp, char __user *buffer,
68                 size_t count, loff_t *ppos)
69 {
70     int len;
71     if (*ppos != 0)
72         return 0;
73     len = strlen(ssv6xxx_result_buf) + 1;
74     if (len == 1)
75         return 0;
76     if (copy_to_user(buffer, ssv6xxx_result_buf, len))
77         return -EFAULT;
78     ssv6xxx_result_buf[0] = 0x00;
79     return len;
80 }
ssv6xxx_dbg_write(struct file * filp,const char __user * buffer,size_t count,loff_t * ppos)81 static ssize_t ssv6xxx_dbg_write(struct file *filp, const char __user *buffer,
82                 size_t count, loff_t *ppos)
83 {
84     if (*ppos != 0 || count > 255)
85         return 0;
86     if (copy_from_user(ssv6xxx_cmd_buf, buffer, count))
87         return -EFAULT;
88     ssv6xxx_cmd_buf[count-1] = 0x00;
89     ssv_cmd_submit(ssv6xxx_cmd_buf);
90     return count;
91 }
read_line(struct file * fp,char * buf,size_t size)92 size_t read_line(struct file *fp, char *buf, size_t size)
93 {
94  size_t num_read = 0;
95  size_t total_read = 0;
96  char *buffer;
97  char ch;
98  size_t start_ignore = 0;
99  if (size <= 0 || buf == NULL) {
100   total_read = -EINVAL;
101   return -EINVAL;
102  }
103  buffer = buf;
104  for (;;) {
105 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,37)
106   if (fp->f_op && fp->f_op->read)
107    num_read = fp->f_op->read(fp, &ch, 1, &fp->f_pos);
108 #else
109   num_read = vfs_read(fp, &ch, 1, &fp->f_pos);
110 #endif
111   if (num_read < 0) {
112    if (num_read == EINTR)
113     continue;
114    else
115     return -1;
116   }
117   else if (num_read == 0) {
118    if (total_read == 0)
119     return 0;
120    else
121     break;
122   }
123   else {
124    if (ch == '#')
125     start_ignore = 1;
126    if (total_read < size - 1) {
127     total_read++;
128     if (start_ignore)
129      *buffer++ = '\0';
130     else
131      *buffer++ = ch;
132    }
133    if (ch == '\n')
134     break;
135   }
136  }
137  *buffer = '\0';
138  return total_read;
139 }
ischar(char * c)140 int ischar(char *c)
141 {
142  int is_char = 1;
143  while(*c) {
144   if (isalpha(*c) || isdigit(*c) || *c == '_' || *c == ':' || *c == '/' || *c == '.' || *c == '-')
145    c++;
146   else {
147    is_char = 0;
148    break;
149   }
150  }
151  return is_char;
152 }
sta_cfg_set(char * stacfgpath)153 void sta_cfg_set(char *stacfgpath)
154 {
155  struct file *fp = (struct file *) NULL;
156  char buf[MAX_CHARS_PER_LINE], cfg_cmd[32], cfg_value[32];
157  mm_segment_t fs;
158  size_t s, read_len = 0, is_cmd_support = 0;
159  printk("\n*** %s, %s ***\n\n", __func__, stacfgpath);
160     if (stacfgpath == NULL) {
161         stacfgpath = DEFAULT_CFG_PATH;
162         printk("redirect to %s\n", stacfgpath);
163     }
164  memset(&ssv_cfg, 0, sizeof(ssv_cfg));
165  memset(buf, 0, sizeof(buf));
166  fp = filp_open(stacfgpath, O_RDONLY, 0);
167  if (IS_ERR(fp) || fp == NULL) {
168   printk("ERROR: filp_open\n");
169         WARN_ON(1);
170   return;
171  }
172  if (fp->f_path.dentry == NULL) {
173   printk("ERROR: dentry NULL\n");
174         WARN_ON(1);
175   return;
176  }
177  do {
178   memset(cfg_cmd, '\0', sizeof(cfg_cmd));
179   memset(cfg_value, '\0', sizeof(cfg_value));
180   fs = get_fs();
181   set_fs(KERNEL_DS);
182   read_len = read_line(fp, buf, MAX_CHARS_PER_LINE);
183   set_fs(fs);
184   sscanf(buf, "%s = %s", cfg_cmd, cfg_value);
185   if (!ischar(cfg_cmd) || !ischar(cfg_value)) {
186    printk("ERORR invalid parameter: %s\n", buf);
187    WARN_ON(1);
188    continue;
189   }
190   is_cmd_support = 0;
191   for(s=0; cfg_cmds[s].cfg_cmd != NULL; s++) {
192    if (strcmp(cfg_cmds[s].cfg_cmd, cfg_cmd)==0) {
193     cfg_cmds[s].translate_func(cfg_value,
194      cfg_cmds[s].var, cfg_cmds[s].arg);
195     is_cmd_support = 1;
196     break;
197    }
198   }
199   if (!is_cmd_support && strlen(cfg_cmd) > 0) {
200    printk("ERROR Unsupported command: %s", cfg_cmd);
201    WARN_ON(1);
202   }
203  } while (read_len > 0);
204  filp_close(fp, NULL);
205 }
206 static struct file_operations ssv6xxx_dbg_fops = {
207     .owner = THIS_MODULE,
208     .open = ssv6xxx_dbg_open,
209     .read = ssv6xxx_dbg_read,
210     .write = ssv6xxx_dbg_write,
211 };
212 #if (defined(CONFIG_SSV_SUPPORT_ANDROID)||defined(CONFIG_SSV_BUILD_AS_ONE_KO))
213 extern int ssv6xxx_hci_init(void);
214 extern void ssv6xxx_hci_exit(void);
215 extern int ssv6xxx_init(void);
216 extern void ssv6xxx_exit(void);
217 extern int ssv6xxx_sdio_init(void);
218 extern void ssv6xxx_sdio_exit(void);
219 #endif
220 #if (defined(CONFIG_SSV_SUPPORT_ANDROID)||defined(CONFIG_SSV_BUILD_AS_ONE_KO))
ssvdevice_init(void)221 int ssvdevice_init(void)
222 #else
223 static int __init ssvdevice_init(void)
224 #endif
225 {
226     ssv6xxx_cmd_buf = (char *)kzalloc(CLI_BUFFER_SIZE+CLI_RESULT_BUF_SIZE, GFP_KERNEL);
227     if (!ssv6xxx_cmd_buf)
228         return -ENOMEM;
229     ssv6xxx_result_buf = ssv6xxx_cmd_buf+CLI_BUFFER_SIZE;
230     ssv6xxx_cmd_buf[0] = 0x00;
231     ssv6xxx_result_buf[0] = 0x00;
232 #ifdef CONFIG_DEBUG_FS
233     debugfs = debugfs_create_dir(DEBUG_DIR_ENTRY,
234          NULL);
235  if (!debugfs)
236   return -ENOMEM;
237  debugfs_create_u32(DEBUG_DEVICETYPE_ENTRY, S_IRUGO|S_IWUSR, debugfs, &ssv_devicetype);
238     debugfs_create_file(DEBUG_CMD_ENTRY, S_IRUGO|S_IWUSR, debugfs, NULL, &ssv6xxx_dbg_fops);
239 #endif
240  procfs = proc_mkdir(DEBUG_DIR_ENTRY, NULL);
241  if (!procfs)
242   return -ENOMEM;
243     proc_create(DEBUG_CMD_ENTRY, S_IRUGO|S_IWUGO, procfs, &ssv6xxx_dbg_fops);
244  sta_cfg_set(stacfgpath);
245 #if (defined(CONFIG_SSV_SUPPORT_ANDROID)||defined(CONFIG_SSV_BUILD_AS_ONE_KO))
246     {
247         int ret;
248         ret = ssv6xxx_hci_init();
249         if(!ret){
250             ret = ssv6xxx_init();
251         }if(!ret){
252             ret = ssv6xxx_sdio_init();
253         }
254         return ret;
255     }
256 #endif
257     return 0;
258 }
259 #if (defined(CONFIG_SSV_SUPPORT_ANDROID)||defined(CONFIG_SSV_BUILD_AS_ONE_KO))
ssvdevice_exit(void)260 void ssvdevice_exit(void)
261 #else
262 static void __exit ssvdevice_exit(void)
263 #endif
264 {
265 #if (defined(CONFIG_SSV_SUPPORT_ANDROID)||defined(CONFIG_SSV_BUILD_AS_ONE_KO))
266     ssv6xxx_exit();
267     ssv6xxx_hci_exit();
268     ssv6xxx_sdio_exit();
269 #endif
270 #ifdef CONFIG_DEBUG_FS
271     debugfs_remove_recursive(debugfs);
272 #endif
273  remove_proc_entry(DEBUG_CMD_ENTRY, procfs);
274  remove_proc_entry(DEBUG_DIR_ENTRY, NULL);
275     kfree(ssv6xxx_cmd_buf);
276 }
277 #if (defined(CONFIG_SSV_SUPPORT_ANDROID)||defined(CONFIG_SSV_BUILD_AS_ONE_KO))
278 EXPORT_SYMBOL(ssvdevice_init);
279 EXPORT_SYMBOL(ssvdevice_exit);
280 #else
281 module_init(ssvdevice_init);
282 module_exit(ssvdevice_exit);
283 module_param_named(devicetype,ssv_devicetype, uint , S_IRUSR | S_IWUSR);
284 MODULE_PARM_DESC(devicetype, "Enable sdio bridge Mode/Wifi Mode.");
285 #endif
286