0001
0002
0003
0004
0005
0006
0007 #include <linux/hardirq.h>
0008 #include <linux/slab.h>
0009 #include <linux/delay.h>
0010 #include <linux/sched.h>
0011 #include <asm/unaligned.h>
0012 #include <net/cfg80211.h>
0013
0014 #include "cfg.h"
0015 #include "cmd.h"
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 void lbs_mac_event_disconnected(struct lbs_private *priv,
0029 bool locally_generated)
0030 {
0031 unsigned long flags;
0032
0033 if (priv->connect_status != LBS_CONNECTED)
0034 return;
0035
0036
0037
0038
0039
0040 msleep_interruptible(1000);
0041
0042 if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
0043 lbs_send_disconnect_notification(priv, locally_generated);
0044
0045
0046 netif_stop_queue(priv->dev);
0047 netif_carrier_off(priv->dev);
0048
0049
0050 spin_lock_irqsave(&priv->driver_lock, flags);
0051 kfree_skb(priv->currenttxskb);
0052 priv->currenttxskb = NULL;
0053 priv->tx_pending_len = 0;
0054 spin_unlock_irqrestore(&priv->driver_lock, flags);
0055
0056 priv->connect_status = LBS_DISCONNECTED;
0057
0058 if (priv->psstate != PS_STATE_FULL_POWER) {
0059
0060 lbs_deb_cmd("disconnected, so exit PS mode\n");
0061 lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
0062 }
0063 }
0064
0065 int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
0066 {
0067 uint16_t respcmd, curcmd;
0068 struct cmd_header *resp;
0069 int ret = 0;
0070 unsigned long flags;
0071 uint16_t result;
0072
0073 mutex_lock(&priv->lock);
0074 spin_lock_irqsave(&priv->driver_lock, flags);
0075
0076 if (!priv->cur_cmd) {
0077 lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
0078 ret = -1;
0079 spin_unlock_irqrestore(&priv->driver_lock, flags);
0080 goto done;
0081 }
0082
0083 resp = (void *)data;
0084 curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
0085 respcmd = le16_to_cpu(resp->command);
0086 result = le16_to_cpu(resp->result);
0087
0088 lbs_deb_cmd("CMD_RESP: response 0x%04x, seq %d, size %d\n",
0089 respcmd, le16_to_cpu(resp->seqnum), len);
0090 lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
0091
0092 if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
0093 netdev_info(priv->dev,
0094 "Received CMD_RESP with invalid sequence %d (expected %d)\n",
0095 le16_to_cpu(resp->seqnum),
0096 le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
0097 spin_unlock_irqrestore(&priv->driver_lock, flags);
0098 ret = -1;
0099 goto done;
0100 }
0101 if (respcmd != CMD_RET(curcmd) &&
0102 respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
0103 netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n",
0104 respcmd, curcmd);
0105 spin_unlock_irqrestore(&priv->driver_lock, flags);
0106 ret = -1;
0107 goto done;
0108 }
0109
0110 if (resp->result == cpu_to_le16(0x0004)) {
0111
0112
0113 netdev_info(priv->dev,
0114 "Firmware returns DEFER to command %x. Will let it time out...\n",
0115 le16_to_cpu(resp->command));
0116 spin_unlock_irqrestore(&priv->driver_lock, flags);
0117 ret = -1;
0118 goto done;
0119 }
0120
0121
0122 del_timer(&priv->command_timer);
0123 priv->cmd_timed_out = 0;
0124
0125 if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
0126
0127
0128
0129 struct cmd_ds_802_11_ps_mode *psmode = (void *)resp;
0130 u16 action = le16_to_cpu(psmode->action);
0131
0132 lbs_deb_host(
0133 "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
0134 result, action);
0135
0136 if (result) {
0137 lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
0138 result);
0139
0140
0141
0142
0143
0144 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR &&
0145 action == PS_MODE_ACTION_ENTER_PS)
0146 priv->psmode = LBS802_11POWERMODECAM;
0147 } else if (action == PS_MODE_ACTION_ENTER_PS) {
0148 priv->needtowakeup = 0;
0149 priv->psstate = PS_STATE_AWAKE;
0150
0151 lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
0152 if (priv->connect_status != LBS_CONNECTED) {
0153
0154
0155
0156
0157 lbs_deb_host(
0158 "disconnected, invoking lbs_ps_wakeup\n");
0159
0160 spin_unlock_irqrestore(&priv->driver_lock, flags);
0161 mutex_unlock(&priv->lock);
0162 lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS,
0163 false);
0164 mutex_lock(&priv->lock);
0165 spin_lock_irqsave(&priv->driver_lock, flags);
0166 }
0167 } else if (action == PS_MODE_ACTION_EXIT_PS) {
0168 priv->needtowakeup = 0;
0169 priv->psstate = PS_STATE_FULL_POWER;
0170 lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
0171 } else {
0172 lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
0173 }
0174
0175 __lbs_complete_command(priv, priv->cur_cmd, result);
0176 spin_unlock_irqrestore(&priv->driver_lock, flags);
0177
0178 ret = 0;
0179 goto done;
0180 }
0181
0182
0183 if ((result != 0 || !(respcmd & 0x8000))) {
0184 lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
0185 result, respcmd);
0186
0187
0188
0189 switch (respcmd) {
0190 case CMD_RET(CMD_GET_HW_SPEC):
0191 case CMD_RET(CMD_802_11_RESET):
0192 lbs_deb_host("CMD_RESP: reset failed\n");
0193 break;
0194
0195 }
0196 __lbs_complete_command(priv, priv->cur_cmd, result);
0197 spin_unlock_irqrestore(&priv->driver_lock, flags);
0198
0199 ret = -1;
0200 goto done;
0201 }
0202
0203 spin_unlock_irqrestore(&priv->driver_lock, flags);
0204
0205 if (priv->cur_cmd && priv->cur_cmd->callback) {
0206 ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
0207 resp);
0208 }
0209
0210 spin_lock_irqsave(&priv->driver_lock, flags);
0211
0212 if (priv->cur_cmd) {
0213
0214 __lbs_complete_command(priv, priv->cur_cmd, result);
0215 }
0216 spin_unlock_irqrestore(&priv->driver_lock, flags);
0217
0218 done:
0219 mutex_unlock(&priv->lock);
0220 return ret;
0221 }
0222
0223 void lbs_process_event(struct lbs_private *priv, u32 event)
0224 {
0225 struct cmd_header cmd;
0226
0227 switch (event) {
0228 case MACREG_INT_CODE_LINK_SENSED:
0229 lbs_deb_cmd("EVENT: link sensed\n");
0230 break;
0231
0232 case MACREG_INT_CODE_DEAUTHENTICATED:
0233 lbs_deb_cmd("EVENT: deauthenticated\n");
0234 lbs_mac_event_disconnected(priv, false);
0235 break;
0236
0237 case MACREG_INT_CODE_DISASSOCIATED:
0238 lbs_deb_cmd("EVENT: disassociated\n");
0239 lbs_mac_event_disconnected(priv, false);
0240 break;
0241
0242 case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
0243 lbs_deb_cmd("EVENT: link lost\n");
0244 lbs_mac_event_disconnected(priv, true);
0245 break;
0246
0247 case MACREG_INT_CODE_PS_SLEEP:
0248 lbs_deb_cmd("EVENT: ps sleep\n");
0249
0250
0251 if (priv->psstate == PS_STATE_FULL_POWER) {
0252 lbs_deb_cmd(
0253 "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n");
0254 break;
0255 }
0256 if (!list_empty(&priv->cmdpendingq)) {
0257 lbs_deb_cmd("EVENT: commands in queue, do not sleep\n");
0258 break;
0259 }
0260 priv->psstate = PS_STATE_PRE_SLEEP;
0261
0262 lbs_ps_confirm_sleep(priv);
0263
0264 break;
0265
0266 case MACREG_INT_CODE_HOST_AWAKE:
0267 lbs_deb_cmd("EVENT: host awake\n");
0268 if (priv->reset_deep_sleep_wakeup)
0269 priv->reset_deep_sleep_wakeup(priv);
0270 priv->is_deep_sleep = 0;
0271 lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
0272 sizeof(cmd));
0273 priv->is_host_sleep_activated = 0;
0274 wake_up_interruptible(&priv->host_sleep_q);
0275 break;
0276
0277 case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
0278 if (priv->reset_deep_sleep_wakeup)
0279 priv->reset_deep_sleep_wakeup(priv);
0280 lbs_deb_cmd("EVENT: ds awake\n");
0281 priv->is_deep_sleep = 0;
0282 priv->wakeup_dev_required = 0;
0283 wake_up_interruptible(&priv->ds_awake_q);
0284 break;
0285
0286 case MACREG_INT_CODE_PS_AWAKE:
0287 lbs_deb_cmd("EVENT: ps awake\n");
0288
0289 if (priv->psstate == PS_STATE_FULL_POWER) {
0290 lbs_deb_cmd(
0291 "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
0292 break;
0293 }
0294
0295 priv->psstate = PS_STATE_AWAKE;
0296
0297 if (priv->needtowakeup) {
0298
0299
0300
0301
0302
0303
0304 lbs_deb_cmd("waking up ...\n");
0305 lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, false);
0306 }
0307 break;
0308
0309 case MACREG_INT_CODE_MIC_ERR_UNICAST:
0310 lbs_deb_cmd("EVENT: UNICAST MIC ERROR\n");
0311 lbs_send_mic_failureevent(priv, event);
0312 break;
0313
0314 case MACREG_INT_CODE_MIC_ERR_MULTICAST:
0315 lbs_deb_cmd("EVENT: MULTICAST MIC ERROR\n");
0316 lbs_send_mic_failureevent(priv, event);
0317 break;
0318
0319 case MACREG_INT_CODE_MIB_CHANGED:
0320 lbs_deb_cmd("EVENT: MIB CHANGED\n");
0321 break;
0322 case MACREG_INT_CODE_INIT_DONE:
0323 lbs_deb_cmd("EVENT: INIT DONE\n");
0324 break;
0325 case MACREG_INT_CODE_ADHOC_BCN_LOST:
0326 lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
0327 break;
0328 case MACREG_INT_CODE_RSSI_LOW:
0329 netdev_alert(priv->dev, "EVENT: rssi low\n");
0330 break;
0331 case MACREG_INT_CODE_SNR_LOW:
0332 netdev_alert(priv->dev, "EVENT: snr low\n");
0333 break;
0334 case MACREG_INT_CODE_MAX_FAIL:
0335 netdev_alert(priv->dev, "EVENT: max fail\n");
0336 break;
0337 case MACREG_INT_CODE_RSSI_HIGH:
0338 netdev_alert(priv->dev, "EVENT: rssi high\n");
0339 break;
0340 case MACREG_INT_CODE_SNR_HIGH:
0341 netdev_alert(priv->dev, "EVENT: snr high\n");
0342 break;
0343
0344 case MACREG_INT_CODE_MESH_AUTO_STARTED:
0345
0346 netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n");
0347 break;
0348
0349 default:
0350 netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event);
0351 break;
0352 }
0353 }