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