blob: b4bc103d7970b51e921f9840c64ccb78f0f7b8c1 [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>
Cliff Cai2c5b9e512009-05-27 14:03:09 -04008#include <asm/unaligned.h>
Kiran Divekare86dc1c2010-06-14 22:01:26 +05309#include <net/cfg80211.h>
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020010
Kiran Divekare86dc1c2010-06-14 22:01:26 +053011#include "cfg.h"
Amitkumar Karwar66fceb62010-05-19 03:24:38 -070012#include "cmd.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020013
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 *
Holger Schurig69f90322007-11-23 15:43:44 +010019 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020020 * @return n/a
21 */
Holger Schurig69f90322007-11-23 15:43:44 +010022void lbs_mac_event_disconnected(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020023{
David Woodhouseaa21c002007-12-08 20:04:36 +000024 if (priv->connect_status != LBS_CONNECTED)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020025 return;
26
Holger Schurig91843462007-11-28 14:05:02 +010027 lbs_deb_enter(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020028
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020029 /*
30 * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
31 * It causes problem in the Supplicant
32 */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020033 msleep_interruptible(1000);
Kiran Divekare4fe4ea2010-06-04 23:20:37 -070034
35 if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
36 lbs_send_disconnect_notification(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020037
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020038 /* report disconnect to upper layer */
Holger Schurig634b8f42007-05-25 13:05:16 -040039 netif_stop_queue(priv->dev);
40 netif_carrier_off(priv->dev);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020041
David Woodhousea27b9f92007-12-12 00:41:51 -050042 /* Free Tx and Rx packets */
43 kfree_skb(priv->currenttxskb);
44 priv->currenttxskb = NULL;
45 priv->tx_pending_len = 0;
46
David Woodhouseaa21c002007-12-08 20:04:36 +000047 priv->connect_status = LBS_DISCONNECTED;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020048
David Woodhouseaa21c002007-12-08 20:04:36 +000049 if (priv->psstate != PS_STATE_FULL_POWER) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020050 /* make firmware to exit PS mode */
Holger Schuriga6c87002007-08-02 11:54:10 -040051 lbs_deb_cmd("disconnected, so exit PS mode\n");
Holger Schurig10078322007-11-15 18:05:47 -050052 lbs_ps_wakeup(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020053 }
Holger Schurig52507c22008-01-28 17:25:53 +010054 lbs_deb_leave(LBS_DEB_ASSOC);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020055}
56
Holger Schurig69f90322007-11-23 15:43:44 +010057static int lbs_ret_reg_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020058 u16 type, struct cmd_ds_command *resp)
59{
Holger Schurig9012b282007-05-25 11:27:16 -040060 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020061
Holger Schurig9012b282007-05-25 11:27:16 -040062 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020063
64 switch (type) {
Holger Schurig6b63cd02007-08-02 11:53:36 -040065 case CMD_RET(CMD_MAC_REG_ACCESS):
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020066 {
David Woodhouse981f1872007-05-25 23:36:54 -040067 struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020068
David Woodhouseaa21c002007-12-08 20:04:36 +000069 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
70 priv->offsetvalue.value = le32_to_cpu(reg->value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020071 break;
72 }
73
Holger Schurig6b63cd02007-08-02 11:53:36 -040074 case CMD_RET(CMD_BBP_REG_ACCESS):
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020075 {
David Woodhouse981f1872007-05-25 23:36:54 -040076 struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020077
David Woodhouseaa21c002007-12-08 20:04:36 +000078 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
79 priv->offsetvalue.value = reg->value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020080 break;
81 }
82
Holger Schurig6b63cd02007-08-02 11:53:36 -040083 case CMD_RET(CMD_RF_REG_ACCESS):
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020084 {
David Woodhouse981f1872007-05-25 23:36:54 -040085 struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020086
David Woodhouseaa21c002007-12-08 20:04:36 +000087 priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
88 priv->offsetvalue.value = reg->value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020089 break;
90 }
91
92 default:
Holger Schurig9012b282007-05-25 11:27:16 -040093 ret = -1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020094 }
95
Holger Schurig8b17d722007-10-08 11:09:30 +020096 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Holger Schurig9012b282007-05-25 11:27:16 -040097 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020098}
99
Kiran Divekar1047d5e2010-06-04 23:20:42 -0700100/**
101 * @brief This function parses countryinfo from AP and download country info to FW
102 * @param priv pointer to struct lbs_private
103 * @param resp pointer to command response buffer
104 * @return 0; -1
105 */
106int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
107{
108 struct cmd_ds_802_11d_domain_info *domaininfo =
109 &resp->params.domaininforesp;
110 struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
111 u16 action = le16_to_cpu(domaininfo->action);
112 s16 ret = 0;
113 u8 nr_triplet = 0;
114
115 lbs_deb_enter(LBS_DEB_11D);
116
117 lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
118 (int)le16_to_cpu(resp->size));
119
120 nr_triplet = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
121 sizeof(struct ieee80211_country_ie_triplet);
122
123 lbs_deb_11d("domain info resp: nr_triplet %d\n", nr_triplet);
124
125 if (nr_triplet > MRVDRV_MAX_TRIPLET_802_11D) {
126 lbs_deb_11d("invalid number of triplets returned!!\n");
127 return -1;
128 }
129
130 switch (action) {
131 case CMD_ACT_SET: /*Proc set action */
132 break;
133
134 case CMD_ACT_GET:
135 break;
136 default:
137 lbs_deb_11d("invalid action:%d\n", domaininfo->action);
138 ret = -1;
139 break;
140 }
141
142 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
143 return ret;
144}
145
David Woodhouse1309b552007-12-10 13:36:10 -0500146static inline int handle_cmd_response(struct lbs_private *priv,
Dan Williamsddac4522007-12-11 13:49:39 -0500147 struct cmd_header *cmd_response)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200148{
Dan Williamsddac4522007-12-11 13:49:39 -0500149 struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200150 int ret = 0;
151 unsigned long flags;
David Woodhouse1309b552007-12-10 13:36:10 -0500152 uint16_t respcmd = le16_to_cpu(resp->command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200153
Holger Schuriga6c87002007-08-02 11:54:10 -0400154 lbs_deb_enter(LBS_DEB_HOST);
155
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200156 switch (respcmd) {
Holger Schurig6b63cd02007-08-02 11:53:36 -0400157 case CMD_RET(CMD_MAC_REG_ACCESS):
158 case CMD_RET(CMD_BBP_REG_ACCESS):
159 case CMD_RET(CMD_RF_REG_ACCESS):
Holger Schurig10078322007-11-15 18:05:47 -0500160 ret = lbs_ret_reg_access(priv, respcmd, resp);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200161 break;
162
Holger Schurig6b63cd02007-08-02 11:53:36 -0400163 case CMD_RET(CMD_802_11_SET_AFC):
164 case CMD_RET(CMD_802_11_GET_AFC):
David Woodhouseaa21c002007-12-08 20:04:36 +0000165 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse75567672007-12-15 02:38:17 -0500166 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200167 sizeof(struct cmd_ds_802_11_afc));
David Woodhouseaa21c002007-12-08 20:04:36 +0000168 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200169
170 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200171
Holger Schurig6b63cd02007-08-02 11:53:36 -0400172 case CMD_RET(CMD_802_11_BEACON_STOP):
Dan Williams18c96c342007-06-18 12:01:12 -0400173 break;
174
Holger Schurig6b63cd02007-08-02 11:53:36 -0400175 case CMD_RET(CMD_802_11_RSSI):
Holger Schurig10078322007-11-15 18:05:47 -0500176 ret = lbs_ret_802_11_rssi(priv, resp);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200177 break;
178
Kiran Divekar1047d5e2010-06-04 23:20:42 -0700179 case CMD_RET(CMD_802_11D_DOMAIN_INFO):
180 ret = lbs_ret_802_11d_domain_info(resp);
181 break;
182
Holger Schurig6b63cd02007-08-02 11:53:36 -0400183 case CMD_RET(CMD_802_11_TPC_CFG):
David Woodhouseaa21c002007-12-08 20:04:36 +0000184 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse75567672007-12-15 02:38:17 -0500185 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200186 sizeof(struct cmd_ds_802_11_tpc_cfg));
David Woodhouseaa21c002007-12-08 20:04:36 +0000187 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200188 break;
Holger Schurig3a188642007-11-26 10:07:14 +0100189
Holger Schurig6b63cd02007-08-02 11:53:36 -0400190 case CMD_RET(CMD_BT_ACCESS):
David Woodhouseaa21c002007-12-08 20:04:36 +0000191 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse75567672007-12-15 02:38:17 -0500192 if (priv->cur_cmd->callback_arg)
193 memcpy((void *)priv->cur_cmd->callback_arg,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200194 &resp->params.bt.addr1, 2 * ETH_ALEN);
David Woodhouseaa21c002007-12-08 20:04:36 +0000195 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200196 break;
Holger Schurig6b63cd02007-08-02 11:53:36 -0400197 case CMD_RET(CMD_FWT_ACCESS):
David Woodhouseaa21c002007-12-08 20:04:36 +0000198 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse75567672007-12-15 02:38:17 -0500199 if (priv->cur_cmd->callback_arg)
200 memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
David Woodhouse981f1872007-05-25 23:36:54 -0400201 sizeof(resp->params.fwt));
David Woodhouseaa21c002007-12-08 20:04:36 +0000202 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200203 break;
Brajesh Dave96287ac2007-11-20 17:44:28 -0500204 case CMD_RET(CMD_802_11_BEACON_CTRL):
205 ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
206 break;
207
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200208 default:
David Woodhousee37fc6e2008-05-20 11:47:16 +0100209 lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
210 le16_to_cpu(resp->command));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200211 break;
212 }
Holger Schuriga6c87002007-08-02 11:54:10 -0400213 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200214 return ret;
215}
216
Holger Schurig7919b892008-04-01 14:50:43 +0200217int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200218{
David Woodhousee1258172007-12-11 23:42:49 -0500219 uint16_t respcmd, curcmd;
Dan Williamsddac4522007-12-11 13:49:39 -0500220 struct cmd_header *resp;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200221 int ret = 0;
David Woodhousee1258172007-12-11 23:42:49 -0500222 unsigned long flags;
223 uint16_t result;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200224
Holger Schuriga6c87002007-08-02 11:54:10 -0400225 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200226
David Woodhouseaa21c002007-12-08 20:04:36 +0000227 mutex_lock(&priv->lock);
228 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200229
David Woodhouseaa21c002007-12-08 20:04:36 +0000230 if (!priv->cur_cmd) {
Holger Schuriga6c87002007-08-02 11:54:10 -0400231 lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200232 ret = -1;
David Woodhouseaa21c002007-12-08 20:04:36 +0000233 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200234 goto done;
235 }
David Woodhousee1258172007-12-11 23:42:49 -0500236
Holger Schurig7919b892008-04-01 14:50:43 +0200237 resp = (void *)data;
Sebastian Siewior8a96df82008-03-04 18:22:27 +0100238 curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200239 respcmd = le16_to_cpu(resp->command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200240 result = le16_to_cpu(resp->result);
241
Holger Schurige5225b32008-03-26 10:04:44 +0100242 lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
Holger Schurig7919b892008-04-01 14:50:43 +0200243 respcmd, le16_to_cpu(resp->seqnum), len);
244 lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200245
David Woodhouse6305f492008-03-03 12:20:12 +0100246 if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
David Woodhousee1258172007-12-11 23:42:49 -0500247 lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
David Woodhouse6305f492008-03-03 12:20:12 +0100248 le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
David Woodhouseaa21c002007-12-08 20:04:36 +0000249 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200250 ret = -1;
251 goto done;
252 }
David Woodhousee1258172007-12-11 23:42:49 -0500253 if (respcmd != CMD_RET(curcmd) &&
Sebastian Siewior5f0547c2008-03-06 10:30:21 +0100254 respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
David Woodhousee1258172007-12-11 23:42:49 -0500255 lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
256 spin_unlock_irqrestore(&priv->driver_lock, flags);
257 ret = -1;
258 goto done;
259 }
260
David Woodhouse85388232007-12-17 15:41:30 -0500261 if (resp->result == cpu_to_le16(0x0004)) {
262 /* 0x0004 means -EAGAIN. Drop the response, let it time out
263 and be resubmitted */
264 lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
265 le16_to_cpu(resp->command));
266 spin_unlock_irqrestore(&priv->driver_lock, flags);
267 ret = -1;
268 goto done;
269 }
270
David Woodhousee1258172007-12-11 23:42:49 -0500271 /* Now we got response from FW, cancel the command timer */
272 del_timer(&priv->command_timer);
David Woodhouse2a345092007-12-15 19:33:43 -0500273 priv->cmd_timed_out = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200274
275 /* Store the response code to cur_cmd_retcode. */
David Woodhouseaa21c002007-12-08 20:04:36 +0000276 priv->cur_cmd_retcode = result;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200277
Holger Schurig6b63cd02007-08-02 11:53:36 -0400278 if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
David Woodhouse38bfab12007-12-16 23:26:54 -0500279 struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
David Woodhouse981f1872007-05-25 23:36:54 -0400280 u16 action = le16_to_cpu(psmode->action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200281
Holger Schuriga6c87002007-08-02 11:54:10 -0400282 lbs_deb_host(
283 "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
David Woodhouse981f1872007-05-25 23:36:54 -0400284 result, action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200285
286 if (result) {
Holger Schuriga6c87002007-08-02 11:54:10 -0400287 lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
David Woodhouse981f1872007-05-25 23:36:54 -0400288 result);
289 /*
290 * We should not re-try enter-ps command in
291 * ad-hoc mode. It takes place in
Holger Schurig10078322007-11-15 18:05:47 -0500292 * lbs_execute_next_command().
David Woodhouse981f1872007-05-25 23:36:54 -0400293 */
Kiran Divekare86dc1c2010-06-14 22:01:26 +0530294 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
Dan Williams0aef64d2007-08-02 11:31:18 -0400295 action == CMD_SUBCMD_ENTER_PS)
David Woodhouseaa21c002007-12-08 20:04:36 +0000296 priv->psmode = LBS802_11POWERMODECAM;
Dan Williams0aef64d2007-08-02 11:31:18 -0400297 } else if (action == CMD_SUBCMD_ENTER_PS) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000298 priv->needtowakeup = 0;
299 priv->psstate = PS_STATE_AWAKE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200300
Holger Schuriga6c87002007-08-02 11:54:10 -0400301 lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
David Woodhouseaa21c002007-12-08 20:04:36 +0000302 if (priv->connect_status != LBS_CONNECTED) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200303 /*
304 * When Deauth Event received before Enter_PS command
305 * response, We need to wake up the firmware.
306 */
Holger Schuriga6c87002007-08-02 11:54:10 -0400307 lbs_deb_host(
Holger Schurig10078322007-11-15 18:05:47 -0500308 "disconnected, invoking lbs_ps_wakeup\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200309
David Woodhouseaa21c002007-12-08 20:04:36 +0000310 spin_unlock_irqrestore(&priv->driver_lock, flags);
311 mutex_unlock(&priv->lock);
Holger Schurig10078322007-11-15 18:05:47 -0500312 lbs_ps_wakeup(priv, 0);
David Woodhouseaa21c002007-12-08 20:04:36 +0000313 mutex_lock(&priv->lock);
314 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200315 }
Dan Williams0aef64d2007-08-02 11:31:18 -0400316 } else if (action == CMD_SUBCMD_EXIT_PS) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000317 priv->needtowakeup = 0;
318 priv->psstate = PS_STATE_FULL_POWER;
Holger Schuriga6c87002007-08-02 11:54:10 -0400319 lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200320 } else {
Holger Schuriga6c87002007-08-02 11:54:10 -0400321 lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200322 }
323
David Woodhouse183aeac2007-12-15 01:52:54 -0500324 lbs_complete_command(priv, priv->cur_cmd, result);
David Woodhouseaa21c002007-12-08 20:04:36 +0000325 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200326
327 ret = 0;
328 goto done;
329 }
330
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200331 /* If the command is not successful, cleanup and return failure */
332 if ((result != 0 || !(respcmd & 0x8000))) {
Holger Schuriga6c87002007-08-02 11:54:10 -0400333 lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
334 result, respcmd);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200335 /*
336 * Handling errors here
337 */
338 switch (respcmd) {
Holger Schurig6b63cd02007-08-02 11:53:36 -0400339 case CMD_RET(CMD_GET_HW_SPEC):
340 case CMD_RET(CMD_802_11_RESET):
Holger Schuriga6c87002007-08-02 11:54:10 -0400341 lbs_deb_host("CMD_RESP: reset failed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200342 break;
343
344 }
David Woodhouse183aeac2007-12-15 01:52:54 -0500345 lbs_complete_command(priv, priv->cur_cmd, result);
David Woodhouseaa21c002007-12-08 20:04:36 +0000346 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200347
348 ret = -1;
349 goto done;
350 }
351
David Woodhouseaa21c002007-12-08 20:04:36 +0000352 spin_unlock_irqrestore(&priv->driver_lock, flags);
David Woodhouse17230472007-12-07 15:13:05 +0000353
Dan Williams7ad994d2007-12-11 12:33:30 -0500354 if (priv->cur_cmd && priv->cur_cmd->callback) {
355 ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
Dan Williamsddac4522007-12-11 13:49:39 -0500356 resp);
Dan Williams7ad994d2007-12-11 12:33:30 -0500357 } else
Holger Schurige98a88d2008-03-19 14:25:58 +0100358 ret = handle_cmd_response(priv, resp);
David Woodhouse17230472007-12-07 15:13:05 +0000359
David Woodhouseaa21c002007-12-08 20:04:36 +0000360 spin_lock_irqsave(&priv->driver_lock, flags);
David Woodhouse17230472007-12-07 15:13:05 +0000361
David Woodhouseaa21c002007-12-08 20:04:36 +0000362 if (priv->cur_cmd) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200363 /* Clean up and Put current command back to cmdfreeq */
David Woodhouse183aeac2007-12-15 01:52:54 -0500364 lbs_complete_command(priv, priv->cur_cmd, result);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200365 }
David Woodhouseaa21c002007-12-08 20:04:36 +0000366 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200367
368done:
David Woodhouseaa21c002007-12-08 20:04:36 +0000369 mutex_unlock(&priv->lock);
Holger Schuriga6c87002007-08-02 11:54:10 -0400370 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200371 return ret;
372}
373
Holger Schurig7919b892008-04-01 14:50:43 +0200374int lbs_process_event(struct lbs_private *priv, u32 event)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200375{
376 int ret = 0;
Amitkumar Karwar66fceb62010-05-19 03:24:38 -0700377 struct cmd_header cmd;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200378
Holger Schurig9556d212007-08-02 13:14:07 -0400379 lbs_deb_enter(LBS_DEB_CMD);
380
Holger Schurig7919b892008-04-01 14:50:43 +0200381 switch (event) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200382 case MACREG_INT_CODE_LINK_SENSED:
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100383 lbs_deb_cmd("EVENT: link sensed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200384 break;
385
386 case MACREG_INT_CODE_DEAUTHENTICATED:
Holger Schuriga6c87002007-08-02 11:54:10 -0400387 lbs_deb_cmd("EVENT: deauthenticated\n");
Holger Schurig10078322007-11-15 18:05:47 -0500388 lbs_mac_event_disconnected(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200389 break;
390
391 case MACREG_INT_CODE_DISASSOCIATED:
Holger Schuriga6c87002007-08-02 11:54:10 -0400392 lbs_deb_cmd("EVENT: disassociated\n");
Holger Schurig10078322007-11-15 18:05:47 -0500393 lbs_mac_event_disconnected(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200394 break;
395
Holger Schurig0b3c07f2007-11-28 09:15:11 +0100396 case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
Holger Schuriga6c87002007-08-02 11:54:10 -0400397 lbs_deb_cmd("EVENT: link lost\n");
Holger Schurig10078322007-11-15 18:05:47 -0500398 lbs_mac_event_disconnected(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200399 break;
400
401 case MACREG_INT_CODE_PS_SLEEP:
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100402 lbs_deb_cmd("EVENT: ps sleep\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200403
404 /* handle unexpected PS SLEEP event */
David Woodhouseaa21c002007-12-08 20:04:36 +0000405 if (priv->psstate == PS_STATE_FULL_POWER) {
Holger Schurig9012b282007-05-25 11:27:16 -0400406 lbs_deb_cmd(
Holger Schuriga6c87002007-08-02 11:54:10 -0400407 "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200408 break;
409 }
David Woodhouseaa21c002007-12-08 20:04:36 +0000410 priv->psstate = PS_STATE_PRE_SLEEP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200411
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100412 lbs_ps_confirm_sleep(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200413
414 break;
415
David Woodhouseb47ef242007-12-17 13:26:42 -0500416 case MACREG_INT_CODE_HOST_AWAKE:
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100417 lbs_deb_cmd("EVENT: host awake\n");
Amitkumar Karwar49125452009-09-30 20:04:38 -0700418 if (priv->reset_deep_sleep_wakeup)
419 priv->reset_deep_sleep_wakeup(priv);
420 priv->is_deep_sleep = 0;
Amitkumar Karwar66fceb62010-05-19 03:24:38 -0700421 lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
422 sizeof(cmd));
423 priv->is_host_sleep_activated = 0;
424 wake_up_interruptible(&priv->host_sleep_q);
David Woodhouseb47ef242007-12-17 13:26:42 -0500425 break;
426
Amitkumar Karwar49125452009-09-30 20:04:38 -0700427 case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
428 if (priv->reset_deep_sleep_wakeup)
429 priv->reset_deep_sleep_wakeup(priv);
430 lbs_deb_cmd("EVENT: ds awake\n");
431 priv->is_deep_sleep = 0;
432 priv->wakeup_dev_required = 0;
433 wake_up_interruptible(&priv->ds_awake_q);
434 break;
435
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200436 case MACREG_INT_CODE_PS_AWAKE:
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100437 lbs_deb_cmd("EVENT: ps awake\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200438 /* handle unexpected PS AWAKE event */
David Woodhouseaa21c002007-12-08 20:04:36 +0000439 if (priv->psstate == PS_STATE_FULL_POWER) {
Holger Schurig9012b282007-05-25 11:27:16 -0400440 lbs_deb_cmd(
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200441 "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
442 break;
443 }
444
David Woodhouseaa21c002007-12-08 20:04:36 +0000445 priv->psstate = PS_STATE_AWAKE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200446
David Woodhouseaa21c002007-12-08 20:04:36 +0000447 if (priv->needtowakeup) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200448 /*
449 * wait for the command processing to finish
450 * before resuming sending
David Woodhouseaa21c002007-12-08 20:04:36 +0000451 * priv->needtowakeup will be set to FALSE
Holger Schurig10078322007-11-15 18:05:47 -0500452 * in lbs_ps_wakeup()
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200453 */
Holger Schuriga6c87002007-08-02 11:54:10 -0400454 lbs_deb_cmd("waking up ...\n");
Holger Schurig10078322007-11-15 18:05:47 -0500455 lbs_ps_wakeup(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200456 }
457 break;
458
459 case MACREG_INT_CODE_MIC_ERR_UNICAST:
Holger Schurig9012b282007-05-25 11:27:16 -0400460 lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
Holger Schurig560c6332009-10-22 15:30:57 +0200461 lbs_send_mic_failureevent(priv, event);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200462 break;
463
464 case MACREG_INT_CODE_MIC_ERR_MULTICAST:
Holger Schurig9012b282007-05-25 11:27:16 -0400465 lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
Holger Schurig560c6332009-10-22 15:30:57 +0200466 lbs_send_mic_failureevent(priv, event);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200467 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200468
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100469 case MACREG_INT_CODE_MIB_CHANGED:
470 lbs_deb_cmd("EVENT: MIB CHANGED\n");
471 break;
472 case MACREG_INT_CODE_INIT_DONE:
473 lbs_deb_cmd("EVENT: INIT DONE\n");
474 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200475 case MACREG_INT_CODE_ADHOC_BCN_LOST:
Holger Schuriga6c87002007-08-02 11:54:10 -0400476 lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200477 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200478 case MACREG_INT_CODE_RSSI_LOW:
Holger Schuriga6c87002007-08-02 11:54:10 -0400479 lbs_pr_alert("EVENT: rssi low\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200480 break;
481 case MACREG_INT_CODE_SNR_LOW:
Holger Schuriga6c87002007-08-02 11:54:10 -0400482 lbs_pr_alert("EVENT: snr low\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200483 break;
484 case MACREG_INT_CODE_MAX_FAIL:
Holger Schuriga6c87002007-08-02 11:54:10 -0400485 lbs_pr_alert("EVENT: max fail\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200486 break;
487 case MACREG_INT_CODE_RSSI_HIGH:
Holger Schuriga6c87002007-08-02 11:54:10 -0400488 lbs_pr_alert("EVENT: rssi high\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200489 break;
490 case MACREG_INT_CODE_SNR_HIGH:
Holger Schuriga6c87002007-08-02 11:54:10 -0400491 lbs_pr_alert("EVENT: snr high\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200492 break;
493
Luis Carlos Cobo Rus7d8d28b2007-05-25 23:12:19 -0400494 case MACREG_INT_CODE_MESH_AUTO_STARTED:
Holger Schurigd6ede672009-12-02 15:25:57 +0100495 /* Ignore spurious autostart events */
496 lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
Luis Carlos Cobo Rus7d8d28b2007-05-25 23:12:19 -0400497 break;
498
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200499 default:
Holger Schurig7919b892008-04-01 14:50:43 +0200500 lbs_pr_alert("EVENT: unknown event id %d\n", event);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200501 break;
502 }
503
Holger Schurig9556d212007-08-02 13:14:07 -0400504 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200505 return ret;
506}