wmt_chrdev_wifi.c 15 KB

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