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