blob: 2efba5708041dea0eae043feb23c643bffc995c2 [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/**
2 * This file contains the handling of command.
3 * It prepares command and sends it to firmware when it is ready.
4 */
5
6#include <net/iw_handler.h>
7#include "host.h"
8#include "hostcmd.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02009#include "decl.h"
10#include "defs.h"
11#include "dev.h"
12#include "join.h"
13#include "wext.h"
14
15static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
Holger Schurig0d61d042007-12-05 17:58:06 +010016struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
17void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
18 struct cmd_ctrl_node *ptempnode,
19 u16 wait_option, void *pdata_buf);
20
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020021
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020022/**
Dan Williams852e1f22007-12-10 15:24:47 -050023 * @brief Checks whether a command is allowed in Power Save mode
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020024 *
25 * @param command the command ID
Dan Williams852e1f22007-12-10 15:24:47 -050026 * @return 1 if allowed, 0 if not allowed
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020027 */
Dan Williams852e1f22007-12-10 15:24:47 -050028static u8 is_command_allowed_in_ps(u16 cmd)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020029{
Dan Williams852e1f22007-12-10 15:24:47 -050030 switch (cmd) {
31 case CMD_802_11_RSSI:
32 return 1;
33 default:
34 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020035 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020036 return 0;
37}
38
Holger Schurig69f90322007-11-23 15:43:44 +010039static int lbs_cmd_hw_spec(struct lbs_private *priv, struct cmd_ds_command *cmd)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020040{
41 struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
42
Holger Schurig9012b282007-05-25 11:27:16 -040043 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020044
Dan Williams0aef64d2007-08-02 11:31:18 -040045 cmd->command = cpu_to_le16(CMD_GET_HW_SPEC);
David Woodhouse981f1872007-05-25 23:36:54 -040046 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
David Woodhouseaa21c002007-12-08 20:04:36 +000047 memcpy(hwspec->permanentaddr, priv->current_addr, ETH_ALEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020048
Holger Schurig9012b282007-05-25 11:27:16 -040049 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020050 return 0;
51}
52
Holger Schurig69f90322007-11-23 15:43:44 +010053static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020054 struct cmd_ds_command *cmd,
55 u16 cmd_action)
56{
57 struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020058
Holger Schurig9012b282007-05-25 11:27:16 -040059 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020060
Dan Williams0aef64d2007-08-02 11:31:18 -040061 cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
David Woodhouse981f1872007-05-25 23:36:54 -040062 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
63 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020064 psm->action = cpu_to_le16(cmd_action);
65 psm->multipledtim = 0;
David Woodhouse981f1872007-05-25 23:36:54 -040066 switch (cmd_action) {
Dan Williams0aef64d2007-08-02 11:31:18 -040067 case CMD_SUBCMD_ENTER_PS:
Holger Schurig9012b282007-05-25 11:27:16 -040068 lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020069
Holger Schurig252cf0d2007-08-02 13:09:34 -040070 psm->locallisteninterval = 0;
Holger Schurig97605c32007-08-02 13:09:15 -040071 psm->nullpktinterval = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020072 psm->multipledtim =
Holger Schurig56c46562007-08-02 13:09:49 -040073 cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020074 break;
75
Dan Williams0aef64d2007-08-02 11:31:18 -040076 case CMD_SUBCMD_EXIT_PS:
Holger Schurig9012b282007-05-25 11:27:16 -040077 lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020078 break;
79
Dan Williams0aef64d2007-08-02 11:31:18 -040080 case CMD_SUBCMD_SLEEP_CONFIRMED:
Holger Schurig9012b282007-05-25 11:27:16 -040081 lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020082 break;
83
84 default:
85 break;
86 }
87
Holger Schurig9012b282007-05-25 11:27:16 -040088 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020089 return 0;
90}
91
Holger Schurig69f90322007-11-23 15:43:44 +010092static int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020093 struct cmd_ds_command *cmd,
94 u16 cmd_action, void *pdata_buf)
95{
96 u16 *timeout = pdata_buf;
97
Holger Schurig8ff12da2007-08-02 11:54:31 -040098 lbs_deb_enter(LBS_DEB_CMD);
99
Dan Williams0aef64d2007-08-02 11:31:18 -0400100 cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200101 cmd->size =
102 cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
103 + S_DS_GEN);
104
105 cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
106
107 if (cmd_action)
David Woodhouse981f1872007-05-25 23:36:54 -0400108 cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200109 else
110 cmd->params.inactivity_timeout.timeout = 0;
111
Holger Schurig8ff12da2007-08-02 11:54:31 -0400112 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200113 return 0;
114}
115
Holger Schurig69f90322007-11-23 15:43:44 +0100116static int lbs_cmd_802_11_sleep_params(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200117 struct cmd_ds_command *cmd,
118 u16 cmd_action)
119{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200120 struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
121
Holger Schurig9012b282007-05-25 11:27:16 -0400122 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200123
David Woodhouse981f1872007-05-25 23:36:54 -0400124 cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
125 S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400126 cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200127
Dan Williams0aef64d2007-08-02 11:31:18 -0400128 if (cmd_action == CMD_ACT_GET) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000129 memset(&priv->sp, 0, sizeof(struct sleep_params));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200130 memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
131 sp->action = cpu_to_le16(cmd_action);
Dan Williams0aef64d2007-08-02 11:31:18 -0400132 } else if (cmd_action == CMD_ACT_SET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200133 sp->action = cpu_to_le16(cmd_action);
David Woodhouseaa21c002007-12-08 20:04:36 +0000134 sp->error = cpu_to_le16(priv->sp.sp_error);
135 sp->offset = cpu_to_le16(priv->sp.sp_offset);
136 sp->stabletime = cpu_to_le16(priv->sp.sp_stabletime);
137 sp->calcontrol = (u8) priv->sp.sp_calcontrol;
138 sp->externalsleepclk = (u8) priv->sp.sp_extsleepclk;
139 sp->reserved = cpu_to_le16(priv->sp.sp_reserved);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200140 }
141
Holger Schurig9012b282007-05-25 11:27:16 -0400142 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200143 return 0;
144}
145
Holger Schurig69f90322007-11-23 15:43:44 +0100146static int lbs_cmd_802_11_set_wep(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200147 struct cmd_ds_command *cmd,
148 u32 cmd_act,
149 void * pdata_buf)
150{
151 struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200152 int ret = 0;
153 struct assoc_request * assoc_req = pdata_buf;
154
Holger Schurig9012b282007-05-25 11:27:16 -0400155 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200156
Dan Williams0aef64d2007-08-02 11:31:18 -0400157 cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
David Woodhouse981f1872007-05-25 23:36:54 -0400158 cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200159
Dan Williams0aef64d2007-08-02 11:31:18 -0400160 if (cmd_act == CMD_ACT_ADD) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200161 int i;
162
163 if (!assoc_req) {
Holger Schurig9012b282007-05-25 11:27:16 -0400164 lbs_deb_cmd("Invalid association request!");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200165 ret = -1;
166 goto done;
167 }
168
Dan Williams0aef64d2007-08-02 11:31:18 -0400169 wep->action = cpu_to_le16(CMD_ACT_ADD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200170
171 /* default tx key index */
David Woodhouse981f1872007-05-25 23:36:54 -0400172 wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
Dan Williams0aef64d2007-08-02 11:31:18 -0400173 (u32)CMD_WEP_KEY_INDEX_MASK));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200174
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200175 /* Copy key types and material to host command structure */
176 for (i = 0; i < 4; i++) {
Dan Williams1443b652007-08-02 10:45:55 -0400177 struct enc_key * pkey = &assoc_req->wep_keys[i];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200178
179 switch (pkey->len) {
180 case KEY_LEN_WEP_40:
Holger Schurig6470a892007-10-08 11:07:27 +0200181 wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200182 memmove(&wep->keymaterial[i], pkey->key,
183 pkey->len);
Holger Schurig8ff12da2007-08-02 11:54:31 -0400184 lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200185 break;
186 case KEY_LEN_WEP_104:
Holger Schurig6470a892007-10-08 11:07:27 +0200187 wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200188 memmove(&wep->keymaterial[i], pkey->key,
189 pkey->len);
Holger Schurig8ff12da2007-08-02 11:54:31 -0400190 lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200191 break;
192 case 0:
193 break;
194 default:
Holger Schurig8ff12da2007-08-02 11:54:31 -0400195 lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200196 i, pkey->len);
197 ret = -1;
198 goto done;
199 break;
200 }
201 }
Dan Williams0aef64d2007-08-02 11:31:18 -0400202 } else if (cmd_act == CMD_ACT_REMOVE) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200203 /* ACT_REMOVE clears _all_ WEP keys */
Dan Williams0aef64d2007-08-02 11:31:18 -0400204 wep->action = cpu_to_le16(CMD_ACT_REMOVE);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200205
206 /* default tx key index */
David Woodhouseaa21c002007-12-08 20:04:36 +0000207 wep->keyindex = cpu_to_le16((u16)(priv->wep_tx_keyidx &
Dan Williams0aef64d2007-08-02 11:31:18 -0400208 (u32)CMD_WEP_KEY_INDEX_MASK));
David Woodhouseaa21c002007-12-08 20:04:36 +0000209 lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200210 }
211
212 ret = 0;
213
214done:
Holger Schurig9012b282007-05-25 11:27:16 -0400215 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200216 return ret;
217}
218
Holger Schurig69f90322007-11-23 15:43:44 +0100219static int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200220 struct cmd_ds_command *cmd,
Dan Williams90a42212007-05-25 23:01:24 -0400221 u16 cmd_action,
222 void * pdata_buf)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200223{
224 struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
Dan Williams18c96c342007-06-18 12:01:12 -0400225 u32 * enable = pdata_buf;
Dan Williams90a42212007-05-25 23:01:24 -0400226
227 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200228
Dan Williams0aef64d2007-08-02 11:31:18 -0400229 cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
David Woodhouse981f1872007-05-25 23:36:54 -0400230 cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200231 penableRSN->action = cpu_to_le16(cmd_action);
Dan Williams18c96c342007-06-18 12:01:12 -0400232
Dan Williams0aef64d2007-08-02 11:31:18 -0400233 if (cmd_action == CMD_ACT_SET) {
Dan Williams18c96c342007-06-18 12:01:12 -0400234 if (*enable)
Dan Williams0aef64d2007-08-02 11:31:18 -0400235 penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
Dan Williams18c96c342007-06-18 12:01:12 -0400236 else
Dan Williams0aef64d2007-08-02 11:31:18 -0400237 penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
Holger Schurig8ff12da2007-08-02 11:54:31 -0400238 lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200239 }
240
Dan Williams90a42212007-05-25 23:01:24 -0400241 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200242 return 0;
243}
244
245
Holger Schurig3a188642007-11-26 10:07:14 +0100246static ssize_t lbs_tlv_size(const u8 *tlv, u16 size)
247{
248 ssize_t pos = 0;
249 struct mrvlietypesheader *tlv_h;
250 while (pos < size) {
251 u16 length;
252 tlv_h = (struct mrvlietypesheader *) tlv;
253 if (tlv_h->len == 0)
254 return pos;
255 length = le16_to_cpu(tlv_h->len) +
256 sizeof(struct mrvlietypesheader);
257 pos += length;
258 tlv += length;
259 }
260 return pos;
261}
262
263
264static void lbs_cmd_802_11_subscribe_event(struct lbs_private *priv,
265 struct cmd_ds_command *cmd, u16 cmd_action,
266 void *pdata_buf)
267{
268 struct cmd_ds_802_11_subscribe_event *events =
269 (struct cmd_ds_802_11_subscribe_event *) pdata_buf;
270
271 /* pdata_buf points to a struct cmd_ds_802_11_subscribe_event and room
272 * for various Marvell TLVs */
273
274 lbs_deb_enter(LBS_DEB_CMD);
275
276 cmd->size = cpu_to_le16(sizeof(*events)
277 - sizeof(events->tlv)
278 + S_DS_GEN);
279 cmd->params.subscribe_event.action = cpu_to_le16(cmd_action);
280 if (cmd_action == CMD_ACT_GET) {
281 cmd->params.subscribe_event.events = 0;
282 } else {
283 ssize_t sz = lbs_tlv_size(events->tlv, sizeof(events->tlv));
284 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + sz);
285 cmd->params.subscribe_event.events = events->events;
286 memcpy(cmd->params.subscribe_event.tlv, events->tlv, sz);
287 }
288
289 lbs_deb_leave(LBS_DEB_CMD);
290}
291
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200292static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
Dan Williams1443b652007-08-02 10:45:55 -0400293 struct enc_key * pkey)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200294{
Holger Schurig8ff12da2007-08-02 11:54:31 -0400295 lbs_deb_enter(LBS_DEB_CMD);
296
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200297 if (pkey->flags & KEY_INFO_WPA_ENABLED) {
Dan Williams90a42212007-05-25 23:01:24 -0400298 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200299 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200300 if (pkey->flags & KEY_INFO_WPA_UNICAST) {
301 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
Dan Williams90a42212007-05-25 23:01:24 -0400302 }
303 if (pkey->flags & KEY_INFO_WPA_MCAST) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200304 pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
305 }
306
307 pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
Dan Williams1443b652007-08-02 10:45:55 -0400308 pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200309 pkeyparamset->keylen = cpu_to_le16(pkey->len);
310 memcpy(pkeyparamset->key, pkey->key, pkey->len);
311 pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
312 + sizeof(pkeyparamset->keyinfo)
313 + sizeof(pkeyparamset->keylen)
314 + sizeof(pkeyparamset->key));
Holger Schurig8ff12da2007-08-02 11:54:31 -0400315 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200316}
317
Holger Schurig69f90322007-11-23 15:43:44 +0100318static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200319 struct cmd_ds_command *cmd,
320 u16 cmd_action,
321 u32 cmd_oid, void *pdata_buf)
322{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200323 struct cmd_ds_802_11_key_material *pkeymaterial =
324 &cmd->params.keymaterial;
Dan Williams90a42212007-05-25 23:01:24 -0400325 struct assoc_request * assoc_req = pdata_buf;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200326 int ret = 0;
327 int index = 0;
328
Holger Schurig9012b282007-05-25 11:27:16 -0400329 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200330
Dan Williams0aef64d2007-08-02 11:31:18 -0400331 cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200332 pkeymaterial->action = cpu_to_le16(cmd_action);
333
Dan Williams0aef64d2007-08-02 11:31:18 -0400334 if (cmd_action == CMD_ACT_GET) {
Dan Williams90a42212007-05-25 23:01:24 -0400335 cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200336 ret = 0;
337 goto done;
338 }
339
340 memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
341
Dan Williams90a42212007-05-25 23:01:24 -0400342 if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200343 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
Dan Williams90a42212007-05-25 23:01:24 -0400344 &assoc_req->wpa_unicast_key);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200345 index++;
346 }
347
Dan Williams90a42212007-05-25 23:01:24 -0400348 if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200349 set_one_wpa_key(&pkeymaterial->keyParamSet[index],
Dan Williams90a42212007-05-25 23:01:24 -0400350 &assoc_req->wpa_mcast_key);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200351 index++;
352 }
353
354 cmd->size = cpu_to_le16( S_DS_GEN
Dan Williams90a42212007-05-25 23:01:24 -0400355 + sizeof (pkeymaterial->action)
356 + (index * sizeof(struct MrvlIEtype_keyParamSet)));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200357
358 ret = 0;
359
360done:
Holger Schurig9012b282007-05-25 11:27:16 -0400361 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200362 return ret;
363}
364
Holger Schurig69f90322007-11-23 15:43:44 +0100365static int lbs_cmd_802_11_reset(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200366 struct cmd_ds_command *cmd, int cmd_action)
367{
368 struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
369
Holger Schurig8ff12da2007-08-02 11:54:31 -0400370 lbs_deb_enter(LBS_DEB_CMD);
371
Dan Williams0aef64d2007-08-02 11:31:18 -0400372 cmd->command = cpu_to_le16(CMD_802_11_RESET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200373 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
374 reset->action = cpu_to_le16(cmd_action);
375
Holger Schurig8ff12da2007-08-02 11:54:31 -0400376 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200377 return 0;
378}
379
Holger Schurig69f90322007-11-23 15:43:44 +0100380static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200381 struct cmd_ds_command *cmd)
382{
Holger Schurig8ff12da2007-08-02 11:54:31 -0400383 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400384 cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200385 cmd->size =
386 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
387
Holger Schurig8ff12da2007-08-02 11:54:31 -0400388 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200389 return 0;
390}
391
Holger Schurig69f90322007-11-23 15:43:44 +0100392static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200393 struct cmd_ds_command *cmd)
394{
Holger Schurig8ff12da2007-08-02 11:54:31 -0400395 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400396 cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200397 cmd->size =
David Woodhouse981f1872007-05-25 23:36:54 -0400398 cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200399
Holger Schurig8ff12da2007-08-02 11:54:31 -0400400 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200401 return 0;
402}
403
Holger Schurig69f90322007-11-23 15:43:44 +0100404static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200405 struct cmd_ds_command *cmd,
406 int cmd_action,
407 int cmd_oid, void *pdata_buf)
408{
409 struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200410 u8 ucTemp;
411
Holger Schurig9012b282007-05-25 11:27:16 -0400412 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200413
Holger Schurig9012b282007-05-25 11:27:16 -0400414 lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200415
Dan Williams0aef64d2007-08-02 11:31:18 -0400416 cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
David Woodhouse981f1872007-05-25 23:36:54 -0400417 cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200418
419 switch (cmd_oid) {
420 case OID_802_11_INFRASTRUCTURE_MODE:
421 {
Dan Williams0dc5a292007-05-10 22:58:02 -0400422 u8 mode = (u8) (size_t) pdata_buf;
Dan Williams0aef64d2007-08-02 11:31:18 -0400423 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
424 pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000425 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
Dan Williams0dc5a292007-05-10 22:58:02 -0400426 if (mode == IW_MODE_ADHOC) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200427 ucTemp = SNMP_MIB_VALUE_ADHOC;
Dan Williams0dc5a292007-05-10 22:58:02 -0400428 } else {
429 /* Infra and Auto modes */
430 ucTemp = SNMP_MIB_VALUE_INFRA;
431 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200432
433 memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
434
435 break;
436 }
437
438 case OID_802_11D_ENABLE:
439 {
440 u32 ulTemp;
441
Dan Williams0aef64d2007-08-02 11:31:18 -0400442 pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200443
Dan Williams0aef64d2007-08-02 11:31:18 -0400444 if (cmd_action == CMD_ACT_SET) {
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000445 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
446 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200447 ulTemp = *(u32 *)pdata_buf;
David Woodhouse981f1872007-05-25 23:36:54 -0400448 *((__le16 *)(pSNMPMIB->value)) =
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200449 cpu_to_le16((u16) ulTemp);
450 }
451 break;
452 }
453
454 case OID_802_11_FRAGMENTATION_THRESHOLD:
455 {
456 u32 ulTemp;
457
Dan Williams0aef64d2007-08-02 11:31:18 -0400458 pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200459
Dan Williams0aef64d2007-08-02 11:31:18 -0400460 if (cmd_action == CMD_ACT_GET) {
461 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
462 } else if (cmd_action == CMD_ACT_SET) {
463 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
David Woodhouse981f1872007-05-25 23:36:54 -0400464 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200465 ulTemp = *((u32 *) pdata_buf);
David Woodhouse981f1872007-05-25 23:36:54 -0400466 *((__le16 *)(pSNMPMIB->value)) =
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200467 cpu_to_le16((u16) ulTemp);
468
469 }
470
471 break;
472 }
473
474 case OID_802_11_RTS_THRESHOLD:
475 {
476
477 u32 ulTemp;
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000478 pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200479
Dan Williams0aef64d2007-08-02 11:31:18 -0400480 if (cmd_action == CMD_ACT_GET) {
481 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
482 } else if (cmd_action == CMD_ACT_SET) {
483 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
David Woodhouse981f1872007-05-25 23:36:54 -0400484 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
485 ulTemp = *((u32 *)pdata_buf);
486 *(__le16 *)(pSNMPMIB->value) =
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200487 cpu_to_le16((u16) ulTemp);
488
489 }
490 break;
491 }
492 case OID_802_11_TX_RETRYCOUNT:
Dan Williams0aef64d2007-08-02 11:31:18 -0400493 pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200494
Dan Williams0aef64d2007-08-02 11:31:18 -0400495 if (cmd_action == CMD_ACT_GET) {
496 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
497 } else if (cmd_action == CMD_ACT_SET) {
498 pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200499 pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
David Woodhouse981f1872007-05-25 23:36:54 -0400500 *((__le16 *)(pSNMPMIB->value)) =
David Woodhouseaa21c002007-12-08 20:04:36 +0000501 cpu_to_le16((u16) priv->txretrycount);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200502 }
503
504 break;
505 default:
506 break;
507 }
508
Holger Schurig9012b282007-05-25 11:27:16 -0400509 lbs_deb_cmd(
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200510 "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
David Woodhouse981f1872007-05-25 23:36:54 -0400511 le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
512 le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200513
Holger Schurig9012b282007-05-25 11:27:16 -0400514 lbs_deb_cmd(
Holger Schurig8ff12da2007-08-02 11:54:31 -0400515 "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
David Woodhouse981f1872007-05-25 23:36:54 -0400516 le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
517 le16_to_cpu(pSNMPMIB->bufsize),
518 le16_to_cpu(*(__le16 *) pSNMPMIB->value));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200519
Holger Schurig9012b282007-05-25 11:27:16 -0400520 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200521 return 0;
522}
523
Holger Schurig69f90322007-11-23 15:43:44 +0100524static int lbs_cmd_802_11_radio_control(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200525 struct cmd_ds_command *cmd,
526 int cmd_action)
527{
David Woodhouse981f1872007-05-25 23:36:54 -0400528 struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200529
Holger Schurig9012b282007-05-25 11:27:16 -0400530 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200531
532 cmd->size =
533 cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
534 S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400535 cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200536
537 pradiocontrol->action = cpu_to_le16(cmd_action);
538
David Woodhouseaa21c002007-12-08 20:04:36 +0000539 switch (priv->preamble) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400540 case CMD_TYPE_SHORT_PREAMBLE:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200541 pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
542 break;
543
Dan Williams0aef64d2007-08-02 11:31:18 -0400544 case CMD_TYPE_LONG_PREAMBLE:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200545 pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
546 break;
547
Dan Williams0aef64d2007-08-02 11:31:18 -0400548 case CMD_TYPE_AUTO_PREAMBLE:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200549 default:
550 pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
551 break;
552 }
553
David Woodhouseaa21c002007-12-08 20:04:36 +0000554 if (priv->radioon)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200555 pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
556 else
557 pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
558
Holger Schurig9012b282007-05-25 11:27:16 -0400559 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200560 return 0;
561}
562
Holger Schurig69f90322007-11-23 15:43:44 +0100563static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200564 struct cmd_ds_command *cmd,
565 u16 cmd_action, void *pdata_buf)
566{
567
568 struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
569
Holger Schurig9012b282007-05-25 11:27:16 -0400570 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200571
572 cmd->size =
David Woodhouse981f1872007-05-25 23:36:54 -0400573 cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400574 cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
David Woodhouse981f1872007-05-25 23:36:54 -0400575 prtp->action = cpu_to_le16(cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200576
David Woodhouse981f1872007-05-25 23:36:54 -0400577 lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
578 le16_to_cpu(cmd->size), le16_to_cpu(cmd->command),
579 le16_to_cpu(prtp->action));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200580
581 switch (cmd_action) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400582 case CMD_ACT_TX_POWER_OPT_GET:
583 prtp->action = cpu_to_le16(CMD_ACT_GET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200584 prtp->currentlevel = 0;
585 break;
586
Dan Williams0aef64d2007-08-02 11:31:18 -0400587 case CMD_ACT_TX_POWER_OPT_SET_HIGH:
588 prtp->action = cpu_to_le16(CMD_ACT_SET);
589 prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200590 break;
591
Dan Williams0aef64d2007-08-02 11:31:18 -0400592 case CMD_ACT_TX_POWER_OPT_SET_MID:
593 prtp->action = cpu_to_le16(CMD_ACT_SET);
594 prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200595 break;
596
Dan Williams0aef64d2007-08-02 11:31:18 -0400597 case CMD_ACT_TX_POWER_OPT_SET_LOW:
598 prtp->action = cpu_to_le16(CMD_ACT_SET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200599 prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
600 break;
601 }
Holger Schurig9012b282007-05-25 11:27:16 -0400602
603 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200604 return 0;
605}
606
Holger Schurig69f90322007-11-23 15:43:44 +0100607static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
Luis Carlos Cobo965f8bbc2007-08-02 13:16:55 -0400608 struct cmd_ds_command *cmd,
609 u16 cmd_action, void *pdata_buf)
610{
611 struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
612
613 cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
614 cmd->size =
615 cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
616 S_DS_GEN);
617
618 monitor->action = cpu_to_le16(cmd_action);
619 if (cmd_action == CMD_ACT_SET) {
620 monitor->mode =
621 cpu_to_le16((u16) (*(u32 *) pdata_buf));
622 }
623
624 return 0;
625}
626
Holger Schurig69f90322007-11-23 15:43:44 +0100627static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200628 struct cmd_ds_command *cmd,
629 u16 cmd_action)
630{
631 struct cmd_ds_802_11_rate_adapt_rateset
632 *rateadapt = &cmd->params.rateset;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200633
Holger Schurig8ff12da2007-08-02 11:54:31 -0400634 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200635 cmd->size =
636 cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
637 + S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400638 cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200639
David Woodhouse981f1872007-05-25 23:36:54 -0400640 rateadapt->action = cpu_to_le16(cmd_action);
David Woodhouseaa21c002007-12-08 20:04:36 +0000641 rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
642 rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200643
Holger Schurig9012b282007-05-25 11:27:16 -0400644 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200645 return 0;
646}
647
Holger Schurig69f90322007-11-23 15:43:44 +0100648static int lbs_cmd_802_11_data_rate(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200649 struct cmd_ds_command *cmd,
650 u16 cmd_action)
651{
652 struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200653
Holger Schurig9012b282007-05-25 11:27:16 -0400654 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200655
David Woodhouse981f1872007-05-25 23:36:54 -0400656 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200657 S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400658 cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200659 memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200660 pdatarate->action = cpu_to_le16(cmd_action);
661
Dan Williamsffcae952007-08-02 11:35:46 -0400662 if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000663 pdatarate->rates[0] = lbs_data_rate_to_fw_index(priv->cur_rate);
Holger Schurig8ff12da2007-08-02 11:54:31 -0400664 lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000665 priv->cur_rate);
Dan Williamsffcae952007-08-02 11:35:46 -0400666 } else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
Holger Schurig8ff12da2007-08-02 11:54:31 -0400667 lbs_deb_cmd("DATA_RATE: setting auto\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200668 }
669
Holger Schurig9012b282007-05-25 11:27:16 -0400670 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200671 return 0;
672}
673
Holger Schurig69f90322007-11-23 15:43:44 +0100674static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200675 struct cmd_ds_command *cmd,
676 u16 cmd_action)
677{
678 struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200679
Holger Schurig8ff12da2007-08-02 11:54:31 -0400680 lbs_deb_enter(LBS_DEB_CMD);
David Woodhouse981f1872007-05-25 23:36:54 -0400681 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200682 S_DS_GEN);
Dan Williams0aef64d2007-08-02 11:31:18 -0400683 cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200684
Holger Schurig8ff12da2007-08-02 11:54:31 -0400685 lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200686 pMCastAdr->action = cpu_to_le16(cmd_action);
687 pMCastAdr->nr_of_adrs =
David Woodhouseaa21c002007-12-08 20:04:36 +0000688 cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
689 memcpy(pMCastAdr->maclist, priv->multicastlist,
690 priv->nr_of_multicastmacaddr * ETH_ALEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200691
Holger Schurig8ff12da2007-08-02 11:54:31 -0400692 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200693 return 0;
694}
695
Holger Schurig69f90322007-11-23 15:43:44 +0100696static int lbs_cmd_802_11_rf_channel(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200697 struct cmd_ds_command *cmd,
698 int option, void *pdata_buf)
699{
700 struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
701
Holger Schurig8ff12da2007-08-02 11:54:31 -0400702 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400703 cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
David Woodhouse981f1872007-05-25 23:36:54 -0400704 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
705 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200706
Dan Williams0aef64d2007-08-02 11:31:18 -0400707 if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200708 rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
709 }
710
711 rfchan->action = cpu_to_le16(option);
712
Holger Schurig8ff12da2007-08-02 11:54:31 -0400713 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200714 return 0;
715}
716
Holger Schurig69f90322007-11-23 15:43:44 +0100717static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200718 struct cmd_ds_command *cmd)
719{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200720
Holger Schurig8ff12da2007-08-02 11:54:31 -0400721 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400722 cmd->command = cpu_to_le16(CMD_802_11_RSSI);
David Woodhouse981f1872007-05-25 23:36:54 -0400723 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
Holger Schuriga783f1e2007-08-02 13:08:24 -0400724 cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200725
726 /* reset Beacon SNR/NF/RSSI values */
David Woodhouseaa21c002007-12-08 20:04:36 +0000727 priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
728 priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
729 priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
730 priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
731 priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
732 priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200733
Holger Schurig8ff12da2007-08-02 11:54:31 -0400734 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200735 return 0;
736}
737
Holger Schurig69f90322007-11-23 15:43:44 +0100738static int lbs_cmd_reg_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200739 struct cmd_ds_command *cmdptr,
740 u8 cmd_action, void *pdata_buf)
741{
Holger Schurig10078322007-11-15 18:05:47 -0500742 struct lbs_offset_value *offval;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200743
Holger Schurig9012b282007-05-25 11:27:16 -0400744 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200745
Holger Schurig10078322007-11-15 18:05:47 -0500746 offval = (struct lbs_offset_value *)pdata_buf;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200747
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000748 switch (le16_to_cpu(cmdptr->command)) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400749 case CMD_MAC_REG_ACCESS:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200750 {
751 struct cmd_ds_mac_reg_access *macreg;
752
753 cmdptr->size =
David Woodhouse981f1872007-05-25 23:36:54 -0400754 cpu_to_le16(sizeof (struct cmd_ds_mac_reg_access)
755 + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200756 macreg =
757 (struct cmd_ds_mac_reg_access *)&cmdptr->params.
758 macreg;
759
760 macreg->action = cpu_to_le16(cmd_action);
761 macreg->offset = cpu_to_le16((u16) offval->offset);
762 macreg->value = cpu_to_le32(offval->value);
763
764 break;
765 }
766
Dan Williams0aef64d2007-08-02 11:31:18 -0400767 case CMD_BBP_REG_ACCESS:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200768 {
769 struct cmd_ds_bbp_reg_access *bbpreg;
770
771 cmdptr->size =
772 cpu_to_le16(sizeof
773 (struct cmd_ds_bbp_reg_access)
774 + S_DS_GEN);
775 bbpreg =
776 (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
777 bbpreg;
778
779 bbpreg->action = cpu_to_le16(cmd_action);
780 bbpreg->offset = cpu_to_le16((u16) offval->offset);
781 bbpreg->value = (u8) offval->value;
782
783 break;
784 }
785
Dan Williams0aef64d2007-08-02 11:31:18 -0400786 case CMD_RF_REG_ACCESS:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200787 {
788 struct cmd_ds_rf_reg_access *rfreg;
789
790 cmdptr->size =
791 cpu_to_le16(sizeof
792 (struct cmd_ds_rf_reg_access) +
793 S_DS_GEN);
794 rfreg =
795 (struct cmd_ds_rf_reg_access *)&cmdptr->params.
796 rfreg;
797
798 rfreg->action = cpu_to_le16(cmd_action);
799 rfreg->offset = cpu_to_le16((u16) offval->offset);
800 rfreg->value = (u8) offval->value;
801
802 break;
803 }
804
805 default:
806 break;
807 }
808
Holger Schurig9012b282007-05-25 11:27:16 -0400809 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200810 return 0;
811}
812
Holger Schurig69f90322007-11-23 15:43:44 +0100813static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200814 struct cmd_ds_command *cmd,
815 u16 cmd_action)
816{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200817
Holger Schurig8ff12da2007-08-02 11:54:31 -0400818 lbs_deb_enter(LBS_DEB_CMD);
Dan Williams0aef64d2007-08-02 11:31:18 -0400819 cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400820 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200821 S_DS_GEN);
822 cmd->result = 0;
823
824 cmd->params.macadd.action = cpu_to_le16(cmd_action);
825
Dan Williams0aef64d2007-08-02 11:31:18 -0400826 if (cmd_action == CMD_ACT_SET) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200827 memcpy(cmd->params.macadd.macadd,
David Woodhouseaa21c002007-12-08 20:04:36 +0000828 priv->current_addr, ETH_ALEN);
829 lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200830 }
831
Holger Schurig8ff12da2007-08-02 11:54:31 -0400832 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200833 return 0;
834}
835
Holger Schurig69f90322007-11-23 15:43:44 +0100836static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200837 struct cmd_ds_command *cmd,
838 int cmd_action, void *pdata_buf)
839{
Holger Schurig10078322007-11-15 18:05:47 -0500840 struct lbs_ioctl_regrdwr *ea = pdata_buf;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200841
Holger Schurig9012b282007-05-25 11:27:16 -0400842 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200843
Dan Williams0aef64d2007-08-02 11:31:18 -0400844 cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400845 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
846 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200847 cmd->result = 0;
848
849 cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
850 cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
851 cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
852 cmd->params.rdeeprom.value = 0;
853
Holger Schurig8ff12da2007-08-02 11:54:31 -0400854 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200855 return 0;
856}
857
Holger Schurig69f90322007-11-23 15:43:44 +0100858static int lbs_cmd_bt_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200859 struct cmd_ds_command *cmd,
860 u16 cmd_action, void *pdata_buf)
861{
862 struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
Holger Schurig8ff12da2007-08-02 11:54:31 -0400863 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200864
Dan Williams0aef64d2007-08-02 11:31:18 -0400865 cmd->command = cpu_to_le16(CMD_BT_ACCESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400866 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200867 cmd->result = 0;
868 bt_access->action = cpu_to_le16(cmd_action);
869
870 switch (cmd_action) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400871 case CMD_ACT_BT_ACCESS_ADD:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200872 memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
Holger Schurigece56192007-08-02 11:53:06 -0400873 lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200874 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400875 case CMD_ACT_BT_ACCESS_DEL:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200876 memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
Holger Schurigece56192007-08-02 11:53:06 -0400877 lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200878 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400879 case CMD_ACT_BT_ACCESS_LIST:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200880 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
881 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400882 case CMD_ACT_BT_ACCESS_RESET:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200883 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400884 case CMD_ACT_BT_ACCESS_SET_INVERT:
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400885 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
886 break;
Dan Williams0aef64d2007-08-02 11:31:18 -0400887 case CMD_ACT_BT_ACCESS_GET_INVERT:
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400888 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200889 default:
890 break;
891 }
Holger Schurig8ff12da2007-08-02 11:54:31 -0400892 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200893 return 0;
894}
895
Holger Schurig69f90322007-11-23 15:43:44 +0100896static int lbs_cmd_fwt_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200897 struct cmd_ds_command *cmd,
898 u16 cmd_action, void *pdata_buf)
899{
900 struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
Holger Schurig8ff12da2007-08-02 11:54:31 -0400901 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200902
Dan Williams0aef64d2007-08-02 11:31:18 -0400903 cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400904 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200905 cmd->result = 0;
906
907 if (pdata_buf)
908 memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
909 else
910 memset(fwt_access, 0, sizeof(*fwt_access));
911
912 fwt_access->action = cpu_to_le16(cmd_action);
913
Holger Schurig8ff12da2007-08-02 11:54:31 -0400914 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200915 return 0;
916}
917
Holger Schurig69f90322007-11-23 15:43:44 +0100918static int lbs_cmd_mesh_access(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200919 struct cmd_ds_command *cmd,
920 u16 cmd_action, void *pdata_buf)
921{
922 struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
Holger Schurig8ff12da2007-08-02 11:54:31 -0400923 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200924
Dan Williams0aef64d2007-08-02 11:31:18 -0400925 cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
David Woodhouse981f1872007-05-25 23:36:54 -0400926 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200927 cmd->result = 0;
928
929 if (pdata_buf)
930 memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
931 else
932 memset(mesh_access, 0, sizeof(*mesh_access));
933
934 mesh_access->action = cpu_to_le16(cmd_action);
935
Holger Schurig8ff12da2007-08-02 11:54:31 -0400936 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200937 return 0;
938}
939
Brajesh Dave96287ac2007-11-20 17:44:28 -0500940static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
941 struct cmd_ds_command *cmd,
942 u16 cmd_action)
943{
944 struct cmd_ds_802_11_beacon_control
945 *bcn_ctrl = &cmd->params.bcn_ctrl;
Brajesh Dave96287ac2007-11-20 17:44:28 -0500946
947 lbs_deb_enter(LBS_DEB_CMD);
948 cmd->size =
949 cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
950 + S_DS_GEN);
951 cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
952
953 bcn_ctrl->action = cpu_to_le16(cmd_action);
David Woodhouseaa21c002007-12-08 20:04:36 +0000954 bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
955 bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
Brajesh Dave96287ac2007-11-20 17:44:28 -0500956
957 lbs_deb_leave(LBS_DEB_CMD);
958 return 0;
959}
960
Marcelo Tosatti29f5f2a2007-10-30 10:52:46 -0400961/*
Holger Schurig10078322007-11-15 18:05:47 -0500962 * Note: NEVER use lbs_queue_cmd() with addtail==0 other than for
Marcelo Tosatti29f5f2a2007-10-30 10:52:46 -0400963 * the command timer, because it does not account for queued commands.
964 */
David Woodhouseaa21c002007-12-08 20:04:36 +0000965void lbs_queue_cmd(struct lbs_private *priv,
Holger Schurig69f90322007-11-23 15:43:44 +0100966 struct cmd_ctrl_node *cmdnode,
967 u8 addtail)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200968{
969 unsigned long flags;
970 struct cmd_ds_command *cmdptr;
971
Holger Schurig8ff12da2007-08-02 11:54:31 -0400972 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200973
974 if (!cmdnode) {
Holger Schurig8ff12da2007-08-02 11:54:31 -0400975 lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200976 goto done;
977 }
978
979 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
980 if (!cmdptr) {
Holger Schurig8ff12da2007-08-02 11:54:31 -0400981 lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200982 goto done;
983 }
984
985 /* Exit_PS command needs to be queued in the header always. */
Holger Schurigc2df2ef2007-12-07 15:30:44 +0000986 if (le16_to_cpu(cmdptr->command) == CMD_802_11_PS_MODE) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200987 struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
Dan Williams0aef64d2007-08-02 11:31:18 -0400988 if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000989 if (priv->psstate != PS_STATE_FULL_POWER)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200990 addtail = 0;
991 }
992 }
993
David Woodhouseaa21c002007-12-08 20:04:36 +0000994 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200995
David Woodhouseac472462007-12-08 00:35:00 +0000996 if (addtail)
David Woodhouseaa21c002007-12-08 20:04:36 +0000997 list_add_tail(&cmdnode->list, &priv->cmdpendingq);
David Woodhouseac472462007-12-08 00:35:00 +0000998 else
David Woodhouseaa21c002007-12-08 20:04:36 +0000999 list_add(&cmdnode->list, &priv->cmdpendingq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001000
David Woodhouseaa21c002007-12-08 20:04:36 +00001001 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001002
Holger Schurig8ff12da2007-08-02 11:54:31 -04001003 lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001004 le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001005
1006done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001007 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001008}
1009
1010/*
1011 * TODO: Fix the issue when DownloadcommandToStation is being called the
Holger Schurig8ff12da2007-08-02 11:54:31 -04001012 * second time when the command times out. All the cmdptr->xxx are in little
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001013 * endian and therefore all the comparissions will fail.
1014 * For now - we are not performing the endian conversion the second time - but
1015 * for PS and DEEP_SLEEP we need to worry
1016 */
Holger Schurig69f90322007-11-23 15:43:44 +01001017static int DownloadcommandToStation(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001018 struct cmd_ctrl_node *cmdnode)
1019{
1020 unsigned long flags;
1021 struct cmd_ds_command *cmdptr;
Eugene Teob031ac12007-08-02 13:18:07 -04001022 int ret = -1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001023 u16 cmdsize;
1024 u16 command;
1025
Holger Schurig8ff12da2007-08-02 11:54:31 -04001026 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001027
David Woodhouseaa21c002007-12-08 20:04:36 +00001028 if (!priv || !cmdnode) {
1029 lbs_deb_host("DNLD_CMD: priv or cmdmode is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001030 goto done;
1031 }
1032
1033 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1034
David Woodhouseaa21c002007-12-08 20:04:36 +00001035 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001036 if (!cmdptr || !cmdptr->size) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001037 lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
Holger Schurig10078322007-11-15 18:05:47 -05001038 __lbs_cleanup_and_insert_cmd(priv, cmdnode);
David Woodhouseaa21c002007-12-08 20:04:36 +00001039 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001040 goto done;
1041 }
1042
David Woodhouseaa21c002007-12-08 20:04:36 +00001043 priv->cur_cmd = cmdnode;
1044 priv->cur_cmd_retcode = 0;
1045 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001046
Holger Schurigc2df2ef2007-12-07 15:30:44 +00001047 cmdsize = le16_to_cpu(cmdptr->size);
1048 command = le16_to_cpu(cmdptr->command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001049
Holger Schurig8ff12da2007-08-02 11:54:31 -04001050 lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
Holger Schurigc2df2ef2007-12-07 15:30:44 +00001051 command, cmdsize, jiffies);
Holger Schurig8ff12da2007-08-02 11:54:31 -04001052 lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);
1053
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001054 cmdnode->cmdwaitqwoken = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001055
Holger Schurig208fdd22007-05-25 12:17:06 -04001056 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001057
1058 if (ret != 0) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001059 lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
David Woodhouseaa21c002007-12-08 20:04:36 +00001060 spin_lock_irqsave(&priv->driver_lock, flags);
1061 priv->cur_cmd_retcode = ret;
1062 __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
1063 priv->cur_cmd = NULL;
1064 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001065 goto done;
1066 }
1067
Holger Schurig8ff12da2007-08-02 11:54:31 -04001068 lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001069
1070 /* Setup the timer after transmit command */
Dan Williams0aef64d2007-08-02 11:31:18 -04001071 if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
1072 || command == CMD_802_11_ASSOCIATE)
David Woodhouseaa21c002007-12-08 20:04:36 +00001073 mod_timer(&priv->command_timer, jiffies + (10*HZ));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001074 else
David Woodhouseaa21c002007-12-08 20:04:36 +00001075 mod_timer(&priv->command_timer, jiffies + (5*HZ));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001076
1077 ret = 0;
1078
Holger Schurig9012b282007-05-25 11:27:16 -04001079done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001080 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001081 return ret;
1082}
1083
Holger Schurig69f90322007-11-23 15:43:44 +01001084static int lbs_cmd_mac_control(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001085 struct cmd_ds_command *cmd)
1086{
1087 struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
1088
Holger Schurig9012b282007-05-25 11:27:16 -04001089 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001090
Dan Williams0aef64d2007-08-02 11:31:18 -04001091 cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
David Woodhouse981f1872007-05-25 23:36:54 -04001092 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
David Woodhouseaa21c002007-12-08 20:04:36 +00001093 mac->action = cpu_to_le16(priv->currentpacketfilter);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001094
Holger Schurig8ff12da2007-08-02 11:54:31 -04001095 lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001096 le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001097
Holger Schurig9012b282007-05-25 11:27:16 -04001098 lbs_deb_leave(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001099 return 0;
1100}
1101
1102/**
1103 * This function inserts command node to cmdfreeq
David Woodhouseaa21c002007-12-08 20:04:36 +00001104 * after cleans it. Requires priv->driver_lock held.
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001105 */
Holger Schurig69f90322007-11-23 15:43:44 +01001106void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1107 struct cmd_ctrl_node *ptempcmd)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001108{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001109
1110 if (!ptempcmd)
Holger Schurig8ff12da2007-08-02 11:54:31 -04001111 return;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001112
1113 cleanup_cmdnode(ptempcmd);
David Woodhouseaa21c002007-12-08 20:04:36 +00001114 list_add_tail(&ptempcmd->list, &priv->cmdfreeq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001115}
1116
Holger Schurig69f90322007-11-23 15:43:44 +01001117static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1118 struct cmd_ctrl_node *ptempcmd)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001119{
1120 unsigned long flags;
1121
David Woodhouseaa21c002007-12-08 20:04:36 +00001122 spin_lock_irqsave(&priv->driver_lock, flags);
Holger Schurig10078322007-11-15 18:05:47 -05001123 __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
David Woodhouseaa21c002007-12-08 20:04:36 +00001124 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001125}
1126
Holger Schurig69f90322007-11-23 15:43:44 +01001127int lbs_set_radio_control(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001128{
1129 int ret = 0;
1130
Holger Schurig9012b282007-05-25 11:27:16 -04001131 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001132
Holger Schurig10078322007-11-15 18:05:47 -05001133 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001134 CMD_802_11_RADIO_CONTROL,
1135 CMD_ACT_SET,
1136 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001137
Holger Schurig8ff12da2007-08-02 11:54:31 -04001138 lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001139 priv->radioon, priv->preamble);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001140
Holger Schurig9012b282007-05-25 11:27:16 -04001141 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001142 return ret;
1143}
1144
Holger Schurig69f90322007-11-23 15:43:44 +01001145int lbs_set_mac_packet_filter(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001146{
1147 int ret = 0;
1148
Holger Schurig9012b282007-05-25 11:27:16 -04001149 lbs_deb_enter(LBS_DEB_CMD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001150
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001151 /* Send MAC control command to station */
Holger Schurig10078322007-11-15 18:05:47 -05001152 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001153 CMD_MAC_CONTROL, 0, 0, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001154
Holger Schurig9012b282007-05-25 11:27:16 -04001155 lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001156 return ret;
1157}
1158
1159/**
1160 * @brief This function prepare the command before send to firmware.
1161 *
Holger Schurig69f90322007-11-23 15:43:44 +01001162 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001163 * @param cmd_no command number
1164 * @param cmd_action command action: GET or SET
1165 * @param wait_option wait option: wait response or not
1166 * @param cmd_oid cmd oid: treated as sub command
1167 * @param pdata_buf A pointer to informaion buffer
1168 * @return 0 or -1
1169 */
Holger Schurig69f90322007-11-23 15:43:44 +01001170int lbs_prepare_and_send_command(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001171 u16 cmd_no,
1172 u16 cmd_action,
1173 u16 wait_option, u32 cmd_oid, void *pdata_buf)
1174{
1175 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001176 struct cmd_ctrl_node *cmdnode;
1177 struct cmd_ds_command *cmdptr;
1178 unsigned long flags;
1179
Holger Schurig8ff12da2007-08-02 11:54:31 -04001180 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001181
David Woodhouseaa21c002007-12-08 20:04:36 +00001182 if (!priv) {
1183 lbs_deb_host("PREP_CMD: priv is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001184 ret = -1;
1185 goto done;
1186 }
1187
David Woodhouseaa21c002007-12-08 20:04:36 +00001188 if (priv->surpriseremoved) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001189 lbs_deb_host("PREP_CMD: card removed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001190 ret = -1;
1191 goto done;
1192 }
1193
Holger Schurig0d61d042007-12-05 17:58:06 +01001194 cmdnode = lbs_get_cmd_ctrl_node(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001195
1196 if (cmdnode == NULL) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001197 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001198
1199 /* Wake up main thread to execute next command */
Dan Williamsfe336152007-08-02 11:32:25 -04001200 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001201 ret = -1;
1202 goto done;
1203 }
1204
David Woodhousef5ece8f2007-12-01 15:15:41 +00001205 lbs_set_cmd_ctrl_node(priv, cmdnode, wait_option, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001206
1207 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1208
Holger Schurig8ff12da2007-08-02 11:54:31 -04001209 lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001210
1211 if (!cmdptr) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001212 lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
Holger Schurig10078322007-11-15 18:05:47 -05001213 lbs_cleanup_and_insert_cmd(priv, cmdnode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001214 ret = -1;
1215 goto done;
1216 }
1217
1218 /* Set sequence number, command and INT option */
David Woodhouseaa21c002007-12-08 20:04:36 +00001219 priv->seqnum++;
1220 cmdptr->seqnum = cpu_to_le16(priv->seqnum);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001221
David Woodhouse981f1872007-05-25 23:36:54 -04001222 cmdptr->command = cpu_to_le16(cmd_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001223 cmdptr->result = 0;
1224
1225 switch (cmd_no) {
Dan Williams0aef64d2007-08-02 11:31:18 -04001226 case CMD_GET_HW_SPEC:
Holger Schurig10078322007-11-15 18:05:47 -05001227 ret = lbs_cmd_hw_spec(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001228 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001229 case CMD_802_11_PS_MODE:
Holger Schurig10078322007-11-15 18:05:47 -05001230 ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001231 break;
1232
Dan Williams0aef64d2007-08-02 11:31:18 -04001233 case CMD_802_11_SCAN:
Holger Schurig10078322007-11-15 18:05:47 -05001234 ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001235 break;
1236
Dan Williams0aef64d2007-08-02 11:31:18 -04001237 case CMD_MAC_CONTROL:
Holger Schurig10078322007-11-15 18:05:47 -05001238 ret = lbs_cmd_mac_control(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001239 break;
1240
Dan Williams0aef64d2007-08-02 11:31:18 -04001241 case CMD_802_11_ASSOCIATE:
1242 case CMD_802_11_REASSOCIATE:
Holger Schurig10078322007-11-15 18:05:47 -05001243 ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001244 break;
1245
Dan Williams0aef64d2007-08-02 11:31:18 -04001246 case CMD_802_11_DEAUTHENTICATE:
Holger Schurig10078322007-11-15 18:05:47 -05001247 ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001248 break;
1249
Dan Williams0aef64d2007-08-02 11:31:18 -04001250 case CMD_802_11_SET_WEP:
Holger Schurig10078322007-11-15 18:05:47 -05001251 ret = lbs_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001252 break;
1253
Dan Williams0aef64d2007-08-02 11:31:18 -04001254 case CMD_802_11_AD_HOC_START:
Holger Schurig10078322007-11-15 18:05:47 -05001255 ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001256 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001257 case CMD_CODE_DNLD:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001258 break;
1259
Dan Williams0aef64d2007-08-02 11:31:18 -04001260 case CMD_802_11_RESET:
Holger Schurig10078322007-11-15 18:05:47 -05001261 ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001262 break;
1263
Dan Williams0aef64d2007-08-02 11:31:18 -04001264 case CMD_802_11_GET_LOG:
Holger Schurig10078322007-11-15 18:05:47 -05001265 ret = lbs_cmd_802_11_get_log(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001266 break;
1267
Dan Williams0aef64d2007-08-02 11:31:18 -04001268 case CMD_802_11_AUTHENTICATE:
Holger Schurig10078322007-11-15 18:05:47 -05001269 ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001270 break;
1271
Dan Williams0aef64d2007-08-02 11:31:18 -04001272 case CMD_802_11_GET_STAT:
Holger Schurig10078322007-11-15 18:05:47 -05001273 ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001274 break;
1275
Dan Williams0aef64d2007-08-02 11:31:18 -04001276 case CMD_802_11_SNMP_MIB:
Holger Schurig10078322007-11-15 18:05:47 -05001277 ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001278 cmd_action, cmd_oid, pdata_buf);
1279 break;
1280
Dan Williams0aef64d2007-08-02 11:31:18 -04001281 case CMD_MAC_REG_ACCESS:
1282 case CMD_BBP_REG_ACCESS:
1283 case CMD_RF_REG_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001284 ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001285 break;
1286
Dan Williams0aef64d2007-08-02 11:31:18 -04001287 case CMD_802_11_RF_CHANNEL:
Holger Schurig10078322007-11-15 18:05:47 -05001288 ret = lbs_cmd_802_11_rf_channel(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001289 cmd_action, pdata_buf);
1290 break;
1291
Dan Williams0aef64d2007-08-02 11:31:18 -04001292 case CMD_802_11_RF_TX_POWER:
Holger Schurig10078322007-11-15 18:05:47 -05001293 ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001294 cmd_action, pdata_buf);
1295 break;
1296
Dan Williams0aef64d2007-08-02 11:31:18 -04001297 case CMD_802_11_RADIO_CONTROL:
Holger Schurig10078322007-11-15 18:05:47 -05001298 ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001299 break;
1300
Dan Williams0aef64d2007-08-02 11:31:18 -04001301 case CMD_802_11_DATA_RATE:
Holger Schurig10078322007-11-15 18:05:47 -05001302 ret = lbs_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001303 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001304 case CMD_802_11_RATE_ADAPT_RATESET:
Holger Schurig10078322007-11-15 18:05:47 -05001305 ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001306 cmdptr, cmd_action);
1307 break;
1308
Dan Williams0aef64d2007-08-02 11:31:18 -04001309 case CMD_MAC_MULTICAST_ADR:
Holger Schurig10078322007-11-15 18:05:47 -05001310 ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001311 break;
1312
Luis Carlos Cobo965f8bbc2007-08-02 13:16:55 -04001313 case CMD_802_11_MONITOR_MODE:
Holger Schurig10078322007-11-15 18:05:47 -05001314 ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
Luis Carlos Cobo965f8bbc2007-08-02 13:16:55 -04001315 cmd_action, pdata_buf);
1316 break;
1317
Dan Williams0aef64d2007-08-02 11:31:18 -04001318 case CMD_802_11_AD_HOC_JOIN:
Holger Schurig10078322007-11-15 18:05:47 -05001319 ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001320 break;
1321
Dan Williams0aef64d2007-08-02 11:31:18 -04001322 case CMD_802_11_RSSI:
Holger Schurig10078322007-11-15 18:05:47 -05001323 ret = lbs_cmd_802_11_rssi(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001324 break;
1325
Dan Williams0aef64d2007-08-02 11:31:18 -04001326 case CMD_802_11_AD_HOC_STOP:
Holger Schurig10078322007-11-15 18:05:47 -05001327 ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001328 break;
1329
Dan Williams0aef64d2007-08-02 11:31:18 -04001330 case CMD_802_11_ENABLE_RSN:
Holger Schurig10078322007-11-15 18:05:47 -05001331 ret = lbs_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
Dan Williams90a42212007-05-25 23:01:24 -04001332 pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001333 break;
1334
Dan Williams0aef64d2007-08-02 11:31:18 -04001335 case CMD_802_11_KEY_MATERIAL:
Holger Schurig10078322007-11-15 18:05:47 -05001336 ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
Dan Williams90a42212007-05-25 23:01:24 -04001337 cmd_oid, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001338 break;
1339
Dan Williams0aef64d2007-08-02 11:31:18 -04001340 case CMD_802_11_PAIRWISE_TSC:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001341 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001342 case CMD_802_11_GROUP_TSC:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001343 break;
1344
Dan Williams0aef64d2007-08-02 11:31:18 -04001345 case CMD_802_11_MAC_ADDRESS:
Holger Schurig10078322007-11-15 18:05:47 -05001346 ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001347 break;
1348
Dan Williams0aef64d2007-08-02 11:31:18 -04001349 case CMD_802_11_EEPROM_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001350 ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001351 cmd_action, pdata_buf);
1352 break;
1353
Dan Williams0aef64d2007-08-02 11:31:18 -04001354 case CMD_802_11_SET_AFC:
1355 case CMD_802_11_GET_AFC:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001356
1357 cmdptr->command = cpu_to_le16(cmd_no);
David Woodhouse981f1872007-05-25 23:36:54 -04001358 cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
1359 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001360
1361 memmove(&cmdptr->params.afc,
1362 pdata_buf, sizeof(struct cmd_ds_802_11_afc));
1363
1364 ret = 0;
1365 goto done;
1366
Dan Williams0aef64d2007-08-02 11:31:18 -04001367 case CMD_802_11D_DOMAIN_INFO:
Holger Schurig10078322007-11-15 18:05:47 -05001368 ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001369 cmd_no, cmd_action);
1370 break;
1371
Dan Williams0aef64d2007-08-02 11:31:18 -04001372 case CMD_802_11_SLEEP_PARAMS:
Holger Schurig10078322007-11-15 18:05:47 -05001373 ret = lbs_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001374 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001375 case CMD_802_11_INACTIVITY_TIMEOUT:
Holger Schurig10078322007-11-15 18:05:47 -05001376 ret = lbs_cmd_802_11_inactivity_timeout(priv, cmdptr,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001377 cmd_action, pdata_buf);
David Woodhousef5ece8f2007-12-01 15:15:41 +00001378 lbs_set_cmd_ctrl_node(priv, cmdnode, 0, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001379 break;
1380
Dan Williams0aef64d2007-08-02 11:31:18 -04001381 case CMD_802_11_TPC_CFG:
1382 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001383 cmdptr->size =
1384 cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
1385 S_DS_GEN);
1386
1387 memmove(&cmdptr->params.tpccfg,
1388 pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
1389
1390 ret = 0;
1391 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001392 case CMD_802_11_LED_GPIO_CTRL:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001393 {
1394 struct mrvlietypes_ledgpio *gpio =
1395 (struct mrvlietypes_ledgpio*)
1396 cmdptr->params.ledgpio.data;
1397
1398 memmove(&cmdptr->params.ledgpio,
1399 pdata_buf,
1400 sizeof(struct cmd_ds_802_11_led_ctrl));
1401
1402 cmdptr->command =
Dan Williams0aef64d2007-08-02 11:31:18 -04001403 cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001404
1405#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
1406 cmdptr->size =
Holger Schurigc2df2ef2007-12-07 15:30:44 +00001407 cpu_to_le16(le16_to_cpu(gpio->header.len)
1408 + S_DS_GEN
1409 + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
1410 gpio->header.len = gpio->header.len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001411
1412 ret = 0;
1413 break;
1414 }
Holger Schurig3a188642007-11-26 10:07:14 +01001415 case CMD_802_11_SUBSCRIBE_EVENT:
1416 lbs_cmd_802_11_subscribe_event(priv, cmdptr,
1417 cmd_action, pdata_buf);
1418 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001419 case CMD_802_11_PWR_CFG:
1420 cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001421 cmdptr->size =
1422 cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
1423 S_DS_GEN);
1424 memmove(&cmdptr->params.pwrcfg, pdata_buf,
1425 sizeof(struct cmd_ds_802_11_pwr_cfg));
1426
1427 ret = 0;
1428 break;
Dan Williams0aef64d2007-08-02 11:31:18 -04001429 case CMD_BT_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001430 ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001431 break;
1432
Dan Williams0aef64d2007-08-02 11:31:18 -04001433 case CMD_FWT_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001434 ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001435 break;
1436
Dan Williams0aef64d2007-08-02 11:31:18 -04001437 case CMD_MESH_ACCESS:
Holger Schurig10078322007-11-15 18:05:47 -05001438 ret = lbs_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001439 break;
1440
Dan Williams0aef64d2007-08-02 11:31:18 -04001441 case CMD_GET_TSF:
1442 cmdptr->command = cpu_to_le16(CMD_GET_TSF);
David Woodhouse981f1872007-05-25 23:36:54 -04001443 cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
1444 S_DS_GEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001445 ret = 0;
1446 break;
Brajesh Dave96287ac2007-11-20 17:44:28 -05001447 case CMD_802_11_BEACON_CTRL:
1448 ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
1449 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001450 default:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001451 lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001452 ret = -1;
1453 break;
1454 }
1455
1456 /* return error, since the command preparation failed */
1457 if (ret != 0) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001458 lbs_deb_host("PREP_CMD: command preparation failed\n");
Holger Schurig10078322007-11-15 18:05:47 -05001459 lbs_cleanup_and_insert_cmd(priv, cmdnode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001460 ret = -1;
1461 goto done;
1462 }
1463
1464 cmdnode->cmdwaitqwoken = 0;
1465
David Woodhouseaa21c002007-12-08 20:04:36 +00001466 lbs_queue_cmd(priv, cmdnode, 1);
Dan Williamsfe336152007-08-02 11:32:25 -04001467 wake_up_interruptible(&priv->waitq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001468
Dan Williams0aef64d2007-08-02 11:31:18 -04001469 if (wait_option & CMD_OPTION_WAITFORRSP) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001470 lbs_deb_host("PREP_CMD: wait for response\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001471 might_sleep();
1472 wait_event_interruptible(cmdnode->cmdwait_q,
1473 cmdnode->cmdwaitqwoken);
1474 }
1475
David Woodhouseaa21c002007-12-08 20:04:36 +00001476 spin_lock_irqsave(&priv->driver_lock, flags);
1477 if (priv->cur_cmd_retcode) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001478 lbs_deb_host("PREP_CMD: command failed with return code %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001479 priv->cur_cmd_retcode);
1480 priv->cur_cmd_retcode = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001481 ret = -1;
1482 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001483 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001484
1485done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001486 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001487 return ret;
1488}
Holger Schurig10078322007-11-15 18:05:47 -05001489EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001490
1491/**
1492 * @brief This function allocates the command buffer and link
1493 * it to command free queue.
1494 *
Holger Schurig69f90322007-11-23 15:43:44 +01001495 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001496 * @return 0 or -1
1497 */
Holger Schurig69f90322007-11-23 15:43:44 +01001498int lbs_allocate_cmd_buffer(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001499{
1500 int ret = 0;
1501 u32 ulbufsize;
1502 u32 i;
1503 struct cmd_ctrl_node *tempcmd_array;
1504 u8 *ptempvirtualaddr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001505
Holger Schurig8ff12da2007-08-02 11:54:31 -04001506 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001507
1508 /* Allocate and initialize cmdCtrlNode */
1509 ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
1510
Holger Schurigfb3dddf2007-05-25 11:58:22 -04001511 if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001512 lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001513 ret = -1;
1514 goto done;
1515 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001516 priv->cmd_array = tempcmd_array;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001517
1518 /* Allocate and initialize command buffers */
1519 ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
1520 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
Holger Schurigfb3dddf2007-05-25 11:58:22 -04001521 if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001522 lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001523 ret = -1;
1524 goto done;
1525 }
1526
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001527 /* Update command buffer virtual */
1528 tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
1529 }
1530
1531 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
1532 init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
Holger Schurig10078322007-11-15 18:05:47 -05001533 lbs_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001534 }
1535
1536 ret = 0;
Holger Schurig9012b282007-05-25 11:27:16 -04001537
1538done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001539 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001540 return ret;
1541}
1542
1543/**
1544 * @brief This function frees the command buffer.
1545 *
Holger Schurig69f90322007-11-23 15:43:44 +01001546 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001547 * @return 0 or -1
1548 */
Holger Schurig69f90322007-11-23 15:43:44 +01001549int lbs_free_cmd_buffer(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001550{
David Woodhouse981f1872007-05-25 23:36:54 -04001551 u32 ulbufsize; /* Someone needs to die for this. Slowly and painfully */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001552 unsigned int i;
1553 struct cmd_ctrl_node *tempcmd_array;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001554
Holger Schurig8ff12da2007-08-02 11:54:31 -04001555 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001556
1557 /* need to check if cmd array is allocated or not */
David Woodhouseaa21c002007-12-08 20:04:36 +00001558 if (priv->cmd_array == NULL) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001559 lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001560 goto done;
1561 }
1562
David Woodhouseaa21c002007-12-08 20:04:36 +00001563 tempcmd_array = priv->cmd_array;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001564
1565 /* Release shared memory buffers */
1566 ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
1567 for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
1568 if (tempcmd_array[i].bufvirtualaddr) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001569 kfree(tempcmd_array[i].bufvirtualaddr);
1570 tempcmd_array[i].bufvirtualaddr = NULL;
1571 }
1572 }
1573
1574 /* Release cmd_ctrl_node */
David Woodhouseaa21c002007-12-08 20:04:36 +00001575 if (priv->cmd_array) {
1576 kfree(priv->cmd_array);
1577 priv->cmd_array = NULL;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001578 }
1579
1580done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001581 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001582 return 0;
1583}
1584
1585/**
1586 * @brief This function gets a free command node if available in
1587 * command free queue.
1588 *
Holger Schurig69f90322007-11-23 15:43:44 +01001589 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001590 * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
1591 */
Holger Schurig0d61d042007-12-05 17:58:06 +01001592struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001593{
1594 struct cmd_ctrl_node *tempnode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001595 unsigned long flags;
1596
Holger Schurig8ff12da2007-08-02 11:54:31 -04001597 lbs_deb_enter(LBS_DEB_HOST);
1598
David Woodhouseaa21c002007-12-08 20:04:36 +00001599 if (!priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001600 return NULL;
1601
David Woodhouseaa21c002007-12-08 20:04:36 +00001602 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001603
David Woodhouseaa21c002007-12-08 20:04:36 +00001604 if (!list_empty(&priv->cmdfreeq)) {
1605 tempnode = list_first_entry(&priv->cmdfreeq,
Li Zefanabe3ed12007-12-06 13:01:21 +01001606 struct cmd_ctrl_node, list);
1607 list_del(&tempnode->list);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001608 } else {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001609 lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001610 tempnode = NULL;
1611 }
1612
David Woodhouseaa21c002007-12-08 20:04:36 +00001613 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001614
Holger Schurig8ff12da2007-08-02 11:54:31 -04001615 if (tempnode)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001616 cleanup_cmdnode(tempnode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001617
Holger Schurig8ff12da2007-08-02 11:54:31 -04001618 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001619 return tempnode;
1620}
1621
1622/**
1623 * @brief This function cleans command node.
1624 *
1625 * @param ptempnode A pointer to cmdCtrlNode structure
1626 * @return n/a
1627 */
1628static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
1629{
Holger Schurig8ff12da2007-08-02 11:54:31 -04001630 lbs_deb_enter(LBS_DEB_HOST);
1631
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001632 if (!ptempnode)
1633 return;
1634 ptempnode->cmdwaitqwoken = 1;
1635 wake_up_interruptible(&ptempnode->cmdwait_q);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001636 ptempnode->wait_option = 0;
1637 ptempnode->pdata_buf = NULL;
David Woodhouse17230472007-12-07 15:13:05 +00001638 ptempnode->callback = NULL;
David Woodhouse1309b552007-12-10 13:36:10 -05001639 ptempnode->callback_arg = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001640
1641 if (ptempnode->bufvirtualaddr != NULL)
1642 memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
Holger Schurig8ff12da2007-08-02 11:54:31 -04001643
1644 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001645}
1646
1647/**
1648 * @brief This function initializes the command node.
1649 *
Holger Schurig69f90322007-11-23 15:43:44 +01001650 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001651 * @param ptempnode A pointer to cmd_ctrl_node structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001652 * @param wait_option wait option: wait response or not
1653 * @param pdata_buf A pointer to informaion buffer
1654 * @return 0 or -1
1655 */
Holger Schurig69f90322007-11-23 15:43:44 +01001656void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001657 struct cmd_ctrl_node *ptempnode,
David Woodhousef5ece8f2007-12-01 15:15:41 +00001658 u16 wait_option, void *pdata_buf)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001659{
Holger Schurig8ff12da2007-08-02 11:54:31 -04001660 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001661
1662 if (!ptempnode)
1663 return;
1664
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001665 ptempnode->wait_option = wait_option;
1666 ptempnode->pdata_buf = pdata_buf;
David Woodhouse17230472007-12-07 15:13:05 +00001667 ptempnode->callback = NULL;
David Woodhouse1309b552007-12-10 13:36:10 -05001668 ptempnode->callback_arg = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001669
Holger Schurig8ff12da2007-08-02 11:54:31 -04001670 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001671}
1672
1673/**
1674 * @brief This function executes next command in command
1675 * pending queue. It will put fimware back to PS mode
1676 * if applicable.
1677 *
Holger Schurig69f90322007-11-23 15:43:44 +01001678 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001679 * @return 0 or -1
1680 */
Holger Schurig69f90322007-11-23 15:43:44 +01001681int lbs_execute_next_command(struct lbs_private *priv)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001682{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001683 struct cmd_ctrl_node *cmdnode = NULL;
1684 struct cmd_ds_command *cmdptr;
1685 unsigned long flags;
1686 int ret = 0;
1687
Holger Schurig8ff12da2007-08-02 11:54:31 -04001688 // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
Holger Schurig10078322007-11-15 18:05:47 -05001689 // only caller to us is lbs_thread() and we get even when a
Holger Schurig8ff12da2007-08-02 11:54:31 -04001690 // data packet is received
1691 lbs_deb_enter(LBS_DEB_THREAD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001692
David Woodhouseaa21c002007-12-08 20:04:36 +00001693 spin_lock_irqsave(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001694
David Woodhouseaa21c002007-12-08 20:04:36 +00001695 if (priv->cur_cmd) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001696 lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
David Woodhouseaa21c002007-12-08 20:04:36 +00001697 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001698 ret = -1;
1699 goto done;
1700 }
1701
David Woodhouseaa21c002007-12-08 20:04:36 +00001702 if (!list_empty(&priv->cmdpendingq)) {
1703 cmdnode = list_first_entry(&priv->cmdpendingq,
Li Zefanabe3ed12007-12-06 13:01:21 +01001704 struct cmd_ctrl_node, list);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001705 }
1706
David Woodhouseaa21c002007-12-08 20:04:36 +00001707 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001708
1709 if (cmdnode) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001710 cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
1711
Dan Williams852e1f22007-12-10 15:24:47 -05001712 if (is_command_allowed_in_ps(le16_to_cpu(cmdptr->command))) {
David Woodhouseaa21c002007-12-08 20:04:36 +00001713 if ((priv->psstate == PS_STATE_SLEEP) ||
1714 (priv->psstate == PS_STATE_PRE_SLEEP)) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001715 lbs_deb_host(
1716 "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001717 le16_to_cpu(cmdptr->command),
David Woodhouseaa21c002007-12-08 20:04:36 +00001718 priv->psstate);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001719 ret = -1;
1720 goto done;
1721 }
Holger Schurig8ff12da2007-08-02 11:54:31 -04001722 lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1723 "0x%04x in psstate %d\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001724 le16_to_cpu(cmdptr->command),
David Woodhouseaa21c002007-12-08 20:04:36 +00001725 priv->psstate);
1726 } else if (priv->psstate != PS_STATE_FULL_POWER) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001727 /*
1728 * 1. Non-PS command:
1729 * Queue it. set needtowakeup to TRUE if current state
Holger Schurig10078322007-11-15 18:05:47 -05001730 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001731 * 2. PS command but not Exit_PS:
1732 * Ignore it.
1733 * 3. PS command Exit_PS:
1734 * Set needtowakeup to TRUE if current state is SLEEP,
1735 * otherwise send this command down to firmware
1736 * immediately.
1737 */
1738 if (cmdptr->command !=
Dan Williams0aef64d2007-08-02 11:31:18 -04001739 cpu_to_le16(CMD_802_11_PS_MODE)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001740 /* Prepare to send Exit PS,
1741 * this non PS command will be sent later */
David Woodhouseaa21c002007-12-08 20:04:36 +00001742 if ((priv->psstate == PS_STATE_SLEEP)
1743 || (priv->psstate == PS_STATE_PRE_SLEEP)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001744 ) {
1745 /* w/ new scheme, it will not reach here.
1746 since it is blocked in main_thread. */
David Woodhouseaa21c002007-12-08 20:04:36 +00001747 priv->needtowakeup = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001748 } else
Holger Schurig10078322007-11-15 18:05:47 -05001749 lbs_ps_wakeup(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001750
1751 ret = 0;
1752 goto done;
1753 } else {
1754 /*
1755 * PS command. Ignore it if it is not Exit_PS.
1756 * otherwise send it down immediately.
1757 */
1758 struct cmd_ds_802_11_ps_mode *psm =
1759 &cmdptr->params.psmode;
1760
Holger Schurig8ff12da2007-08-02 11:54:31 -04001761 lbs_deb_host(
1762 "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001763 psm->action);
1764 if (psm->action !=
Dan Williams0aef64d2007-08-02 11:31:18 -04001765 cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001766 lbs_deb_host(
1767 "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
Li Zefanabe3ed12007-12-06 13:01:21 +01001768 list_del(&cmdnode->list);
Holger Schurig10078322007-11-15 18:05:47 -05001769 lbs_cleanup_and_insert_cmd(priv, cmdnode);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001770
1771 ret = 0;
1772 goto done;
1773 }
1774
David Woodhouseaa21c002007-12-08 20:04:36 +00001775 if ((priv->psstate == PS_STATE_SLEEP) ||
1776 (priv->psstate == PS_STATE_PRE_SLEEP)) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001777 lbs_deb_host(
1778 "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
Li Zefanabe3ed12007-12-06 13:01:21 +01001779 list_del(&cmdnode->list);
Holger Schurig10078322007-11-15 18:05:47 -05001780 lbs_cleanup_and_insert_cmd(priv, cmdnode);
David Woodhouseaa21c002007-12-08 20:04:36 +00001781 priv->needtowakeup = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001782
1783 ret = 0;
1784 goto done;
1785 }
1786
Holger Schurig8ff12da2007-08-02 11:54:31 -04001787 lbs_deb_host(
1788 "EXEC_NEXT_CMD: sending EXIT_PS\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001789 }
1790 }
Li Zefanabe3ed12007-12-06 13:01:21 +01001791 list_del(&cmdnode->list);
Holger Schurig8ff12da2007-08-02 11:54:31 -04001792 lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
David Woodhouse981f1872007-05-25 23:36:54 -04001793 le16_to_cpu(cmdptr->command));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001794 DownloadcommandToStation(priv, cmdnode);
1795 } else {
1796 /*
1797 * check if in power save mode, if yes, put the device back
1798 * to PS mode
1799 */
David Woodhouseaa21c002007-12-08 20:04:36 +00001800 if ((priv->psmode != LBS802_11POWERMODECAM) &&
1801 (priv->psstate == PS_STATE_FULL_POWER) &&
1802 ((priv->connect_status == LBS_CONNECTED) ||
1803 (priv->mesh_connect_status == LBS_CONNECTED))) {
1804 if (priv->secinfo.WPAenabled ||
1805 priv->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001806 /* check for valid WPA group keys */
David Woodhouseaa21c002007-12-08 20:04:36 +00001807 if (priv->wpa_mcast_key.len ||
1808 priv->wpa_unicast_key.len) {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001809 lbs_deb_host(
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001810 "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
1811 " go back to PS_SLEEP");
Holger Schurig10078322007-11-15 18:05:47 -05001812 lbs_ps_sleep(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001813 }
1814 } else {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001815 lbs_deb_host(
1816 "EXEC_NEXT_CMD: cmdpendingq empty, "
1817 "go back to PS_SLEEP");
Holger Schurig10078322007-11-15 18:05:47 -05001818 lbs_ps_sleep(priv, 0);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001819 }
1820 }
1821 }
1822
1823 ret = 0;
1824done:
Holger Schurig8ff12da2007-08-02 11:54:31 -04001825 lbs_deb_leave(LBS_DEB_THREAD);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001826 return ret;
1827}
1828
Holger Schurig69f90322007-11-23 15:43:44 +01001829void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001830{
1831 union iwreq_data iwrq;
1832 u8 buf[50];
1833
Holger Schurig8ff12da2007-08-02 11:54:31 -04001834 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001835
1836 memset(&iwrq, 0, sizeof(union iwreq_data));
1837 memset(buf, 0, sizeof(buf));
1838
1839 snprintf(buf, sizeof(buf) - 1, "%s", str);
1840
1841 iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
1842
1843 /* Send Event to upper layer */
Holger Schurig8ff12da2007-08-02 11:54:31 -04001844 lbs_deb_wext("event indication string %s\n", (char *)buf);
1845 lbs_deb_wext("event indication length %d\n", iwrq.data.length);
1846 lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001847
Holger Schurig634b8f42007-05-25 13:05:16 -04001848 wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001849
Holger Schurig8ff12da2007-08-02 11:54:31 -04001850 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001851}
1852
Holger Schurig69f90322007-11-23 15:43:44 +01001853static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001854{
1855 unsigned long flags;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001856 int ret = 0;
1857
Holger Schurig8ff12da2007-08-02 11:54:31 -04001858 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001859
Holger Schurig8ff12da2007-08-02 11:54:31 -04001860 lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001861 size);
1862
Holger Schurig8ff12da2007-08-02 11:54:31 -04001863 lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001864
Holger Schurig208fdd22007-05-25 12:17:06 -04001865 ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
Holger Schurig634b8f42007-05-25 13:05:16 -04001866 priv->dnld_sent = DNLD_RES_RECEIVED;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001867
David Woodhouseaa21c002007-12-08 20:04:36 +00001868 spin_lock_irqsave(&priv->driver_lock, flags);
1869 if (priv->intcounter || priv->currenttxskb)
Holger Schurig8ff12da2007-08-02 11:54:31 -04001870 lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001871 priv->intcounter, priv->currenttxskb);
1872 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001873
1874 if (ret) {
1875 lbs_pr_alert(
1876 "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
1877 } else {
David Woodhouseaa21c002007-12-08 20:04:36 +00001878 spin_lock_irqsave(&priv->driver_lock, flags);
1879 if (!priv->intcounter) {
1880 priv->psstate = PS_STATE_SLEEP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001881 } else {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001882 lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001883 priv->intcounter);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001884 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001885 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001886
Holger Schurig8ff12da2007-08-02 11:54:31 -04001887 lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001888 }
1889
Holger Schurig8ff12da2007-08-02 11:54:31 -04001890 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001891 return ret;
1892}
1893
Holger Schurig69f90322007-11-23 15:43:44 +01001894void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001895{
Holger Schurig8ff12da2007-08-02 11:54:31 -04001896 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001897
1898 /*
1899 * PS is currently supported only in Infrastructure mode
1900 * Remove this check if it is to be supported in IBSS mode also
1901 */
1902
Holger Schurig10078322007-11-15 18:05:47 -05001903 lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
Dan Williams0aef64d2007-08-02 11:31:18 -04001904 CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001905
Holger Schurig8ff12da2007-08-02 11:54:31 -04001906 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001907}
1908
1909/**
Holger Schurig8ff12da2007-08-02 11:54:31 -04001910 * @brief This function sends Exit_PS command to firmware.
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001911 *
Holger Schurig69f90322007-11-23 15:43:44 +01001912 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001913 * @param wait_option wait response or not
1914 * @return n/a
1915 */
Holger Schurig69f90322007-11-23 15:43:44 +01001916void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001917{
David Woodhouse981f1872007-05-25 23:36:54 -04001918 __le32 Localpsmode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001919
Holger Schurig8ff12da2007-08-02 11:54:31 -04001920 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001921
Holger Schurig10078322007-11-15 18:05:47 -05001922 Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001923
Holger Schurig10078322007-11-15 18:05:47 -05001924 lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
Dan Williams0aef64d2007-08-02 11:31:18 -04001925 CMD_SUBCMD_EXIT_PS,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001926 wait_option, 0, &Localpsmode);
1927
Holger Schurig8ff12da2007-08-02 11:54:31 -04001928 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001929}
1930
1931/**
1932 * @brief This function checks condition and prepares to
1933 * send sleep confirm command to firmware if ok.
1934 *
Holger Schurig69f90322007-11-23 15:43:44 +01001935 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001936 * @param psmode Power Saving mode
1937 * @return n/a
1938 */
Holger Schurig69f90322007-11-23 15:43:44 +01001939void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001940{
1941 unsigned long flags =0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001942 u8 allowed = 1;
1943
Holger Schurig8ff12da2007-08-02 11:54:31 -04001944 lbs_deb_enter(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001945
Holger Schurig634b8f42007-05-25 13:05:16 -04001946 if (priv->dnld_sent) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001947 allowed = 0;
Holger Schurig8ff12da2007-08-02 11:54:31 -04001948 lbs_deb_host("dnld_sent was set");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001949 }
1950
David Woodhouseaa21c002007-12-08 20:04:36 +00001951 spin_lock_irqsave(&priv->driver_lock, flags);
1952 if (priv->cur_cmd) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001953 allowed = 0;
Holger Schurig8ff12da2007-08-02 11:54:31 -04001954 lbs_deb_host("cur_cmd was set");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001955 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001956 if (priv->intcounter > 0) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001957 allowed = 0;
David Woodhouseaa21c002007-12-08 20:04:36 +00001958 lbs_deb_host("intcounter %d", priv->intcounter);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001959 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001960 spin_unlock_irqrestore(&priv->driver_lock, flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001961
1962 if (allowed) {
Holger Schurig10078322007-11-15 18:05:47 -05001963 lbs_deb_host("sending lbs_ps_confirm_sleep\n");
David Woodhouseaa21c002007-12-08 20:04:36 +00001964 sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001965 sizeof(struct PS_CMD_ConfirmSleep));
1966 } else {
Holger Schurig8ff12da2007-08-02 11:54:31 -04001967 lbs_deb_host("sleep confirm has been delayed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001968 }
1969
Holger Schurig8ff12da2007-08-02 11:54:31 -04001970 lbs_deb_leave(LBS_DEB_HOST);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001971}
Holger Schurig675787e2007-12-05 17:58:11 +01001972
1973
1974/**
1975 * @brief Simple way to call firmware functions
1976 *
1977 * @param priv A pointer to struct lbs_private structure
1978 * @param psmode one of the many CMD_802_11_xxxx
1979 * @param cmd pointer to the parameters structure for above command
1980 * (this should not include the command, size, sequence
1981 * and result fields from struct cmd_ds_gen)
1982 * @param cmd_size size structure pointed to by cmd
1983 * @param rsp pointer to an area where the result should be placed
1984 * @param rsp_size pointer to the size of the rsp area. If the firmware
1985 * returns fewer bytes, then this *rsp_size will be
1986 * changed to the actual size.
1987 * @return -1 in case of a higher level error, otherwise
1988 * the result code from the firmware
1989 */
David Woodhouse17230472007-12-07 15:13:05 +00001990
Dan Williams14e865b2007-12-10 15:11:23 -05001991int __lbs_cmd(struct lbs_private *priv, uint16_t command, void *cmd, int cmd_size,
1992 int (*callback)(struct lbs_private *, unsigned long, struct cmd_ds_command *),
1993 unsigned long callback_arg)
Holger Schurig675787e2007-12-05 17:58:11 +01001994{
Holger Schurig675787e2007-12-05 17:58:11 +01001995 struct cmd_ctrl_node *cmdnode;
1996 struct cmd_ds_gen *cmdptr;
1997 unsigned long flags;
1998 int ret = 0;
1999
2000 lbs_deb_enter(LBS_DEB_HOST);
Holger Schurig675787e2007-12-05 17:58:11 +01002001
David Woodhouseaa21c002007-12-08 20:04:36 +00002002 if (!priv) {
2003 lbs_deb_host("PREP_CMD: priv is NULL\n");
Holger Schurig675787e2007-12-05 17:58:11 +01002004 ret = -1;
2005 goto done;
2006 }
2007
David Woodhouseaa21c002007-12-08 20:04:36 +00002008 if (priv->surpriseremoved) {
Holger Schurig675787e2007-12-05 17:58:11 +01002009 lbs_deb_host("PREP_CMD: card removed\n");
2010 ret = -1;
2011 goto done;
2012 }
2013
2014 cmdnode = lbs_get_cmd_ctrl_node(priv);
2015
2016 if (cmdnode == NULL) {
2017 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
2018
2019 /* Wake up main thread to execute next command */
2020 wake_up_interruptible(&priv->waitq);
2021 ret = -1;
2022 goto done;
2023 }
2024
2025 cmdptr = (struct cmd_ds_gen *)cmdnode->bufvirtualaddr;
2026 cmdnode->wait_option = CMD_OPTION_WAITFORRSP;
David Woodhouse448a51a2007-12-08 00:59:54 +00002027 cmdnode->callback = callback;
David Woodhouse1309b552007-12-10 13:36:10 -05002028 cmdnode->callback_arg = callback_arg;
Holger Schurig675787e2007-12-05 17:58:11 +01002029
2030 /* Set sequence number, clean result, move to buffer */
David Woodhouseaa21c002007-12-08 20:04:36 +00002031 priv->seqnum++;
Holger Schurig675787e2007-12-05 17:58:11 +01002032 cmdptr->command = cpu_to_le16(command);
David Woodhouse6228c0a2007-12-06 12:38:31 +00002033 cmdptr->size = cpu_to_le16(cmd_size + S_DS_GEN);
David Woodhouseaa21c002007-12-08 20:04:36 +00002034 cmdptr->seqnum = cpu_to_le16(priv->seqnum);
Holger Schurig675787e2007-12-05 17:58:11 +01002035 cmdptr->result = 0;
2036 memcpy(cmdptr->cmdresp, cmd, cmd_size);
2037
2038 lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
2039
2040 /* here was the big old switch() statement, which is now obsolete,
2041 * because the caller of lbs_cmd() sets up all of *cmd for us. */
2042
2043 cmdnode->cmdwaitqwoken = 0;
David Woodhouseaa21c002007-12-08 20:04:36 +00002044 lbs_queue_cmd(priv, cmdnode, 1);
Holger Schurig675787e2007-12-05 17:58:11 +01002045 wake_up_interruptible(&priv->waitq);
2046
2047 might_sleep();
2048 wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
2049
David Woodhouseaa21c002007-12-08 20:04:36 +00002050 spin_lock_irqsave(&priv->driver_lock, flags);
2051 if (priv->cur_cmd_retcode) {
Holger Schurig675787e2007-12-05 17:58:11 +01002052 lbs_deb_host("PREP_CMD: command failed with return code %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00002053 priv->cur_cmd_retcode);
2054 priv->cur_cmd_retcode = 0;
Holger Schurig675787e2007-12-05 17:58:11 +01002055 ret = -1;
2056 }
David Woodhouseaa21c002007-12-08 20:04:36 +00002057 spin_unlock_irqrestore(&priv->driver_lock, flags);
Holger Schurig675787e2007-12-05 17:58:11 +01002058
2059done:
2060 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
2061 return ret;
2062}
Dan Williams14e865b2007-12-10 15:11:23 -05002063EXPORT_SYMBOL_GPL(__lbs_cmd);
Holger Schurig675787e2007-12-05 17:58:11 +01002064
2065