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