0001
0002
0003
0004
0005
0006 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0007
0008 #include <linux/hardirq.h>
0009 #include <linux/slab.h>
0010 #include <linux/export.h>
0011
0012 #include "libertas_tf.h"
0013
0014 static const struct channel_range channel_ranges[] = {
0015 { LBTF_REGDOMAIN_US, 1, 12 },
0016 { LBTF_REGDOMAIN_CA, 1, 12 },
0017 { LBTF_REGDOMAIN_EU, 1, 14 },
0018 { LBTF_REGDOMAIN_JP, 1, 14 },
0019 { LBTF_REGDOMAIN_SP, 1, 14 },
0020 { LBTF_REGDOMAIN_FR, 1, 14 },
0021 };
0022
0023 static u16 lbtf_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
0024 {
0025 LBTF_REGDOMAIN_US, LBTF_REGDOMAIN_CA, LBTF_REGDOMAIN_EU,
0026 LBTF_REGDOMAIN_SP, LBTF_REGDOMAIN_FR, LBTF_REGDOMAIN_JP,
0027 };
0028
0029 static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv);
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra,
0043 struct cmd_header *resp)
0044 {
0045 struct cmd_header *buf = (void *)extra;
0046 uint16_t copy_len;
0047
0048 copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
0049 memcpy(buf, resp, copy_len);
0050 return 0;
0051 }
0052 EXPORT_SYMBOL_GPL(lbtf_cmd_copyback);
0053
0054 #define CHAN_TO_IDX(chan) ((chan) - 1)
0055
0056 static void lbtf_geo_init(struct lbtf_private *priv)
0057 {
0058 const struct channel_range *range = channel_ranges;
0059 u8 ch;
0060 int i;
0061
0062 for (i = 0; i < ARRAY_SIZE(channel_ranges); i++)
0063 if (channel_ranges[i].regdomain == priv->regioncode) {
0064 range = &channel_ranges[i];
0065 break;
0066 }
0067
0068 for (ch = range->start; ch < range->end; ch++)
0069 priv->channels[CHAN_TO_IDX(ch)].flags = 0;
0070 }
0071
0072
0073
0074
0075
0076
0077
0078
0079 int lbtf_update_hw_spec(struct lbtf_private *priv)
0080 {
0081 struct cmd_ds_get_hw_spec cmd;
0082 int ret = -1;
0083 u32 i;
0084
0085 lbtf_deb_enter(LBTF_DEB_CMD);
0086
0087 memset(&cmd, 0, sizeof(cmd));
0088 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0089 memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
0090 ret = lbtf_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
0091 if (ret)
0092 goto out;
0093
0094 priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
0095
0096
0097
0098 priv->fwrelease = le32_to_cpu(cmd.fwrelease);
0099 priv->fwrelease = (priv->fwrelease << 8) |
0100 (priv->fwrelease >> 24 & 0xff);
0101
0102 printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n",
0103 cmd.permanentaddr,
0104 priv->fwrelease >> 24 & 0xff,
0105 priv->fwrelease >> 16 & 0xff,
0106 priv->fwrelease >> 8 & 0xff,
0107 priv->fwrelease & 0xff,
0108 priv->fwcapinfo);
0109 lbtf_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
0110 cmd.hwifversion, cmd.version);
0111
0112
0113
0114
0115
0116 priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
0117
0118 for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
0119
0120 if (priv->regioncode == lbtf_region_code_to_index[i])
0121 break;
0122 }
0123
0124
0125 if (i >= MRVDRV_MAX_REGION_CODE) {
0126 priv->regioncode = 0x10;
0127 pr_info("unidentified region code; using the default (USA)\n");
0128 }
0129
0130 if (priv->current_addr[0] == 0xff)
0131 memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
0132
0133 SET_IEEE80211_PERM_ADDR(priv->hw, priv->current_addr);
0134
0135 lbtf_geo_init(priv);
0136 out:
0137 lbtf_deb_leave(LBTF_DEB_CMD);
0138 return ret;
0139 }
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 int lbtf_set_channel(struct lbtf_private *priv, u8 channel)
0150 {
0151 int ret = 0;
0152 struct cmd_ds_802_11_rf_channel cmd;
0153
0154 lbtf_deb_enter(LBTF_DEB_CMD);
0155
0156 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0157 cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
0158 cmd.channel = cpu_to_le16(channel);
0159
0160 ret = lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
0161 lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
0162 return ret;
0163 }
0164
0165 int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
0166 {
0167 struct cmd_ds_802_11_beacon_set cmd;
0168 int size;
0169
0170 lbtf_deb_enter(LBTF_DEB_CMD);
0171
0172 if (beacon->len > MRVL_MAX_BCN_SIZE) {
0173 lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", -1);
0174 return -1;
0175 }
0176 size = sizeof(cmd) - sizeof(cmd.beacon) + beacon->len;
0177 cmd.hdr.size = cpu_to_le16(size);
0178 cmd.len = cpu_to_le16(beacon->len);
0179 memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len);
0180
0181 lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size);
0182
0183 lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", 0);
0184 return 0;
0185 }
0186
0187 int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
0188 int beacon_int)
0189 {
0190 struct cmd_ds_802_11_beacon_control cmd;
0191 lbtf_deb_enter(LBTF_DEB_CMD);
0192
0193 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0194 cmd.action = cpu_to_le16(CMD_ACT_SET);
0195 cmd.beacon_enable = cpu_to_le16(beacon_enable);
0196 cmd.beacon_period = cpu_to_le16(beacon_int);
0197
0198 lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd));
0199
0200 lbtf_deb_leave(LBTF_DEB_CMD);
0201 return 0;
0202 }
0203
0204 static void lbtf_queue_cmd(struct lbtf_private *priv,
0205 struct cmd_ctrl_node *cmdnode)
0206 {
0207 unsigned long flags;
0208 lbtf_deb_enter(LBTF_DEB_HOST);
0209
0210 if (!cmdnode) {
0211 lbtf_deb_host("QUEUE_CMD: cmdnode is NULL\n");
0212 goto qcmd_done;
0213 }
0214
0215 if (!cmdnode->cmdbuf->size) {
0216 lbtf_deb_host("DNLD_CMD: cmd size is zero\n");
0217 goto qcmd_done;
0218 }
0219
0220 cmdnode->result = 0;
0221 spin_lock_irqsave(&priv->driver_lock, flags);
0222 list_add_tail(&cmdnode->list, &priv->cmdpendingq);
0223 spin_unlock_irqrestore(&priv->driver_lock, flags);
0224
0225 lbtf_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
0226 le16_to_cpu(cmdnode->cmdbuf->command));
0227
0228 qcmd_done:
0229 lbtf_deb_leave(LBTF_DEB_HOST);
0230 }
0231
0232 static void lbtf_submit_command(struct lbtf_private *priv,
0233 struct cmd_ctrl_node *cmdnode)
0234 {
0235 unsigned long flags;
0236 struct cmd_header *cmd;
0237 uint16_t cmdsize;
0238 uint16_t command;
0239 int timeo = 5 * HZ;
0240 int ret;
0241
0242 lbtf_deb_enter(LBTF_DEB_HOST);
0243
0244 cmd = cmdnode->cmdbuf;
0245
0246 spin_lock_irqsave(&priv->driver_lock, flags);
0247 priv->cur_cmd = cmdnode;
0248 cmdsize = le16_to_cpu(cmd->size);
0249 command = le16_to_cpu(cmd->command);
0250
0251 lbtf_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
0252 command, le16_to_cpu(cmd->seqnum), cmdsize);
0253 lbtf_deb_hex(LBTF_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
0254
0255 ret = priv->ops->hw_host_to_card(priv, MVMS_CMD, (u8 *)cmd, cmdsize);
0256 spin_unlock_irqrestore(&priv->driver_lock, flags);
0257
0258 if (ret) {
0259 pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
0260
0261
0262 timeo = HZ;
0263 }
0264
0265
0266 mod_timer(&priv->command_timer, jiffies + timeo);
0267
0268 lbtf_deb_leave(LBTF_DEB_HOST);
0269 }
0270
0271
0272
0273
0274
0275 static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
0276 struct cmd_ctrl_node *cmdnode)
0277 {
0278 lbtf_deb_enter(LBTF_DEB_HOST);
0279
0280 if (!cmdnode)
0281 goto cl_ins_out;
0282
0283 cmdnode->callback = NULL;
0284 cmdnode->callback_arg = 0;
0285
0286 memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
0287
0288 list_add_tail(&cmdnode->list, &priv->cmdfreeq);
0289
0290 cl_ins_out:
0291 lbtf_deb_leave(LBTF_DEB_HOST);
0292 }
0293
0294 static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
0295 struct cmd_ctrl_node *ptempcmd)
0296 {
0297 unsigned long flags;
0298
0299 spin_lock_irqsave(&priv->driver_lock, flags);
0300 __lbtf_cleanup_and_insert_cmd(priv, ptempcmd);
0301 spin_unlock_irqrestore(&priv->driver_lock, flags);
0302 }
0303
0304 void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd,
0305 int result)
0306 {
0307 cmd->result = result;
0308 cmd->cmdwaitqwoken = 1;
0309 wake_up_interruptible(&cmd->cmdwait_q);
0310
0311 if (!cmd->callback)
0312 __lbtf_cleanup_and_insert_cmd(priv, cmd);
0313 priv->cur_cmd = NULL;
0314 }
0315
0316 int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv)
0317 {
0318 struct cmd_ds_mac_multicast_addr cmd;
0319
0320 lbtf_deb_enter(LBTF_DEB_CMD);
0321
0322 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0323 cmd.action = cpu_to_le16(CMD_ACT_SET);
0324
0325 cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
0326
0327 lbtf_deb_cmd("MULTICAST_ADR: setting %d addresses\n", cmd.nr_of_adrs);
0328
0329 memcpy(cmd.maclist, priv->multicastlist,
0330 priv->nr_of_multicastmacaddr * ETH_ALEN);
0331
0332 lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd));
0333
0334 lbtf_deb_leave(LBTF_DEB_CMD);
0335 return 0;
0336 }
0337
0338 void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode)
0339 {
0340 struct cmd_ds_set_mode cmd;
0341 lbtf_deb_enter(LBTF_DEB_WEXT);
0342
0343 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0344 cmd.mode = cpu_to_le16(mode);
0345 lbtf_deb_wext("Switching to mode: 0x%x\n", mode);
0346 lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd));
0347
0348 lbtf_deb_leave(LBTF_DEB_WEXT);
0349 }
0350
0351 void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid)
0352 {
0353 struct cmd_ds_set_bssid cmd;
0354 lbtf_deb_enter(LBTF_DEB_CMD);
0355
0356 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0357 cmd.activate = activate ? 1 : 0;
0358 if (activate)
0359 memcpy(cmd.bssid, bssid, ETH_ALEN);
0360
0361 lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd));
0362 lbtf_deb_leave(LBTF_DEB_CMD);
0363 }
0364
0365 int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
0366 {
0367 struct cmd_ds_802_11_mac_address cmd;
0368 lbtf_deb_enter(LBTF_DEB_CMD);
0369
0370 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0371 cmd.action = cpu_to_le16(CMD_ACT_SET);
0372
0373 memcpy(cmd.macadd, mac_addr, ETH_ALEN);
0374
0375 lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd));
0376 lbtf_deb_leave(LBTF_DEB_CMD);
0377 return 0;
0378 }
0379
0380 int lbtf_set_radio_control(struct lbtf_private *priv)
0381 {
0382 int ret = 0;
0383 struct cmd_ds_802_11_radio_control cmd;
0384
0385 lbtf_deb_enter(LBTF_DEB_CMD);
0386
0387 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0388 cmd.action = cpu_to_le16(CMD_ACT_SET);
0389
0390 switch (priv->preamble) {
0391 case CMD_TYPE_SHORT_PREAMBLE:
0392 cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
0393 break;
0394
0395 case CMD_TYPE_LONG_PREAMBLE:
0396 cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
0397 break;
0398
0399 case CMD_TYPE_AUTO_PREAMBLE:
0400 default:
0401 cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
0402 break;
0403 }
0404
0405 if (priv->radioon)
0406 cmd.control |= cpu_to_le16(TURN_ON_RF);
0407 else
0408 cmd.control &= cpu_to_le16(~TURN_ON_RF);
0409
0410 lbtf_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
0411 priv->preamble);
0412
0413 ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
0414
0415 lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
0416 return ret;
0417 }
0418
0419 void lbtf_set_mac_control(struct lbtf_private *priv)
0420 {
0421 struct cmd_ds_mac_control cmd;
0422 lbtf_deb_enter(LBTF_DEB_CMD);
0423
0424 cmd.hdr.size = cpu_to_le16(sizeof(cmd));
0425 cmd.action = cpu_to_le16(priv->mac_control);
0426 cmd.reserved = 0;
0427
0428 lbtf_cmd_async(priv, CMD_MAC_CONTROL,
0429 &cmd.hdr, sizeof(cmd));
0430
0431 lbtf_deb_leave(LBTF_DEB_CMD);
0432 }
0433
0434
0435
0436
0437
0438
0439
0440
0441 int lbtf_allocate_cmd_buffer(struct lbtf_private *priv)
0442 {
0443 int ret = 0;
0444 u32 bufsize;
0445 u32 i;
0446 struct cmd_ctrl_node *cmdarray;
0447
0448 lbtf_deb_enter(LBTF_DEB_HOST);
0449
0450
0451 bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
0452 cmdarray = kzalloc(bufsize, GFP_KERNEL);
0453 if (!cmdarray) {
0454 lbtf_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
0455 ret = -1;
0456 goto done;
0457 }
0458 priv->cmd_array = cmdarray;
0459
0460
0461 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
0462 cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
0463 if (!cmdarray[i].cmdbuf) {
0464 lbtf_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
0465 ret = -1;
0466 goto done;
0467 }
0468 }
0469
0470 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
0471 init_waitqueue_head(&cmdarray[i].cmdwait_q);
0472 lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]);
0473 }
0474
0475 ret = 0;
0476
0477 done:
0478 lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %d", ret);
0479 return ret;
0480 }
0481
0482
0483
0484
0485
0486
0487
0488
0489 int lbtf_free_cmd_buffer(struct lbtf_private *priv)
0490 {
0491 struct cmd_ctrl_node *cmdarray;
0492 unsigned int i;
0493
0494 lbtf_deb_enter(LBTF_DEB_HOST);
0495
0496
0497 if (priv->cmd_array == NULL) {
0498 lbtf_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
0499 goto done;
0500 }
0501
0502 cmdarray = priv->cmd_array;
0503
0504
0505 for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
0506 kfree(cmdarray[i].cmdbuf);
0507 cmdarray[i].cmdbuf = NULL;
0508 }
0509
0510
0511 kfree(priv->cmd_array);
0512 priv->cmd_array = NULL;
0513
0514 done:
0515 lbtf_deb_leave(LBTF_DEB_HOST);
0516 return 0;
0517 }
0518
0519
0520
0521
0522
0523
0524
0525
0526 static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
0527 {
0528 struct cmd_ctrl_node *tempnode;
0529 unsigned long flags;
0530
0531 lbtf_deb_enter(LBTF_DEB_HOST);
0532
0533 if (!priv)
0534 return NULL;
0535
0536 spin_lock_irqsave(&priv->driver_lock, flags);
0537
0538 if (!list_empty(&priv->cmdfreeq)) {
0539 tempnode = list_first_entry(&priv->cmdfreeq,
0540 struct cmd_ctrl_node, list);
0541 list_del(&tempnode->list);
0542 } else {
0543 lbtf_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
0544 tempnode = NULL;
0545 }
0546
0547 spin_unlock_irqrestore(&priv->driver_lock, flags);
0548
0549 lbtf_deb_leave(LBTF_DEB_HOST);
0550 return tempnode;
0551 }
0552
0553
0554
0555
0556
0557
0558
0559
0560 int lbtf_execute_next_command(struct lbtf_private *priv)
0561 {
0562 struct cmd_ctrl_node *cmdnode = NULL;
0563 struct cmd_header *cmd;
0564 unsigned long flags;
0565 int ret = 0;
0566
0567
0568
0569
0570 lbtf_deb_enter(LBTF_DEB_THREAD);
0571
0572 spin_lock_irqsave(&priv->driver_lock, flags);
0573
0574 if (priv->cur_cmd) {
0575 pr_alert("EXEC_NEXT_CMD: already processing command!\n");
0576 spin_unlock_irqrestore(&priv->driver_lock, flags);
0577 ret = -1;
0578 goto done;
0579 }
0580
0581 if (!list_empty(&priv->cmdpendingq)) {
0582 cmdnode = list_first_entry(&priv->cmdpendingq,
0583 struct cmd_ctrl_node, list);
0584 }
0585
0586 if (cmdnode) {
0587 cmd = cmdnode->cmdbuf;
0588
0589 list_del(&cmdnode->list);
0590 lbtf_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
0591 le16_to_cpu(cmd->command));
0592 spin_unlock_irqrestore(&priv->driver_lock, flags);
0593 lbtf_submit_command(priv, cmdnode);
0594 } else
0595 spin_unlock_irqrestore(&priv->driver_lock, flags);
0596
0597 ret = 0;
0598 done:
0599 lbtf_deb_leave(LBTF_DEB_THREAD);
0600 return ret;
0601 }
0602
0603 static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
0604 uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
0605 int (*callback)(struct lbtf_private *, unsigned long,
0606 struct cmd_header *),
0607 unsigned long callback_arg)
0608 {
0609 struct cmd_ctrl_node *cmdnode;
0610
0611 lbtf_deb_enter(LBTF_DEB_HOST);
0612
0613 if (priv->surpriseremoved) {
0614 lbtf_deb_host("PREP_CMD: card removed\n");
0615 cmdnode = ERR_PTR(-ENOENT);
0616 goto done;
0617 }
0618
0619 cmdnode = lbtf_get_cmd_ctrl_node(priv);
0620 if (cmdnode == NULL) {
0621 lbtf_deb_host("PREP_CMD: cmdnode is NULL\n");
0622
0623
0624 queue_work(lbtf_wq, &priv->cmd_work);
0625 cmdnode = ERR_PTR(-ENOBUFS);
0626 goto done;
0627 }
0628
0629 cmdnode->callback = callback;
0630 cmdnode->callback_arg = callback_arg;
0631
0632
0633 memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
0634
0635
0636 priv->seqnum++;
0637 cmdnode->cmdbuf->command = cpu_to_le16(command);
0638 cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size);
0639 cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum);
0640 cmdnode->cmdbuf->result = 0;
0641
0642 lbtf_deb_host("PREP_CMD: command 0x%04x\n", command);
0643
0644 cmdnode->cmdwaitqwoken = 0;
0645 lbtf_queue_cmd(priv, cmdnode);
0646 queue_work(lbtf_wq, &priv->cmd_work);
0647
0648 done:
0649 lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %p", cmdnode);
0650 return cmdnode;
0651 }
0652
0653 void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
0654 struct cmd_header *in_cmd, int in_cmd_size)
0655 {
0656 lbtf_deb_enter(LBTF_DEB_CMD);
0657 __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0);
0658 lbtf_deb_leave(LBTF_DEB_CMD);
0659 }
0660
0661 int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
0662 struct cmd_header *in_cmd, int in_cmd_size,
0663 int (*callback)(struct lbtf_private *,
0664 unsigned long, struct cmd_header *),
0665 unsigned long callback_arg)
0666 {
0667 struct cmd_ctrl_node *cmdnode;
0668 unsigned long flags;
0669 int ret = 0;
0670
0671 lbtf_deb_enter(LBTF_DEB_HOST);
0672
0673 cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size,
0674 callback, callback_arg);
0675 if (IS_ERR(cmdnode)) {
0676 ret = PTR_ERR(cmdnode);
0677 goto done;
0678 }
0679
0680 might_sleep();
0681 ret = wait_event_interruptible(cmdnode->cmdwait_q,
0682 cmdnode->cmdwaitqwoken);
0683 if (ret) {
0684 pr_info("PREP_CMD: command 0x%04x interrupted by signal: %d\n",
0685 command, ret);
0686 goto done;
0687 }
0688
0689 spin_lock_irqsave(&priv->driver_lock, flags);
0690 ret = cmdnode->result;
0691 if (ret)
0692 pr_info("PREP_CMD: command 0x%04x failed: %d\n",
0693 command, ret);
0694
0695 __lbtf_cleanup_and_insert_cmd(priv, cmdnode);
0696 spin_unlock_irqrestore(&priv->driver_lock, flags);
0697
0698 done:
0699 lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %d", ret);
0700 return ret;
0701 }
0702 EXPORT_SYMBOL_GPL(__lbtf_cmd);
0703
0704
0705 void lbtf_cmd_response_rx(struct lbtf_private *priv)
0706 {
0707 priv->cmd_response_rxed = 1;
0708 queue_work(lbtf_wq, &priv->cmd_work);
0709 }
0710 EXPORT_SYMBOL_GPL(lbtf_cmd_response_rx);
0711
0712 int lbtf_process_rx_command(struct lbtf_private *priv)
0713 {
0714 uint16_t respcmd, curcmd;
0715 struct cmd_header *resp;
0716 int ret = 0;
0717 unsigned long flags;
0718 uint16_t result;
0719
0720 lbtf_deb_enter(LBTF_DEB_CMD);
0721
0722 mutex_lock(&priv->lock);
0723 spin_lock_irqsave(&priv->driver_lock, flags);
0724
0725 if (!priv->cur_cmd) {
0726 ret = -1;
0727 spin_unlock_irqrestore(&priv->driver_lock, flags);
0728 goto done;
0729 }
0730
0731 resp = (void *)priv->cmd_resp_buff;
0732 curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
0733 respcmd = le16_to_cpu(resp->command);
0734 result = le16_to_cpu(resp->result);
0735
0736 lbtf_deb_cmd("libertastf: cmd response 0x%04x, seq %d, size %d\n",
0737 respcmd, le16_to_cpu(resp->seqnum),
0738 le16_to_cpu(resp->size));
0739
0740 if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
0741 spin_unlock_irqrestore(&priv->driver_lock, flags);
0742 ret = -1;
0743 goto done;
0744 }
0745 if (respcmd != CMD_RET(curcmd)) {
0746 spin_unlock_irqrestore(&priv->driver_lock, flags);
0747 ret = -1;
0748 goto done;
0749 }
0750
0751 if (resp->result == cpu_to_le16(0x0004)) {
0752
0753
0754 spin_unlock_irqrestore(&priv->driver_lock, flags);
0755 ret = -1;
0756 goto done;
0757 }
0758
0759
0760 del_timer(&priv->command_timer);
0761 priv->cmd_timed_out = 0;
0762 if (priv->nr_retries)
0763 priv->nr_retries = 0;
0764
0765
0766 if ((result != 0 || !(respcmd & 0x8000))) {
0767
0768
0769
0770 switch (respcmd) {
0771 case CMD_RET(CMD_GET_HW_SPEC):
0772 case CMD_RET(CMD_802_11_RESET):
0773 pr_info("libertastf: reset failed\n");
0774 break;
0775
0776 }
0777 lbtf_complete_command(priv, priv->cur_cmd, result);
0778 spin_unlock_irqrestore(&priv->driver_lock, flags);
0779
0780 ret = -1;
0781 goto done;
0782 }
0783
0784 spin_unlock_irqrestore(&priv->driver_lock, flags);
0785
0786 if (priv->cur_cmd && priv->cur_cmd->callback) {
0787 ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
0788 resp);
0789 }
0790 spin_lock_irqsave(&priv->driver_lock, flags);
0791
0792 if (priv->cur_cmd) {
0793
0794 lbtf_complete_command(priv, priv->cur_cmd, result);
0795 }
0796 spin_unlock_irqrestore(&priv->driver_lock, flags);
0797
0798 done:
0799 mutex_unlock(&priv->lock);
0800 lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
0801 return ret;
0802 }