blob: e9ff971d7a598038af0f5d567f9a0bec79520d8a [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Prashanth Bhatta98f04d22016-01-08 16:46:21 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_ftm.c
30 *
31 * This file contains the WLAN factory test mode implementation
32 */
33
34#include <cds_mq.h>
35#include "cds_sched.h"
36#include <cds_api.h>
37#include "sir_types.h"
Anurag Chouhan6d760662016-02-20 16:05:43 +053038#include "qdf_types.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080039#include "sir_api.h"
40#include "sir_mac_prot_def.h"
41#include "sme_api.h"
42#include "mac_init_api.h"
43#include "wlan_qct_sys.h"
44#include "wlan_hdd_misc.h"
45#include "i_cds_packet.h"
46#include "cds_reg_service.h"
47#include "wlan_hdd_main.h"
48#include "qwlan_version.h"
49#include "wma_types.h"
50#include "cfg_api.h"
51
52#if defined(QCA_WIFI_FTM)
53#include "bmi.h"
54#include "ol_fw.h"
55#include "wlan_hdd_cfg80211.h"
56#include "wlan_hdd_main.h"
57#include "hif.h"
58#endif
59
60#define HDD_FTM_WMA_PRE_START_TIMEOUT (30000) /* 30 seconds */
61
62#if defined(QCA_WIFI_FTM)
63#if defined(LINUX_QCMBR)
64#define ATH_XIOCTL_UNIFIED_UTF_CMD 0x1000
65#define ATH_XIOCTL_UNIFIED_UTF_RSP 0x1001
66#define MAX_UTF_LENGTH 1024
67typedef struct qcmbr_data_s {
68 unsigned int cmd;
69 unsigned int length;
70 unsigned char buf[MAX_UTF_LENGTH + 4];
71 unsigned int copy_to_user;
72} qcmbr_data_t;
73typedef struct qcmbr_queue_s {
74 unsigned char utf_buf[MAX_UTF_LENGTH + 4];
75 struct list_head list;
76} qcmbr_queue_t;
77LIST_HEAD(qcmbr_queue_head);
78DEFINE_SPINLOCK(qcmbr_queue_lock);
79#endif
80#endif
81
82/**
83 * wlan_ftm_postmsg() - Post FTM message
84 * @cmd_ptr: Pointer to FTM command buffer
85 * @cmd_len: Length of command in @cmd_ptr
86 *
87 * This function is used to send FTM commands to firmware
88 *
89 * Return: 0 for success, non zero for failure
90 */
91static uint32_t wlan_ftm_postmsg(uint8_t *cmd_ptr, uint16_t cmd_len)
92{
93 cds_msg_t ftmMsg;
94
95 ENTER();
96
97 ftmMsg.type = WMA_FTM_CMD_REQ;
98 ftmMsg.reserved = 0;
99 ftmMsg.bodyptr = (uint8_t *) cmd_ptr;
100 ftmMsg.bodyval = 0;
101
Anurag Chouhan6d760662016-02-20 16:05:43 +0530102 if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800103 &ftmMsg)) {
104 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: : Failed to post Msg to HAL",
105 __func__);
106
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530107 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800108 }
109
110 EXIT();
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530111 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800112}
113
114/**
115 * wlan_hdd_ftm_update_tgt_cfg() - Update target configuration
116 * @context: context registered with WMA
117 * @param: target configuration
118 *
119 * This function is registered with WMA via wma_open(), and is
120 * invoked via callback when target parameters are received
121 * from firmware.
122 *
123 * Return: None
124 */
125static void wlan_hdd_ftm_update_tgt_cfg(void *context, void *param)
126{
127 hdd_context_t *hdd_ctx = (hdd_context_t *) context;
128 struct wma_tgt_cfg *cfg = (struct wma_tgt_cfg *)param;
129
130 if (!cdf_is_macaddr_zero(&cfg->hw_macaddr)) {
131 hdd_update_macaddr(hdd_ctx->config, cfg->hw_macaddr);
132 } else {
133 hddLog(CDF_TRACE_LEVEL_ERROR,
134 "%s: Invalid MAC passed from target, using MAC from ini file"
135 MAC_ADDRESS_STR, __func__,
136 MAC_ADDR_ARRAY(hdd_ctx->config->intfMacAddr[0].bytes));
137 }
138}
139
Komal Seelamc11bb222016-01-27 18:57:10 +0530140#ifdef WLAN_FEATURE_LPSS
141static inline void hdd_is_lpass_supported(tMacOpenParameters *mac_openParms,
142 hdd_context_t *hdd_ctx)
143{
144 mac_openParms->is_lpass_enabled = hdd_ctx->config->enable_lpass_support;
145}
146#else
147static inline void hdd_is_lpass_supported(tMacOpenParameters *mac_openParms,
148 hdd_context_t *hdd_ctx)
149{ }
150#endif
151
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800152/**
153 * wlan_ftm_cds_open() - Open the CDS Module in FTM mode
154 * @p_cds_context: pointer to the global CDS context
155 * @hddContextSize: Size of the HDD context to allocate.
156 *
157 * The wlan_ftm_cds_open() function opens the CDF Scheduler
158 * Upon successful initialization:
159 * - All CDS submodules should have been initialized
160 * - The CDS scheduler should have opened
161 * - All the WLAN SW components should have been opened. This includes MAC.
162 *
163 * Returns:
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530164 * QDF_STATUS_SUCCESS - Scheduler was successfully initialized and
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800165 * is ready to be used.
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530166 * QDF_STATUS_E_RESOURCES - System resources (other than memory)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800167 * are unavailable to initialize the scheduler
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530168 * QDF_STATUS_E_FAILURE - Failure to initialize the scheduler
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800169 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530170static QDF_STATUS wlan_ftm_cds_open(v_CONTEXT_t p_cds_context,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800171 uint32_t hddContextSize)
172{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530173 QDF_STATUS vStatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800174 int iter = 0;
175 tSirRetStatus sirStatus = eSIR_SUCCESS;
176 tMacOpenParameters mac_openParms;
177 p_cds_contextType gp_cds_context = (p_cds_contextType) p_cds_context;
178#if defined(QCA_WIFI_FTM)
Anurag Chouhan6d760662016-02-20 16:05:43 +0530179 qdf_device_t cdf_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800180 HTC_INIT_INFO htcInfo;
181 void *pHifContext = NULL;
182 void *pHtcContext = NULL;
Komal Seelamd9106492016-02-15 10:31:44 +0530183 struct ol_context *ol_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800184#endif
185 hdd_context_t *hdd_ctx;
186
Anurag Chouhan6d760662016-02-20 16:05:43 +0530187 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800188 "%s: Opening CDS", __func__);
189
190 if (NULL == gp_cds_context) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530191 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800192 "%s: Trying to open CDS without a PreOpen", __func__);
193 CDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530194 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800195 }
196
197 /* Initialize the probe event */
Anurag Chouhance0dc992016-02-16 18:18:03 +0530198 if (qdf_event_create(&gp_cds_context->ProbeEvent) != QDF_STATUS_SUCCESS) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530199 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800200 "%s: Unable to init probeEvent", __func__);
201 CDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530202 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800203 }
204
Anurag Chouhance0dc992016-02-16 18:18:03 +0530205 if (qdf_event_create(&(gp_cds_context->wmaCompleteEvent)) !=
206 QDF_STATUS_SUCCESS) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530207 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800208 "%s: Unable to init wmaCompleteEvent", __func__);
209 CDF_ASSERT(0);
210
211 goto err_probe_event;
212 }
213
214 /* Initialize the free message queue */
215 vStatus = cds_mq_init(&gp_cds_context->freeVosMq);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530216 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800217
218 /* Critical Error ... Cannot proceed further */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530219 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800220 "%s: Failed to initialize CDS free message queue %d",
221 __func__, vStatus);
222 CDF_ASSERT(0);
223 goto err_wma_complete_event;
224 }
225
226 for (iter = 0; iter < CDS_CORE_MAX_MESSAGES; iter++) {
227 (gp_cds_context->aMsgWrappers[iter]).pVosMsg =
228 &(gp_cds_context->aMsgBuffers[iter]);
229 INIT_LIST_HEAD(&gp_cds_context->aMsgWrappers[iter].msgNode);
230 cds_mq_put(&gp_cds_context->freeVosMq,
231 &(gp_cds_context->aMsgWrappers[iter]));
232 }
233
234 /* Now Open the CDS Scheduler */
235 vStatus = cds_sched_open(gp_cds_context, &gp_cds_context->cdf_sched,
236 sizeof(cds_sched_context));
237
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530238 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800239 /* Critical Error ... Cannot proceed further */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530240 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800241 "%s: Failed to open CDS Scheduler %d", __func__,
242 vStatus);
243 CDF_ASSERT(0);
244 goto err_msg_queue;
245 }
246#if defined(QCA_WIFI_FTM)
247 /* Initialize BMI and Download firmware */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530248 pHifContext = cds_get_context(QDF_MODULE_ID_HIF);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800249 if (!pHifContext) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530250 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800251 "%s: failed to get HIF context", __func__);
252 goto err_sched_close;
253 }
254
Komal Seelamd9106492016-02-15 10:31:44 +0530255 ol_ctx = cds_get_context(CDF_MODULE_ID_BMI);
256 if (bmi_download_firmware(ol_ctx)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530257 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800258 "%s: BMI failed to download target", __func__);
259 goto err_bmi_close;
260 }
Komal Seelam08633492016-02-24 18:05:07 +0530261
262 htcInfo.pContext = ol_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800263 htcInfo.TargetFailure = ol_target_failure;
264 htcInfo.TargetSendSuspendComplete = wma_target_suspend_acknowledge;
Anurag Chouhan6d760662016-02-20 16:05:43 +0530265 cdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800266
267 /* Create HTC */
268 gp_cds_context->htc_ctx =
Komal Seelam08633492016-02-24 18:05:07 +0530269 htc_create(pHifContext, &htcInfo, cdf_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800270 if (!gp_cds_context->htc_ctx) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530271 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800272 "%s: Failed to Create HTC", __func__);
273 goto err_bmi_close;
274 }
275
Komal Seelamd9106492016-02-15 10:31:44 +0530276 if (bmi_done(ol_ctx)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530277 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800278 "%s: Failed to complete BMI phase", __func__);
279 goto err_htc_close;
280 }
281#endif /* QCA_WIFI_FTM */
282
283 /*Open the WMA module */
284 cdf_mem_set(&mac_openParms, sizeof(mac_openParms), 0);
285 mac_openParms.driverType = eDRIVER_TYPE_MFG;
286
287 hdd_ctx = (hdd_context_t *) (gp_cds_context->pHDDContext);
288 if ((NULL == hdd_ctx) || (NULL == hdd_ctx->config)) {
289 /* Critical Error ... Cannot proceed further */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530290 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800291 "%s: Hdd Context is Null", __func__);
292 CDF_ASSERT(0);
293 goto err_htc_close;
294 }
295
296 mac_openParms.powersaveOffloadEnabled =
297 hdd_ctx->config->enablePowersaveOffload;
298
Komal Seelamc11bb222016-01-27 18:57:10 +0530299 hdd_is_lpass_supported(&mac_openParms, hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800300
301 vStatus = wma_open(gp_cds_context,
302 wlan_hdd_ftm_update_tgt_cfg, NULL, &mac_openParms);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530303 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800304 /* Critical Error ... Cannot proceed further */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530305 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800306 "%s: Failed to open WMA module %d", __func__,
307 vStatus);
308 CDF_ASSERT(0);
309 goto err_htc_close;
310 }
311#if defined(QCA_WIFI_FTM)
Komal Seelamec702b02016-02-24 18:42:16 +0530312 hdd_update_config(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800313
Anurag Chouhan6d760662016-02-20 16:05:43 +0530314 pHtcContext = cds_get_context(QDF_MODULE_ID_HTC);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800315 if (!pHtcContext) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530316 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800317 "%s: failed to get HTC context", __func__);
318 goto err_wma_close;
319 }
320 if (htc_wait_target(pHtcContext)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530321 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_FATAL,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800322 "%s: Failed to complete BMI phase", __func__);
323 goto err_wma_close;
324 }
325#endif
326
327 /* Now proceed to open the MAC */
328
329 /* UMA is supported in hardware for performing the
330 * frame translation 802.11 <-> 802.3
331 */
332 mac_openParms.frameTransRequired = 1;
333
334 sirStatus =
335 mac_open(&(gp_cds_context->pMACContext),
336 gp_cds_context->pHDDContext,
337 &mac_openParms);
338
339 if (eSIR_SUCCESS != sirStatus) {
340 /* Critical Error ... Cannot proceed further */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530341 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800342 "%s: Failed to open MAC %d", __func__, sirStatus);
343 CDF_ASSERT(0);
344 goto err_wma_close;
345 }
346#ifndef QCA_WIFI_FTM
347 /* Now proceed to open the SME */
348 vStatus = sme_open(gp_cds_context->pMACContext);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530349 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800350 /* Critical Error ... Cannot proceed further */
Anurag Chouhan6d760662016-02-20 16:05:43 +0530351 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800352 "%s: Failed to open SME %d", __func__, vStatus);
353 goto err_mac_close;
354 }
355
356 vStatus = sme_init_chan_list(gp_cds_context->pMACContext,
357 hdd_ctx->reg.alpha2, hdd_ctx->reg.cc_src);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530358 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530359 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800360 "%s: Failed to init sme channel list", __func__);
361 } else {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530362 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_INFO_HIGH,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800363 "%s: CDS successfully Opened", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530364 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800365 }
366#else
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530367 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800368#endif
369
370#ifndef QCA_WIFI_FTM
371err_mac_close:
372#endif
373 mac_close(gp_cds_context->pMACContext);
374
375err_wma_close:
376 wma_close(gp_cds_context);
377
378err_htc_close:
379#if defined(QCA_WIFI_FTM)
380 if (gp_cds_context->htc_ctx) {
381 htc_destroy(gp_cds_context->htc_ctx);
382 gp_cds_context->htc_ctx = NULL;
383 }
384
385err_bmi_close:
Komal Seelam5a6e5082016-02-24 17:59:09 +0530386 bmi_cleanup(ol_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800387#endif /* QCA_WIFI_FTM */
388
389err_sched_close:
390 cds_sched_close(gp_cds_context);
391err_msg_queue:
392 cds_mq_deinit(&gp_cds_context->freeVosMq);
393
394err_wma_complete_event:
Anurag Chouhance0dc992016-02-16 18:18:03 +0530395 qdf_event_destroy(&gp_cds_context->wmaCompleteEvent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800396
397err_probe_event:
Anurag Chouhance0dc992016-02-16 18:18:03 +0530398 qdf_event_destroy(&gp_cds_context->ProbeEvent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800399
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530400 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800401
402} /* wlan_ftm_cds_open() */
403
404/**
405 * wlan_ftm_cds_close() - Close the CDF Module in FTM mode
406 * @cds_context: context of cds
407 *
408 * The wlan_ftm_cds_close() function closes the CDF Module
409 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530410 * Return: QDF_STATUS_SUCCESS - successfully closed
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800411 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530412static QDF_STATUS wlan_ftm_cds_close(v_CONTEXT_t cds_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800413{
Anurag Chouhance0dc992016-02-16 18:18:03 +0530414 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800415 p_cds_contextType gp_cds_context = (p_cds_contextType) cds_context;
416
417#ifndef QCA_WIFI_FTM
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530418 qdf_status = sme_close(((p_cds_contextType) cds_context)->pMACContext);
419 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530420 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530421 "%s: Failed to close SME %d", __func__, qdf_status);
422 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800423 }
424#endif
425
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530426 qdf_status = mac_close(((p_cds_contextType) cds_context)->pMACContext);
427 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530428 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530429 "%s: Failed to close MAC %d", __func__, qdf_status);
430 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800431 }
432
433 ((p_cds_contextType) cds_context)->pMACContext = NULL;
434
435
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530436 qdf_status = wma_close(cds_context);
437 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530438 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530439 "%s: Failed to close WMA %d", __func__, qdf_status);
440 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800441 }
442#if defined(QCA_WIFI_FTM)
443 if (gp_cds_context->htc_ctx) {
444 htc_stop(gp_cds_context->htc_ctx);
445 htc_destroy(gp_cds_context->htc_ctx);
446 gp_cds_context->htc_ctx = NULL;
447 }
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530448 qdf_status = wma_wmi_service_close(cds_context);
449 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530450 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800451 "%s: Failed to close wma_wmi_service", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530452 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800453 }
454
455 hif_disable_isr(gp_cds_context->pHIFContext);
456#endif
457
458 cds_mq_deinit(&((p_cds_contextType) cds_context)->freeVosMq);
459
Anurag Chouhance0dc992016-02-16 18:18:03 +0530460 qdf_status = qdf_event_destroy(&gp_cds_context->ProbeEvent);
461 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530462 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800463 "%s: Failed to destroy ProbeEvent %d", __func__,
Anurag Chouhance0dc992016-02-16 18:18:03 +0530464 qdf_status);
465 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800466 }
467
Anurag Chouhance0dc992016-02-16 18:18:03 +0530468 qdf_status = qdf_event_destroy(&gp_cds_context->wmaCompleteEvent);
469 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530470 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800471 "%s: Failed to destroy wmaCompleteEvent %d", __func__,
Anurag Chouhance0dc992016-02-16 18:18:03 +0530472 qdf_status);
473 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474 }
475
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530476 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800477}
478
479/**
480 * cds_ftm_pre_start() - Pre-start CDS Module in FTM Mode
481 * @cds_context: The CDS context
482 *
483 * The cds_ftm_pre_start() function performs all pre-start activities
484 * in FTM mode.
485 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530486 * Return: QDF_STATUS_SUCCESS if pre-start was successful, an
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800487 * appropriate CDF_STATUS_E_* error code otherwise
488 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530489static QDF_STATUS cds_ftm_pre_start(v_CONTEXT_t cds_context)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800490{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530491 QDF_STATUS vStatus = QDF_STATUS_SUCCESS;
Anurag Chouhance0dc992016-02-16 18:18:03 +0530492 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800493 p_cds_contextType p_cds_context = (p_cds_contextType) cds_context;
494#if defined(QCA_WIFI_FTM)
495 p_cds_contextType gp_cds_context =
496 cds_get_global_context();
497#endif
498
499 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_INFO, "cds prestart");
500 if (NULL == p_cds_context->pWMAContext) {
501 CDF_ASSERT(0);
502 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR,
503 "%s: WMA NULL context", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530504 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800505 }
506
507 /* Reset WMA wait event */
Anurag Chouhance0dc992016-02-16 18:18:03 +0530508 qdf_event_reset(&p_cds_context->wmaCompleteEvent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800509
510 /*call WMA pre start */
511 vStatus = wma_pre_start(p_cds_context);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530512 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800513 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR,
514 "Failed to WMA prestart ");
515 CDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530516 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800517 }
518
519 /* Need to update time out of complete */
Anurag Chouhance0dc992016-02-16 18:18:03 +0530520 qdf_status = qdf_wait_single_event(&p_cds_context->wmaCompleteEvent,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800521 HDD_FTM_WMA_PRE_START_TIMEOUT);
Anurag Chouhance0dc992016-02-16 18:18:03 +0530522 if (qdf_status != QDF_STATUS_SUCCESS) {
523 if (qdf_status == QDF_STATUS_E_TIMEOUT) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530524 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800525 "%s: Timeout occurred before WMA complete",
526 __func__);
527 } else {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530528 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800529 "%s: wma_pre_start reporting other error",
530 __func__);
531 }
532 CDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530533 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800534 }
535#if defined(QCA_WIFI_FTM)
536 vStatus = htc_start(gp_cds_context->htc_ctx);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530537 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800538 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_FATAL,
539 "Failed to Start HTC");
540 CDF_ASSERT(0);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530541 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800542 }
543 wma_wait_for_ready_event(gp_cds_context->pWMAContext);
544#endif /* QCA_WIFI_FTM */
545
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530546 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800547}
548
549/**
550 * wlan_hdd_ftm_open() - Open HDD in FTM Mode
551 * @hdd_ctx: global HDD context
552 *
553 * The function hdd_wlan_startup calls this function to initialize the
554 * FTM specific modules.
555 *
556 * Return: 0 on success, non-zero on error
557 */
558int wlan_hdd_ftm_open(hdd_context_t *hdd_ctx)
559{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530560 QDF_STATUS vStatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800561 p_cds_contextType p_cds_context = NULL;
562
563 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO_HIGH,
564 "%s: Opening CDS", __func__);
565
566 p_cds_context = cds_get_global_context();
567
568 if (NULL == p_cds_context) {
569 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
570 "%s: Trying to open CDS without a PreOpen", __func__);
571 CDF_ASSERT(0);
572 goto err_cdf_status_failure;
573 }
574
575 vStatus = wlan_ftm_cds_open(p_cds_context, 0);
576
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530577 if (!QDF_IS_STATUS_SUCCESS(vStatus)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800578 hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_open failed", __func__);
579 goto err_cdf_status_failure;
580 }
581
582 /*
583 * only needed to start WMA, which happens in wlan_hdd_ftm_start()
584 */
585
586 /* Save the hal context in Adapter */
587 hdd_ctx->hHal =
588 (tHalHandle) cds_get_context(CDF_MODULE_ID_SME);
589
590 if (NULL == hdd_ctx->hHal) {
591 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: HAL context is null",
592 __func__);
593 goto err_ftm_close;
594 }
595
596 return 0;
597
598err_ftm_close:
599 wlan_ftm_cds_close(p_cds_context);
600
601err_cdf_status_failure:
602 return -EPERM;
603}
604
605/**
606 * hdd_ftm_service_registration() - Register FTM service
607 * @hdd_ctx: global HDD context
608 *
609 * Return: 0 on success, non-zero on failure
610 */
611static int hdd_ftm_service_registration(hdd_context_t *hdd_ctx)
612{
613 hdd_adapter_t *adapter;
614 adapter = hdd_open_adapter(hdd_ctx, WLAN_HDD_FTM, "wlan%d",
615 wlan_hdd_get_intf_addr(hdd_ctx), false);
616 if (NULL == adapter) {
617 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: hdd_open_adapter failed",
618 __func__);
619 goto err_adapter_open_failure;
620 }
621
622 hdd_ctx->ftm.ftm_state = WLAN_FTM_INITIALIZED;
623
624 return 0;
625
626err_adapter_open_failure:
627
628 return -EPERM;
629}
630
631/**
632 * wlan_ftm_stop() - Stop HDD in FTM mode
633 * @hdd_ctx: pointer to HDD context
634 *
635 * This function stops the following modules
Varun Reddy Yeturu08efa3a2015-11-03 16:59:57 -0800636 * WMA
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800637 *
638 * Return: 0 on success, non-zero on failure
639 */
640static int wlan_ftm_stop(hdd_context_t *hdd_ctx)
641{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800642 if (hdd_ctx->ftm.ftm_state != WLAN_FTM_STARTED) {
Varun Reddy Yeturu08efa3a2015-11-03 16:59:57 -0800643 hddLog(LOGP, FL("FTM has not started. No need to stop"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800644 return -EPERM;
645 }
Varun Reddy Yeturu08efa3a2015-11-03 16:59:57 -0800646 wma_stop(hdd_ctx->pcds_context, HAL_STOP_TYPE_RF_KILL);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800647 return 0;
648}
649
650/**
651 * wlan_hdd_ftm_close() - Close HDD in FTM mode
652 * @hdd_ctx: pointer to HDD context
653 *
654 * Return: 0 on success, non-zero on failure
655 */
656int wlan_hdd_ftm_close(hdd_context_t *hdd_ctx)
657{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530658 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800659 v_CONTEXT_t cds_context = hdd_ctx->pcds_context;
660
661 hdd_adapter_t *adapter = hdd_get_adapter(hdd_ctx, WLAN_HDD_FTM);
662 ENTER();
663 if (adapter == NULL) {
664 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL,
665 "%s:adapter is NULL", __func__);
666 return -ENXIO;
667 }
668
669 if (WLAN_FTM_STARTED == hdd_ctx->ftm.ftm_state) {
670 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_FATAL,
671 "%s: Ftm has been started. stopping ftm", __func__);
672 wlan_ftm_stop(hdd_ctx);
673 }
674
Prashanth Bhatta98f04d22016-01-08 16:46:21 -0800675 hdd_close_all_adapters(hdd_ctx, false);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800676
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530677 qdf_status = cds_sched_close(cds_context);
678 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530679 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800680 "%s: Failed to close CDS Scheduler", __func__);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530681 CDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800682 }
683 /* Close CDS */
684 wlan_ftm_cds_close(cds_context);
685
686#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR)
687 spin_lock_bh(&qcmbr_queue_lock);
688 if (!list_empty(&qcmbr_queue_head)) {
689 qcmbr_queue_t *msg_buf, *tmp_buf;
690 list_for_each_entry_safe(msg_buf, tmp_buf, &qcmbr_queue_head,
691 list) {
692 list_del(&msg_buf->list);
693 kfree(msg_buf);
694 }
695 }
696 spin_unlock_bh(&qcmbr_queue_lock);
697#endif
698
699 return 0;
700
701}
702
703
704/**
705 * hdd_ftm_mc_process_msg() - Process FTM mailbox message
706 * @message: FTM response message
707 *
708 * Process FTM mailbox message
709 *
710 * Return: void
711 */
712static void hdd_ftm_mc_process_msg(void *message)
713{
714 void *data;
715 uint32_t data_len;
716
717 if (!message) {
718 hdd_err("Message is NULL, nothing to process.");
719 return;
720 }
721
722 data_len = *((uint32_t *) message);
723 data = (uint32_t *) message + 1;
724
725#if defined(LINUX_QCMBR)
726 wlanqcmbr_mc_process_msg(message);
727#else
728#ifdef CONFIG_NL80211_TESTMODE
729 wlan_hdd_testmode_rx_event(data, (size_t) data_len);
730#endif
731#endif
732 return;
733}
734
735/**
736 * wlan_hdd_ftm_start() - Start HDD in FTM mode
737 * @hdd_ctx: Global HDD context
738 *
739 * This function starts the following modules.
740 * 1) WMA Start.
741 * 2) HTC Start.
742 * 3) MAC Start to download the firmware.
743 *
744 * Return: 0 for success, non zero for failure
745 */
746static int wlan_hdd_ftm_start(hdd_context_t *hdd_ctx)
747{
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530748 QDF_STATUS vStatus = QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800749 p_cds_contextType p_cds_context =
750 (p_cds_contextType) (hdd_ctx->pcds_context);
751
752 if (WLAN_FTM_STARTED == hdd_ctx->ftm.ftm_state) {
753 return 0;
754 }
755
756 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
757 "%s: Starting CLD SW", __func__);
758
759 /* We support only one instance for now ... */
760 if (p_cds_context == NULL) {
761 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
762 "%s: mismatch in context", __func__);
763 goto err_status_failure;
764 }
765
766 if (p_cds_context->pMACContext == NULL) {
767 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
768 "%s: MAC NULL context", __func__);
769 goto err_status_failure;
770 }
771
772 /* Vos preStart is calling */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530773 if (!QDF_IS_STATUS_SUCCESS(cds_ftm_pre_start(hdd_ctx->pcds_context))) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800774 hddLog(CDF_TRACE_LEVEL_FATAL, "%s: cds_pre_enable failed",
775 __func__);
776 goto err_status_failure;
777 }
778
779 sme_register_ftm_msg_processor(hdd_ctx->hHal, hdd_ftm_mc_process_msg);
780
781 vStatus = wma_start(p_cds_context);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530782 if (vStatus != QDF_STATUS_SUCCESS) {
Anurag Chouhan6d760662016-02-20 16:05:43 +0530783 CDF_TRACE(QDF_MODULE_ID_QDF, CDF_TRACE_LEVEL_ERROR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800784 "%s: Failed to start WMA", __func__);
785 goto err_status_failure;
786 }
787
788 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
789 "%s: MAC correctly started", __func__);
790
791 if (hdd_ftm_service_registration(hdd_ctx)) {
792 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
793 "%s: failed", __func__);
794 goto err_ftm_service_reg;
795 }
796
797 hdd_ctx->ftm.ftm_state = WLAN_FTM_STARTED;
798
799 return 0;
800
801err_ftm_service_reg:
802 wlan_hdd_ftm_close(hdd_ctx);
803
804err_status_failure:
805
806 return -EPERM;
807
808}
809
810#if defined(QCA_WIFI_FTM)
811/**
812 * hdd_ftm_start() - Start HDD in FTM mode
813 * @hdd_ctx: Global HDD context
814 *
815 * Return: 0 for success, non zero for failure
816 */
817int hdd_ftm_start(hdd_context_t *hdd_ctx)
818{
819 return wlan_hdd_ftm_start(hdd_ctx);
820}
821#endif
822
823#if defined(QCA_WIFI_FTM)
824/**
825 * hdd_ftm_stop() - Stop HDD in FTM mode
826 * @hdd_ctx: Global HDD context
827 *
828 * Return: 0 for success, non zero for failure
829 */
830int hdd_ftm_stop(hdd_context_t *hdd_ctx)
831{
832 return wlan_ftm_stop(hdd_ctx);
833}
834#endif
835
836#if defined(QCA_WIFI_FTM)
837#if defined(LINUX_QCMBR)
838/**
839 * wlan_hdd_qcmbr_command() - QCMBR command handler
840 * @adapter: adapter upon which the command was received
841 * @pqcmbr_data: QCMBR command
842 *
843 * Return: 0 on success, non-zero on error
844 */
845static int wlan_hdd_qcmbr_command(hdd_adapter_t *adapter,
846 qcmbr_data_t *pqcmbr_data)
847{
848 int ret = 0;
849 qcmbr_queue_t *qcmbr_buf = NULL;
850
851 switch (pqcmbr_data->cmd) {
852 case ATH_XIOCTL_UNIFIED_UTF_CMD: {
853 pqcmbr_data->copy_to_user = 0;
854 if (pqcmbr_data->length) {
855 if (wlan_hdd_ftm_testmode_cmd(pqcmbr_data->buf,
856 pqcmbr_data->
857 length)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530858 != QDF_STATUS_SUCCESS) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859 ret = -EBUSY;
860 } else {
861 ret = 0;
862 }
863 }
864 }
865 break;
866
867 case ATH_XIOCTL_UNIFIED_UTF_RSP: {
868 pqcmbr_data->copy_to_user = 1;
869 if (!list_empty(&qcmbr_queue_head)) {
870 spin_lock_bh(&qcmbr_queue_lock);
871 qcmbr_buf = list_first_entry(&qcmbr_queue_head,
872 qcmbr_queue_t,
873 list);
874 list_del(&qcmbr_buf->list);
875 spin_unlock_bh(&qcmbr_queue_lock);
876 ret = 0;
877 } else {
878 ret = -1;
879 }
880
881 if (!ret) {
882 memcpy(pqcmbr_data->buf, qcmbr_buf->utf_buf,
883 (MAX_UTF_LENGTH + 4));
884 kfree(qcmbr_buf);
885 } else {
886 ret = -EAGAIN;
887 }
888 }
889 break;
890 }
891
892 return ret;
893}
894
895#ifdef CONFIG_COMPAT
896/**
897 * wlan_hdd_qcmbr_ioctl() - Compatability-mode QCMBR ioctl handler
898 * @adapter: adapter upon which the ioctl was received
899 * @ifr: the ioctl request
900 *
901 * Return: 0 on success, non-zero on error
902 */
903static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter,
904 struct ifreq *ifr)
905{
906 qcmbr_data_t *qcmbr_data;
907 int ret = 0;
908
909 qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL);
910 if (qcmbr_data == NULL)
911 return -ENOMEM;
912
913 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
914 ret = -EFAULT;
915 goto exit;
916 }
917
918 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
919 if (qcmbr_data->copy_to_user) {
920 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
921 (MAX_UTF_LENGTH + 4));
922 }
923
924exit:
925 kfree(qcmbr_data);
926 return ret;
927}
928#else /* CONFIG_COMPAT */
929static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter,
930 struct ifreq *ifr)
931{
932 return 0;
933}
934#endif /* CONFIG_COMPAT */
935
936/**
937 * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler
938 * @adapter: adapter upon which the ioctl was received
939 * @ifr: the ioctl request
940 *
941 * Return: 0 on success, non-zero on error
942 */
943static int wlan_hdd_qcmbr_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
944{
945 qcmbr_data_t *qcmbr_data;
946 int ret = 0;
947
948 qcmbr_data = kzalloc(sizeof(qcmbr_data_t), GFP_KERNEL);
949 if (qcmbr_data == NULL)
950 return -ENOMEM;
951
952 if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) {
953 ret = -EFAULT;
954 goto exit;
955 }
956
957 ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data);
958 if (qcmbr_data->copy_to_user) {
959 ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf,
960 (MAX_UTF_LENGTH + 4));
961 }
962
963exit:
964 kfree(qcmbr_data);
965 return ret;
966}
967
968/**
969 * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler
970 * @adapter: adapter upon which the ioctl was received
971 * @ifr: the ioctl request
972 *
973 * Return: 0 on success, non-zero on error
974 */
975int wlan_hdd_qcmbr_unified_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr)
976{
977 int ret = 0;
978
979 if (is_compat_task()) {
980 ret = wlan_hdd_qcmbr_compat_ioctl(adapter, ifr);
981 } else {
982 ret = wlan_hdd_qcmbr_ioctl(adapter, ifr);
983 }
984
985 return ret;
986}
987
988/**
989 * wlanqcmbr_mc_process_msg() - Process QCMBR response message
990 * @message: QCMBR message
991 *
992 * Return: None
993 */
994static void wlanqcmbr_mc_process_msg(void *message)
995{
996 qcmbr_queue_t *qcmbr_buf = NULL;
997 uint32_t data_len;
998
999 data_len = *((uint32_t *) message) + sizeof(uint32_t);
1000 qcmbr_buf = kzalloc(sizeof(qcmbr_queue_t), GFP_KERNEL);
1001 if (qcmbr_buf != NULL) {
1002 memcpy(qcmbr_buf->utf_buf, message, data_len);
1003 spin_lock_bh(&qcmbr_queue_lock);
1004 list_add_tail(&(qcmbr_buf->list), &qcmbr_queue_head);
1005 spin_unlock_bh(&qcmbr_queue_lock);
1006 }
1007}
1008#endif /*LINUX_QCMBR */
1009
1010/**
1011 * wlan_hdd_ftm_testmode_cmd() - Process FTM testmode command
1012 * @data: FTM testmode command
1013 * @len: length of @data
1014 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301015 * Return: QDF_STATUS_SUCCESS on success, CDF_STATUS_E_* on error
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001016 */
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301017QDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001018{
1019 struct ar6k_testmode_cmd_data *cmd_data;
1020
1021 cmd_data = (struct ar6k_testmode_cmd_data *)
1022 cdf_mem_malloc(sizeof(*cmd_data));
1023
1024 if (!cmd_data) {
1025 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1026 ("Failed to allocate FTM command data"));
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301027 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001028 }
1029
1030 cmd_data->data = cdf_mem_malloc(len);
1031
1032 if (!cmd_data->data) {
1033 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
1034 ("Failed to allocate FTM command data buffer"));
1035 cdf_mem_free(cmd_data);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301036 return QDF_STATUS_E_NOMEM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001037 }
1038
1039 cmd_data->len = len;
1040 cdf_mem_copy(cmd_data->data, data, len);
1041
1042 if (wlan_ftm_postmsg((uint8_t *) cmd_data, sizeof(*cmd_data))) {
1043 cdf_mem_free(cmd_data->data);
1044 cdf_mem_free(cmd_data);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301045 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001046 }
1047
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05301048 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001049}
1050#endif /*QCA_WIFI_FTM */