0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <net/netlink.h>
0018 #include <linux/firmware.h>
0019 #include <net/cfg80211.h>
0020 #include "wcn36xx.h"
0021
0022 #include "testmode.h"
0023 #include "testmode_i.h"
0024 #include "hal.h"
0025 #include "smd.h"
0026
0027 static const struct nla_policy wcn36xx_tm_policy[WCN36XX_TM_ATTR_MAX + 1] = {
0028 [WCN36XX_TM_ATTR_CMD] = { .type = NLA_U16 },
0029 [WCN36XX_TM_ATTR_DATA] = { .type = NLA_BINARY,
0030 .len = WCN36XX_TM_DATA_MAX_LEN },
0031 };
0032
0033 struct build_release_number {
0034 u16 drv_major;
0035 u16 drv_minor;
0036 u16 drv_patch;
0037 u16 drv_build;
0038 u16 ptt_max;
0039 u16 ptt_min;
0040 u16 fw_ver;
0041 } __packed;
0042
0043 static int wcn36xx_tm_cmd_ptt(struct wcn36xx *wcn, struct ieee80211_vif *vif,
0044 struct nlattr *tb[])
0045 {
0046 int ret = 0, buf_len;
0047 void *buf;
0048 struct ftm_rsp_msg *msg, *rsp = NULL;
0049 struct sk_buff *skb;
0050
0051 if (!tb[WCN36XX_TM_ATTR_DATA])
0052 return -EINVAL;
0053
0054 buf = nla_data(tb[WCN36XX_TM_ATTR_DATA]);
0055 buf_len = nla_len(tb[WCN36XX_TM_ATTR_DATA]);
0056 msg = (struct ftm_rsp_msg *)buf;
0057
0058 wcn36xx_dbg(WCN36XX_DBG_TESTMODE,
0059 "testmode cmd wmi msg_id 0x%04X msg_len %d buf %pK buf_len %d\n",
0060 msg->msg_id, msg->msg_body_length,
0061 buf, buf_len);
0062
0063 wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "REQ ", buf, buf_len);
0064
0065 if (msg->msg_id == MSG_GET_BUILD_RELEASE_NUMBER) {
0066 struct build_release_number *body =
0067 (struct build_release_number *)
0068 msg->msg_response;
0069
0070 body->drv_major = wcn->fw_major;
0071 body->drv_minor = wcn->fw_minor;
0072 body->drv_patch = wcn->fw_version;
0073 body->drv_build = wcn->fw_revision;
0074 body->ptt_max = 10;
0075 body->ptt_min = 0;
0076
0077 rsp = msg;
0078 rsp->resp_status = 0;
0079 } else {
0080 wcn36xx_dbg(WCN36XX_DBG_TESTMODE,
0081 "PPT Request >> HAL size %d\n",
0082 msg->msg_body_length);
0083
0084 msg->resp_status = wcn36xx_smd_process_ptt_msg(wcn, vif, msg,
0085 msg->msg_body_length, (void *)(&rsp));
0086
0087 wcn36xx_dbg(WCN36XX_DBG_TESTMODE,
0088 "Response status = %d\n",
0089 msg->resp_status);
0090 if (rsp)
0091 wcn36xx_dbg(WCN36XX_DBG_TESTMODE,
0092 "PPT Response << HAL size %d\n",
0093 rsp->msg_body_length);
0094 }
0095
0096 if (!rsp) {
0097 rsp = msg;
0098 wcn36xx_warn("No response! Echoing request with response status %d\n",
0099 rsp->resp_status);
0100 }
0101 wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "RSP ",
0102 rsp, rsp->msg_body_length);
0103
0104 skb = cfg80211_testmode_alloc_reply_skb(wcn->hw->wiphy,
0105 nla_total_size(msg->msg_body_length));
0106 if (!skb) {
0107 ret = -ENOMEM;
0108 goto out;
0109 }
0110
0111 ret = nla_put(skb, WCN36XX_TM_ATTR_DATA, rsp->msg_body_length, rsp);
0112 if (ret) {
0113 kfree_skb(skb);
0114 goto out;
0115 }
0116
0117 ret = cfg80211_testmode_reply(skb);
0118
0119 out:
0120 if (rsp != msg)
0121 kfree(rsp);
0122
0123 return ret;
0124 }
0125
0126 int wcn36xx_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0127 void *data, int len)
0128 {
0129 struct wcn36xx *wcn = hw->priv;
0130 struct nlattr *tb[WCN36XX_TM_ATTR_MAX + 1];
0131 int ret = 0;
0132 unsigned short attr;
0133
0134 wcn36xx_dbg_dump(WCN36XX_DBG_TESTMODE_DUMP, "Data:", data, len);
0135 ret = nla_parse_deprecated(tb, WCN36XX_TM_ATTR_MAX, data, len,
0136 wcn36xx_tm_policy, NULL);
0137 if (ret)
0138 return ret;
0139
0140 if (!tb[WCN36XX_TM_ATTR_CMD])
0141 return -EINVAL;
0142
0143 attr = nla_get_u16(tb[WCN36XX_TM_ATTR_CMD]);
0144
0145 if (attr != WCN36XX_TM_CMD_PTT)
0146 return -EOPNOTSUPP;
0147
0148 return wcn36xx_tm_cmd_ptt(wcn, vif, tb);
0149 }