blob: d6c3063536403a66119d4f4ced1d4c336f11b8e4 [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/**
2 * This file contains the handling of command
3 * responses as well as events generated by firmware.
4 */
Tejun Heo5a0e3ad2010-03-24 17:04:11 +09005#include <linux/slab.h>
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02006#include <linux/delay.h>
Alan Cox767e3662009-10-12 05:27:48 +00007#include <linux/sched.h>
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02008#include <linux/if_arp.h>
9#include <linux/netdevice.h>
Cliff Cai2c5b9e512009-05-27 14:03:09 -040010#include <asm/unaligned.h>
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020011#include <net/iw_handler.h>
12
13#include "host.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020014#include "decl.h"
Holger Schurigbca61f82009-10-16 17:33:23 +020015#include "cmd.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020016#include "defs.h"
17#include "dev.h"
Holger Schurig697900a2008-04-02 16:27:10 +020018#include "assoc.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020019#include "wext.h"
Amitkumar Karwar66fceb62010-05-19 03:24:38 -070020#include "cmd.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020021
22/**
23 * @brief This function handles disconnect event. it
24 * reports disconnect to upper layer, clean tx/rx packets,
25 * reset link state etc.
26 *
Holger Schurig69f90322007-11-23 15:43:44 +010027 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020028 * @return n/a
29 */
Holger Schurig69f90322007-11-23 15:43:44 +010030void lbs_mac_event_disconnected(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020031{
David Woodhouseaa21c002007-12-08 20:04:36 +000032 if (priv->connect_status != LBS_CONNECTED)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020033 return;
34
Holger Schurig91843462007-11-28 14:05:02 +010035 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020036
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020037 /*
38 * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
39 * It causes problem in the Supplicant
40 */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020041 msleep_interruptible(1000);
Holger Schurigfea2b8e2009-10-22 15:30:56 +020042 lbs_send_disconnect_notification(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020043
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020044 /* report disconnect to upper layer */
Holger Schurig634b8f42007-05-25 13:05:16 -040045 netif_stop_queue(priv->dev);
46 netif_carrier_off(priv->dev);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020047
David Woodhousea27b9f92007-12-12 00:41:51 -050048 /* Free Tx and Rx packets */
49 kfree_skb(priv->currenttxskb);
50 priv->currenttxskb = NULL;
51 priv->tx_pending_len = 0;
52
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020053 /* reset SNR/NF/RSSI values */
David Woodhouseaa21c002007-12-08 20:04:36 +000054 memset(priv->SNR, 0x00, sizeof(priv->SNR));
55 memset(priv->NF, 0x00, sizeof(priv->NF));
56 memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
57 memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
58 memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
59 priv->nextSNRNF = 0;
60 priv->numSNRNF = 0;
61 priv->connect_status = LBS_DISCONNECTED;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020062
Dan Williamse76850d2007-05-25 17:09:41 -040063 /* Clear out associated SSID and BSSID since connection is
64 * no longer valid.
65 */
David Woodhouseaa21c002007-12-08 20:04:36 +000066 memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
Holger Schurig243e84e2009-10-22 15:30:47 +020067 memset(&priv->curbssparams.ssid, 0, IEEE80211_MAX_SSID_LEN);
David Woodhouseaa21c002007-12-08 20:04:36 +000068 priv->curbssparams.ssid_len = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020069
David Woodhouseaa21c002007-12-08 20:04:36 +000070 if (priv->psstate != PS_STATE_FULL_POWER) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020071 /* make firmware to exit PS mode */
Holger Schuriga6c87002007-08-02 11:54:10 -040072 lbs_deb_cmd("disconnected, so exit PS mode\n");
Holger Schurig10078322007-11-15 18:05:47 -050073 lbs_ps_wakeup(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020074 }
Holger Schurig52507c22008-01-28 17:25:53 +010075 lbs_deb_leave(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020076}
77
Holger Schurig69f90322007-11-23 15:43:44 +010078static int lbs_ret_reg_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020079 u16 type, struct cmd_ds_command *resp)
80{
Holger Schurig9012b282007-05-25 11:27:16 -040081 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020082
Holger Schurig9012b282007-05-25 11:27:16 -040083 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020084
85 switch (type) {
Holger Schurig6b63cd02007-08-02 11:53:36 -040086 case CMD_RET(CMD_MAC_REG_ACCESS):
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020087 {
David Woodhouse981f1872007-05-25 23:36:54 -040088 struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020089
David Woodhouseaa21c002007-12-08 20:04:36 +000090 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
91 priv->offsetvalue.value = le32_to_cpu(reg->value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020092 break;
93 }
94
Holger Schurig6b63cd02007-08-02 11:53:36 -040095 case CMD_RET(CMD_BBP_REG_ACCESS):
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020096 {
David Woodhouse981f1872007-05-25 23:36:54 -040097 struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020098
David Woodhouseaa21c002007-12-08 20:04:36 +000099 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
100 priv->offsetvalue.value = reg->value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200101 break;
102 }
103
Holger Schurig6b63cd02007-08-02 11:53:36 -0400104 case CMD_RET(CMD_RF_REG_ACCESS):
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200105 {
David Woodhouse981f1872007-05-25 23:36:54 -0400106 struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200107
David Woodhouseaa21c002007-12-08 20:04:36 +0000108 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
109 priv->offsetvalue.value = reg->value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200110 break;
111 }
112
113 default:
Holger Schurig9012b282007-05-25 11:27:16 -0400114 ret = -1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200115 }
116
Holger Schurig8b17d722007-10-08 11:09:30 +0200117 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Holger Schurig9012b282007-05-25 11:27:16 -0400118 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200119}
120
David Woodhouse1309b552007-12-10 13:36:10 -0500121static inline int handle_cmd_response(struct lbs_private *priv,
Dan Williamsddac4522007-12-11 13:49:39 -0500122 struct cmd_header *cmd_response)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200123{
Dan Williamsddac4522007-12-11 13:49:39 -0500124 struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200125 int ret = 0;
126 unsigned long flags;
David Woodhouse1309b552007-12-10 13:36:10 -0500127 uint16_t respcmd = le16_to_cpu(resp->command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200128
Holger Schuriga6c87002007-08-02 11:54:10 -0400129 lbs_deb_enter(LBS_DEB_HOST);
130
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200131 switch (respcmd) {
Holger Schurig6b63cd02007-08-02 11:53:36 -0400132 case CMD_RET(CMD_MAC_REG_ACCESS):
133 case CMD_RET(CMD_BBP_REG_ACCESS):
134 case CMD_RET(CMD_RF_REG_ACCESS):
Holger Schurig10078322007-11-15 18:05:47 -0500135 ret = lbs_ret_reg_access(priv, respcmd, resp);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200136 break;
137
Holger Schurig6b63cd02007-08-02 11:53:36 -0400138 case CMD_RET(CMD_802_11_SET_AFC):
139 case CMD_RET(CMD_802_11_GET_AFC):
David Woodhouseaa21c002007-12-08 20:04:36 +0000140 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse75567672007-12-15 02:38:17 -0500141 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200142 sizeof(struct cmd_ds_802_11_afc));
David Woodhouseaa21c002007-12-08 20:04:36 +0000143 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200144
145 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200146
Holger Schurig6b63cd02007-08-02 11:53:36 -0400147 case CMD_RET(CMD_802_11_BEACON_STOP):
Dan Williams18c96c342007-06-18 12:01:12 -0400148 break;
149
Holger Schurig6b63cd02007-08-02 11:53:36 -0400150 case CMD_RET(CMD_802_11_RSSI):
Holger Schurig10078322007-11-15 18:05:47 -0500151 ret = lbs_ret_802_11_rssi(priv, resp);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200152 break;
153
Holger Schurig6b63cd02007-08-02 11:53:36 -0400154 case CMD_RET(CMD_802_11_TPC_CFG):
David Woodhouseaa21c002007-12-08 20:04:36 +0000155 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse75567672007-12-15 02:38:17 -0500156 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200157 sizeof(struct cmd_ds_802_11_tpc_cfg));
David Woodhouseaa21c002007-12-08 20:04:36 +0000158 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200159 break;
Holger Schurig3a188642007-11-26 10:07:14 +0100160
Holger Schurig6b63cd02007-08-02 11:53:36 -0400161 case CMD_RET(CMD_BT_ACCESS):
David Woodhouseaa21c002007-12-08 20:04:36 +0000162 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse75567672007-12-15 02:38:17 -0500163 if (priv->cur_cmd->callback_arg)
164 memcpy((void *)priv->cur_cmd->callback_arg,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200165 &resp->params.bt.addr1, 2 * ETH_ALEN);
David Woodhouseaa21c002007-12-08 20:04:36 +0000166 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200167 break;
Holger Schurig6b63cd02007-08-02 11:53:36 -0400168 case CMD_RET(CMD_FWT_ACCESS):
David Woodhouseaa21c002007-12-08 20:04:36 +0000169 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse75567672007-12-15 02:38:17 -0500170 if (priv->cur_cmd->callback_arg)
171 memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
David Woodhouse981f1872007-05-25 23:36:54 -0400172 sizeof(resp->params.fwt));
David Woodhouseaa21c002007-12-08 20:04:36 +0000173 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200174 break;
Brajesh Dave96287ac2007-11-20 17:44:28 -0500175 case CMD_RET(CMD_802_11_BEACON_CTRL):
176 ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
177 break;
178
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200179 default:
David Woodhousee37fc6e2008-05-20 11:47:16 +0100180 lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
181 le16_to_cpu(resp->command));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200182 break;
183 }
Holger Schuriga6c87002007-08-02 11:54:10 -0400184 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200185 return ret;
186}
187
Holger Schurig7919b892008-04-01 14:50:43 +0200188int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200189{
David Woodhousee1258172007-12-11 23:42:49 -0500190 uint16_t respcmd, curcmd;
Dan Williamsddac4522007-12-11 13:49:39 -0500191 struct cmd_header *resp;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200192 int ret = 0;
David Woodhousee1258172007-12-11 23:42:49 -0500193 unsigned long flags;
194 uint16_t result;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200195
Holger Schuriga6c87002007-08-02 11:54:10 -0400196 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200197
David Woodhouseaa21c002007-12-08 20:04:36 +0000198 mutex_lock(&priv->lock);
199 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200200
David Woodhouseaa21c002007-12-08 20:04:36 +0000201 if (!priv->cur_cmd) {
Holger Schuriga6c87002007-08-02 11:54:10 -0400202 lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200203 ret = -1;
David Woodhouseaa21c002007-12-08 20:04:36 +0000204 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200205 goto done;
206 }
David Woodhousee1258172007-12-11 23:42:49 -0500207
Holger Schurig7919b892008-04-01 14:50:43 +0200208 resp = (void *)data;
Sebastian Siewior8a96df82008-03-04 18:22:27 +0100209 curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200210 respcmd = le16_to_cpu(resp->command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200211 result = le16_to_cpu(resp->result);
212
Holger Schurige5225b32008-03-26 10:04:44 +0100213 lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
Holger Schurig7919b892008-04-01 14:50:43 +0200214 respcmd, le16_to_cpu(resp->seqnum), len);
215 lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200216
David Woodhouse6305f492008-03-03 12:20:12 +0100217 if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
David Woodhousee1258172007-12-11 23:42:49 -0500218 lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
David Woodhouse6305f492008-03-03 12:20:12 +0100219 le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
David Woodhouseaa21c002007-12-08 20:04:36 +0000220 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200221 ret = -1;
222 goto done;
223 }
David Woodhousee1258172007-12-11 23:42:49 -0500224 if (respcmd != CMD_RET(curcmd) &&
Sebastian Siewior5f0547c2008-03-06 10:30:21 +0100225 respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
David Woodhousee1258172007-12-11 23:42:49 -0500226 lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
227 spin_unlock_irqrestore(&priv->driver_lock, flags);
228 ret = -1;
229 goto done;
230 }
231
David Woodhouse85388232007-12-17 15:41:30 -0500232 if (resp->result == cpu_to_le16(0x0004)) {
233 /* 0x0004 means -EAGAIN. Drop the response, let it time out
234 and be resubmitted */
235 lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
236 le16_to_cpu(resp->command));
237 spin_unlock_irqrestore(&priv->driver_lock, flags);
238 ret = -1;
239 goto done;
240 }
241
David Woodhousee1258172007-12-11 23:42:49 -0500242 /* Now we got response from FW, cancel the command timer */
243 del_timer(&priv->command_timer);
David Woodhouse2a345092007-12-15 19:33:43 -0500244 priv->cmd_timed_out = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200245
246 /* Store the response code to cur_cmd_retcode. */
David Woodhouseaa21c002007-12-08 20:04:36 +0000247 priv->cur_cmd_retcode = result;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200248
Holger Schurig6b63cd02007-08-02 11:53:36 -0400249 if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
David Woodhouse38bfab12007-12-16 23:26:54 -0500250 struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
David Woodhouse981f1872007-05-25 23:36:54 -0400251 u16 action = le16_to_cpu(psmode->action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200252
Holger Schuriga6c87002007-08-02 11:54:10 -0400253 lbs_deb_host(
254 "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
David Woodhouse981f1872007-05-25 23:36:54 -0400255 result, action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200256
257 if (result) {
Holger Schuriga6c87002007-08-02 11:54:10 -0400258 lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
David Woodhouse981f1872007-05-25 23:36:54 -0400259 result);
260 /*
261 * We should not re-try enter-ps command in
262 * ad-hoc mode. It takes place in
Holger Schurig10078322007-11-15 18:05:47 -0500263 * lbs_execute_next_command().
David Woodhouse981f1872007-05-25 23:36:54 -0400264 */
David Woodhouseaa21c002007-12-08 20:04:36 +0000265 if (priv->mode == IW_MODE_ADHOC &&
Dan Williams0aef64d2007-08-02 11:31:18 -0400266 action == CMD_SUBCMD_ENTER_PS)
David Woodhouseaa21c002007-12-08 20:04:36 +0000267 priv->psmode = LBS802_11POWERMODECAM;
Dan Williams0aef64d2007-08-02 11:31:18 -0400268 } else if (action == CMD_SUBCMD_ENTER_PS) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000269 priv->needtowakeup = 0;
270 priv->psstate = PS_STATE_AWAKE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200271
Holger Schuriga6c87002007-08-02 11:54:10 -0400272 lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
David Woodhouseaa21c002007-12-08 20:04:36 +0000273 if (priv->connect_status != LBS_CONNECTED) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200274 /*
275 * When Deauth Event received before Enter_PS command
276 * response, We need to wake up the firmware.
277 */
Holger Schuriga6c87002007-08-02 11:54:10 -0400278 lbs_deb_host(
Holger Schurig10078322007-11-15 18:05:47 -0500279 "disconnected, invoking lbs_ps_wakeup\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200280
David Woodhouseaa21c002007-12-08 20:04:36 +0000281 spin_unlock_irqrestore(&priv->driver_lock, flags);
282 mutex_unlock(&priv->lock);
Holger Schurig10078322007-11-15 18:05:47 -0500283 lbs_ps_wakeup(priv, 0);
David Woodhouseaa21c002007-12-08 20:04:36 +0000284 mutex_lock(&priv->lock);
285 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200286 }
Dan Williams0aef64d2007-08-02 11:31:18 -0400287 } else if (action == CMD_SUBCMD_EXIT_PS) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000288 priv->needtowakeup = 0;
289 priv->psstate = PS_STATE_FULL_POWER;
Holger Schuriga6c87002007-08-02 11:54:10 -0400290 lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200291 } else {
Holger Schuriga6c87002007-08-02 11:54:10 -0400292 lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200293 }
294
David Woodhouse183aeac2007-12-15 01:52:54 -0500295 lbs_complete_command(priv, priv->cur_cmd, result);
David Woodhouseaa21c002007-12-08 20:04:36 +0000296 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200297
298 ret = 0;
299 goto done;
300 }
301
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200302 /* If the command is not successful, cleanup and return failure */
303 if ((result != 0 || !(respcmd & 0x8000))) {
Holger Schuriga6c87002007-08-02 11:54:10 -0400304 lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
305 result, respcmd);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200306 /*
307 * Handling errors here
308 */
309 switch (respcmd) {
Holger Schurig6b63cd02007-08-02 11:53:36 -0400310 case CMD_RET(CMD_GET_HW_SPEC):
311 case CMD_RET(CMD_802_11_RESET):
Holger Schuriga6c87002007-08-02 11:54:10 -0400312 lbs_deb_host("CMD_RESP: reset failed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200313 break;
314
315 }
David Woodhouse183aeac2007-12-15 01:52:54 -0500316 lbs_complete_command(priv, priv->cur_cmd, result);
David Woodhouseaa21c002007-12-08 20:04:36 +0000317 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200318
319 ret = -1;
320 goto done;
321 }
322
David Woodhouseaa21c002007-12-08 20:04:36 +0000323 spin_unlock_irqrestore(&priv->driver_lock, flags);
David Woodhouse17230472007-12-07 15:13:05 +0000324
Dan Williams7ad994d2007-12-11 12:33:30 -0500325 if (priv->cur_cmd && priv->cur_cmd->callback) {
326 ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
Dan Williamsddac4522007-12-11 13:49:39 -0500327 resp);
Dan Williams7ad994d2007-12-11 12:33:30 -0500328 } else
Holger Schurige98a88d2008-03-19 14:25:58 +0100329 ret = handle_cmd_response(priv, resp);
David Woodhouse17230472007-12-07 15:13:05 +0000330
David Woodhouseaa21c002007-12-08 20:04:36 +0000331 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse17230472007-12-07 15:13:05 +0000332
David Woodhouseaa21c002007-12-08 20:04:36 +0000333 if (priv->cur_cmd) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200334 /* Clean up and Put current command back to cmdfreeq */
David Woodhouse183aeac2007-12-15 01:52:54 -0500335 lbs_complete_command(priv, priv->cur_cmd, result);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200336 }
David Woodhouseaa21c002007-12-08 20:04:36 +0000337 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200338
339done:
David Woodhouseaa21c002007-12-08 20:04:36 +0000340 mutex_unlock(&priv->lock);
Holger Schuriga6c87002007-08-02 11:54:10 -0400341 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200342 return ret;
343}
344
Holger Schurig7919b892008-04-01 14:50:43 +0200345int lbs_process_event(struct lbs_private *priv, u32 event)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200346{
347 int ret = 0;
Amitkumar Karwar66fceb62010-05-19 03:24:38 -0700348 struct cmd_header cmd;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200349
Holger Schurig9556d212007-08-02 13:14:07 -0400350 lbs_deb_enter(LBS_DEB_CMD);
351
Holger Schurig7919b892008-04-01 14:50:43 +0200352 switch (event) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200353 case MACREG_INT_CODE_LINK_SENSED:
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100354 lbs_deb_cmd("EVENT: link sensed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200355 break;
356
357 case MACREG_INT_CODE_DEAUTHENTICATED:
Holger Schuriga6c87002007-08-02 11:54:10 -0400358 lbs_deb_cmd("EVENT: deauthenticated\n");
Holger Schurig10078322007-11-15 18:05:47 -0500359 lbs_mac_event_disconnected(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200360 break;
361
362 case MACREG_INT_CODE_DISASSOCIATED:
Holger Schuriga6c87002007-08-02 11:54:10 -0400363 lbs_deb_cmd("EVENT: disassociated\n");
Holger Schurig10078322007-11-15 18:05:47 -0500364 lbs_mac_event_disconnected(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200365 break;
366
Holger Schurig0b3c07f2007-11-28 09:15:11 +0100367 case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
Holger Schuriga6c87002007-08-02 11:54:10 -0400368 lbs_deb_cmd("EVENT: link lost\n");
Holger Schurig10078322007-11-15 18:05:47 -0500369 lbs_mac_event_disconnected(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200370 break;
371
372 case MACREG_INT_CODE_PS_SLEEP:
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100373 lbs_deb_cmd("EVENT: ps sleep\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200374
375 /* handle unexpected PS SLEEP event */
David Woodhouseaa21c002007-12-08 20:04:36 +0000376 if (priv->psstate == PS_STATE_FULL_POWER) {
Holger Schurig9012b282007-05-25 11:27:16 -0400377 lbs_deb_cmd(
Holger Schuriga6c87002007-08-02 11:54:10 -0400378 "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200379 break;
380 }
David Woodhouseaa21c002007-12-08 20:04:36 +0000381 priv->psstate = PS_STATE_PRE_SLEEP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200382
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100383 lbs_ps_confirm_sleep(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200384
385 break;
386
David Woodhouseb47ef242007-12-17 13:26:42 -0500387 case MACREG_INT_CODE_HOST_AWAKE:
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100388 lbs_deb_cmd("EVENT: host awake\n");
Amitkumar Karwar49125452009-09-30 20:04:38 -0700389 if (priv->reset_deep_sleep_wakeup)
390 priv->reset_deep_sleep_wakeup(priv);
391 priv->is_deep_sleep = 0;
Amitkumar Karwar66fceb62010-05-19 03:24:38 -0700392 lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
393 sizeof(cmd));
394 priv->is_host_sleep_activated = 0;
395 wake_up_interruptible(&priv->host_sleep_q);
David Woodhouseb47ef242007-12-17 13:26:42 -0500396 break;
397
Amitkumar Karwar49125452009-09-30 20:04:38 -0700398 case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
399 if (priv->reset_deep_sleep_wakeup)
400 priv->reset_deep_sleep_wakeup(priv);
401 lbs_deb_cmd("EVENT: ds awake\n");
402 priv->is_deep_sleep = 0;
403 priv->wakeup_dev_required = 0;
404 wake_up_interruptible(&priv->ds_awake_q);
405 break;
406
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200407 case MACREG_INT_CODE_PS_AWAKE:
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100408 lbs_deb_cmd("EVENT: ps awake\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200409 /* handle unexpected PS AWAKE event */
David Woodhouseaa21c002007-12-08 20:04:36 +0000410 if (priv->psstate == PS_STATE_FULL_POWER) {
Holger Schurig9012b282007-05-25 11:27:16 -0400411 lbs_deb_cmd(
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200412 "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
413 break;
414 }
415
David Woodhouseaa21c002007-12-08 20:04:36 +0000416 priv->psstate = PS_STATE_AWAKE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200417
David Woodhouseaa21c002007-12-08 20:04:36 +0000418 if (priv->needtowakeup) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200419 /*
420 * wait for the command processing to finish
421 * before resuming sending
David Woodhouseaa21c002007-12-08 20:04:36 +0000422 * priv->needtowakeup will be set to FALSE
Holger Schurig10078322007-11-15 18:05:47 -0500423 * in lbs_ps_wakeup()
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200424 */
Holger Schuriga6c87002007-08-02 11:54:10 -0400425 lbs_deb_cmd("waking up ...\n");
Holger Schurig10078322007-11-15 18:05:47 -0500426 lbs_ps_wakeup(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200427 }
428 break;
429
430 case MACREG_INT_CODE_MIC_ERR_UNICAST:
Holger Schurig9012b282007-05-25 11:27:16 -0400431 lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
Holger Schurig560c6332009-10-22 15:30:57 +0200432 lbs_send_mic_failureevent(priv, event);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200433 break;
434
435 case MACREG_INT_CODE_MIC_ERR_MULTICAST:
Holger Schurig9012b282007-05-25 11:27:16 -0400436 lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
Holger Schurig560c6332009-10-22 15:30:57 +0200437 lbs_send_mic_failureevent(priv, event);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200438 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200439
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100440 case MACREG_INT_CODE_MIB_CHANGED:
441 lbs_deb_cmd("EVENT: MIB CHANGED\n");
442 break;
443 case MACREG_INT_CODE_INIT_DONE:
444 lbs_deb_cmd("EVENT: INIT DONE\n");
445 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200446 case MACREG_INT_CODE_ADHOC_BCN_LOST:
Holger Schuriga6c87002007-08-02 11:54:10 -0400447 lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200448 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200449 case MACREG_INT_CODE_RSSI_LOW:
Holger Schuriga6c87002007-08-02 11:54:10 -0400450 lbs_pr_alert("EVENT: rssi low\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200451 break;
452 case MACREG_INT_CODE_SNR_LOW:
Holger Schuriga6c87002007-08-02 11:54:10 -0400453 lbs_pr_alert("EVENT: snr low\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200454 break;
455 case MACREG_INT_CODE_MAX_FAIL:
Holger Schuriga6c87002007-08-02 11:54:10 -0400456 lbs_pr_alert("EVENT: max fail\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200457 break;
458 case MACREG_INT_CODE_RSSI_HIGH:
Holger Schuriga6c87002007-08-02 11:54:10 -0400459 lbs_pr_alert("EVENT: rssi high\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200460 break;
461 case MACREG_INT_CODE_SNR_HIGH:
Holger Schuriga6c87002007-08-02 11:54:10 -0400462 lbs_pr_alert("EVENT: snr high\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200463 break;
464
Luis Carlos Cobo Rus7d8d28b2007-05-25 23:12:19 -0400465 case MACREG_INT_CODE_MESH_AUTO_STARTED:
Holger Schurigd6ede672009-12-02 15:25:57 +0100466 /* Ignore spurious autostart events */
467 lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
Luis Carlos Cobo Rus7d8d28b2007-05-25 23:12:19 -0400468 break;
469
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200470 default:
Holger Schurig7919b892008-04-01 14:50:43 +0200471 lbs_pr_alert("EVENT: unknown event id %d\n", event);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200472 break;
473 }
474
Holger Schurig9556d212007-08-02 13:14:07 -0400475 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200476 return ret;
477}