xref: /wlan-dirver/qca-wifi-host-cmn/umac/wifi_pos/src/wifi_pos_main.c (revision ad85c389289a03e320cd08dea21861f9857892fc)
1 /*
2  * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: wifi_pos_main.c
21  * This file defines the important functions pertinent to
22  * wifi positioning to initialize and de-initialize the component.
23  */
24 #include "target_if_wifi_pos.h"
25 #include "wifi_pos_oem_interface_i.h"
26 #include "wifi_pos_utils_i.h"
27 #include "wifi_pos_api.h"
28 #include "wifi_pos_main_i.h"
29 #include "wifi_pos_ucfg_i.h"
30 #include "wlan_objmgr_cmn.h"
31 #include "wlan_objmgr_global_obj.h"
32 #include "wlan_objmgr_psoc_obj.h"
33 #include "wlan_objmgr_pdev_obj.h"
34 #include "wlan_objmgr_vdev_obj.h"
35 #include "wlan_ptt_sock_svc.h"
36 
37 #include "wlan_reg_services_api.h"
38 /* forward declartion */
39 struct regulatory_channel;
40 
41 #define REG_SET_CHANNEL_REG_POWER(reg_info_1, val) do { \
42 	reg_info_1 &= 0xff00ffff;           \
43 	reg_info_1 |= ((val & 0xff) << 16); \
44 } while (0)
45 
46 /* max tx power is in 1 dBm units */
47 #define REG_SET_CHANNEL_MAX_TX_POWER(reg_info_2, val) do { \
48 	reg_info_2 &= 0xffff00ff;              \
49 	reg_info_2 |= ((val & 0xff) << 8);     \
50 } while (0)
51 
52 /* channel info consists of 6 bits of channel mode */
53 
54 #define REG_SET_CHANNEL_MODE(reg_channel, val) do { \
55 	(reg_channel)->info &= 0xffffffc0;            \
56 	(reg_channel)->info |= (val);                 \
57 } while (0)
58 
59 /*
60  * obj mgr api to iterate over vdevs does not provide a direct array or vdevs,
61  * rather takes a callback that is called for every vdev. wifi pos needs to
62  * store device mode and vdev id of all active vdevs and provide this info to
63  * user space as part of APP registration response. due to this, vdev_idx is
64  * used to identify how many vdevs have been populated by obj manager API.
65  */
66 static uint32_t vdev_idx;
67 
68 /**
69  * wifi_pos_get_tlv_support: indicates if firmware supports TLV wifi pos msg
70  * @psoc: psoc object
71  *
72  * Return: status of operation
73  */
74 static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc)
75 {
76 	/* this is TBD */
77 	return true;
78 }
79 
80 static QDF_STATUS wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc,
81 					struct wifi_pos_req_msg *req)
82 {
83 	uint8_t idx;
84 	uint32_t sub_type = 0;
85 	uint32_t channel_mhz = 0;
86 	void *pdev_id = NULL;
87 	uint32_t offset;
88 	struct oem_data_req data_req;
89 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
90 
91 	wifi_pos_debug("Received data req pid(%d), len(%d)",
92 			req->pid, req->buf_len);
93 
94 	/* look for fields */
95 	if (req->field_info_buf)
96 		for (idx = 0; idx < req->field_info_buf->count; idx++) {
97 			offset = req->field_info_buf->fields[idx].offset;
98 			/*
99 			 * replace following reads with read_api based on
100 			 * length
101 			 */
102 			if (req->field_info_buf->fields[idx].id ==
103 					WMIRTT_FIELD_ID_oem_data_sub_type) {
104 				sub_type = *((uint32_t *)&req->buf[offset]);
105 				continue;
106 			}
107 
108 			if (req->field_info_buf->fields[idx].id ==
109 					WMIRTT_FIELD_ID_channel_mhz) {
110 				channel_mhz = *((uint32_t *)&req->buf[offset]);
111 				continue;
112 			}
113 
114 			if (req->field_info_buf->fields[idx].id ==
115 					WMIRTT_FIELD_ID_pdev) {
116 				pdev_id = &req->buf[offset];
117 				continue;
118 			}
119 		}
120 
121 	switch (sub_type) {
122 	case TARGET_OEM_CAPABILITY_REQ:
123 		/* TBD */
124 		break;
125 	case TARGET_OEM_CONFIGURE_LCR:
126 		/* TBD */
127 		break;
128 	case TARGET_OEM_CONFIGURE_LCI:
129 		/* TBD */
130 		break;
131 	case TARGET_OEM_MEASUREMENT_REQ:
132 		/* TBD */
133 		break;
134 	case TARGET_OEM_CONFIGURE_FTMRR:
135 		/* TBD */
136 		break;
137 	case TARGET_OEM_CONFIGURE_WRU:
138 		/* TBD */
139 		break;
140 	default:
141 		wifi_pos_debug("invalid sub type or not passed");
142 		/*
143 		 * this is legacy MCL operation. pass whole msg to firmware as
144 		 * it is.
145 		 */
146 		tx_ops = target_if_wifi_pos_get_txops(psoc);
147 		if (!tx_ops) {
148 			wifi_pos_err("tx ops null");
149 			return QDF_STATUS_E_INVAL;
150 		}
151 		data_req.data_len = req->buf_len;
152 		data_req.data = req->buf;
153 		tx_ops->data_req_tx(psoc, &data_req);
154 		break;
155 	}
156 
157 	return QDF_STATUS_SUCCESS;
158 }
159 
160 static QDF_STATUS wifi_pos_process_set_cap_req(struct wlan_objmgr_psoc *psoc,
161 					struct wifi_pos_req_msg *req)
162 {
163 	int error_code;
164 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
165 				wifi_pos_get_psoc_priv_obj(psoc);
166 	struct wifi_pos_user_defined_caps *caps =
167 				(struct wifi_pos_user_defined_caps *)req->buf;
168 
169 	if (!wifi_pos_obj) {
170 		wifi_pos_err("wifi_pos priv obj is null");
171 		return QDF_STATUS_E_INVAL;
172 	}
173 
174 	wifi_pos_debug("Received set cap req pid(%d), len(%d)",
175 			req->pid, req->buf_len);
176 
177 	wifi_pos_obj->ftm_rr = caps->ftm_rr;
178 	wifi_pos_obj->lci_capability = caps->lci_capability;
179 	error_code = qdf_status_to_os_return(QDF_STATUS_SUCCESS);
180 	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
181 					ANI_MSG_SET_OEM_CAP_RSP,
182 					sizeof(error_code),
183 					(uint8_t *)&error_code);
184 
185 	return QDF_STATUS_SUCCESS;
186 }
187 
188 static QDF_STATUS wifi_pos_process_get_cap_req(struct wlan_objmgr_psoc *psoc,
189 					struct wifi_pos_req_msg *req)
190 {
191 	struct wifi_pos_oem_get_cap_rsp cap_rsp = { { {0} } };
192 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
193 					wifi_pos_get_psoc_priv_obj(psoc);
194 
195 	if (!wifi_pos_obj) {
196 		wifi_pos_err("wifi_pos priv obj is null");
197 		return QDF_STATUS_E_INVAL;
198 	}
199 
200 	wifi_pos_debug("Received get cap req pid(%d), len(%d)",
201 			req->pid, req->buf_len);
202 
203 	wifi_pos_populate_caps(psoc, &cap_rsp.driver_cap);
204 	cap_rsp.user_defined_cap.ftm_rr = wifi_pos_obj->ftm_rr;
205 	cap_rsp.user_defined_cap.lci_capability = wifi_pos_obj->lci_capability;
206 	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
207 					ANI_MSG_GET_OEM_CAP_RSP,
208 					sizeof(cap_rsp),
209 					(uint8_t *)&cap_rsp);
210 
211 	return QDF_STATUS_SUCCESS;
212 }
213 
214 static void wifi_update_channel_bw_info(struct wlan_objmgr_psoc *psoc,
215 					struct wlan_objmgr_pdev *pdev,
216 					uint16_t chan,
217 					struct wifi_pos_ch_info_rsp *chan_info)
218 {
219 	struct ch_params ch_params = {0};
220 	uint16_t sec_ch_2g = 0;
221 	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc =
222 		wifi_pos_get_psoc_priv_obj(psoc);
223 	uint32_t phy_mode;
224 
225 	if (!wifi_pos_psoc) {
226 		wifi_pos_err("wifi_pos priv obj is null");
227 		return;
228 	}
229 
230 	/* Passing CH_WIDTH_MAX will give the max bandwidth supported */
231 	ch_params.ch_width = CH_WIDTH_MAX;
232 
233 	wlan_reg_set_channel_params(pdev, chan, sec_ch_2g, &ch_params);
234 	if (ch_params.center_freq_seg0)
235 		chan_info->band_center_freq1 =
236 			wlan_reg_get_channel_freq(pdev,
237 						  ch_params.center_freq_seg0);
238 
239 	wifi_pos_psoc->wifi_pos_get_phy_mode(chan, ch_params.ch_width,
240 					     &phy_mode);
241 
242 	REG_SET_CHANNEL_MODE(chan_info, phy_mode);
243 }
244 
245 static void wifi_pos_get_reg_info(struct wlan_objmgr_pdev *pdev,
246 				  uint32_t chan_num, uint32_t *reg_info_1,
247 				  uint32_t *reg_info_2)
248 {
249 	uint32_t reg_power = wlan_reg_get_channel_reg_power(pdev, chan_num);
250 
251 	*reg_info_1 = 0;
252 	*reg_info_2 = 0;
253 
254 	REG_SET_CHANNEL_REG_POWER(*reg_info_1, reg_power);
255 	REG_SET_CHANNEL_MAX_TX_POWER(*reg_info_2, reg_power);
256 }
257 
258 /**
259  * wifi_pos_get_valid_channels: Get the list of valid channels from the
260  * given channel list
261  * @channels: Channel list to be validated
262  * @num_ch: NUmber of channels in the channel list to be validated
263  * @valid_channel_list: Pointer to valid channel list
264  *
265  * Return: Number of valid channels in the given list
266  */
267 
268 static uint32_t wifi_pos_get_valid_channels(uint8_t *channels, uint32_t num_ch,
269 					    uint8_t *valid_channel_list) {
270 	uint32_t i, num_valid_channels = 0;
271 
272 	for (i = 0; i < num_ch; i++) {
273 		if (wlan_reg_get_chan_enum(channels[i]) == INVALID_CHANNEL)
274 			continue;
275 		valid_channel_list[num_valid_channels++] = channels[i];
276 	}
277 	return num_valid_channels;
278 }
279 
280 static QDF_STATUS wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc,
281 					struct wifi_pos_req_msg *req)
282 {
283 	uint8_t idx;
284 	uint8_t *buf;
285 	uint32_t len;
286 	uint32_t reg_info_1;
287 	uint32_t reg_info_2;
288 	uint8_t *channels = req->buf;
289 	struct wlan_objmgr_pdev *pdev;
290 	uint32_t num_ch = req->buf_len;
291 	uint8_t valid_channel_list[NUM_CHANNELS];
292 	uint32_t num_valid_channels;
293 	struct wifi_pos_ch_info_rsp *ch_info;
294 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
295 					wifi_pos_get_psoc_priv_obj(psoc);
296 
297 	if (!wifi_pos_obj) {
298 		wifi_pos_err("wifi_pos priv obj is null");
299 		return QDF_STATUS_E_INVAL;
300 	}
301 
302 	wifi_pos_debug("Received ch info req pid(%d), len(%d)",
303 			req->pid, req->buf_len);
304 
305 	/* get first pdev since we need that only for freq and dfs state */
306 	pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_WIFI_POS_CORE_ID);
307 	if (!pdev) {
308 		wifi_pos_err("pdev get API failed");
309 		return QDF_STATUS_E_INVAL;
310 	}
311 	if (num_ch > NUM_CHANNELS) {
312 		wifi_pos_err("Invalid number of channels");
313 		return QDF_STATUS_E_INVAL;
314 	}
315 	num_valid_channels = wifi_pos_get_valid_channels(channels, num_ch,
316 							 valid_channel_list);
317 
318 	len = sizeof(uint8_t) + sizeof(struct wifi_pos_ch_info_rsp) *
319 			num_valid_channels;
320 	buf = qdf_mem_malloc(len);
321 	if (!buf) {
322 		wifi_pos_alert("malloc failed");
323 		wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID);
324 		return QDF_STATUS_E_NOMEM;
325 	}
326 
327 	qdf_mem_zero(buf, len);
328 
329 	/* First byte of message body will have num of channels */
330 	buf[0] = num_valid_channels;
331 	ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1];
332 	for (idx = 0; idx < num_valid_channels; idx++) {
333 		ch_info[idx].chan_id = valid_channel_list[idx];
334 		wifi_pos_get_reg_info(pdev, ch_info[idx].chan_id,
335 				      &reg_info_1, &reg_info_2);
336 		ch_info[idx].reserved0 = 0;
337 		ch_info[idx].mhz = wlan_reg_get_channel_freq(
338 						pdev,
339 						valid_channel_list[idx]);
340 		ch_info[idx].band_center_freq1 = ch_info[idx].mhz;
341 		ch_info[idx].band_center_freq2 = 0;
342 		ch_info[idx].info = 0;
343 		if (wlan_reg_is_dfs_ch(pdev, valid_channel_list[idx]))
344 			WIFI_POS_SET_DFS(ch_info[idx].info);
345 
346 		wifi_update_channel_bw_info(psoc, pdev,
347 					    ch_info[idx].chan_id,
348 					    &ch_info[idx]);
349 
350 		ch_info[idx].reg_info_1 = reg_info_1;
351 		ch_info[idx].reg_info_2 = reg_info_2;
352 	}
353 
354 	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
355 					ANI_MSG_CHANNEL_INFO_RSP,
356 					len, buf);
357 	qdf_mem_free(buf);
358 	wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID);
359 
360 	return QDF_STATUS_SUCCESS;
361 }
362 
363 static void wifi_pos_vdev_iterator(struct wlan_objmgr_psoc *psoc,
364 				   void *vdev, void *arg)
365 {
366 	struct app_reg_rsp_vdev_info *vdev_info = arg;
367 
368 	vdev_info[vdev_idx].dev_mode = wlan_vdev_mlme_get_opmode(vdev);
369 	vdev_info[vdev_idx].vdev_id = wlan_vdev_get_id(vdev);
370 	vdev_idx++;
371 }
372 
373 static QDF_STATUS wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc,
374 					struct wifi_pos_req_msg *req)
375 {
376 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
377 	uint8_t err = 0;
378 	uint32_t rsp_len;
379 	char *sign_str = NULL;
380 	struct wifi_app_reg_rsp *app_reg_rsp;
381 	struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS]
382 								= { { 0 } };
383 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
384 			wifi_pos_get_psoc_priv_obj(psoc);
385 
386 	if (!wifi_pos_obj) {
387 		wifi_pos_err("wifi_pos priv obj is null");
388 		return QDF_STATUS_E_INVAL;
389 	}
390 
391 	wifi_pos_err("Received App Req Req pid(%d), len(%d)",
392 			req->pid, req->buf_len);
393 
394 	sign_str = (char *)req->buf;
395 	/* Registration request is only allowed for QTI Application */
396 	if ((OEM_APP_SIGNATURE_LEN != req->buf_len) ||
397 		(strncmp(sign_str, OEM_APP_SIGNATURE_STR,
398 			 OEM_APP_SIGNATURE_LEN))) {
399 		wifi_pos_err("Invalid signature pid(%d)", req->pid);
400 		ret = QDF_STATUS_E_PERM;
401 		err = OEM_ERR_INVALID_SIGNATURE;
402 		goto app_reg_failed;
403 	}
404 
405 	wifi_pos_debug("Valid App Req Req from pid(%d)", req->pid);
406 	qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock);
407 	wifi_pos_obj->is_app_registered = true;
408 	wifi_pos_obj->app_pid = req->pid;
409 	qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock);
410 
411 	vdev_idx = 0;
412 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
413 				     wifi_pos_vdev_iterator,
414 				     vdevs_info, true, WLAN_WIFI_POS_CORE_ID);
415 	rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
416 			+ sizeof(uint8_t);
417 	app_reg_rsp = qdf_mem_malloc(rsp_len);
418 	if (!app_reg_rsp) {
419 		wifi_pos_alert("malloc failed");
420 		ret = QDF_STATUS_E_NOMEM;
421 		err = OEM_ERR_NULL_CONTEXT;
422 		goto app_reg_failed;
423 	}
424 
425 	app_reg_rsp->num_inf = vdev_idx;
426 	qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
427 		     sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
428 	if (!vdev_idx)
429 		wifi_pos_debug("no active vdev");
430 
431 	vdev_idx = 0;
432 	wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_APP_REG_RSP,
433 					rsp_len, (uint8_t *)app_reg_rsp);
434 
435 	qdf_mem_free(app_reg_rsp);
436 	return ret;
437 
438 app_reg_failed:
439 
440 	wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_OEM_ERROR,
441 					sizeof(err), &err);
442 	return ret;
443 }
444 
445 /**
446  * wifi_pos_tlv_callback: wifi pos msg handler registered for TLV type req
447  * @wmi_msg: wmi type request msg
448  *
449  * Return: status of operation
450  */
451 static QDF_STATUS wifi_pos_tlv_callback(struct wlan_objmgr_psoc *psoc,
452 					struct wifi_pos_req_msg *req)
453 {
454 	wifi_pos_debug("enter: msg_type: %d", req->msg_type);
455 	switch (req->msg_type) {
456 	case ANI_MSG_APP_REG_REQ:
457 		return wifi_pos_process_app_reg_req(psoc, req);
458 	case ANI_MSG_OEM_DATA_REQ:
459 		return wifi_pos_process_data_req(psoc, req);
460 	case ANI_MSG_CHANNEL_INFO_REQ:
461 		return wifi_pos_process_ch_info_req(psoc, req);
462 	case ANI_MSG_SET_OEM_CAP_REQ:
463 		return wifi_pos_process_set_cap_req(psoc, req);
464 	case ANI_MSG_GET_OEM_CAP_REQ:
465 		return wifi_pos_process_get_cap_req(psoc, req);
466 	default:
467 		wifi_pos_err("invalid request type");
468 		break;
469 	}
470 	return 0;
471 }
472 
473 /**
474  * wifi_pos_non_tlv_callback: wifi pos msg handler registered for non-TLV
475  * type req
476  * @wmi_msg: wmi type request msg
477  *
478  * Return: status of operation
479  */
480 static QDF_STATUS wifi_pos_non_tlv_callback(struct wlan_objmgr_psoc *psoc,
481 					    struct wifi_pos_req_msg *req)
482 {
483 	return QDF_STATUS_SUCCESS;
484 }
485 
486 QDF_STATUS wifi_pos_psoc_obj_created_notification(
487 		struct wlan_objmgr_psoc *psoc, void *arg_list)
488 {
489 	QDF_STATUS status;
490 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj;
491 
492 	/*
493 	 * this is for WIN, if they have multiple psoc, we dont want to create
494 	 * multiple priv object. Since there is just one LOWI app registered to
495 	 * one driver, avoid 2nd private object with another psoc.
496 	 */
497 	if (wifi_pos_get_psoc()) {
498 		wifi_pos_debug("global psoc obj already set. do not allocate another psoc private object");
499 		return QDF_STATUS_SUCCESS;
500 	} else {
501 		wifi_pos_debug("setting global pos object");
502 		wifi_pos_set_psoc(psoc);
503 	}
504 
505 	/* initialize wifi-pos psoc priv object */
506 	wifi_pos_obj = qdf_mem_malloc(sizeof(*wifi_pos_obj));
507 	if (!wifi_pos_obj) {
508 		wifi_pos_alert("Mem alloc failed for wifi pos psoc priv obj");
509 		wifi_pos_clear_psoc();
510 		return QDF_STATUS_E_NOMEM;
511 	}
512 
513 	qdf_spinlock_create(&wifi_pos_obj->wifi_pos_lock);
514 	/* Register TLV or non-TLV callbacks depending on target fw version */
515 	if (wifi_pos_get_tlv_support(psoc))
516 		wifi_pos_obj->wifi_pos_req_handler = wifi_pos_tlv_callback;
517 	else
518 		wifi_pos_obj->wifi_pos_req_handler = wifi_pos_non_tlv_callback;
519 
520 	/*
521 	 * MGMT Rx is not handled in this phase since wifi pos only uses few
522 	 * measurement subtypes under RRM_RADIO_MEASURE_REQ. Rest of them are
523 	 * used for 80211k. That part is not yet converged and still follows
524 	 * legacy MGMT Rx to work. Action frame in new TXRX can be registered
525 	 * at per ACTION Frame type granularity only.
526 	 */
527 
528 	status = wlan_objmgr_psoc_component_obj_attach(psoc,
529 						WLAN_UMAC_COMP_WIFI_POS,
530 						wifi_pos_obj,
531 						QDF_STATUS_SUCCESS);
532 
533 	if (QDF_IS_STATUS_ERROR(status)) {
534 		wifi_pos_err("obj attach with psoc failed with status: %d",
535 				status);
536 		qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock);
537 		qdf_mem_free(wifi_pos_obj);
538 		wifi_pos_clear_psoc();
539 	}
540 
541 	return status;
542 }
543 
544 QDF_STATUS  wifi_pos_psoc_obj_destroyed_notification(
545 		struct wlan_objmgr_psoc *psoc, void *arg_list)
546 {
547 	QDF_STATUS status;
548 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj = NULL;
549 
550 	if (wifi_pos_get_psoc() == psoc) {
551 		wifi_pos_debug("deregistering wifi_pos_psoc object");
552 		wifi_pos_clear_psoc();
553 	} else {
554 		wifi_pos_warn("un-related PSOC closed. do nothing");
555 		return QDF_STATUS_SUCCESS;
556 	}
557 
558 	wifi_pos_obj = wifi_pos_get_psoc_priv_obj(psoc);
559 	if (!wifi_pos_obj) {
560 		wifi_pos_err("wifi_pos_obj is NULL");
561 		return QDF_STATUS_E_FAULT;
562 	}
563 
564 	target_if_wifi_pos_deinit_dma_rings(psoc);
565 
566 	status = wlan_objmgr_psoc_component_obj_detach(psoc,
567 						WLAN_UMAC_COMP_WIFI_POS,
568 						wifi_pos_obj);
569 	if (status != QDF_STATUS_SUCCESS)
570 		wifi_pos_err("wifi_pos_obj detach failed");
571 
572 	wifi_pos_debug("wifi_pos_obj deleted with status %d", status);
573 	qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock);
574 	qdf_mem_free(wifi_pos_obj);
575 
576 	return status;
577 }
578 
579 int wifi_pos_oem_rsp_handler(struct wlan_objmgr_psoc *psoc,
580 			     struct oem_data_rsp *oem_rsp)
581 {
582 	uint32_t len;
583 	uint8_t *data;
584 	uint32_t app_pid;
585 	struct wifi_pos_psoc_priv_obj *priv =
586 					wifi_pos_get_psoc_priv_obj(psoc);
587 	void (*wifi_pos_send_rsp)(uint32_t, uint32_t, uint32_t, uint8_t *);
588 
589 	if (!priv) {
590 		wifi_pos_err("private object is NULL");
591 		return -EINVAL;
592 	}
593 
594 	qdf_spin_lock_bh(&priv->wifi_pos_lock);
595 	app_pid = priv->app_pid;
596 	wifi_pos_send_rsp = priv->wifi_pos_send_rsp;
597 	qdf_spin_unlock_bh(&priv->wifi_pos_lock);
598 
599 	len = oem_rsp->rsp_len_1 + oem_rsp->rsp_len_2 + oem_rsp->dma_len;
600 	if (oem_rsp->rsp_len_1 > OEM_DATA_RSP_SIZE ||
601 			oem_rsp->rsp_len_2 > OEM_DATA_RSP_SIZE) {
602 		wifi_pos_err("invalid length of Oem Data response");
603 		return -EINVAL;
604 	}
605 
606 	if (!wifi_pos_send_rsp) {
607 		wifi_pos_err("invalid response handler");
608 		return -EINVAL;
609 	}
610 
611 	wifi_pos_debug("oem data rsp, len: %d to pid: %d", len, app_pid);
612 
613 	if (oem_rsp->rsp_len_2 + oem_rsp->dma_len) {
614 		/* stitch togther the msg data_1 + CIR/CFR + data_2 */
615 		data = qdf_mem_malloc(len);
616 		if (!data) {
617 			wifi_pos_err("malloc failed");
618 			return -ENOMEM;
619 		}
620 		qdf_mem_copy(data, oem_rsp->data_1, oem_rsp->rsp_len_1);
621 		qdf_mem_copy(&data[oem_rsp->rsp_len_1],
622 			     oem_rsp->vaddr, oem_rsp->dma_len);
623 		qdf_mem_copy(&data[oem_rsp->rsp_len_1 + oem_rsp->dma_len],
624 			     oem_rsp->data_2, oem_rsp->rsp_len_2);
625 
626 		wifi_pos_send_rsp(app_pid, ANI_MSG_OEM_DATA_RSP, len, data);
627 		qdf_mem_free(data);
628 	} else {
629 		wifi_pos_send_rsp(app_pid, ANI_MSG_OEM_DATA_RSP,
630 				  oem_rsp->rsp_len_1, oem_rsp->data_1);
631 	}
632 
633 	return 0;
634 }
635 
636 static void wifi_pos_pdev_iterator(struct wlan_objmgr_psoc *psoc,
637 				   void *obj, void *arg)
638 {
639 	uint32_t i;
640 	QDF_STATUS status;
641 	struct wlan_objmgr_pdev *pdev = obj;
642 	struct regulatory_channel *psoc_ch_lst = arg;
643 	struct regulatory_channel pdev_ch_lst[NUM_CHANNELS];
644 
645 	status = wlan_reg_get_current_chan_list(pdev, pdev_ch_lst);
646 	if (QDF_IS_STATUS_ERROR(status)) {
647 		wifi_pos_err("wlan_reg_get_current_chan_list_by_range failed");
648 		return;
649 	}
650 
651 	for (i = 0; i < NUM_CHANNELS; i++) {
652 		if (pdev_ch_lst[i].state != CHANNEL_STATE_DISABLE &&
653 			pdev_ch_lst[i].state != CHANNEL_STATE_INVALID)
654 			psoc_ch_lst[i] = pdev_ch_lst[i];
655 	}
656 }
657 
658 static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc,
659 				 struct wifi_pos_driver_caps *caps)
660 {
661 	uint32_t i, num_ch = 0;
662 	struct regulatory_channel ch_lst[NUM_CHANNELS] = {{0}};
663 
664 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
665 				     wifi_pos_pdev_iterator,
666 				     ch_lst, true, WLAN_WIFI_POS_CORE_ID);
667 
668 	for (i = 0; i < NUM_CHANNELS && num_ch < OEM_CAP_MAX_NUM_CHANNELS;
669 	     i++) {
670 		if (ch_lst[i].state != CHANNEL_STATE_DISABLE &&
671 		    ch_lst[i].state != CHANNEL_STATE_INVALID) {
672 			num_ch++;
673 			caps->channel_list[i] = ch_lst[i].chan_num;
674 		}
675 	}
676 
677 	caps->num_channels = num_ch;
678 	wifi_pos_err("num channels: %d", num_ch);
679 }
680 
681 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
682 			   struct wifi_pos_driver_caps *caps)
683 {
684 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
685 					wifi_pos_get_psoc_priv_obj(psoc);
686 
687 	wifi_pos_debug("Enter");
688 	if (!wifi_pos_obj) {
689 		wifi_pos_err("wifi_pos_obj is null");
690 		return QDF_STATUS_E_NULL_VALUE;
691 	}
692 
693 	strlcpy(caps->oem_target_signature,
694 		OEM_TARGET_SIGNATURE,
695 		OEM_TARGET_SIGNATURE_LEN);
696 	caps->oem_target_type = wifi_pos_obj->oem_target_type;
697 	caps->oem_fw_version = wifi_pos_obj->oem_fw_version;
698 	caps->driver_version.major = wifi_pos_obj->driver_version.major;
699 	caps->driver_version.minor = wifi_pos_obj->driver_version.minor;
700 	caps->driver_version.patch = wifi_pos_obj->driver_version.patch;
701 	caps->driver_version.build = wifi_pos_obj->driver_version.build;
702 	caps->allowed_dwell_time_min = wifi_pos_obj->allowed_dwell_time_min;
703 	caps->allowed_dwell_time_max = wifi_pos_obj->allowed_dwell_time_max;
704 	caps->curr_dwell_time_min = wifi_pos_obj->current_dwell_time_min;
705 	caps->curr_dwell_time_max = wifi_pos_obj->current_dwell_time_max;
706 	caps->supported_bands = wlan_objmgr_psoc_get_band_capability(psoc);
707 	wifi_pos_get_ch_info(psoc, caps);
708 	return QDF_STATUS_SUCCESS;
709 }
710