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 wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID); 323 return QDF_STATUS_E_NOMEM; 324 } 325 326 qdf_mem_zero(buf, len); 327 328 /* First byte of message body will have num of channels */ 329 buf[0] = num_valid_channels; 330 ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1]; 331 for (idx = 0; idx < num_valid_channels; idx++) { 332 ch_info[idx].chan_id = valid_channel_list[idx]; 333 wifi_pos_get_reg_info(pdev, ch_info[idx].chan_id, 334 ®_info_1, ®_info_2); 335 ch_info[idx].reserved0 = 0; 336 ch_info[idx].mhz = wlan_reg_get_channel_freq( 337 pdev, 338 valid_channel_list[idx]); 339 ch_info[idx].band_center_freq1 = ch_info[idx].mhz; 340 ch_info[idx].band_center_freq2 = 0; 341 ch_info[idx].info = 0; 342 if (wlan_reg_is_dfs_ch(pdev, valid_channel_list[idx])) 343 WIFI_POS_SET_DFS(ch_info[idx].info); 344 345 wifi_update_channel_bw_info(psoc, pdev, 346 ch_info[idx].chan_id, 347 &ch_info[idx]); 348 349 ch_info[idx].reg_info_1 = reg_info_1; 350 ch_info[idx].reg_info_2 = reg_info_2; 351 } 352 353 wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid, 354 ANI_MSG_CHANNEL_INFO_RSP, 355 len, buf); 356 qdf_mem_free(buf); 357 wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID); 358 359 return QDF_STATUS_SUCCESS; 360 } 361 362 static void wifi_pos_vdev_iterator(struct wlan_objmgr_psoc *psoc, 363 void *vdev, void *arg) 364 { 365 struct app_reg_rsp_vdev_info *vdev_info = arg; 366 367 vdev_info[vdev_idx].dev_mode = wlan_vdev_mlme_get_opmode(vdev); 368 vdev_info[vdev_idx].vdev_id = wlan_vdev_get_id(vdev); 369 vdev_idx++; 370 } 371 372 static QDF_STATUS wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc, 373 struct wifi_pos_req_msg *req) 374 { 375 QDF_STATUS ret = QDF_STATUS_SUCCESS; 376 uint8_t err = 0; 377 uint32_t rsp_len; 378 char *sign_str = NULL; 379 struct wifi_app_reg_rsp *app_reg_rsp; 380 struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS] 381 = { { 0 } }; 382 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 383 wifi_pos_get_psoc_priv_obj(psoc); 384 385 if (!wifi_pos_obj) { 386 wifi_pos_err("wifi_pos priv obj is null"); 387 return QDF_STATUS_E_INVAL; 388 } 389 390 wifi_pos_err("Received App Req Req pid(%d), len(%d)", 391 req->pid, req->buf_len); 392 393 sign_str = (char *)req->buf; 394 /* Registration request is only allowed for QTI Application */ 395 if ((OEM_APP_SIGNATURE_LEN != req->buf_len) || 396 (strncmp(sign_str, OEM_APP_SIGNATURE_STR, 397 OEM_APP_SIGNATURE_LEN))) { 398 wifi_pos_err("Invalid signature pid(%d)", req->pid); 399 ret = QDF_STATUS_E_PERM; 400 err = OEM_ERR_INVALID_SIGNATURE; 401 goto app_reg_failed; 402 } 403 404 wifi_pos_debug("Valid App Req Req from pid(%d)", req->pid); 405 qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock); 406 wifi_pos_obj->is_app_registered = true; 407 wifi_pos_obj->app_pid = req->pid; 408 qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock); 409 410 vdev_idx = 0; 411 wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, 412 wifi_pos_vdev_iterator, 413 vdevs_info, true, WLAN_WIFI_POS_CORE_ID); 414 rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx) 415 + sizeof(uint8_t); 416 app_reg_rsp = qdf_mem_malloc(rsp_len); 417 if (!app_reg_rsp) { 418 ret = QDF_STATUS_E_NOMEM; 419 err = OEM_ERR_NULL_CONTEXT; 420 goto app_reg_failed; 421 } 422 423 app_reg_rsp->num_inf = vdev_idx; 424 qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info, 425 sizeof(struct app_reg_rsp_vdev_info) * vdev_idx); 426 if (!vdev_idx) 427 wifi_pos_debug("no active vdev"); 428 429 vdev_idx = 0; 430 wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_APP_REG_RSP, 431 rsp_len, (uint8_t *)app_reg_rsp); 432 433 qdf_mem_free(app_reg_rsp); 434 return ret; 435 436 app_reg_failed: 437 438 wifi_pos_obj->wifi_pos_send_rsp(req->pid, ANI_MSG_OEM_ERROR, 439 sizeof(err), &err); 440 return ret; 441 } 442 443 /** 444 * wifi_pos_tlv_callback: wifi pos msg handler registered for TLV type req 445 * @wmi_msg: wmi type request msg 446 * 447 * Return: status of operation 448 */ 449 static QDF_STATUS wifi_pos_tlv_callback(struct wlan_objmgr_psoc *psoc, 450 struct wifi_pos_req_msg *req) 451 { 452 wifi_pos_debug("enter: msg_type: %d", req->msg_type); 453 switch (req->msg_type) { 454 case ANI_MSG_APP_REG_REQ: 455 return wifi_pos_process_app_reg_req(psoc, req); 456 case ANI_MSG_OEM_DATA_REQ: 457 return wifi_pos_process_data_req(psoc, req); 458 case ANI_MSG_CHANNEL_INFO_REQ: 459 return wifi_pos_process_ch_info_req(psoc, req); 460 case ANI_MSG_SET_OEM_CAP_REQ: 461 return wifi_pos_process_set_cap_req(psoc, req); 462 case ANI_MSG_GET_OEM_CAP_REQ: 463 return wifi_pos_process_get_cap_req(psoc, req); 464 default: 465 wifi_pos_err("invalid request type"); 466 break; 467 } 468 return 0; 469 } 470 471 /** 472 * wifi_pos_non_tlv_callback: wifi pos msg handler registered for non-TLV 473 * type req 474 * @wmi_msg: wmi type request msg 475 * 476 * Return: status of operation 477 */ 478 static QDF_STATUS wifi_pos_non_tlv_callback(struct wlan_objmgr_psoc *psoc, 479 struct wifi_pos_req_msg *req) 480 { 481 return QDF_STATUS_SUCCESS; 482 } 483 484 QDF_STATUS wifi_pos_psoc_obj_created_notification( 485 struct wlan_objmgr_psoc *psoc, void *arg_list) 486 { 487 QDF_STATUS status; 488 struct wifi_pos_psoc_priv_obj *wifi_pos_obj; 489 490 /* 491 * this is for WIN, if they have multiple psoc, we dont want to create 492 * multiple priv object. Since there is just one LOWI app registered to 493 * one driver, avoid 2nd private object with another psoc. 494 */ 495 if (wifi_pos_get_psoc()) { 496 wifi_pos_debug("global psoc obj already set. do not allocate another psoc private object"); 497 return QDF_STATUS_SUCCESS; 498 } else { 499 wifi_pos_debug("setting global pos object"); 500 wifi_pos_set_psoc(psoc); 501 } 502 503 /* initialize wifi-pos psoc priv object */ 504 wifi_pos_obj = qdf_mem_malloc(sizeof(*wifi_pos_obj)); 505 if (!wifi_pos_obj) { 506 wifi_pos_clear_psoc(); 507 return QDF_STATUS_E_NOMEM; 508 } 509 510 qdf_spinlock_create(&wifi_pos_obj->wifi_pos_lock); 511 /* Register TLV or non-TLV callbacks depending on target fw version */ 512 if (wifi_pos_get_tlv_support(psoc)) 513 wifi_pos_obj->wifi_pos_req_handler = wifi_pos_tlv_callback; 514 else 515 wifi_pos_obj->wifi_pos_req_handler = wifi_pos_non_tlv_callback; 516 517 /* 518 * MGMT Rx is not handled in this phase since wifi pos only uses few 519 * measurement subtypes under RRM_RADIO_MEASURE_REQ. Rest of them are 520 * used for 80211k. That part is not yet converged and still follows 521 * legacy MGMT Rx to work. Action frame in new TXRX can be registered 522 * at per ACTION Frame type granularity only. 523 */ 524 525 status = wlan_objmgr_psoc_component_obj_attach(psoc, 526 WLAN_UMAC_COMP_WIFI_POS, 527 wifi_pos_obj, 528 QDF_STATUS_SUCCESS); 529 530 if (QDF_IS_STATUS_ERROR(status)) { 531 wifi_pos_err("obj attach with psoc failed with status: %d", 532 status); 533 qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock); 534 qdf_mem_free(wifi_pos_obj); 535 wifi_pos_clear_psoc(); 536 } 537 538 return status; 539 } 540 541 QDF_STATUS wifi_pos_psoc_obj_destroyed_notification( 542 struct wlan_objmgr_psoc *psoc, void *arg_list) 543 { 544 QDF_STATUS status; 545 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = NULL; 546 547 if (wifi_pos_get_psoc() == psoc) { 548 wifi_pos_debug("deregistering wifi_pos_psoc object"); 549 wifi_pos_clear_psoc(); 550 } else { 551 wifi_pos_warn("un-related PSOC closed. do nothing"); 552 return QDF_STATUS_SUCCESS; 553 } 554 555 wifi_pos_obj = wifi_pos_get_psoc_priv_obj(psoc); 556 if (!wifi_pos_obj) { 557 wifi_pos_err("wifi_pos_obj is NULL"); 558 return QDF_STATUS_E_FAULT; 559 } 560 561 target_if_wifi_pos_deinit_dma_rings(psoc); 562 563 status = wlan_objmgr_psoc_component_obj_detach(psoc, 564 WLAN_UMAC_COMP_WIFI_POS, 565 wifi_pos_obj); 566 if (status != QDF_STATUS_SUCCESS) 567 wifi_pos_err("wifi_pos_obj detach failed"); 568 569 wifi_pos_debug("wifi_pos_obj deleted with status %d", status); 570 qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock); 571 qdf_mem_free(wifi_pos_obj); 572 573 return status; 574 } 575 576 int wifi_pos_oem_rsp_handler(struct wlan_objmgr_psoc *psoc, 577 struct oem_data_rsp *oem_rsp) 578 { 579 uint32_t len; 580 uint8_t *data; 581 uint32_t app_pid; 582 struct wifi_pos_psoc_priv_obj *priv = 583 wifi_pos_get_psoc_priv_obj(psoc); 584 void (*wifi_pos_send_rsp)(uint32_t, uint32_t, uint32_t, uint8_t *); 585 586 if (!priv) { 587 wifi_pos_err("private object is NULL"); 588 return -EINVAL; 589 } 590 591 qdf_spin_lock_bh(&priv->wifi_pos_lock); 592 app_pid = priv->app_pid; 593 wifi_pos_send_rsp = priv->wifi_pos_send_rsp; 594 qdf_spin_unlock_bh(&priv->wifi_pos_lock); 595 596 len = oem_rsp->rsp_len_1 + oem_rsp->rsp_len_2 + oem_rsp->dma_len; 597 if (oem_rsp->rsp_len_1 > OEM_DATA_RSP_SIZE || 598 oem_rsp->rsp_len_2 > OEM_DATA_RSP_SIZE) { 599 wifi_pos_err("invalid length of Oem Data response"); 600 return -EINVAL; 601 } 602 603 if (!wifi_pos_send_rsp) { 604 wifi_pos_err("invalid response handler"); 605 return -EINVAL; 606 } 607 608 wifi_pos_debug("oem data rsp, len: %d to pid: %d", len, app_pid); 609 610 if (oem_rsp->rsp_len_2 + oem_rsp->dma_len) { 611 /* stitch togther the msg data_1 + CIR/CFR + data_2 */ 612 data = qdf_mem_malloc(len); 613 if (!data) 614 return -ENOMEM; 615 616 qdf_mem_copy(data, oem_rsp->data_1, oem_rsp->rsp_len_1); 617 qdf_mem_copy(&data[oem_rsp->rsp_len_1], 618 oem_rsp->vaddr, oem_rsp->dma_len); 619 qdf_mem_copy(&data[oem_rsp->rsp_len_1 + oem_rsp->dma_len], 620 oem_rsp->data_2, oem_rsp->rsp_len_2); 621 622 wifi_pos_send_rsp(app_pid, ANI_MSG_OEM_DATA_RSP, len, data); 623 qdf_mem_free(data); 624 } else { 625 wifi_pos_send_rsp(app_pid, ANI_MSG_OEM_DATA_RSP, 626 oem_rsp->rsp_len_1, oem_rsp->data_1); 627 } 628 629 return 0; 630 } 631 632 static void wifi_pos_pdev_iterator(struct wlan_objmgr_psoc *psoc, 633 void *obj, void *arg) 634 { 635 uint32_t i; 636 QDF_STATUS status; 637 struct wlan_objmgr_pdev *pdev = obj; 638 struct regulatory_channel *psoc_ch_lst = arg; 639 struct regulatory_channel pdev_ch_lst[NUM_CHANNELS]; 640 641 status = wlan_reg_get_current_chan_list(pdev, pdev_ch_lst); 642 if (QDF_IS_STATUS_ERROR(status)) { 643 wifi_pos_err("wlan_reg_get_current_chan_list_by_range failed"); 644 return; 645 } 646 647 for (i = 0; i < NUM_CHANNELS; i++) { 648 if (pdev_ch_lst[i].state != CHANNEL_STATE_DISABLE && 649 pdev_ch_lst[i].state != CHANNEL_STATE_INVALID) 650 psoc_ch_lst[i] = pdev_ch_lst[i]; 651 } 652 } 653 654 static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc, 655 struct wifi_pos_driver_caps *caps) 656 { 657 uint32_t i, num_ch = 0; 658 struct regulatory_channel ch_lst[NUM_CHANNELS] = {{0}}; 659 660 wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, 661 wifi_pos_pdev_iterator, 662 ch_lst, true, WLAN_WIFI_POS_CORE_ID); 663 664 for (i = 0; i < NUM_CHANNELS && num_ch < OEM_CAP_MAX_NUM_CHANNELS; 665 i++) { 666 if (ch_lst[i].state != CHANNEL_STATE_DISABLE && 667 ch_lst[i].state != CHANNEL_STATE_INVALID) { 668 num_ch++; 669 caps->channel_list[i] = ch_lst[i].chan_num; 670 } 671 } 672 673 caps->num_channels = num_ch; 674 wifi_pos_err("num channels: %d", num_ch); 675 } 676 677 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc, 678 struct wifi_pos_driver_caps *caps) 679 { 680 struct wifi_pos_psoc_priv_obj *wifi_pos_obj = 681 wifi_pos_get_psoc_priv_obj(psoc); 682 683 wifi_pos_debug("Enter"); 684 if (!wifi_pos_obj) { 685 wifi_pos_err("wifi_pos_obj is null"); 686 return QDF_STATUS_E_NULL_VALUE; 687 } 688 689 strlcpy(caps->oem_target_signature, 690 OEM_TARGET_SIGNATURE, 691 OEM_TARGET_SIGNATURE_LEN); 692 caps->oem_target_type = wifi_pos_obj->oem_target_type; 693 caps->oem_fw_version = wifi_pos_obj->oem_fw_version; 694 caps->driver_version.major = wifi_pos_obj->driver_version.major; 695 caps->driver_version.minor = wifi_pos_obj->driver_version.minor; 696 caps->driver_version.patch = wifi_pos_obj->driver_version.patch; 697 caps->driver_version.build = wifi_pos_obj->driver_version.build; 698 caps->allowed_dwell_time_min = wifi_pos_obj->allowed_dwell_time_min; 699 caps->allowed_dwell_time_max = wifi_pos_obj->allowed_dwell_time_max; 700 caps->curr_dwell_time_min = wifi_pos_obj->current_dwell_time_min; 701 caps->curr_dwell_time_max = wifi_pos_obj->current_dwell_time_max; 702 caps->supported_bands = wlan_objmgr_psoc_get_band_capability(psoc); 703 wifi_pos_get_ch_info(psoc, caps); 704 return QDF_STATUS_SUCCESS; 705 } 706