libertas: remove unused indirect TPC_CFG command leftovers
[linux-3.10.git] / drivers / net / wireless / libertas / cmdresp.c
1 /**
2   * This file contains the handling of command
3   * responses as well as events generated by firmware.
4   */
5 #include <linux/slab.h>
6 #include <linux/delay.h>
7 #include <linux/sched.h>
8 #include <asm/unaligned.h>
9 #include <net/cfg80211.h>
10
11 #include "cfg.h"
12 #include "cmd.h"
13
14 /**
15  *  @brief This function handles disconnect event. it
16  *  reports disconnect to upper layer, clean tx/rx packets,
17  *  reset link state etc.
18  *
19  *  @param priv    A pointer to struct lbs_private structure
20  *  @return        n/a
21  */
22 void lbs_mac_event_disconnected(struct lbs_private *priv)
23 {
24         if (priv->connect_status != LBS_CONNECTED)
25                 return;
26
27         lbs_deb_enter(LBS_DEB_ASSOC);
28
29         /*
30          * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
31          * It causes problem in the Supplicant
32          */
33         msleep_interruptible(1000);
34
35         if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
36                 lbs_send_disconnect_notification(priv);
37
38         /* report disconnect to upper layer */
39         netif_stop_queue(priv->dev);
40         netif_carrier_off(priv->dev);
41
42         /* Free Tx and Rx packets */
43         kfree_skb(priv->currenttxskb);
44         priv->currenttxskb = NULL;
45         priv->tx_pending_len = 0;
46
47         priv->connect_status = LBS_DISCONNECTED;
48
49         if (priv->psstate != PS_STATE_FULL_POWER) {
50                 /* make firmware to exit PS mode */
51                 lbs_deb_cmd("disconnected, so exit PS mode\n");
52                 lbs_ps_wakeup(priv, 0);
53         }
54         lbs_deb_leave(LBS_DEB_ASSOC);
55 }
56
57 static int lbs_ret_reg_access(struct lbs_private *priv,
58                                u16 type, struct cmd_ds_command *resp)
59 {
60         int ret = 0;
61
62         lbs_deb_enter(LBS_DEB_CMD);
63
64         switch (type) {
65         case CMD_RET(CMD_MAC_REG_ACCESS):
66                 {
67                         struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
68
69                         priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
70                         priv->offsetvalue.value = le32_to_cpu(reg->value);
71                         break;
72                 }
73
74         case CMD_RET(CMD_BBP_REG_ACCESS):
75                 {
76                         struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
77
78                         priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
79                         priv->offsetvalue.value = reg->value;
80                         break;
81                 }
82
83         case CMD_RET(CMD_RF_REG_ACCESS):
84                 {
85                         struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
86
87                         priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
88                         priv->offsetvalue.value = reg->value;
89                         break;
90                 }
91
92         default:
93                 ret = -1;
94         }
95
96         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
97         return ret;
98 }
99 static inline int handle_cmd_response(struct lbs_private *priv,
100                                       struct cmd_header *cmd_response)
101 {
102         struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
103         int ret = 0;
104         unsigned long flags;
105         uint16_t respcmd = le16_to_cpu(resp->command);
106
107         lbs_deb_enter(LBS_DEB_HOST);
108
109         switch (respcmd) {
110         case CMD_RET(CMD_MAC_REG_ACCESS):
111         case CMD_RET(CMD_BBP_REG_ACCESS):
112         case CMD_RET(CMD_RF_REG_ACCESS):
113                 ret = lbs_ret_reg_access(priv, respcmd, resp);
114                 break;
115
116         case CMD_RET(CMD_802_11_SET_AFC):
117         case CMD_RET(CMD_802_11_GET_AFC):
118                 spin_lock_irqsave(&priv->driver_lock, flags);
119                 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
120                         sizeof(struct cmd_ds_802_11_afc));
121                 spin_unlock_irqrestore(&priv->driver_lock, flags);
122
123                 break;
124
125         case CMD_RET(CMD_802_11_BEACON_STOP):
126                 break;
127
128         case CMD_RET(CMD_BT_ACCESS):
129                 spin_lock_irqsave(&priv->driver_lock, flags);
130                 if (priv->cur_cmd->callback_arg)
131                         memcpy((void *)priv->cur_cmd->callback_arg,
132                                &resp->params.bt.addr1, 2 * ETH_ALEN);
133                 spin_unlock_irqrestore(&priv->driver_lock, flags);
134                 break;
135         case CMD_RET(CMD_FWT_ACCESS):
136                 spin_lock_irqsave(&priv->driver_lock, flags);
137                 if (priv->cur_cmd->callback_arg)
138                         memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
139                                sizeof(resp->params.fwt));
140                 spin_unlock_irqrestore(&priv->driver_lock, flags);
141                 break;
142         case CMD_RET(CMD_802_11_BEACON_CTRL):
143                 ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
144                 break;
145
146         default:
147                 lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
148                            le16_to_cpu(resp->command));
149                 break;
150         }
151         lbs_deb_leave(LBS_DEB_HOST);
152         return ret;
153 }
154
155 int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
156 {
157         uint16_t respcmd, curcmd;
158         struct cmd_header *resp;
159         int ret = 0;
160         unsigned long flags;
161         uint16_t result;
162
163         lbs_deb_enter(LBS_DEB_HOST);
164
165         mutex_lock(&priv->lock);
166         spin_lock_irqsave(&priv->driver_lock, flags);
167
168         if (!priv->cur_cmd) {
169                 lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
170                 ret = -1;
171                 spin_unlock_irqrestore(&priv->driver_lock, flags);
172                 goto done;
173         }
174
175         resp = (void *)data;
176         curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
177         respcmd = le16_to_cpu(resp->command);
178         result = le16_to_cpu(resp->result);
179
180         lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
181                      respcmd, le16_to_cpu(resp->seqnum), len);
182         lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
183
184         if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
185                 lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
186                             le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
187                 spin_unlock_irqrestore(&priv->driver_lock, flags);
188                 ret = -1;
189                 goto done;
190         }
191         if (respcmd != CMD_RET(curcmd) &&
192             respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
193                 lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
194                 spin_unlock_irqrestore(&priv->driver_lock, flags);
195                 ret = -1;
196                 goto done;
197         }
198
199         if (resp->result == cpu_to_le16(0x0004)) {
200                 /* 0x0004 means -EAGAIN. Drop the response, let it time out
201                    and be resubmitted */
202                 lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
203                             le16_to_cpu(resp->command));
204                 spin_unlock_irqrestore(&priv->driver_lock, flags);
205                 ret = -1;
206                 goto done;
207         }
208
209         /* Now we got response from FW, cancel the command timer */
210         del_timer(&priv->command_timer);
211         priv->cmd_timed_out = 0;
212
213         /* Store the response code to cur_cmd_retcode. */
214         priv->cur_cmd_retcode = result;
215
216         if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
217                 struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
218                 u16 action = le16_to_cpu(psmode->action);
219
220                 lbs_deb_host(
221                        "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
222                        result, action);
223
224                 if (result) {
225                         lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
226                                     result);
227                         /*
228                          * We should not re-try enter-ps command in
229                          * ad-hoc mode. It takes place in
230                          * lbs_execute_next_command().
231                          */
232                         if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
233                             action == CMD_SUBCMD_ENTER_PS)
234                                 priv->psmode = LBS802_11POWERMODECAM;
235                 } else if (action == CMD_SUBCMD_ENTER_PS) {
236                         priv->needtowakeup = 0;
237                         priv->psstate = PS_STATE_AWAKE;
238
239                         lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
240                         if (priv->connect_status != LBS_CONNECTED) {
241                                 /*
242                                  * When Deauth Event received before Enter_PS command
243                                  * response, We need to wake up the firmware.
244                                  */
245                                 lbs_deb_host(
246                                        "disconnected, invoking lbs_ps_wakeup\n");
247
248                                 spin_unlock_irqrestore(&priv->driver_lock, flags);
249                                 mutex_unlock(&priv->lock);
250                                 lbs_ps_wakeup(priv, 0);
251                                 mutex_lock(&priv->lock);
252                                 spin_lock_irqsave(&priv->driver_lock, flags);
253                         }
254                 } else if (action == CMD_SUBCMD_EXIT_PS) {
255                         priv->needtowakeup = 0;
256                         priv->psstate = PS_STATE_FULL_POWER;
257                         lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
258                 } else {
259                         lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
260                 }
261
262                 lbs_complete_command(priv, priv->cur_cmd, result);
263                 spin_unlock_irqrestore(&priv->driver_lock, flags);
264
265                 ret = 0;
266                 goto done;
267         }
268
269         /* If the command is not successful, cleanup and return failure */
270         if ((result != 0 || !(respcmd & 0x8000))) {
271                 lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
272                        result, respcmd);
273                 /*
274                  * Handling errors here
275                  */
276                 switch (respcmd) {
277                 case CMD_RET(CMD_GET_HW_SPEC):
278                 case CMD_RET(CMD_802_11_RESET):
279                         lbs_deb_host("CMD_RESP: reset failed\n");
280                         break;
281
282                 }
283                 lbs_complete_command(priv, priv->cur_cmd, result);
284                 spin_unlock_irqrestore(&priv->driver_lock, flags);
285
286                 ret = -1;
287                 goto done;
288         }
289
290         spin_unlock_irqrestore(&priv->driver_lock, flags);
291
292         if (priv->cur_cmd && priv->cur_cmd->callback) {
293                 ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
294                                 resp);
295         } else
296                 ret = handle_cmd_response(priv, resp);
297
298         spin_lock_irqsave(&priv->driver_lock, flags);
299
300         if (priv->cur_cmd) {
301                 /* Clean up and Put current command back to cmdfreeq */
302                 lbs_complete_command(priv, priv->cur_cmd, result);
303         }
304         spin_unlock_irqrestore(&priv->driver_lock, flags);
305
306 done:
307         mutex_unlock(&priv->lock);
308         lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
309         return ret;
310 }
311
312 int lbs_process_event(struct lbs_private *priv, u32 event)
313 {
314         int ret = 0;
315         struct cmd_header cmd;
316
317         lbs_deb_enter(LBS_DEB_CMD);
318
319         switch (event) {
320         case MACREG_INT_CODE_LINK_SENSED:
321                 lbs_deb_cmd("EVENT: link sensed\n");
322                 break;
323
324         case MACREG_INT_CODE_DEAUTHENTICATED:
325                 lbs_deb_cmd("EVENT: deauthenticated\n");
326                 lbs_mac_event_disconnected(priv);
327                 break;
328
329         case MACREG_INT_CODE_DISASSOCIATED:
330                 lbs_deb_cmd("EVENT: disassociated\n");
331                 lbs_mac_event_disconnected(priv);
332                 break;
333
334         case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
335                 lbs_deb_cmd("EVENT: link lost\n");
336                 lbs_mac_event_disconnected(priv);
337                 break;
338
339         case MACREG_INT_CODE_PS_SLEEP:
340                 lbs_deb_cmd("EVENT: ps sleep\n");
341
342                 /* handle unexpected PS SLEEP event */
343                 if (priv->psstate == PS_STATE_FULL_POWER) {
344                         lbs_deb_cmd(
345                                "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
346                         break;
347                 }
348                 priv->psstate = PS_STATE_PRE_SLEEP;
349
350                 lbs_ps_confirm_sleep(priv);
351
352                 break;
353
354         case MACREG_INT_CODE_HOST_AWAKE:
355                 lbs_deb_cmd("EVENT: host awake\n");
356                 if (priv->reset_deep_sleep_wakeup)
357                         priv->reset_deep_sleep_wakeup(priv);
358                 priv->is_deep_sleep = 0;
359                 lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
360                                 sizeof(cmd));
361                 priv->is_host_sleep_activated = 0;
362                 wake_up_interruptible(&priv->host_sleep_q);
363                 break;
364
365         case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
366                 if (priv->reset_deep_sleep_wakeup)
367                         priv->reset_deep_sleep_wakeup(priv);
368                 lbs_deb_cmd("EVENT: ds awake\n");
369                 priv->is_deep_sleep = 0;
370                 priv->wakeup_dev_required = 0;
371                 wake_up_interruptible(&priv->ds_awake_q);
372                 break;
373
374         case MACREG_INT_CODE_PS_AWAKE:
375                 lbs_deb_cmd("EVENT: ps awake\n");
376                 /* handle unexpected PS AWAKE event */
377                 if (priv->psstate == PS_STATE_FULL_POWER) {
378                         lbs_deb_cmd(
379                                "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
380                         break;
381                 }
382
383                 priv->psstate = PS_STATE_AWAKE;
384
385                 if (priv->needtowakeup) {
386                         /*
387                          * wait for the command processing to finish
388                          * before resuming sending
389                          * priv->needtowakeup will be set to FALSE
390                          * in lbs_ps_wakeup()
391                          */
392                         lbs_deb_cmd("waking up ...\n");
393                         lbs_ps_wakeup(priv, 0);
394                 }
395                 break;
396
397         case MACREG_INT_CODE_MIC_ERR_UNICAST:
398                 lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
399                 lbs_send_mic_failureevent(priv, event);
400                 break;
401
402         case MACREG_INT_CODE_MIC_ERR_MULTICAST:
403                 lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
404                 lbs_send_mic_failureevent(priv, event);
405                 break;
406
407         case MACREG_INT_CODE_MIB_CHANGED:
408                 lbs_deb_cmd("EVENT: MIB CHANGED\n");
409                 break;
410         case MACREG_INT_CODE_INIT_DONE:
411                 lbs_deb_cmd("EVENT: INIT DONE\n");
412                 break;
413         case MACREG_INT_CODE_ADHOC_BCN_LOST:
414                 lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
415                 break;
416         case MACREG_INT_CODE_RSSI_LOW:
417                 lbs_pr_alert("EVENT: rssi low\n");
418                 break;
419         case MACREG_INT_CODE_SNR_LOW:
420                 lbs_pr_alert("EVENT: snr low\n");
421                 break;
422         case MACREG_INT_CODE_MAX_FAIL:
423                 lbs_pr_alert("EVENT: max fail\n");
424                 break;
425         case MACREG_INT_CODE_RSSI_HIGH:
426                 lbs_pr_alert("EVENT: rssi high\n");
427                 break;
428         case MACREG_INT_CODE_SNR_HIGH:
429                 lbs_pr_alert("EVENT: snr high\n");
430                 break;
431
432         case MACREG_INT_CODE_MESH_AUTO_STARTED:
433                 /* Ignore spurious autostart events */
434                 lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
435                 break;
436
437         default:
438                 lbs_pr_alert("EVENT: unknown event id %d\n", event);
439                 break;
440         }
441
442         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
443         return ret;
444 }