2 \brief brief description
4 Detailed descriptions here.
10 /*******************************************************************************
11 * C O M P I L E R F L A G S
12 ********************************************************************************
15 /*******************************************************************************
17 ********************************************************************************
22 /*******************************************************************************
23 * E X T E R N A L R E F E R E N C E S
24 ********************************************************************************
27 #include <linux/device.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>
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 */
53 #define WMT_DEV_INIT_TO_MS (2 * 1000)
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
;
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
= {
69 .write
= wmt_aee_write
,
77 #define WMT_DRIVER_NAME "mtk_stp_wmt"
80 P_OSAL_EVENT gpRxEvent
= NULL
;
82 UINT32 u4RxFlag
= 0x0;
83 static atomic_t gRxCount
= ATOMIC_INIT(0);
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 */
92 static UINT32 gLpbkBufLog
; /* George LPBK debug */
93 static INT32 gWmtInitDone
= 0;
94 static wait_queue_head_t gWmtInitWq
;
96 P_WMT_PATCH_INFO pPatchInfo
= NULL
;
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);
104 #if CONSYS_EARLYSUSPEND_ENABLE
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
)
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");
119 WMT_INFO_FUNC("WMT turn off LPBK suceed");
123 static void wmt_dev_late_resume(struct early_suspend
*h
)
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();
135 struct early_suspend wmt_early_suspend_handler
= {
136 .suspend
= wmt_dev_early_suspend
,
137 .resume
= wmt_dev_late_resume
,
141 UINT32 g_early_suspend_flag
= 0;
143 /*******************************************************************************
145 ********************************************************************************
149 #if CONSYS_WMT_REG_SUSPEND_CB_ENABLE || CONSYS_EARLYSUSPEND_ENABLE
151 static INT32
wmt_pwr_on_thread (void *pvData
)
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
)
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
);
163 osal_unlock_sleepable_lock(&g_es_lr_lock
);
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
);
173 WMT_INFO_FUNC("WMT turn on LPBK suceed");
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
)
181 WMT_INFO_FUNC("turn off lpbk due to early_suspend flag set\n");
182 mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK
);
184 osal_unlock_sleepable_lock(&g_es_lr_lock
);
186 WMT_INFO_FUNC("wmt_pwr_on_thread exits\n");
190 static INT32
mtk_wmt_func_on_background(void)
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
);
201 WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pThread
, iRet
);
204 /* 3. start: start running background power on thread*/
205 iRet
= osal_thread_run(pThread
);
207 WMT_ERR_FUNC("osal_thread_run(0x%p) fail(%d)\n", pThread
, iRet
);
212 static INT32
mtk_wmt_func_off_background(void)
214 if (MTK_WCN_BOOL_FALSE
== mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK
)) {
215 WMT_WARN_FUNC("WMT turn off LPBK fail\n");
219 WMT_INFO_FUNC("WMT turn off LPBK suceed");
226 #if CFG_WMT_PROC_FOR_AEE
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
)
233 WMT_INFO_FUNC("%s: count %d pos %lld\n", __func__
, count
, *f_pos
);
236 pBuf
= wmt_lib_get_cpupcr_xml_format(&len
);
238 WMT_INFO_FUNC("wmt_dev:wmt for aee buffer len(%d)\n", g_buf_len
);
241 if (g_buf_len
>= count
) {
243 retval
= copy_to_user(buf
, pBuf
, count
);
245 WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval
);
253 WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len
);
256 } else if (0 != g_buf_len
) {
258 retval
= copy_to_user(buf
, pBuf
, g_buf_len
);
260 WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval
);
270 WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len
);
272 WMT_INFO_FUNC("wmt_dev: no data avaliable for aee\n");
280 ssize_t
wmt_aee_write(struct file
*filp
, const char __user
*buf
, size_t count
, loff_t
*f_pos
)
287 static UINT32 passCnt
;
288 static int wmt_dev_proc_for_aee_read(char *page
, char **start
, off_t off
, int count
, int *eof
,
293 WMT_INFO_FUNC("wmt-dev:wmt for aee page(%p)off(%d)count(%d)\n", page
, off
, count
);
296 pBuf
= wmt_lib_get_cpupcr_xml_format(&len
);
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
,
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
);
315 return WMT_PROC_AEE_SIZE
;
317 osal_memcpy(page
, pBuf
, g_buf_len
);
332 static int wmt_dev_proc_for_aee_write(struct file
*file
, const char *buffer
, unsigned long count
,
340 INT32
wmt_dev_proc_for_aee_setup(VOID
)
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");
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");
356 gWmtAeeEntry
->read_proc
= wmt_dev_proc_for_aee_read
;
357 gWmtAeeEntry
->write_proc
= wmt_dev_proc_for_aee_write
;
363 INT32
wmt_dev_proc_for_aee_remove(VOID
)
365 #if USE_NEW_PROC_FS_FLAG
366 if (NULL
!= gWmtAeeEntry
) {
367 proc_remove(gWmtAeeEntry
);
371 if (NULL
!= gWmtAeeEntry
) {
372 remove_proc_entry(WMT_AEE_PROCNAME
, NULL
);
377 #endif /* end of "CFG_WMT_PROC_FOR_AEE" */
380 VOID
wmt_dev_rx_event_cb(VOID
)
382 if (NULL
!= gpRxEvent
) {
384 atomic_inc(&gRxCount
);
385 wake_up_interruptible(&gpRxEvent
->waitQueue
);
387 WMT_ERR_FUNC("null gpRxEvent, flush rx!\n");
393 INT32
wmt_dev_rx_timeout(P_OSAL_EVENT pEvent
)
396 UINT32 ms
= pEvent
->timeoutValue
;
401 wait_event_interruptible_timeout(gpRxEvent
->waitQueue
, 0 != u4RxFlag
,
402 msecs_to_jiffies(ms
));
404 lRet
= wait_event_interruptible(gpRxEvent
->waitQueue
, 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);
416 INT32
wmt_dev_read_file(PUINT8 pName
, const PPUINT8 ppBufPtr
, INT32 offset
, INT32 padSzBuf
)
425 /* struct cred *cred = get_task_cred(current); */
426 const struct cred
*cred
= get_current_cred();
429 WMT_ERR_FUNC("invalid ppBufptr!\n");
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
,
441 file_len
= fd
->f_path
.dentry
->d_inode
->i_size
;
442 pBuf
= vmalloc((file_len
+ BCNT_PATCH_BUF_HEADROOM
+ 3) & ~0x3UL
);
444 WMT_ERR_FUNC("failed to vmalloc(%d)\n", (INT32
) ((file_len
+ 3) & ~0x3UL
));
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");
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
,
477 filp_close(fd
, NULL
);
479 return (iRet
) ? iRet
: read_len
;
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
)
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();
495 mm_segment_t orig_fs
= get_fs();
498 WMT_WARN_FUNC("f/w patch already exists\n");
499 if ((*ppPatch
)->data
) {
500 vfree((*ppPatch
)->data
);
506 if (!osal_strlen(pPatchName
)) {
507 WMT_ERR_FUNC("empty f/w name\n");
508 osal_assert((osal_strlen(pPatchName
) > 0));
512 pfw
= kzalloc(sizeof(osal_firmware
), /*GFP_KERNEL */ GFP_ATOMIC
);
514 WMT_ERR_FUNC("kzalloc(%d) fail\n", sizeof(osal_firmware
));
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;
522 orig_uid
= current
->fsuid
;
523 orig_gid
= current
->fsgid
;
524 current
->fsuid
= current
->fsgid
= 0;
529 /* load patch file from fs */
530 iRet
= wmt_dev_read_file(pPatchName
, &pfw
->data
, 0, padSzBuf
);
533 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
534 cred
->fsuid
= orig_uid
;
535 cred
->fsgid
= orig_gid
;
537 current
->fsuid
= orig_uid
;
538 current
->fsgid
= orig_gid
;
544 WMT_DBG_FUNC("load (%s) to addr(0x%p) success\n", pPatchName
, pfw
->data
);
549 WMT_ERR_FUNC("load file (%s) fail, iRet(%d)\n", pPatchName
, iRet
);
555 INT32
wmt_dev_patch_put(osal_firmware
**ppPatch
)
557 if (NULL
!= *ppPatch
) {
558 if ((*ppPatch
)->data
) {
559 vfree((*ppPatch
)->data
);
567 VOID
wmt_dev_patch_info_free(VOID
)
575 MTK_WCN_BOOL
wmt_dev_is_file_exist(PUINT8 pFileName
)
577 struct file
*fd
= NULL
;
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
;
585 if (osal_strlen(pFileName
) < osal_strlen(defaultPatchName
)) {
586 WMT_ERR_FUNC("invalid file name(%s)\n", pFileName
);
587 return MTK_WCN_BOOL_FALSE
;
590 /* struct cred *cred = get_task_cred(current); */
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
;
598 fileLen
= fd
->f_path
.dentry
->d_inode
->i_size
;
599 filp_close(fd
, NULL
);
602 WMT_ERR_FUNC("invalid file(%s), length(%d)\n", pFileName
, fileLen
);
603 return MTK_WCN_BOOL_FALSE
;
605 WMT_ERR_FUNC("valid file(%s), length(%d)\n", pFileName
, fileLen
);
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;
614 static INT32
wmt_dev_tra_sdio_update(VOID
)
616 count_last_access_sdio
+= 1;
617 /* WMT_INFO_FUNC("jiffies_last_access_sdio: jiffies = %ul\n", jiffies); */
622 extern INT32
wmt_dev_tra_uart_update(VOID
)
624 count_last_access_uart
+= 1;
625 /* WMT_INFO_FUNC("jiffies_last_access_uart: jiffies = %ul\n", jiffies); */
630 static UINT32
wmt_dev_tra_sdio_poll(VOID
)
632 #define TIME_THRESHOLD_TO_TEMP_QUERY 3000
633 #define COUNT_THRESHOLD_TO_TEMP_QUERY 200
635 unsigned long sdio_during_count
= 0;
636 unsigned long poll_during_time
= 0;
638 if (jiffies
> jiffies_last_poll
) {
639 poll_during_time
= jiffies
- jiffies_last_poll
;
641 poll_during_time
= 0xffffffff;
644 WMT_DBG_FUNC("**jiffies_to_mesecs(0xffffffff) = %u\n", jiffies_to_msecs(0xffffffff));
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
);
652 sdio_during_count
= count_last_access_sdio
;
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
);
660 count_last_access_sdio
= 0;
661 jiffies_last_poll
= jiffies
;
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
);
671 static UINT32
wmt_dev_tra_uart_poll(void)
673 /* we not support the uart case. */
678 INT32
wmt_dev_tm_temp_query(VOID
)
680 #define HISTORY_NUM 5
681 #define TEMP_THRESHOLD 65
682 #define REFRESH_TIME 300 /* sec */
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
;
690 INT32 current_temp
= 0;
692 MTK_WCN_BOOL bRet
= MTK_WCN_BOOL_FALSE
;
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
) {
701 ("high temperature (current temp = %d), we must keep querying temp temperature..\n",
706 do_gettimeofday(&now_time
);
708 /* Query condition 2: */
709 /* Moniter the hif_sdio activity to decide if we have the need to query temperature. */
711 if (wmt_dev_tra_sdio_poll() == 0) {
713 WMT_DBG_FUNC("sdio traffic , we must query temperature..\n");
715 WMT_DBG_FUNC("sdio idle traffic ....\n");
718 /* only WIFI tx power might make temperature varies largely */
721 last_access_time
= wmt_dev_tra_uart_poll();
722 if (jiffies_to_msecs(last_access_time
) < TIME_THRESHOLD_TO_TEMP_QUERY
) {
724 WMT_DBG_FUNC("uart busy traffic , we must query temperature..\n");
727 ("uart still idle traffic , we don't query temp temperature..\n");
733 /* Query condition 3: */
734 /* If the query time exceeds the a certain of period, refresh temp table. */
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
)) {
743 ("It is long time (> %d sec) not to query, we must query temp temperature..\n",
745 for (index
= 0; index
< HISTORY_NUM
; index
++) {
746 temp_table
[index
] = 99;
752 /* update the temperature record */
753 bRet
= mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE
);
754 if (bRet
== MTK_WCN_BOOL_TRUE
)
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))
763 current_temp
= ~((INT32
)ctemp
- 1);
766 current_temp
= ctemp
;
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
);
774 idx_temp_table
= (idx_temp_table
+ 1) % HISTORY_NUM
;
775 temp_table
[idx_temp_table
] = current_temp
;
776 do_gettimeofday(&query_time
);
778 WMT_DBG_FUNC("[Thermal] current_temp = 0x%x \n", current_temp
);
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
;
786 /* Dump information */
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
);
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]);
798 ssize_t
WMT_write(struct file
*filp
, const char __user
*buf
, size_t count
, loff_t
*f_pos
)
801 UINT8 wrBuf
[NAME_MAX
+ 1] = { 0 };
802 INT32 copySize
= (count
< NAME_MAX
) ? count
: NAME_MAX
;
804 WMT_LOUD_FUNC("count:%d copySize:%d\n", count
, copySize
);
807 if (copy_from_user(wrBuf
, buf
, copySize
)) {
812 wrBuf
[NAME_MAX
] = '\0';
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);
819 WMT_WARN_FUNC("warning resp str (%s)\n", wrBuf
);
820 /* pWmtDevCtx->cmd_result = -1; */
821 wmt_lib_trigger_cmd_signal(-1);
823 /* complete(&pWmtDevCtx->cmd_comp); */
831 ssize_t
WMT_read(struct file
*filp
, char __user
*buf
, size_t count
, loff_t
*f_pos
)
836 pCmd
= wmt_lib_get_cmd();
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
)) {
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
)) {
861 unsigned int WMT_poll(struct file
*filp
, poll_table
*wait
)
864 P_OSAL_EVENT pEvent
= wmt_lib_get_cmd_event();
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 */
872 if (test_bit(WMT_STAT_CMD
, &pWmtDevCtx
->state
)) {
873 mask
|= POLLIN
| POLLRDNORM
; /* readable */
876 mask
|= POLLOUT
| POLLWRNORM
; /* writable */
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
)
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)
903 UINT8 pBuffer
[NAME_MAX
+ 1];
904 WMT_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd
, arg
);
906 case WMT_IOCTL_SET_PATCH_NAME
: /* patch location */
909 if (copy_from_user(pBuffer
, (void *)arg
, NAME_MAX
)) {
913 pBuffer
[NAME_MAX
] = '\0';
914 wmt_lib_set_patch_name(pBuffer
);
918 case WMT_IOCTL_SET_STP_MODE
: /* stp/hif/fm mode */
924 P_OSAL_SIGNAL pSignal
= NULL
;
925 P_WMT_HIF_CONF pHif
= NULL
;
927 iRet
= wmt_lib_set_hif(arg
);
929 WMT_INFO_FUNC("wmt_lib_set_hif fail (%lu)\n", arg
);
933 pOp
= wmt_lib_get_free_op();
935 WMT_INFO_FUNC("get_free_lxop fail\n");
938 pSignal
= &pOp
->signal
;
939 pOp
->op
.opId
= WMT_OPID_HIF_CONF
;
941 pHif
= wmt_lib_get_hif();
943 osal_memcpy(&pOp
->op
.au4OpData
[0], pHif
, sizeof(WMT_HIF_CONF
));
944 pOp
->op
.u4InfoBit
= WMT_OP_HIF_BIT
;
945 pSignal
->timeoutValue
= 0;
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;
954 case WMT_IOCTL_FUNC_ONOFF_CTRL
: /* test turn on/off func */
957 MTK_WCN_BOOL bRet
= MTK_WCN_BOOL_FALSE
;
958 if (arg
& 0x80000000) {
959 bRet
= mtk_wcn_wmt_func_on(arg
& 0xF);
961 bRet
= mtk_wcn_wmt_func_off(arg
& 0xF);
963 iRet
= (MTK_WCN_BOOL_FALSE
== bRet
) ? -EFAULT
: 0;
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
974 MTK_WCN_BOOL bRet
= MTK_WCN_BOOL_FALSE
;
976 bRet
= mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK
);
978 bRet
= mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK
);
980 iRet
= (MTK_WCN_BOOL_FALSE
== bRet
) ? -EFAULT
: 0;
987 case WMT_IOCTL_LPBK_TEST
:
992 /* UINT8 lpbk_buf[1024] = {0}; */
993 UINT32 effectiveLen
= 0;
994 P_OSAL_SIGNAL pSignal
= NULL
;
996 if (copy_from_user(&effectiveLen
, (void *)arg
, sizeof(effectiveLen
))) {
998 WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__
);
1001 if (effectiveLen
> sizeof(gLpbkBuf
)) {
1003 WMT_ERR_FUNC("length is too long\n");
1006 WMT_DBG_FUNC("len = %d\n", effectiveLen
);
1008 pOp
= wmt_lib_get_free_op();
1010 WMT_WARN_FUNC("get_free_lxop fail\n");
1016 (&gLpbkBuf
[0], (void *)arg
+ sizeof(unsigned long), effectiveLen
)) {
1017 WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__
);
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
);
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
);
1044 WMT_INFO_FUNC("OPID(%d) length(%d) ok\n",
1045 pOp
->op
.opId
, pOp
->op
.au4OpData
[0]);
1046 iRet
= pOp
->op
.au4OpData
[0];
1048 ((void *)arg
+ sizeof(unsigned long) + sizeof(UINT8
[2048]), gLpbkBuf
,
1060 #define LOG_BUF_SZ 300
1061 UINT8 buf
[LOG_BUF_SZ
];
1063 INT32 remaining
= 0;
1065 remaining
= mtk_wcn_stp_btm_get_dmp(buf
, &len
);
1067 if (remaining
== 0) {
1068 WMT_DBG_FUNC("waiting dmp\n");
1069 wait_event_interruptible(dmp_wq
, dmp_flag
!= 0);
1071 remaining
= mtk_wcn_stp_btm_get_dmp(buf
, &len
);
1073 /* WMT_INFO_FUNC("len = %d ###%s#\n", len, buf); */
1075 WMT_LOUD_FUNC("no waiting dmp\n");
1078 if (unlikely((len
+ sizeof(INT32
)) >= LOG_BUF_SZ
)) {
1079 WMT_ERR_FUNC("len is larger buffer\n");
1084 buf
[sizeof(INT32
) + len
] = '\0';
1086 if (copy_to_user((void *)arg
, (PUINT8
)&len
, sizeof(INT32
))) {
1091 if (copy_to_user((void *)arg
+ sizeof(INT32
), buf
, len
)) {
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();
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();
1119 wmt_lib_host_awake_get();
1120 mtk_wcn_stp_coredump_start_ctrl(1);
1121 osal_strcpy(pBuffer
, "MT662x f/w coredump start-");
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");
1128 pBuffer
[NAME_MAX
] = '\0';
1129 osal_dbg_assert_aee(pBuffer
, pBuffer
);
1134 osal_dbg_assert_aee("MT662x f/w coredump end",
1135 "MT662x firmware coredump ends");
1136 wmt_lib_host_awake_put();
1141 case WMT_IOCTL_GET_CHIP_INFO
:
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
);
1153 case WMT_IOCTL_SET_LAUNCHER_KILL
:{
1155 WMT_INFO_FUNC("launcher may be killed,block abnormal stp tx.\n");
1156 wmt_lib_set_stp_wmt_last_close(1);
1158 wmt_lib_set_stp_wmt_last_close(0);
1164 case WMT_IOCTL_SET_PATCH_NUM
:{
1166 if (pAtchNum
== 0 || pAtchNum
> MAX_PATCH_NUM
) {
1167 WMT_ERR_FUNC("patch num(%d) == 0 or > %d!\n", pAtchNum
, MAX_PATCH_NUM
);
1172 pPatchInfo
= kzalloc(sizeof(WMT_PATCH_INFO
) * pAtchNum
, GFP_ATOMIC
);
1174 WMT_ERR_FUNC("allocate memory fail!\n");
1178 WMT_INFO_FUNC(" get patch num from launcher = %d\n", pAtchNum
);
1179 wmt_lib_set_patch_num(pAtchNum
);
1183 case WMT_IOCTL_SET_PATCH_INFO
:{
1184 WMT_PATCH_INFO wMtPatchInfo
;
1185 P_WMT_PATCH_INFO pTemp
= NULL
;
1187 static UINT32 counter
= 0;
1190 WMT_ERR_FUNC("NULL patch info pointer\n");
1194 if (copy_from_user(&wMtPatchInfo
, (void *)arg
, sizeof(WMT_PATCH_INFO
))) {
1195 WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__
);
1200 dWloadSeq
= wMtPatchInfo
.dowloadSeq
;
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
);
1216 case WMT_IOCTL_PORT_NAME
:{
1217 INT8 cUartName
[NAME_MAX
+ 1];
1218 if (copy_from_user(cUartName
, (void *)arg
, NAME_MAX
)) {
1222 cUartName
[NAME_MAX
] = '\0';
1223 wmt_lib_set_uart_name(cUartName
);
1227 case WMT_IOCTL_WMT_CFG_NAME
:
1229 INT8 cWmtCfgName
[NAME_MAX
+ 1];
1230 if (copy_from_user(cWmtCfgName
, (void *)arg
, NAME_MAX
)) {
1234 cWmtCfgName
[NAME_MAX
] = '\0';
1235 wmt_conf_set_cfg_file(cWmtCfgName
);
1238 case WMT_IOCTL_WMT_QUERY_CHIPID
:
1240 #if !(DELETE_HIF_SDIO_CHRDEV)
1241 iRet
= mtk_wcn_hif_sdio_query_chipid(1);
1243 iRet
= mtk_wcn_wmt_chipid_query();
1247 case WMT_IOCTL_WMT_TELL_CHIPID
:
1249 #if !(DELETE_HIF_SDIO_CHRDEV)
1250 iRet
= mtk_wcn_hif_sdio_tell_chipid(arg
);
1253 if (0x6628 == arg
|| 0x6630 == arg
) {
1254 wmt_lib_merge_if_flag_ctrl(1);
1256 wmt_lib_merge_if_flag_ctrl(0);
1260 case WMT_IOCTL_WMT_COREDUMP_CTRL
:
1263 mtk_wcn_stp_coredump_flag_ctrl(0);
1265 mtk_wcn_stp_coredump_flag_ctrl(1);
1269 case WMT_IOCTL_WMT_STP_ASSERT_CTRL
:
1270 if (MTK_WCN_BOOL_TRUE
== wmt_lib_btm_cb(BTM_TRIGGER_STP_ASSERT_OP
))
1272 WMT_INFO_FUNC("trigger stp assert succeed\n");
1277 WMT_INFO_FUNC("trigger stp assert failed\n");
1283 WMT_WARN_FUNC("unknown cmd (%d)\n", cmd
);
1291 static int WMT_open(struct inode
*inode
, struct file
*file
)
1295 WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode
), iminor(inode
), current
->pid
);
1296 if (0 == gWmtInitDone
) {
1298 wait_event_timeout(gWmtInitWq
, gWmtInitDone
!= 0,
1299 msecs_to_jiffies(WMT_DEV_INIT_TO_MS
));
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
));
1306 if (atomic_inc_return(&gWmtRefCnt
) == 1) {
1307 WMT_INFO_FUNC("1st call\n");
1313 static int WMT_close(struct inode
*inode
, struct file
*file
)
1315 WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode
), iminor(inode
), current
->pid
);
1317 if (atomic_dec_return(&gWmtRefCnt
) == 0) {
1318 WMT_INFO_FUNC("last call\n");
1324 struct file_operations gWmtFops
= {
1326 .release
= WMT_close
,
1329 /* .ioctl = WMT_ioctl, */
1330 .unlocked_ioctl
= WMT_unlocked_ioctl
,
1335 struct class *wmt_class
= NULL
;
1338 #if CONSYS_WMT_REG_SUSPEND_CB_ENABLE
1339 static int wmt_pm_event(struct notifier_block
*notifier
, unsigned long pm_event
, void *unused
)
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();
1346 case PM_POST_HIBERNATION
: /* Hibernation finished */
1347 mtk_wmt_func_on_background();
1348 pr_warn("[%s] pm_event %lu\n", __func__
, pm_event
);
1354 static struct notifier_block wmt_pm_notifier_block
= {
1355 .notifier_call
= wmt_pm_event
,
1358 #endif /* CONSYS_WMT_REG_SUSPEND_CB_ENABLE */
1360 static int WMT_init(void)
1362 dev_t devID
= MKDEV(gWmtMajor
, 0);
1366 struct device
*wmt_dev
= NULL
;
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 */
1374 init_waitqueue_head((wait_queue_head_t
*) &gWmtInitWq
);
1378 ret
= register_chrdev_region(devID
, WMT_DEV_NUM
, WMT_DRIVER_NAME
);
1380 WMT_ERR_FUNC("fail to register chrdev\n");
1384 cdev_init(&gWmtCdev
, &gWmtFops
);
1385 gWmtCdev
.owner
= THIS_MODULE
;
1387 cdevErr
= cdev_add(&gWmtCdev
, devID
, WMT_DEV_NUM
);
1389 WMT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr
);
1392 WMT_INFO_FUNC("driver(major %d) installed\n", gWmtMajor
);
1394 wmt_class
= class_create(THIS_MODULE
, "stpwmt");
1395 if (IS_ERR(wmt_class
))
1397 wmt_dev
= device_create(wmt_class
, NULL
, devID
, NULL
, "stpwmt");
1398 if (IS_ERR(wmt_dev
))
1403 pWmtDevCtx
= wmt_drv_create();
1405 WMT_ERR_FUNC("wmt_drv_create() fails\n");
1409 ret
= wmt_drv_init(pWmtDevCtx
);
1411 WMT_ERR_FUNC("wmt_drv_init() fails (%d)\n", ret
);
1415 WMT_INFO_FUNC("stp_btmcb_reg\n");
1416 wmt_cdev_btmcb_reg();
1418 ret
= wmt_drv_start(pWmtDevCtx
);
1420 WMT_ERR_FUNC("wmt_drv_start() fails (%d)\n", ret
);
1424 ret
= wmt_lib_init();
1426 WMT_ERR_FUNC("wmt_lib_init() fails (%d)\n", ret
);
1429 #if CFG_WMT_DBG_SUPPORT
1430 wmt_dev_dbg_setup();
1433 #if CFG_WMT_PROC_FOR_AEE
1434 wmt_dev_proc_for_aee_setup();
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
);
1441 WMT_ERR_FUNC("WMT failed to register PM notifier failed(%d)\n", ret
);
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");
1450 WMT_INFO_FUNC("success \n");
1455 #if CFG_WMT_DBG_SUPPORT
1456 wmt_dev_dbg_remove();
1459 if (!IS_ERR(wmt_dev
))
1460 device_destroy(wmt_class
, devID
);
1461 if (!IS_ERR(wmt_class
)) {
1462 class_destroy(wmt_class
);
1468 cdev_del(&gWmtCdev
);
1472 unregister_chrdev_region(devID
, WMT_DEV_NUM
);
1476 WMT_ERR_FUNC("fail\n");
1481 static void WMT_exit(void)
1483 dev_t dev
= MKDEV(gWmtMajor
, 0);
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");
1491 #if CONSYS_WMT_REG_SUSPEND_CB_ENABLE
1492 unregister_pm_notifier(&wmt_pm_notifier_block
);
1496 #if CFG_WMT_DBG_SUPPORT
1497 wmt_dev_dbg_remove();
1500 #if CFG_WMT_PROC_FOR_AEE
1501 wmt_dev_proc_for_aee_remove();
1504 cdev_del(&gWmtCdev
);
1505 unregister_chrdev_region(dev
, WMT_DEV_NUM
);
1508 device_destroy(wmt_class
, MKDEV(gWmtMajor
, 0));
1509 class_destroy(wmt_class
);
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
);
1519 WMT_INFO_FUNC("done\n");
1522 #ifdef MTK_WCN_REMOVE_KERNEL_MODULE
1524 INT32
mtk_wcn_combo_common_drv_init(VOID
)
1530 VOID
mtk_wcn_combo_common_drv_exit(VOID
)
1536 EXPORT_SYMBOL(mtk_wcn_combo_common_drv_init
);
1537 EXPORT_SYMBOL(mtk_wcn_combo_common_drv_exit
);
1539 module_init(WMT_init
);
1540 module_exit(WMT_exit
);
1542 /* MODULE_LICENSE("Proprietary"); */
1543 MODULE_LICENSE("GPL");
1544 MODULE_AUTHOR("MediaTek Inc WCN");
1545 MODULE_DESCRIPTION("MTK WCN combo driver for WMT function");
1547 module_param(gWmtMajor
, uint
, 0);