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