0001
0002
0003
0004
0005
0006
0007 #include <linux/hardirq.h>
0008 #include <linux/kfifo.h>
0009 #include <linux/sched.h>
0010 #include <linux/slab.h>
0011 #include <linux/if_arp.h>
0012 #include <linux/export.h>
0013
0014 #include "decl.h"
0015 #include "cfg.h"
0016 #include "cmd.h"
0017
0018 #define CAL_NF(nf) ((s32)(-(s32)(nf)))
0019 #define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf)))
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
0032 struct cmd_header *resp)
0033 {
0034 struct cmd_header *buf = (void *)extra;
0035 uint16_t copy_len;
0036
0037 copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
0038 memcpy(buf, resp, copy_len);
0039 return 0;
0040 }
0041 EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
0055 struct cmd_header *resp)
0056 {
0057 return 0;
0058 }
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 static u8 is_command_allowed_in_ps(u16 cmd)
0069 {
0070 switch (cmd) {
0071 case CMD_802_11_RSSI:
0072 return 1;
0073 case CMD_802_11_HOST_SLEEP_CFG:
0074 return 1;
0075 default:
0076 break;
0077 }
0078 return 0;
0079 }
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 int lbs_update_hw_spec(struct lbs_private *priv)
0090 {
0091 struct cmd_ds_get_hw_spec cmd;
0092 int ret = -1;
0093 u32 i;
0094
0095 memset(&cmd, 0, sizeof(cmd));
0096 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0097 memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
0098 ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
0099 if (ret)
0100 goto out;
0101
0102 priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
0103
0104
0105
0106 priv->fwrelease = le32_to_cpu(cmd.fwrelease);
0107 priv->fwrelease = (priv->fwrelease << 8) |
0108 (priv->fwrelease >> 24 & 0xff);
0109
0110
0111
0112
0113
0114 netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n",
0115 cmd.permanentaddr,
0116 priv->fwrelease >> 24 & 0xff,
0117 priv->fwrelease >> 16 & 0xff,
0118 priv->fwrelease >> 8 & 0xff,
0119 priv->fwrelease & 0xff,
0120 priv->fwcapinfo);
0121 lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
0122 cmd.hwifversion, cmd.version);
0123
0124
0125
0126
0127
0128
0129
0130
0131 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V4)
0132 priv->regioncode = (le16_to_cpu(cmd.regioncode) >> 8) & 0xFF;
0133 else
0134 priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
0135
0136 for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
0137
0138 if (priv->regioncode == lbs_region_code_to_index[i])
0139 break;
0140 }
0141
0142
0143 if (i >= MRVDRV_MAX_REGION_CODE) {
0144 priv->regioncode = 0x10;
0145 netdev_info(priv->dev,
0146 "unidentified region code; using the default (USA)\n");
0147 }
0148
0149 if (priv->current_addr[0] == 0xff)
0150 memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
0151
0152 if (!priv->copied_hwaddr) {
0153 eth_hw_addr_set(priv->dev, priv->current_addr);
0154 if (priv->mesh_dev)
0155 eth_hw_addr_set(priv->mesh_dev, priv->current_addr);
0156 priv->copied_hwaddr = 1;
0157 }
0158
0159 out:
0160 return ret;
0161 }
0162
0163 static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
0164 struct cmd_header *resp)
0165 {
0166 if (priv->is_host_sleep_activated) {
0167 priv->is_host_sleep_configured = 0;
0168 if (priv->psstate == PS_STATE_FULL_POWER) {
0169 priv->is_host_sleep_activated = 0;
0170 wake_up_interruptible(&priv->host_sleep_q);
0171 }
0172 } else {
0173 priv->is_host_sleep_configured = 1;
0174 }
0175
0176 return 0;
0177 }
0178
0179 int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
0180 struct wol_config *p_wol_config)
0181 {
0182 struct cmd_ds_host_sleep cmd_config;
0183 int ret;
0184
0185
0186
0187
0188
0189
0190 if (criteria == EHS_REMOVE_WAKEUP && !priv->ehs_remove_supported)
0191 criteria = 0;
0192
0193 cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
0194 cmd_config.criteria = cpu_to_le32(criteria);
0195 cmd_config.gpio = priv->wol_gpio;
0196 cmd_config.gap = priv->wol_gap;
0197
0198 if (p_wol_config != NULL)
0199 memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config,
0200 sizeof(struct wol_config));
0201 else
0202 cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
0203
0204 ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
0205 le16_to_cpu(cmd_config.hdr.size),
0206 lbs_ret_host_sleep_cfg, 0);
0207 if (!ret) {
0208 if (p_wol_config)
0209 memcpy((uint8_t *) p_wol_config,
0210 (uint8_t *)&cmd_config.wol_conf,
0211 sizeof(struct wol_config));
0212 } else {
0213 netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret);
0214 }
0215
0216 return ret;
0217 }
0218 EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230 int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
0231 {
0232 struct cmd_ds_802_11_ps_mode cmd;
0233 int ret = 0;
0234
0235 memset(&cmd, 0, sizeof(cmd));
0236 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0237 cmd.action = cpu_to_le16(cmd_action);
0238
0239 if (cmd_action == PS_MODE_ACTION_ENTER_PS) {
0240 lbs_deb_cmd("PS_MODE: action ENTER_PS\n");
0241 cmd.multipledtim = cpu_to_le16(1);
0242 } else if (cmd_action == PS_MODE_ACTION_EXIT_PS) {
0243 lbs_deb_cmd("PS_MODE: action EXIT_PS\n");
0244 } else {
0245
0246
0247
0248 lbs_deb_cmd("PS_MODE: unknown action 0x%X\n", cmd_action);
0249 ret = -EOPNOTSUPP;
0250 goto out;
0251 }
0252
0253 if (block)
0254 ret = lbs_cmd_with_response(priv, CMD_802_11_PS_MODE, &cmd);
0255 else
0256 lbs_cmd_async(priv, CMD_802_11_PS_MODE, &cmd.hdr, sizeof (cmd));
0257
0258 out:
0259 return ret;
0260 }
0261
0262 int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
0263 struct sleep_params *sp)
0264 {
0265 struct cmd_ds_802_11_sleep_params cmd;
0266 int ret;
0267
0268 if (cmd_action == CMD_ACT_GET) {
0269 memset(&cmd, 0, sizeof(cmd));
0270 } else {
0271 cmd.error = cpu_to_le16(sp->sp_error);
0272 cmd.offset = cpu_to_le16(sp->sp_offset);
0273 cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
0274 cmd.calcontrol = sp->sp_calcontrol;
0275 cmd.externalsleepclk = sp->sp_extsleepclk;
0276 cmd.reserved = cpu_to_le16(sp->sp_reserved);
0277 }
0278 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0279 cmd.action = cpu_to_le16(cmd_action);
0280
0281 ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);
0282
0283 if (!ret) {
0284 lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
0285 "calcontrol 0x%x extsleepclk 0x%x\n",
0286 le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
0287 le16_to_cpu(cmd.stabletime), cmd.calcontrol,
0288 cmd.externalsleepclk);
0289
0290 sp->sp_error = le16_to_cpu(cmd.error);
0291 sp->sp_offset = le16_to_cpu(cmd.offset);
0292 sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
0293 sp->sp_calcontrol = cmd.calcontrol;
0294 sp->sp_extsleepclk = cmd.externalsleepclk;
0295 sp->sp_reserved = le16_to_cpu(cmd.reserved);
0296 }
0297
0298 return ret;
0299 }
0300
0301 static int lbs_wait_for_ds_awake(struct lbs_private *priv)
0302 {
0303 int ret = 0;
0304
0305 if (priv->is_deep_sleep) {
0306 if (!wait_event_interruptible_timeout(priv->ds_awake_q,
0307 !priv->is_deep_sleep, (10 * HZ))) {
0308 netdev_err(priv->dev, "ds_awake_q: timer expired\n");
0309 ret = -1;
0310 }
0311 }
0312
0313 return ret;
0314 }
0315
0316 int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
0317 {
0318 int ret = 0;
0319
0320 if (deep_sleep) {
0321 if (priv->is_deep_sleep != 1) {
0322 lbs_deb_cmd("deep sleep: sleep\n");
0323 BUG_ON(!priv->enter_deep_sleep);
0324 ret = priv->enter_deep_sleep(priv);
0325 if (!ret) {
0326 netif_stop_queue(priv->dev);
0327 netif_carrier_off(priv->dev);
0328 }
0329 } else {
0330 netdev_err(priv->dev, "deep sleep: already enabled\n");
0331 }
0332 } else {
0333 if (priv->is_deep_sleep) {
0334 lbs_deb_cmd("deep sleep: wakeup\n");
0335 BUG_ON(!priv->exit_deep_sleep);
0336 ret = priv->exit_deep_sleep(priv);
0337 if (!ret) {
0338 ret = lbs_wait_for_ds_awake(priv);
0339 if (ret)
0340 netdev_err(priv->dev,
0341 "deep sleep: wakeup failed\n");
0342 }
0343 }
0344 }
0345
0346 return ret;
0347 }
0348
0349 static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
0350 unsigned long dummy,
0351 struct cmd_header *cmd)
0352 {
0353 priv->is_host_sleep_activated = 1;
0354 wake_up_interruptible(&priv->host_sleep_q);
0355
0356 return 0;
0357 }
0358
0359 int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
0360 {
0361 struct cmd_header cmd;
0362 int ret = 0;
0363 uint32_t criteria = EHS_REMOVE_WAKEUP;
0364
0365 if (host_sleep) {
0366 if (priv->is_host_sleep_activated != 1) {
0367 memset(&cmd, 0, sizeof(cmd));
0368 ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
0369 (struct wol_config *)NULL);
0370 if (ret) {
0371 netdev_info(priv->dev,
0372 "Host sleep configuration failed: %d\n",
0373 ret);
0374 return ret;
0375 }
0376 if (priv->psstate == PS_STATE_FULL_POWER) {
0377 ret = __lbs_cmd(priv,
0378 CMD_802_11_HOST_SLEEP_ACTIVATE,
0379 &cmd,
0380 sizeof(cmd),
0381 lbs_ret_host_sleep_activate, 0);
0382 if (ret)
0383 netdev_info(priv->dev,
0384 "HOST_SLEEP_ACTIVATE failed: %d\n",
0385 ret);
0386 }
0387
0388 if (!wait_event_interruptible_timeout(
0389 priv->host_sleep_q,
0390 priv->is_host_sleep_activated,
0391 (10 * HZ))) {
0392 netdev_err(priv->dev,
0393 "host_sleep_q: timer expired\n");
0394 ret = -1;
0395 }
0396 } else {
0397 netdev_err(priv->dev, "host sleep: already enabled\n");
0398 }
0399 } else {
0400 if (priv->is_host_sleep_activated)
0401 ret = lbs_host_sleep_cfg(priv, criteria,
0402 (struct wol_config *)NULL);
0403 }
0404
0405 return ret;
0406 }
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417 int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
0418 {
0419 struct cmd_ds_802_11_snmp_mib cmd;
0420 int ret;
0421
0422 memset(&cmd, 0, sizeof (cmd));
0423 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0424 cmd.action = cpu_to_le16(CMD_ACT_SET);
0425 cmd.oid = cpu_to_le16((u16) oid);
0426
0427 switch (oid) {
0428 case SNMP_MIB_OID_BSS_TYPE:
0429 cmd.bufsize = cpu_to_le16(sizeof(u8));
0430 cmd.value[0] = val;
0431 break;
0432 case SNMP_MIB_OID_11D_ENABLE:
0433 case SNMP_MIB_OID_FRAG_THRESHOLD:
0434 case SNMP_MIB_OID_RTS_THRESHOLD:
0435 case SNMP_MIB_OID_SHORT_RETRY_LIMIT:
0436 case SNMP_MIB_OID_LONG_RETRY_LIMIT:
0437 cmd.bufsize = cpu_to_le16(sizeof(u16));
0438 *((__le16 *)(&cmd.value)) = cpu_to_le16(val);
0439 break;
0440 default:
0441 lbs_deb_cmd("SNMP_CMD: (set) unhandled OID 0x%x\n", oid);
0442 ret = -EINVAL;
0443 goto out;
0444 }
0445
0446 lbs_deb_cmd("SNMP_CMD: (set) oid 0x%x, oid size 0x%x, value 0x%x\n",
0447 le16_to_cpu(cmd.oid), le16_to_cpu(cmd.bufsize), val);
0448
0449 ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
0450
0451 out:
0452 return ret;
0453 }
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464 int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
0465 {
0466 struct cmd_ds_802_11_snmp_mib cmd;
0467 int ret;
0468
0469 memset(&cmd, 0, sizeof (cmd));
0470 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0471 cmd.action = cpu_to_le16(CMD_ACT_GET);
0472 cmd.oid = cpu_to_le16(oid);
0473
0474 ret = lbs_cmd_with_response(priv, CMD_802_11_SNMP_MIB, &cmd);
0475 if (ret)
0476 goto out;
0477
0478 switch (le16_to_cpu(cmd.bufsize)) {
0479 case sizeof(u8):
0480 *out_val = cmd.value[0];
0481 break;
0482 case sizeof(u16):
0483 *out_val = le16_to_cpu(*((__le16 *)(&cmd.value)));
0484 break;
0485 default:
0486 lbs_deb_cmd("SNMP_CMD: (get) unhandled OID 0x%x size %d\n",
0487 oid, le16_to_cpu(cmd.bufsize));
0488 break;
0489 }
0490
0491 out:
0492 return ret;
0493 }
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505 int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
0506 s16 *maxlevel)
0507 {
0508 struct cmd_ds_802_11_rf_tx_power cmd;
0509 int ret;
0510
0511 memset(&cmd, 0, sizeof(cmd));
0512 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0513 cmd.action = cpu_to_le16(CMD_ACT_GET);
0514
0515 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
0516 if (ret == 0) {
0517 *curlevel = le16_to_cpu(cmd.curlevel);
0518 if (minlevel)
0519 *minlevel = cmd.minlevel;
0520 if (maxlevel)
0521 *maxlevel = cmd.maxlevel;
0522 }
0523
0524 return ret;
0525 }
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535 int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
0536 {
0537 struct cmd_ds_802_11_rf_tx_power cmd;
0538 int ret;
0539
0540 memset(&cmd, 0, sizeof(cmd));
0541 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0542 cmd.action = cpu_to_le16(CMD_ACT_SET);
0543 cmd.curlevel = cpu_to_le16(dbm);
0544
0545 lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm);
0546
0547 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd);
0548
0549 return ret;
0550 }
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561 int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
0562 {
0563 struct cmd_ds_802_11_monitor_mode cmd;
0564 int ret;
0565
0566 memset(&cmd, 0, sizeof(cmd));
0567 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0568 cmd.action = cpu_to_le16(CMD_ACT_SET);
0569 if (enable)
0570 cmd.mode = cpu_to_le16(0x1);
0571
0572 lbs_deb_cmd("SET_MONITOR_MODE: %d\n", enable);
0573
0574 ret = lbs_cmd_with_response(priv, CMD_802_11_MONITOR_MODE, &cmd);
0575 if (ret == 0) {
0576 priv->dev->type = enable ? ARPHRD_IEEE80211_RADIOTAP :
0577 ARPHRD_ETHER;
0578 }
0579
0580 return ret;
0581 }
0582
0583
0584
0585
0586
0587
0588
0589
0590 static int lbs_get_channel(struct lbs_private *priv)
0591 {
0592 struct cmd_ds_802_11_rf_channel cmd;
0593 int ret = 0;
0594
0595 memset(&cmd, 0, sizeof(cmd));
0596 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0597 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
0598
0599 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
0600 if (ret)
0601 goto out;
0602
0603 ret = le16_to_cpu(cmd.channel);
0604 lbs_deb_cmd("current radio channel is %d\n", ret);
0605
0606 out:
0607 return ret;
0608 }
0609
0610 int lbs_update_channel(struct lbs_private *priv)
0611 {
0612 int ret;
0613
0614
0615 ret = lbs_get_channel(priv);
0616 if (ret > 0) {
0617 priv->channel = ret;
0618 ret = 0;
0619 }
0620
0621 return ret;
0622 }
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632 int lbs_set_channel(struct lbs_private *priv, u8 channel)
0633 {
0634 struct cmd_ds_802_11_rf_channel cmd;
0635 #ifdef DEBUG
0636 u8 old_channel = priv->channel;
0637 #endif
0638 int ret = 0;
0639
0640 memset(&cmd, 0, sizeof(cmd));
0641 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0642 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
0643 cmd.channel = cpu_to_le16(channel);
0644
0645 ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
0646 if (ret)
0647 goto out;
0648
0649 priv->channel = (uint8_t) le16_to_cpu(cmd.channel);
0650 lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
0651 priv->channel);
0652
0653 out:
0654 return ret;
0655 }
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666 int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
0667 {
0668 struct cmd_ds_802_11_rssi cmd;
0669 int ret = 0;
0670
0671 BUG_ON(rssi == NULL);
0672 BUG_ON(nf == NULL);
0673
0674 memset(&cmd, 0, sizeof(cmd));
0675 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0676
0677 cmd.n_or_snr = cpu_to_le16(8);
0678
0679 ret = lbs_cmd_with_response(priv, CMD_802_11_RSSI, &cmd);
0680 if (ret == 0) {
0681 *nf = CAL_NF(le16_to_cpu(cmd.nf));
0682 *rssi = CAL_RSSI(le16_to_cpu(cmd.n_or_snr), le16_to_cpu(cmd.nf));
0683 }
0684
0685 return ret;
0686 }
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696 int lbs_set_11d_domain_info(struct lbs_private *priv)
0697 {
0698 struct wiphy *wiphy = priv->wdev->wiphy;
0699 struct ieee80211_supported_band **bands = wiphy->bands;
0700 struct cmd_ds_802_11d_domain_info cmd;
0701 struct mrvl_ie_domain_param_set *domain = &cmd.domain;
0702 struct ieee80211_country_ie_triplet *t;
0703 enum nl80211_band band;
0704 struct ieee80211_channel *ch;
0705 u8 num_triplet = 0;
0706 u8 num_parsed_chan = 0;
0707 u8 first_channel = 0, next_chan = 0, max_pwr = 0;
0708 u8 i, flag = 0;
0709 size_t triplet_size;
0710 int ret = 0;
0711
0712 if (!priv->country_code[0])
0713 goto out;
0714
0715 memset(&cmd, 0, sizeof(cmd));
0716 cmd.action = cpu_to_le16(CMD_ACT_SET);
0717
0718 lbs_deb_11d("Setting country code '%c%c'\n",
0719 priv->country_code[0], priv->country_code[1]);
0720
0721 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
0722
0723
0724 domain->country_code[0] = priv->country_code[0];
0725 domain->country_code[1] = priv->country_code[1];
0726 domain->country_code[2] = ' ';
0727
0728
0729
0730
0731
0732
0733
0734
0735 for (band = 0;
0736 (band < NUM_NL80211_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
0737 band++) {
0738
0739 if (!bands[band])
0740 continue;
0741
0742 for (i = 0;
0743 (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
0744 i++) {
0745 ch = &bands[band]->channels[i];
0746 if (ch->flags & IEEE80211_CHAN_DISABLED)
0747 continue;
0748
0749 if (!flag) {
0750 flag = 1;
0751 next_chan = first_channel = (u32) ch->hw_value;
0752 max_pwr = ch->max_power;
0753 num_parsed_chan = 1;
0754 continue;
0755 }
0756
0757 if ((ch->hw_value == next_chan + 1) &&
0758 (ch->max_power == max_pwr)) {
0759
0760 next_chan++;
0761 num_parsed_chan++;
0762 } else {
0763
0764 lbs_deb_11d("11D triplet (%d, %d, %d)\n",
0765 first_channel, num_parsed_chan,
0766 max_pwr);
0767 t = &domain->triplet[num_triplet];
0768 t->chans.first_channel = first_channel;
0769 t->chans.num_channels = num_parsed_chan;
0770 t->chans.max_power = max_pwr;
0771 num_triplet++;
0772 flag = 0;
0773 }
0774 }
0775
0776 if (flag) {
0777
0778 lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
0779 num_parsed_chan, max_pwr);
0780 t = &domain->triplet[num_triplet];
0781 t->chans.first_channel = first_channel;
0782 t->chans.num_channels = num_parsed_chan;
0783 t->chans.max_power = max_pwr;
0784 num_triplet++;
0785 }
0786 }
0787
0788 lbs_deb_11d("# triplets %d\n", num_triplet);
0789
0790
0791 triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
0792 domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
0793 triplet_size);
0794
0795 lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
0796 (u8 *) &cmd.domain.country_code,
0797 le16_to_cpu(domain->header.len));
0798
0799 cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
0800 sizeof(cmd.action) +
0801 sizeof(cmd.domain.header) +
0802 sizeof(cmd.domain.country_code) +
0803 triplet_size);
0804
0805 ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);
0806
0807 out:
0808 return ret;
0809 }
0810
0811
0812
0813
0814
0815
0816
0817
0818
0819
0820
0821
0822 int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
0823 {
0824 struct cmd_ds_reg_access cmd;
0825 int ret = 0;
0826
0827 BUG_ON(value == NULL);
0828
0829 memset(&cmd, 0, sizeof(cmd));
0830 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0831 cmd.action = cpu_to_le16(CMD_ACT_GET);
0832 cmd.offset = cpu_to_le16(offset);
0833
0834 if (reg != CMD_MAC_REG_ACCESS &&
0835 reg != CMD_BBP_REG_ACCESS &&
0836 reg != CMD_RF_REG_ACCESS) {
0837 ret = -EINVAL;
0838 goto out;
0839 }
0840
0841 ret = lbs_cmd_with_response(priv, reg, &cmd);
0842 if (!ret) {
0843 if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
0844 *value = cmd.value.bbp_rf;
0845 else if (reg == CMD_MAC_REG_ACCESS)
0846 *value = le32_to_cpu(cmd.value.mac);
0847 }
0848
0849 out:
0850 return ret;
0851 }
0852
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864 int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
0865 {
0866 struct cmd_ds_reg_access cmd;
0867 int ret = 0;
0868
0869 memset(&cmd, 0, sizeof(cmd));
0870 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0871 cmd.action = cpu_to_le16(CMD_ACT_SET);
0872 cmd.offset = cpu_to_le16(offset);
0873
0874 if (reg == CMD_BBP_REG_ACCESS || reg == CMD_RF_REG_ACCESS)
0875 cmd.value.bbp_rf = (u8) (value & 0xFF);
0876 else if (reg == CMD_MAC_REG_ACCESS)
0877 cmd.value.mac = cpu_to_le32(value);
0878 else {
0879 ret = -EINVAL;
0880 goto out;
0881 }
0882
0883 ret = lbs_cmd_with_response(priv, reg, &cmd);
0884
0885 out:
0886 return ret;
0887 }
0888
0889 static void lbs_queue_cmd(struct lbs_private *priv,
0890 struct cmd_ctrl_node *cmdnode)
0891 {
0892 unsigned long flags;
0893 int addtail = 1;
0894
0895 if (!cmdnode) {
0896 lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
0897 return;
0898 }
0899 if (!cmdnode->cmdbuf->size) {
0900 lbs_deb_host("DNLD_CMD: cmd size is zero\n");
0901 return;
0902 }
0903 cmdnode->result = 0;
0904
0905
0906 if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
0907 struct cmd_ds_802_11_ps_mode *psm = (void *)cmdnode->cmdbuf;
0908
0909 if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
0910 if (priv->psstate != PS_STATE_FULL_POWER)
0911 addtail = 0;
0912 }
0913 }
0914
0915 if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_WAKEUP_CONFIRM)
0916 addtail = 0;
0917
0918 spin_lock_irqsave(&priv->driver_lock, flags);
0919
0920 if (addtail)
0921 list_add_tail(&cmdnode->list, &priv->cmdpendingq);
0922 else
0923 list_add(&cmdnode->list, &priv->cmdpendingq);
0924
0925 spin_unlock_irqrestore(&priv->driver_lock, flags);
0926
0927 lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
0928 le16_to_cpu(cmdnode->cmdbuf->command));
0929 }
0930
0931 static void lbs_submit_command(struct lbs_private *priv,
0932 struct cmd_ctrl_node *cmdnode)
0933 {
0934 unsigned long flags;
0935 struct cmd_header *cmd;
0936 uint16_t cmdsize;
0937 uint16_t command;
0938 int timeo = 3 * HZ;
0939 int ret;
0940
0941 cmd = cmdnode->cmdbuf;
0942
0943 spin_lock_irqsave(&priv->driver_lock, flags);
0944 priv->seqnum++;
0945 cmd->seqnum = cpu_to_le16(priv->seqnum);
0946 priv->cur_cmd = cmdnode;
0947 spin_unlock_irqrestore(&priv->driver_lock, flags);
0948
0949 cmdsize = le16_to_cpu(cmd->size);
0950 command = le16_to_cpu(cmd->command);
0951
0952
0953 if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
0954 timeo = 5 * HZ;
0955
0956 lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
0957 command, le16_to_cpu(cmd->seqnum), cmdsize);
0958 lbs_deb_hex(LBS_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
0959
0960 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
0961
0962 if (ret) {
0963 netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n",
0964 ret);
0965
0966 priv->dnld_sent = DNLD_RES_RECEIVED;
0967 lbs_complete_command(priv, cmdnode, ret);
0968 }
0969
0970 if (command == CMD_802_11_DEEP_SLEEP) {
0971 if (priv->is_auto_deep_sleep_enabled) {
0972 priv->wakeup_dev_required = 1;
0973 priv->dnld_sent = 0;
0974 }
0975 priv->is_deep_sleep = 1;
0976 lbs_complete_command(priv, cmdnode, 0);
0977 } else {
0978
0979 mod_timer(&priv->command_timer, jiffies + timeo);
0980 }
0981 }
0982
0983
0984
0985
0986
0987 static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
0988 struct cmd_ctrl_node *cmdnode)
0989 {
0990 if (!cmdnode)
0991 return;
0992
0993 cmdnode->callback = NULL;
0994 cmdnode->callback_arg = 0;
0995
0996 memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
0997
0998 list_add_tail(&cmdnode->list, &priv->cmdfreeq);
0999 }
1000
1001 static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
1002 struct cmd_ctrl_node *ptempcmd)
1003 {
1004 unsigned long flags;
1005
1006 spin_lock_irqsave(&priv->driver_lock, flags);
1007 __lbs_cleanup_and_insert_cmd(priv, ptempcmd);
1008 spin_unlock_irqrestore(&priv->driver_lock, flags);
1009 }
1010
1011 void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
1012 int result)
1013 {
1014
1015
1016
1017
1018
1019
1020 list_del_init(&cmd->list);
1021
1022 cmd->result = result;
1023 cmd->cmdwaitqwoken = 1;
1024 wake_up(&cmd->cmdwait_q);
1025
1026 if (!cmd->callback || cmd->callback == lbs_cmd_async_callback)
1027 __lbs_cleanup_and_insert_cmd(priv, cmd);
1028 priv->cur_cmd = NULL;
1029 wake_up(&priv->waitq);
1030 }
1031
1032 void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
1033 int result)
1034 {
1035 unsigned long flags;
1036 spin_lock_irqsave(&priv->driver_lock, flags);
1037 __lbs_complete_command(priv, cmd, result);
1038 spin_unlock_irqrestore(&priv->driver_lock, flags);
1039 }
1040
1041 int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on)
1042 {
1043 struct cmd_ds_802_11_radio_control cmd;
1044 int ret = -EINVAL;
1045
1046 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1047 cmd.action = cpu_to_le16(CMD_ACT_SET);
1048 cmd.control = 0;
1049
1050
1051 if (priv->fwrelease < 0x09000000) {
1052 switch (preamble) {
1053 case RADIO_PREAMBLE_SHORT:
1054 case RADIO_PREAMBLE_AUTO:
1055 case RADIO_PREAMBLE_LONG:
1056 cmd.control = cpu_to_le16(preamble);
1057 break;
1058 default:
1059 goto out;
1060 }
1061 }
1062
1063 if (radio_on)
1064 cmd.control |= cpu_to_le16(0x1);
1065 else {
1066 cmd.control &= cpu_to_le16(~0x1);
1067 priv->txpower_cur = 0;
1068 }
1069
1070 lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n",
1071 radio_on ? "ON" : "OFF", preamble);
1072
1073 priv->radio_on = radio_on;
1074
1075 ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
1076
1077 out:
1078 return ret;
1079 }
1080
1081 void lbs_set_mac_control(struct lbs_private *priv)
1082 {
1083 struct cmd_ds_mac_control cmd;
1084
1085 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1086 cmd.action = cpu_to_le16(priv->mac_control);
1087 cmd.reserved = 0;
1088
1089 lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
1090 }
1091
1092 int lbs_set_mac_control_sync(struct lbs_private *priv)
1093 {
1094 struct cmd_ds_mac_control cmd;
1095 int ret = 0;
1096
1097 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1098 cmd.action = cpu_to_le16(priv->mac_control);
1099 cmd.reserved = 0;
1100 ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd);
1101
1102 return ret;
1103 }
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113 int lbs_allocate_cmd_buffer(struct lbs_private *priv)
1114 {
1115 int ret = 0;
1116 u32 bufsize;
1117 u32 i;
1118 struct cmd_ctrl_node *cmdarray;
1119
1120
1121 bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
1122 if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
1123 lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
1124 ret = -1;
1125 goto done;
1126 }
1127 priv->cmd_array = cmdarray;
1128
1129
1130 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1131 cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
1132 if (!cmdarray[i].cmdbuf) {
1133 lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
1134 ret = -1;
1135 goto done;
1136 }
1137 }
1138
1139 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1140 init_waitqueue_head(&cmdarray[i].cmdwait_q);
1141 lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
1142 }
1143 ret = 0;
1144
1145 done:
1146 return ret;
1147 }
1148
1149
1150
1151
1152
1153
1154
1155
1156 int lbs_free_cmd_buffer(struct lbs_private *priv)
1157 {
1158 struct cmd_ctrl_node *cmdarray;
1159 unsigned int i;
1160
1161
1162 if (priv->cmd_array == NULL) {
1163 lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
1164 goto done;
1165 }
1166
1167 cmdarray = priv->cmd_array;
1168
1169
1170 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
1171 if (cmdarray[i].cmdbuf) {
1172 kfree(cmdarray[i].cmdbuf);
1173 cmdarray[i].cmdbuf = NULL;
1174 }
1175 }
1176
1177
1178 if (priv->cmd_array) {
1179 kfree(priv->cmd_array);
1180 priv->cmd_array = NULL;
1181 }
1182
1183 done:
1184 return 0;
1185 }
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196 static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
1197 {
1198 struct cmd_ctrl_node *tempnode;
1199 unsigned long flags;
1200
1201 if (!priv)
1202 return NULL;
1203
1204 spin_lock_irqsave(&priv->driver_lock, flags);
1205
1206 if (!list_empty(&priv->cmdfreeq)) {
1207 tempnode = list_first_entry(&priv->cmdfreeq,
1208 struct cmd_ctrl_node, list);
1209 list_del_init(&tempnode->list);
1210 } else {
1211 lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
1212 tempnode = NULL;
1213 }
1214
1215 spin_unlock_irqrestore(&priv->driver_lock, flags);
1216
1217 return tempnode;
1218 }
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228 int lbs_execute_next_command(struct lbs_private *priv)
1229 {
1230 struct cmd_ctrl_node *cmdnode = NULL;
1231 struct cmd_header *cmd;
1232 unsigned long flags;
1233 int ret = 0;
1234
1235
1236
1237
1238 spin_lock_irqsave(&priv->driver_lock, flags);
1239
1240 if (priv->cur_cmd) {
1241 netdev_alert(priv->dev,
1242 "EXEC_NEXT_CMD: already processing command!\n");
1243 spin_unlock_irqrestore(&priv->driver_lock, flags);
1244 ret = -1;
1245 goto done;
1246 }
1247
1248 if (!list_empty(&priv->cmdpendingq)) {
1249 cmdnode = list_first_entry(&priv->cmdpendingq,
1250 struct cmd_ctrl_node, list);
1251 }
1252
1253 spin_unlock_irqrestore(&priv->driver_lock, flags);
1254
1255 if (cmdnode) {
1256 cmd = cmdnode->cmdbuf;
1257
1258 if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
1259 if ((priv->psstate == PS_STATE_SLEEP) ||
1260 (priv->psstate == PS_STATE_PRE_SLEEP)) {
1261 lbs_deb_host(
1262 "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
1263 le16_to_cpu(cmd->command),
1264 priv->psstate);
1265 ret = -1;
1266 goto done;
1267 }
1268 lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
1269 "0x%04x in psstate %d\n",
1270 le16_to_cpu(cmd->command), priv->psstate);
1271 } else if (priv->psstate != PS_STATE_FULL_POWER) {
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283 if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
1284
1285
1286 if ((priv->psstate == PS_STATE_SLEEP)
1287 || (priv->psstate == PS_STATE_PRE_SLEEP)
1288 ) {
1289
1290
1291 priv->needtowakeup = 1;
1292 } else {
1293 lbs_set_ps_mode(priv,
1294 PS_MODE_ACTION_EXIT_PS,
1295 false);
1296 }
1297
1298 ret = 0;
1299 goto done;
1300 } else {
1301
1302
1303
1304
1305 struct cmd_ds_802_11_ps_mode *psm = (void *)cmd;
1306
1307 lbs_deb_host(
1308 "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
1309 psm->action);
1310 if (psm->action !=
1311 cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
1312 lbs_deb_host(
1313 "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
1314 lbs_complete_command(priv, cmdnode, 0);
1315
1316 ret = 0;
1317 goto done;
1318 }
1319
1320 if ((priv->psstate == PS_STATE_SLEEP) ||
1321 (priv->psstate == PS_STATE_PRE_SLEEP)) {
1322 lbs_deb_host(
1323 "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
1324 lbs_complete_command(priv, cmdnode, 0);
1325 priv->needtowakeup = 1;
1326
1327 ret = 0;
1328 goto done;
1329 }
1330
1331 lbs_deb_host(
1332 "EXEC_NEXT_CMD: sending EXIT_PS\n");
1333 }
1334 }
1335 spin_lock_irqsave(&priv->driver_lock, flags);
1336 list_del_init(&cmdnode->list);
1337 spin_unlock_irqrestore(&priv->driver_lock, flags);
1338 lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
1339 le16_to_cpu(cmd->command));
1340 lbs_submit_command(priv, cmdnode);
1341 } else {
1342
1343
1344
1345
1346 if ((priv->psmode != LBS802_11POWERMODECAM) &&
1347 (priv->psstate == PS_STATE_FULL_POWER) &&
1348 (priv->connect_status == LBS_CONNECTED)) {
1349 lbs_deb_host(
1350 "EXEC_NEXT_CMD: cmdpendingq empty, go back to PS_SLEEP");
1351 lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
1352 false);
1353 }
1354 }
1355
1356 ret = 0;
1357 done:
1358 return ret;
1359 }
1360
1361 static void lbs_send_confirmsleep(struct lbs_private *priv)
1362 {
1363 unsigned long flags;
1364 int ret;
1365
1366 lbs_deb_hex(LBS_DEB_HOST, "sleep confirm", (u8 *) &confirm_sleep,
1367 sizeof(confirm_sleep));
1368
1369 ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
1370 sizeof(confirm_sleep));
1371 if (ret) {
1372 netdev_alert(priv->dev, "confirm_sleep failed\n");
1373 return;
1374 }
1375
1376 spin_lock_irqsave(&priv->driver_lock, flags);
1377
1378
1379 priv->dnld_sent = DNLD_RES_RECEIVED;
1380
1381 if (priv->is_host_sleep_configured) {
1382 priv->is_host_sleep_activated = 1;
1383 wake_up_interruptible(&priv->host_sleep_q);
1384 }
1385
1386
1387 if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
1388 priv->psstate = PS_STATE_SLEEP;
1389
1390 spin_unlock_irqrestore(&priv->driver_lock, flags);
1391 }
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401 void lbs_ps_confirm_sleep(struct lbs_private *priv)
1402 {
1403 unsigned long flags =0;
1404 int allowed = 1;
1405
1406 spin_lock_irqsave(&priv->driver_lock, flags);
1407 if (priv->dnld_sent) {
1408 allowed = 0;
1409 lbs_deb_host("dnld_sent was set\n");
1410 }
1411
1412
1413 if (priv->cur_cmd) {
1414 allowed = 0;
1415 lbs_deb_host("cur_cmd was set\n");
1416 }
1417
1418
1419 if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
1420 allowed = 0;
1421 lbs_deb_host("pending events or command responses\n");
1422 }
1423 spin_unlock_irqrestore(&priv->driver_lock, flags);
1424
1425 if (allowed) {
1426 lbs_deb_host("sending lbs_ps_confirm_sleep\n");
1427 lbs_send_confirmsleep(priv);
1428 } else {
1429 lbs_deb_host("sleep confirm has been delayed\n");
1430 }
1431 }
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446 int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
1447 int8_t p2, int usesnr)
1448 {
1449 struct cmd_ds_802_11_tpc_cfg cmd;
1450 int ret;
1451
1452 memset(&cmd, 0, sizeof(cmd));
1453 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1454 cmd.action = cpu_to_le16(CMD_ACT_SET);
1455 cmd.enable = !!enable;
1456 cmd.usesnr = !!usesnr;
1457 cmd.P0 = p0;
1458 cmd.P1 = p1;
1459 cmd.P2 = p2;
1460
1461 ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd);
1462
1463 return ret;
1464 }
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478 int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
1479 int8_t p1, int8_t p2)
1480 {
1481 struct cmd_ds_802_11_pa_cfg cmd;
1482 int ret;
1483
1484 memset(&cmd, 0, sizeof(cmd));
1485 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
1486 cmd.action = cpu_to_le16(CMD_ACT_SET);
1487 cmd.enable = !!enable;
1488 cmd.P0 = p0;
1489 cmd.P1 = p1;
1490 cmd.P2 = p2;
1491
1492 ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd);
1493
1494 return ret;
1495 }
1496
1497
1498 struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
1499 uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
1500 int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
1501 unsigned long callback_arg)
1502 {
1503 struct cmd_ctrl_node *cmdnode;
1504
1505 if (priv->surpriseremoved) {
1506 lbs_deb_host("PREP_CMD: card removed\n");
1507 cmdnode = ERR_PTR(-ENOENT);
1508 goto done;
1509 }
1510
1511
1512
1513
1514 if (!priv->is_auto_deep_sleep_enabled) {
1515 if (priv->is_deep_sleep) {
1516 lbs_deb_cmd("command not allowed in deep sleep\n");
1517 cmdnode = ERR_PTR(-EBUSY);
1518 goto done;
1519 }
1520 }
1521
1522 cmdnode = lbs_get_free_cmd_node(priv);
1523 if (cmdnode == NULL) {
1524 lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
1525
1526
1527 wake_up(&priv->waitq);
1528 cmdnode = ERR_PTR(-ENOBUFS);
1529 goto done;
1530 }
1531
1532 cmdnode->callback = callback;
1533 cmdnode->callback_arg = callback_arg;
1534
1535
1536 memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
1537
1538
1539 cmdnode->cmdbuf->command = cpu_to_le16(command);
1540 cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size);
1541 cmdnode->cmdbuf->result = 0;
1542
1543 lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
1544
1545 cmdnode->cmdwaitqwoken = 0;
1546 lbs_queue_cmd(priv, cmdnode);
1547 wake_up(&priv->waitq);
1548
1549 done:
1550 return cmdnode;
1551 }
1552
1553 void lbs_cmd_async(struct lbs_private *priv, uint16_t command,
1554 struct cmd_header *in_cmd, int in_cmd_size)
1555 {
1556 __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
1557 lbs_cmd_async_callback, 0);
1558 }
1559
1560 int __lbs_cmd(struct lbs_private *priv, uint16_t command,
1561 struct cmd_header *in_cmd, int in_cmd_size,
1562 int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
1563 unsigned long callback_arg)
1564 {
1565 struct cmd_ctrl_node *cmdnode;
1566 unsigned long flags;
1567 int ret = 0;
1568
1569 cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
1570 callback, callback_arg);
1571 if (IS_ERR(cmdnode)) {
1572 ret = PTR_ERR(cmdnode);
1573 goto done;
1574 }
1575
1576 might_sleep();
1577
1578
1579
1580
1581
1582
1583 wait_event(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
1584
1585 spin_lock_irqsave(&priv->driver_lock, flags);
1586 ret = cmdnode->result;
1587 if (ret)
1588 netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n",
1589 command, ret);
1590
1591 __lbs_cleanup_and_insert_cmd(priv, cmdnode);
1592 spin_unlock_irqrestore(&priv->driver_lock, flags);
1593
1594 done:
1595 return ret;
1596 }
1597 EXPORT_SYMBOL_GPL(__lbs_cmd);