Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6] / drivers / net / wireless / libertas / cmdresp.c
1 /**
2   * This file contains the handling of command
3   * responses as well as events generated by firmware.
4   */
5 #include <linux/delay.h>
6 #include <linux/if_arp.h>
7 #include <linux/netdevice.h>
8
9 #include <net/iw_handler.h>
10
11 #include "host.h"
12 #include "sbi.h"
13 #include "decl.h"
14 #include "defs.h"
15 #include "dev.h"
16 #include "join.h"
17 #include "wext.h"
18
19 /**
20  *  @brief This function handles disconnect event. it
21  *  reports disconnect to upper layer, clean tx/rx packets,
22  *  reset link state etc.
23  *
24  *  @param priv    A pointer to wlan_private structure
25  *  @return        n/a
26  */
27 void libertas_mac_event_disconnected(wlan_private * priv)
28 {
29         wlan_adapter *adapter = priv->adapter;
30         union iwreq_data wrqu;
31
32         if (adapter->connect_status != libertas_connected)
33                 return;
34
35         lbs_pr_debug(1, "Handles disconnect event.\n");
36
37         memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
38         wrqu.ap_addr.sa_family = ARPHRD_ETHER;
39
40         /*
41          * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
42          * It causes problem in the Supplicant
43          */
44
45         msleep_interruptible(1000);
46         wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
47
48         /* Free Tx and Rx packets */
49         kfree_skb(priv->adapter->currenttxskb);
50         priv->adapter->currenttxskb = NULL;
51
52         /* report disconnect to upper layer */
53         netif_stop_queue(priv->wlan_dev.netdev);
54         netif_carrier_off(priv->wlan_dev.netdev);
55
56         /* reset SNR/NF/RSSI values */
57         memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
58         memset(adapter->NF, 0x00, sizeof(adapter->NF));
59         memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
60         memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
61         memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
62         adapter->nextSNRNF = 0;
63         adapter->numSNRNF = 0;
64         adapter->rxpd_rate = 0;
65         lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n",
66                adapter->curbssparams.ssid.ssid,
67                adapter->curbssparams.ssid.ssidlength);
68         lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n",
69                adapter->previousssid.ssid, adapter->previousssid.ssidlength);
70
71         /* reset internal flags */
72         adapter->secinfo.WPAenabled = 0;
73         adapter->secinfo.WPA2enabled = 0;
74         adapter->wpa_ie_len = 0;
75
76         adapter->connect_status = libertas_disconnected;
77
78         /*
79          * memorize the previous SSID and BSSID
80          * it could be used for re-assoc
81          */
82         memcpy(&adapter->previousssid,
83                &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID));
84         memcpy(adapter->previousbssid,
85                adapter->curbssparams.bssid, ETH_ALEN);
86
87         /* need to erase the current SSID and BSSID info */
88         adapter->pattemptedbssdesc = NULL;
89         memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
90
91         if (adapter->psstate != PS_STATE_FULL_POWER) {
92                 /* make firmware to exit PS mode */
93                 lbs_pr_debug(1, "Disconnected, so exit PS mode.\n");
94                 libertas_ps_wakeup(priv, 0);
95         }
96 }
97
98 /**
99  *  @brief This function handles MIC failure event.
100  *
101  *  @param priv    A pointer to wlan_private structure
102  *  @para  event   the event id
103  *  @return        n/a
104  */
105 static void handle_mic_failureevent(wlan_private * priv, u32 event)
106 {
107         char buf[50];
108
109         memset(buf, 0, sizeof(buf));
110
111         sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
112
113         if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
114                 strcat(buf, "unicast ");
115         } else {
116                 strcat(buf, "multicast ");
117         }
118
119         libertas_send_iwevcustom_event(priv, buf);
120 }
121
122 static int wlan_ret_reg_access(wlan_private * priv,
123                                u16 type, struct cmd_ds_command *resp)
124 {
125         wlan_adapter *adapter = priv->adapter;
126
127         ENTER();
128
129         switch (type) {
130         case cmd_ret_mac_reg_access:
131                 {
132                         struct cmd_ds_mac_reg_access *reg;
133
134                         reg =
135                             (struct cmd_ds_mac_reg_access *)&resp->params.
136                             macreg;
137
138                         adapter->offsetvalue.offset = reg->offset;
139                         adapter->offsetvalue.value = reg->value;
140                         break;
141                 }
142
143         case cmd_ret_bbp_reg_access:
144                 {
145                         struct cmd_ds_bbp_reg_access *reg;
146                         reg =
147                             (struct cmd_ds_bbp_reg_access *)&resp->params.
148                             bbpreg;
149
150                         adapter->offsetvalue.offset = reg->offset;
151                         adapter->offsetvalue.value = reg->value;
152                         break;
153                 }
154
155         case cmd_ret_rf_reg_access:
156                 {
157                         struct cmd_ds_rf_reg_access *reg;
158                         reg =
159                             (struct cmd_ds_rf_reg_access *)&resp->params.
160                             rfreg;
161
162                         adapter->offsetvalue.offset = reg->offset;
163                         adapter->offsetvalue.value = reg->value;
164                         break;
165                 }
166
167         default:
168                 LEAVE();
169                 return -1;
170         }
171
172         LEAVE();
173         return 0;
174 }
175
176 static int wlan_ret_get_hw_spec(wlan_private * priv,
177                                 struct cmd_ds_command *resp)
178 {
179         u32 i;
180         struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
181         wlan_adapter *adapter = priv->adapter;
182         int ret = 0;
183
184         ENTER();
185
186         adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
187
188         adapter->fwreleasenumber = hwspec->fwreleasenumber;
189
190         lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
191                adapter->fwreleasenumber);
192         lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
193                hwspec->permanentaddr[0], hwspec->permanentaddr[1],
194                hwspec->permanentaddr[2], hwspec->permanentaddr[3],
195                hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
196         lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X  version=0x%X\n",
197                hwspec->hwifversion, hwspec->version);
198
199         adapter->regioncode = le16_to_cpu(hwspec->regioncode);
200
201         for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
202                 /* use the region code to search for the index */
203                 if (adapter->regioncode == libertas_region_code_to_index[i]) {
204                         adapter->regiontableindex = (u16) i;
205                         break;
206                 }
207         }
208
209         /* if it's unidentified region code, use the default (USA) */
210         if (i >= MRVDRV_MAX_REGION_CODE) {
211                 adapter->regioncode = 0x10;
212                 adapter->regiontableindex = 0;
213                 lbs_pr_info(
214                        "unidentified region code, use the default (USA)\n");
215         }
216
217         if (adapter->current_addr[0] == 0xff) {
218                 memmove(adapter->current_addr, hwspec->permanentaddr,
219                         ETH_ALEN);
220         }
221
222         memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN);
223         memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
224
225         if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
226                 ret = -1;
227                 goto done;
228         }
229
230         if (libertas_set_universaltable(priv, 0)) {
231                 ret = -1;
232                 goto done;
233         }
234
235       done:
236         LEAVE();
237         return ret;
238 }
239
240 static int wlan_ret_802_11_sleep_params(wlan_private * priv,
241                                         struct cmd_ds_command *resp)
242 {
243         struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
244         wlan_adapter *adapter = priv->adapter;
245
246         ENTER();
247
248         lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
249                " extsleepclk=%x\n", sp->error, sp->offset,
250                sp->stabletime, sp->calcontrol, sp->externalsleepclk);
251         adapter->sp.sp_error = le16_to_cpu(sp->error);
252         adapter->sp.sp_offset = le16_to_cpu(sp->offset);
253         adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
254         adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol);
255         adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk);
256         adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
257
258         LEAVE();
259         return 0;
260 }
261
262 static int wlan_ret_802_11_stat(wlan_private * priv,
263                                 struct cmd_ds_command *resp)
264 {
265 /*      currently adapter->wlan802_11Stat is unused
266
267         struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
268         wlan_adapter *adapter = priv->adapter;
269
270         // TODO Convert it to Big endian befor copy
271         memcpy(&adapter->wlan802_11Stat,
272                p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
273 */
274         return 0;
275 }
276
277 static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
278                                     struct cmd_ds_command *resp)
279 {
280         struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
281         u16 oid = le16_to_cpu(smib->oid);
282         u16 querytype = le16_to_cpu(smib->querytype);
283
284         ENTER();
285
286         lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
287                querytype);
288         lbs_pr_debug(1, "SNMP_RESP: Buf size  = %x\n",
289                le16_to_cpu(smib->bufsize));
290
291         if (querytype == cmd_act_get) {
292                 switch (oid) {
293                 case fragthresh_i:
294                         priv->adapter->fragthsd =
295                             le16_to_cpu(*
296                                              ((unsigned short *)(smib->value)));
297                         lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n",
298                                priv->adapter->fragthsd);
299                         break;
300                 case rtsthresh_i:
301                         priv->adapter->rtsthsd =
302                             le16_to_cpu(*
303                                              ((unsigned short *)(smib->value)));
304                         lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n",
305                                priv->adapter->rtsthsd);
306                         break;
307                 case short_retrylim_i:
308                         priv->adapter->txretrycount =
309                             le16_to_cpu(*
310                                              ((unsigned short *)(smib->value)));
311                         lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n",
312                                priv->adapter->rtsthsd);
313                         break;
314                 default:
315                         break;
316                 }
317         }
318
319         LEAVE();
320         return 0;
321 }
322
323 static int wlan_ret_802_11_key_material(wlan_private * priv,
324                                         struct cmd_ds_command *resp)
325 {
326         struct cmd_ds_802_11_key_material *pkeymaterial =
327             &resp->params.keymaterial;
328         wlan_adapter *adapter = priv->adapter;
329         u16 action = le16_to_cpu(pkeymaterial->action);
330
331         ENTER();
332
333         /* Copy the returned key to driver private data */
334         if (action == cmd_act_get) {
335                 u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
336                 u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
337
338                 while (buf_ptr < resp_end) {
339                         struct MrvlIEtype_keyParamSet * pkeyparamset =
340                             (struct MrvlIEtype_keyParamSet *) buf_ptr;
341                         struct WLAN_802_11_KEY * pkey;
342                         u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
343                         u16 param_set_len = le16_to_cpu(pkeyparamset->length);
344                         u8 * end;
345                         u16 key_len = le16_to_cpu(pkeyparamset->keylen);
346
347                         end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
348                                                   + sizeof (pkeyparamset->length)
349                                                   + param_set_len;
350                         /* Make sure we don't access past the end of the IEs */
351                         if (end > resp_end)
352                                 break;
353
354                         if (key_info & KEY_INFO_WPA_UNICAST)
355                                 pkey = &adapter->wpa_unicast_key;
356                         else if (key_info & KEY_INFO_WPA_MCAST)
357                                 pkey = &adapter->wpa_mcast_key;
358                         else
359                                 break;
360
361                         /* Copy returned key into driver */
362                         memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
363                         if (key_len > sizeof(pkey->key))
364                                 break;
365                         pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
366                         pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
367                         pkey->len = le16_to_cpu(pkeyparamset->keylen);
368                         memcpy(pkey->key, pkeyparamset->key, pkey->len);
369
370                         buf_ptr = end + 1;
371                 }
372         }
373
374         LEAVE();
375         return 0;
376 }
377
378 static int wlan_ret_802_11_mac_address(wlan_private * priv,
379                                        struct cmd_ds_command *resp)
380 {
381         struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
382         wlan_adapter *adapter = priv->adapter;
383
384         ENTER();
385
386         memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
387
388         LEAVE();
389         return 0;
390 }
391
392 static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
393                                        struct cmd_ds_command *resp)
394 {
395         struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
396         wlan_adapter *adapter = priv->adapter;
397
398         ENTER();
399
400         adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
401
402         lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel);
403
404         LEAVE();
405         return 0;
406 }
407
408 static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
409                                       struct cmd_ds_command *resp)
410 {
411         struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
412         wlan_adapter *adapter = priv->adapter;
413         u16 action = le16_to_cpu(pAntenna->action);
414
415         if (action == cmd_act_get_rx)
416                 adapter->rxantennamode =
417                     le16_to_cpu(pAntenna->antennamode);
418
419         if (action == cmd_act_get_tx)
420                 adapter->txantennamode =
421                     le16_to_cpu(pAntenna->antennamode);
422
423         lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
424                action, le16_to_cpu(pAntenna->antennamode));
425
426         return 0;
427 }
428
429 static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
430                                               struct cmd_ds_command *resp)
431 {
432         struct cmd_ds_802_11_rate_adapt_rateset *rates =
433             &resp->params.rateset;
434         wlan_adapter *adapter = priv->adapter;
435
436         ENTER();
437
438         if (rates->action == cmd_act_get) {
439                 adapter->enablehwauto = rates->enablehwauto;
440                 adapter->ratebitmap = rates->bitmap;
441         }
442
443         LEAVE();
444
445         return 0;
446 }
447
448 static int wlan_ret_802_11_data_rate(wlan_private * priv,
449                                      struct cmd_ds_command *resp)
450 {
451         struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
452         wlan_adapter *adapter = priv->adapter;
453         u8 dot11datarate;
454
455         ENTER();
456
457         lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
458                 (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
459
460         dot11datarate = pdatarate->datarate[0];
461         if (pdatarate->action == cmd_act_get_tx_rate) {
462                 memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
463                        sizeof(adapter->libertas_supported_rates));
464         }
465         adapter->datarate = libertas_index_to_data_rate(dot11datarate);
466
467         LEAVE();
468         return 0;
469 }
470
471 static int wlan_ret_802_11_rf_channel(wlan_private * priv,
472                                       struct cmd_ds_command *resp)
473 {
474         struct cmd_ds_802_11_rf_channel *rfchannel =
475             &resp->params.rfchannel;
476         wlan_adapter *adapter = priv->adapter;
477         u16 action = le16_to_cpu(rfchannel->action);
478         u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
479
480         ENTER();
481
482         if (action == cmd_opt_802_11_rf_channel_get
483             && adapter->curbssparams.channel != newchannel) {
484                 lbs_pr_debug(1, "channel Switch: %d to %d\n",
485                        adapter->curbssparams.channel, newchannel);
486
487                 /* Update the channel again */
488                 adapter->curbssparams.channel = newchannel;
489         }
490
491         LEAVE();
492         return 0;
493 }
494
495 static int wlan_ret_802_11_rssi(wlan_private * priv,
496                                 struct cmd_ds_command *resp)
497 {
498         struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
499         wlan_adapter *adapter = priv->adapter;
500
501         /* store the non average value */
502         adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
503         adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
504             le16_to_cpu(rssirsp->noisefloor);
505
506         adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
507         adapter->NF[TYPE_BEACON][TYPE_AVG] =
508             le16_to_cpu(rssirsp->avgnoisefloor);
509
510         adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
511             CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
512                      adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
513
514         adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
515             CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
516                      adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
517
518         lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n",
519                adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
520
521         return 0;
522 }
523
524 static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
525                                   struct cmd_ds_command *resp)
526 {
527         wlan_adapter *adapter = priv->adapter;
528         struct wlan_ioctl_regrdwr *pbuf;
529         pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
530
531         lbs_pr_debug(1, "eeprom read len=%x\n",
532                le16_to_cpu(resp->params.rdeeprom.bytecount));
533         if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
534                 pbuf->NOB = 0;
535                 lbs_pr_debug(1, "eeprom read return length is too big\n");
536                 return -1;
537         }
538         pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
539         if (pbuf->NOB > 0) {
540
541                 memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
542                        le16_to_cpu(resp->params.rdeeprom.bytecount));
543                 lbs_dbg_hex("adapter", (char *)&pbuf->value,
544                         le16_to_cpu(resp->params.rdeeprom.bytecount));
545         }
546         return 0;
547 }
548
549 static int wlan_ret_get_log(wlan_private * priv,
550                             struct cmd_ds_command *resp)
551 {
552         struct cmd_ds_802_11_get_log *logmessage =
553             (struct cmd_ds_802_11_get_log *)&resp->params.glog;
554         wlan_adapter *adapter = priv->adapter;
555
556         ENTER();
557
558         /* TODO Convert it to Big Endian before copy */
559         memcpy(&adapter->logmsg, logmessage,
560                sizeof(struct cmd_ds_802_11_get_log));
561
562         LEAVE();
563         return 0;
564 }
565
566 static inline int handle_cmd_response(u16 respcmd,
567                                       struct cmd_ds_command *resp,
568                                       wlan_private *priv)
569 {
570         int ret = 0;
571         unsigned long flags;
572         wlan_adapter *adapter = priv->adapter;
573
574         switch (respcmd) {
575         case cmd_ret_mac_reg_access:
576         case cmd_ret_bbp_reg_access:
577         case cmd_ret_rf_reg_access:
578                 ret = wlan_ret_reg_access(priv, respcmd, resp);
579                 break;
580
581         case cmd_ret_hw_spec_info:
582                 ret = wlan_ret_get_hw_spec(priv, resp);
583                 break;
584
585         case cmd_ret_802_11_scan:
586                 ret = libertas_ret_80211_scan(priv, resp);
587                 break;
588
589         case cmd_ret_802_11_get_log:
590                 ret = wlan_ret_get_log(priv, resp);
591                 break;
592
593         case cmd_ret_802_11_associate:
594         case cmd_ret_802_11_reassociate:
595                 ret = libertas_ret_80211_associate(priv, resp);
596                 break;
597
598         case cmd_ret_802_11_disassociate:
599         case cmd_ret_802_11_deauthenticate:
600                 ret = libertas_ret_80211_disassociate(priv, resp);
601                 break;
602
603         case cmd_ret_802_11_ad_hoc_start:
604         case cmd_ret_802_11_ad_hoc_join:
605                 ret = libertas_ret_80211_ad_hoc_start(priv, resp);
606                 break;
607
608         case cmd_ret_802_11_stat:
609                 ret = wlan_ret_802_11_stat(priv, resp);
610                 break;
611
612         case cmd_ret_802_11_snmp_mib:
613                 ret = wlan_ret_802_11_snmp_mib(priv, resp);
614                 break;
615
616         case cmd_ret_802_11_rf_tx_power:
617                 ret = wlan_ret_802_11_rf_tx_power(priv, resp);
618                 break;
619
620         case cmd_ret_802_11_set_afc:
621         case cmd_ret_802_11_get_afc:
622                 spin_lock_irqsave(&adapter->driver_lock, flags);
623                 memmove(adapter->cur_cmd->pdata_buf,
624                         &resp->params.afc,
625                         sizeof(struct cmd_ds_802_11_afc));
626                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
627
628                 break;
629         case cmd_ret_802_11_rf_antenna:
630                 ret = wlan_ret_802_11_rf_antenna(priv, resp);
631                 break;
632
633         case cmd_ret_mac_multicast_adr:
634         case cmd_ret_mac_control:
635         case cmd_ret_802_11_set_wep:
636         case cmd_ret_802_11_reset:
637         case cmd_ret_802_11_authenticate:
638         case cmd_ret_802_11_radio_control:
639         case cmd_ret_802_11_beacon_stop:
640         case cmd_ret_802_11_enable_rsn:
641                 break;
642
643         case cmd_ret_802_11_data_rate:
644                 ret = wlan_ret_802_11_data_rate(priv, resp);
645                 break;
646         case cmd_ret_802_11_rate_adapt_rateset:
647                 ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
648                 break;
649         case cmd_ret_802_11_rf_channel:
650                 ret = wlan_ret_802_11_rf_channel(priv, resp);
651                 break;
652
653         case cmd_ret_802_11_rssi:
654                 ret = wlan_ret_802_11_rssi(priv, resp);
655                 break;
656
657         case cmd_ret_802_11_mac_address:
658                 ret = wlan_ret_802_11_mac_address(priv, resp);
659                 break;
660
661         case cmd_ret_802_11_ad_hoc_stop:
662                 ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
663                 break;
664
665         case cmd_ret_802_11_key_material:
666                 lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n");
667                 ret = wlan_ret_802_11_key_material(priv, resp);
668                 break;
669
670         case cmd_ret_802_11_eeprom_access:
671                 ret = wlan_ret_802_11_eeprom_access(priv, resp);
672                 break;
673
674         case cmd_ret_802_11d_domain_info:
675                 ret = libertas_ret_802_11d_domain_info(priv, resp);
676                 break;
677
678         case cmd_ret_802_11_sleep_params:
679                 ret = wlan_ret_802_11_sleep_params(priv, resp);
680                 break;
681         case cmd_ret_802_11_inactivity_timeout:
682                 spin_lock_irqsave(&adapter->driver_lock, flags);
683                 *((u16 *) adapter->cur_cmd->pdata_buf) =
684                     le16_to_cpu(resp->params.inactivity_timeout.timeout);
685                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
686                 break;
687
688         case cmd_ret_802_11_tpc_cfg:
689                 spin_lock_irqsave(&adapter->driver_lock, flags);
690                 memmove(adapter->cur_cmd->pdata_buf,
691                         &resp->params.tpccfg,
692                         sizeof(struct cmd_ds_802_11_tpc_cfg));
693                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
694                 break;
695         case cmd_ret_802_11_led_gpio_ctrl:
696                 spin_lock_irqsave(&adapter->driver_lock, flags);
697                 memmove(adapter->cur_cmd->pdata_buf,
698                         &resp->params.ledgpio,
699                         sizeof(struct cmd_ds_802_11_led_ctrl));
700                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
701                 break;
702         case cmd_ret_802_11_pwr_cfg:
703                 spin_lock_irqsave(&adapter->driver_lock, flags);
704                 memmove(adapter->cur_cmd->pdata_buf,
705                         &resp->params.pwrcfg,
706                         sizeof(struct cmd_ds_802_11_pwr_cfg));
707                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
708
709                 break;
710
711         case cmd_ret_get_tsf:
712                 spin_lock_irqsave(&adapter->driver_lock, flags);
713                 memcpy(priv->adapter->cur_cmd->pdata_buf,
714                        &resp->params.gettsf.tsfvalue, sizeof(u64));
715                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
716                 break;
717         case cmd_ret_bt_access:
718                 spin_lock_irqsave(&adapter->driver_lock, flags);
719                 if (adapter->cur_cmd->pdata_buf)
720                         memcpy(adapter->cur_cmd->pdata_buf,
721                                &resp->params.bt.addr1, 2 * ETH_ALEN);
722                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
723                 break;
724         case cmd_ret_fwt_access:
725                 spin_lock_irqsave(&adapter->driver_lock, flags);
726                 if (adapter->cur_cmd->pdata_buf)
727                         memcpy(adapter->cur_cmd->pdata_buf,
728                                &resp->params.fwt,
729                                 sizeof(resp->params.fwt));
730                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
731                 break;
732         case cmd_ret_mesh_access:
733                 if (adapter->cur_cmd->pdata_buf)
734                         memcpy(adapter->cur_cmd->pdata_buf,
735                                &resp->params.mesh,
736                                sizeof(resp->params.mesh));
737                 break;
738         case cmd_rte_802_11_tx_rate_query:
739                 priv->adapter->txrate = resp->params.txrate.txrate;
740                 break;
741         default:
742                 lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n",
743                        resp->command);
744                 break;
745         }
746         return ret;
747 }
748
749 int libertas_process_rx_command(wlan_private * priv)
750 {
751         u16 respcmd;
752         struct cmd_ds_command *resp;
753         wlan_adapter *adapter = priv->adapter;
754         int ret = 0;
755         ulong flags;
756         u16 result;
757
758         ENTER();
759
760         lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies);
761
762         /* Now we got response from FW, cancel the command timer */
763         del_timer(&adapter->command_timer);
764
765         mutex_lock(&adapter->lock);
766         spin_lock_irqsave(&adapter->driver_lock, flags);
767
768         if (!adapter->cur_cmd) {
769                 lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
770                 ret = -1;
771                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
772                 goto done;
773         }
774         resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
775
776         lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
777                 priv->wlan_dev.upld_len);
778
779         respcmd = le16_to_cpu(resp->command);
780
781         result = le16_to_cpu(resp->result);
782
783         lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd,
784                result, priv->wlan_dev.upld_len);
785
786         if (!(respcmd & 0x8000)) {
787                 lbs_pr_debug(1, "Invalid response to command!");
788                 adapter->cur_cmd_retcode = -1;
789                 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
790                 adapter->nr_cmd_pending--;
791                 adapter->cur_cmd = NULL;
792                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
793                 ret = -1;
794                 goto done;
795         }
796
797         /* Store the response code to cur_cmd_retcode. */
798         adapter->cur_cmd_retcode = le16_to_cpu(resp->result);
799
800         if (respcmd == cmd_ret_802_11_ps_mode) {
801                 struct cmd_ds_802_11_ps_mode *psmode;
802
803                 psmode = &resp->params.psmode;
804                 lbs_pr_debug(1,
805                        "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
806                        resp->result, psmode->action);
807                 psmode->action = cpu_to_le16(psmode->action);
808
809                 if (result) {
810                         lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n",
811                                resp->result);
812                         if (adapter->mode == IW_MODE_ADHOC) {
813                                 /*
814                                  * We should not re-try enter-ps command in
815                                  * ad-hoc mode. It takes place in
816                                  * libertas_execute_next_command().
817                                  */
818                                 if (psmode->action == cmd_subcmd_enter_ps)
819                                         adapter->psmode =
820                                             wlan802_11powermodecam;
821                         }
822                 } else if (psmode->action == cmd_subcmd_enter_ps) {
823                         adapter->needtowakeup = 0;
824                         adapter->psstate = PS_STATE_AWAKE;
825
826                         lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n");
827                         if (adapter->connect_status != libertas_connected) {
828                                 /*
829                                  * When Deauth Event received before Enter_PS command
830                                  * response, We need to wake up the firmware.
831                                  */
832                                 lbs_pr_debug(1,
833                                        "Disconnected, Going to invoke libertas_ps_wakeup\n");
834
835                                 mutex_unlock(&adapter->lock);
836                                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
837                                 libertas_ps_wakeup(priv, 0);
838                                 mutex_lock(&adapter->lock);
839                                 spin_lock_irqsave(&adapter->driver_lock, flags);
840                         }
841                 } else if (psmode->action == cmd_subcmd_exit_ps) {
842                         adapter->needtowakeup = 0;
843                         adapter->psstate = PS_STATE_FULL_POWER;
844                         lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n");
845                 } else {
846                         lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n",
847                                psmode->action);
848                 }
849
850                 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
851                 adapter->nr_cmd_pending--;
852                 adapter->cur_cmd = NULL;
853                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
854
855                 ret = 0;
856                 goto done;
857         }
858
859         if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
860                 /* Copy the response back to response buffer */
861                 memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
862
863                 adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
864         }
865
866         /* If the command is not successful, cleanup and return failure */
867         if ((result != 0 || !(respcmd & 0x8000))) {
868                 lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n",
869                        resp->command, resp->result);
870                 /*
871                  * Handling errors here
872                  */
873                 switch (respcmd) {
874                 case cmd_ret_hw_spec_info:
875                 case cmd_ret_802_11_reset:
876                         lbs_pr_debug(1, "CMD_RESP: Reset command failed\n");
877                         break;
878
879                 }
880
881                 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
882                 adapter->nr_cmd_pending--;
883                 adapter->cur_cmd = NULL;
884                 spin_unlock_irqrestore(&adapter->driver_lock, flags);
885
886                 ret = -1;
887                 goto done;
888         }
889
890         spin_unlock_irqrestore(&adapter->driver_lock, flags);
891
892         ret = handle_cmd_response(respcmd, resp, priv);
893
894         spin_lock_irqsave(&adapter->driver_lock, flags);
895         if (adapter->cur_cmd) {
896                 /* Clean up and Put current command back to cmdfreeq */
897                 __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
898                 adapter->nr_cmd_pending--;
899                 WARN_ON(adapter->nr_cmd_pending > 128);
900                 adapter->cur_cmd = NULL;
901         }
902         spin_unlock_irqrestore(&adapter->driver_lock, flags);
903
904 done:
905         mutex_unlock(&adapter->lock);
906         LEAVE();
907         return ret;
908 }
909
910 int libertas_process_event(wlan_private * priv)
911 {
912         int ret = 0;
913         wlan_adapter *adapter = priv->adapter;
914         u32 eventcause;
915
916         spin_lock_irq(&adapter->driver_lock);
917         eventcause = adapter->eventcause;
918         spin_unlock_irq(&adapter->driver_lock);
919
920         ENTER();
921
922         lbs_pr_debug(1, "EVENT Cause %x\n", eventcause);
923
924         switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
925         case MACREG_INT_CODE_LINK_SENSED:
926                 lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n");
927                 break;
928
929         case MACREG_INT_CODE_DEAUTHENTICATED:
930                 lbs_pr_debug(1, "EVENT: Deauthenticated\n");
931                 libertas_mac_event_disconnected(priv);
932                 break;
933
934         case MACREG_INT_CODE_DISASSOCIATED:
935                 lbs_pr_debug(1, "EVENT: Disassociated\n");
936                 libertas_mac_event_disconnected(priv);
937                 break;
938
939         case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
940                 lbs_pr_debug(1, "EVENT: Link lost\n");
941                 libertas_mac_event_disconnected(priv);
942                 break;
943
944         case MACREG_INT_CODE_PS_SLEEP:
945                 lbs_pr_debug(1, "EVENT: SLEEP\n");
946                 lbs_pr_debug(1, "_");
947
948                 /* handle unexpected PS SLEEP event */
949                 if (adapter->psstate == PS_STATE_FULL_POWER) {
950                         lbs_pr_debug(1,
951                                "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
952                         break;
953                 }
954                 adapter->psstate = PS_STATE_PRE_SLEEP;
955
956                 libertas_ps_confirm_sleep(priv, (u16) adapter->psmode);
957
958                 break;
959
960         case MACREG_INT_CODE_PS_AWAKE:
961                 lbs_pr_debug(1, "EVENT: AWAKE \n");
962                 lbs_pr_debug(1, "|");
963
964                 /* handle unexpected PS AWAKE event */
965                 if (adapter->psstate == PS_STATE_FULL_POWER) {
966                         lbs_pr_debug(1,
967                                "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
968                         break;
969                 }
970
971                 adapter->psstate = PS_STATE_AWAKE;
972
973                 if (adapter->needtowakeup) {
974                         /*
975                          * wait for the command processing to finish
976                          * before resuming sending
977                          * adapter->needtowakeup will be set to FALSE
978                          * in libertas_ps_wakeup()
979                          */
980                         lbs_pr_debug(1, "Waking up...\n");
981                         libertas_ps_wakeup(priv, 0);
982                 }
983                 break;
984
985         case MACREG_INT_CODE_MIC_ERR_UNICAST:
986                 lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n");
987                 handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
988                 break;
989
990         case MACREG_INT_CODE_MIC_ERR_MULTICAST:
991                 lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n");
992                 handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
993                 break;
994         case MACREG_INT_CODE_MIB_CHANGED:
995         case MACREG_INT_CODE_INIT_DONE:
996                 break;
997
998         case MACREG_INT_CODE_ADHOC_BCN_LOST:
999                 lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n");
1000                 break;
1001
1002         case MACREG_INT_CODE_RSSI_LOW:
1003                 lbs_pr_alert( "EVENT: RSSI_LOW\n");
1004                 break;
1005         case MACREG_INT_CODE_SNR_LOW:
1006                 lbs_pr_alert( "EVENT: SNR_LOW\n");
1007                 break;
1008         case MACREG_INT_CODE_MAX_FAIL:
1009                 lbs_pr_alert( "EVENT: MAX_FAIL\n");
1010                 break;
1011         case MACREG_INT_CODE_RSSI_HIGH:
1012                 lbs_pr_alert( "EVENT: RSSI_HIGH\n");
1013                 break;
1014         case MACREG_INT_CODE_SNR_HIGH:
1015                 lbs_pr_alert( "EVENT: SNR_HIGH\n");
1016                 break;
1017
1018         default:
1019                 lbs_pr_alert( "EVENT: unknown event id: %#x\n",
1020                        eventcause >> SBI_EVENT_CAUSE_SHIFT);
1021                 break;
1022         }
1023
1024         spin_lock_irq(&adapter->driver_lock);
1025         adapter->eventcause = 0;
1026         spin_unlock_irq(&adapter->driver_lock);
1027         LEAVE();
1028         return ret;
1029 }