import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / combo / common / linux / wmt_chrdev_wifi.c
1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/types.h>
4 #include <linux/kernel.h>
5 #include <linux/fs.h>
6 #include <linux/cdev.h>
7 #include <linux/sched.h>
8 #include <asm/current.h>
9 #include <asm/uaccess.h>
10 #include <linux/fcntl.h>
11 #include <linux/poll.h>
12 #include <linux/time.h>
13 #include <linux/delay.h>
14 #include <linux/netdevice.h>
15 #include <net/net_namespace.h>
16 #include <linux/string.h>
17
18 #include "wmt_exp.h"
19 #include "stp_exp.h"
20
21
22 MODULE_LICENSE("Dual BSD/GPL");
23
24 #define WIFI_DRIVER_NAME "mtk_wmt_WIFI_chrdev"
25 #define WIFI_DEV_MAJOR 153
26
27 #define PFX "[MTK-WIFI] "
28 #define WIFI_LOG_DBG 3
29 #define WIFI_LOG_INFO 2
30 #define WIFI_LOG_WARN 1
31 #define WIFI_LOG_ERR 0
32
33 UINT32 gDbgLevel = WIFI_LOG_DBG;
34
35 #define WIFI_DBG_FUNC(fmt, arg...)\
36 do {if (gDbgLevel >= WIFI_LOG_DBG) pr_warn(PFX "%s: " fmt, __func__ , ##arg); } while (0)
37 #define WIFI_INFO_FUNC(fmt, arg...)\
38 do {if (gDbgLevel >= WIFI_LOG_INFO) pr_warn(PFX "%s: " fmt, __func__ , ##arg); } while (0)
39 #define WIFI_WARN_FUNC(fmt, arg...)\
40 do {if (gDbgLevel >= WIFI_LOG_WARN) pr_warn(PFX "%s: " fmt, __func__ , ##arg); } while (0)
41 #define WIFI_ERR_FUNC(fmt, arg...)\
42 do {if (gDbgLevel >= WIFI_LOG_ERR) pr_warn(PFX "%s: " fmt, __func__ , ##arg); } while (0)
43 #define WIFI_TRC_FUNC(f)\
44 do {if (gDbgLevel >= WIFI_LOG_DBG) pr_warn(PFX "<%s> <%d>\n", __func__, __LINE__); } while (0)
45
46 #define VERSION "1.0"
47
48
49 #define WLAN_IFACE_NAME "wlan0"
50
51 enum {
52 WLAN_MODE_HALT,
53 WLAN_MODE_AP,
54 WLAN_MODE_STA_P2P,
55 WLAN_MODE_MAX
56 };
57 static INT32 wlan_mode = WLAN_MODE_HALT;
58 static INT32 powered;
59
60 typedef enum _ENUM_RESET_STATUS_T {
61 RESET_FAIL,
62 RESET_SUCCESS
63 } ENUM_RESET_STATUS_T;
64
65 /*
66 * enable = 1, mode = 0 => init P2P network
67 * enable = 1, mode = 1 => init Soft AP network
68 * enable = 0 => uninit P2P/AP network
69 */
70 typedef struct _PARAM_CUSTOM_P2P_SET_STRUC_T {
71 UINT32 u4Enable;
72 UINT32 u4Mode;
73 } PARAM_CUSTOM_P2P_SET_STRUC_T, *P_PARAM_CUSTOM_P2P_SET_STRUC_T;
74 typedef INT32 (*set_p2p_mode) (struct net_device *netdev, PARAM_CUSTOM_P2P_SET_STRUC_T p2pmode);
75
76 static set_p2p_mode pf_set_p2p_mode;
77 VOID register_set_p2p_mode_handler(set_p2p_mode handler) {
78 WIFI_INFO_FUNC("(pid %d) register set p2p mode handler %p\n", current->pid, handler);
79 pf_set_p2p_mode = handler;
80 }
81 EXPORT_SYMBOL(register_set_p2p_mode_handler);
82
83 /* For dynamical debug level setting */
84 /* copy of debug.h in wlan driver */
85 #define DBG_CLASS_ERROR BIT(0)
86 #define DBG_CLASS_WARN BIT(1)
87 #define DBG_CLASS_STATE BIT(2)
88 #define DBG_CLASS_EVENT BIT(3)
89 #define DBG_CLASS_TRACE BIT(4)
90 #define DBG_CLASS_INFO BIT(5)
91 #define DBG_CLASS_LOUD BIT(6)
92 #define DBG_CLASS_TEMP BIT(7)
93 #define DBG_CLASS_MASK BITS(0, 7)
94
95 typedef enum _ENUM_DBG_MODULE_T {
96 DBG_INIT_IDX = 0, /* For driver initial */
97 DBG_HAL_IDX, /* For HAL(HW) Layer */
98 DBG_INTR_IDX, /* For Interrupt */
99 DBG_REQ_IDX,
100 DBG_TX_IDX,
101 DBG_RX_IDX,
102 DBG_RFTEST_IDX, /* For RF test mode */
103 DBG_EMU_IDX, /* Developer specific */
104
105 DBG_SW1_IDX, /* Developer specific */
106 DBG_SW2_IDX, /* Developer specific */
107 DBG_SW3_IDX, /* Developer specific */
108 DBG_SW4_IDX, /* Developer specific */
109
110 DBG_HEM_IDX, /* HEM */
111 DBG_AIS_IDX, /* AIS */
112 DBG_RLM_IDX, /* RLM */
113 DBG_MEM_IDX, /* RLM */
114 DBG_CNM_IDX, /* CNM */
115 DBG_RSN_IDX, /* RSN */
116 DBG_BSS_IDX, /* BSS */
117 DBG_SCN_IDX, /* SCN */
118 DBG_SAA_IDX, /* SAA */
119 DBG_AAA_IDX, /* AAA */
120 DBG_P2P_IDX, /* P2P */
121 DBG_QM_IDX, /* QUE_MGT */
122 DBG_SEC_IDX, /* SEC */
123 DBG_BOW_IDX, /* BOW */
124 DBG_WAPI_IDX, /* WAPI */
125 DBG_ROAMING_IDX, /* ROAMING */
126
127 DBG_MODULE_NUM /* Notice the X-LOG check */
128 } ENUM_DBG_MODULE_T;
129 /* end */
130 typedef VOID (*set_dbg_level) (UINT8 modules[DBG_MODULE_NUM]);
131
132 UINT8 wlan_dbg_level[DBG_MODULE_NUM];
133 static set_dbg_level pf_set_dbg_level;
134 VOID register_set_dbg_level_handler(set_dbg_level handler) {
135 pf_set_dbg_level = handler;
136 }
137 EXPORT_SYMBOL(register_set_dbg_level_handler);
138
139
140 static INT32 WIFI_devs = 1;
141 static INT32 WIFI_major = WIFI_DEV_MAJOR;
142 module_param(WIFI_major, uint, 0);
143 static struct cdev WIFI_cdev;
144 volatile INT32 retflag = 0;
145 static struct semaphore wr_mtx;
146
147
148 /*******************************************************************
149 * WHOLE CHIP RESET PROCEDURE:
150 *
151 * WMTRSTMSG_RESET_START callback
152 * -> wlanRemove
153 * -> WMTRSTMSG_RESET_END callback
154 *
155 *******************************************************************
156 */
157 /*-----------------------------------------------------------------*/
158 /*
159 * Receiving RESET_START message
160 */
161 /*-----------------------------------------------------------------*/
162 INT32 wifi_reset_start(VOID)
163 {
164 struct net_device *netdev = NULL;
165 PARAM_CUSTOM_P2P_SET_STRUC_T p2pmode;
166
167 down(&wr_mtx);
168
169 if (powered == 1) {
170 netdev = dev_get_by_name(&init_net, WLAN_IFACE_NAME);
171 if (netdev == NULL) {
172 WIFI_ERR_FUNC("Fail to get wlan0 net device\n");
173 } else {
174 p2pmode.u4Enable = 0;
175 p2pmode.u4Mode = 0;
176
177 if (pf_set_p2p_mode) {
178 if (pf_set_p2p_mode(netdev, p2pmode) != 0) {
179 WIFI_ERR_FUNC("Turn off p2p/ap mode fail");
180 } else {
181 WIFI_INFO_FUNC("Turn off p2p/ap mode");
182 }
183 }
184 dev_put(netdev);
185 netdev = NULL;
186 }
187 } else {
188 /* WIFI is off before whole chip reset, do nothing */
189 }
190
191 return 0;
192 }
193 EXPORT_SYMBOL(wifi_reset_start);
194
195 /*-----------------------------------------------------------------*/
196 /*
197 * Receiving RESET_END/RESET_END_FAIL message
198 */
199 /*-----------------------------------------------------------------*/
200 INT32 wifi_reset_end(ENUM_RESET_STATUS_T status)
201 {
202 struct net_device *netdev = NULL;
203 PARAM_CUSTOM_P2P_SET_STRUC_T p2pmode;
204 INT32 wait_cnt = 0;
205 INT32 ret = -1;
206
207 if (status == RESET_FAIL) {
208 /* whole chip reset fail, donot recover WIFI */
209 ret = 0;
210 up(&wr_mtx);
211 } else if (status == RESET_SUCCESS) {
212 WIFI_WARN_FUNC("WIFI state recovering...\n");
213
214 if (powered == 1) {
215 /* WIFI is on before whole chip reset, reopen it now */
216 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) {
217 WIFI_ERR_FUNC("WMT turn on WIFI fail!\n");
218 goto done;
219 } else {
220 WIFI_INFO_FUNC("WMT turn on WIFI success!\n");
221 }
222
223 if (pf_set_p2p_mode == NULL) {
224 WIFI_ERR_FUNC("Set p2p mode handler is NULL\n");
225 goto done;
226 }
227
228 netdev = dev_get_by_name(&init_net, WLAN_IFACE_NAME);
229 while (netdev == NULL && wait_cnt < 10) {
230 WIFI_ERR_FUNC("Fail to get wlan0 net device, sleep 300ms\n");
231 msleep(300);
232 wait_cnt++;
233 netdev = dev_get_by_name(&init_net, WLAN_IFACE_NAME);
234 }
235 if (wait_cnt >= 10) {
236 WIFI_ERR_FUNC("Get wlan0 net device timeout\n");
237 goto done;
238 }
239
240 if (wlan_mode == WLAN_MODE_STA_P2P) {
241 p2pmode.u4Enable = 1;
242 p2pmode.u4Mode = 0;
243 if (pf_set_p2p_mode(netdev, p2pmode) != 0) {
244 WIFI_ERR_FUNC("Set wlan mode fail\n");
245 } else {
246 WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_STA_P2P);
247 ret = 0;
248 }
249 } else if (wlan_mode == WLAN_MODE_AP) {
250 p2pmode.u4Enable = 1;
251 p2pmode.u4Mode = 1;
252 if (pf_set_p2p_mode(netdev, p2pmode) != 0) {
253 WIFI_ERR_FUNC("Set wlan mode fail\n");
254 } else {
255 WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_AP);
256 ret = 0;
257 }
258 }
259 done:
260 if (netdev != NULL) {
261 dev_put(netdev);
262 }
263 } else {
264 /* WIFI is off before whole chip reset, do nothing */
265 ret = 0;
266 }
267 up(&wr_mtx);
268 }
269
270 return ret;
271 }
272 EXPORT_SYMBOL(wifi_reset_end);
273
274
275 static int WIFI_open(struct inode *inode, struct file *file)
276 {
277 WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__,
278 imajor(inode), iminor(inode), current->pid);
279
280 return 0;
281 }
282
283 static int WIFI_close(struct inode *inode, struct file *file)
284 {
285 WIFI_INFO_FUNC("%s: major %d minor %d (pid %d)\n", __func__,
286 imajor(inode), iminor(inode), current->pid);
287 retflag = 0;
288
289 return 0;
290 }
291
292 ssize_t WIFI_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
293 {
294 INT32 retval = -EIO;
295 INT8 local[12] = { 0 };
296 struct net_device *netdev = NULL;
297 PARAM_CUSTOM_P2P_SET_STRUC_T p2pmode;
298 INT32 wait_cnt = 0;
299
300 down(&wr_mtx);
301 if (count <= 0) {
302 WIFI_ERR_FUNC("WIFI_write invalid param\n");
303 goto done;
304 }
305
306 if (0 == copy_from_user(local, buf, (count > sizeof(local)) ? sizeof(local) : count)) {
307 local[11] = 0;
308 WIFI_INFO_FUNC("WIFI_write %s\n", local);
309
310 if (local[0] == '0') {
311 if (powered == 0) {
312 WIFI_INFO_FUNC("WIFI is already power off!\n");
313 retval = count;
314 wlan_mode = WLAN_MODE_HALT;
315 goto done;
316 }
317
318 netdev = dev_get_by_name(&init_net, WLAN_IFACE_NAME);
319 if (netdev == NULL) {
320 WIFI_ERR_FUNC("Fail to get wlan0 net device\n");
321 } else {
322 p2pmode.u4Enable = 0;
323 p2pmode.u4Mode = 0;
324
325 if (pf_set_p2p_mode) {
326 if (pf_set_p2p_mode(netdev, p2pmode) != 0) {
327 WIFI_ERR_FUNC("Turn off p2p/ap mode fail");
328 } else {
329 WIFI_INFO_FUNC("Turn off p2p/ap mode");
330 wlan_mode = WLAN_MODE_HALT;
331 }
332 }
333 dev_put(netdev);
334 netdev = NULL;
335 }
336
337 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI)) {
338 WIFI_ERR_FUNC("WMT turn off WIFI fail!\n");
339 } else {
340 WIFI_INFO_FUNC("WMT turn off WIFI OK!\n");
341 powered = 0;
342 retval = count;
343 wlan_mode = WLAN_MODE_HALT;
344 }
345 } else if (local[0] == '1') {
346 if (powered == 1) {
347 WIFI_INFO_FUNC("WIFI is already power on!\n");
348 retval = count;
349 goto done;
350 }
351
352 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) {
353 WIFI_ERR_FUNC("WMT turn on WIFI fail!\n");
354 } else {
355 powered = 1;
356 retval = count;
357 WIFI_INFO_FUNC("WMT turn on WIFI success!\n");
358 wlan_mode = WLAN_MODE_HALT;
359 }
360 } else if (local[0] == 'D') {
361 INT32 k = 0;
362 /*
363 * 0: no debug
364 * 1: common debug output
365 * 2: more detials
366 * 3: verbose
367 */
368 switch (local[1]) {
369 case '0':
370 for (k = 0; k < DBG_MODULE_NUM; k++) {
371 wlan_dbg_level[k] = 0;
372 }
373 if (pf_set_dbg_level) {
374 pf_set_dbg_level(wlan_dbg_level);
375 }
376 break;
377 case '1':
378 for (k = 0; k < DBG_MODULE_NUM; k++) {
379 wlan_dbg_level[k] = DBG_CLASS_ERROR |
380 DBG_CLASS_WARN |
381 DBG_CLASS_STATE |
382 DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO;
383 }
384 wlan_dbg_level[DBG_TX_IDX] &= ~(DBG_CLASS_EVENT |
385 DBG_CLASS_TRACE | DBG_CLASS_INFO);
386 wlan_dbg_level[DBG_RX_IDX] &= ~(DBG_CLASS_EVENT |
387 DBG_CLASS_TRACE | DBG_CLASS_INFO);
388 wlan_dbg_level[DBG_REQ_IDX] &= ~(DBG_CLASS_EVENT |
389 DBG_CLASS_TRACE | DBG_CLASS_INFO);
390 wlan_dbg_level[DBG_INTR_IDX] = 0;
391 wlan_dbg_level[DBG_MEM_IDX] = 0;
392 if (pf_set_dbg_level) {
393 pf_set_dbg_level(wlan_dbg_level);
394 }
395 break;
396 case '2':
397 for (k = 0; k < DBG_MODULE_NUM; k++) {
398 wlan_dbg_level[k] = DBG_CLASS_ERROR |
399 DBG_CLASS_WARN |
400 DBG_CLASS_STATE |
401 DBG_CLASS_EVENT | DBG_CLASS_TRACE | DBG_CLASS_INFO;
402 }
403 wlan_dbg_level[DBG_INTR_IDX] = 0;
404 wlan_dbg_level[DBG_MEM_IDX] = 0;
405 if (pf_set_dbg_level) {
406 pf_set_dbg_level(wlan_dbg_level);
407 }
408 break;
409 case '3':
410 for (k = 0; k < DBG_MODULE_NUM; k++) {
411 wlan_dbg_level[k] = DBG_CLASS_ERROR |
412 DBG_CLASS_WARN |
413 DBG_CLASS_STATE |
414 DBG_CLASS_EVENT |
415 DBG_CLASS_TRACE | DBG_CLASS_INFO | DBG_CLASS_LOUD;
416 }
417 if (pf_set_dbg_level) {
418 pf_set_dbg_level(wlan_dbg_level);
419 }
420 break;
421 default:
422 break;
423 }
424 } else if (local[0] == 'S' || local[0] == 'P' || local[0] == 'A') {
425 if (powered == 0) {
426 /* If WIFI is off, turn on WIFI first */
427 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI)) {
428 WIFI_ERR_FUNC("WMT turn on WIFI fail!\n");
429 goto done;
430 } else {
431 powered = 1;
432 WIFI_INFO_FUNC("WMT turn on WIFI success!\n");
433 wlan_mode = WLAN_MODE_HALT;
434 }
435 }
436
437 if (pf_set_p2p_mode == NULL) {
438 WIFI_ERR_FUNC("Set p2p mode handler is NULL\n");
439 goto done;
440 }
441
442 netdev = dev_get_by_name(&init_net, WLAN_IFACE_NAME);
443 while (netdev == NULL && wait_cnt < 10) {
444 WIFI_ERR_FUNC("Fail to get wlan0 net device, sleep 300ms\n");
445 msleep(300);
446 wait_cnt++;
447 netdev = dev_get_by_name(&init_net, WLAN_IFACE_NAME);
448 }
449 if (wait_cnt >= 10) {
450 WIFI_ERR_FUNC("Get wlan0 net device timeout\n");
451 goto done;
452 }
453
454 if ((wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'S' || local[0] == 'P')) ||
455 (wlan_mode == WLAN_MODE_AP && (local[0] == 'A'))){
456 WIFI_INFO_FUNC("WIFI is already in mode %d!\n", wlan_mode);
457 retval = count;
458 goto done;
459 }
460
461 if ((wlan_mode == WLAN_MODE_AP && (local[0] == 'S' || local[0] == 'P')) ||
462 (wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'A'))) {
463 p2pmode.u4Enable = 0;
464 p2pmode.u4Mode = 0;
465 if (pf_set_p2p_mode(netdev, p2pmode) != 0) {
466 WIFI_ERR_FUNC("Turn off p2p/ap mode fail");
467 goto done;
468 }
469 }
470
471 if (local[0] == 'S' || local[0] == 'P') {
472 p2pmode.u4Enable = 1;
473 p2pmode.u4Mode = 0;
474 if (pf_set_p2p_mode(netdev, p2pmode) != 0) {
475 WIFI_ERR_FUNC("Set wlan mode fail\n");
476 } else {
477 WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode,
478 WLAN_MODE_STA_P2P);
479 wlan_mode = WLAN_MODE_STA_P2P;
480 retval = count;
481 }
482 } else if (local[0] == 'A') {
483 p2pmode.u4Enable = 1;
484 p2pmode.u4Mode = 1;
485 if (pf_set_p2p_mode(netdev, p2pmode) != 0) {
486 WIFI_ERR_FUNC("Set wlan mode fail\n");
487 } else {
488 WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode,
489 WLAN_MODE_AP);
490 wlan_mode = WLAN_MODE_AP;
491 retval = count;
492 }
493 }
494 dev_put(netdev);
495 netdev = NULL;
496 }
497 }
498 done:
499 if (netdev != NULL) {
500 dev_put(netdev);
501 }
502 up(&wr_mtx);
503 return (retval);
504 }
505
506
507 struct file_operations WIFI_fops = {
508 .open = WIFI_open,
509 .release = WIFI_close,
510 .write = WIFI_write,
511 };
512
513
514 #if REMOVE_MK_NODE
515 struct class *wmtWifi_class = NULL;
516 #endif
517
518
519 static int WIFI_init(void)
520 {
521 dev_t dev = MKDEV(WIFI_major, 0);
522 INT32 alloc_ret = 0;
523 INT32 cdev_err = 0;
524 #if REMOVE_MK_NODE
525 struct device *wmtWifi_dev = NULL;
526 #endif
527 /*static allocate chrdev */
528 alloc_ret = register_chrdev_region(dev, 1, WIFI_DRIVER_NAME);
529 if (alloc_ret) {
530 WIFI_ERR_FUNC("Fail to register chrdev\n");
531 return alloc_ret;
532 }
533
534 cdev_init(&WIFI_cdev, &WIFI_fops);
535 WIFI_cdev.owner = THIS_MODULE;
536
537 cdev_err = cdev_add(&WIFI_cdev, dev, WIFI_devs);
538 if (cdev_err) {
539 goto error;
540 }
541
542 #if REMOVE_MK_NODE
543 wmtWifi_class = class_create(THIS_MODULE, "wmtWifi");
544 if (IS_ERR(wmtWifi_class))
545 goto error;
546 wmtWifi_dev = device_create(wmtWifi_class, NULL, dev, NULL, "wmtWifi");
547 if (IS_ERR(wmtWifi_dev))
548 goto error;
549 #endif
550
551 sema_init(&wr_mtx, 1);
552
553 WIFI_INFO_FUNC("%s driver(major %d) installed.\n", WIFI_DRIVER_NAME, WIFI_major);
554 retflag = 0;
555 wlan_mode = WLAN_MODE_HALT;
556 pf_set_p2p_mode = NULL;
557
558 return 0;
559
560 error:
561 #if REMOVE_MK_NODE
562 if (!IS_ERR(wmtWifi_dev))
563 device_destroy(wmtWifi_class, dev);
564 if (!IS_ERR(wmtWifi_class)) {
565 class_destroy(wmtWifi_class);
566 wmtWifi_class = NULL;
567 }
568 #endif
569
570 if (cdev_err == 0) {
571 cdev_del(&WIFI_cdev);
572 }
573
574 if (alloc_ret == 0) {
575 unregister_chrdev_region(dev, WIFI_devs);
576 }
577
578 return -1;
579 }
580
581 static void WIFI_exit(void)
582 {
583 dev_t dev = MKDEV(WIFI_major, 0);
584 retflag = 0;
585
586 #if REMOVE_MK_NODE
587 device_destroy(wmtWifi_class, dev);
588 class_destroy(wmtWifi_class);
589 wmtWifi_class = NULL;
590 #endif
591
592 cdev_del(&WIFI_cdev);
593 unregister_chrdev_region(dev, WIFI_devs);
594
595 WIFI_INFO_FUNC("%s driver removed.\n", WIFI_DRIVER_NAME);
596 }
597
598
599 #ifdef MTK_WCN_REMOVE_KERNEL_MODULE
600 INT32 mtk_wcn_wmt_wifi_init(VOID)
601 {
602 return WIFI_init();
603 }
604
605 VOID mtk_wcn_wmt_wifi_exit(VOID)
606 {
607 return WIFI_exit();
608 }
609 EXPORT_SYMBOL(mtk_wcn_wmt_wifi_init);
610 EXPORT_SYMBOL(mtk_wcn_wmt_wifi_exit);
611 #else
612 module_init(WIFI_init);
613 module_exit(WIFI_exit);
614 #endif