import PULS_20180308
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / connectivity / combo / common / linux / wmt_dev.c
1 /*! \file
2 \brief brief description
3
4 Detailed descriptions here.
5
6 */
7
8
9
10 /*******************************************************************************
11 * C O M P I L E R F L A G S
12 ********************************************************************************
13 */
14
15 /*******************************************************************************
16 * M A C R O S
17 ********************************************************************************
18 */
19
20
21
22 /*******************************************************************************
23 * E X T E R N A L R E F E R E N C E S
24 ********************************************************************************
25 */
26
27 #include <linux/device.h>
28 #include "wmt_dev.h"
29 #include "wmt_core.h"
30 #include "wmt_exp.h"
31 #include "wmt_lib.h"
32 #include "wmt_conf.h"
33 #include "psm_core.h"
34 #include "stp_core.h"
35 #include "stp_exp.h"
36 #include "hif_sdio.h"
37 #include "wmt_dbg.h"
38 #include "wmt_idc.h"
39 #include "osal.h"
40 #include <linux/suspend.h>
41 #include <linux/device.h>
42 #include <linux/platform_device.h>
43 #if CONSYS_EARLYSUSPEND_ENABLE
44 #include <linux/earlysuspend.h>
45 #endif
46
47
48 #define MTK_WMT_VERSION "Combo WMT Driver - v1.0"
49 #define MTK_WMT_DATE "2011/10/04"
50 #define MTK_COMBO_DRIVER_VERSION "APEX.WCN.MT6620.JB2.MP.V1.0"
51 #define WMT_DEV_MAJOR 190 /* never used number */
52 #define WMT_DEV_NUM 1
53 #define WMT_DEV_INIT_TO_MS (2 * 1000)
54
55 #if CFG_WMT_PROC_FOR_AEE
56 static struct proc_dir_entry *gWmtAeeEntry = NULL;
57 #define WMT_AEE_PROCNAME "driver/wmt_aee"
58 #define WMT_PROC_AEE_SIZE 3072
59 static UINT32 g_buf_len = 0;
60 static PUINT8 pBuf = NULL;
61
62
63
64 #if USE_NEW_PROC_FS_FLAG
65 ssize_t wmt_aee_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
66 ssize_t wmt_aee_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
67 static struct file_operations wmt_aee_fops = {
68 .read = wmt_aee_read,
69 .write = wmt_aee_write,
70 };
71 #endif
72
73
74 #endif
75
76
77 #define WMT_DRIVER_NAME "mtk_stp_wmt"
78
79
80 P_OSAL_EVENT gpRxEvent = NULL;
81
82 UINT32 u4RxFlag = 0x0;
83 static atomic_t gRxCount = ATOMIC_INIT(0);
84
85 /* Linux UCHAR device */
86 static INT32 gWmtMajor = WMT_DEV_MAJOR;
87 static struct cdev gWmtCdev;
88 static atomic_t gWmtRefCnt = ATOMIC_INIT(0);
89 /* WMT driver information */
90 static UINT8 gLpbkBuf[WMT_LPBK_BUF_LEN] = { 0 }; /* modify for support 1024 loopback */
91
92 static UINT32 gLpbkBufLog; /* George LPBK debug */
93 static INT32 gWmtInitDone = 0;
94 static wait_queue_head_t gWmtInitWq;
95
96 P_WMT_PATCH_INFO pPatchInfo = NULL;
97 UINT32 pAtchNum = 0;
98
99 #if CONSYS_WMT_REG_SUSPEND_CB_ENABLE || CONSYS_EARLYSUSPEND_ENABLE
100 static int mtk_wmt_func_off_background(void);
101 static int mtk_wmt_func_on_background(void);
102 #endif
103
104 #if CONSYS_EARLYSUSPEND_ENABLE
105
106 UINT32 g_early_suspend_flag = 0;
107 OSAL_SLEEPABLE_LOCK g_es_lr_lock;
108 static void wmt_dev_early_suspend(struct early_suspend *h)
109 {
110 osal_lock_sleepable_lock(&g_es_lr_lock);
111 g_early_suspend_flag = 1;
112 osal_unlock_sleepable_lock(&g_es_lr_lock);
113 WMT_INFO_FUNC("@@@@@@@@@@wmt enter early suspend@@@@@@@@@@@@@@\n");
114 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK)) {
115 WMT_WARN_FUNC("WMT turn off LPBK fail\n");
116 }
117 else
118 {
119 WMT_INFO_FUNC("WMT turn off LPBK suceed");
120 }
121 }
122
123 static void wmt_dev_late_resume(struct early_suspend *h)
124 {
125
126 WMT_INFO_FUNC("@@@@@@@@@@wmt enter late resume@@@@@@@@@@@@@@\n");
127 osal_lock_sleepable_lock(&g_es_lr_lock);
128 g_early_suspend_flag = 0;
129 osal_unlock_sleepable_lock(&g_es_lr_lock);
130 mtk_wmt_func_on_background();
131
132 return 0;
133 }
134
135 struct early_suspend wmt_early_suspend_handler = {
136 .suspend = wmt_dev_early_suspend,
137 .resume = wmt_dev_late_resume,
138 };
139
140 #else
141 UINT32 g_early_suspend_flag = 0;
142 #endif
143 /*******************************************************************************
144 * F U N C T I O N S
145 ********************************************************************************
146 */
147
148
149 #if CONSYS_WMT_REG_SUSPEND_CB_ENABLE || CONSYS_EARLYSUSPEND_ENABLE
150
151 static INT32 wmt_pwr_on_thread (void *pvData)
152 {
153 INT32 retryCounter = 1;
154 WMT_INFO_FUNC("wmt_pwr_on_thread start to run\n");
155 #if CONSYS_EARLYSUSPEND_ENABLE
156 osal_lock_sleepable_lock(&g_es_lr_lock);
157 if (1 == g_early_suspend_flag)
158 {
159 WMT_INFO_FUNC("wmt_pwr_on_thread exit, do nothing due to early_suspend flag set\n");
160 osal_unlock_sleepable_lock(&g_es_lr_lock);
161 return 0;
162 }
163 osal_unlock_sleepable_lock(&g_es_lr_lock);
164 #endif
165 do {
166 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK)) {
167 WMT_WARN_FUNC("WMT turn on LPBK fail, retrying, retryCounter left:%d!\n", retryCounter);
168 retryCounter--;
169 osal_sleep_ms(1000);
170 }
171 else
172 {
173 WMT_INFO_FUNC("WMT turn on LPBK suceed");
174 break;
175 }
176 } while (retryCounter > 0);
177 #if CONSYS_EARLYSUSPEND_ENABLE
178 osal_lock_sleepable_lock(&g_es_lr_lock);
179 if (1 == g_early_suspend_flag)
180 {
181 WMT_INFO_FUNC("turn off lpbk due to early_suspend flag set\n");
182 mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK);
183 }
184 osal_unlock_sleepable_lock(&g_es_lr_lock);
185 #endif
186 WMT_INFO_FUNC("wmt_pwr_on_thread exits\n");
187 return 0;
188 }
189
190 static INT32 mtk_wmt_func_on_background(void)
191 {
192 INT32 iRet = 0;
193 OSAL_THREAD bgFuncOnThread;
194 P_OSAL_THREAD pThread = &bgFuncOnThread;
195 /* Create background power on thread */
196 osal_strncpy(pThread->threadName, ("mtk_wmtd_pwr_bg"), sizeof(pThread->threadName));
197 pThread->pThreadData = NULL;
198 pThread->pThreadFunc = (VOID *)wmt_pwr_on_thread;
199 iRet = osal_thread_create(pThread);
200 if (iRet) {
201 WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pThread, iRet);
202 return -1;
203 }
204 /* 3. start: start running background power on thread*/
205 iRet = osal_thread_run(pThread);
206 if (iRet) {
207 WMT_ERR_FUNC("osal_thread_run(0x%p) fail(%d)\n", pThread, iRet);
208 return -2;
209 }
210 return 0;
211 }
212 static INT32 mtk_wmt_func_off_background(void)
213 {
214 if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK)) {
215 WMT_WARN_FUNC("WMT turn off LPBK fail\n");
216 }
217 else
218 {
219 WMT_INFO_FUNC("WMT turn off LPBK suceed");
220 }
221 return 0;
222 }
223
224 #endif
225
226 #if CFG_WMT_PROC_FOR_AEE
227
228 #if USE_NEW_PROC_FS_FLAG
229 ssize_t wmt_aee_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
230 {
231 INT32 retval = 0;
232 UINT32 len = 0;
233 WMT_INFO_FUNC("%s: count %d pos %lld\n", __func__, count, *f_pos);
234
235 if (0 == *f_pos) {
236 pBuf = wmt_lib_get_cpupcr_xml_format(&len);
237 g_buf_len = len;
238 WMT_INFO_FUNC("wmt_dev:wmt for aee buffer len(%d)\n", g_buf_len);
239 }
240
241 if (g_buf_len >= count) {
242
243 retval = copy_to_user(buf, pBuf, count);
244 if (retval) {
245 WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval);
246 retval = -EFAULT;
247 goto err_exit;
248 }
249
250 *f_pos += count;
251 g_buf_len -= count;
252 pBuf += count;
253 WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len);
254
255 retval = count;
256 } else if (0 != g_buf_len) {
257
258 retval = copy_to_user(buf, pBuf, g_buf_len);
259 if (retval) {
260 WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval);
261 retval = -EFAULT;
262 goto err_exit;
263 }
264
265 *f_pos += g_buf_len;
266 len = g_buf_len;
267 g_buf_len = 0;
268 pBuf += len;
269 retval = len;
270 WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len);
271 } else {
272 WMT_INFO_FUNC("wmt_dev: no data avaliable for aee\n");
273 retval = 0;
274 }
275 err_exit:
276 return retval;
277 }
278
279
280 ssize_t wmt_aee_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
281 {
282 WMT_TRC_FUNC();
283 return 0;
284 }
285
286 #else
287 static UINT32 passCnt;
288 static int wmt_dev_proc_for_aee_read(char *page, char **start, off_t off, int count, int *eof,
289 void *data)
290 {
291 UINT32 len = 0;
292
293 WMT_INFO_FUNC("wmt-dev:wmt for aee page(%p)off(%d)count(%d)\n", page, off, count);
294
295 if (off == 0) {
296 pBuf = wmt_lib_get_cpupcr_xml_format(&len);
297 g_buf_len = len;
298
299 /*pass 3k buffer for each proc read */
300 passCnt = g_buf_len / WMT_PROC_AEE_SIZE;
301 passCnt = (g_buf_len % WMT_PROC_AEE_SIZE) ? (passCnt + 1) : passCnt;
302 WMT_INFO_FUNC("wmt_dev:wmt for aee buffer len(%d)passCnt(%d)\n", g_buf_len,
303 passCnt);
304 }
305
306 if (passCnt) {
307 if (g_buf_len > WMT_PROC_AEE_SIZE) {
308 osal_memcpy(page, pBuf, WMT_PROC_AEE_SIZE);
309 *start += WMT_PROC_AEE_SIZE;
310 g_buf_len -= WMT_PROC_AEE_SIZE;
311 pBuf += WMT_PROC_AEE_SIZE;
312 WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len);
313 *eof = 1;
314 passCnt--;
315 return WMT_PROC_AEE_SIZE;
316 } else {
317 osal_memcpy(page, pBuf, g_buf_len);
318 *start += g_buf_len;
319 len = g_buf_len;
320 g_buf_len = 0;
321 *eof = 1;
322 passCnt--;
323 pBuf += len;
324 return len;
325 }
326 }
327
328 return len;
329 }
330
331
332 static int wmt_dev_proc_for_aee_write(struct file *file, const char *buffer, unsigned long count,
333 void *data)
334 {
335 return 0;
336 }
337
338 #endif
339
340 INT32 wmt_dev_proc_for_aee_setup(VOID)
341 {
342 INT32 i_ret = 0;
343 #if USE_NEW_PROC_FS_FLAG
344 gWmtAeeEntry = proc_create(WMT_AEE_PROCNAME, 0664, NULL, &wmt_aee_fops);
345 if (gWmtAeeEntry == NULL) {
346 WMT_ERR_FUNC("Unable to create / wmt_aee proc entry\n\r");
347 i_ret = -1;
348 }
349 #else
350
351 gWmtAeeEntry = create_proc_entry(WMT_AEE_PROCNAME, 0664, NULL);
352 if (gWmtAeeEntry == NULL) {
353 WMT_ERR_FUNC("Unable to create / wmt_aee proc entry\n\r");
354 i_ret = -1;
355 }
356 gWmtAeeEntry->read_proc = wmt_dev_proc_for_aee_read;
357 gWmtAeeEntry->write_proc = wmt_dev_proc_for_aee_write;
358 #endif
359 return i_ret;
360 }
361
362
363 INT32 wmt_dev_proc_for_aee_remove(VOID)
364 {
365 #if USE_NEW_PROC_FS_FLAG
366 if (NULL != gWmtAeeEntry) {
367 proc_remove(gWmtAeeEntry);
368 }
369 #else
370
371 if (NULL != gWmtAeeEntry) {
372 remove_proc_entry(WMT_AEE_PROCNAME, NULL);
373 }
374 #endif
375 return 0;
376 }
377 #endif /* end of "CFG_WMT_PROC_FOR_AEE" */
378
379
380 VOID wmt_dev_rx_event_cb(VOID)
381 {
382 if (NULL != gpRxEvent) {
383 u4RxFlag = 1;
384 atomic_inc(&gRxCount);
385 wake_up_interruptible(&gpRxEvent->waitQueue);
386 } else {
387 WMT_ERR_FUNC("null gpRxEvent, flush rx!\n");
388 wmt_lib_flush_rx();
389 }
390 }
391
392
393 INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent)
394 {
395
396 UINT32 ms = pEvent->timeoutValue;
397 INT32 lRet = 0;
398 gpRxEvent = pEvent;
399 if (0 != ms) {
400 lRet =
401 wait_event_interruptible_timeout(gpRxEvent->waitQueue, 0 != u4RxFlag,
402 msecs_to_jiffies(ms));
403 } else {
404 lRet = wait_event_interruptible(gpRxEvent->waitQueue, u4RxFlag != 0);
405 }
406 u4RxFlag = 0;
407 /* gpRxEvent = NULL; */
408 if (atomic_dec_return(&gRxCount)) {
409 WMT_ERR_FUNC("gRxCount != 0 (%d), reset it!\n", atomic_read(&gRxCount));
410 atomic_set(&gRxCount, 0);
411 }
412
413 return lRet;
414 }
415
416 INT32 wmt_dev_read_file(PUINT8 pName, const PPUINT8 ppBufPtr, INT32 offset, INT32 padSzBuf)
417 {
418 INT32 iRet = -1;
419 struct file *fd;
420 /* ssize_t iRet; */
421 INT32 file_len;
422 INT32 read_len;
423 PVOID pBuf;
424
425 /* struct cred *cred = get_task_cred(current); */
426 const struct cred *cred = get_current_cred();
427
428 if (!ppBufPtr) {
429 WMT_ERR_FUNC("invalid ppBufptr!\n");
430 return -1;
431 }
432 *ppBufPtr = NULL;
433
434 fd = filp_open(pName, O_RDONLY, 0);
435 if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) {
436 WMT_ERR_FUNC("failed to open or read!(0x%p, %d, %d)\n", fd, cred->fsuid,
437 cred->fsgid);
438 return -1;
439 }
440
441 file_len = fd->f_path.dentry->d_inode->i_size;
442 pBuf = vmalloc((file_len + BCNT_PATCH_BUF_HEADROOM + 3) & ~0x3UL);
443 if (!pBuf) {
444 WMT_ERR_FUNC("failed to vmalloc(%d)\n", (INT32) ((file_len + 3) & ~0x3UL));
445 goto read_file_done;
446 }
447
448 do {
449 if (fd->f_pos != offset) {
450 if (fd->f_op->llseek) {
451 if (fd->f_op->llseek(fd, offset, 0) != offset) {
452 WMT_ERR_FUNC("failed to seek!!\n");
453 goto read_file_done;
454 }
455 } else {
456 fd->f_pos = offset;
457 }
458 }
459
460 read_len = fd->f_op->read(fd, pBuf + padSzBuf, file_len, &fd->f_pos);
461 if (read_len != file_len) {
462 WMT_WARN_FUNC("read abnormal: read_len(%d), file_len(%d)\n", read_len,
463 file_len);
464 }
465 } while (false);
466
467 iRet = 0;
468 *ppBufPtr = pBuf;
469
470 read_file_done:
471 if (iRet) {
472 if (pBuf) {
473 vfree(pBuf);
474 }
475 }
476
477 filp_close(fd, NULL);
478
479 return (iRet) ? iRet : read_len;
480 }
481
482 /* TODO: [ChangeFeature][George] refine this function name for general filesystem read operation, not patch only. */
483 INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch, INT32 padSzBuf)
484 {
485 INT32 iRet = -1;
486 osal_firmware *pfw;
487 uid_t orig_uid;
488 gid_t orig_gid;
489
490 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
491 /* struct cred *cred = get_task_cred(current); */
492 struct cred *cred = (struct cred *)get_current_cred();
493 #endif
494
495 mm_segment_t orig_fs = get_fs();
496
497 if (*ppPatch) {
498 WMT_WARN_FUNC("f/w patch already exists\n");
499 if ((*ppPatch)->data) {
500 vfree((*ppPatch)->data);
501 }
502 kfree(*ppPatch);
503 *ppPatch = NULL;
504 }
505
506 if (!osal_strlen(pPatchName)) {
507 WMT_ERR_FUNC("empty f/w name\n");
508 osal_assert((osal_strlen(pPatchName) > 0));
509 return -1;
510 }
511
512 pfw = kzalloc(sizeof(osal_firmware), /*GFP_KERNEL */ GFP_ATOMIC);
513 if (!pfw) {
514 WMT_ERR_FUNC("kzalloc(%d) fail\n", sizeof(osal_firmware));
515 return -2;
516 }
517 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
518 orig_uid = cred->fsuid;
519 orig_gid = cred->fsgid;
520 cred->fsuid = cred->fsgid = 0;
521 #else
522 orig_uid = current->fsuid;
523 orig_gid = current->fsgid;
524 current->fsuid = current->fsgid = 0;
525 #endif
526
527 set_fs(get_ds());
528
529 /* load patch file from fs */
530 iRet = wmt_dev_read_file(pPatchName, &pfw->data, 0, padSzBuf);
531 set_fs(orig_fs);
532
533 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
534 cred->fsuid = orig_uid;
535 cred->fsgid = orig_gid;
536 #else
537 current->fsuid = orig_uid;
538 current->fsgid = orig_gid;
539 #endif
540
541 if (iRet > 0) {
542 pfw->size = iRet;
543 *ppPatch = pfw;
544 WMT_DBG_FUNC("load (%s) to addr(0x%p) success\n", pPatchName, pfw->data);
545 return 0;
546 } else {
547 kfree(pfw);
548 *ppPatch = NULL;
549 WMT_ERR_FUNC("load file (%s) fail, iRet(%d)\n", pPatchName, iRet);
550 return -1;
551 }
552 }
553
554
555 INT32 wmt_dev_patch_put(osal_firmware **ppPatch)
556 {
557 if (NULL != *ppPatch) {
558 if ((*ppPatch)->data) {
559 vfree((*ppPatch)->data);
560 }
561 kfree(*ppPatch);
562 *ppPatch = NULL;
563 }
564 return 0;
565 }
566
567 VOID wmt_dev_patch_info_free(VOID)
568 {
569 if (pPatchInfo) {
570 kfree(pPatchInfo);
571 pPatchInfo = NULL;
572 }
573 }
574
575 MTK_WCN_BOOL wmt_dev_is_file_exist(PUINT8 pFileName)
576 {
577 struct file *fd = NULL;
578 /* ssize_t iRet; */
579 INT32 fileLen = -1;
580 const struct cred *cred = get_current_cred();
581 if (pFileName == NULL) {
582 WMT_ERR_FUNC("invalid file name pointer(%p)\n", pFileName);
583 return MTK_WCN_BOOL_FALSE;
584 }
585 if (osal_strlen(pFileName) < osal_strlen(defaultPatchName)) {
586 WMT_ERR_FUNC("invalid file name(%s)\n", pFileName);
587 return MTK_WCN_BOOL_FALSE;
588 }
589
590 /* struct cred *cred = get_task_cred(current); */
591
592 fd = filp_open(pFileName, O_RDONLY, 0);
593 if (!fd || IS_ERR(fd) || !fd->f_op || !fd->f_op->read) {
594 WMT_ERR_FUNC("failed to open or read(%s)!(0x%p, %d, %d)\n", pFileName, fd,
595 cred->fsuid, cred->fsgid);
596 return MTK_WCN_BOOL_FALSE;
597 }
598 fileLen = fd->f_path.dentry->d_inode->i_size;
599 filp_close(fd, NULL);
600 fd = NULL;
601 if (fileLen <= 0) {
602 WMT_ERR_FUNC("invalid file(%s), length(%d)\n", pFileName, fileLen);
603 return MTK_WCN_BOOL_FALSE;
604 }
605 WMT_ERR_FUNC("valid file(%s), length(%d)\n", pFileName, fileLen);
606 return true;
607
608 }
609
610 static unsigned long count_last_access_sdio = 0;
611 static unsigned long count_last_access_uart = 0;
612 static unsigned long jiffies_last_poll = 0;
613
614 static INT32 wmt_dev_tra_sdio_update(VOID)
615 {
616 count_last_access_sdio += 1;
617 /* WMT_INFO_FUNC("jiffies_last_access_sdio: jiffies = %ul\n", jiffies); */
618
619 return 0;
620 }
621
622 extern INT32 wmt_dev_tra_uart_update(VOID)
623 {
624 count_last_access_uart += 1;
625 /* WMT_INFO_FUNC("jiffies_last_access_uart: jiffies = %ul\n", jiffies); */
626
627 return 0;
628 }
629
630 static UINT32 wmt_dev_tra_sdio_poll(VOID)
631 {
632 #define TIME_THRESHOLD_TO_TEMP_QUERY 3000
633 #define COUNT_THRESHOLD_TO_TEMP_QUERY 200
634
635 unsigned long sdio_during_count = 0;
636 unsigned long poll_during_time = 0;
637
638 if (jiffies > jiffies_last_poll) {
639 poll_during_time = jiffies - jiffies_last_poll;
640 } else {
641 poll_during_time = 0xffffffff;
642 }
643
644 WMT_DBG_FUNC("**jiffies_to_mesecs(0xffffffff) = %u\n", jiffies_to_msecs(0xffffffff));
645
646 if (jiffies_to_msecs(poll_during_time) < TIME_THRESHOLD_TO_TEMP_QUERY) {
647 WMT_DBG_FUNC("**poll_during_time = %u < %u, not to query\n",
648 jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY);
649 return -1;
650 }
651
652 sdio_during_count = count_last_access_sdio;
653
654 if (sdio_during_count < COUNT_THRESHOLD_TO_TEMP_QUERY) {
655 WMT_DBG_FUNC("**sdio_during_count = %lu < %u, not to query\n",
656 sdio_during_count, COUNT_THRESHOLD_TO_TEMP_QUERY);
657 return -1;
658 }
659
660 count_last_access_sdio = 0;
661 jiffies_last_poll = jiffies;
662
663 WMT_INFO_FUNC("**poll_during_time = %u > %u, sdio_during_count = %u > %u, query\n",
664 jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY,
665 jiffies_to_msecs(sdio_during_count), COUNT_THRESHOLD_TO_TEMP_QUERY);
666
667 return 0;
668 }
669
670 #if 0
671 static UINT32 wmt_dev_tra_uart_poll(void)
672 {
673 /* we not support the uart case. */
674 return -1;
675 }
676 #endif
677
678 INT32 wmt_dev_tm_temp_query(VOID)
679 {
680 #define HISTORY_NUM 5
681 #define TEMP_THRESHOLD 65
682 #define REFRESH_TIME 300 /* sec */
683
684 static INT32 temp_table[HISTORY_NUM] = { 99 }; /* not query yet. */
685 static INT32 idx_temp_table;
686 static struct timeval query_time, now_time;
687
688 INT8 query_cond = 0;
689 INT8 ctemp = 0;
690 INT32 current_temp = 0;
691 INT32 index = 0;
692 MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
693
694 /* Query condition 1: */
695 /* If we have the high temperature records on the past, we continue to query/monitor */
696 /* the real temperature until cooling */
697 for (index = 0; index < HISTORY_NUM; index++) {
698 if (temp_table[index] >= TEMP_THRESHOLD) {
699 query_cond = 1;
700 WMT_INFO_FUNC
701 ("high temperature (current temp = %d), we must keep querying temp temperature..\n",
702 temp_table[index]);
703 }
704 }
705
706 do_gettimeofday(&now_time);
707 #if 1
708 /* Query condition 2: */
709 /* Moniter the hif_sdio activity to decide if we have the need to query temperature. */
710 if (!query_cond) {
711 if (wmt_dev_tra_sdio_poll() == 0) {
712 query_cond = 1;
713 WMT_DBG_FUNC("sdio traffic , we must query temperature..\n");
714 } else {
715 WMT_DBG_FUNC("sdio idle traffic ....\n");
716 }
717
718 /* only WIFI tx power might make temperature varies largely */
719 #if 0
720 if (!query_cond) {
721 last_access_time = wmt_dev_tra_uart_poll();
722 if (jiffies_to_msecs(last_access_time) < TIME_THRESHOLD_TO_TEMP_QUERY) {
723 query_cond = 1;
724 WMT_DBG_FUNC("uart busy traffic , we must query temperature..\n");
725 } else {
726 WMT_DBG_FUNC
727 ("uart still idle traffic , we don't query temp temperature..\n");
728 }
729 }
730 #endif
731 }
732 #endif
733 /* Query condition 3: */
734 /* If the query time exceeds the a certain of period, refresh temp table. */
735 /* */
736 if (!query_cond) {
737 if ((now_time.tv_sec < query_time.tv_sec) || /* time overflow, we refresh temp table again for simplicity! */
738 ((now_time.tv_sec > query_time.tv_sec) &&
739 (now_time.tv_sec - query_time.tv_sec) > REFRESH_TIME)) {
740 query_cond = 1;
741
742 WMT_INFO_FUNC
743 ("It is long time (> %d sec) not to query, we must query temp temperature..\n",
744 REFRESH_TIME);
745 for (index = 0; index < HISTORY_NUM; index++) {
746 temp_table[index] = 99;
747 }
748 }
749 }
750
751 if (query_cond) {
752 /* update the temperature record */
753 bRet = mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE);
754 if (bRet == MTK_WCN_BOOL_TRUE)
755 {
756 ctemp = mtk_wcn_wmt_therm_ctrl(WMTTHERM_READ);
757 bRet = mtk_wcn_wmt_therm_ctrl(WMTTHERM_DISABLE);
758 if(bRet == MTK_WCN_BOOL_TRUE)
759 wmt_lib_notify_stp_sleep();
760 if (0 != (ctemp & 0x80))
761 {
762 ctemp &= 0x7f;
763 current_temp = ~((INT32)ctemp - 1);
764 }
765 else
766 current_temp = ctemp;
767 }
768 else
769 {
770 current_temp = -1;
771 if (MTK_WCN_BOOL_TRUE == wmt_lib_is_therm_ctrl_support())
772 WMT_WARN_FUNC("thermal function enable command failed, set current_temp = 0x%x \n", current_temp);
773 }
774 idx_temp_table = (idx_temp_table + 1) % HISTORY_NUM;
775 temp_table[idx_temp_table] = current_temp;
776 do_gettimeofday(&query_time);
777
778 WMT_DBG_FUNC("[Thermal] current_temp = 0x%x \n", current_temp);
779 } else {
780 current_temp = temp_table[idx_temp_table];
781 idx_temp_table = (idx_temp_table + 1) % HISTORY_NUM;
782 temp_table[idx_temp_table] = current_temp;
783 }
784
785 /* */
786 /* Dump information */
787 /* */
788 WMT_DBG_FUNC("[Thermal] idx_temp_table = %d\n", idx_temp_table);
789 WMT_DBG_FUNC("[Thermal] now.time = %ld, query.time = %ld, REFRESH_TIME = %d\n",
790 now_time.tv_sec, query_time.tv_sec, REFRESH_TIME);
791
792 WMT_DBG_FUNC("[0] = %d, [1] = %d, [2] = %d, [3] = %d, [4] = %d\n----\n",
793 temp_table[0], temp_table[1], temp_table[2], temp_table[3], temp_table[4]);
794
795 return current_temp;
796 }
797
798 ssize_t WMT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
799 {
800 INT32 iRet = 0;
801 UINT8 wrBuf[NAME_MAX + 1] = { 0 };
802 INT32 copySize = (count < NAME_MAX) ? count : NAME_MAX;
803
804 WMT_LOUD_FUNC("count:%d copySize:%d\n", count, copySize);
805
806 if (copySize > 0) {
807 if (copy_from_user(wrBuf, buf, copySize)) {
808 iRet = -EFAULT;
809 goto write_done;
810 }
811 iRet = copySize;
812 wrBuf[NAME_MAX] = '\0';
813
814 if (!strncasecmp(wrBuf, "ok", NAME_MAX)) {
815 WMT_DBG_FUNC("resp str ok\n");
816 /* pWmtDevCtx->cmd_result = 0; */
817 wmt_lib_trigger_cmd_signal(0);
818 } else {
819 WMT_WARN_FUNC("warning resp str (%s)\n", wrBuf);
820 /* pWmtDevCtx->cmd_result = -1; */
821 wmt_lib_trigger_cmd_signal(-1);
822 }
823 /* complete(&pWmtDevCtx->cmd_comp); */
824
825 }
826
827 write_done:
828 return iRet;
829 }
830
831 ssize_t WMT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
832 {
833 INT32 iRet = 0;
834 PUINT8 pCmd = NULL;
835 UINT32 cmdLen = 0;
836 pCmd = wmt_lib_get_cmd();
837
838 if (pCmd != NULL) {
839 cmdLen = osal_strlen(pCmd) < NAME_MAX ? osal_strlen(pCmd) : NAME_MAX;
840 WMT_DBG_FUNC("cmd str(%s)\n", pCmd);
841 if (copy_to_user(buf, pCmd, cmdLen)) {
842 iRet = -EFAULT;
843 } else {
844 iRet = cmdLen;
845 }
846 }
847 #if 0
848 if (test_and_clear_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) {
849 iRet = osal_strlen(localBuf) < NAME_MAX ? osal_strlen(localBuf) : NAME_MAX;
850 /* we got something from STP driver */
851 WMT_DBG_FUNC("copy cmd to user by read:%s\n", localBuf);
852 if (copy_to_user(buf, localBuf, iRet)) {
853 iRet = -EFAULT;
854 goto read_done;
855 }
856 }
857 #endif
858 return iRet;
859 }
860
861 unsigned int WMT_poll(struct file *filp, poll_table *wait)
862 {
863 UINT32 mask = 0;
864 P_OSAL_EVENT pEvent = wmt_lib_get_cmd_event();
865
866 poll_wait(filp, &pEvent->waitQueue, wait);
867 /* empty let select sleep */
868 if (MTK_WCN_BOOL_TRUE == wmt_lib_get_cmd_status()) {
869 mask |= POLLIN | POLLRDNORM; /* readable */
870 }
871 #if 0
872 if (test_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) {
873 mask |= POLLIN | POLLRDNORM; /* readable */
874 }
875 #endif
876 mask |= POLLOUT | POLLWRNORM; /* writable */
877 return mask;
878 }
879
880 /* INT32 WMT_ioctl(struct inode *inode, struct file *filp, UINT32 cmd, unsigned long arg) */
881 long WMT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
882 {
883 #define WMT_IOC_MAGIC 0xa0
884 #define WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, char*)
885 #define WMT_IOCTL_SET_STP_MODE _IOW(WMT_IOC_MAGIC, 5, int)
886 #define WMT_IOCTL_FUNC_ONOFF_CTRL _IOW(WMT_IOC_MAGIC, 6, int)
887 #define WMT_IOCTL_LPBK_POWER_CTRL _IOW(WMT_IOC_MAGIC, 7, int)
888 #define WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, char*)
889 #define WMT_IOCTL_GET_CHIP_INFO _IOR(WMT_IOC_MAGIC, 12, int)
890 #define WMT_IOCTL_SET_LAUNCHER_KILL _IOW(WMT_IOC_MAGIC, 13, int)
891 #define WMT_IOCTL_SET_PATCH_NUM _IOW(WMT_IOC_MAGIC, 14, int)
892 #define WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, char*)
893 #define WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, char*)
894 #define WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, char*)
895 #define WMT_IOCTL_WMT_QUERY_CHIPID _IOR(WMT_IOC_MAGIC, 22, int)
896 #define WMT_IOCTL_WMT_TELL_CHIPID _IOW(WMT_IOC_MAGIC, 23, int)
897 #define WMT_IOCTL_WMT_COREDUMP_CTRL _IOW(WMT_IOC_MAGIC, 24, int)
898 #define WMT_IOCTL_WMT_STP_ASSERT_CTRL _IOW(WMT_IOC_MAGIC, 27, int)
899
900
901
902 INT32 iRet = 0;
903 UINT8 pBuffer[NAME_MAX + 1];
904 WMT_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg);
905 switch (cmd) {
906 case WMT_IOCTL_SET_PATCH_NAME: /* patch location */
907 {
908
909 if (copy_from_user(pBuffer, (void *)arg, NAME_MAX)) {
910 iRet = -EFAULT;
911 break;
912 }
913 pBuffer[NAME_MAX] = '\0';
914 wmt_lib_set_patch_name(pBuffer);
915 }
916 break;
917
918 case WMT_IOCTL_SET_STP_MODE: /* stp/hif/fm mode */
919
920 /* set hif conf */
921 do {
922 P_OSAL_OP pOp;
923 MTK_WCN_BOOL bRet;
924 P_OSAL_SIGNAL pSignal = NULL;
925 P_WMT_HIF_CONF pHif = NULL;
926
927 iRet = wmt_lib_set_hif(arg);
928 if (0 != iRet) {
929 WMT_INFO_FUNC("wmt_lib_set_hif fail (%lu)\n", arg);
930 break;
931 }
932
933 pOp = wmt_lib_get_free_op();
934 if (!pOp) {
935 WMT_INFO_FUNC("get_free_lxop fail\n");
936 break;
937 }
938 pSignal = &pOp->signal;
939 pOp->op.opId = WMT_OPID_HIF_CONF;
940
941 pHif = wmt_lib_get_hif();
942
943 osal_memcpy(&pOp->op.au4OpData[0], pHif, sizeof(WMT_HIF_CONF));
944 pOp->op.u4InfoBit = WMT_OP_HIF_BIT;
945 pSignal->timeoutValue = 0;
946
947 bRet = wmt_lib_put_act_op(pOp);
948 WMT_DBG_FUNC("WMT_OPID_HIF_CONF result(%d)\n", bRet);
949 iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0;
950 } while (0);
951
952 break;
953
954 case WMT_IOCTL_FUNC_ONOFF_CTRL: /* test turn on/off func */
955
956 do {
957 MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
958 if (arg & 0x80000000) {
959 bRet = mtk_wcn_wmt_func_on(arg & 0xF);
960 } else {
961 bRet = mtk_wcn_wmt_func_off(arg & 0xF);
962 }
963 iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0;
964 } while (0);
965
966 break;
967
968 case WMT_IOCTL_LPBK_POWER_CTRL:
969 /*switch Loopback function on/off
970 arg: bit0 = 1:turn loopback function on
971 bit0 = 0:turn loopback function off
972 */
973 do {
974 MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE;
975 if (arg & 0x01) {
976 bRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK);
977 } else {
978 bRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK);
979 }
980 iRet = (MTK_WCN_BOOL_FALSE == bRet) ? -EFAULT : 0;
981 } while (0);
982
983
984 break;
985
986
987 case WMT_IOCTL_LPBK_TEST:
988 do {
989 P_OSAL_OP pOp;
990 MTK_WCN_BOOL bRet;
991 UINT32 u4Wait;
992 /* UINT8 lpbk_buf[1024] = {0}; */
993 UINT32 effectiveLen = 0;
994 P_OSAL_SIGNAL pSignal = NULL;
995
996 if (copy_from_user(&effectiveLen, (void *)arg, sizeof(effectiveLen))) {
997 iRet = -EFAULT;
998 WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__);
999 break;
1000 }
1001 if (effectiveLen > sizeof(gLpbkBuf)) {
1002 iRet = -EFAULT;
1003 WMT_ERR_FUNC("length is too long\n");
1004 break;
1005 }
1006 WMT_DBG_FUNC("len = %d\n", effectiveLen);
1007
1008 pOp = wmt_lib_get_free_op();
1009 if (!pOp) {
1010 WMT_WARN_FUNC("get_free_lxop fail\n");
1011 iRet = -EFAULT;
1012 break;
1013 }
1014 u4Wait = 2000;
1015 if (copy_from_user
1016 (&gLpbkBuf[0], (void *)arg + sizeof(unsigned long), effectiveLen)) {
1017 WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__);
1018 iRet = -EFAULT;
1019 break;
1020 }
1021 pSignal = &pOp->signal;
1022 pOp->op.opId = WMT_OPID_LPBK;
1023 pOp->op.au4OpData[0] = effectiveLen; /* packet length */
1024 pOp->op.au4OpData[1] = (size_t) &gLpbkBuf[0];
1025 memcpy(&gLpbkBufLog,
1026 &gLpbkBuf[((effectiveLen >= 4) ? effectiveLen - 4 : 0)], 4);
1027 pSignal->timeoutValue = MAX_EACH_WMT_CMD;
1028 WMT_INFO_FUNC("OPID(%d) type(%d) start\n",
1029 pOp->op.opId, pOp->op.au4OpData[0]);
1030 if (DISABLE_PSM_MONITOR()) {
1031 WMT_ERR_FUNC("wake up failed\n");
1032 wmt_lib_put_op_to_free_queue(pOp);
1033 return -1;
1034 }
1035
1036 bRet = wmt_lib_put_act_op(pOp);
1037 ENABLE_PSM_MONITOR();
1038 if (MTK_WCN_BOOL_FALSE == bRet) {
1039 WMT_WARN_FUNC("OPID(%d) type(%d) buf tail(0x%08x) fail\n",
1040 pOp->op.opId, pOp->op.au4OpData[0], gLpbkBufLog);
1041 iRet = -1;
1042 break;
1043 } else {
1044 WMT_INFO_FUNC("OPID(%d) length(%d) ok\n",
1045 pOp->op.opId, pOp->op.au4OpData[0]);
1046 iRet = pOp->op.au4OpData[0];
1047 if (copy_to_user
1048 ((void *)arg + sizeof(unsigned long) + sizeof(UINT8[2048]), gLpbkBuf,
1049 iRet)) {
1050 iRet = -EFAULT;
1051 break;
1052 }
1053 }
1054 } while (0);
1055
1056 break;
1057 #if 0
1058 case 9:
1059 {
1060 #define LOG_BUF_SZ 300
1061 UINT8 buf[LOG_BUF_SZ];
1062 INT32 len = 0;
1063 INT32 remaining = 0;
1064
1065 remaining = mtk_wcn_stp_btm_get_dmp(buf, &len);
1066
1067 if (remaining == 0) {
1068 WMT_DBG_FUNC("waiting dmp\n");
1069 wait_event_interruptible(dmp_wq, dmp_flag != 0);
1070 dmp_flag = 0;
1071 remaining = mtk_wcn_stp_btm_get_dmp(buf, &len);
1072
1073 /* WMT_INFO_FUNC("len = %d ###%s#\n", len, buf); */
1074 } else {
1075 WMT_LOUD_FUNC("no waiting dmp\n");
1076 }
1077
1078 if (unlikely((len + sizeof(INT32)) >= LOG_BUF_SZ)) {
1079 WMT_ERR_FUNC("len is larger buffer\n");
1080 iRet = -EFAULT;
1081 goto fail_exit;
1082 }
1083
1084 buf[sizeof(INT32) + len] = '\0';
1085
1086 if (copy_to_user((void *)arg, (PUINT8)&len, sizeof(INT32))) {
1087 iRet = -EFAULT;
1088 goto fail_exit;
1089 }
1090
1091 if (copy_to_user((void *)arg + sizeof(INT32), buf, len)) {
1092 iRet = -EFAULT;
1093 goto fail_exit;
1094 }
1095 }
1096 break;
1097
1098 case 10:
1099 {
1100 WMT_INFO_FUNC("Enable combo trace32 dump\n");
1101 wmt_cdev_t32dmp_enable();
1102 WMT_INFO_FUNC("Enable STP debugging mode\n");
1103 mtk_wcn_stp_dbg_enable();
1104 }
1105 break;
1106
1107 case 11:
1108 {
1109 WMT_INFO_FUNC("Disable combo trace32 dump\n");
1110 wmt_cdev_t32dmp_disable();
1111 WMT_INFO_FUNC("Disable STP debugging mode\n");
1112 mtk_wcn_stp_dbg_disable();
1113 }
1114 break;
1115 #endif
1116
1117 case 10:
1118 {
1119 wmt_lib_host_awake_get();
1120 mtk_wcn_stp_coredump_start_ctrl(1);
1121 osal_strcpy(pBuffer, "MT662x f/w coredump start-");
1122 if (copy_from_user
1123 (pBuffer + osal_strlen(pBuffer), (void *)arg,
1124 NAME_MAX - osal_strlen(pBuffer))) {
1125 /* osal_strcpy(pBuffer, "MT662x f/w assert core dump start"); */
1126 WMT_ERR_FUNC("copy assert string failed\n");
1127 }
1128 pBuffer[NAME_MAX] = '\0';
1129 osal_dbg_assert_aee(pBuffer, pBuffer);
1130 }
1131 break;
1132 case 11:
1133 {
1134 osal_dbg_assert_aee("MT662x f/w coredump end",
1135 "MT662x firmware coredump ends");
1136 wmt_lib_host_awake_put();
1137 }
1138 break;
1139
1140
1141 case WMT_IOCTL_GET_CHIP_INFO:
1142 {
1143 if (0 == arg) {
1144 return wmt_lib_get_icinfo(WMTCHIN_CHIPID);
1145 } else if (1 == arg) {
1146 return wmt_lib_get_icinfo(WMTCHIN_HWVER);
1147 } else if (2 == arg) {
1148 return wmt_lib_get_icinfo(WMTCHIN_FWVER);
1149 }
1150 }
1151 break;
1152
1153 case WMT_IOCTL_SET_LAUNCHER_KILL:{
1154 if (1 == arg) {
1155 WMT_INFO_FUNC("launcher may be killed,block abnormal stp tx.\n");
1156 wmt_lib_set_stp_wmt_last_close(1);
1157 } else {
1158 wmt_lib_set_stp_wmt_last_close(0);
1159 }
1160
1161 }
1162 break;
1163
1164 case WMT_IOCTL_SET_PATCH_NUM:{
1165 pAtchNum = arg;
1166 if (pAtchNum == 0 || pAtchNum > MAX_PATCH_NUM) {
1167 WMT_ERR_FUNC("patch num(%d) == 0 or > %d!\n", pAtchNum, MAX_PATCH_NUM);
1168 iRet = -1;
1169 break;
1170 }
1171
1172 pPatchInfo = kzalloc(sizeof(WMT_PATCH_INFO) * pAtchNum, GFP_ATOMIC);
1173 if (!pPatchInfo) {
1174 WMT_ERR_FUNC("allocate memory fail!\n");
1175 iRet = -EFAULT;
1176 break;
1177 }
1178 WMT_INFO_FUNC(" get patch num from launcher = %d\n", pAtchNum);
1179 wmt_lib_set_patch_num(pAtchNum);
1180 }
1181 break;
1182
1183 case WMT_IOCTL_SET_PATCH_INFO:{
1184 WMT_PATCH_INFO wMtPatchInfo;
1185 P_WMT_PATCH_INFO pTemp = NULL;
1186 UINT32 dWloadSeq;
1187 static UINT32 counter = 0;
1188
1189 if (!pPatchInfo) {
1190 WMT_ERR_FUNC("NULL patch info pointer\n");
1191 break;
1192 }
1193
1194 if (copy_from_user(&wMtPatchInfo, (void *)arg, sizeof(WMT_PATCH_INFO))) {
1195 WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__);
1196 iRet = -EFAULT;
1197 break;
1198 }
1199
1200 dWloadSeq = wMtPatchInfo.dowloadSeq;
1201 WMT_DBG_FUNC
1202 ("current download seq no is %d,patch name is %s,addres info is 0x%02x,0x%02x,0x%02x,0x%02x\n",
1203 dWloadSeq, wMtPatchInfo.patchName, wMtPatchInfo.addRess[0],
1204 wMtPatchInfo.addRess[1], wMtPatchInfo.addRess[2],
1205 wMtPatchInfo.addRess[3]);
1206 osal_memcpy(pPatchInfo + dWloadSeq - 1, &wMtPatchInfo,
1207 sizeof(WMT_PATCH_INFO));
1208 pTemp = pPatchInfo + dWloadSeq - 1;
1209 if (++counter == pAtchNum) {
1210 wmt_lib_set_patch_info(pPatchInfo);
1211 counter = 0;
1212 }
1213 }
1214 break;
1215
1216 case WMT_IOCTL_PORT_NAME:{
1217 INT8 cUartName[NAME_MAX + 1];
1218 if (copy_from_user(cUartName, (void *)arg, NAME_MAX)) {
1219 iRet = -EFAULT;
1220 break;
1221 }
1222 cUartName[NAME_MAX] = '\0';
1223 wmt_lib_set_uart_name(cUartName);
1224 }
1225 break;
1226
1227 case WMT_IOCTL_WMT_CFG_NAME:
1228 {
1229 INT8 cWmtCfgName[NAME_MAX + 1];
1230 if (copy_from_user(cWmtCfgName, (void *)arg, NAME_MAX)) {
1231 iRet = -EFAULT;
1232 break;
1233 }
1234 cWmtCfgName[NAME_MAX] = '\0';
1235 wmt_conf_set_cfg_file(cWmtCfgName);
1236 }
1237 break;
1238 case WMT_IOCTL_WMT_QUERY_CHIPID:
1239 {
1240 #if !(DELETE_HIF_SDIO_CHRDEV)
1241 iRet = mtk_wcn_hif_sdio_query_chipid(1);
1242 #else
1243 iRet = mtk_wcn_wmt_chipid_query();
1244 #endif
1245 }
1246 break;
1247 case WMT_IOCTL_WMT_TELL_CHIPID:
1248 {
1249 #if !(DELETE_HIF_SDIO_CHRDEV)
1250 iRet = mtk_wcn_hif_sdio_tell_chipid(arg);
1251 #endif
1252
1253 if (0x6628 == arg || 0x6630 == arg) {
1254 wmt_lib_merge_if_flag_ctrl(1);
1255 } else {
1256 wmt_lib_merge_if_flag_ctrl(0);
1257 }
1258 }
1259 break;
1260 case WMT_IOCTL_WMT_COREDUMP_CTRL:
1261 {
1262 if (0 == arg) {
1263 mtk_wcn_stp_coredump_flag_ctrl(0);
1264 } else {
1265 mtk_wcn_stp_coredump_flag_ctrl(1);
1266 }
1267 }
1268 break;
1269 case WMT_IOCTL_WMT_STP_ASSERT_CTRL:
1270 if (MTK_WCN_BOOL_TRUE == wmt_lib_btm_cb(BTM_TRIGGER_STP_ASSERT_OP))
1271 {
1272 WMT_INFO_FUNC("trigger stp assert succeed\n");
1273 iRet = 0;
1274 }
1275 else
1276 {
1277 WMT_INFO_FUNC("trigger stp assert failed\n");
1278 iRet = -1;
1279 }
1280 break;
1281 default:
1282 iRet = -EINVAL;
1283 WMT_WARN_FUNC("unknown cmd (%d)\n", cmd);
1284 break;
1285 }
1286
1287
1288 return iRet;
1289 }
1290
1291 static int WMT_open(struct inode *inode, struct file *file)
1292 {
1293 INT32 ret;
1294
1295 WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid);
1296 if (0 == gWmtInitDone) {
1297 ret =
1298 wait_event_timeout(gWmtInitWq, gWmtInitDone != 0,
1299 msecs_to_jiffies(WMT_DEV_INIT_TO_MS));
1300 if (!ret) {
1301 WMT_WARN_FUNC("wait_event_timeout (%d)ms,(%ld)jiffies,return -EIO\n",
1302 WMT_DEV_INIT_TO_MS, msecs_to_jiffies(WMT_DEV_INIT_TO_MS));
1303 return -EIO;
1304 }
1305 }
1306 if (atomic_inc_return(&gWmtRefCnt) == 1) {
1307 WMT_INFO_FUNC("1st call\n");
1308 }
1309
1310 return 0;
1311 }
1312
1313 static int WMT_close(struct inode *inode, struct file *file)
1314 {
1315 WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid);
1316
1317 if (atomic_dec_return(&gWmtRefCnt) == 0) {
1318 WMT_INFO_FUNC("last call\n");
1319 }
1320
1321 return 0;
1322 }
1323
1324 struct file_operations gWmtFops = {
1325 .open = WMT_open,
1326 .release = WMT_close,
1327 .read = WMT_read,
1328 .write = WMT_write,
1329 /* .ioctl = WMT_ioctl, */
1330 .unlocked_ioctl = WMT_unlocked_ioctl,
1331 .poll = WMT_poll,
1332 };
1333
1334 #if REMOVE_MK_NODE
1335 struct class *wmt_class = NULL;
1336 #endif
1337
1338 #if CONSYS_WMT_REG_SUSPEND_CB_ENABLE
1339 static int wmt_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused)
1340 {
1341 switch(pm_event) {
1342 case PM_HIBERNATION_PREPARE: /* Going to hibernate */
1343 pr_warn("[%s] pm_event %lu\n", __func__, pm_event);
1344 mtk_wmt_func_off_background();
1345 return NOTIFY_DONE;
1346 case PM_POST_HIBERNATION: /* Hibernation finished */
1347 mtk_wmt_func_on_background();
1348 pr_warn("[%s] pm_event %lu\n", __func__, pm_event);
1349 return NOTIFY_DONE;
1350 }
1351 return NOTIFY_OK;
1352 }
1353
1354 static struct notifier_block wmt_pm_notifier_block = {
1355 .notifier_call = wmt_pm_event,
1356 .priority = 0,
1357 };
1358 #endif /* CONSYS_WMT_REG_SUSPEND_CB_ENABLE */
1359
1360 static int WMT_init(void)
1361 {
1362 dev_t devID = MKDEV(gWmtMajor, 0);
1363 INT32 cdevErr = -1;
1364 INT32 ret = -1;
1365 #if REMOVE_MK_NODE
1366 struct device *wmt_dev = NULL;
1367 #endif
1368
1369 WMT_INFO_FUNC("WMT Version= %s DATE=%s\n", MTK_WMT_VERSION, MTK_WMT_DATE);
1370 WMT_INFO_FUNC("COMBO Driver Version= %s\n", MTK_COMBO_DRIVER_VERSION);
1371 /* Prepare a UCHAR device */
1372 /*static allocate chrdev */
1373 gWmtInitDone = 0;
1374 init_waitqueue_head((wait_queue_head_t *) &gWmtInitWq);
1375
1376 stp_drv_init();
1377
1378 ret = register_chrdev_region(devID, WMT_DEV_NUM, WMT_DRIVER_NAME);
1379 if (ret) {
1380 WMT_ERR_FUNC("fail to register chrdev\n");
1381 return ret;
1382 }
1383
1384 cdev_init(&gWmtCdev, &gWmtFops);
1385 gWmtCdev.owner = THIS_MODULE;
1386
1387 cdevErr = cdev_add(&gWmtCdev, devID, WMT_DEV_NUM);
1388 if (cdevErr) {
1389 WMT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr);
1390 goto error;
1391 }
1392 WMT_INFO_FUNC("driver(major %d) installed\n", gWmtMajor);
1393 #if REMOVE_MK_NODE
1394 wmt_class = class_create(THIS_MODULE, "stpwmt");
1395 if (IS_ERR(wmt_class))
1396 goto error;
1397 wmt_dev = device_create(wmt_class, NULL, devID, NULL, "stpwmt");
1398 if (IS_ERR(wmt_dev))
1399 goto error;
1400 #endif
1401
1402 #if 0
1403 pWmtDevCtx = wmt_drv_create();
1404 if (!pWmtDevCtx) {
1405 WMT_ERR_FUNC("wmt_drv_create() fails\n");
1406 goto error;
1407 }
1408
1409 ret = wmt_drv_init(pWmtDevCtx);
1410 if (ret) {
1411 WMT_ERR_FUNC("wmt_drv_init() fails (%d)\n", ret);
1412 goto error;
1413 }
1414
1415 WMT_INFO_FUNC("stp_btmcb_reg\n");
1416 wmt_cdev_btmcb_reg();
1417
1418 ret = wmt_drv_start(pWmtDevCtx);
1419 if (ret) {
1420 WMT_ERR_FUNC("wmt_drv_start() fails (%d)\n", ret);
1421 goto error;
1422 }
1423 #endif
1424 ret = wmt_lib_init();
1425 if (ret) {
1426 WMT_ERR_FUNC("wmt_lib_init() fails (%d)\n", ret);
1427 goto error;
1428 }
1429 #if CFG_WMT_DBG_SUPPORT
1430 wmt_dev_dbg_setup();
1431 #endif
1432
1433 #if CFG_WMT_PROC_FOR_AEE
1434 wmt_dev_proc_for_aee_setup();
1435 #endif
1436
1437 mtk_wcn_hif_sdio_update_cb_reg(wmt_dev_tra_sdio_update);
1438 #if CONSYS_WMT_REG_SUSPEND_CB_ENABLE
1439 ret = register_pm_notifier(&wmt_pm_notifier_block);
1440 if (ret)
1441 WMT_ERR_FUNC("WMT failed to register PM notifier failed(%d)\n", ret);
1442 #endif
1443 gWmtInitDone = 1;
1444 wake_up(&gWmtInitWq);
1445 #if CONSYS_EARLYSUSPEND_ENABLE
1446 osal_sleepable_lock_init(&g_es_lr_lock);
1447 register_early_suspend(&wmt_early_suspend_handler);
1448 WMT_INFO_FUNC("register_early_suspend finished\n");
1449 #endif
1450 WMT_INFO_FUNC("success \n");
1451 return 0;
1452
1453 error:
1454 wmt_lib_deinit();
1455 #if CFG_WMT_DBG_SUPPORT
1456 wmt_dev_dbg_remove();
1457 #endif
1458 #if REMOVE_MK_NODE
1459 if (!IS_ERR(wmt_dev))
1460 device_destroy(wmt_class, devID);
1461 if (!IS_ERR(wmt_class)) {
1462 class_destroy(wmt_class);
1463 wmt_class = NULL;
1464 }
1465 #endif
1466
1467 if (cdevErr == 0) {
1468 cdev_del(&gWmtCdev);
1469 }
1470
1471 if (ret == 0) {
1472 unregister_chrdev_region(devID, WMT_DEV_NUM);
1473 gWmtMajor = -1;
1474 }
1475
1476 WMT_ERR_FUNC("fail\n");
1477
1478 return -1;
1479 }
1480
1481 static void WMT_exit(void)
1482 {
1483 dev_t dev = MKDEV(gWmtMajor, 0);
1484
1485 #if CONSYS_EARLYSUSPEND_ENABLE
1486 unregister_early_suspend(&wmt_early_suspend_handler);
1487 osal_sleepable_lock_deinit(&g_es_lr_lock);
1488 WMT_INFO_FUNC("unregister_early_suspend finished\n");
1489 #endif
1490
1491 #if CONSYS_WMT_REG_SUSPEND_CB_ENABLE
1492 unregister_pm_notifier(&wmt_pm_notifier_block);
1493 #endif
1494 wmt_lib_deinit();
1495
1496 #if CFG_WMT_DBG_SUPPORT
1497 wmt_dev_dbg_remove();
1498 #endif
1499
1500 #if CFG_WMT_PROC_FOR_AEE
1501 wmt_dev_proc_for_aee_remove();
1502 #endif
1503
1504 cdev_del(&gWmtCdev);
1505 unregister_chrdev_region(dev, WMT_DEV_NUM);
1506 gWmtMajor = -1;
1507 #if REMOVE_MK_NODE
1508 device_destroy(wmt_class, MKDEV(gWmtMajor, 0));
1509 class_destroy(wmt_class);
1510 wmt_class = NULL;
1511 #endif
1512 #ifdef MTK_WMT_WAKELOCK_SUPPORT
1513 WMT_WARN_FUNC("destroy func_on_off_wake_lock\n");
1514 wake_lock_destroy(&func_on_off_wake_lock);
1515 #endif
1516
1517 stp_drv_exit();
1518
1519 WMT_INFO_FUNC("done\n");
1520 }
1521
1522 #ifdef MTK_WCN_REMOVE_KERNEL_MODULE
1523
1524 INT32 mtk_wcn_combo_common_drv_init(VOID)
1525 {
1526 return WMT_init();
1527
1528 }
1529
1530 VOID mtk_wcn_combo_common_drv_exit(VOID)
1531 {
1532 return WMT_exit();
1533 }
1534
1535
1536 EXPORT_SYMBOL(mtk_wcn_combo_common_drv_init);
1537 EXPORT_SYMBOL(mtk_wcn_combo_common_drv_exit);
1538 #else
1539 module_init(WMT_init);
1540 module_exit(WMT_exit);
1541 #endif
1542 /* MODULE_LICENSE("Proprietary"); */
1543 MODULE_LICENSE("GPL");
1544 MODULE_AUTHOR("MediaTek Inc WCN");
1545 MODULE_DESCRIPTION("MTK WCN combo driver for WMT function");
1546
1547 module_param(gWmtMajor, uint, 0);