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