Files
bes2600-dkms/bes2600/tx_loop.c
T

538 lines
20 KiB
C

/*
* Mac80211 driver for BES2600 device
*
* Copyright (c) 2022, Bestechnic
* Author:
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "bes2600.h"
#include "wsm.h"
#include "queue.h"
#include "bes_log.h"
struct tx_loop_table
{
u16 cmd;
void (*proc)(struct bes2600_common *hw_priv, u8 *buf, u32 len);
};
static void bes2600_tx_loop_build_lmac_tx_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len);
static void bes2600_tx_loop_build_scan_compl_ind(struct bes2600_common *hw_priv);
static void bes2600_tx_loop_build_pm_ind(struct bes2600_common *hw_priv);
void bes2600_tx_loop_init(struct bes2600_common *hw_priv)
{
hw_priv->tx_loop.enabled = false;
hw_priv->tx_loop.start_lmac_seq = 0;
hw_priv->tx_loop.start_mcu_seq = 0;
INIT_LIST_HEAD(&hw_priv->tx_loop.pending_record_list);
spin_lock_init(&hw_priv->tx_loop.pending_record_lock);
spin_lock_init(&hw_priv->tx_loop.tx_loop_lock);
skb_queue_head_init(&hw_priv->tx_loop.rx_queue);
}
struct sk_buff *bes2600_tx_loop_read(struct bes2600_common *hw_priv)
{
struct sk_buff *skb;
struct wsm_hdr *wsm;
if(hw_priv == NULL)
return NULL;
skb = skb_dequeue(&hw_priv->tx_loop.rx_queue);
if(skb != NULL) {
wsm = (struct wsm_hdr *)skb->data;
bes_devel("tx loop pipe read msg_id:0x%04x seq:%d\n",
WSM_MSG_ID_GET(wsm->id), WSM_MSG_SEQ_GET(wsm->id));
}
return skb;
}
static void bes2600_tx_loop_item_pending_item(struct bes2600_common *hw_priv, struct sk_buff *skb)
{
bes_devel("tx loop confirm pending skb.\n");
bes2600_tx_loop_build_lmac_tx_cfm(hw_priv, skb->data, skb->data_len);
}
void bes2600_tx_loop_record_wsm_cmd(struct bes2600_common *hw_priv, u8 *wsm_cmd)
{
hw_priv->tx_loop.wsm_cmd_ptr = wsm_cmd;
}
void bes2600_tx_loop_clear_wsm_cmd(struct bes2600_common *hw_priv)
{
hw_priv->tx_loop.wsm_cmd_ptr = NULL;
}
void bes2600_tx_loop_set_enable(struct bes2600_common *hw_priv, bool need_warn)
{
int i = 0;
u16 cmd_id = -1;
if(hw_priv == NULL)
return;
if(hw_priv->tx_loop.enabled)
return;
WARN_ON(need_warn);
hw_priv->tx_loop.enabled = true;
hw_priv->tx_loop.start_lmac_seq = hw_priv->wsm_rx_seq[0];
hw_priv->tx_loop.start_mcu_seq = hw_priv->wsm_rx_seq[1];
if(hw_priv->tx_loop.wsm_cmd_ptr) {
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)hw_priv->tx_loop.wsm_cmd_ptr;
cmd_id = tx_wsm->id & WSM_MSG_ID_MASK;
if(cmd_id == 0x0005 || cmd_id == 0x0006){
struct wsm_mib *mib = (struct wsm_mib *)hw_priv->wsm_cmd.arg;
u16 mib_id = mib->mibId;
bes_devel("pending cmd:0x%04x seq:%d mib_id:0x%04x\n",
cmd_id, WSM_MSG_SEQ_GET(tx_wsm->id), mib_id);
} else {
bes_devel("pending cmd:0x%04x seq:%d\n",
cmd_id, WSM_MSG_SEQ_GET(tx_wsm->id));
}
bes2600_tx_loop_pipe_send(hw_priv, hw_priv->tx_loop.wsm_cmd_ptr, 8);
}
if (atomic_read(&hw_priv->scan.in_progress) && cmd_id != 0x0007) {
bes2600_tx_loop_build_scan_compl_ind(hw_priv);
} else if (atomic_read(&hw_priv->bes_power.pm_set_in_process) && cmd_id != 0x0010) {
bes2600_tx_loop_build_pm_ind(hw_priv);
}
for (i = 0; i < 4; i++) {
bes2600_queue_iterate_pending_packet(&hw_priv->tx_queue[i],
bes2600_tx_loop_item_pending_item);
}
spin_lock(&hw_priv->tx_loop.pending_record_lock);
bes2600_queue_iterate_record_pending_packet(hw_priv, bes2600_tx_loop_item_pending_item);
spin_unlock(&hw_priv->tx_loop.pending_record_lock);
if (atomic_read(&hw_priv->bh_rx) > 0)
wake_up(&hw_priv->bh_wq);
}
static void bes2600_tx_loop_build_lmac_generic_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
struct sk_buff *out_skb;
struct wsm_hdr *rx_wsm, *tx_wsm;
u32 msg_len = sizeof(struct wsm_hdr) + 4;
u16 msg_id = 0;
tx_wsm = (struct wsm_hdr *)buf;
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_err("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s cmd 0x%04x len:%d\n",
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_hdr *)out_skb->data;
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
msg_id |= 0x400; // set confirm flag
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
rx_wsm->id = __cpu_to_le16(msg_id);
rx_wsm->len = __cpu_to_le16(msg_len);
*((u32 *)&rx_wsm[1]) = __cpu_to_le32(WSM_STATUS_SUCCESS);
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static void bes2600_tx_loop_build_lmac_tx_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
struct sk_buff *out_skb;
struct wsm_hdr *rx_wsm;
struct wsm_tx *tx_wsm;
struct wsm_tx_confirm *cfm;
u32 msg_len = sizeof(struct wsm_hdr) + sizeof(struct wsm_tx_confirm);
u16 msg_id = 0;
tx_wsm = (struct wsm_tx *)buf;
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_err("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s cmd 0x%04x len:%d\n",
__func__, (tx_wsm->hdr.id & WSM_MSG_ID_MASK), msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_hdr *)out_skb->data;
msg_id = (tx_wsm->hdr.id & WSM_MSG_ID_MASK);
msg_id |= 0x400; // set confirm flag
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
rx_wsm->id = __cpu_to_le16(msg_id);
rx_wsm->len = __cpu_to_le16(msg_len);
cfm = (struct wsm_tx_confirm *)&rx_wsm[1];
cfm->packetID = tx_wsm->packetID;
cfm->status = WSM_STATUS_SUCCESS;
cfm->txedRate = tx_wsm->maxTxRate;
cfm->ackFailures = 0;
cfm->flags = WSM_TX_STATUS_NORMAL_ACK;
cfm->txQueueDelay = 5;
cfm->mediaDelay = 3;
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static void bes2600_tx_loop_build_config_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
struct sk_buff *out_skb;
struct wsm_hdr *rx_wsm;
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
u32 msg_len = sizeof(struct wsm_hdr) + sizeof(struct wsm_configuration) + 4;
u16 msg_id = 0;
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_err("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s cmd 0x%04x len:%d\n",
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_hdr *)out_skb->data;
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
msg_id |= 0x400; // set confirm flag
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
rx_wsm->id = __cpu_to_le16(msg_id);
rx_wsm->len = __cpu_to_le16(msg_len);
*(u32 *)&rx_wsm[1] = WSM_STATUS_SUCCESS;
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static void bes2600_tx_loop_build_read_mib_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
struct sk_buff *out_skb;
struct wsm_hdr *rx_wsm;
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
struct wsm_mib *mib = (struct wsm_mib *)hw_priv->wsm_cmd.arg;
u32 *status;
u16 *mib_id, *size;
u32 msg_len = sizeof(struct wsm_hdr) + 4 /* status */ + 2 /* mib_id */ + mib->buf_size;
u16 msg_id = 0;
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_err("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s cmd 0x%04x len:%d\n",
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_hdr *)out_skb->data;
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
msg_id |= 0x400; // set confirm flag
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
rx_wsm->id = __cpu_to_le16(msg_id);
rx_wsm->len = __cpu_to_le16(msg_len);
status = (u32 *)&rx_wsm[1];
*status = WSM_STATUS_SUCCESS;
mib_id = (u16 *)&status[1];
*mib_id = mib->mibId;
size = (u16 *)&mib_id[1];
*size = mib->buf_size;
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static void bes2600_tx_loop_build_join_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
struct sk_buff *out_skb;
struct wsm_hdr *rx_wsm;
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
u16 msg_id = 0;
u32 msg_len = sizeof(struct wsm_hdr) + 4 /* status */ + 8 /* power_level */;
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_err("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s cmd 0x%04x len:%d\n",
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_hdr *)out_skb->data;
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
msg_id |= 0x400; // set confirm flag
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
rx_wsm->id = __cpu_to_le16(msg_id);
rx_wsm->len = __cpu_to_le16(msg_len);
*(u32 *)&rx_wsm[1] = WSM_STATUS_SUCCESS;
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static void bes2600_tx_loop_build_rfcmd_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
struct sk_buff *out_skb;
struct wsm_mcu_hdr *rx_wsm;
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
u16 msg_id = 0;
u32 msg_len = sizeof(struct wsm_mcu_hdr);
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_err("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s cmd 0x%04x len:%d\n",
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_mcu_hdr *)out_skb->data;
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_mcu_seq);
rx_wsm->hdr.id = __cpu_to_le16(msg_id);
rx_wsm->hdr.len = __cpu_to_le16(msg_len);
rx_wsm->handle_label = WSM_TO_MCU_CMD_CONFIRM_LABEL;
rx_wsm->cmd_type = (tx_wsm->id & WSM_MSG_ID_MASK);
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_mcu_seq = (hw_priv->tx_loop.start_mcu_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static void bes2600_tx_loop_build_driver_cmd_cfm(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
struct sk_buff *out_skb;
struct wsm_mcu_hdr *rx_wsm;
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
u16 msg_id = 0;
u32 msg_len = sizeof(struct wsm_mcu_hdr) + 4;
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_err("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s cmd 0x%04x len:%d\n",
__func__, (tx_wsm->id & WSM_MSG_ID_MASK), msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_mcu_hdr *)out_skb->data;
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_mcu_seq);
rx_wsm->hdr.id = __cpu_to_le16(msg_id);
rx_wsm->hdr.len = __cpu_to_le16(msg_len);
rx_wsm->handle_label = WSM_TO_MCU_CMD_CONFIRM_LABEL;
rx_wsm->cmd_type = (tx_wsm->id & WSM_MSG_ID_MASK);
*(uint32_t *)(rx_wsm + 1) = 0;
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_mcu_seq = (hw_priv->tx_loop.start_mcu_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static struct tx_loop_table tx_loop_tbl[] = {
{.cmd = 0x0004, .proc = bes2600_tx_loop_build_lmac_tx_cfm},
{.cmd = 0x0009, .proc = bes2600_tx_loop_build_config_cfm},
{.cmd = 0x0005, .proc = bes2600_tx_loop_build_read_mib_cfm},
{.cmd = 0x0006, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x000B, .proc = bes2600_tx_loop_build_join_cfm},
{.cmd = 0x0007, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0008, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x000A, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x000C, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x000D, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0010, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0011, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0012, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0013, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0016, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0017, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0018, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0019, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x001A, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x001B, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x001C, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0029, .proc = bes2600_tx_loop_build_lmac_generic_cfm},
{.cmd = 0x0C25, .proc = bes2600_tx_loop_build_rfcmd_cfm},
{.cmd = 0x0C27, .proc = bes2600_tx_loop_build_driver_cmd_cfm},
};
static void bes2600_tx_loop_build_scan_compl_ind(struct bes2600_common *hw_priv)
{
struct sk_buff *out_skb;
struct wsm_hdr *rx_wsm;
struct wsm_scan_complete *scan_compl;
u16 msg_id = 0;
u32 msg_len = sizeof(struct wsm_hdr) + sizeof(struct wsm_scan_complete);
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_devel("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s len:%d\n", __func__, msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_hdr *)out_skb->data;
msg_id |= 0x806; // set indication flag
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
rx_wsm->id = __cpu_to_le16(msg_id);
rx_wsm->len = __cpu_to_le16(msg_len);
scan_compl = (struct wsm_scan_complete *)&rx_wsm[1];
scan_compl->status = WSM_STATUS_SUCCESS;
scan_compl->psm = WSM_PSM_PS;
scan_compl->numChannels = 2;
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static void bes2600_tx_loop_build_pm_ind(struct bes2600_common *hw_priv)
{
struct sk_buff *out_skb;
struct wsm_hdr *rx_wsm;
struct wsm_set_pm_complete *pm_compl;
u16 msg_id = 0;
u32 msg_len = sizeof(struct wsm_hdr) + sizeof(struct wsm_set_pm_complete);
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_devel("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s len:%d\n", __func__, msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_hdr *)out_skb->data;
msg_id |= 0x809; // set indication flag
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_lmac_seq);
rx_wsm->id = __cpu_to_le16(msg_id);
rx_wsm->len = __cpu_to_le16(msg_len);
pm_compl = (struct wsm_set_pm_complete *)&rx_wsm[1];
pm_compl->status = WSM_STATUS_SUCCESS;
pm_compl->psm = WSM_PSM_PS;
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_lmac_seq = (hw_priv->tx_loop.start_lmac_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
static void bes2600_tx_loop_build_rfcmd_ind(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
struct sk_buff *out_skb;
struct wsm_mcu_hdr *rx_wsm;
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
u16 msg_id = 0;
u32 msg_len = sizeof(struct wsm_mcu_hdr);
out_skb = dev_alloc_skb(msg_len);
if(IS_ERR_OR_NULL(out_skb)) {
bes_err("%s, alloc mem fail.\n", __func__);
return;
}
bes_devel("%s len:%d\n",__func__, msg_len);
skb_put(out_skb, msg_len);
rx_wsm = (struct wsm_mcu_hdr *)out_skb->data;
msg_id = (tx_wsm->id & WSM_MSG_ID_MASK);
msg_id |= WSM_TX_SEQ(hw_priv->tx_loop.start_mcu_seq);
rx_wsm->hdr.id = __cpu_to_le16(msg_id);
rx_wsm->hdr.len = __cpu_to_le16(msg_len);
rx_wsm->handle_label = WSM_TO_MCU_CMD_INDICATION_LABEL;
rx_wsm->cmd_type = (tx_wsm->id & WSM_MSG_ID_MASK);
spin_lock(&hw_priv->tx_loop.tx_loop_lock);
hw_priv->tx_loop.start_mcu_seq = (hw_priv->tx_loop.start_mcu_seq + 1) & 7;
skb_queue_tail(&hw_priv->tx_loop.rx_queue, out_skb);
spin_unlock(&hw_priv->tx_loop.tx_loop_lock);
atomic_add_return(1, &hw_priv->bh_rx);
}
void bes2600_tx_loop_pipe_send(struct bes2600_common *hw_priv, u8 *buf, u32 len)
{
int i = 0;
int tbl_size = ARRAY_SIZE(tx_loop_tbl);
struct wsm_hdr *tx_wsm = (struct wsm_hdr *)buf;
u16 cmd_id = tx_wsm->id & WSM_MSG_ID_MASK;
/* don't need to tx loop if wifi is unregistered */
if(hw_priv == NULL)
return;
bes_devel("tx loop pipe send cmd:0x%04x seq:%d\n",
cmd_id, WSM_MSG_SEQ_GET(tx_wsm->id));
/* select build confirm function based on command id */
for(i = 0; i < tbl_size; i++) {
if(cmd_id == tx_loop_tbl[i].cmd) {
tx_loop_tbl[i].proc(hw_priv, buf, len);
break;
}
}
/* build indication for special command */
if(cmd_id == 0x0007) {
bes2600_tx_loop_build_scan_compl_ind(hw_priv);
} else if(cmd_id == 0x0010) {
bes2600_tx_loop_build_pm_ind(hw_priv);
} else if(cmd_id == 0x0C25) {
bes2600_tx_loop_build_rfcmd_ind(hw_priv, buf, len);
}
}