Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
0011  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
0013  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
0014  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
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 }