Files
bes2600-dkms/bes2600/tx_loop.c
T
test0r 8dd79199f8 bes2600: Patch G — restore SPDX identifiers + ST-Ericsson attribution
The bes2600 driver is a fork of the upstream cw1200 driver
(drivers/net/wireless/st/cw1200/, ST-Ericsson, Dmitry Tarnyagin
2010-2011).  The fork's file headers have three GPL-compliance issues:

  1. NO SPDX-License-Identifier on any of 48 source files (cw1200
     mainline has them on all 25).  kernel.org-mandated since 2017.

  2. Original "Copyright (c) 2010, ST-Ericsson" lines stripped from
     all files inherited from cw1200, replaced with
     "Copyright (c) 2010, Bestechnic" — factually impossible
     (Bestechnic did not author the 2010 work) and a GPL-2.0 §1
     attribution-preservation violation.

  3. The "GPL version 2 as published by the Free Software Foundation"
     boilerplate paragraph is redundant alongside SPDX and is the
     legacy form modern kernel sources have replaced.

This patch corrects all three for the 48 .c/.h files in bes2600/:

  - Adds `// SPDX-License-Identifier: GPL-2.0-only` (or `/* ... */`
    for headers) as line 1 of every file.
  - Restores `Copyright (c) 2010, ST-Ericsson` + `Author: Dmitry
    Tarnyagin <dmitry.tarnyagin@lockless.no>` as the FIRST copyright
    chain entry on all 22 files derived from cw1200 (bh.{c,h},
    debug.{c,h}, fwio.{c,h}, hwio.{c,h}, main.c, pm.{c,h},
    queue.{c,h}, scan.{c,h}, sta.{c,h}, txrx.{c,h}, wsm.{c,h}).
  - Keeps `Copyright (c) 2022, Bestechnic (Beijing) Co., Ltd.` as
    the SECOND chain entry where Bestechnic genuinely contributed.
  - Notes "Derived from cw1200_sdio.c" + ST-Ericsson copyright on
    bes2600_sdio.c (heavy derivation, not a literal rename).
  - Notes "Replaces hwbus.h from cw1200/" + ST-Ericsson copyright
    on sbus.h.
  - Preserves the prism54/islsm authorship chain on main.c and
    bes2600.h (Michael Wu 2006 + Jean-Baptiste Note 2004-2006).
  - Drops the GPL-2.0 boilerplate paragraph in favour of SPDX.

No code changes — only file-header comment blocks.  Module build is
unaffected (verified by header-only diff scope).

This is a prerequisite for any kernel.org submission attempt.  The
existing MODULE_LICENSE("GPL") + MODULE_AUTHOR(Tarnyagin@stericsson.com)
declarations were already present and are unchanged here; the
mismatch between MODULE_AUTHOR and the (since-corrected) per-file
copyrights is now resolved.
2026-05-08 00:03:50 +02:00

535 lines
20 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Test-mode TX loopback for BES2600
*
* Copyright (c) 2022, Bestechnic (Beijing) Co., Ltd.
*
*/
#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);
}
}