wmt_dev.c 41 KB

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