Merge tag 'pci-v5.18-changes-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / staging / r8188eu / core / rtw_cmd.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2007 - 2012 Realtek Corporation. */
3
4 #define _RTW_CMD_C_
5
6 #include "../include/osdep_service.h"
7 #include "../include/drv_types.h"
8 #include "../include/recv_osdep.h"
9 #include "../include/mlme_osdep.h"
10 #include "../include/rtw_br_ext.h"
11 #include "../include/rtw_mlme_ext.h"
12 #include "../include/rtl8188e_dm.h"
13
14 /*
15 Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
16 No irqsave is necessary.
17 */
18
19 static int _rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
20 {
21         int res = _SUCCESS;
22
23         init_completion(&pcmdpriv->enqueue_cmd);
24         /* sema_init(&(pcmdpriv->cmd_done_sema), 0); */
25         init_completion(&pcmdpriv->start_cmd_thread);
26         init_completion(&pcmdpriv->stop_cmd_thread);
27
28         rtw_init_queue(&pcmdpriv->cmd_queue);
29
30         /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
31
32         pcmdpriv->cmd_seq = 1;
33
34         pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
35                                               GFP_KERNEL);
36
37         if (!pcmdpriv->cmd_allocated_buf) {
38                 res = _FAIL;
39                 goto exit;
40         }
41
42         pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ - ((size_t)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ - 1));
43
44         pcmdpriv->rsp_allocated_buf = kzalloc(MAX_RSPSZ + 4, GFP_KERNEL);
45
46         if (!pcmdpriv->rsp_allocated_buf) {
47                 res = _FAIL;
48                 goto exit;
49         }
50
51         pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 - ((size_t)(pcmdpriv->rsp_allocated_buf) & 3);
52
53         pcmdpriv->cmd_done_cnt = 0;
54         pcmdpriv->rsp_cnt = 0;
55 exit:
56
57         return res;
58 }
59
60 static void c2h_wk_callback(struct work_struct *work);
61
62 static int _rtw_init_evt_priv(struct evt_priv *pevtpriv)
63 {
64         int res = _SUCCESS;
65
66         /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
67         atomic_set(&pevtpriv->event_seq, 0);
68
69         INIT_WORK(&pevtpriv->c2h_wk, c2h_wk_callback);
70         pevtpriv->c2h_wk_alive = false;
71         pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN + 1);
72
73         return res;
74 }
75
76 void rtw_free_evt_priv(struct   evt_priv *pevtpriv)
77 {
78         cancel_work_sync(&pevtpriv->c2h_wk);
79         while (pevtpriv->c2h_wk_alive)
80                 msleep(10);
81
82         while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
83                 void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue);
84                 if (c2h && c2h != (void *)pevtpriv)
85                         kfree(c2h);
86         }
87 }
88
89 static void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv)
90 {
91         if (pcmdpriv) {
92                 kfree(pcmdpriv->cmd_allocated_buf);
93                 kfree(pcmdpriv->rsp_allocated_buf);
94         }
95 }
96
97 /*
98 Calling Context:
99
100 rtw_enqueue_cmd can only be called between kernel thread,
101 since only spin_lock is used.
102
103 ISR/Call-Back functions can't call this sub-function.
104
105 */
106
107 static int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
108 {
109         unsigned long flags;
110
111         if (!obj)
112                 goto exit;
113
114         spin_lock_irqsave(&queue->lock, flags);
115
116         list_add_tail(&obj->list, &queue->queue);
117
118         spin_unlock_irqrestore(&queue->lock, flags);
119
120 exit:
121
122         return _SUCCESS;
123 }
124
125 static struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue)
126 {
127         struct cmd_obj *obj;
128         unsigned long flags;
129
130         spin_lock_irqsave(&queue->lock, flags);
131         if (list_empty(&queue->queue)) {
132                 obj = NULL;
133         } else {
134                 obj = container_of((&queue->queue)->next, struct cmd_obj, list);
135                 list_del_init(&obj->list);
136         }
137
138         spin_unlock_irqrestore(&queue->lock, flags);
139
140         return obj;
141 }
142
143 u32     rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
144 {
145         u32     res;
146
147         res = _rtw_init_cmd_priv(pcmdpriv);
148
149         return res;
150 }
151
152 u32 rtw_init_evt_priv(struct evt_priv *pevtpriv)
153 {
154         int     res;
155
156         res = _rtw_init_evt_priv(pevtpriv);
157
158         return res;
159 }
160
161 void rtw_free_cmd_priv(struct   cmd_priv *pcmdpriv)
162 {
163         _rtw_free_cmd_priv(pcmdpriv);
164 }
165
166 static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
167 {
168         u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
169
170         if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
171                 bAllow = true;
172
173         if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
174             !pcmdpriv->cmdthd_running)  /* com_thread not running */
175                 return _FAIL;
176         return _SUCCESS;
177 }
178
179 u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
180 {
181         int res = _FAIL;
182         struct adapter *padapter = pcmdpriv->padapter;
183
184         if (!cmd_obj)
185                 goto exit;
186
187         cmd_obj->padapter = padapter;
188
189         res = rtw_cmd_filter(pcmdpriv, cmd_obj);
190         if (_FAIL == res) {
191                 rtw_free_cmd_obj(cmd_obj);
192                 goto exit;
193         }
194
195         res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
196
197         if (res == _SUCCESS)
198                 complete(&pcmdpriv->enqueue_cmd);
199
200 exit:
201
202         return res;
203 }
204
205 struct  cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
206 {
207         struct cmd_obj *cmd_obj;
208
209         cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
210
211         return cmd_obj;
212 }
213
214 void rtw_free_cmd_obj(struct cmd_obj *pcmd)
215 {
216
217         if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) {
218                 /* free parmbuf in cmd_obj */
219                 kfree(pcmd->parmbuf);
220         }
221
222         if (pcmd->rsp) {
223                 if (pcmd->rspsz != 0) {
224                         /* free rsp in cmd_obj */
225                         kfree(pcmd->rsp);
226                 }
227         }
228
229         /* free cmd_obj */
230         kfree(pcmd);
231
232 }
233
234 int rtw_cmd_thread(void *context)
235 {
236         u8 ret;
237         struct cmd_obj *pcmd;
238         u8 *pcmdbuf;
239         u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
240         void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd);
241         struct adapter *padapter = (struct adapter *)context;
242         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
243
244         pcmdbuf = pcmdpriv->cmd_buf;
245
246         pcmdpriv->cmdthd_running = true;
247         complete(&pcmdpriv->start_cmd_thread);
248
249         while (1) {
250                 wait_for_completion(&pcmdpriv->enqueue_cmd);
251
252 _next:
253                 if (padapter->bDriverStopped ||
254                     padapter->bSurpriseRemoved)
255                         break;
256
257                 pcmd = rtw_dequeue_cmd(pcmdpriv);
258                 if (!pcmd)
259                         continue;
260
261                 if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) {
262                         pcmd->res = H2C_DROPPED;
263                         goto post_process;
264                 }
265
266                 pcmd->cmdsz = _RND4((pcmd->cmdsz));/* _RND4 */
267
268                 memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
269
270                 if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
271                         cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
272
273                         if (cmd_hdl) {
274                                 ret = cmd_hdl(pcmd->padapter, pcmdbuf);
275                                 pcmd->res = ret;
276                         }
277
278                         pcmdpriv->cmd_seq++;
279                 } else {
280                         pcmd->res = H2C_PARAMETERS_ERROR;
281                 }
282
283                 cmd_hdl = NULL;
284
285 post_process:
286
287                 /* call callback function for post-processed */
288                 if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
289                         pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
290                         if (!pcmd_callback)
291                                 rtw_free_cmd_obj(pcmd);
292                         else
293                                 /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
294                                 pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */
295                 } else {
296                         rtw_free_cmd_obj(pcmd);
297                 }
298
299                 flush_signals_thread();
300
301                 goto _next;
302         }
303         pcmdpriv->cmdthd_running = false;
304
305         /*  free all cmd_obj resources */
306         do {
307                 pcmd = rtw_dequeue_cmd(pcmdpriv);
308                 if (!pcmd)
309                         break;
310
311                 rtw_free_cmd_obj(pcmd);
312         } while (1);
313
314         complete(&pcmdpriv->stop_cmd_thread);
315
316         return 0;
317 }
318
319 /*
320 rtw_sitesurvey_cmd(~)
321         ### NOTE:#### (!!!!)
322         MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
323 */
324 u8 rtw_sitesurvey_cmd(struct adapter  *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
325         struct rtw_ieee80211_channel *ch, int ch_num)
326 {
327         u8 res = _FAIL;
328         struct cmd_obj          *ph2c;
329         struct sitesurvey_parm  *psurveyPara;
330         struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
331         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
332
333         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
334                 rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
335         }
336
337         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
338                 p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1);
339         }
340
341         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
342         if (!ph2c)
343                 return _FAIL;
344
345         psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
346         if (!psurveyPara) {
347                 kfree(ph2c);
348                 return _FAIL;
349         }
350
351         rtw_free_network_queue(padapter, false);
352
353         init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
354
355         /* psurveyPara->bsslimit = 48; */
356         psurveyPara->scan_mode = pmlmepriv->scan_mode;
357
358         /* prepare ssid list */
359         if (ssid) {
360                 int i;
361                 for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
362                         if (ssid[i].SsidLength) {
363                                 memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
364                                 psurveyPara->ssid_num++;
365                         }
366                 }
367         }
368
369         /* prepare channel list */
370         if (ch) {
371                 int i;
372                 for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
373                         if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
374                                 memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
375                                 psurveyPara->ch_num++;
376                         }
377                 }
378         }
379
380         set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
381
382         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
383
384         if (res == _SUCCESS) {
385                 pmlmepriv->scan_start_time = jiffies;
386
387                 _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT);
388
389                 rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
390
391                 pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
392         } else {
393                 _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
394         }
395
396         return res;
397 }
398
399 u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset)
400 {
401         struct cmd_obj *ph2c;
402         struct setdatarate_parm *pbsetdataratepara;
403         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
404         u8      res = _SUCCESS;
405
406         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
407         if (!ph2c) {
408                 res = _FAIL;
409                 goto exit;
410         }
411
412         pbsetdataratepara = kzalloc(sizeof(struct setdatarate_parm), GFP_ATOMIC);
413         if (!pbsetdataratepara) {
414                 kfree(ph2c);
415                 res = _FAIL;
416                 goto exit;
417         }
418
419         init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
420         pbsetdataratepara->mac_id = 5;
421         memcpy(pbsetdataratepara->datarates, rateset, NumRates);
422         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
423 exit:
424
425         return res;
426 }
427
428 void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
429 {
430
431
432         kfree(pcmd->parmbuf);
433         kfree(pcmd);
434 }
435
436 u8 rtw_createbss_cmd(struct adapter  *padapter)
437 {
438         struct cmd_obj *pcmd;
439         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
440         struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
441         u8      res = _SUCCESS;
442
443         rtw_led_control(padapter, LED_CTL_START_TO_LINK);
444
445         pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
446         if (!pcmd) {
447                 res = _FAIL;
448                 goto exit;
449         }
450
451         INIT_LIST_HEAD(&pcmd->list);
452         pcmd->cmdcode = _CreateBss_CMD_;
453         pcmd->parmbuf = (unsigned char *)pdev_network;
454         pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
455         pcmd->rsp = NULL;
456         pcmd->rspsz = 0;
457         pdev_network->Length = pcmd->cmdsz;
458         res = rtw_enqueue_cmd(pcmdpriv, pcmd);
459 exit:
460
461         return res;
462 }
463
464 u8 rtw_joinbss_cmd(struct adapter  *padapter, struct wlan_network *pnetwork)
465 {
466         u8      res = _SUCCESS;
467         uint    t_len = 0;
468         struct wlan_bssid_ex            *psecnetwork;
469         struct cmd_obj          *pcmd;
470         struct cmd_priv         *pcmdpriv = &padapter->cmdpriv;
471         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
472         struct qos_priv         *pqospriv = &pmlmepriv->qospriv;
473         struct security_priv    *psecuritypriv = &padapter->securitypriv;
474         struct registry_priv    *pregistrypriv = &padapter->registrypriv;
475         struct ht_priv          *phtpriv = &pmlmepriv->htpriv;
476         enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode;
477         struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
478         struct mlme_ext_info    *pmlmeinfo = &pmlmeext->mlmext_info;
479
480         rtw_led_control(padapter, LED_CTL_START_TO_LINK);
481
482         pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
483         if (!pcmd) {
484                 res = _FAIL;
485                 goto exit;
486         }
487         /* for IEs is fix buf size */
488         t_len = sizeof(struct wlan_bssid_ex);
489
490         /* for hidden ap to set fw_state here */
491         if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) {
492                 switch (ndis_network_mode) {
493                 case Ndis802_11IBSS:
494                         set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
495                         break;
496                 case Ndis802_11Infrastructure:
497                         set_fwstate(pmlmepriv, WIFI_STATION_STATE);
498                         break;
499                 case Ndis802_11APMode:
500                 case Ndis802_11AutoUnknown:
501                 case Ndis802_11InfrastructureMax:
502                         break;
503                 }
504         }
505
506         psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss;
507         if (!psecnetwork) {
508                 kfree(pcmd);
509                 res = _FAIL;
510                 goto exit;
511         }
512
513         memset(psecnetwork, 0, t_len);
514
515         memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
516
517         psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
518
519         if (psecnetwork->IELength - 12 < 255) {
520                 memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength - 12);
521         } else {
522                 memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], 255);
523         }
524
525         psecnetwork->IELength = 0;
526         /*  Added by Albert 2009/02/18 */
527         /*  If the the driver wants to use the bssid to create the connection. */
528         /*  If not,  we have to copy the connecting AP's MAC address to it so that */
529         /*  the driver just has the bssid information for PMKIDList searching. */
530
531         if (!pmlmepriv->assoc_by_bssid)
532                 memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN);
533
534         psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength);
535
536         pqospriv->qos_option = 0;
537
538         if (pregistrypriv->wmm_enable) {
539                 u32 tmp_len;
540
541                 tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength);
542
543                 if (psecnetwork->IELength != tmp_len) {
544                         psecnetwork->IELength = tmp_len;
545                         pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */
546                 } else {
547                         pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */
548                 }
549         }
550
551         phtpriv->ht_option = false;
552         if (pregistrypriv->ht_enable) {
553                 /*      Added by Albert 2010/06/23 */
554                 /*      For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */
555                 /*      Especially for Realtek 8192u SoftAP. */
556                 if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
557                     (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
558                     (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
559                         /* rtw_restructure_ht_ie */
560                         rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0],
561                                                                         pnetwork->network.IELength, &psecnetwork->IELength);
562                 }
563         }
564
565         pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
566
567         if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA)
568                 padapter->pwrctrlpriv.smart_ps = 0;
569         else
570                 padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps;
571
572         pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
573
574         INIT_LIST_HEAD(&pcmd->list);
575         pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */
576         pcmd->parmbuf = (unsigned char *)psecnetwork;
577         pcmd->rsp = NULL;
578         pcmd->rspsz = 0;
579
580         res = rtw_enqueue_cmd(pcmdpriv, pcmd);
581
582 exit:
583
584         return res;
585 }
586
587 u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
588 {
589         struct cmd_obj *cmdobj = NULL;
590         struct disconnect_parm *param = NULL;
591         struct cmd_priv *cmdpriv = &padapter->cmdpriv;
592         u8 res = _SUCCESS;
593
594         /* prepare cmd parameter */
595         param = kzalloc(sizeof(*param), GFP_ATOMIC);
596         if (!param) {
597                 res = _FAIL;
598                 goto exit;
599         }
600         param->deauth_timeout_ms = deauth_timeout_ms;
601
602         if (enqueue) {
603                 /* need enqueue, prepare cmd_obj and enqueue */
604                 cmdobj = kzalloc(sizeof(*cmdobj), GFP_ATOMIC);
605                 if (!cmdobj) {
606                         res = _FAIL;
607                         kfree(param);
608                         goto exit;
609                 }
610                 init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
611                 res = rtw_enqueue_cmd(cmdpriv, cmdobj);
612         } else {
613                 /* no need to enqueue, do the cmd hdl directly and free cmd parameter */
614                 if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param))
615                         res = _FAIL;
616                 kfree(param);
617         }
618
619 exit:
620
621         return res;
622 }
623
624 u8 rtw_setopmode_cmd(struct adapter  *padapter, enum ndis_802_11_network_infra networktype)
625 {
626         struct  cmd_obj *ph2c;
627         struct  setopmode_parm *psetop;
628
629         struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
630         u8      res = _SUCCESS;
631
632         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
633         if (!ph2c) {
634                 res = false;
635                 goto exit;
636         }
637         psetop = kzalloc(sizeof(struct setopmode_parm), GFP_KERNEL);
638
639         if (!psetop) {
640                 kfree(ph2c);
641                 res = false;
642                 goto exit;
643         }
644
645         init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
646         psetop->mode = (u8)networktype;
647
648         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
649
650 exit:
651
652         return res;
653 }
654
655 u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
656 {
657         struct cmd_obj *ph2c;
658         struct set_stakey_parm *psetstakey_para;
659         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
660         struct set_stakey_rsp *psetstakey_rsp = NULL;
661
662         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
663         struct security_priv *psecuritypriv = &padapter->securitypriv;
664         struct sta_info *sta = (struct sta_info *)psta;
665         u8      res = _SUCCESS;
666
667         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
668         if (!ph2c) {
669                 res = _FAIL;
670                 goto exit;
671         }
672
673         psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL);
674         if (!psetstakey_para) {
675                 kfree(ph2c);
676                 res = _FAIL;
677                 goto exit;
678         }
679
680         psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_KERNEL);
681         if (!psetstakey_rsp) {
682                 kfree(ph2c);
683                 kfree(psetstakey_para);
684                 res = _FAIL;
685                 goto exit;
686         }
687
688         init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
689         ph2c->rsp = (u8 *)psetstakey_rsp;
690         ph2c->rspsz = sizeof(struct set_stakey_rsp);
691
692         memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
693
694         if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
695                 psetstakey_para->algorithm = (unsigned char)psecuritypriv->dot11PrivacyAlgrthm;
696         else
697                 GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
698
699         if (unicast_key)
700                 memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
701         else
702                 memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
703
704         /* jeff: set this because at least sw key is ready */
705         padapter->securitypriv.busetkipkey = true;
706
707         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
708
709 exit:
710
711         return res;
712 }
713
714 u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
715 {
716         struct cmd_obj *ph2c;
717         struct set_stakey_parm  *psetstakey_para;
718         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
719         struct set_stakey_rsp *psetstakey_rsp = NULL;
720         struct sta_info *sta = (struct sta_info *)psta;
721         u8      res = _SUCCESS;
722
723         if (!enqueue) {
724                 clear_cam_entry(padapter, entry);
725         } else {
726                 ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
727                 if (!ph2c) {
728                         res = _FAIL;
729                         goto exit;
730                 }
731
732                 psetstakey_para = kzalloc(sizeof(struct set_stakey_parm),
733                                           GFP_ATOMIC);
734                 if (!psetstakey_para) {
735                         kfree(ph2c);
736                         res = _FAIL;
737                         goto exit;
738                 }
739
740                 psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp),
741                                          GFP_ATOMIC);
742                 if (!psetstakey_rsp) {
743                         kfree(ph2c);
744                         kfree(psetstakey_para);
745                         res = _FAIL;
746                         goto exit;
747                 }
748
749                 init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
750                 ph2c->rsp = (u8 *)psetstakey_rsp;
751                 ph2c->rspsz = sizeof(struct set_stakey_rsp);
752
753                 memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
754
755                 psetstakey_para->algorithm = _NO_PRIVACY_;
756
757                 psetstakey_para->id = entry;
758
759                 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
760         }
761 exit:
762
763         return res;
764 }
765
766 u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
767 {
768         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
769         struct cmd_obj *ph2c;
770         struct addBaReq_parm *paddbareq_parm;
771         u8      res = _SUCCESS;
772
773         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
774         if (!ph2c) {
775                 res = _FAIL;
776                 goto exit;
777         }
778
779         paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_ATOMIC);
780         if (!paddbareq_parm) {
781                 kfree(ph2c);
782                 res = _FAIL;
783                 goto exit;
784         }
785
786         paddbareq_parm->tid = tid;
787         memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
788
789         init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
790
791         /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
792         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
793
794 exit:
795
796         return res;
797 }
798
799 u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
800 {
801         struct cmd_obj *ph2c;
802         struct drvextra_cmd_parm *pdrvextra_cmd_parm;
803         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
804         u8      res = _SUCCESS;
805
806         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
807         if (!ph2c) {
808                 res = _FAIL;
809                 goto exit;
810         }
811
812         pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
813         if (!pdrvextra_cmd_parm) {
814                 kfree(ph2c);
815                 res = _FAIL;
816                 goto exit;
817         }
818
819         pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
820         pdrvextra_cmd_parm->type_size = 0;
821         pdrvextra_cmd_parm->pbuf = (u8 *)padapter;
822
823         init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
824
825         /* rtw_enqueue_cmd(pcmdpriv, ph2c); */
826         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
827 exit:
828
829         return res;
830 }
831
832 u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan)
833 {
834         struct  cmd_obj *pcmdobj;
835         struct  SetChannelPlan_param *setChannelPlan_param;
836         struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
837
838         u8      res = _SUCCESS;
839
840         /* check input parameter */
841         if (!rtw_is_channel_plan_valid(chplan)) {
842                 res = _FAIL;
843                 goto exit;
844         }
845
846         /* prepare cmd parameter */
847         setChannelPlan_param = kzalloc(sizeof(struct SetChannelPlan_param),
848                                        GFP_KERNEL);
849         if (!setChannelPlan_param) {
850                 res = _FAIL;
851                 goto exit;
852         }
853         setChannelPlan_param->channel_plan = chplan;
854
855         /* need enqueue, prepare cmd_obj and enqueue */
856         pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
857         if (!pcmdobj) {
858                 kfree(setChannelPlan_param);
859                 res = _FAIL;
860                 goto exit;
861         }
862
863         init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan));
864         res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
865
866         /* do something based on res... */
867         if (res == _SUCCESS)
868                 padapter->mlmepriv.ChannelPlan = chplan;
869
870 exit:
871
872         return res;
873 }
874
875 static void traffic_status_watchdog(struct adapter *padapter)
876 {
877         u8      bEnterPS;
878         u8      bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
879         u8      bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false;
880         struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
881
882         /*  */
883         /*  Determine if our traffic is busy now */
884         /*  */
885         if (check_fwstate(pmlmepriv, _FW_LINKED)) {
886                 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 ||
887                     pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) {
888                         bBusyTraffic = true;
889
890                         if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
891                                 bRxBusyTraffic = true;
892                         else
893                                 bTxBusyTraffic = true;
894                 }
895
896                 /*  Higher Tx/Rx data. */
897                 if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
898                     pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
899                         bHigherBusyTraffic = true;
900
901                         if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
902                                 bHigherBusyRxTraffic = true;
903                         else
904                                 bHigherBusyTxTraffic = true;
905                 }
906
907                 /*  check traffic for  powersaving. */
908                 if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
909                     (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2))
910                         bEnterPS = false;
911                 else
912                         bEnterPS = true;
913
914                 /*  LeisurePS only work in infra mode. */
915                 if (bEnterPS)
916                         LPS_Enter(padapter);
917                 else
918                         LPS_Leave(padapter);
919         } else {
920                 LPS_Leave(padapter);
921         }
922
923         pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
924         pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
925         pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
926         pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
927         pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
928         pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
929         pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
930         pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
931         pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
932 }
933
934 static void rtl8188e_sreset_xmit_status_check(struct adapter *padapter)
935 {
936         u32 txdma_status;
937
938         txdma_status = rtw_read32(padapter, REG_TXDMA_STATUS);
939         if (txdma_status != 0x00)
940                 rtw_write32(padapter, REG_TXDMA_STATUS, txdma_status);
941         /* total xmit irp = 4 */
942 }
943
944 static void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf)
945 {
946         struct mlme_priv *pmlmepriv;
947
948         padapter = (struct adapter *)pbuf;
949         pmlmepriv = &padapter->mlmepriv;
950
951         if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
952                 expire_timeout_chk(padapter);
953
954         rtl8188e_sreset_xmit_status_check(padapter);
955
956         linked_status_chk(padapter);
957         traffic_status_watchdog(padapter);
958
959         rtl8188e_HalDmWatchDog(padapter);
960 }
961
962 static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
963 {
964         struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
965         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
966         u8      mstatus;
967
968         if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
969             check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
970                 return;
971
972         switch (lps_ctrl_type) {
973         case LPS_CTRL_SCAN:
974                 if (check_fwstate(pmlmepriv, _FW_LINKED)) {
975                         /* connect */
976                         LPS_Leave(padapter);
977                 }
978                 break;
979         case LPS_CTRL_JOINBSS:
980                 LPS_Leave(padapter);
981                 break;
982         case LPS_CTRL_CONNECT:
983                 mstatus = 1;/* connect */
984                 /*  Reset LPS Setting */
985                 padapter->pwrctrlpriv.LpsIdleCount = 0;
986                 SetHwReg8188EU(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
987                 break;
988         case LPS_CTRL_DISCONNECT:
989                 mstatus = 0;/* disconnect */
990                 LPS_Leave(padapter);
991                 SetHwReg8188EU(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
992                 break;
993         case LPS_CTRL_SPECIAL_PACKET:
994                 pwrpriv->DelayLPSLastTimeStamp = jiffies;
995                 LPS_Leave(padapter);
996                 break;
997         case LPS_CTRL_LEAVE:
998                 LPS_Leave(padapter);
999                 break;
1000         default:
1001                 break;
1002         }
1003
1004 }
1005
1006 u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
1007 {
1008         struct cmd_obj  *ph2c;
1009         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1010         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1011         /* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */
1012         u8      res = _SUCCESS;
1013
1014         /* if (!pwrctrlpriv->bLeisurePs) */
1015         /*      return res; */
1016
1017         if (enqueue) {
1018                 ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
1019                 if (!ph2c) {
1020                         res = _FAIL;
1021                         goto exit;
1022                 }
1023
1024                 pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
1025                                              GFP_ATOMIC);
1026                 if (!pdrvextra_cmd_parm) {
1027                         kfree(ph2c);
1028                         res = _FAIL;
1029                         goto exit;
1030                 }
1031
1032                 pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
1033                 pdrvextra_cmd_parm->type_size = lps_ctrl_type;
1034                 pdrvextra_cmd_parm->pbuf = NULL;
1035
1036                 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1037
1038                 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1039         } else {
1040                 lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
1041         }
1042
1043 exit:
1044
1045         return res;
1046 }
1047
1048 static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time)
1049 {
1050         SetHwReg8188EU(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&min_time));
1051 }
1052
1053 u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
1054 {
1055         struct cmd_obj          *ph2c;
1056         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1057         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1058
1059         u8      res = _SUCCESS;
1060
1061         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
1062         if (!ph2c) {
1063                 res = _FAIL;
1064                 goto exit;
1065         }
1066
1067         pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
1068                                      GFP_ATOMIC);
1069         if (!pdrvextra_cmd_parm) {
1070                 kfree(ph2c);
1071                 res = _FAIL;
1072                 goto exit;
1073         }
1074
1075         pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID;
1076         pdrvextra_cmd_parm->type_size = min_time;
1077         pdrvextra_cmd_parm->pbuf = NULL;
1078         init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1079         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1080 exit:
1081
1082         return res;
1083 }
1084
1085 static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna)
1086 {
1087         SetHwReg8188EU(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna));
1088 }
1089
1090 u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
1091 {
1092         struct cmd_obj          *ph2c;
1093         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1094         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1095         u8      support_ant_div;
1096         u8      res = _SUCCESS;
1097
1098         GetHalDefVar8188EUsb(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div);
1099         if (!support_ant_div)
1100                 return res;
1101
1102         if (enqueue) {
1103                 ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
1104                 if (!ph2c) {
1105                         res = _FAIL;
1106                         goto exit;
1107                 }
1108
1109                 pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
1110                                              GFP_KERNEL);
1111                 if (!pdrvextra_cmd_parm) {
1112                         kfree(ph2c);
1113                         res = _FAIL;
1114                         goto exit;
1115                 }
1116
1117                 pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID;
1118                 pdrvextra_cmd_parm->type_size = antenna;
1119                 pdrvextra_cmd_parm->pbuf = NULL;
1120                 init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1121
1122                 res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1123         } else {
1124                 antenna_select_wk_hdl(padapter, antenna);
1125         }
1126 exit:
1127
1128         return res;
1129 }
1130
1131 u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType)
1132 {
1133         struct cmd_obj  *ph2c;
1134         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1135         struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
1136         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1137         u8      res = _SUCCESS;
1138
1139         if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
1140                 return res;
1141
1142         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
1143         if (!ph2c) {
1144                 res = _FAIL;
1145                 goto exit;
1146         }
1147
1148         pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
1149         if (!pdrvextra_cmd_parm) {
1150                 kfree(ph2c);
1151                 res = _FAIL;
1152                 goto exit;
1153         }
1154
1155         pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
1156         pdrvextra_cmd_parm->type_size = intCmdType;     /*      As the command tppe. */
1157         pdrvextra_cmd_parm->pbuf = NULL;                /*      Must be NULL here */
1158
1159         init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1160
1161         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1162
1163 exit:
1164
1165         return res;
1166 }
1167
1168 u8 rtw_ps_cmd(struct adapter *padapter)
1169 {
1170         struct cmd_obj          *ppscmd;
1171         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1172         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1173
1174         u8      res = _SUCCESS;
1175
1176         ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
1177         if (!ppscmd) {
1178                 res = _FAIL;
1179                 goto exit;
1180         }
1181
1182         pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
1183         if (!pdrvextra_cmd_parm) {
1184                 kfree(ppscmd);
1185                 res = _FAIL;
1186                 goto exit;
1187         }
1188
1189         pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
1190         pdrvextra_cmd_parm->pbuf = NULL;
1191         init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1192
1193         res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
1194
1195 exit:
1196
1197         return res;
1198 }
1199
1200 static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
1201 {
1202         int cnt = 0;
1203         struct sta_info *psta_bmc;
1204         struct sta_priv *pstapriv = &padapter->stapriv;
1205
1206         psta_bmc = rtw_get_bcmc_stainfo(padapter);
1207         if (!psta_bmc)
1208                 return;
1209
1210         if (psta_bmc->sleepq_len == 0) {
1211                 u8 val = 0;
1212
1213                 /* while ((rtw_read32(padapter, 0x414)&0x00ffff00)!= 0) */
1214                 /* while ((rtw_read32(padapter, 0x414)&0x0000ff00)!= 0) */
1215
1216                 GetHwReg8188EU(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
1217
1218                 while (!val) {
1219                         msleep(100);
1220
1221                         cnt++;
1222
1223                         if (cnt > 10)
1224                                 break;
1225
1226                         GetHwReg8188EU(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
1227                 }
1228
1229                 if (cnt <= 10) {
1230                         pstapriv->tim_bitmap &= ~BIT(0);
1231                         pstapriv->sta_dz_bitmap &= ~BIT(0);
1232
1233                         update_beacon(padapter, _TIM_IE_, NULL, false);
1234                 } else { /* re check again */
1235                         rtw_chk_hi_queue_cmd(padapter);
1236                 }
1237         }
1238 }
1239
1240 u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
1241 {
1242         struct cmd_obj  *ph2c;
1243         struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
1244         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1245         u8      res = _SUCCESS;
1246
1247         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
1248         if (!ph2c) {
1249                 res = _FAIL;
1250                 goto exit;
1251         }
1252
1253         pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
1254         if (!pdrvextra_cmd_parm) {
1255                 kfree(ph2c);
1256                 res = _FAIL;
1257                 goto exit;
1258         }
1259
1260         pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
1261         pdrvextra_cmd_parm->type_size = 0;
1262         pdrvextra_cmd_parm->pbuf = NULL;
1263
1264         init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1265
1266         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1267 exit:
1268         return res;
1269 }
1270
1271 u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
1272 {
1273         struct cmd_obj *ph2c;
1274         struct drvextra_cmd_parm *pdrvextra_cmd_parm;
1275         struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
1276         u8      res = _SUCCESS;
1277
1278         ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
1279         if (!ph2c) {
1280                 res = _FAIL;
1281                 goto exit;
1282         }
1283
1284         pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
1285         if (!pdrvextra_cmd_parm) {
1286                 kfree(ph2c);
1287                 res = _FAIL;
1288                 goto exit;
1289         }
1290
1291         pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
1292         pdrvextra_cmd_parm->type_size = c2h_evt ? 16 : 0;
1293         pdrvextra_cmd_parm->pbuf = c2h_evt;
1294
1295         init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
1296
1297         res = rtw_enqueue_cmd(pcmdpriv, ph2c);
1298
1299 exit:
1300
1301         return res;
1302 }
1303
1304 static void c2h_evt_hdl(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter)
1305 {
1306         u8 buf[16];
1307
1308         if (!c2h_evt)
1309                 c2h_evt_read(adapter, buf);
1310 }
1311
1312 static void c2h_wk_callback(struct work_struct *work)
1313 {
1314         struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk);
1315         struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv);
1316         struct c2h_evt_hdr *c2h_evt;
1317
1318         evtpriv->c2h_wk_alive = true;
1319
1320         while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
1321                 c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue);
1322                 if (c2h_evt) {
1323                         /* This C2H event is read, clear it */
1324                         rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
1325                 } else {
1326                         c2h_evt = kmalloc(16, GFP_KERNEL);
1327                         if (c2h_evt) {
1328                                 /* This C2H event is not read, read & clear now */
1329                                 if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS) {
1330                                         kfree(c2h_evt);
1331                                         continue;
1332                                 }
1333                         } else {
1334                                 return;
1335                         }
1336                 }
1337
1338                 /* Special pointer to trigger c2h_evt_clear only */
1339                 if ((void *)c2h_evt == (void *)evtpriv)
1340                         continue;
1341
1342                 if (!c2h_evt_exist(c2h_evt)) {
1343                         kfree(c2h_evt);
1344                         continue;
1345                 }
1346
1347                 /* Enqueue into cmd_thread for others */
1348                 rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt);
1349         }
1350
1351         evtpriv->c2h_wk_alive = false;
1352 }
1353
1354 u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
1355 {
1356         struct drvextra_cmd_parm *pdrvextra_cmd;
1357
1358         if (!pbuf)
1359                 return H2C_PARAMETERS_ERROR;
1360
1361         pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
1362
1363         switch (pdrvextra_cmd->ec_id) {
1364         case DYNAMIC_CHK_WK_CID:
1365                 dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf);
1366                 break;
1367         case POWER_SAVING_CTRL_WK_CID:
1368                 rtw_ps_processor(padapter);
1369                 break;
1370         case LPS_CTRL_WK_CID:
1371                 lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size);
1372                 break;
1373         case RTP_TIMER_CFG_WK_CID:
1374                 rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size);
1375                 break;
1376         case ANT_SELECT_WK_CID:
1377                 antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size);
1378                 break;
1379         case P2P_PS_WK_CID:
1380                 p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size);
1381                 break;
1382         case P2P_PROTO_WK_CID:
1383                 /*      Commented by Albert 2011/07/01 */
1384                 /*      I used the type_size as the type command */
1385                 p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size);
1386                 break;
1387         case CHECK_HIQ_WK_CID:
1388                 rtw_chk_hi_queue_hdl(padapter);
1389                 break;
1390         case C2H_WK_CID:
1391                 c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL);
1392                 break;
1393         default:
1394                 break;
1395         }
1396
1397         if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0)
1398                 kfree(pdrvextra_cmd->pbuf);
1399
1400         return H2C_SUCCESS;
1401 }
1402
1403 void rtw_survey_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1404 {
1405         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1406
1407         if (pcmd->res == H2C_DROPPED) {
1408                 /* TODO: cancel timer and do timeout handler directly... */
1409                 /* need to make timeout handlerOS independent */
1410                 _set_timer(&pmlmepriv->scan_to_timer, 1);
1411                 } else if (pcmd->res != H2C_SUCCESS) {
1412                 _set_timer(&pmlmepriv->scan_to_timer, 1);
1413         }
1414
1415         /*  free cmd */
1416         rtw_free_cmd_obj(pcmd);
1417
1418 }
1419 void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1420 {
1421         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1422
1423         if (pcmd->res != H2C_SUCCESS) {
1424                 spin_lock_bh(&pmlmepriv->lock);
1425                 set_fwstate(pmlmepriv, _FW_LINKED);
1426                 spin_unlock_bh(&pmlmepriv->lock);
1427
1428                 return;
1429         } else /* clear bridge database */
1430                 nat25_db_cleanup(padapter);
1431
1432         /*  free cmd */
1433         rtw_free_cmd_obj(pcmd);
1434 }
1435
1436 void rtw_joinbss_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1437 {
1438         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1439
1440         if (pcmd->res == H2C_DROPPED) {
1441                 /* TODO: cancel timer and do timeout handler directly... */
1442                 /* need to make timeout handlerOS independent */
1443                 _set_timer(&pmlmepriv->assoc_timer, 1);
1444         } else if (pcmd->res != H2C_SUCCESS) {
1445                 _set_timer(&pmlmepriv->assoc_timer, 1);
1446         }
1447
1448         rtw_free_cmd_obj(pcmd);
1449 }
1450
1451 void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
1452 {
1453         struct sta_info *psta = NULL;
1454         struct wlan_network *pwlan = NULL;
1455         struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
1456         struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
1457         struct wlan_network *tgt_network = &pmlmepriv->cur_network;
1458
1459         if (pcmd->res != H2C_SUCCESS)
1460                 _set_timer(&pmlmepriv->assoc_timer, 1);
1461
1462         del_timer_sync(&pmlmepriv->assoc_timer);
1463
1464         spin_lock_bh(&pmlmepriv->lock);
1465
1466         if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
1467                 psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
1468                 if (!psta) {
1469                         psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
1470                         if (!psta)
1471                                 goto createbss_cmd_fail;
1472                 }
1473
1474                 rtw_indicate_connect(padapter);
1475         } else {
1476
1477                 pwlan = _rtw_alloc_network(pmlmepriv);
1478                 spin_lock_bh(&pmlmepriv->scanned_queue.lock);
1479                 if (!pwlan) {
1480                         pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
1481                         if (!pwlan) {
1482                                 spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1483                                 goto createbss_cmd_fail;
1484                         }
1485                         pwlan->last_scanned = jiffies;
1486                 } else {
1487                         list_add_tail(&pwlan->list, &pmlmepriv->scanned_queue.queue);
1488                 }
1489
1490                 pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
1491                 memcpy(&pwlan->network, pnetwork, pnetwork->Length);
1492
1493                 memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork)));
1494
1495                 _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
1496
1497                 spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
1498                 /*  we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */
1499         }
1500
1501 createbss_cmd_fail:
1502
1503         spin_unlock_bh(&pmlmepriv->lock);
1504
1505         rtw_free_cmd_obj(pcmd);
1506
1507 }
1508
1509 void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1510 {
1511         struct sta_priv *pstapriv = &padapter->stapriv;
1512         struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
1513         struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
1514
1515         if (!psta)
1516                 goto exit;
1517 exit:
1518         rtw_free_cmd_obj(pcmd);
1519
1520 }
1521
1522 void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
1523 {
1524         struct sta_priv *pstapriv = &padapter->stapriv;
1525         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
1526         struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
1527         struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp);
1528         struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
1529
1530         if (!psta)
1531                 goto exit;
1532
1533         psta->aid = passocsta_rsp->cam_id;
1534         psta->mac_id = passocsta_rsp->cam_id;
1535
1536         spin_lock_bh(&pmlmepriv->lock);
1537
1538         if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
1539                 _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
1540
1541         set_fwstate(pmlmepriv, _FW_LINKED);
1542         spin_unlock_bh(&pmlmepriv->lock);
1543
1544 exit:
1545         rtw_free_cmd_obj(pcmd);
1546
1547 }