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 #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 (INVALID_CHANNEL == reg_get_chan_enum(channels[i])) 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 ®_info_1, ®_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