| /* |
| * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| /* |
| * This file was originally distributed by Qualcomm Atheros, Inc. |
| * under proprietary terms before Copyright ownership was assigned |
| * to the Linux Foundation. |
| */ |
| |
| /*======================================================================== |
| |
| \file epping_main.c |
| |
| \brief WLAN End Point Ping test tool implementation |
| |
| ========================================================================*/ |
| |
| /*-------------------------------------------------------------------------- |
| Include Files |
| ------------------------------------------------------------------------*/ |
| #include <wlan_hdd_includes.h> |
| #include <vos_api.h> |
| #include <vos_sched.h> |
| #include <linux/etherdevice.h> |
| #include <linux/firmware.h> |
| #include <wcnss_api.h> |
| #include <wlan_hdd_tx_rx.h> |
| #include <wniApi.h> |
| #include <wlan_nlink_srv.h> |
| #include <wlan_hdd_cfg.h> |
| #include <wlan_ptt_sock_svc.h> |
| #include <wlan_hdd_wowl.h> |
| #include <wlan_hdd_misc.h> |
| #include <wlan_hdd_wext.h> |
| #include <linux/wireless.h> |
| #include <net/cfg80211.h> |
| #include <linux/rtnetlink.h> |
| #include <linux/semaphore.h> |
| #include <linux/ctype.h> |
| #include <wlan_hdd_hostapd.h> |
| #include <wlan_hdd_softap_tx_rx.h> |
| #include "bmi.h" |
| #include "ol_fw.h" |
| #include "ol_if_athvar.h" |
| #if defined(HIF_PCI) |
| #include "if_pci.h" |
| #elif defined(HIF_USB) |
| #include "if_usb.h" |
| #elif defined(HIF_SDIO) |
| #include "if_ath_sdio.h" |
| #endif |
| #include "epping_main.h" |
| #include "epping_internal.h" |
| |
| #ifdef TIMER_MANAGER |
| #define TIMER_MANAGER_STR " +TIMER_MANAGER" |
| #else |
| #define TIMER_MANAGER_STR "" |
| #endif |
| |
| #ifdef MEMORY_DEBUG |
| #define MEMORY_DEBUG_STR " +MEMORY_DEBUG" |
| #else |
| #define MEMORY_DEBUG_STR "" |
| #endif |
| |
| #if defined(HIF_PCI) || defined(HIF_USB) |
| extern int hif_register_driver(void); |
| extern void hif_unregister_driver(void); |
| #endif |
| |
| /**--------------------------------------------------------------------------- |
| |
| \brief epping_driver_init() - End point ping driver Init Function |
| |
| This is the driver entry point - called in different timeline depending |
| on whether the driver is statically or dynamically linked |
| |
| \param - con_mode connection mode |
| |
| \return - 0 for success, negative for failure |
| |
| ----------------------------------------------------------------------------*/ |
| int epping_driver_init(int con_mode, vos_wake_lock_t *g_wake_lock, |
| char *pwlan_module_name) |
| { |
| int ret = 0; |
| unsigned long rc; |
| epping_context_t *pEpping_ctx = NULL; |
| VOS_STATUS status = VOS_STATUS_SUCCESS; |
| |
| EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__); |
| |
| #ifdef TIMER_MANAGER |
| vos_timer_manager_init(); |
| #endif |
| #ifdef MEMORY_DEBUG |
| vos_mem_init(); |
| adf_net_buf_debug_init(); |
| #endif |
| |
| pEpping_ctx = vos_mem_malloc(sizeof(epping_context_t)); |
| if (pEpping_ctx == NULL) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, "%s: No memory", __func__); |
| ret = -ENOMEM; |
| goto error1; |
| } |
| vos_mem_zero(pEpping_ctx, sizeof(epping_context_t)); |
| pEpping_ctx->g_wake_lock = g_wake_lock; |
| pEpping_ctx->con_mode = con_mode; |
| pEpping_ctx->pwlan_module_name = pwlan_module_name; |
| |
| status = vos_preOpen(&pEpping_ctx->pVosContext); |
| if (!VOS_IS_STATUS_SUCCESS(status)) |
| { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: Failed to preOpen VOSS", __func__); |
| ret = -1; |
| goto error1; |
| } |
| |
| /* save epping_context in VOSS */ |
| ((VosContextType *)(pEpping_ctx->pVosContext))->pHDDContext = |
| (v_VOID_t*)pEpping_ctx; |
| |
| #ifdef HIF_SDIO |
| #define WLAN_WAIT_TIME_WLANSTART 10000 |
| #else |
| #define WLAN_WAIT_TIME_WLANSTART 2000 |
| #endif |
| init_completion(&pEpping_ctx->wlan_start_comp); |
| ret = hif_register_driver(); |
| if (!ret) { |
| rc = wait_for_completion_timeout( |
| &pEpping_ctx->wlan_start_comp, |
| msecs_to_jiffies(WLAN_WAIT_TIME_WLANSTART)); |
| if (!rc) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: timed-out waiting for hif_register_driver", __func__); |
| ret = -1; |
| } else |
| ret = 0; |
| } |
| if (ret) |
| { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: %s driver Initialization failed", |
| __func__, pEpping_ctx->pwlan_module_name); |
| hif_unregister_driver(); |
| vos_preClose(&pEpping_ctx->pVosContext); |
| ret = -ENODEV; |
| vos_mem_free(pEpping_ctx); |
| |
| #ifdef MEMORY_DEBUG |
| adf_net_buf_debug_exit(); |
| vos_mem_exit(); |
| #endif |
| #ifdef TIMER_MANAGER |
| vos_timer_exit(); |
| #endif |
| return ret; |
| } else { |
| pr_info("%s: %s driver loaded\n", |
| __func__, pEpping_ctx->pwlan_module_name); |
| return 0; |
| } |
| error1: |
| if (pEpping_ctx) { |
| vos_mem_free(pEpping_ctx); |
| pEpping_ctx = NULL; |
| } |
| #ifdef MEMORY_DEBUG |
| adf_net_buf_debug_exit(); |
| vos_mem_exit(); |
| #endif |
| #ifdef TIMER_MANAGER |
| vos_timer_exit(); |
| #endif |
| return ret; |
| } |
| |
| void epping_exit(v_CONTEXT_t pVosContext) |
| { |
| epping_context_t *pEpping_ctx; |
| VosContextType *gpVosContext; |
| |
| pEpping_ctx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext); |
| if (pEpping_ctx == NULL) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: error: pEpping_ctx = NULL", |
| __func__); |
| return; |
| } |
| gpVosContext = pEpping_ctx->pVosContext; |
| if (pVosContext == NULL) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: error: pVosContext = NULL", |
| __func__); |
| return; |
| } |
| if (pEpping_ctx->epping_adapter) { |
| epping_destroy_adapter(pEpping_ctx->epping_adapter); |
| pEpping_ctx->epping_adapter = NULL; |
| } |
| hif_disable_isr(gpVosContext->pHIFContext); |
| hif_reset_soc(gpVosContext->pHIFContext); |
| HTCStop(gpVosContext->htc_ctx); |
| HTCDestroy(gpVosContext->htc_ctx); |
| gpVosContext->htc_ctx = NULL; |
| #ifdef HIF_PCI |
| { |
| int i; |
| for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) { |
| epping_unregister_tx_copier(i, pEpping_ctx); |
| } |
| } |
| #endif /* HIF_PCI */ |
| epping_cookie_cleanup(pEpping_ctx); |
| } |
| |
| void epping_driver_exit(v_CONTEXT_t pVosContext) |
| { |
| epping_context_t *pEpping_ctx; |
| |
| pr_info("%s: unloading driver\n", __func__); |
| |
| pEpping_ctx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext); |
| |
| if(!pEpping_ctx) |
| { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: module exit called before probe",__func__); |
| } |
| else |
| { |
| vos_set_unload_in_progress(TRUE); |
| vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE); |
| } |
| hif_unregister_driver(); |
| vos_mem_free(pEpping_ctx); |
| vos_preClose( &pVosContext ); |
| #ifdef MEMORY_DEBUG |
| adf_net_buf_debug_exit(); |
| vos_mem_exit(); |
| #endif |
| #ifdef TIMER_MANAGER |
| vos_timer_exit(); |
| #endif |
| pr_info("%s: driver unloaded\n", __func__); |
| } |
| |
| static void epping_target_suspend_acknowledge(void *context) |
| { |
| void *vos_context = vos_get_global_context(VOS_MODULE_ID_WDA, NULL); |
| epping_context_t *pEpping_ctx = vos_get_context(VOS_MODULE_ID_HDD, |
| vos_context); |
| int wow_nack = *((int *)context); |
| |
| if (NULL == pEpping_ctx) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: epping_ctx is NULL", __func__); |
| return; |
| } |
| /* EPPING_TODO: do we need wow_nack? */ |
| pEpping_ctx->wow_nack = wow_nack; |
| } |
| |
| int epping_wlan_startup(struct device *parent_dev, v_VOID_t *hif_sc) |
| { |
| int ret = 0; |
| epping_context_t *pEpping_ctx = NULL; |
| VosContextType *pVosContext = NULL; |
| HTC_INIT_INFO htcInfo; |
| struct ol_softc *scn; |
| tSirMacAddr adapter_macAddr; |
| adf_os_device_t adf_ctx; |
| |
| EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__); |
| |
| pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); |
| |
| if(pVosContext == NULL) |
| { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: Failed vos_get_global_context", __func__); |
| ret = -1; |
| return ret; |
| } |
| |
| pEpping_ctx = vos_get_context(VOS_MODULE_ID_HDD, pVosContext); |
| if(pEpping_ctx == NULL) |
| { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: Failed to get pEpping_ctx", __func__); |
| ret = -1; |
| return ret; |
| } |
| pEpping_ctx->parent_dev = (void *)parent_dev; |
| epping_get_dummy_mac_addr(adapter_macAddr); |
| |
| ((VosContextType*)pVosContext)->pHIFContext = hif_sc; |
| |
| /* store target type and target version info in hdd ctx */ |
| pEpping_ctx->target_type = ((struct ol_softc *)hif_sc)->target_type; |
| |
| /* Initialize the timer module */ |
| vos_timer_module_init(); |
| |
| scn = vos_get_context(VOS_MODULE_ID_HIF, pVosContext); |
| if (!scn) { |
| VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, |
| "%s: scn is null!", __func__); |
| return -1; |
| } |
| scn->enableuartprint = 0; |
| scn->enablefwlog = 0; |
| |
| /* Initialize BMI and Download firmware */ |
| if (bmi_download_firmware(scn)) { |
| VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, |
| "%s: BMI failed to download target", __func__); |
| BMICleanup(scn); |
| return -1; |
| } |
| |
| EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, |
| "%s: bmi_download_firmware done", __func__); |
| |
| htcInfo.pContext = pVosContext->pHIFContext; |
| htcInfo.TargetFailure = ol_target_failure; |
| htcInfo.TargetSendSuspendComplete = epping_target_suspend_acknowledge; |
| adf_ctx = vos_get_context(VOS_MODULE_ID_ADF, pVosContext); |
| |
| /* Create HTC */ |
| pVosContext->htc_ctx = HTCCreate(htcInfo.pContext, &htcInfo, adf_ctx); |
| if (!pVosContext->htc_ctx) { |
| VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, |
| "%s: Failed to Create HTC", __func__); |
| BMICleanup(scn); |
| return -1; |
| } |
| pEpping_ctx->HTCHandle = vos_get_context(VOS_MODULE_ID_HTC, pVosContext); |
| if (pEpping_ctx->HTCHandle == NULL) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: HTCHandle is NULL", __func__); |
| return -1; |
| } |
| scn->htc_handle = pEpping_ctx->HTCHandle; |
| |
| HIFClaimDevice(scn->hif_hdl, scn); |
| |
| if (bmi_done(scn)) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: Failed to complete BMI phase", __func__); |
| goto error_end; |
| } |
| /* start HIF */ |
| if (HTCWaitTarget(scn->htc_handle) != A_OK) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: HTCWaitTarget error", __func__); |
| goto error_end; |
| } |
| EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, |
| "%s: HTC ready", __func__); |
| |
| ret = epping_connect_service(pEpping_ctx); |
| if (ret != 0) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: HTCWaitTargetdone", __func__); |
| goto error_end; |
| } |
| if (HTCStart(pEpping_ctx->HTCHandle) != A_OK) { |
| goto error_end; |
| } |
| EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, |
| "%s: HTC started", __func__); |
| |
| /* init the tx cookie resource */ |
| ret = epping_cookie_init(pEpping_ctx); |
| if (ret == 0) { |
| pEpping_ctx->epping_adapter = epping_add_adapter(pEpping_ctx, |
| adapter_macAddr, |
| WLAN_HDD_INFRA_STATION); |
| } |
| if (ret < 0 || pEpping_ctx->epping_adapter == NULL) { |
| EPPING_LOG(VOS_TRACE_LEVEL_FATAL, |
| "%s: epping_add_adaptererror error", __func__); |
| HTCStop(pEpping_ctx->HTCHandle); |
| epping_cookie_cleanup(pEpping_ctx); |
| goto error_end; |
| } |
| #ifdef HIF_PCI |
| { |
| int i; |
| for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) { |
| epping_register_tx_copier(i, pEpping_ctx); |
| } |
| } |
| #endif /* HIF_PCI */ |
| EPPING_LOG(VOS_TRACE_LEVEL_INFO_HIGH, "%s: Exit", __func__); |
| complete(&pEpping_ctx->wlan_start_comp); |
| return ret; |
| |
| error_end: |
| HTCDestroy(pVosContext->htc_ctx); |
| pVosContext->htc_ctx = NULL; |
| BMICleanup(scn); |
| return -1; |
| } |