libertas: wait for 'firmware ready' event from firmware after loading
[deliverable/linux.git] / drivers / net / wireless / libertas / cmdresp.c
CommitLineData
876c9d3a
MT
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"
876c9d3a
MT
12#include "decl.h"
13#include "defs.h"
14#include "dev.h"
15#include "join.h"
16#include "wext.h"
17
18/**
19 * @brief This function handles disconnect event. it
20 * reports disconnect to upper layer, clean tx/rx packets,
21 * reset link state etc.
22 *
69f9032d 23 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
24 * @return n/a
25 */
69f9032d 26void lbs_mac_event_disconnected(struct lbs_private *priv)
876c9d3a 27{
876c9d3a
MT
28 union iwreq_data wrqu;
29
aa21c004 30 if (priv->connect_status != LBS_CONNECTED)
876c9d3a
MT
31 return;
32
91843463 33 lbs_deb_enter(LBS_DEB_ASSOC);
876c9d3a
MT
34
35 memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
36 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
37
38 /*
39 * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
40 * It causes problem in the Supplicant
41 */
42
43 msleep_interruptible(1000);
634b8f49 44 wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
876c9d3a
MT
45
46 /* Free Tx and Rx packets */
aa21c004
DW
47 kfree_skb(priv->currenttxskb);
48 priv->currenttxskb = NULL;
876c9d3a
MT
49
50 /* report disconnect to upper layer */
634b8f49
HS
51 netif_stop_queue(priv->dev);
52 netif_carrier_off(priv->dev);
876c9d3a
MT
53
54 /* reset SNR/NF/RSSI values */
aa21c004
DW
55 memset(priv->SNR, 0x00, sizeof(priv->SNR));
56 memset(priv->NF, 0x00, sizeof(priv->NF));
57 memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
58 memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
59 memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
60 priv->nextSNRNF = 0;
61 priv->numSNRNF = 0;
62 priv->connect_status = LBS_DISCONNECTED;
876c9d3a 63
e76850d6
DW
64 /* Clear out associated SSID and BSSID since connection is
65 * no longer valid.
66 */
aa21c004
DW
67 memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
68 memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
69 priv->curbssparams.ssid_len = 0;
876c9d3a 70
aa21c004 71 if (priv->psstate != PS_STATE_FULL_POWER) {
876c9d3a 72 /* make firmware to exit PS mode */
a6c8700f 73 lbs_deb_cmd("disconnected, so exit PS mode\n");
10078321 74 lbs_ps_wakeup(priv, 0);
876c9d3a 75 }
a6c8700f 76 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
77}
78
79/**
80 * @brief This function handles MIC failure event.
81 *
69f9032d 82 * @param priv A pointer to struct lbs_private structure
876c9d3a
MT
83 * @para event the event id
84 * @return n/a
85 */
69f9032d 86static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
876c9d3a
MT
87{
88 char buf[50];
89
a6c8700f 90 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
91 memset(buf, 0, sizeof(buf));
92
93 sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
94
95 if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
96 strcat(buf, "unicast ");
97 } else {
98 strcat(buf, "multicast ");
99 }
100
10078321 101 lbs_send_iwevcustom_event(priv, buf);
a6c8700f 102 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
103}
104
69f9032d 105static int lbs_ret_reg_access(struct lbs_private *priv,
876c9d3a
MT
106 u16 type, struct cmd_ds_command *resp)
107{
9012b28a 108 int ret = 0;
876c9d3a 109
9012b28a 110 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
111
112 switch (type) {
6b63cd0f 113 case CMD_RET(CMD_MAC_REG_ACCESS):
876c9d3a 114 {
981f187b 115 struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
876c9d3a 116
aa21c004
DW
117 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
118 priv->offsetvalue.value = le32_to_cpu(reg->value);
876c9d3a
MT
119 break;
120 }
121
6b63cd0f 122 case CMD_RET(CMD_BBP_REG_ACCESS):
876c9d3a 123 {
981f187b 124 struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
876c9d3a 125
aa21c004
DW
126 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
127 priv->offsetvalue.value = reg->value;
876c9d3a
MT
128 break;
129 }
130
6b63cd0f 131 case CMD_RET(CMD_RF_REG_ACCESS):
876c9d3a 132 {
981f187b 133 struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
876c9d3a 134
aa21c004
DW
135 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
136 priv->offsetvalue.value = reg->value;
876c9d3a
MT
137 break;
138 }
139
140 default:
9012b28a 141 ret = -1;
876c9d3a
MT
142 }
143
8b17d723 144 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
9012b28a 145 return ret;
876c9d3a
MT
146}
147
69f9032d 148static int lbs_ret_802_11_sleep_params(struct lbs_private *priv,
876c9d3a
MT
149 struct cmd_ds_command *resp)
150{
151 struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
876c9d3a 152
9012b28a 153 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 154
a6c8700f
HS
155 lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
156 "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
981f187b
DW
157 le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
158 sp->calcontrol, sp->externalsleepclk);
159
aa21c004
DW
160 priv->sp.sp_error = le16_to_cpu(sp->error);
161 priv->sp.sp_offset = le16_to_cpu(sp->offset);
162 priv->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
163 priv->sp.sp_calcontrol = sp->calcontrol;
164 priv->sp.sp_extsleepclk = sp->externalsleepclk;
165 priv->sp.sp_reserved = le16_to_cpu(sp->reserved);
876c9d3a 166
9012b28a 167 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
168 return 0;
169}
170
69f9032d 171static int lbs_ret_802_11_stat(struct lbs_private *priv,
876c9d3a
MT
172 struct cmd_ds_command *resp)
173{
a6c8700f 174 lbs_deb_enter(LBS_DEB_CMD);
aa21c004 175/* currently priv->wlan802_11Stat is unused
876c9d3a
MT
176
177 struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
876c9d3a
MT
178
179 // TODO Convert it to Big endian befor copy
aa21c004 180 memcpy(&priv->wlan802_11Stat,
876c9d3a
MT
181 p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
182*/
a6c8700f 183 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
184 return 0;
185}
186
69f9032d 187static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
876c9d3a
MT
188 struct cmd_ds_command *resp)
189{
190 struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
191 u16 oid = le16_to_cpu(smib->oid);
192 u16 querytype = le16_to_cpu(smib->querytype);
193
9012b28a 194 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 195
a6c8700f 196 lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
876c9d3a 197 querytype);
a6c8700f 198 lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
876c9d3a 199
0aef64d7 200 if (querytype == CMD_ACT_GET) {
876c9d3a 201 switch (oid) {
0aef64d7 202 case FRAGTHRESH_I:
aa21c004 203 priv->fragthsd =
981f187b 204 le16_to_cpu(*((__le16 *)(smib->value)));
a6c8700f 205 lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
aa21c004 206 priv->fragthsd);
876c9d3a 207 break;
0aef64d7 208 case RTSTHRESH_I:
aa21c004 209 priv->rtsthsd =
981f187b 210 le16_to_cpu(*((__le16 *)(smib->value)));
a6c8700f 211 lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
aa21c004 212 priv->rtsthsd);
876c9d3a 213 break;
0aef64d7 214 case SHORT_RETRYLIM_I:
aa21c004 215 priv->txretrycount =
981f187b 216 le16_to_cpu(*((__le16 *)(smib->value)));
a6c8700f 217 lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
aa21c004 218 priv->rtsthsd);
876c9d3a
MT
219 break;
220 default:
221 break;
222 }
223 }
224
9012b28a 225 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
226 return 0;
227}
228
69f9032d 229static int lbs_ret_802_11_key_material(struct lbs_private *priv,
876c9d3a
MT
230 struct cmd_ds_command *resp)
231{
232 struct cmd_ds_802_11_key_material *pkeymaterial =
233 &resp->params.keymaterial;
876c9d3a
MT
234 u16 action = le16_to_cpu(pkeymaterial->action);
235
9012b28a 236 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
237
238 /* Copy the returned key to driver private data */
0aef64d7 239 if (action == CMD_ACT_GET) {
876c9d3a
MT
240 u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
241 u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
242
243 while (buf_ptr < resp_end) {
244 struct MrvlIEtype_keyParamSet * pkeyparamset =
245 (struct MrvlIEtype_keyParamSet *) buf_ptr;
1443b653 246 struct enc_key * pkey;
876c9d3a 247 u16 param_set_len = le16_to_cpu(pkeyparamset->length);
876c9d3a 248 u16 key_len = le16_to_cpu(pkeyparamset->keylen);
1443b653
DW
249 u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
250 u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
251 u8 * end;
876c9d3a
MT
252
253 end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
254 + sizeof (pkeyparamset->length)
255 + param_set_len;
256 /* Make sure we don't access past the end of the IEs */
257 if (end > resp_end)
258 break;
259
1443b653 260 if (key_flags & KEY_INFO_WPA_UNICAST)
aa21c004 261 pkey = &priv->wpa_unicast_key;
1443b653 262 else if (key_flags & KEY_INFO_WPA_MCAST)
aa21c004 263 pkey = &priv->wpa_mcast_key;
876c9d3a
MT
264 else
265 break;
266
267 /* Copy returned key into driver */
1443b653 268 memset(pkey, 0, sizeof(struct enc_key));
876c9d3a
MT
269 if (key_len > sizeof(pkey->key))
270 break;
1443b653
DW
271 pkey->type = key_type;
272 pkey->flags = key_flags;
273 pkey->len = key_len;
876c9d3a
MT
274 memcpy(pkey->key, pkeyparamset->key, pkey->len);
275
276 buf_ptr = end + 1;
277 }
278 }
279
9012b28a 280 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
281 return 0;
282}
283
69f9032d 284static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
876c9d3a
MT
285 struct cmd_ds_command *resp)
286{
287 struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
876c9d3a 288
9012b28a 289 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 290
aa21c004 291 memcpy(priv->current_addr, macadd->macadd, ETH_ALEN);
876c9d3a 292
9012b28a 293 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
294 return 0;
295}
296
69f9032d 297static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
876c9d3a
MT
298 struct cmd_ds_command *resp)
299{
300 struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
876c9d3a 301
9012b28a 302 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 303
aa21c004 304 priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
876c9d3a 305
aa21c004 306 lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
876c9d3a 307
a6c8700f 308 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
309 return 0;
310}
311
69f9032d 312static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
876c9d3a
MT
313 struct cmd_ds_command *resp)
314{
981f187b 315 struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
876c9d3a 316
9012b28a 317 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 318
0aef64d7 319 if (rates->action == CMD_ACT_GET) {
aa21c004
DW
320 priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
321 priv->ratebitmap = le16_to_cpu(rates->bitmap);
876c9d3a
MT
322 }
323
a6c8700f 324 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
325 return 0;
326}
327
69f9032d 328static int lbs_ret_802_11_data_rate(struct lbs_private *priv,
876c9d3a
MT
329 struct cmd_ds_command *resp)
330{
331 struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
876c9d3a 332
9012b28a 333 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 334
a6c8700f 335 lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
8c512765 336 sizeof(struct cmd_ds_802_11_data_rate));
876c9d3a 337
8c512765
DW
338 /* FIXME: get actual rates FW can do if this command actually returns
339 * all data rates supported.
340 */
aa21c004
DW
341 priv->cur_rate = lbs_fw_index_to_data_rate(pdatarate->rates[0]);
342 lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", priv->cur_rate);
876c9d3a 343
8c512765 344 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
345 return 0;
346}
347
69f9032d 348static int lbs_ret_802_11_rf_channel(struct lbs_private *priv,
876c9d3a
MT
349 struct cmd_ds_command *resp)
350{
981f187b 351 struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel;
876c9d3a
MT
352 u16 action = le16_to_cpu(rfchannel->action);
353 u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
354
9012b28a 355 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 356
0aef64d7 357 if (action == CMD_OPT_802_11_RF_CHANNEL_GET
aa21c004 358 && priv->curbssparams.channel != newchannel) {
a6c8700f 359 lbs_deb_cmd("channel switch from %d to %d\n",
aa21c004 360 priv->curbssparams.channel, newchannel);
876c9d3a
MT
361
362 /* Update the channel again */
aa21c004 363 priv->curbssparams.channel = newchannel;
876c9d3a
MT
364 }
365
9012b28a 366 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a
MT
367 return 0;
368}
369
69f9032d 370static int lbs_ret_802_11_rssi(struct lbs_private *priv,
876c9d3a
MT
371 struct cmd_ds_command *resp)
372{
373 struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
876c9d3a 374
a6c8700f
HS
375 lbs_deb_enter(LBS_DEB_CMD);
376
876c9d3a 377 /* store the non average value */
aa21c004
DW
378 priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
379 priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
876c9d3a 380
aa21c004
DW
381 priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
382 priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
876c9d3a 383
aa21c004
DW
384 priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
385 CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
386 priv->NF[TYPE_BEACON][TYPE_NOAVG]);
876c9d3a 387
aa21c004
DW
388 priv->RSSI[TYPE_BEACON][TYPE_AVG] =
389 CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
390 priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
876c9d3a 391
a6c8700f 392 lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
aa21c004
DW
393 priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
394 priv->RSSI[TYPE_BEACON][TYPE_AVG]);
876c9d3a 395
a6c8700f 396 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
397 return 0;
398}
399
69f9032d 400static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
876c9d3a
MT
401 struct cmd_ds_command *resp)
402{
10078321 403 struct lbs_ioctl_regrdwr *pbuf;
aa21c004 404 pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom;
876c9d3a 405
a6c8700f 406 lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
876c9d3a
MT
407 le16_to_cpu(resp->params.rdeeprom.bytecount));
408 if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
409 pbuf->NOB = 0;
a6c8700f 410 lbs_deb_cmd("EEPROM read length too big\n");
876c9d3a
MT
411 return -1;
412 }
413 pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
414 if (pbuf->NOB > 0) {
415
416 memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
417 le16_to_cpu(resp->params.rdeeprom.bytecount));
a6c8700f 418 lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
876c9d3a
MT
419 le16_to_cpu(resp->params.rdeeprom.bytecount));
420 }
a6c8700f 421 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
422 return 0;
423}
424
69f9032d 425static int lbs_ret_get_log(struct lbs_private *priv,
876c9d3a
MT
426 struct cmd_ds_command *resp)
427{
981f187b 428 struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
876c9d3a 429
9012b28a 430 lbs_deb_enter(LBS_DEB_CMD);
876c9d3a 431
981f187b 432 /* Stored little-endian */
aa21c004 433 memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
876c9d3a 434
a6c8700f 435 lbs_deb_leave(LBS_DEB_CMD);
876c9d3a
MT
436 return 0;
437}
438
69f9032d 439static int lbs_ret_802_11_enable_rsn(struct lbs_private *priv,
18c96c34
DW
440 struct cmd_ds_command *resp)
441{
442 struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
aa21c004 443 u32 * pdata_buf = priv->cur_cmd->pdata_buf;
18c96c34
DW
444
445 lbs_deb_enter(LBS_DEB_CMD);
446
0aef64d7 447 if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
18c96c34
DW
448 if (pdata_buf)
449 *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
450 }
451
a6c8700f 452 lbs_deb_leave(LBS_DEB_CMD);
18c96c34
DW
453 return 0;
454}
455
96287ac4
BD
456static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
457 struct cmd_ds_command *resp)
458{
459 struct cmd_ds_802_11_beacon_control *bcn_ctrl =
460 &resp->params.bcn_ctrl;
96287ac4
BD
461
462 lbs_deb_enter(LBS_DEB_CMD);
463
464 if (bcn_ctrl->action == CMD_ACT_GET) {
aa21c004
DW
465 priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
466 priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
96287ac4
BD
467 }
468
469 lbs_deb_enter(LBS_DEB_CMD);
470 return 0;
471}
472
3a188649
HS
473static int lbs_ret_802_11_subscribe_event(struct lbs_private *priv,
474 struct cmd_ds_command *resp)
475{
3a188649
HS
476 struct cmd_ds_802_11_subscribe_event *cmd_event =
477 &resp->params.subscribe_event;
478 struct cmd_ds_802_11_subscribe_event *dst_event =
aa21c004 479 priv->cur_cmd->pdata_buf;
3a188649
HS
480
481 lbs_deb_enter(LBS_DEB_CMD);
482
483 if (dst_event->action == cpu_to_le16(CMD_ACT_GET)) {
c2df2efe 484 dst_event->events = cmd_event->events;
3a188649
HS
485 memcpy(dst_event->tlv, cmd_event->tlv, sizeof(dst_event->tlv));
486 }
487
488 lbs_deb_leave(LBS_DEB_CMD);
489 return 0;
490}
491
1309b55b
DW
492static inline int handle_cmd_response(struct lbs_private *priv,
493 unsigned long dummy,
494 struct cmd_ds_command *resp)
876c9d3a
MT
495{
496 int ret = 0;
497 unsigned long flags;
1309b55b 498 uint16_t respcmd = le16_to_cpu(resp->command);
876c9d3a 499
a6c8700f
HS
500 lbs_deb_enter(LBS_DEB_HOST);
501
876c9d3a 502 switch (respcmd) {
6b63cd0f
HS
503 case CMD_RET(CMD_MAC_REG_ACCESS):
504 case CMD_RET(CMD_BBP_REG_ACCESS):
505 case CMD_RET(CMD_RF_REG_ACCESS):
10078321 506 ret = lbs_ret_reg_access(priv, respcmd, resp);
876c9d3a
MT
507 break;
508
6b63cd0f 509 case CMD_RET(CMD_802_11_SCAN):
10078321 510 ret = lbs_ret_80211_scan(priv, resp);
876c9d3a
MT
511 break;
512
6b63cd0f 513 case CMD_RET(CMD_802_11_GET_LOG):
10078321 514 ret = lbs_ret_get_log(priv, resp);
876c9d3a
MT
515 break;
516
0aef64d7 517 case CMD_RET_802_11_ASSOCIATE:
6b63cd0f
HS
518 case CMD_RET(CMD_802_11_ASSOCIATE):
519 case CMD_RET(CMD_802_11_REASSOCIATE):
10078321 520 ret = lbs_ret_80211_associate(priv, resp);
876c9d3a
MT
521 break;
522
6b63cd0f
HS
523 case CMD_RET(CMD_802_11_DISASSOCIATE):
524 case CMD_RET(CMD_802_11_DEAUTHENTICATE):
10078321 525 ret = lbs_ret_80211_disassociate(priv, resp);
876c9d3a
MT
526 break;
527
6b63cd0f
HS
528 case CMD_RET(CMD_802_11_AD_HOC_START):
529 case CMD_RET(CMD_802_11_AD_HOC_JOIN):
10078321 530 ret = lbs_ret_80211_ad_hoc_start(priv, resp);
876c9d3a
MT
531 break;
532
6b63cd0f 533 case CMD_RET(CMD_802_11_GET_STAT):
10078321 534 ret = lbs_ret_802_11_stat(priv, resp);
876c9d3a
MT
535 break;
536
6b63cd0f 537 case CMD_RET(CMD_802_11_SNMP_MIB):
10078321 538 ret = lbs_ret_802_11_snmp_mib(priv, resp);
876c9d3a
MT
539 break;
540
6b63cd0f 541 case CMD_RET(CMD_802_11_RF_TX_POWER):
10078321 542 ret = lbs_ret_802_11_rf_tx_power(priv, resp);
876c9d3a
MT
543 break;
544
6b63cd0f
HS
545 case CMD_RET(CMD_802_11_SET_AFC):
546 case CMD_RET(CMD_802_11_GET_AFC):
aa21c004
DW
547 spin_lock_irqsave(&priv->driver_lock, flags);
548 memmove(priv->cur_cmd->pdata_buf, &resp->params.afc,
876c9d3a 549 sizeof(struct cmd_ds_802_11_afc));
aa21c004 550 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
551
552 break;
876c9d3a 553
6b63cd0f
HS
554 case CMD_RET(CMD_MAC_MULTICAST_ADR):
555 case CMD_RET(CMD_MAC_CONTROL):
556 case CMD_RET(CMD_802_11_SET_WEP):
557 case CMD_RET(CMD_802_11_RESET):
558 case CMD_RET(CMD_802_11_AUTHENTICATE):
559 case CMD_RET(CMD_802_11_RADIO_CONTROL):
560 case CMD_RET(CMD_802_11_BEACON_STOP):
18c96c34
DW
561 break;
562
6b63cd0f 563 case CMD_RET(CMD_802_11_ENABLE_RSN):
10078321 564 ret = lbs_ret_802_11_enable_rsn(priv, resp);
876c9d3a
MT
565 break;
566
6b63cd0f 567 case CMD_RET(CMD_802_11_DATA_RATE):
10078321 568 ret = lbs_ret_802_11_data_rate(priv, resp);
876c9d3a 569 break;
6b63cd0f 570 case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
10078321 571 ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
876c9d3a 572 break;
6b63cd0f 573 case CMD_RET(CMD_802_11_RF_CHANNEL):
10078321 574 ret = lbs_ret_802_11_rf_channel(priv, resp);
876c9d3a
MT
575 break;
576
6b63cd0f 577 case CMD_RET(CMD_802_11_RSSI):
10078321 578 ret = lbs_ret_802_11_rssi(priv, resp);
876c9d3a
MT
579 break;
580
6b63cd0f 581 case CMD_RET(CMD_802_11_MAC_ADDRESS):
10078321 582 ret = lbs_ret_802_11_mac_address(priv, resp);
876c9d3a
MT
583 break;
584
6b63cd0f 585 case CMD_RET(CMD_802_11_AD_HOC_STOP):
10078321 586 ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
876c9d3a
MT
587 break;
588
6b63cd0f 589 case CMD_RET(CMD_802_11_KEY_MATERIAL):
10078321 590 ret = lbs_ret_802_11_key_material(priv, resp);
876c9d3a
MT
591 break;
592
6b63cd0f 593 case CMD_RET(CMD_802_11_EEPROM_ACCESS):
10078321 594 ret = lbs_ret_802_11_eeprom_access(priv, resp);
876c9d3a
MT
595 break;
596
6b63cd0f 597 case CMD_RET(CMD_802_11D_DOMAIN_INFO):
10078321 598 ret = lbs_ret_802_11d_domain_info(priv, resp);
876c9d3a
MT
599 break;
600
6b63cd0f 601 case CMD_RET(CMD_802_11_SLEEP_PARAMS):
10078321 602 ret = lbs_ret_802_11_sleep_params(priv, resp);
876c9d3a 603 break;
6b63cd0f 604 case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
aa21c004
DW
605 spin_lock_irqsave(&priv->driver_lock, flags);
606 *((u16 *) priv->cur_cmd->pdata_buf) =
876c9d3a 607 le16_to_cpu(resp->params.inactivity_timeout.timeout);
aa21c004 608 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
609 break;
610
6b63cd0f 611 case CMD_RET(CMD_802_11_TPC_CFG):
aa21c004
DW
612 spin_lock_irqsave(&priv->driver_lock, flags);
613 memmove(priv->cur_cmd->pdata_buf, &resp->params.tpccfg,
876c9d3a 614 sizeof(struct cmd_ds_802_11_tpc_cfg));
aa21c004 615 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 616 break;
6b63cd0f 617 case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
aa21c004
DW
618 spin_lock_irqsave(&priv->driver_lock, flags);
619 memmove(priv->cur_cmd->pdata_buf, &resp->params.ledgpio,
876c9d3a 620 sizeof(struct cmd_ds_802_11_led_ctrl));
aa21c004 621 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 622 break;
3a188649
HS
623 case CMD_RET(CMD_802_11_SUBSCRIBE_EVENT):
624 ret = lbs_ret_802_11_subscribe_event(priv, resp);
625 break;
626
6b63cd0f 627 case CMD_RET(CMD_802_11_PWR_CFG):
aa21c004
DW
628 spin_lock_irqsave(&priv->driver_lock, flags);
629 memmove(priv->cur_cmd->pdata_buf, &resp->params.pwrcfg,
876c9d3a 630 sizeof(struct cmd_ds_802_11_pwr_cfg));
aa21c004 631 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
632
633 break;
634
6b63cd0f 635 case CMD_RET(CMD_GET_TSF):
aa21c004
DW
636 spin_lock_irqsave(&priv->driver_lock, flags);
637 memcpy(priv->cur_cmd->pdata_buf,
876c9d3a 638 &resp->params.gettsf.tsfvalue, sizeof(u64));
aa21c004 639 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 640 break;
6b63cd0f 641 case CMD_RET(CMD_BT_ACCESS):
aa21c004
DW
642 spin_lock_irqsave(&priv->driver_lock, flags);
643 if (priv->cur_cmd->pdata_buf)
644 memcpy(priv->cur_cmd->pdata_buf,
876c9d3a 645 &resp->params.bt.addr1, 2 * ETH_ALEN);
aa21c004 646 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 647 break;
6b63cd0f 648 case CMD_RET(CMD_FWT_ACCESS):
aa21c004
DW
649 spin_lock_irqsave(&priv->driver_lock, flags);
650 if (priv->cur_cmd->pdata_buf)
651 memcpy(priv->cur_cmd->pdata_buf, &resp->params.fwt,
981f187b 652 sizeof(resp->params.fwt));
aa21c004 653 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a 654 break;
6b63cd0f 655 case CMD_RET(CMD_MESH_ACCESS):
aa21c004
DW
656 if (priv->cur_cmd->pdata_buf)
657 memcpy(priv->cur_cmd->pdata_buf, &resp->params.mesh,
876c9d3a
MT
658 sizeof(resp->params.mesh));
659 break;
96287ac4
BD
660 case CMD_RET(CMD_802_11_BEACON_CTRL):
661 ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
662 break;
663
876c9d3a 664 default:
a6c8700f 665 lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
981f187b 666 resp->command);
876c9d3a
MT
667 break;
668 }
a6c8700f 669 lbs_deb_leave(LBS_DEB_HOST);
876c9d3a
MT
670 return ret;
671}
672
69f9032d 673int lbs_process_rx_command(struct lbs_private *priv)
876c9d3a
MT
674{
675 u16 respcmd;
676 struct cmd_ds_command *resp;
876c9d3a
MT
677 int ret = 0;
678 ulong flags;
679 u16 result;
680
a6c8700f 681 lbs_deb_enter(LBS_DEB_HOST);
876c9d3a
MT
682
683 /* Now we got response from FW, cancel the command timer */
aa21c004 684 del_timer(&priv->command_timer);
876c9d3a 685
aa21c004
DW
686 mutex_lock(&priv->lock);
687 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 688
aa21c004 689 if (!priv->cur_cmd) {
a6c8700f 690 lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
876c9d3a 691 ret = -1;
aa21c004 692 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
693 goto done;
694 }
aa21c004 695 resp = (struct cmd_ds_command *)(priv->cur_cmd->bufvirtualaddr);
876c9d3a 696
876c9d3a 697 respcmd = le16_to_cpu(resp->command);
876c9d3a
MT
698 result = le16_to_cpu(resp->result);
699
a6c8700f
HS
700 lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
701 respcmd, priv->upld_len, jiffies);
aa21c004 702 lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", priv->cur_cmd->bufvirtualaddr,
a6c8700f 703 priv->upld_len);
876c9d3a
MT
704
705 if (!(respcmd & 0x8000)) {
a6c8700f 706 lbs_deb_host("invalid response!\n");
aa21c004
DW
707 priv->cur_cmd_retcode = -1;
708 __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
709 priv->cur_cmd = NULL;
710 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
711 ret = -1;
712 goto done;
713 }
714
715 /* Store the response code to cur_cmd_retcode. */
aa21c004 716 priv->cur_cmd_retcode = result;
876c9d3a 717
6b63cd0f 718 if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
981f187b
DW
719 struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
720 u16 action = le16_to_cpu(psmode->action);
876c9d3a 721
a6c8700f
HS
722 lbs_deb_host(
723 "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
981f187b 724 result, action);
876c9d3a
MT
725
726 if (result) {
a6c8700f 727 lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
981f187b
DW
728 result);
729 /*
730 * We should not re-try enter-ps command in
731 * ad-hoc mode. It takes place in
10078321 732 * lbs_execute_next_command().
981f187b 733 */
aa21c004 734 if (priv->mode == IW_MODE_ADHOC &&
0aef64d7 735 action == CMD_SUBCMD_ENTER_PS)
aa21c004 736 priv->psmode = LBS802_11POWERMODECAM;
0aef64d7 737 } else if (action == CMD_SUBCMD_ENTER_PS) {
aa21c004
DW
738 priv->needtowakeup = 0;
739 priv->psstate = PS_STATE_AWAKE;
876c9d3a 740
a6c8700f 741 lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
aa21c004 742 if (priv->connect_status != LBS_CONNECTED) {
876c9d3a
MT
743 /*
744 * When Deauth Event received before Enter_PS command
745 * response, We need to wake up the firmware.
746 */
a6c8700f 747 lbs_deb_host(
10078321 748 "disconnected, invoking lbs_ps_wakeup\n");
876c9d3a 749
aa21c004
DW
750 spin_unlock_irqrestore(&priv->driver_lock, flags);
751 mutex_unlock(&priv->lock);
10078321 752 lbs_ps_wakeup(priv, 0);
aa21c004
DW
753 mutex_lock(&priv->lock);
754 spin_lock_irqsave(&priv->driver_lock, flags);
876c9d3a 755 }
0aef64d7 756 } else if (action == CMD_SUBCMD_EXIT_PS) {
aa21c004
DW
757 priv->needtowakeup = 0;
758 priv->psstate = PS_STATE_FULL_POWER;
a6c8700f 759 lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
876c9d3a 760 } else {
a6c8700f 761 lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
876c9d3a
MT
762 }
763
aa21c004
DW
764 __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
765 priv->cur_cmd = NULL;
766 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
767
768 ret = 0;
769 goto done;
770 }
771
876c9d3a
MT
772 /* If the command is not successful, cleanup and return failure */
773 if ((result != 0 || !(respcmd & 0x8000))) {
a6c8700f
HS
774 lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
775 result, respcmd);
876c9d3a
MT
776 /*
777 * Handling errors here
778 */
779 switch (respcmd) {
6b63cd0f
HS
780 case CMD_RET(CMD_GET_HW_SPEC):
781 case CMD_RET(CMD_802_11_RESET):
a6c8700f 782 lbs_deb_host("CMD_RESP: reset failed\n");
876c9d3a
MT
783 break;
784
785 }
786
aa21c004
DW
787 __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
788 priv->cur_cmd = NULL;
789 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
790
791 ret = -1;
792 goto done;
793 }
794
aa21c004 795 spin_unlock_irqrestore(&priv->driver_lock, flags);
1723047d 796
7ad994de
DW
797 if (priv->cur_cmd && priv->cur_cmd->callback) {
798 ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
799 (struct cmd_header *) resp);
800 } else
1309b55b 801 ret = handle_cmd_response(priv, 0, resp);
1723047d 802
aa21c004 803 spin_lock_irqsave(&priv->driver_lock, flags);
1723047d 804
aa21c004 805 if (priv->cur_cmd) {
876c9d3a 806 /* Clean up and Put current command back to cmdfreeq */
aa21c004
DW
807 __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
808 priv->cur_cmd = NULL;
876c9d3a 809 }
aa21c004 810 spin_unlock_irqrestore(&priv->driver_lock, flags);
876c9d3a
MT
811
812done:
aa21c004 813 mutex_unlock(&priv->lock);
a6c8700f 814 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
876c9d3a
MT
815 return ret;
816}
817
69f9032d 818int lbs_process_event(struct lbs_private *priv)
876c9d3a
MT
819{
820 int ret = 0;
876c9d3a
MT
821 u32 eventcause;
822
9556d212
HS
823 lbs_deb_enter(LBS_DEB_CMD);
824
aa21c004
DW
825 spin_lock_irq(&priv->driver_lock);
826 eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
827 spin_unlock_irq(&priv->driver_lock);
876c9d3a 828
0b3c07ff 829 lbs_deb_cmd("event cause %d\n", eventcause);
876c9d3a 830
0b3c07ff 831 switch (eventcause) {
876c9d3a 832 case MACREG_INT_CODE_LINK_SENSED:
9012b28a 833 lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n");
876c9d3a
MT
834 break;
835
836 case MACREG_INT_CODE_DEAUTHENTICATED:
a6c8700f 837 lbs_deb_cmd("EVENT: deauthenticated\n");
10078321 838 lbs_mac_event_disconnected(priv);
876c9d3a
MT
839 break;
840
841 case MACREG_INT_CODE_DISASSOCIATED:
a6c8700f 842 lbs_deb_cmd("EVENT: disassociated\n");
10078321 843 lbs_mac_event_disconnected(priv);
876c9d3a
MT
844 break;
845
0b3c07ff 846 case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
a6c8700f 847 lbs_deb_cmd("EVENT: link lost\n");
10078321 848 lbs_mac_event_disconnected(priv);
876c9d3a
MT
849 break;
850
851 case MACREG_INT_CODE_PS_SLEEP:
a6c8700f 852 lbs_deb_cmd("EVENT: sleep\n");
876c9d3a
MT
853
854 /* handle unexpected PS SLEEP event */
aa21c004 855 if (priv->psstate == PS_STATE_FULL_POWER) {
9012b28a 856 lbs_deb_cmd(
a6c8700f 857 "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
876c9d3a
MT
858 break;
859 }
aa21c004 860 priv->psstate = PS_STATE_PRE_SLEEP;
876c9d3a 861
aa21c004 862 lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
876c9d3a
MT
863
864 break;
865
866 case MACREG_INT_CODE_PS_AWAKE:
a6c8700f 867 lbs_deb_cmd("EVENT: awake\n");
876c9d3a
MT
868
869 /* handle unexpected PS AWAKE event */
aa21c004 870 if (priv->psstate == PS_STATE_FULL_POWER) {
9012b28a 871 lbs_deb_cmd(
876c9d3a
MT
872 "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
873 break;
874 }
875
aa21c004 876 priv->psstate = PS_STATE_AWAKE;
876c9d3a 877
aa21c004 878 if (priv->needtowakeup) {
876c9d3a
MT
879 /*
880 * wait for the command processing to finish
881 * before resuming sending
aa21c004 882 * priv->needtowakeup will be set to FALSE
10078321 883 * in lbs_ps_wakeup()
876c9d3a 884 */
a6c8700f 885 lbs_deb_cmd("waking up ...\n");
10078321 886 lbs_ps_wakeup(priv, 0);
876c9d3a
MT
887 }
888 break;
889
890 case MACREG_INT_CODE_MIC_ERR_UNICAST:
9012b28a 891 lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
876c9d3a
MT
892 handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
893 break;
894
895 case MACREG_INT_CODE_MIC_ERR_MULTICAST:
9012b28a 896 lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
876c9d3a
MT
897 handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
898 break;
899 case MACREG_INT_CODE_MIB_CHANGED:
900 case MACREG_INT_CODE_INIT_DONE:
901 break;
902
903 case MACREG_INT_CODE_ADHOC_BCN_LOST:
a6c8700f 904 lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
876c9d3a
MT
905 break;
906
907 case MACREG_INT_CODE_RSSI_LOW:
a6c8700f 908 lbs_pr_alert("EVENT: rssi low\n");
876c9d3a
MT
909 break;
910 case MACREG_INT_CODE_SNR_LOW:
a6c8700f 911 lbs_pr_alert("EVENT: snr low\n");
876c9d3a
MT
912 break;
913 case MACREG_INT_CODE_MAX_FAIL:
a6c8700f 914 lbs_pr_alert("EVENT: max fail\n");
876c9d3a
MT
915 break;
916 case MACREG_INT_CODE_RSSI_HIGH:
a6c8700f 917 lbs_pr_alert("EVENT: rssi high\n");
876c9d3a
MT
918 break;
919 case MACREG_INT_CODE_SNR_HIGH:
a6c8700f 920 lbs_pr_alert("EVENT: snr high\n");
876c9d3a
MT
921 break;
922
7d8d28b3 923 case MACREG_INT_CODE_MESH_AUTO_STARTED:
5612c014
DW
924 /* Ignore spurious autostart events if autostart is disabled */
925 if (!priv->mesh_autostart_enabled) {
926 lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
927 break;
928 }
9cdc6d29 929 lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
aa21c004 930 priv->mesh_connect_status = LBS_CONNECTED;
7d8d28b3 931 if (priv->mesh_open == 1) {
9cdc6d29
LCC
932 netif_wake_queue(priv->mesh_dev);
933 netif_carrier_on(priv->mesh_dev);
7d8d28b3 934 }
aa21c004 935 priv->mode = IW_MODE_ADHOC;
b8bedefd 936 schedule_work(&priv->sync_channel);
7d8d28b3
LCCR
937 break;
938
876c9d3a 939 default:
0b3c07ff 940 lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
876c9d3a
MT
941 break;
942 }
943
aa21c004
DW
944 spin_lock_irq(&priv->driver_lock);
945 priv->eventcause = 0;
946 spin_unlock_irq(&priv->driver_lock);
9012b28a 947
9556d212 948 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
876c9d3a
MT
949 return ret;
950}
This page took 0.259322 seconds and 5 git commands to generate.