xref: /wlan-dirver/qca-wifi-host-cmn/umac/wifi_pos/src/wifi_pos_main.c (revision 92d87f51612f6c3b2285266215edee8911647c2f)
1 /*
2  * Copyright (c) 2012-2018 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 /*
42  * obj mgr api to iterate over vdevs does not provide a direct array or vdevs,
43  * rather takes a callback that is called for every vdev. wifi pos needs to
44  * store device mode and vdev id of all active vdevs and provide this info to
45  * user space as part of APP registration response. due to this, vdev_idx is
46  * used to identify how many vdevs have been populated by obj manager API.
47  */
48 static uint32_t vdev_idx;
49 
50 /**
51  * wifi_pos_get_tlv_support: indicates if firmware supports TLV wifi pos msg
52  * @psoc: psoc object
53  *
54  * Return: status of operation
55  */
56 static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc)
57 {
58 	/* this is TBD */
59 	return true;
60 }
61 
62 static QDF_STATUS wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc,
63 					struct wifi_pos_req_msg *req)
64 {
65 	uint8_t idx;
66 	uint32_t sub_type = 0;
67 	uint32_t channel_mhz = 0;
68 	void *pdev_id = NULL;
69 	uint32_t offset;
70 	struct oem_data_req data_req;
71 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
72 
73 	wifi_pos_debug("Received data req pid(%d), len(%d)",
74 			req->pid, req->buf_len);
75 
76 	/* look for fields */
77 	if (req->field_info_buf)
78 		for (idx = 0; idx < req->field_info_buf->count; idx++) {
79 			offset = req->field_info_buf->fields[idx].offset;
80 			/*
81 			 * replace following reads with read_api based on
82 			 * length
83 			 */
84 			if (req->field_info_buf->fields[idx].id ==
85 					WMIRTT_FIELD_ID_oem_data_sub_type) {
86 				sub_type = *((uint32_t *)&req->buf[offset]);
87 				continue;
88 			}
89 
90 			if (req->field_info_buf->fields[idx].id ==
91 					WMIRTT_FIELD_ID_channel_mhz) {
92 				channel_mhz = *((uint32_t *)&req->buf[offset]);
93 				continue;
94 			}
95 
96 			if (req->field_info_buf->fields[idx].id ==
97 					WMIRTT_FIELD_ID_pdev) {
98 				pdev_id = &req->buf[offset];
99 				continue;
100 			}
101 		}
102 
103 	switch (sub_type) {
104 	case TARGET_OEM_CAPABILITY_REQ:
105 		/* TBD */
106 		break;
107 	case TARGET_OEM_CONFIGURE_LCR:
108 		/* TBD */
109 		break;
110 	case TARGET_OEM_CONFIGURE_LCI:
111 		/* TBD */
112 		break;
113 	case TARGET_OEM_MEASUREMENT_REQ:
114 		/* TBD */
115 		break;
116 	case TARGET_OEM_CONFIGURE_FTMRR:
117 		/* TBD */
118 		break;
119 	case TARGET_OEM_CONFIGURE_WRU:
120 		/* TBD */
121 		break;
122 	default:
123 		wifi_pos_debug("invalid sub type or not passed");
124 		/*
125 		 * this is legacy MCL operation. pass whole msg to firmware as
126 		 * it is.
127 		 */
128 		tx_ops = target_if_wifi_pos_get_txops(psoc);
129 		if (!tx_ops) {
130 			wifi_pos_err("tx ops null");
131 			return QDF_STATUS_E_INVAL;
132 		}
133 		data_req.data_len = req->buf_len;
134 		data_req.data = req->buf;
135 		tx_ops->data_req_tx(psoc, &data_req);
136 		break;
137 	}
138 
139 	return QDF_STATUS_SUCCESS;
140 }
141 
142 static QDF_STATUS wifi_pos_process_set_cap_req(struct wlan_objmgr_psoc *psoc,
143 					struct wifi_pos_req_msg *req)
144 {
145 	int error_code;
146 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
147 				wifi_pos_get_psoc_priv_obj(psoc);
148 	struct wifi_pos_user_defined_caps *caps =
149 				(struct wifi_pos_user_defined_caps *)req->buf;
150 
151 	wifi_pos_debug("Received set cap req pid(%d), len(%d)",
152 			req->pid, req->buf_len);
153 
154 	wifi_pos_obj->ftm_rr = caps->ftm_rr;
155 	wifi_pos_obj->lci_capability = caps->lci_capability;
156 	error_code = qdf_status_to_os_return(QDF_STATUS_SUCCESS);
157 	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
158 					ANI_MSG_SET_OEM_CAP_RSP,
159 					sizeof(error_code),
160 					(uint8_t *)&error_code);
161 
162 	return QDF_STATUS_SUCCESS;
163 }
164 
165 static QDF_STATUS wifi_pos_process_get_cap_req(struct wlan_objmgr_psoc *psoc,
166 					struct wifi_pos_req_msg *req)
167 {
168 	struct wifi_pos_oem_get_cap_rsp cap_rsp = { { {0} } };
169 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
170 					wifi_pos_get_psoc_priv_obj(psoc);
171 
172 	wifi_pos_debug("Received get cap req pid(%d), len(%d)",
173 			req->pid, req->buf_len);
174 
175 	wifi_pos_populate_caps(psoc, &cap_rsp.driver_cap);
176 	cap_rsp.user_defined_cap.ftm_rr = wifi_pos_obj->ftm_rr;
177 	cap_rsp.user_defined_cap.lci_capability = wifi_pos_obj->lci_capability;
178 	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
179 					ANI_MSG_GET_OEM_CAP_RSP,
180 					sizeof(cap_rsp),
181 					(uint8_t *)&cap_rsp);
182 
183 	return QDF_STATUS_SUCCESS;
184 }
185 
186 static QDF_STATUS wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc,
187 					struct wifi_pos_req_msg *req)
188 {
189 	uint8_t idx;
190 	uint8_t *buf;
191 	uint32_t len;
192 	uint8_t *channels = req->buf;
193 	struct wlan_objmgr_pdev *pdev;
194 	uint32_t num_ch = req->buf_len;
195 	struct wifi_pos_ch_info_rsp *ch_info;
196 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
197 					wifi_pos_get_psoc_priv_obj(psoc);
198 
199 	wifi_pos_debug("Received ch info req pid(%d), len(%d)",
200 			req->pid, req->buf_len);
201 
202 	/* get first pdev since we need that only for freq and dfs state */
203 	pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_WIFI_POS_CORE_ID);
204 	if (!pdev) {
205 		wifi_pos_err("pdev get API failed");
206 		return QDF_STATUS_E_INVAL;
207 	}
208 
209 	len = sizeof(uint8_t) + sizeof(struct wifi_pos_ch_info_rsp) * num_ch;
210 	buf = qdf_mem_malloc(len);
211 	if (!buf) {
212 		wifi_pos_alert("malloc failed");
213 		wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID);
214 		return QDF_STATUS_E_NOMEM;
215 	}
216 
217 	/* First byte of message body will have num of channels */
218 	buf[0] = num_ch;
219 	ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1];
220 	for (idx = 0; idx < num_ch; idx++) {
221 		ch_info[idx].chan_id = channels[idx];
222 		ch_info[idx].reserved0 = 0;
223 		ch_info[idx].mhz = wlan_reg_get_channel_freq(pdev,
224 							channels[idx]);
225 		ch_info[idx].band_center_freq1 = ch_info[idx].mhz;
226 		ch_info[idx].band_center_freq2 = 0;
227 		ch_info[idx].info = 0;
228 		if (wlan_reg_is_dfs_ch(pdev, channels[idx]))
229 			WIFI_POS_SET_DFS(ch_info[idx].info);
230 		ch_info[idx].reg_info_1 = 0;
231 		ch_info[idx].reg_info_2 = 0;
232 	}
233 
234 	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
235 					ANI_MSG_CHANNEL_INFO_RSP,
236 					len, buf);
237 	qdf_mem_free(buf);
238 	wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID);
239 
240 	return QDF_STATUS_SUCCESS;
241 }
242 
243 static void wifi_pos_vdev_iterator(struct wlan_objmgr_psoc *psoc,
244 				   void *vdev, void *arg)
245 {
246 	struct app_reg_rsp_vdev_info *vdev_info = arg;
247 
248 	vdev_info[vdev_idx].dev_mode = wlan_vdev_mlme_get_opmode(vdev);
249 	vdev_info[vdev_idx].vdev_id = wlan_vdev_get_id(vdev);
250 	vdev_idx++;
251 }
252 
253 static QDF_STATUS wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc,
254 					struct wifi_pos_req_msg *req)
255 {
256 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
257 	uint8_t err = 0;
258 	uint32_t rsp_len;
259 	char *sign_str = NULL;
260 	struct wifi_app_reg_rsp *app_reg_rsp;
261 	struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS]
262 								= { { 0 } };
263 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
264 			wifi_pos_get_psoc_priv_obj(psoc);
265 
266 	wifi_pos_err("Received App Req Req pid(%d), len(%d)",
267 			req->pid, req->buf_len);
268 
269 	sign_str = (char *)req->buf;
270 	/* Registration request is only allowed for QTI Application */
271 	if ((OEM_APP_SIGNATURE_LEN != req->buf_len) ||
272 		(strncmp(sign_str, OEM_APP_SIGNATURE_STR,
273 			 OEM_APP_SIGNATURE_LEN))) {
274 		wifi_pos_err("Invalid signature pid(%d)", req->pid);
275 		ret = QDF_STATUS_E_PERM;
276 		err = OEM_ERR_INVALID_SIGNATURE;
277 		goto app_reg_failed;
278 	}
279 
280 	wifi_pos_debug("Valid App Req Req from pid(%d)", req->pid);
281 	wifi_pos_obj->is_app_registered = true;
282 	wifi_pos_obj->app_pid = req->pid;
283 
284 	vdev_idx = 0;
285 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
286 				     wifi_pos_vdev_iterator,
287 				     vdevs_info, true, WLAN_WIFI_POS_CORE_ID);
288 	rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
289 			+ sizeof(uint8_t);
290 	app_reg_rsp = qdf_mem_malloc(rsp_len);
291 	if (!app_reg_rsp) {
292 		wifi_pos_alert("malloc failed");
293 		ret = QDF_STATUS_E_NOMEM;
294 		err = OEM_ERR_NULL_CONTEXT;
295 		goto app_reg_failed;
296 	}
297 
298 	app_reg_rsp->num_inf = vdev_idx;
299 	qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
300 		     sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
301 	if (!vdev_idx)
302 		wifi_pos_debug("no active vdev");
303 
304 	vdev_idx = 0;
305 	wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_APP_REG_RSP,
306 					rsp_len, (uint8_t *)app_reg_rsp);
307 
308 	qdf_mem_free(app_reg_rsp);
309 	return ret;
310 
311 app_reg_failed:
312 
313 	wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_OEM_ERROR,
314 					sizeof(err), &err);
315 	return ret;
316 }
317 
318 /**
319  * wifi_pos_tlv_callback: wifi pos msg handler registered for TLV type req
320  * @wmi_msg: wmi type request msg
321  *
322  * Return: status of operation
323  */
324 static QDF_STATUS wifi_pos_tlv_callback(struct wlan_objmgr_psoc *psoc,
325 					struct wifi_pos_req_msg *req)
326 {
327 	wifi_pos_debug("enter: msg_type: %d", req->msg_type);
328 	switch (req->msg_type) {
329 	case ANI_MSG_APP_REG_REQ:
330 		return wifi_pos_process_app_reg_req(psoc, req);
331 	case ANI_MSG_OEM_DATA_REQ:
332 		return wifi_pos_process_data_req(psoc, req);
333 	case ANI_MSG_CHANNEL_INFO_REQ:
334 		return wifi_pos_process_ch_info_req(psoc, req);
335 	case ANI_MSG_SET_OEM_CAP_REQ:
336 		return wifi_pos_process_set_cap_req(psoc, req);
337 	case ANI_MSG_GET_OEM_CAP_REQ:
338 		return wifi_pos_process_get_cap_req(psoc, req);
339 	default:
340 		wifi_pos_err("invalid request type");
341 		break;
342 	}
343 	return 0;
344 }
345 
346 /**
347  * wifi_pos_non_tlv_callback: wifi pos msg handler registered for non-TLV
348  * type req
349  * @wmi_msg: wmi type request msg
350  *
351  * Return: status of operation
352  */
353 static QDF_STATUS wifi_pos_non_tlv_callback(struct wlan_objmgr_psoc *psoc,
354 					    struct wifi_pos_req_msg *req)
355 {
356 	return QDF_STATUS_SUCCESS;
357 }
358 
359 QDF_STATUS wifi_pos_psoc_obj_created_notification(
360 		struct wlan_objmgr_psoc *psoc, void *arg_list)
361 {
362 	QDF_STATUS status;
363 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj;
364 
365 	/*
366 	 * this is for WIN, if they have multiple psoc, we dont want to create
367 	 * multiple priv object. Since there is just one LOWI app registered to
368 	 * one driver, avoid 2nd private object with another psoc.
369 	 */
370 	if (wifi_pos_get_psoc()) {
371 		wifi_pos_debug("global psoc obj already set. do not allocate another psoc private object");
372 		return QDF_STATUS_SUCCESS;
373 	} else {
374 		wifi_pos_debug("setting global pos object");
375 		wifi_pos_set_psoc(psoc);
376 	}
377 
378 	/* initialize wifi-pos psoc priv object */
379 	wifi_pos_obj = qdf_mem_malloc(sizeof(*wifi_pos_obj));
380 	if (!wifi_pos_obj) {
381 		wifi_pos_alert("Mem alloc failed for wifi pos psoc priv obj");
382 		wifi_pos_clear_psoc();
383 		return QDF_STATUS_E_NOMEM;
384 	}
385 
386 	qdf_spinlock_create(&wifi_pos_obj->wifi_pos_lock);
387 	/* Register TLV or non-TLV callbacks depending on target fw version */
388 	if (wifi_pos_get_tlv_support(psoc))
389 		wifi_pos_obj->wifi_pos_req_handler = wifi_pos_tlv_callback;
390 	else
391 		wifi_pos_obj->wifi_pos_req_handler = wifi_pos_non_tlv_callback;
392 
393 	/*
394 	 * MGMT Rx is not handled in this phase since wifi pos only uses few
395 	 * measurement subtypes under RRM_RADIO_MEASURE_REQ. Rest of them are
396 	 * used for 80211k. That part is not yet converged and still follows
397 	 * legacy MGMT Rx to work. Action frame in new TXRX can be registered
398 	 * at per ACTION Frame type granularity only.
399 	 */
400 
401 	status = wlan_objmgr_psoc_component_obj_attach(psoc,
402 						WLAN_UMAC_COMP_WIFI_POS,
403 						wifi_pos_obj,
404 						QDF_STATUS_SUCCESS);
405 
406 	if (QDF_IS_STATUS_ERROR(status)) {
407 		wifi_pos_err("obj attach with psoc failed with status: %d",
408 				status);
409 		qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock);
410 		qdf_mem_free(wifi_pos_obj);
411 		wifi_pos_clear_psoc();
412 	}
413 
414 	return status;
415 }
416 
417 QDF_STATUS  wifi_pos_psoc_obj_destroyed_notification(
418 		struct wlan_objmgr_psoc *psoc, void *arg_list)
419 {
420 	QDF_STATUS status;
421 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj = NULL;
422 
423 	if (wifi_pos_get_psoc() == psoc) {
424 		wifi_pos_debug("deregistering wifi_pos_psoc object");
425 		wifi_pos_clear_psoc();
426 	} else {
427 		wifi_pos_warn("un-related PSOC closed. do nothing");
428 		return QDF_STATUS_SUCCESS;
429 	}
430 
431 	wifi_pos_obj = wifi_pos_get_psoc_priv_obj(psoc);
432 	if (!wifi_pos_obj) {
433 		wifi_pos_err("wifi_pos_obj is NULL");
434 		return QDF_STATUS_E_FAULT;
435 	}
436 
437 	target_if_wifi_pos_deinit_dma_rings(psoc);
438 
439 	status = wlan_objmgr_psoc_component_obj_detach(psoc,
440 						WLAN_UMAC_COMP_WIFI_POS,
441 						wifi_pos_obj);
442 	if (status != QDF_STATUS_SUCCESS)
443 		wifi_pos_err("wifi_pos_obj detach failed");
444 
445 	wifi_pos_debug("wifi_pos_obj deleted with status %d", status);
446 	qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock);
447 	qdf_mem_free(wifi_pos_obj);
448 
449 	return status;
450 }
451 
452 int wifi_pos_oem_rsp_handler(struct wlan_objmgr_psoc *psoc,
453 			     struct oem_data_rsp *oem_rsp)
454 {
455 	uint32_t len;
456 	uint8_t *data;
457 	uint32_t app_pid;
458 	struct wifi_pos_psoc_priv_obj *priv =
459 					wifi_pos_get_psoc_priv_obj(psoc);
460 	void (*wifi_pos_send_rsp)(uint32_t, uint32_t, uint32_t, uint8_t *);
461 
462 	if (!priv) {
463 		wifi_pos_err("private object is NULL");
464 		return -EINVAL;
465 	}
466 
467 	qdf_spin_lock_bh(&priv->wifi_pos_lock);
468 	app_pid = priv->app_pid;
469 	wifi_pos_send_rsp = priv->wifi_pos_send_rsp;
470 	qdf_spin_unlock_bh(&priv->wifi_pos_lock);
471 
472 	len = oem_rsp->rsp_len_1 + oem_rsp->rsp_len_2 + oem_rsp->dma_len;
473 	if (oem_rsp->rsp_len_1 > OEM_DATA_RSP_SIZE ||
474 			oem_rsp->rsp_len_2 > OEM_DATA_RSP_SIZE) {
475 		wifi_pos_err("invalid length of Oem Data response");
476 		return -EINVAL;
477 	}
478 
479 	wifi_pos_debug("oem data rsp, len: %d to pid: %d", len, app_pid);
480 
481 	if (oem_rsp->rsp_len_2 + oem_rsp->dma_len) {
482 		/* stitch togther the msg data_1 + CIR/CFR + data_2 */
483 		data = qdf_mem_malloc(len);
484 		if (!data) {
485 			wifi_pos_err("malloc failed");
486 			return -ENOMEM;
487 		}
488 		qdf_mem_copy(data, oem_rsp->data_1, oem_rsp->rsp_len_1);
489 		qdf_mem_copy(&data[oem_rsp->rsp_len_1],
490 			     oem_rsp->vaddr, oem_rsp->dma_len);
491 		qdf_mem_copy(&data[oem_rsp->rsp_len_1 + oem_rsp->dma_len],
492 			     oem_rsp->data_2, oem_rsp->rsp_len_2);
493 
494 		wifi_pos_send_rsp(app_pid, ANI_MSG_OEM_DATA_RSP, len, data);
495 		qdf_mem_free(data);
496 	} else {
497 		wifi_pos_send_rsp(app_pid, ANI_MSG_OEM_DATA_RSP,
498 				  oem_rsp->rsp_len_1, oem_rsp->data_1);
499 	}
500 
501 	return 0;
502 }
503 
504 static void wifi_pos_pdev_iterator(struct wlan_objmgr_psoc *psoc,
505 				   void *obj, void *arg)
506 {
507 	uint32_t i;
508 	QDF_STATUS status;
509 	struct wlan_objmgr_pdev *pdev = obj;
510 	struct regulatory_channel *psoc_ch_lst = arg;
511 	struct regulatory_channel pdev_ch_lst[NUM_CHANNELS];
512 
513 	status = wlan_reg_get_current_chan_list(pdev, pdev_ch_lst);
514 	if (QDF_IS_STATUS_ERROR(status)) {
515 		wifi_pos_err("wlan_reg_get_current_chan_list_by_range failed");
516 		return;
517 	}
518 
519 	for (i = 0; i < NUM_CHANNELS; i++) {
520 		if (pdev_ch_lst[i].state != CHANNEL_STATE_DISABLE &&
521 			pdev_ch_lst[i].state != CHANNEL_STATE_INVALID)
522 			psoc_ch_lst[i] = pdev_ch_lst[i];
523 	}
524 }
525 
526 static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc,
527 				 struct wifi_pos_driver_caps *caps)
528 {
529 	uint32_t i, num_ch = 0;
530 	struct regulatory_channel ch_lst[NUM_CHANNELS];
531 
532 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
533 				     wifi_pos_pdev_iterator,
534 				     ch_lst, true, WLAN_WIFI_POS_CORE_ID);
535 
536 	for (i = 0; i < NUM_CHANNELS && num_ch < OEM_CAP_MAX_NUM_CHANNELS;
537 	     i++) {
538 		if (ch_lst[i].state != CHANNEL_STATE_DISABLE &&
539 		    ch_lst[i].state != CHANNEL_STATE_INVALID) {
540 			num_ch++;
541 			caps->channel_list[i] = ch_lst[i].chan_num;
542 		}
543 	}
544 
545 	caps->num_channels = num_ch;
546 	wifi_pos_err("num channels: %d", num_ch);
547 }
548 
549 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
550 			   struct wifi_pos_driver_caps *caps)
551 {
552 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
553 					wifi_pos_get_psoc_priv_obj(psoc);
554 
555 	wifi_pos_debug("Enter");
556 	if (!wifi_pos_obj) {
557 		wifi_pos_err("wifi_pos_obj is null");
558 		return QDF_STATUS_E_NULL_VALUE;
559 	}
560 
561 	strlcpy(caps->oem_target_signature,
562 		OEM_TARGET_SIGNATURE,
563 		OEM_TARGET_SIGNATURE_LEN);
564 	caps->oem_target_type = wifi_pos_obj->oem_target_type;
565 	caps->oem_fw_version = wifi_pos_obj->oem_fw_version;
566 	caps->driver_version.major = wifi_pos_obj->driver_version.major;
567 	caps->driver_version.minor = wifi_pos_obj->driver_version.minor;
568 	caps->driver_version.patch = wifi_pos_obj->driver_version.patch;
569 	caps->driver_version.build = wifi_pos_obj->driver_version.build;
570 	caps->allowed_dwell_time_min = wifi_pos_obj->allowed_dwell_time_min;
571 	caps->allowed_dwell_time_max = wifi_pos_obj->allowed_dwell_time_max;
572 	caps->curr_dwell_time_min = wifi_pos_obj->current_dwell_time_min;
573 	caps->curr_dwell_time_max = wifi_pos_obj->current_dwell_time_max;
574 	caps->supported_bands = wlan_objmgr_psoc_get_band_capability(psoc);
575 	wifi_pos_get_ch_info(psoc, caps);
576 	return QDF_STATUS_SUCCESS;
577 }
578