| /****************************************************************************** |
| * |
| * This file is provided under a dual license. When you use or |
| * distribute this software, you may choose to be licensed under |
| * version 2 of the GNU General Public License ("GPLv2 License") |
| * or BSD License. |
| * |
| * GPLv2 License |
| * |
| * Copyright(C) 2016 MediaTek Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of version 2 of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * See http://www.gnu.org/licenses/gpl-2.0.html for more details. |
| * |
| * BSD LICENSE |
| * |
| * Copyright(C) 2016 MediaTek Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of the copyright holder nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| *****************************************************************************/ |
| /* |
| ** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/os/linux/gl_kal.c#10 |
| */ |
| |
| /*! \file gl_kal.c |
| * \brief GLUE Layer will export the required procedures here for internal driver stack. |
| * |
| * This file contains all routines which are exported from GLUE Layer to internal |
| * driver stack. |
| */ |
| |
| |
| /******************************************************************************* |
| * C O M P I L E R F L A G S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * E X T E R N A L R E F E R E N C E S |
| ******************************************************************************** |
| */ |
| #include "gl_os.h" |
| #include "gl_kal.h" |
| #include "gl_wext.h" |
| #include "precomp.h" |
| #if CFG_SUPPORT_AGPS_ASSIST |
| #include <net/netlink.h> |
| #endif |
| #include <linux/ctype.h> |
| #ifdef CFG_USE_LINUX_GPIO_GLUE |
| #include <linux/interrupt.h> |
| #endif |
| |
| /******************************************************************************* |
| * C O N S T A N T S |
| ******************************************************************************** |
| */ |
| #define FILE_NAME_MAX CFG_FW_NAME_MAX_LEN /* the maximum length of a file name */ |
| #define FILE_NAME_TOTAL 8 /* the maximum number of all possible file name */ |
| |
| /******************************************************************************* |
| * D A T A T Y P E S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * P U B L I C D A T A |
| ******************************************************************************** |
| */ |
| #if DBG |
| int allocatedMemSize; |
| #endif |
| |
| /******************************************************************************* |
| * P R I V A T E D A T A |
| ******************************************************************************** |
| */ |
| static PVOID pvIoBuffer; |
| static UINT_32 pvIoBufferSize; |
| static UINT_32 pvIoBufferUsage; |
| |
| /******************************************************************************* |
| * M A C R O S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * F U N C T I O N D E C L A R A T I O N S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * F U N C T I O N S |
| ******************************************************************************** |
| */ |
| #if CFG_ENABLE_FW_DOWNLOAD |
| |
| #if (defined(CONFIG_UIDGID_STRICT_TYPE_CHECKS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))) |
| #define KUIDT_VALUE(v) (v.val) |
| #define KGIDT_VALUE(v) (v.val) |
| #else |
| #define KUIDT_VALUE(v) v |
| #define KGIDT_VALUE(v) v |
| #endif |
| |
| const struct firmware *fw_entry; |
| |
| /* Default */ |
| static PUINT_8 apucFwName[] = { |
| (PUINT_8) CFG_FW_FILENAME "_MT", |
| |
| NULL |
| }; |
| |
| static PUINT_8 apucCr4FwName[] = { |
| (PUINT_8) CFG_CR4_FW_FILENAME "_" HIF_NAME "_MT", |
| (PUINT_8) CFG_CR4_FW_FILENAME "_MT", |
| NULL |
| }; |
| |
| static PUINT_8 apucPatchName[] = { |
| (PUINT_8) "mt6632_patch_e1_hdr.bin", |
| (PUINT_8) "mt7666_patch_e1_hdr.bin", |
| NULL |
| }; |
| |
| static PPUINT_8 appucFwNameTable[] = { |
| apucFwName |
| }; |
| #if CFG_ASSERT_DUMP |
| /* Core dump debug usage */ |
| #if MTK_WCN_HIF_SDIO |
| PUINT_8 apucCorDumpN9FileName = "/data/misc/wifi/FW_DUMP_N9"; |
| PUINT_8 apucCorDumpCr4FileName = "/data/misc/wifi/FW_DUMP_Cr4"; |
| #else |
| PUINT_8 apucCorDumpN9FileName = "/tmp/FW_DUMP_N9"; |
| PUINT_8 apucCorDumpCr4FileName = "/tmp/FW_DUMP_Cr4"; |
| #endif |
| #endif |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to |
| * open firmware image in kernel space |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval WLAN_STATUS_SUCCESS. |
| * \retval WLAN_STATUS_FAILURE. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS kalFirmwareOpen(IN P_GLUE_INFO_T prGlueInfo, IN PPUINT_8 apucNameTable) |
| { |
| UINT_8 ucNameIdx; |
| /* PPUINT_8 apucNameTable; */ |
| UINT_8 ucMaxEcoVer = (sizeof(appucFwNameTable) / sizeof(PPUINT_8)); |
| UINT_8 ucCurEcoVer = wlanGetEcoVersion(prGlueInfo->prAdapter); |
| BOOLEAN fgResult = FALSE; |
| int ret; |
| |
| /* Try to open FW binary */ |
| for (ucNameIdx = 0; apucNameTable[ucNameIdx]; ucNameIdx++) { |
| /* |
| * Driver support request_firmware() to get files |
| * Android path: "/etc/firmware", "/vendor/firmware", "/firmware/image" |
| * Linux path: "/lib/firmware", "/lib/firmware/update" |
| */ |
| ret = REQUEST_FIRMWARE(&fw_entry, apucNameTable[ucNameIdx], prGlueInfo->prDev); |
| |
| if (ret) { |
| DBGLOG(INIT, TRACE, "Request FW image: %s failed, errno[%d]\n", |
| apucNameTable[ucNameIdx], fgResult); |
| RELEASE_FIRMWARE(fw_entry); |
| continue; |
| } else { |
| DBGLOG(INIT, TRACE, "Request FW image: %s done\n", apucNameTable[ucNameIdx]); |
| fgResult = TRUE; |
| break; |
| } |
| } |
| |
| |
| /* Check result */ |
| if (!fgResult) |
| goto error_open; |
| |
| |
| return WLAN_STATUS_SUCCESS; |
| |
| error_open: |
| DBGLOG(INIT, ERROR, "Request FW image failed! Cur/Max ECO Ver[E%u/E%u]\n", ucCurEcoVer, ucMaxEcoVer); |
| |
| return WLAN_STATUS_FAILURE; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to |
| * release firmware image in kernel space |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval WLAN_STATUS_SUCCESS. |
| * \retval WLAN_STATUS_FAILURE. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS kalFirmwareClose(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| RELEASE_FIRMWARE(fw_entry); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to |
| * load firmware image in kernel space |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval WLAN_STATUS_SUCCESS. |
| * \retval WLAN_STATUS_FAILURE. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS kalFirmwareLoad(IN P_GLUE_INFO_T prGlueInfo, OUT PVOID prBuf, IN UINT_32 u4Offset, OUT PUINT_32 pu4Size) |
| { |
| ASSERT(prGlueInfo); |
| ASSERT(pu4Size); |
| ASSERT(prBuf); |
| |
| if ((fw_entry == NULL) || (fw_entry->size == 0) || (fw_entry->data == NULL)) { |
| goto error_read; |
| } else { |
| memcpy(prBuf, fw_entry->data, fw_entry->size); |
| *pu4Size = fw_entry->size; |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| |
| error_read: |
| return WLAN_STATUS_FAILURE; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to |
| * query firmware image size in kernel space |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval WLAN_STATUS_SUCCESS. |
| * \retval WLAN_STATUS_FAILURE. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| WLAN_STATUS kalFirmwareSize(IN P_GLUE_INFO_T prGlueInfo, OUT PUINT_32 pu4Size) |
| { |
| ASSERT(prGlueInfo); |
| ASSERT(pu4Size); |
| |
| *pu4Size = fw_entry->size; |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| VOID |
| kalConstructDefaultFirmwarePrio(P_GLUE_INFO_T prGlueInfo, PPUINT_8 apucNameTable, |
| PPUINT_8 apucName, PUINT_8 pucNameIdx, UINT_8 ucMaxNameIdx) |
| { |
| struct mt66xx_chip_info *prChipInfo = prGlueInfo->prAdapter->chip_info; |
| UINT_32 chip_id = prChipInfo->chip_id; |
| UINT_8 sub_idx = 0; |
| |
| for (sub_idx = 0; apucNameTable[sub_idx]; sub_idx++) { |
| if ((*pucNameIdx + 3) < ucMaxNameIdx) { |
| /* Type 1. WIFI_RAM_CODE_MTxxxx_Ex */ |
| snprintf(*(apucName + (*pucNameIdx)), FILE_NAME_MAX, "%s%x_E%u", |
| apucNameTable[sub_idx], chip_id, |
| wlanGetEcoVersion(prGlueInfo->prAdapter)); |
| (*pucNameIdx) += 1; |
| |
| /* Type 2. WIFI_RAM_CODE_MTxxxx_Ex.bin */ |
| snprintf(*(apucName + (*pucNameIdx)), FILE_NAME_MAX, "%s%x_E%u.bin", |
| apucNameTable[sub_idx], chip_id, |
| wlanGetEcoVersion(prGlueInfo->prAdapter)); |
| (*pucNameIdx) += 1; |
| |
| /* Type 3. WIFI_RAM_CODE_MTxxxx */ |
| snprintf(*(apucName + (*pucNameIdx)), FILE_NAME_MAX, "%s%x", |
| apucNameTable[sub_idx], chip_id); |
| (*pucNameIdx) += 1; |
| |
| /* Type 4. WIFI_RAM_CODE_MTxxxx.bin */ |
| snprintf(*(apucName + (*pucNameIdx)), FILE_NAME_MAX, "%s%x.bin", |
| apucNameTable[sub_idx], chip_id); |
| (*pucNameIdx) += 1; |
| } else { |
| /* the table is not large enough */ |
| DBGLOG(INIT, ERROR, "kalFirmwareImageMapping >> file name array is not enough.\n"); |
| ASSERT(0); |
| } |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to load firmware image |
| * |
| * \param pvGlueInfo Pointer of GLUE Data Structure |
| * \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image |
| * \param pu4FileLength File length and memory mapped length as well |
| |
| * \retval Map File Handle, used for unammping |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| PVOID |
| kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, |
| OUT PPVOID ppvMapFileBuf, OUT PUINT_32 pu4FileLength, IN ENUM_IMG_DL_IDX_T eDlIdx) |
| { |
| PPUINT_8 apucNameTable = NULL; |
| PUINT_8 apucName[FILE_NAME_TOTAL + 1]; /* extra +1, for the purpose of detecting the end of the array */ |
| UINT_8 idx = 0, max_idx, aucNameBody[FILE_NAME_TOTAL][FILE_NAME_MAX], sub_idx = 0; |
| struct mt66xx_chip_info *prChipInfo = prGlueInfo->prAdapter->chip_info; |
| UINT_32 chip_id = prChipInfo->chip_id; |
| |
| DEBUGFUNC("kalFirmwareImageMapping"); |
| |
| ASSERT(prGlueInfo); |
| ASSERT(ppvMapFileBuf); |
| ASSERT(pu4FileLength); |
| |
| *ppvMapFileBuf = NULL; |
| *pu4FileLength = 0; |
| |
| do { |
| /* <0.0> Get FW name prefix table */ |
| switch (eDlIdx) { |
| case IMG_DL_IDX_N9_FW: |
| apucNameTable = apucFwName; |
| break; |
| |
| case IMG_DL_IDX_CR4_FW: |
| apucNameTable = apucCr4FwName; |
| break; |
| |
| case IMG_DL_IDX_PATCH: |
| apucNameTable = apucPatchName; |
| break; |
| |
| default: |
| ASSERT(0); |
| break; |
| } |
| |
| /* <0.2> Construct FW name */ |
| memset(apucName, 0, sizeof(apucName)); |
| |
| /* magic number 1: reservation for detection |
| * of the end of the array |
| */ |
| max_idx = (sizeof(apucName) / sizeof(PUINT_8)) - 1; |
| |
| idx = 0; |
| apucName[idx] = (PUINT_8)(aucNameBody + idx); |
| |
| if (eDlIdx == IMG_DL_IDX_PATCH) { |
| /* construct the file name for patch */ |
| |
| /* mtxxxx_patch_ex_hdr.bin*/ |
| snprintf(apucName[idx], FILE_NAME_MAX, "mt%x_patch_e%x_hdr.bin", |
| chip_id, wlanGetEcoVersion(prGlueInfo->prAdapter)); |
| idx += 1; |
| } else { |
| for (sub_idx = 0; sub_idx < max_idx; sub_idx++) |
| apucName[sub_idx] = (PUINT_8)(aucNameBody + sub_idx); |
| |
| if (prChipInfo->constructFirmwarePrio) |
| prChipInfo->constructFirmwarePrio(prGlueInfo, apucNameTable, apucName, &idx, max_idx); |
| else |
| kalConstructDefaultFirmwarePrio(prGlueInfo, apucNameTable, apucName, &idx, max_idx); |
| } |
| |
| /* let the last pointer point to NULL |
| * so that we can detect the end of the array in kalFirmwareOpen(). |
| */ |
| apucName[idx] = NULL; |
| |
| apucNameTable = apucName; |
| |
| /* <1> Open firmware */ |
| if (kalFirmwareOpen(prGlueInfo, apucNameTable) != WLAN_STATUS_SUCCESS) |
| break; |
| { |
| UINT_32 u4FwSize = 0; |
| PVOID prFwBuffer = NULL; |
| /* <2> Query firmare size */ |
| kalFirmwareSize(prGlueInfo, &u4FwSize); |
| /* <3> Use vmalloc for allocating large memory trunk */ |
| prFwBuffer = vmalloc(ALIGN_4(u4FwSize)); |
| /* <4> Load image binary into buffer */ |
| if (kalFirmwareLoad(prGlueInfo, prFwBuffer, 0, &u4FwSize) != WLAN_STATUS_SUCCESS) { |
| vfree(prFwBuffer); |
| kalFirmwareClose(prGlueInfo); |
| break; |
| } |
| /* <5> write back info */ |
| *pu4FileLength = u4FwSize; |
| *ppvMapFileBuf = prFwBuffer; |
| |
| return prFwBuffer; |
| } |
| } while (FALSE); |
| |
| return NULL; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to unload firmware image mapped memory |
| * |
| * \param pvGlueInfo Pointer of GLUE Data Structure |
| * \param pvFwHandle Pointer to mapping handle |
| * \param pvMapFileBuf Pointer to memory-mapped firmware image |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| VOID kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN PVOID prFwHandle, IN PVOID pvMapFileBuf) |
| { |
| DEBUGFUNC("kalFirmwareImageUnmapping"); |
| |
| ASSERT(prGlueInfo); |
| |
| /* pvMapFileBuf might be NULL when file doesn't exist */ |
| if (pvMapFileBuf) |
| vfree(pvMapFileBuf); |
| |
| kalFirmwareClose(prGlueInfo); |
| } |
| #endif |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to acquire |
| * OS SPIN_LOCK. |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * \param[in] rLockCategory Specify which SPIN_LOCK |
| * \param[out] pu4Flags Pointer of a variable for saving IRQ flags |
| * |
| * \return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, OUT PULONG plFlags) |
| { |
| ULONG ulFlags = 0; |
| |
| ASSERT(prGlueInfo); |
| ASSERT(plFlags); |
| |
| if (rLockCategory < SPIN_LOCK_NUM) { |
| DBGLOG(INIT, LOUD, "SPIN_LOCK[%u] Try to acquire\n", rLockCategory); |
| #if CFG_USE_SPIN_LOCK_BOTTOM_HALF |
| spin_lock_bh(&prGlueInfo->rSpinLock[rLockCategory]); |
| #else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ |
| spin_lock_irqsave(&prGlueInfo->rSpinLock[rLockCategory], ulFlags); |
| #endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ |
| |
| *plFlags = ulFlags; |
| |
| DBGLOG(INIT, LOUD, "SPIN_LOCK[%u] Acquired\n", rLockCategory); |
| } |
| |
| } /* end of kalAcquireSpinLock() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to release |
| * OS SPIN_LOCK. |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * \param[in] rLockCategory Specify which SPIN_LOCK |
| * \param[in] u4Flags Saved IRQ flags |
| * |
| * \return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, IN ULONG ulFlags) |
| { |
| ASSERT(prGlueInfo); |
| |
| if (rLockCategory < SPIN_LOCK_NUM) { |
| |
| #if CFG_USE_SPIN_LOCK_BOTTOM_HALF |
| spin_unlock_bh(&prGlueInfo->rSpinLock[rLockCategory]); |
| #else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ |
| spin_unlock_irqrestore(&prGlueInfo->rSpinLock[rLockCategory], ulFlags); |
| #endif /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ |
| DBGLOG(INIT, LOUD, "SPIN_UNLOCK[%u]\n", rLockCategory); |
| } |
| |
| } /* end of kalReleaseSpinLock() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to acquire |
| * OS MUTEX. |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * \param[in] rMutexCategory Specify which MUTEX |
| * |
| * \return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalAcquireMutex(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_MUTEX_CATEGORY_E rMutexCategory) |
| { |
| ASSERT(prGlueInfo); |
| |
| if (rMutexCategory < MUTEX_NUM) { |
| DBGLOG(INIT, TRACE, "MUTEX_LOCK[%u] Try to acquire\n", rMutexCategory); |
| mutex_lock(&prGlueInfo->arMutex[rMutexCategory]); |
| DBGLOG(INIT, TRACE, "MUTEX_LOCK[%u] Acquired\n", rMutexCategory); |
| } |
| |
| } /* end of kalAcquireMutex() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to release |
| * OS MUTEX. |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * \param[in] rMutexCategory Specify which MUTEX |
| * |
| * \return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalReleaseMutex(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_MUTEX_CATEGORY_E rMutexCategory) |
| { |
| ASSERT(prGlueInfo); |
| |
| if (rMutexCategory < MUTEX_NUM) { |
| mutex_unlock(&prGlueInfo->arMutex[rMutexCategory]); |
| DBGLOG(INIT, TRACE, "MUTEX_UNLOCK[%u]\n", rMutexCategory); |
| } |
| |
| } /* end of kalReleaseMutex() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is provided by GLUE Layer for internal driver stack to update |
| * current MAC address. |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * \param[in] pucMacAddr Pointer of current MAC address |
| * |
| * \return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucMacAddr) |
| { |
| ASSERT(prGlueInfo); |
| ASSERT(pucMacAddr); |
| |
| if (UNEQUAL_MAC_ADDR(prGlueInfo->prDevHandler->dev_addr, pucMacAddr)) |
| memcpy(prGlueInfo->prDevHandler->dev_addr, pucMacAddr, PARAM_MAC_ADDR_LEN); |
| |
| } |
| |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief To query the packet information for offload related parameters. |
| * |
| * \param[in] pvPacket Pointer to the packet descriptor. |
| * \param[in] pucFlag Points to the offload related parameter. |
| * |
| * \return (none) |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalQueryTxChksumOffloadParam(IN PVOID pvPacket, OUT PUINT_8 pucFlag) |
| { |
| struct sk_buff *skb = (struct sk_buff *)pvPacket; |
| UINT_8 ucFlag = 0; |
| |
| ASSERT(pvPacket); |
| ASSERT(pucFlag); |
| |
| if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| #if DBG |
| /* Kevin: do double check, we can remove this part in Normal Driver. |
| * Because we register NIC feature with NETIF_F_IP_CSUM for MT5912B MAC, so |
| * we'll process IP packet only. |
| */ |
| if (skb->protocol != htons(ETH_P_IP)) { |
| /* printk("Wrong skb->protocol( = %08x) for TX Checksum Offload.\n", skb->protocol); */ |
| } else |
| #endif |
| ucFlag |= (TX_CS_IP_GEN | TX_CS_TCP_UDP_GEN); |
| } |
| |
| *pucFlag = ucFlag; |
| |
| } /* kalQueryChksumOffloadParam */ |
| |
| /* 4 2007/10/8, mikewu, this is rewritten by Mike */ |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief To update the checksum offload status to the packet to be indicated to OS. |
| * |
| * \param[in] pvPacket Pointer to the packet descriptor. |
| * \param[in] pucFlag Points to the offload related parameter. |
| * |
| * \return (none) |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalUpdateRxCSUMOffloadParam(IN PVOID pvPacket, IN ENUM_CSUM_RESULT_T aeCSUM[]) |
| { |
| struct sk_buff *skb = (struct sk_buff *)pvPacket; |
| |
| ASSERT(pvPacket); |
| |
| if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS || aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS) |
| && ((aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) |
| || (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS))) { |
| skb->ip_summed = CHECKSUM_UNNECESSARY; |
| } else { |
| skb->ip_summed = CHECKSUM_NONE; |
| #if DBG |
| if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE && aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE) |
| DBGLOG(RX, TRACE, "RX: \"non-IPv4/IPv6\" Packet\n"); |
| else if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) |
| DBGLOG(RX, TRACE, "RX: \"bad IP Checksum\" Packet\n"); |
| else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) |
| DBGLOG(RX, TRACE, "RX: \"bad TCP Checksum\" Packet\n"); |
| else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) |
| DBGLOG(RX, TRACE, "RX: \"bad UDP Checksum\" Packet\n"); |
| |
| #endif |
| } |
| |
| } /* kalUpdateRxCSUMOffloadParam */ |
| #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This function is called to free packet allocated from kalPacketAlloc. |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * \param[in] pvPacket Pointer of the packet descriptor |
| * |
| * \return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket) |
| { |
| dev_kfree_skb((struct sk_buff *)pvPacket); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Only handles driver own creating packet (coalescing buffer). |
| * |
| * \param prGlueInfo Pointer of GLUE Data Structure |
| * \param u4Size Pointer of Packet Handle |
| * \param ppucData Status Code for OS upper layer |
| * |
| * \return NULL: Failed to allocate skb, Not NULL get skb |
| */ |
| /*----------------------------------------------------------------------------*/ |
| PVOID kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, IN UINT_32 u4Size, OUT PUINT_8 *ppucData) |
| { |
| struct sk_buff *prSkb; |
| |
| if (in_interrupt()) |
| prSkb = __dev_alloc_skb(u4Size + NIC_TX_HEAD_ROOM, GFP_ATOMIC); |
| else |
| prSkb = __dev_alloc_skb(u4Size + NIC_TX_HEAD_ROOM, GFP_KERNEL); |
| |
| if (prSkb) { |
| skb_reserve(prSkb, NIC_TX_HEAD_ROOM); |
| |
| *ppucData = (PUINT_8) (prSkb->data); |
| |
| /* DBGLOG(TDLS, INFO, "kalPacketAlloc, skb head[0x%x] data[0x%x] tail[0x%x] end[0x%x]\n", |
| * prSkb->head, prSkb->data, prSkb->tail, prSkb->end); |
| */ |
| |
| kalResetPacket(prGlueInfo, (P_NATIVE_PACKET) prSkb); |
| } |
| #if DBG |
| { |
| PUINT_32 pu4Head = (PUINT_32) &prSkb->cb[0]; |
| *pu4Head = (UINT_32) prSkb->head; |
| DBGLOG(RX, TRACE, "prSkb->head = %#lx, prSkb->cb = %#lx\n", (UINT_32) prSkb->head, *pu4Head); |
| } |
| #endif |
| return (PVOID) prSkb; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Process the received packet for indicating to OS. |
| * |
| * \param[in] prGlueInfo Pointer to the Adapter structure. |
| * \param[in] pvPacket Pointer of the packet descriptor |
| * \param[in] pucPacketStart The starting address of the buffer of Rx packet. |
| * \param[in] u4PacketLen The packet length. |
| * \param[in] pfgIsRetain Is the packet to be retained. |
| * \param[in] aerCSUM The result of TCP/ IP checksum offload. |
| * |
| * \retval WLAN_STATUS_SUCCESS. |
| * \retval WLAN_STATUS_FAILURE. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS |
| kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket, IN PUINT_8 pucPacketStart, IN UINT_32 u4PacketLen, |
| /* IN PBOOLEAN pfgIsRetain, */ |
| IN BOOLEAN fgIsRetain, IN ENUM_CSUM_RESULT_T aerCSUM[]) |
| { |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| struct sk_buff *skb = (struct sk_buff *)pvPacket; |
| |
| skb->data = (unsigned char *)pucPacketStart; |
| |
| /* Reset skb */ |
| skb_reset_tail_pointer(skb); |
| skb_trim(skb, 0); |
| |
| /* Put data */ |
| skb_put(skb, u4PacketLen); |
| |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| if (prGlueInfo->prAdapter->fgIsSupportCsumOffload) |
| kalUpdateRxCSUMOffloadParam(skb, aerCSUM); |
| #endif |
| |
| return rStatus; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief To indicate an array of received packets is available for higher |
| * level protocol uses. |
| * |
| * \param[in] prGlueInfo Pointer to the Adapter structure. |
| * \param[in] apvPkts The packet array to be indicated |
| * \param[in] ucPktNum The number of packets to be indicated |
| * |
| * \retval TRUE Success. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, IN PVOID apvPkts[], IN UINT_8 ucPktNum) |
| { |
| UINT_8 ucIdx = 0; |
| |
| ASSERT(prGlueInfo); |
| ASSERT(apvPkts); |
| |
| for (ucIdx = 0; ucIdx < ucPktNum; ucIdx++) |
| kalRxIndicateOnePkt(prGlueInfo, apvPkts[ucIdx]); |
| |
| KAL_WAKE_LOCK_TIMEOUT(prGlueInfo->prAdapter, &prGlueInfo->rTimeoutWakeLock, |
| MSEC_TO_JIFFIES(prGlueInfo->prAdapter->rWifiVar.u4WakeLockRxTimeout)); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief To indicate one received packets is available for higher |
| * level protocol uses. |
| * |
| * \param[in] prGlueInfo Pointer to the Adapter structure. |
| * \param[in] pvPkt The packet to be indicated |
| * |
| * \retval TRUE Success. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS kalRxIndicateOnePkt(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPkt) |
| { |
| struct net_device *prNetDev = prGlueInfo->prDevHandler; |
| struct sk_buff *prSkb = NULL; |
| struct mt66xx_chip_info *prChipInfo; |
| |
| ASSERT(prGlueInfo); |
| ASSERT(pvPkt); |
| |
| prSkb = pvPkt; |
| prChipInfo = prGlueInfo->prAdapter->chip_info; |
| #if DBG && 0 |
| do { |
| PUINT_8 pu4Head = (PUINT_8) &prSkb->cb[0]; |
| UINT_32 u4HeadValue = 0; |
| |
| kalMemCopy(&u4HeadValue, pu4Head, sizeof(u4HeadValue)); |
| DBGLOG(RX, TRACE, "prSkb->head = 0x%p, prSkb->cb = 0x%lx\n", pu4Head, u4HeadValue); |
| } while (0); |
| #endif |
| |
| #if 1 |
| |
| prNetDev = (struct net_device *)wlanGetNetInterfaceByBssIdx(prGlueInfo, GLUE_GET_PKT_BSS_IDX(prSkb)); |
| if (!prNetDev) |
| prNetDev = prGlueInfo->prDevHandler; |
| #if CFG_SUPPORT_SNIFFER |
| if (prGlueInfo->fgIsEnableMon) |
| prNetDev = prGlueInfo->prMonDevHandler; |
| #endif |
| prNetDev->stats.rx_bytes += prSkb->len; |
| prNetDev->stats.rx_packets++; |
| #else |
| if (GLUE_GET_PKT_IS_P2P(prSkb)) { |
| /* P2P */ |
| #if CFG_ENABLE_WIFI_DIRECT |
| if (prGlueInfo->prAdapter->fgIsP2PRegistered) |
| prNetDev = kalP2PGetDevHdlr(prGlueInfo); |
| /* prNetDev->stats.rx_bytes += prSkb->len; */ |
| /* prNetDev->stats.rx_packets++; */ |
| prGlueInfo->prP2PInfo[0]->rNetDevStats.rx_bytes += prSkb->len; |
| prGlueInfo->prP2PInfo[0]->rNetDevStats.rx_packets++; |
| |
| #else |
| prNetDev = prGlueInfo->prDevHandler; |
| #endif |
| } else if (GLUE_GET_PKT_IS_PAL(prSkb)) { |
| /* BOW */ |
| #if CFG_ENABLE_BT_OVER_WIFI && CFG_BOW_SEPARATE_DATA_PATH |
| if (prGlueInfo->rBowInfo.fgIsNetRegistered) |
| prNetDev = prGlueInfo->rBowInfo.prDevHandler; |
| #else |
| prNetDev = prGlueInfo->prDevHandler; |
| #endif |
| } else { |
| /* AIS */ |
| prNetDev = prGlueInfo->prDevHandler; |
| prGlueInfo->rNetDevStats.rx_bytes += prSkb->len; |
| prGlueInfo->rNetDevStats.rx_packets++; |
| |
| } |
| #endif |
| prNetDev->last_rx = jiffies; |
| #if CFG_SUPPORT_SNIFFER |
| if (prGlueInfo->fgIsEnableMon) { |
| skb_reset_mac_header(prSkb); |
| prSkb->ip_summed = CHECKSUM_UNNECESSARY; |
| prSkb->pkt_type = PACKET_OTHERHOST; |
| prSkb->protocol = htons(ETH_P_802_2); |
| } else { |
| prSkb->protocol = eth_type_trans(prSkb, prNetDev); |
| } |
| #else |
| prSkb->protocol = eth_type_trans(prSkb, prNetDev); |
| #endif |
| prSkb->dev = prNetDev; |
| /* DBGLOG_MEM32(RX, TRACE, (PUINT_32)prSkb->data, prSkb->len); */ |
| /* DBGLOG(RX, EVENT, ("kalRxIndicatePkts len = %d\n", prSkb->len)); */ |
| if (prSkb->tail > prSkb->end) { |
| DBGLOG(RX, ERROR, |
| "kalRxIndicateOnePkt [prSkb = 0x%p][prSkb->len = %d][prSkb->protocol = 0x%02X] %p,%p\n", |
| (PUINT_8) prSkb, prSkb->len, prSkb->protocol, prSkb->tail, prSkb->end); |
| DBGLOG_MEM32(RX, ERROR, (PUINT_32) prSkb->data, prSkb->len); |
| } |
| |
| if (prSkb->protocol == NTOHS(ETH_P_8021Q) |
| && !FEAT_SUP_LLC_VLAN_RX(prChipInfo)) { |
| /* |
| * DA-MAC + SA-MAC + 0x8100 was removed in eth_type_trans() |
| * pkt format here is TCI(2-bytes) + Len(2-btyes) + payload-type(2-bytes) + payload |
| * Remove "Len" field inserted by RX VLAN header translation |
| * Note: TCI+payload-type is a standard 8021Q header |
| * |
| * This format update is based on RX VLAN HW header translation. |
| * If the setting was changed, you may need to change rules here as well. |
| */ |
| const UINT_8 vlan_skb_mem_move = 2; |
| |
| /* Remove "Len" and shift data pointer 2 bytes */ |
| kalMemCopy(prSkb->data+vlan_skb_mem_move, prSkb->data, vlan_skb_mem_move); |
| skb_pull_rcsum(prSkb, vlan_skb_mem_move); |
| |
| /* Have to update MAC header properly. Otherwise, wrong MACs woud be passed up */ |
| kalMemMove(prSkb->data - ETH_HLEN, prSkb->data - ETH_HLEN - vlan_skb_mem_move, ETH_HLEN); |
| prSkb->mac_header += vlan_skb_mem_move; |
| |
| skb_reset_network_header(prSkb); |
| skb_reset_transport_header(prSkb); |
| kal_skb_reset_mac_len(prSkb); |
| } |
| |
| if (!in_interrupt()) |
| netif_rx_ni(prSkb); /* only in non-interrupt context */ |
| else |
| netif_rx(prSkb); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Called by driver to indicate event to upper layer, for example, the wpa |
| * supplicant or wireless tools. |
| * |
| * \param[in] pvAdapter Pointer to the adapter descriptor. |
| * \param[in] eStatus Indicated status. |
| * \param[in] pvBuf Indicated message buffer. |
| * \param[in] u4BufLen Indicated message buffer size. |
| * |
| * \return (none) |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID |
| kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, IN WLAN_STATUS eStatus, IN PVOID pvBuf, IN UINT_32 u4BufLen) |
| { |
| |
| UINT_32 bufLen; |
| P_PARAM_STATUS_INDICATION_T pStatus = (P_PARAM_STATUS_INDICATION_T) pvBuf; |
| P_PARAM_AUTH_EVENT_T pAuth = (P_PARAM_AUTH_EVENT_T) pStatus; |
| P_PARAM_PMKID_CANDIDATE_LIST_T pPmkid = (P_PARAM_PMKID_CANDIDATE_LIST_T) (pStatus + 1); |
| PARAM_MAC_ADDRESS arBssid; |
| PARAM_SSID_T ssid; |
| struct ieee80211_channel *prChannel = NULL; |
| struct cfg80211_bss *bss; |
| UINT_8 ucChannelNum; |
| P_BSS_DESC_T prBssDesc = NULL; |
| |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| kalMemZero(arBssid, MAC_ADDR_LEN); |
| |
| ASSERT(prGlueInfo); |
| |
| switch (eStatus) { |
| case WLAN_STATUS_ROAM_OUT_FIND_BEST: |
| case WLAN_STATUS_MEDIA_CONNECT: |
| |
| prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_CONNECTED; |
| |
| /* indicate assoc event */ |
| wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], sizeof(arBssid), &bufLen); |
| wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, arBssid, bufLen); |
| |
| /* switch netif on */ |
| netif_carrier_on(prGlueInfo->prDevHandler); |
| |
| do { |
| /* print message on console */ |
| wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQuerySsid, &ssid, sizeof(ssid), &bufLen); |
| |
| ssid.aucSsid[(ssid.u4SsidLen >= PARAM_MAX_LEN_SSID) ? |
| (PARAM_MAX_LEN_SSID - 1) : ssid.u4SsidLen] = '\0'; |
| DBGLOG(INIT, INFO, "[wifi] %s netif_carrier_on [ssid:%s " MACSTR "]\n", |
| prGlueInfo->prDevHandler->name, ssid.aucSsid, MAC2STR(arBssid)); |
| } while (0); |
| |
| if (prGlueInfo->fgIsRegistered == TRUE) { |
| /* retrieve channel */ |
| ucChannelNum = |
| wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, |
| prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); |
| if (ucChannelNum <= 14) { |
| prChannel = |
| ieee80211_get_channel(priv_to_wiphy(prGlueInfo), |
| ieee80211_channel_to_frequency |
| (ucChannelNum, KAL_BAND_2GHZ)); |
| } else { |
| prChannel = |
| ieee80211_get_channel(priv_to_wiphy(prGlueInfo), |
| ieee80211_channel_to_frequency |
| (ucChannelNum, KAL_BAND_5GHZ)); |
| } |
| |
| /* ensure BSS exists */ |
| bss = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), prChannel, arBssid, |
| ssid.aucSsid, ssid.u4SsidLen, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
| |
| if (bss == NULL) { |
| /* create BSS on-the-fly */ |
| prBssDesc = ((P_AIS_FSM_INFO_T) |
| (&(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo)))->prTargetBssDesc; |
| |
| if (prChannel && prBssDesc != NULL) { |
| #if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE |
| bss = cfg80211_inform_bss(priv_to_wiphy(prGlueInfo), |
| prChannel, |
| CFG80211_BSS_FTYPE_PRESP, |
| arBssid, |
| 0, /* TSF */ |
| WLAN_CAPABILITY_ESS, |
| prBssDesc->u2BeaconInterval, /* beacon interval */ |
| prBssDesc->aucIEBuf, /* IE */ |
| prBssDesc->u2IELength, /* IE Length */ |
| RCPI_TO_dBm(prBssDesc->ucRCPI) * 100, /* MBM */ |
| GFP_KERNEL); |
| #else |
| bss = cfg80211_inform_bss(priv_to_wiphy(prGlueInfo), prChannel, |
| arBssid, 0, /* TSF */ |
| WLAN_CAPABILITY_ESS, |
| prBssDesc->u2BeaconInterval, /* beacon interval */ |
| prBssDesc->aucIEBuf, /* IE */ |
| prBssDesc->u2IELength, /* IE Length */ |
| RCPI_TO_dBm(prBssDesc->ucRCPI) * 100, /* MBM */ |
| GFP_KERNEL); |
| #endif |
| } |
| } |
| /* CFG80211 Indication */ |
| if (eStatus == WLAN_STATUS_ROAM_OUT_FIND_BEST) { |
| struct ieee80211_channel *prChannel = NULL; |
| UINT_8 ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, |
| prGlueInfo->prAdapter-> |
| prAisBssInfo->ucBssIndex); |
| |
| if (ucChannelNum <= 14) { |
| prChannel = ieee80211_get_channel(priv_to_wiphy(prGlueInfo), |
| ieee80211_channel_to_frequency |
| (ucChannelNum, KAL_BAND_2GHZ)); |
| } else { |
| prChannel = ieee80211_get_channel(priv_to_wiphy(prGlueInfo), |
| ieee80211_channel_to_frequency |
| (ucChannelNum, KAL_BAND_5GHZ)); |
| } |
| |
| cfg80211_roamed(prGlueInfo->prDevHandler, |
| prChannel, |
| arBssid, |
| prGlueInfo->aucReqIe, |
| prGlueInfo->u4ReqIeLength, |
| prGlueInfo->aucRspIe, prGlueInfo->u4RspIeLength, GFP_KERNEL); |
| } else { |
| cfg80211_connect_result(prGlueInfo->prDevHandler, arBssid, |
| prGlueInfo->aucReqIe, |
| prGlueInfo->u4ReqIeLength, |
| prGlueInfo->aucRspIe, |
| prGlueInfo->u4RspIeLength, WLAN_STATUS_SUCCESS, GFP_KERNEL); |
| } |
| } |
| |
| break; |
| |
| case WLAN_STATUS_MEDIA_DISCONNECT: |
| case WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY: |
| /* indicate disassoc event */ |
| wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, NULL, 0); |
| /* For CR 90 and CR99, While supplicant do reassociate, driver will do netif_carrier_off first, |
| * after associated success, at joinComplete(), do netif_carier_on, |
| * but for unknown reason, the supplicant 1x pkt will not called the driver |
| * hardStartXmit, for template workaround these bugs, add this compiling flag |
| */ |
| /* switch netif off */ |
| |
| #if 1 /* CONSOLE_MESSAGE */ |
| DBGLOG(INIT, INFO, "[wifi] %s netif_carrier_off\n", prGlueInfo->prDevHandler->name); |
| #endif |
| |
| netif_carrier_off(prGlueInfo->prDevHandler); |
| if (prGlueInfo->fgIsRegistered == TRUE) { |
| P_BSS_INFO_T prBssInfo = prGlueInfo->prAdapter->prAisBssInfo; |
| UINT_16 u2DeauthReason = 0; |
| #if CFG_WPS_DISCONNECT || (KERNEL_VERSION(4, 4, 0) <= CFG80211_VERSION_CODE) |
| |
| if (prBssInfo) |
| u2DeauthReason = prBssInfo->u2DeauthReason; |
| /* CFG80211 Indication */ |
| DBGLOG(INIT, INFO, "[wifi]Indicate disconnection: Locally[%d]\n", |
| (eStatus == WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY)); |
| cfg80211_disconnected(prGlueInfo->prDevHandler, u2DeauthReason, NULL, 0, |
| eStatus == WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY, |
| GFP_KERNEL); |
| |
| #else |
| |
| #ifdef CONFIG_ANDROID |
| #if LINUX_VERSION_CODE == KERNEL_VERSION(3, 10, 0) |
| /* Don't indicate disconnection to upper layer for ANDROID kernel 3.10 */ |
| /* since cfg80211 will indicate disconnection to wpa_supplicant for this kernel */ |
| if (eStatus == WLAN_STATUS_MEDIA_DISCONNECT) |
| #endif |
| #endif |
| { |
| |
| |
| if (prBssInfo) |
| u2DeauthReason = prBssInfo->u2DeauthReason; |
| /* CFG80211 Indication */ |
| cfg80211_disconnected(prGlueInfo->prDevHandler, u2DeauthReason, NULL, 0, |
| GFP_KERNEL); |
| } |
| |
| |
| #endif |
| } |
| |
| |
| prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; |
| |
| break; |
| |
| case WLAN_STATUS_SCAN_COMPLETE: |
| /* indicate scan complete event */ |
| wext_indicate_wext_event(prGlueInfo, SIOCGIWSCAN, NULL, 0); |
| |
| /* 1. reset first for newly incoming request */ |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); |
| if (prGlueInfo->prScanRequest != NULL) { |
| /* 2. then CFG80211 Indication */ |
| kalCfg80211ScanDone(prGlueInfo->prScanRequest, FALSE); |
| prGlueInfo->prScanRequest = NULL; |
| } |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); |
| |
| break; |
| |
| #if 0 |
| case WLAN_STATUS_MSDU_OK: |
| if (netif_running(prGlueInfo->prDevHandler)) |
| netif_wake_queue(prGlueInfo->prDevHandler); |
| break; |
| #endif |
| |
| case WLAN_STATUS_MEDIA_SPECIFIC_INDICATION: |
| if (pStatus) { |
| switch (pStatus->eStatusType) { |
| case ENUM_STATUS_TYPE_AUTHENTICATION: |
| /* |
| * printk(KERN_NOTICE "ENUM_STATUS_TYPE_AUTHENTICATION: L(%ld) [" MACSTR "] F:%lx\n", |
| * pAuth->Request[0].Length, |
| * MAC2STR(pAuth->Request[0].Bssid), |
| * pAuth->Request[0].Flags); |
| */ |
| /* indicate (UC/GC) MIC ERROR event only */ |
| if ((pAuth->arRequest[0].u4Flags == |
| PARAM_AUTH_REQUEST_PAIRWISE_ERROR) || |
| (pAuth->arRequest[0].u4Flags == PARAM_AUTH_REQUEST_GROUP_ERROR)) { |
| cfg80211_michael_mic_failure(prGlueInfo->prDevHandler, NULL, |
| (pAuth->arRequest[0].u4Flags == |
| PARAM_AUTH_REQUEST_PAIRWISE_ERROR) |
| ? NL80211_KEYTYPE_PAIRWISE : |
| NL80211_KEYTYPE_GROUP, 0, NULL, GFP_KERNEL); |
| wext_indicate_wext_event(prGlueInfo, IWEVMICHAELMICFAILURE, |
| (unsigned char *)&pAuth->arRequest[0], |
| pAuth->arRequest[0].u4Length); |
| } |
| break; |
| |
| case ENUM_STATUS_TYPE_CANDIDATE_LIST: |
| /* |
| * printk(KERN_NOTICE "Param_StatusType_PMKID_CandidateList: Ver(%ld) Num(%ld)\n", |
| * pPmkid->u2Version, |
| * pPmkid->u4NumCandidates); |
| * if (pPmkid->u4NumCandidates > 0) { |
| * printk(KERN_NOTICE "candidate[" MACSTR "] preAuth Flag:%lx\n", |
| * MAC2STR(pPmkid->arCandidateList[0].rBSSID), |
| * pPmkid->arCandidateList[0].fgFlags); |
| * } |
| */ |
| { |
| UINT_32 i; |
| |
| for (i = 0; i < pPmkid->u4NumCandidates; i++) { |
| wext_indicate_wext_event(prGlueInfo, |
| IWEVPMKIDCAND, |
| (unsigned char *)&pPmkid->arCandidateList[i], |
| pPmkid->u4NumCandidates); |
| } |
| } |
| break; |
| |
| default: |
| /* case ENUM_STATUS_TYPE_MEDIA_STREAM_MODE */ |
| /* |
| * printk(KERN_NOTICE "unknown media specific indication type:%x\n", |
| * pStatus->StatusType); |
| */ |
| break; |
| } |
| } else { |
| /* |
| * printk(KERN_WARNING "media specific indication buffer NULL\n"); |
| */ |
| } |
| break; |
| |
| #if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS |
| case WLAN_STATUS_BWCS_UPDATE: |
| { |
| wext_indicate_wext_event(prGlueInfo, IWEVCUSTOM, pvBuf, sizeof(PTA_IPC_T)); |
| } |
| |
| break; |
| |
| #endif |
| case WLAN_STATUS_JOIN_TIMEOUT: |
| { |
| P_BSS_DESC_T prBssDesc = prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; |
| |
| if (prBssDesc) |
| COPY_MAC_ADDR(arBssid, prBssDesc->aucBSSID); |
| cfg80211_connect_result(prGlueInfo->prDevHandler, |
| arBssid, |
| prGlueInfo->aucReqIe, |
| prGlueInfo->u4ReqIeLength, |
| prGlueInfo->aucRspIe, |
| prGlueInfo->u4RspIeLength, WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); |
| break; |
| } |
| default: |
| /* |
| * printk(KERN_WARNING "unknown indication:%lx\n", eStatus); |
| */ |
| break; |
| } |
| } /* kalIndicateStatusAndComplete */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is called to update the (re)association request |
| * information to the structure used to query and set |
| * OID_802_11_ASSOCIATION_INFORMATION. |
| * |
| * \param[in] prGlueInfo Pointer to the Glue structure. |
| * \param[in] pucFrameBody Pointer to the frame body of the last (Re)Association |
| * Request frame from the AP. |
| * \param[in] u4FrameBodyLen The length of the frame body of the last |
| * (Re)Association Request frame. |
| * \param[in] fgReassocRequest TRUE, if it is a Reassociation Request frame. |
| * |
| * \return (none) |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID |
| kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, |
| IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen, IN BOOLEAN fgReassocRequest) |
| { |
| PUINT_8 cp; |
| |
| ASSERT(prGlueInfo); |
| |
| /* reset */ |
| prGlueInfo->u4ReqIeLength = 0; |
| |
| if (fgReassocRequest) { |
| if (u4FrameBodyLen < 15) { |
| /* |
| * printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); |
| */ |
| return; |
| } |
| } else { |
| if (u4FrameBodyLen < 9) { |
| /* |
| * printk(KERN_WARNING "frameBodyLen too short:%ld\n", frameBodyLen); |
| */ |
| return; |
| } |
| } |
| |
| cp = pucFrameBody; |
| |
| if (fgReassocRequest) { |
| /* Capability information field 2 */ |
| /* Listen interval field 2 */ |
| /* Current AP address 6 */ |
| cp += 10; |
| u4FrameBodyLen -= 10; |
| } else { |
| /* Capability information field 2 */ |
| /* Listen interval field 2 */ |
| cp += 4; |
| u4FrameBodyLen -= 4; |
| } |
| |
| wext_indicate_wext_event(prGlueInfo, IWEVASSOCREQIE, cp, u4FrameBodyLen); |
| |
| if (u4FrameBodyLen <= CFG_CFG80211_IE_BUF_LEN) { |
| prGlueInfo->u4ReqIeLength = u4FrameBodyLen; |
| kalMemCopy(prGlueInfo->aucReqIe, cp, u4FrameBodyLen); |
| } |
| |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief This routine is called to update the (re)association |
| * response information to the structure used to reply with |
| * cfg80211_connect_result |
| * |
| * @param prGlueInfo Pointer to adapter descriptor |
| * @param pucFrameBody Pointer to the frame body of the last (Re)Association |
| * Response frame from the AP |
| * @param u4FrameBodyLen The length of the frame body of the last |
| * (Re)Association Response frame |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, IN PUINT_8 pucFrameBody, IN UINT_32 u4FrameBodyLen) |
| { |
| UINT_32 u4IEOffset = 6; /* cap_info, status_code & assoc_id */ |
| UINT_32 u4IELength = u4FrameBodyLen - u4IEOffset; |
| |
| ASSERT(prGlueInfo); |
| |
| /* reset */ |
| prGlueInfo->u4RspIeLength = 0; |
| |
| if (u4IELength <= CFG_CFG80211_IE_BUF_LEN) { |
| prGlueInfo->u4RspIeLength = u4IELength; |
| kalMemCopy(prGlueInfo->aucRspIe, pucFrameBody + u4IEOffset, u4IELength); |
| } |
| |
| } /* kalUpdateReAssocRspInfo */ |
| |
| VOID kalResetPacket(IN P_GLUE_INFO_T prGlueInfo, IN P_NATIVE_PACKET prPacket) |
| { |
| struct sk_buff *prSkb = (struct sk_buff *)prPacket; |
| |
| /* Reset cb */ |
| kalMemZero(prSkb->cb, sizeof(prSkb->cb)); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is to check the pairwise eapol and wapi 1x. |
| * |
| * \param[in] prPacket Pointer to struct net_device |
| * |
| * \retval WLAN_STATUS |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN kalIsPairwiseEapolPacket(IN P_NATIVE_PACKET prPacket) |
| { |
| struct sk_buff *prSkb = (struct sk_buff *)prPacket; |
| PUINT_8 pucPacket = (PUINT_8)prSkb->data; |
| UINT_16 u2EthType = 0; |
| UINT_16 u2KeyInfo = 0; |
| |
| WLAN_GET_FIELD_BE16(&pucPacket[ETHER_HEADER_LEN - ETHER_TYPE_LEN], &u2EthType); |
| #if CFG_SUPPORT_WAPI |
| /* prBssInfo && prBssInfo->eNetworkType == NETWORK_TYPE_AIS && wlanQueryWapiMode(prAdapter) */ |
| if (u2EthType == ETH_WPI_1X) |
| return TRUE; |
| #endif |
| if (u2EthType != ETH_P_1X) |
| return FALSE; |
| u2KeyInfo = pucPacket[5+ETHER_HEADER_LEN]<<8 | pucPacket[6+ETHER_HEADER_LEN]; |
| #if 1 |
| /* BIT3 is pairwise key bit, and check SM is 0. it means this is 4-way handshake frame */ |
| DBGLOG(RSN, INFO, "u2KeyInfo=%d\n", u2KeyInfo); |
| if ((u2KeyInfo & BIT(3)) && !(u2KeyInfo & BIT(13))) |
| return TRUE; |
| #else |
| /* BIT3 is pairwise key bit, bit 8 is key mic bit. |
| * only the two bits are set, it means this is 4-way handshake 4/4 or 2/4 frame |
| */ |
| DBGLOG(RSN, INFO, "u2KeyInfo=%d\n", u2KeyInfo); |
| if ((u2KeyInfo & (BIT(3) | BIT(8))) == (BIT(3) | BIT(8))) |
| return TRUE; |
| #endif |
| return FALSE; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is TX entry point of NET DEVICE. |
| * |
| * \param[in] prSkb Pointer of the sk_buff to be sent |
| * \param[in] prDev Pointer to struct net_device |
| * \param[in] prGlueInfo Pointer of prGlueInfo |
| * \param[in] ucBssIndex BSS index of this net device |
| * |
| * \retval WLAN_STATUS |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS |
| kalHardStartXmit(struct sk_buff *prOrgSkb, IN struct net_device *prDev, P_GLUE_INFO_T prGlueInfo, UINT_8 ucBssIndex) |
| { |
| P_QUE_ENTRY_T prQueueEntry = NULL; |
| P_QUE_T prTxQueue = NULL; |
| UINT_16 u2QueueIdx = 0; |
| UINT_32 u4MaxTxPendingNum = prGlueInfo->prAdapter->rWifiVar.u4NetifStopTh; |
| struct sk_buff *prSkbNew = NULL; |
| struct sk_buff *prSkb = NULL; |
| |
| ASSERT(prOrgSkb); |
| ASSERT(prGlueInfo); |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| DBGLOG(INIT, INFO, "GLUE_FLAG_HALT skip tx\n"); |
| dev_kfree_skb(prOrgSkb); |
| return WLAN_STATUS_ADAPTER_NOT_READY; |
| } |
| |
| #if defined(_HIF_USB) |
| if (prGlueInfo->rHifInfo.state != USB_STATE_LINK_UP) { |
| DBGLOG(INIT, WARN, "USB in suspend skip tx\n"); |
| dev_kfree_skb(prOrgSkb); |
| return WLAN_STATUS_ADAPTER_NOT_READY; |
| } |
| #endif |
| |
| if (prGlueInfo->prAdapter->fgIsEnableLpdvt) { |
| DBGLOG(INIT, INFO, "LPDVT enable, skip this frame\n"); |
| dev_kfree_skb(prOrgSkb); |
| return WLAN_STATUS_NOT_ACCEPTED; |
| } |
| |
| if (skb_headroom(prOrgSkb) < NIC_TX_HEAD_ROOM) { |
| prSkbNew = skb_realloc_headroom(prOrgSkb, NIC_TX_HEAD_ROOM); |
| ASSERT(prSkbNew); |
| prSkb = prSkbNew; |
| dev_kfree_skb(prOrgSkb); |
| } else |
| prSkb = prOrgSkb; |
| |
| prQueueEntry = (P_QUE_ENTRY_T) GLUE_GET_PKT_QUEUE_ENTRY(prSkb); |
| prTxQueue = &prGlueInfo->rTxQueue; |
| |
| GLUE_SET_PKT_BSS_IDX(prSkb, ucBssIndex); |
| |
| /* Parsing frame info */ |
| if (!wlanProcessTxFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb)) { |
| /* Cannot extract packet */ |
| DBGLOG(INIT, INFO, "Cannot extract content, skip this frame\n"); |
| dev_kfree_skb(prSkb); |
| return WLAN_STATUS_INVALID_PACKET; |
| } |
| |
| /* Tx profiling */ |
| wlanTxProfilingTagPacket(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb, TX_PROF_TAG_OS_TO_DRV); |
| |
| /* Handle normal data frame */ |
| u2QueueIdx = skb_get_queue_mapping(prSkb); |
| |
| if (u2QueueIdx >= CFG_MAX_TXQ_NUM) { |
| DBGLOG(INIT, INFO, "Incorrect queue index, skip this frame\n"); |
| dev_kfree_skb(prSkb); |
| return WLAN_STATUS_INVALID_PACKET; |
| } |
| |
| if (!HAL_IS_TX_DIRECT(prGlueInfo->prAdapter)) { |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); |
| QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); |
| } |
| |
| GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); |
| GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex][u2QueueIdx]); |
| |
| /* |
| * WMM flow control |
| * 1. To enlarge threshold for WMM certification, WMM phase two may hit netif_stop_subquene |
| * Which may cause test case fail due to high priority packets are not enough. |
| * 2. Dynamic control threshold for AC queue. |
| * If there is high priority traffic, decrease low priority threshold. |
| * If these is low priority traffic, increase high priority threshold. |
| * Else, remians the original threshold. |
| */ |
| if (prGlueInfo->prAdapter->rWifiVar.ucTpTestMode == ENUM_TP_TEST_MODE_SIGMA_AC_N_PMF) { |
| P_BSS_INFO_T prWmmBssInfo = prGlueInfo->prAdapter->aprBssInfo[ucBssIndex]; |
| |
| if ((u2QueueIdx < 3) && |
| (GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex][u2QueueIdx+1]) |
| > CFG_CERT_WMM_MAX_TX_PENDING)) { |
| /* |
| * Use au8Statistics[RX_SIZE_ERR_DROP_COUNT] to track RX traffic in certification. |
| */ |
| if ((prWmmBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && |
| ((prDev->stats.rx_packets - |
| (prGlueInfo->prAdapter->rRxCtrl.au8Statistics[RX_SIZE_ERR_DROP_COUNT])) |
| > CFG_CERT_WMM_MAX_RX_NUM)) |
| |
| u4MaxTxPendingNum = CFG_CERT_WMM_LOW_STOP_TX_WITH_RX; |
| |
| else |
| u4MaxTxPendingNum = CFG_CERT_WMM_LOW_STOP_TX_WO_RX; |
| } |
| else if ((u2QueueIdx > 0) && |
| (GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex][u2QueueIdx-1]) |
| > CFG_CERT_WMM_MAX_TX_PENDING)) { |
| /* |
| * Use au8Statistics[RX_SIZE_ERR_DROP_COUNT] to track RX traffic in certification. |
| */ |
| if ((prWmmBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && |
| ((prDev->stats.rx_packets - |
| (prGlueInfo->prAdapter->rRxCtrl.au8Statistics[RX_SIZE_ERR_DROP_COUNT])) |
| > CFG_CERT_WMM_MAX_RX_NUM)) |
| |
| u4MaxTxPendingNum = CFG_CERT_WMM_HIGH_STOP_TX_WITH_RX; |
| |
| else |
| u4MaxTxPendingNum = CFG_CERT_WMM_HIGH_STOP_TX_WO_RX; |
| } |
| else |
| u4MaxTxPendingNum = prGlueInfo->prAdapter->rWifiVar.u4NetifStopTh; |
| } |
| |
| if (GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex][u2QueueIdx]) |
| >= u4MaxTxPendingNum) { |
| netif_stop_subqueue(prDev, u2QueueIdx); |
| |
| DBGLOG(TX, TRACE, |
| "Stop subqueue for BSS[%u] QIDX[%u] PKT_LEN[%u] TOT_CNT[%ld] PER-Q_CNT[%ld]\n", |
| ucBssIndex, u2QueueIdx, prSkb->len, |
| GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum), |
| GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex] |
| [u2QueueIdx])); |
| |
| /* Re-use au8Statistics[RX_SIZE_ERR_DROP_COUNT] buffer to track RX traffic in certification */ |
| if (prGlueInfo->prAdapter->rWifiVar.ucTpTestMode == ENUM_TP_TEST_MODE_SIGMA_AC_N_PMF) |
| prGlueInfo->prAdapter->rRxCtrl.au8Statistics[RX_SIZE_ERR_DROP_COUNT] = prDev->stats.rx_packets; |
| } |
| |
| /* Update NetDev statisitcs */ |
| prDev->stats.tx_bytes += prSkb->len; |
| prDev->stats.tx_packets++; |
| |
| DBGLOG(TX, LOUD, |
| "Enqueue frame for BSS[%u] QIDX[%u] PKT_LEN[%u] TOT_CNT[%ld] PER-Q_CNT[%ld]\n", |
| ucBssIndex, u2QueueIdx, prSkb->len, |
| GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum), |
| GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex][u2QueueIdx])); |
| |
| if (HAL_IS_TX_DIRECT(prGlueInfo->prAdapter)) |
| return nicTxDirectStartXmit(prSkb, prGlueInfo); |
| |
| kalSetEvent(prGlueInfo); |
| |
| return WLAN_STATUS_SUCCESS; |
| } /* end of kalHardStartXmit() */ |
| |
| WLAN_STATUS kalResetStats(IN struct net_device *prDev) |
| { |
| DBGLOG(QM, INFO, "Reset NetDev[0x%p] statistics\n", prDev); |
| |
| kalMemZero(kalGetStats(prDev), sizeof(struct net_device_stats)); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief A method of struct net_device, to get the network interface statistical |
| * information. |
| * |
| * Whenever an application needs to get statistics for the interface, this method |
| * is called. This happens, for example, when ifconfig or netstat -i is run. |
| * |
| * \param[in] prDev Pointer to struct net_device. |
| * |
| * \return net_device_stats buffer pointer. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| PVOID kalGetStats(IN struct net_device *prDev) |
| { |
| return (PVOID) &prDev->stats; |
| } /* end of wlanGetStats() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Notify OS with SendComplete event of the specific packet. Linux should |
| * free packets here. |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * \param[in] pvPacket Pointer of Packet Handle |
| * \param[in] status Status Code for OS upper layer |
| * |
| * \return - |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, IN PVOID pvPacket) |
| { |
| struct net_device *prDev = NULL; |
| struct sk_buff *prSkb = NULL; |
| UINT_16 u2QueueIdx = 0; |
| UINT_8 ucBssIndex = 0; |
| BOOLEAN fgIsValidDevice = TRUE; |
| |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(pvPacket); |
| /* ASSERT(prGlueInfo->i4TxPendingFrameNum); */ |
| |
| prSkb = (struct sk_buff *)pvPacket; |
| u2QueueIdx = skb_get_queue_mapping(prSkb); |
| ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); |
| |
| ucBssIndex = GLUE_GET_PKT_BSS_IDX(pvPacket); |
| |
| #if 0 |
| if ((GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum) <= 0)) { |
| UINT_8 ucBssIdx; |
| UINT_16 u2QIdx; |
| |
| DBGLOG(INIT, INFO, "TxPendingFrameNum[%u] CurFrameId[%u]\n", prGlueInfo->i4TxPendingFrameNum, |
| GLUE_GET_PKT_ARRIVAL_TIME(pvPacket)); |
| |
| for (ucBssIdx = 0; ucBssIdx < HW_BSSID_NUM; ucBssIdx++) { |
| for (u2QIdx = 0; u2QIdx < CFG_MAX_TXQ_NUM; u2QIdx++) { |
| DBGLOG(INIT, INFO, "BSS[%u] Q[%u] TxPendingFrameNum[%u]\n", |
| ucBssIdx, u2QIdx, prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIdx][u2QIdx]); |
| } |
| } |
| } |
| |
| ASSERT((GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum) > 0)); |
| #endif |
| |
| GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); |
| GLUE_DEC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex][u2QueueIdx]); |
| |
| DBGLOG(TX, LOUD, |
| "Release frame for BSS[%u] QIDX[%u] PKT_LEN[%u] TOT_CNT[%ld] PER-Q_CNT[%ld]\n", |
| ucBssIndex, u2QueueIdx, prSkb->len, |
| GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum), |
| GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex][u2QueueIdx])); |
| |
| prDev = prSkb->dev; |
| |
| ASSERT(prDev); |
| |
| #if CFG_ENABLE_WIFI_DIRECT |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); |
| |
| { |
| P_BSS_INFO_T prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIndex); |
| P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T) NULL; |
| struct net_device *prNetdevice = NULL; |
| |
| /* in case packet was sent after P2P device is unregistered or the net_device was be free */ |
| if (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) { |
| if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) |
| fgIsValidDevice = FALSE; |
| else { |
| ASSERT(prBssInfo->u4PrivateData < KAL_P2P_NUM); |
| prGlueP2pInfo = prGlueInfo->prP2PInfo[prBssInfo->u4PrivateData]; |
| if (prGlueP2pInfo) { |
| prNetdevice = prGlueP2pInfo->aprRoleHandler; |
| /* The net_device may be free */ |
| if ((prDev != prNetdevice) && (prDev != prGlueP2pInfo->prDevHandler)) { |
| fgIsValidDevice = FALSE; |
| DBGLOG(TX, LOUD, |
| "kalSendCompleteAndAwakeQueue net device deleted! ucBssIndex = %u\n", |
| ucBssIndex); |
| } |
| } |
| } |
| } |
| } |
| #endif |
| |
| if (fgIsValidDevice == TRUE) { |
| UINT_32 u4StartTh = prGlueInfo->prAdapter->rWifiVar.u4NetifStartTh; |
| |
| if (netif_subqueue_stopped(prDev, prSkb) && |
| prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex][u2QueueIdx] <= u4StartTh) { |
| netif_wake_subqueue(prDev, u2QueueIdx); |
| DBGLOG(TX, TRACE, |
| "WakeUp Queue BSS[%u] QIDX[%u] PKT_LEN[%u] TOT_CNT[%ld] PER-Q_CNT[%ld]\n", |
| ucBssIndex, u2QueueIdx, prSkb->len, |
| GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum), |
| GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex] |
| [u2QueueIdx])); |
| } |
| } |
| |
| #if CFG_ENABLE_WIFI_DIRECT |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); |
| #endif |
| |
| dev_kfree_skb_any((struct sk_buff *)pvPacket); |
| |
| DBGLOG(TX, LOUD, "----- pending frame %d -----\n", prGlueInfo->i4TxPendingFrameNum); |
| |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Copy Mac Address setting from registry. It's All Zeros in Linux. |
| * |
| * \param[in] prAdapter Pointer to the Adapter structure |
| * |
| * \param[out] paucMacAddr Pointer to the Mac Address buffer |
| * |
| * \retval WLAN_STATUS_SUCCESS |
| * |
| * \note |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalQueryRegistryMacAddr(IN P_GLUE_INFO_T prGlueInfo, OUT PUINT_8 paucMacAddr) |
| { |
| UINT_8 aucZeroMac[MAC_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 } |
| |
| DEBUGFUNC("kalQueryRegistryMacAddr"); |
| |
| ASSERT(prGlueInfo); |
| ASSERT(paucMacAddr); |
| |
| kalMemCopy((PVOID) paucMacAddr, (PVOID) aucZeroMac, MAC_ADDR_LEN); |
| |
| } /* end of kalQueryRegistryMacAddr() */ |
| |
| #if CFG_SUPPORT_EXT_CONFIG |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Read external configuration, ex. NVRAM or file |
| * |
| * \param[in] prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \return none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| UINT_32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| ASSERT(prGlueInfo); |
| |
| /* External data is given from user space by ioctl or /proc, not read by |
| * driver. |
| */ |
| if (prGlueInfo->u4ExtCfgLength != 0) |
| DBGLOG(INIT, TRACE, "Read external configuration data -- OK\n"); |
| else |
| DBGLOG(INIT, TRACE, "Read external configuration data -- fail\n"); |
| |
| return prGlueInfo->u4ExtCfgLength; |
| } |
| #endif |
| |
| BOOLEAN |
| kalIPv4FrameClassifier(IN P_GLUE_INFO_T prGlueInfo, |
| IN P_NATIVE_PACKET prPacket, IN PUINT_8 pucIpHdr, OUT P_TX_PACKET_INFO prTxPktInfo) |
| { |
| UINT_8 ucIpVersion; |
| /* UINT_16 u2IpId; */ |
| |
| /* IPv4 version check */ |
| ucIpVersion = (pucIpHdr[0] & IP_VERSION_MASK) >> IP_VERSION_OFFSET; |
| if (ucIpVersion != IP_VERSION_4) { |
| DBGLOG(INIT, WARN, "Invalid IPv4 packet version: %u\n", ucIpVersion); |
| return FALSE; |
| } |
| /* WLAN_GET_FIELD_16(&pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET], &u2IpId); */ |
| |
| if (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP) { |
| PUINT_8 pucUdpHdr = &pucIpHdr[IPV4_HDR_LEN]; |
| UINT_16 u2DstPort; |
| /* UINT_16 u2SrcPort; */ |
| |
| /* DBGLOG_MEM8(INIT, INFO, pucUdpHdr, 256); */ |
| |
| /* Get UDP DST port */ |
| WLAN_GET_FIELD_BE16(&pucUdpHdr[UDP_HDR_DST_PORT_OFFSET], &u2DstPort); |
| |
| /* DBGLOG(INIT, INFO, ("UDP DST[%u]\n", u2DstPort)); */ |
| |
| /* Get UDP SRC port */ |
| /* WLAN_GET_FIELD_BE16(&pucUdpHdr[UDP_HDR_SRC_PORT_OFFSET], &u2SrcPort); */ |
| |
| /* BOOTP/DHCP protocol */ |
| if ((u2DstPort == IP_PORT_BOOTP_SERVER) || (u2DstPort == IP_PORT_BOOTP_CLIENT)) { |
| |
| P_BOOTP_PROTOCOL_T prBootp = (P_BOOTP_PROTOCOL_T) &pucUdpHdr[UDP_HDR_LEN]; |
| |
| UINT_32 u4DhcpMagicCode; |
| |
| WLAN_GET_FIELD_BE32(&prBootp->aucOptions[0], &u4DhcpMagicCode); |
| #if 0 |
| DBGLOG(INIT, INFO, "DHCP MGC[0x%08x] XID[%u] OPT[%u] TYPE[%u]\n", |
| u4DhcpMagicCode, prBootp->u4TransId, prBootp->aucOptions[4], prBootp->aucOptions[6]); |
| #endif |
| if (u4DhcpMagicCode == DHCP_MAGIC_NUMBER) { |
| UINT_32 u4Xid; |
| |
| WLAN_GET_FIELD_BE32(&prBootp->u4TransId, &u4Xid); |
| |
| DBGLOG(SW4, INFO, "DHCP PKT[0x%p] XID[0x%08x] OPT[%u] TYPE[%u]\n", |
| prPacket, u4Xid, prBootp->aucOptions[4], prBootp->aucOptions[6]); |
| |
| prTxPktInfo->u2Flag |= BIT(ENUM_PKT_DHCP); |
| } |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief This inline function is to extract some packet information, including |
| * user priority, packet length, destination address, 802.1x and BT over Wi-Fi |
| * or not. |
| * |
| * @param prGlueInfo Pointer to the glue structure |
| * @param prPacket Packet descriptor |
| * @param prTxPktInfo Extracted packet info |
| * |
| * @retval TRUE Success to extract information |
| * @retval FALSE Fail to extract correct information |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN |
| kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, |
| IN P_NATIVE_PACKET prPacket, OUT P_TX_PACKET_INFO prTxPktInfo) |
| { |
| UINT_32 u4PacketLen; |
| UINT_16 u2EtherTypeLen; |
| struct sk_buff *prSkb = (struct sk_buff *)prPacket; |
| PUINT_8 aucLookAheadBuf = NULL; |
| UINT_8 ucEthTypeLenOffset = ETHER_HEADER_LEN - ETHER_TYPE_LEN; |
| PUINT_8 pucNextProtocol = NULL; |
| UINT_16 u2KeyInfo = 0; |
| UINT_8 ucEAPoLKey = 0; |
| UINT_8 ucEapOffset = ETHER_HEADER_LEN; |
| |
| u4PacketLen = prSkb->len; |
| |
| if (u4PacketLen < ETHER_HEADER_LEN) { |
| DBGLOG(INIT, WARN, "Invalid Ether packet length: %lu\n", u4PacketLen); |
| return FALSE; |
| } |
| |
| aucLookAheadBuf = prSkb->data; |
| |
| /* Reset Packet Info */ |
| kalMemZero(prTxPktInfo, sizeof(TX_PACKET_INFO)); |
| |
| /* 4 <0> Obtain Ether Type/Len */ |
| WLAN_GET_FIELD_BE16(&aucLookAheadBuf[ucEthTypeLenOffset], &u2EtherTypeLen); |
| |
| /* 4 <1> Skip 802.1Q header (VLAN Tagging) */ |
| if (u2EtherTypeLen == ETH_P_VLAN) { |
| prTxPktInfo->u2Flag |= BIT(ENUM_PKT_VLAN_EXIST); |
| ucEthTypeLenOffset += ETH_802_1Q_HEADER_LEN; |
| WLAN_GET_FIELD_BE16(&aucLookAheadBuf[ucEthTypeLenOffset], &u2EtherTypeLen); |
| } |
| /* 4 <2> Obtain next protocol pointer */ |
| pucNextProtocol = &aucLookAheadBuf[ucEthTypeLenOffset + ETHER_TYPE_LEN]; |
| |
| /* 4 <3> Handle ethernet format */ |
| switch (u2EtherTypeLen) { |
| |
| /* IPv4 */ |
| case ETH_P_IPV4: |
| /* IPv4 header length check */ |
| if (u4PacketLen < (ucEthTypeLenOffset + ETHER_TYPE_LEN + IPV4_HDR_LEN)) { |
| DBGLOG(INIT, WARN, "Invalid IPv4 packet length: %lu\n", u4PacketLen); |
| break; |
| } |
| |
| kalIPv4FrameClassifier(prGlueInfo, prPacket, pucNextProtocol, prTxPktInfo); |
| break; |
| |
| #if 0 |
| /* IPv6 */ |
| case ETH_P_IPV6: |
| { |
| PUINT_8 pucIpHdr = pucNextProtocol; |
| UINT_8 ucIpVersion; |
| |
| /* IPv6 header length check */ |
| if (u4PacketLen < (ucEthTypeLenOffset + ETHER_TYPE_LEN + IPV6_HDR_LEN)) { |
| DBGLOG(INIT, WARN, "Invalid IPv6 packet length: %lu\n", u4PacketLen); |
| return FALSE; |
| } |
| |
| /* IPv6 version check */ |
| ucIpVersion = (pucIpHdr[0] & IP_VERSION_MASK) >> IP_VERSION_OFFSET; |
| if (ucIpVersion != IP_VERSION_6) { |
| DBGLOG(INIT, WARN, "Invalid IPv6 packet version: %u\n", ucIpVersion); |
| return FALSE; |
| } |
| |
| /* Get the DSCP value from the header of IP packet. */ |
| ucUserPriority = ((pucIpHdr[0] & IPV6_HDR_TC_PREC_MASK) >> IPV6_HDR_TC_PREC_OFFSET); |
| } |
| break; |
| #endif |
| |
| case ETH_P_ARP: |
| { |
| UINT_16 u2ArpOp; |
| |
| WLAN_GET_FIELD_BE16(&pucNextProtocol[ARP_OPERATION_OFFSET], &u2ArpOp); |
| |
| DBGLOG(SW4, INFO, "ARP %s PKT[0x%p] TAR MAC/IP[" MACSTR "]/[" IPV4STR "]\n", |
| u2ArpOp == ARP_OPERATION_REQUEST ? "REQ" : "RSP", |
| prPacket, MAC2STR(&pucNextProtocol[ARP_TARGET_MAC_OFFSET]), |
| IPV4TOSTR(&pucNextProtocol[ARP_TARGET_IP_OFFSET])); |
| |
| prTxPktInfo->u2Flag |= BIT(ENUM_PKT_ARP); |
| } |
| break; |
| |
| case ETH_P_1X: |
| case ETH_P_PRE_1X: |
| #if CFG_SUPPORT_WAPI |
| case ETH_WPI_1X: |
| #endif |
| prTxPktInfo->u2Flag |= BIT(ENUM_PKT_1X); |
| DBGLOG(RSN, INFO, "T1x like normal data, PKT[0x%p]\n", prPacket); |
| |
| if (u2EtherTypeLen == ETH_P_1X) { |
| /* Leave EAP to check */ |
| ucEAPoLKey = aucLookAheadBuf[1 + ucEapOffset]; |
| if (ucEAPoLKey != ETH_EAPOL_KEY) |
| prTxPktInfo->u2Flag |= BIT(ENUM_PKT_NON_PROTECTED_1X); |
| else { |
| WLAN_GET_FIELD_BE16(&aucLookAheadBuf[5 + ucEapOffset], &u2KeyInfo); |
| /* BIT3 is pairwise key bit */ |
| DBGLOG(RSN, INFO, "u2KeyInfo=%d\n", u2KeyInfo); |
| if (u2KeyInfo & BIT(3)) |
| prTxPktInfo->u2Flag |= BIT(ENUM_PKT_NON_PROTECTED_1X); |
| } |
| } |
| #if CFG_SUPPORT_WAPI |
| else if (u2EtherTypeLen == ETH_WPI_1X) |
| prTxPktInfo->u2Flag |= BIT(ENUM_PKT_NON_PROTECTED_1X); |
| #endif |
| break; |
| |
| default: |
| /* 4 <4> Handle 802.3 format if LEN <= 1500 */ |
| if (u2EtherTypeLen <= ETH_802_3_MAX_LEN) |
| prTxPktInfo->u2Flag |= BIT(ENUM_PKT_802_3); |
| break; |
| } |
| |
| /* 4 <4.1> Check for PAL (BT over Wi-Fi) */ |
| /* Move to kalBowFrameClassifier */ |
| |
| /* 4 <5> Return the value of Priority Parameter. */ |
| /* prSkb->priority is assigned by Linux wireless utility function(cfg80211_classify8021d) */ |
| /* at net_dev selection callback (ndo_select_queue) */ |
| prTxPktInfo->ucPriorityParam = prSkb->priority; |
| |
| /* 4 <6> Retrieve Packet Information - DA */ |
| /* Packet Length/ Destination Address */ |
| prTxPktInfo->u4PacketLen = u4PacketLen; |
| |
| kalMemCopy(prTxPktInfo->aucEthDestAddr, aucLookAheadBuf, PARAM_MAC_ADDR_LEN); |
| |
| return TRUE; |
| } /* end of kalQoSFrameClassifier() */ |
| |
| BOOLEAN kalGetEthDestAddr(IN P_GLUE_INFO_T prGlueInfo, IN P_NATIVE_PACKET prPacket, OUT PUINT_8 pucEthDestAddr) |
| { |
| struct sk_buff *prSkb = (struct sk_buff *)prPacket; |
| PUINT_8 aucLookAheadBuf = NULL; |
| |
| /* Sanity Check */ |
| if (!prPacket || !prGlueInfo) |
| return FALSE; |
| |
| aucLookAheadBuf = prSkb->data; |
| |
| kalMemCopy(pucEthDestAddr, aucLookAheadBuf, PARAM_MAC_ADDR_LEN); |
| |
| return TRUE; |
| } |
| |
| VOID |
| kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, |
| IN BOOLEAN fgSetQuery, IN UINT_32 u4SetQueryInfoLen, IN WLAN_STATUS rOidStatus) |
| { |
| |
| ASSERT(prGlueInfo); |
| /* remove timeout check timer */ |
| wlanoidClearTimeoutCheck(prGlueInfo->prAdapter); |
| |
| prGlueInfo->rPendStatus = rOidStatus; |
| |
| prGlueInfo->u4OidCompleteFlag = 1; |
| /* complete ONLY if there are waiters */ |
| if (!completion_done(&prGlueInfo->rPendComp)) { |
| complete(&prGlueInfo->rPendComp); |
| } else { |
| DBGLOG(INIT, WARN, "SKIP multiple OID complete!\n"); |
| /* WARN_ON(TRUE); */ |
| } |
| |
| if (rOidStatus == WLAN_STATUS_SUCCESS) |
| DBGLOG(INIT, TRACE, "Complete OID, status:success\n"); |
| else |
| DBGLOG(INIT, WARN, "Complete OID, status:0x%08x\n", rOidStatus); |
| |
| /* else let it timeout on kalIoctl entry */ |
| } |
| |
| VOID kalOidClearance(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief This function is used to transfer linux ioctl to OID, and we |
| * need to specify the behavior of the OID by ourself |
| * |
| * @param prGlueInfo Pointer to the glue structure |
| * @param pvInfoBuf Data buffer |
| * @param u4InfoBufLen Data buffer length |
| * @param fgRead Is this a read OID |
| * @param fgWaitResp does this OID need to wait for values |
| * @param fgCmd does this OID compose command packet |
| * @param pu4QryInfoLen The data length of the return values |
| * |
| * @retval TRUE Success to extract information |
| * @retval FALSE Fail to extract correct information |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| /* todo: enqueue the i/o requests for multiple processes access */ |
| /* */ |
| /* currently, return -1 */ |
| /* */ |
| |
| /* static GL_IO_REQ_T OidEntry; */ |
| |
| WLAN_STATUS |
| kalIoctl(IN P_GLUE_INFO_T prGlueInfo, |
| IN PFN_OID_HANDLER_FUNC pfnOidHandler, |
| IN PVOID pvInfoBuf, |
| IN UINT_32 u4InfoBufLen, IN BOOL fgRead, IN BOOL fgWaitResp, IN BOOL fgCmd, OUT PUINT_32 pu4QryInfoLen) |
| { |
| return kalIoctlTimeout(prGlueInfo, |
| pfnOidHandler, |
| pvInfoBuf, |
| u4InfoBufLen, fgRead, fgWaitResp, fgCmd, -1, |
| pu4QryInfoLen); |
| } |
| |
| |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief This function is used to transfer linux ioctl to OID, and we |
| * need to specify the behavior of the OID by ourself |
| * |
| * @param prGlueInfo Pointer to the glue structure |
| * @param pvInfoBuf Data buffer |
| * @param u4InfoBufLen Data buffer length |
| * @param fgRead Is this a read OID |
| * @param fgWaitResp does this OID need to wait for values |
| * @param fgCmd does this OID compose command packet |
| * @param i4OidTimeout timeout for this OID |
| * @param pu4QryInfoLen The data length of the return values |
| * |
| * @retval TRUE Success to extract information |
| * @retval FALSE Fail to extract correct information |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| WLAN_STATUS |
| kalIoctlTimeout(IN P_GLUE_INFO_T prGlueInfo, |
| IN PFN_OID_HANDLER_FUNC pfnOidHandler, |
| IN PVOID pvInfoBuf, |
| IN UINT_32 u4InfoBufLen, IN BOOL fgRead, IN BOOL fgWaitResp, IN BOOL fgCmd, IN INT_32 i4OidTimeout, |
| OUT PUINT_32 pu4QryInfoLen) |
| { |
| P_GL_IO_REQ_T prIoReq = NULL; |
| WLAN_STATUS ret = WLAN_STATUS_SUCCESS; |
| |
| #if CFG_CHIP_RESET_SUPPORT |
| if (kalIsResetting()) |
| return WLAN_STATUS_SUCCESS; |
| #endif |
| |
| if (wlanIsChipAssert(prGlueInfo->prAdapter)) |
| return WLAN_STATUS_SUCCESS; |
| |
| /* GLUE_SPIN_LOCK_DECLARATION(); */ |
| ASSERT(prGlueInfo); |
| |
| /* <1> Check if driver is halt */ |
| /* if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { */ |
| /* return WLAN_STATUS_ADAPTER_NOT_READY; */ |
| /* } */ |
| |
| if (down_interruptible(&g_halt_sem)) |
| return WLAN_STATUS_FAILURE; |
| |
| if (g_u4HaltFlag) { |
| up(&g_halt_sem); |
| return WLAN_STATUS_ADAPTER_NOT_READY; |
| } |
| |
| if (down_interruptible(&prGlueInfo->ioctl_sem)) { |
| up(&g_halt_sem); |
| return WLAN_STATUS_FAILURE; |
| } |
| |
| /* <2> TODO: thread-safe */ |
| |
| /* <3> point to the OidEntry of Glue layer */ |
| |
| prIoReq = &(prGlueInfo->OidEntry); |
| |
| ASSERT(prIoReq); |
| |
| /* <4> Compose the I/O request */ |
| prIoReq->prAdapter = prGlueInfo->prAdapter; |
| prIoReq->pfnOidHandler = pfnOidHandler; |
| prIoReq->pvInfoBuf = pvInfoBuf; |
| prIoReq->u4InfoBufLen = u4InfoBufLen; |
| prIoReq->pu4QryInfoLen = pu4QryInfoLen; |
| prIoReq->fgRead = fgRead; |
| prIoReq->fgWaitResp = fgWaitResp; |
| prIoReq->rStatus = WLAN_STATUS_FAILURE; |
| |
| if (i4OidTimeout >= 0 && i4OidTimeout <= WLAN_OID_TIMEOUT_THRESHOLD_MAX) |
| prIoReq->u4Timeout = (UINT_32)i4OidTimeout; |
| else |
| prIoReq->u4Timeout = WLAN_OID_TIMEOUT_THRESHOLD; |
| |
| |
| /* <5> Reset the status of pending OID */ |
| prGlueInfo->rPendStatus = WLAN_STATUS_FAILURE; |
| /* prGlueInfo->u4TimeoutFlag = 0; */ |
| prGlueInfo->u4OidCompleteFlag = 0; |
| |
| /* <6> Check if we use the command queue */ |
| prIoReq->u4Flag = fgCmd; |
| |
| /* <7> schedule the OID bit */ |
| set_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag); |
| |
| /* <7.1> Hold wakelock to ensure OS won't be suspended */ |
| KAL_WAKE_LOCK_TIMEOUT(prGlueInfo->prAdapter, &prGlueInfo->rTimeoutWakeLock, |
| MSEC_TO_JIFFIES(prGlueInfo->prAdapter->rWifiVar.u4WakeLockThreadWakeup)); |
| |
| /* <8> Wake up tx thread to handle kick start the I/O request */ |
| wake_up_interruptible(&prGlueInfo->waitq); |
| |
| /* <9> Block and wait for event or timeout, current the timeout is 2 secs */ |
| wait_for_completion(&prGlueInfo->rPendComp); |
| { |
| /* Case 1: No timeout. */ |
| /* if return WLAN_STATUS_PENDING, the status of cmd is stored in prGlueInfo */ |
| if (prIoReq->rStatus == WLAN_STATUS_PENDING) |
| ret = prGlueInfo->rPendStatus; |
| else |
| ret = prIoReq->rStatus; |
| } |
| #if 0 |
| { |
| /* Case 2: timeout */ |
| /* clear pending OID's cmd in CMD queue */ |
| if (fgCmd) { |
| prGlueInfo->u4TimeoutFlag = 1; |
| wlanReleasePendingOid(prGlueInfo->prAdapter, 0); |
| } |
| ret = WLAN_STATUS_FAILURE; |
| } |
| #endif |
| |
| /* <10> Clear bit for error handling */ |
| clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag); |
| |
| up(&prGlueInfo->ioctl_sem); |
| up(&g_halt_sem); |
| |
| return ret; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to clear all pending security frames |
| * |
| * \param prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| P_QUE_T prCmdQue; |
| QUE_T rTempCmdQue; |
| P_QUE_T prTempCmdQue = &rTempCmdQue; |
| QUE_T rReturnCmdQue; |
| P_QUE_T prReturnCmdQue = &rReturnCmdQue; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| |
| P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; |
| |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prGlueInfo); |
| |
| QUEUE_INITIALIZE(prReturnCmdQue); |
| /* Clear pending security frames in prGlueInfo->rCmdQueue */ |
| prCmdQue = &prGlueInfo->rCmdQueue; |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| while (prQueueEntry) { |
| prCmdInfo = (P_CMD_INFO_T) prQueueEntry; |
| |
| if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { |
| if (prCmdInfo->pfCmdTimeoutHandler) |
| prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); |
| else |
| wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo, TX_RESULT_QUEUE_CLEARANCE); |
| cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); |
| GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); |
| } else { |
| QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); |
| } |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| } |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to clear pending security frames |
| * belongs to dedicated network type |
| * |
| * \param prGlueInfo Pointer of GLUE Data Structure |
| * \param eNetworkTypeIdx Network Type Index |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalClearSecurityFramesByBssIdx(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucBssIndex) |
| { |
| P_QUE_T prCmdQue; |
| QUE_T rTempCmdQue; |
| P_QUE_T prTempCmdQue = &rTempCmdQue; |
| QUE_T rReturnCmdQue; |
| P_QUE_T prReturnCmdQue = &rReturnCmdQue; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; |
| P_MSDU_INFO_T prMsduInfo; |
| BOOLEAN fgFree; |
| |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prGlueInfo); |
| |
| QUEUE_INITIALIZE(prReturnCmdQue); |
| /* Clear pending security frames in prGlueInfo->rCmdQueue */ |
| prCmdQue = &prGlueInfo->rCmdQueue; |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| while (prQueueEntry) { |
| prCmdInfo = (P_CMD_INFO_T) prQueueEntry; |
| prMsduInfo = prCmdInfo->prMsduInfo; |
| fgFree = FALSE; |
| |
| if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME && prMsduInfo) { |
| if (prMsduInfo->ucBssIndex == ucBssIndex) |
| fgFree = TRUE; |
| } |
| |
| if (fgFree) { |
| if (prCmdInfo->pfCmdTimeoutHandler) |
| prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); |
| else |
| wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo, TX_RESULT_QUEUE_CLEARANCE); |
| cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); |
| GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); |
| } else |
| QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| } |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to clear all pending management frames |
| * |
| * \param prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| P_QUE_T prCmdQue; |
| QUE_T rTempCmdQue; |
| P_QUE_T prTempCmdQue = &rTempCmdQue; |
| QUE_T rReturnCmdQue; |
| P_QUE_T prReturnCmdQue = &rReturnCmdQue; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; |
| |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prGlueInfo); |
| |
| QUEUE_INITIALIZE(prReturnCmdQue); |
| /* Clear pending management frames in prGlueInfo->rCmdQueue */ |
| prCmdQue = &prGlueInfo->rCmdQueue; |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| while (prQueueEntry) { |
| prCmdInfo = (P_CMD_INFO_T) prQueueEntry; |
| |
| if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { |
| wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo, TX_RESULT_QUEUE_CLEARANCE); |
| cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); |
| GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); |
| } else { |
| QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); |
| } |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| } |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to clear all pending management frames |
| * belongs to dedicated network type |
| * \param prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalClearMgmtFramesByBssIdx(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucBssIndex) |
| { |
| P_QUE_T prCmdQue; |
| QUE_T rTempCmdQue; |
| P_QUE_T prTempCmdQue = &rTempCmdQue; |
| QUE_T rReturnCmdQue; |
| P_QUE_T prReturnCmdQue = &rReturnCmdQue; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; |
| P_MSDU_INFO_T prMsduInfo; |
| BOOLEAN fgFree; |
| |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prGlueInfo); |
| |
| QUEUE_INITIALIZE(prReturnCmdQue); |
| /* Clear pending management frames in prGlueInfo->rCmdQueue */ |
| prCmdQue = &prGlueInfo->rCmdQueue; |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| while (prQueueEntry) { |
| prCmdInfo = (P_CMD_INFO_T) prQueueEntry; |
| prMsduInfo = prCmdInfo->prMsduInfo; |
| fgFree = FALSE; |
| |
| if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME && prMsduInfo) { |
| if (prMsduInfo->ucBssIndex == ucBssIndex) |
| fgFree = TRUE; |
| } |
| |
| if (fgFree) { |
| wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo, TX_RESULT_QUEUE_CLEARANCE); |
| cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); |
| GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); |
| } else { |
| QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); |
| } |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| } |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| } /* kalClearMgmtFramesByBssIdx */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to clear all commands in command queue |
| * \param prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalClearCommandQueue(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| P_QUE_T prCmdQue; |
| QUE_T rTempCmdQue; |
| P_QUE_T prTempCmdQue = &rTempCmdQue; |
| QUE_T rReturnCmdQue; |
| P_QUE_T prReturnCmdQue = &rReturnCmdQue; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; |
| |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prGlueInfo); |
| |
| QUEUE_INITIALIZE(prReturnCmdQue); |
| |
| /* Clear ALL in prGlueInfo->rCmdQueue */ |
| prCmdQue = &prGlueInfo->rCmdQueue; |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| while (prQueueEntry) { |
| prCmdInfo = (P_CMD_INFO_T) prQueueEntry; |
| |
| if (prCmdInfo->pfCmdTimeoutHandler) |
| prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, prCmdInfo); |
| else |
| wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo, TX_RESULT_QUEUE_CLEARANCE); |
| |
| cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); |
| GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); |
| |
| QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); |
| } |
| } |
| |
| UINT_32 kalProcessTxPacket(P_GLUE_INFO_T prGlueInfo, struct sk_buff *prSkb) |
| { |
| UINT_32 u4Status = WLAN_STATUS_SUCCESS; |
| |
| if (prSkb == NULL) { |
| DBGLOG(INIT, WARN, "prSkb == NULL in tx\n"); |
| return u4Status; |
| } |
| |
| /* Handle security frame */ |
| if (0 /* GLUE_TEST_PKT_FLAG(prSkb, ENUM_PKT_1X) *//* No more sending via cmd */) { |
| if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb)) { |
| u4Status = WLAN_STATUS_SUCCESS; |
| GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); |
| } else { |
| u4Status = WLAN_STATUS_RESOURCES; |
| } |
| } |
| /* Handle normal frame */ |
| else |
| u4Status = wlanEnqueueTxPacket(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb); |
| |
| return u4Status; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to process Tx request to main_thread |
| * |
| * \param prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalProcessTxReq(P_GLUE_INFO_T prGlueInfo, PBOOLEAN pfgNeedHwAccess) |
| { |
| P_QUE_T prCmdQue = NULL; |
| P_QUE_T prTxQueue = NULL; |
| QUE_T rTempQue; |
| P_QUE_T prTempQue = &rTempQue; |
| QUE_T rTempReturnQue; |
| P_QUE_T prTempReturnQue = &rTempReturnQue; |
| P_QUE_ENTRY_T prQueueEntry = NULL; |
| /* struct sk_buff *prSkb = NULL; */ |
| UINT_32 u4Status; |
| #if CFG_SUPPORT_MULTITHREAD |
| UINT_32 u4CmdCount = 0; |
| #endif |
| UINT_32 u4TxLoopCount; |
| |
| /* for spin lock acquire and release */ |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| prTxQueue = &prGlueInfo->rTxQueue; |
| prCmdQue = &prGlueInfo->rCmdQueue; |
| |
| QUEUE_INITIALIZE(prTempQue); |
| QUEUE_INITIALIZE(prTempReturnQue); |
| |
| u4TxLoopCount = prGlueInfo->prAdapter->rWifiVar.u4TxFromOsLoopCount; |
| |
| /* Process Mailbox Messages */ |
| wlanProcessMboxMessage(prGlueInfo->prAdapter); |
| |
| /* Process CMD request */ |
| #if CFG_SUPPORT_MULTITHREAD |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| u4CmdCount = prCmdQue->u4NumElem; |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); |
| if (u4CmdCount > 0) |
| wlanProcessCommandQueue(prGlueInfo->prAdapter, prCmdQue); |
| |
| #else |
| if (prCmdQue->u4NumElem > 0) { |
| if (*pfgNeedHwAccess == FALSE) { |
| *pfgNeedHwAccess = TRUE; |
| |
| wlanAcquirePowerControl(prGlueInfo->prAdapter); |
| } |
| wlanProcessCommandQueue(prGlueInfo->prAdapter, prCmdQue); |
| } |
| #endif |
| |
| while (u4TxLoopCount--) { |
| while (QUEUE_IS_NOT_EMPTY(prTxQueue)) { |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); |
| QUEUE_MOVE_ALL(prTempQue, prTxQueue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); |
| |
| /* Handle Packet Tx */ |
| while (QUEUE_IS_NOT_EMPTY(prTempQue)) { |
| QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); |
| |
| if (prQueueEntry == NULL) |
| break; |
| |
| u4Status = kalProcessTxPacket(prGlueInfo, |
| (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry)); |
| #if 0 |
| prSkb = (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); |
| ASSERT(prSkb); |
| if (prSkb == NULL) { |
| DBGLOG(INIT, WARN, "prSkb == NULL in tx\n"); |
| continue; |
| } |
| |
| /* Handle security frame */ |
| if (GLUE_GET_PKT_IS_1X(prSkb)) { |
| if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb)) { |
| u4Status = WLAN_STATUS_SUCCESS; |
| GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); |
| } else { |
| u4Status = WLAN_STATUS_RESOURCES; |
| } |
| } |
| /* Handle normal frame */ |
| else |
| u4Status = wlanEnqueueTxPacket(prGlueInfo->prAdapter, (P_NATIVE_PACKET) prSkb); |
| #endif |
| /* Enqueue packet back into TxQueue if resource is not enough */ |
| if (u4Status == WLAN_STATUS_RESOURCES) { |
| QUEUE_INSERT_TAIL(prTempReturnQue, prQueueEntry); |
| break; |
| } |
| } |
| |
| if (wlanGetTxPendingFrameCount(prGlueInfo->prAdapter) > 0) |
| wlanTxPendingPackets(prGlueInfo->prAdapter, pfgNeedHwAccess); |
| |
| /* Enqueue packet back into TxQueue if resource is not enough */ |
| if (QUEUE_IS_NOT_EMPTY(prTempReturnQue)) { |
| QUEUE_CONCATENATE_QUEUES(prTempReturnQue, prTempQue); |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); |
| QUEUE_CONCATENATE_QUEUES_HEAD(prTxQueue, prTempReturnQue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); |
| |
| break; |
| } |
| } |
| |
| if (wlanGetTxPendingFrameCount(prGlueInfo->prAdapter) > 0) |
| wlanTxPendingPackets(prGlueInfo->prAdapter, pfgNeedHwAccess); |
| } |
| |
| } |
| |
| #if CFG_SUPPORT_MULTITHREAD |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief |
| * |
| * @param data data pointer to private data of hif_thread |
| * |
| * @retval If the function succeeds, the return value is 0. |
| * Otherwise, an error code is returned. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| int hif_thread(void *data) |
| { |
| struct net_device *dev = data; |
| P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); |
| int ret = 0; |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| KAL_WAKE_LOCK_T rHifThreadWakeLock; |
| #endif |
| |
| KAL_WAKE_LOCK_INIT(prGlueInfo->prAdapter, &rHifThreadWakeLock, "WLAN hif_thread"); |
| KAL_WAKE_LOCK(prGlueInfo->prAdapter, &rHifThreadWakeLock); |
| |
| DBGLOG(INIT, INFO, "%s:%u starts running...\n", KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); |
| |
| prGlueInfo->u4HifThreadPid = KAL_GET_CURRENT_THREAD_ID(); |
| |
| set_user_nice(current, prGlueInfo->prAdapter->rWifiVar.cThreadNice); |
| |
| while (TRUE) { |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| DBGLOG(INIT, INFO, "hif_thread should stop now...\n"); |
| break; |
| } |
| |
| /* Unlock wakelock if hif_thread going to idle */ |
| if (!(prGlueInfo->ulFlag & GLUE_FLAG_HIF_PROCESS)) |
| KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &rHifThreadWakeLock); |
| |
| /* |
| * sleep on waitqueue if no events occurred. Event contain (1) GLUE_FLAG_INT |
| * (2) GLUE_FLAG_OID (3) GLUE_FLAG_TXREQ (4) GLUE_FLAG_HALT |
| * |
| */ |
| do { |
| ret = wait_event_interruptible(prGlueInfo->waitq_hif, |
| ((prGlueInfo->ulFlag & GLUE_FLAG_HIF_PROCESS) != 0)); |
| } while (ret != 0); |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| if (!KAL_WAKE_LOCK_ACTIVE(prGlueInfo->prAdapter, &rHifThreadWakeLock)) |
| KAL_WAKE_LOCK(prGlueInfo->prAdapter, &rHifThreadWakeLock); |
| #endif |
| wlanAcquirePowerControl(prGlueInfo->prAdapter); |
| |
| /* Handle Interrupt */ |
| if (test_and_clear_bit(GLUE_FLAG_INT_BIT, &prGlueInfo->ulFlag)) { |
| /* the Wi-Fi interrupt is already disabled in mmc thread, |
| * so we set the flag only to enable the interrupt later |
| */ |
| prGlueInfo->prAdapter->fgIsIntEnable = FALSE; |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| /* Should stop now... skip pending interrupt */ |
| DBGLOG(INIT, INFO, "ignore pending interrupt\n"); |
| } else { |
| /* DBGLOG(INIT, INFO, ("HIF Interrupt!\n")); */ |
| wlanIST(prGlueInfo->prAdapter); |
| } |
| } |
| |
| /* Skip Tx request if SER is operating */ |
| if (!nicSerIsTxStop(prGlueInfo->prAdapter)) { |
| /* TX Commands */ |
| if (test_and_clear_bit(GLUE_FLAG_HIF_TX_CMD_BIT, &prGlueInfo->ulFlag)) |
| wlanTxCmdMthread(prGlueInfo->prAdapter); |
| |
| /* Process TX data packet to HIF */ |
| if (test_and_clear_bit(GLUE_FLAG_HIF_TX_BIT, &prGlueInfo->ulFlag)) |
| nicTxMsduQueueMthread(prGlueInfo->prAdapter); |
| } |
| |
| /* Read chip status when chip no response */ |
| if (test_and_clear_bit(GLUE_FLAG_HIF_PRT_HIF_DBG_INFO_BIT, &prGlueInfo->ulFlag)) |
| halPrintHifDbgInfo(prGlueInfo->prAdapter); |
| |
| /* Set FW own */ |
| if (test_and_clear_bit(GLUE_FLAG_HIF_FW_OWN_BIT, &prGlueInfo->ulFlag)) |
| prGlueInfo->prAdapter->fgWiFiInSleepyState = TRUE; |
| |
| /* Release to FW own */ |
| wlanReleasePowerControl(prGlueInfo->prAdapter); |
| } |
| |
| complete(&prGlueInfo->rHifHaltComp); |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| if (KAL_WAKE_LOCK_ACTIVE(prGlueInfo->prAdapter, &rHifThreadWakeLock)) |
| KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &rHifThreadWakeLock); |
| KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &rHifThreadWakeLock); |
| #endif |
| |
| DBGLOG(INIT, INFO, "%s:%u stopped!\n", KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); |
| |
| return 0; |
| } |
| |
| int rx_thread(void *data) |
| { |
| struct net_device *dev = data; |
| P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); |
| |
| QUE_T rTempRxQue; |
| P_QUE_T prTempRxQue = NULL; |
| P_QUE_ENTRY_T prQueueEntry = NULL; |
| |
| int ret = 0; |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| KAL_WAKE_LOCK_T rRxThreadWakeLock; |
| #endif |
| UINT_32 u4LoopCount; |
| |
| /* for spin lock acquire and release */ |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| KAL_WAKE_LOCK_INIT(prGlueInfo->prAdapter, &rRxThreadWakeLock, "WLAN rx_thread"); |
| KAL_WAKE_LOCK(prGlueInfo->prAdapter, &rRxThreadWakeLock); |
| |
| DBGLOG(INIT, INFO, "%s:%u starts running...\n", KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); |
| |
| prGlueInfo->u4RxThreadPid = KAL_GET_CURRENT_THREAD_ID(); |
| |
| set_user_nice(current, prGlueInfo->prAdapter->rWifiVar.cThreadNice); |
| |
| prTempRxQue = &rTempRxQue; |
| |
| while (TRUE) { |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| DBGLOG(INIT, INFO, "rx_thread should stop now...\n"); |
| break; |
| } |
| |
| /* Unlock wakelock if rx_thread going to idle */ |
| if (!(prGlueInfo->ulFlag & GLUE_FLAG_RX_PROCESS)) |
| KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &rRxThreadWakeLock); |
| |
| /* |
| * sleep on waitqueue if no events occurred. |
| */ |
| do { |
| ret = wait_event_interruptible(prGlueInfo->waitq_rx, |
| ((prGlueInfo->ulFlag & GLUE_FLAG_RX_PROCESS) != 0)); |
| } while (ret != 0); |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| if (!KAL_WAKE_LOCK_ACTIVE(prGlueInfo->prAdapter, &rRxThreadWakeLock)) |
| KAL_WAKE_LOCK(prGlueInfo->prAdapter, &rRxThreadWakeLock); |
| #endif |
| if (test_and_clear_bit(GLUE_FLAG_RX_TO_OS_BIT, &prGlueInfo->ulFlag)) { |
| u4LoopCount = prGlueInfo->prAdapter->rWifiVar.u4Rx2OsLoopCount; |
| |
| while (u4LoopCount--) { |
| while (QUEUE_IS_NOT_EMPTY(&prGlueInfo->prAdapter->rRxQueue)) { |
| QUEUE_INITIALIZE(prTempRxQue); |
| |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_RX_TO_OS_QUE); |
| QUEUE_MOVE_ALL(prTempRxQue, &prGlueInfo->prAdapter->rRxQueue); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_RX_TO_OS_QUE); |
| |
| while (QUEUE_IS_NOT_EMPTY(prTempRxQue)) { |
| QUEUE_REMOVE_HEAD(prTempRxQue, prQueueEntry, P_QUE_ENTRY_T); |
| kalRxIndicateOnePkt(prGlueInfo, |
| (PVOID) GLUE_GET_PKT_DESCRIPTOR(prQueueEntry)); |
| } |
| |
| KAL_WAKE_LOCK_TIMEOUT(prGlueInfo->prAdapter, &prGlueInfo->rTimeoutWakeLock, |
| MSEC_TO_JIFFIES(prGlueInfo->prAdapter->rWifiVar.u4WakeLockRxTimeout)); |
| } |
| } |
| } |
| } |
| |
| complete(&prGlueInfo->rRxHaltComp); |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| if (KAL_WAKE_LOCK_ACTIVE(prGlueInfo->prAdapter, &rRxThreadWakeLock)) |
| KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &rRxThreadWakeLock); |
| KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &rRxThreadWakeLock); |
| #endif |
| |
| DBGLOG(INIT, INFO, "%s:%u stopped!\n", KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); |
| |
| return 0; |
| } |
| #endif |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief This function is a kernel thread function for handling command packets |
| * Tx requests and interrupt events |
| * |
| * @param data data pointer to private data of main_thread |
| * |
| * @retval If the function succeeds, the return value is 0. |
| * Otherwise, an error code is returned. |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| int main_thread(void *data) |
| { |
| struct net_device *dev = data; |
| P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(dev)); |
| P_GL_IO_REQ_T prIoReq = NULL; |
| int ret = 0; |
| BOOLEAN fgNeedHwAccess = FALSE; |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| KAL_WAKE_LOCK_T rTxThreadWakeLock; |
| #endif |
| |
| #if CFG_SUPPORT_MULTITHREAD |
| prGlueInfo->u4TxThreadPid = KAL_GET_CURRENT_THREAD_ID(); |
| #endif |
| |
| current->flags |= PF_NOFREEZE; |
| ASSERT(prGlueInfo); |
| ASSERT(prGlueInfo->prAdapter); |
| set_user_nice(current, prGlueInfo->prAdapter->rWifiVar.cThreadNice); |
| |
| KAL_WAKE_LOCK_INIT(prGlueInfo->prAdapter, &rTxThreadWakeLock, "WLAN main_thread"); |
| KAL_WAKE_LOCK(prGlueInfo->prAdapter, &rTxThreadWakeLock); |
| |
| DBGLOG(INIT, INFO, "%s:%u starts running...\n", KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); |
| |
| while (TRUE) { |
| |
| #if CFG_ENABLE_WIFI_DIRECT |
| /*run p2p multicast list work. */ |
| if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag)) |
| p2pSetMulticastListWorkQueueWrapper(prGlueInfo); |
| #endif |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| DBGLOG(INIT, INFO, "%s should stop now...\n", KAL_GET_CURRENT_THREAD_NAME()); |
| break; |
| } |
| |
| /* Unlock wakelock if main_thread going to idle */ |
| if (!(prGlueInfo->ulFlag & GLUE_FLAG_MAIN_PROCESS)) |
| KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &rTxThreadWakeLock); |
| |
| /* |
| * sleep on waitqueue if no events occurred. Event contain (1) GLUE_FLAG_INT |
| * (2) GLUE_FLAG_OID (3) GLUE_FLAG_TXREQ (4) GLUE_FLAG_HALT |
| * |
| */ |
| do { |
| ret = wait_event_interruptible(prGlueInfo->waitq, |
| ((prGlueInfo->ulFlag & GLUE_FLAG_MAIN_PROCESS) != 0)); |
| } while (ret != 0); |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| if (!KAL_WAKE_LOCK_ACTIVE(prGlueInfo->prAdapter, &rTxThreadWakeLock)) |
| KAL_WAKE_LOCK(prGlueInfo->prAdapter, &rTxThreadWakeLock); |
| #endif |
| |
| #if CFG_ENABLE_WIFI_DIRECT |
| /*run p2p multicast list work. */ |
| if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag)) |
| p2pSetMulticastListWorkQueueWrapper(prGlueInfo); |
| |
| if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_BIT, &prGlueInfo->ulFlag)) { |
| p2pFuncUpdateMgmtFrameRegister(prGlueInfo->prAdapter, |
| prGlueInfo->prP2PDevInfo->u4OsMgmtFrameFilter); |
| } |
| #endif |
| if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag)) { |
| P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T) NULL; |
| /* printk("prGlueInfo->u4OsMgmtFrameFilter = %x", prGlueInfo->u4OsMgmtFrameFilter); */ |
| prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); |
| prAisFsmInfo->u4AisPacketFilter = prGlueInfo->u4OsMgmtFrameFilter; |
| } |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| DBGLOG(INIT, INFO, "%s should stop now...\n", KAL_GET_CURRENT_THREAD_NAME()); |
| break; |
| } |
| |
| fgNeedHwAccess = FALSE; |
| |
| #if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN |
| if (prGlueInfo->fgEnSdioTestPattern == TRUE) { |
| if (fgNeedHwAccess == FALSE) { |
| fgNeedHwAccess = TRUE; |
| |
| wlanAcquirePowerControl(prGlueInfo->prAdapter); |
| } |
| |
| if (prGlueInfo->fgIsSdioTestInitialized == FALSE) { |
| /* enable PRBS mode */ |
| kalDevRegWrite(prGlueInfo, MCR_WTMCR, 0x00080002); |
| prGlueInfo->fgIsSdioTestInitialized = TRUE; |
| } |
| |
| if (prGlueInfo->fgSdioReadWriteMode == TRUE) { |
| /* read test */ |
| kalDevPortRead(prGlueInfo, |
| MCR_WTMDR, |
| 256, |
| prGlueInfo->aucSdioTestBuffer, sizeof(prGlueInfo->aucSdioTestBuffer)); |
| } else { |
| /* write test */ |
| kalDevPortWrite(prGlueInfo, |
| MCR_WTMDR, |
| 172, |
| prGlueInfo->aucSdioTestBuffer, sizeof(prGlueInfo->aucSdioTestBuffer)); |
| } |
| } |
| #endif |
| #if CFG_SUPPORT_MULTITHREAD |
| #else |
| /* Handle Interrupt */ |
| if (test_and_clear_bit(GLUE_FLAG_INT_BIT, &prGlueInfo->ulFlag)) { |
| |
| if (fgNeedHwAccess == FALSE) { |
| fgNeedHwAccess = TRUE; |
| |
| wlanAcquirePowerControl(prGlueInfo->prAdapter); |
| } |
| |
| /* the Wi-Fi interrupt is already disabled in mmc thread, |
| * so we set the flag only to enable the interrupt later |
| */ |
| prGlueInfo->prAdapter->fgIsIntEnable = FALSE; |
| /* wlanISR(prGlueInfo->prAdapter, TRUE); */ |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| /* Should stop now... skip pending interrupt */ |
| DBGLOG(INIT, INFO, "ignore pending interrupt\n"); |
| } else { |
| wlanIST(prGlueInfo->prAdapter); |
| } |
| } |
| #endif |
| /* transfer ioctl to OID request */ |
| |
| do { |
| if (test_and_clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag)) { |
| /* get current prIoReq */ |
| prIoReq = &(prGlueInfo->OidEntry); |
| if (prIoReq->fgRead == FALSE) { |
| prIoReq->rStatus = wlanSetInformation(prIoReq->prAdapter, |
| prIoReq->pfnOidHandler, |
| prIoReq->pvInfoBuf, |
| prIoReq->u4InfoBufLen, |
| prIoReq->pu4QryInfoLen); |
| } else { |
| prIoReq->rStatus = wlanQueryInformation(prIoReq->prAdapter, |
| prIoReq->pfnOidHandler, |
| prIoReq->pvInfoBuf, |
| prIoReq->u4InfoBufLen, |
| prIoReq->pu4QryInfoLen); |
| } |
| |
| if (prIoReq->rStatus != WLAN_STATUS_PENDING) { |
| /* complete ONLY if there are waiters */ |
| if (!completion_done(&prGlueInfo->rPendComp)) |
| complete(&prGlueInfo->rPendComp); |
| else |
| DBGLOG(INIT, WARN, "SKIP multiple OID complete!\n"); |
| } else { |
| wlanoidTimeoutCheck(prGlueInfo->prAdapter, |
| prIoReq->pfnOidHandler, |
| prIoReq->u4Timeout); |
| } |
| } |
| |
| } while (FALSE); |
| |
| /* |
| * |
| * if TX request, clear the TXREQ flag. TXREQ set by kalSetEvent/GlueSetEvent |
| * indicates the following requests occur |
| * |
| */ |
| |
| if (test_and_clear_bit(GLUE_FLAG_TXREQ_BIT, &prGlueInfo->ulFlag)) |
| kalProcessTxReq(prGlueInfo, &fgNeedHwAccess); |
| #if CFG_SUPPORT_MULTITHREAD |
| /* Process RX */ |
| if (test_and_clear_bit(GLUE_FLAG_RX_BIT, &prGlueInfo->ulFlag)) |
| nicRxProcessRFBs(prGlueInfo->prAdapter); |
| if (test_and_clear_bit(GLUE_FLAG_TX_CMD_DONE_BIT, &prGlueInfo->ulFlag)) |
| wlanTxCmdDoneMthread(prGlueInfo->prAdapter); |
| #endif |
| |
| /* Process RX, In linux, we don't need to free sk_buff by ourself */ |
| |
| /* In linux, we don't need to free sk_buff by ourself */ |
| |
| /* In linux, we don't do reset */ |
| #if CFG_SUPPORT_MULTITHREAD |
| #else |
| if (fgNeedHwAccess == TRUE) |
| wlanReleasePowerControl(prGlueInfo->prAdapter); |
| #endif |
| /* handle cnmTimer time out */ |
| if (test_and_clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag)) |
| wlanTimerTimeoutCheck(prGlueInfo->prAdapter); |
| #if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN |
| if (prGlueInfo->fgEnSdioTestPattern == TRUE) |
| kalSetEvent(prGlueInfo); |
| #endif |
| } |
| |
| #if 0 |
| if (fgNeedHwAccess == TRUE) |
| wlanReleasePowerControl(prGlueInfo->prAdapter); |
| #endif |
| |
| /* flush the pending TX packets */ |
| if (GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum) > 0) |
| kalFlushPendingTxPackets(prGlueInfo); |
| |
| /* flush pending security frames */ |
| if (GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum) > 0) |
| kalClearSecurityFrames(prGlueInfo); |
| |
| /* remove pending oid */ |
| wlanReleasePendingOid(prGlueInfo->prAdapter, 0); |
| |
| complete(&prGlueInfo->rHaltComp); |
| #if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK) |
| if (KAL_WAKE_LOCK_ACTIVE(prGlueInfo->prAdapter, &rTxThreadWakeLock)) |
| KAL_WAKE_UNLOCK(prGlueInfo->prAdapter, &rTxThreadWakeLock); |
| KAL_WAKE_LOCK_DESTROY(prGlueInfo->prAdapter, &rTxThreadWakeLock); |
| #endif |
| |
| DBGLOG(INIT, INFO, "%s:%u stopped!\n", KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); |
| |
| return 0; |
| |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to check if card is removed |
| * |
| * \param pvGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval TRUE: card is removed |
| * FALSE: card is still attached |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| ASSERT(prGlueInfo); |
| |
| return FALSE; |
| /* Linux MMC doesn't have removal notification yet */ |
| } |
| |
| |
| #ifdef CONFIG_IDME |
| #define IDME_MACADDR "/proc/idme/mac_addr" |
| static int idme_get_mac_addr(unsigned char *mac_addr, size_t addr_len) |
| { |
| unsigned char buf[IFHWADDRLEN * 2 + 1] = {""}, str[3] = {""}; |
| int i, mac[IFHWADDRLEN]; |
| mm_segment_t old_fs; |
| struct file *f; |
| size_t len; |
| |
| if (!mac_addr || addr_len < IFHWADDRLEN) { |
| DBGLOG(INIT, ERROR, "invalid mac_addr ptr or buf\n"); |
| return -1; |
| } |
| |
| f = filp_open(IDME_MACADDR, O_RDONLY, 0); |
| if (IS_ERR(f)) { |
| DBGLOG(INIT, ERROR, "can't open mac addr file\n"); |
| return -1; |
| } |
| |
| old_fs = get_fs(); |
| set_fs(get_ds()); |
| f->f_op->read(f, buf, IFHWADDRLEN * 2, &f->f_pos); |
| filp_close(f, NULL); |
| set_fs(old_fs); |
| |
| if (strlen(buf) != IFHWADDRLEN * 2) |
| goto bailout; |
| |
| for (i = 0; i < IFHWADDRLEN; i++) { |
| str[0] = buf[i * 2]; |
| str[1] = buf[i * 2 + 1]; |
| if (!isxdigit(str[0]) || !isxdigit(str[1])) |
| goto bailout; |
| len = sscanf(str, "%02x", &mac[i]); |
| if (len != 1) |
| goto bailout; |
| } |
| for (i = 0; i < IFHWADDRLEN; i++) |
| mac_addr[i] = (unsigned char)mac[i]; |
| return 0; |
| bailout: |
| DBGLOG(INIT, ERROR, "wrong mac addr %02x %02x\n", buf[0], buf[1]); |
| return -1; |
| } |
| #endif |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to send command to firmware for overriding netweork address |
| * |
| * \param pvGlueInfo Pointer of GLUE Data Structure |
| |
| * \retval TRUE |
| * FALSE |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, IN OUT PARAM_MAC_ADDRESS *prMacAddr) |
| { |
| P_ADAPTER_T prAdapter; |
| ASSERT(prGlueInfo); |
| |
| prAdapter = prGlueInfo->prAdapter; |
| |
| /* Get MAC address override from wlan feature option */ |
| prGlueInfo->fgIsMacAddrOverride = prAdapter->rWifiVar.ucMacAddrOverride; |
| |
| wlanHwAddrToBin(prAdapter->rWifiVar.aucMacAddrStr, prGlueInfo->rMacAddrOverride); |
| |
| #ifdef CONFIG_IDME |
| if (prMacAddr && 0 == idme_get_mac_addr((unsigned char *)prMacAddr, sizeof(PARAM_MAC_ADDRESS))) { |
| DBGLOG(INIT, INFO, "use IDME mac addr\n"); |
| return TRUE; |
| } |
| #endif |
| |
| if (prGlueInfo->fgIsMacAddrOverride == FALSE) { |
| UINT_32 i; |
| BOOLEAN fgIsReadError = FALSE; |
| |
| #if !defined(CONFIG_X86) |
| for (i = 0; i < MAC_ADDR_LEN; i += 2) { |
| if (kalCfgDataRead16(prGlueInfo, |
| OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, |
| (PUINT_16) (((PUINT_8) prMacAddr) + i)) == FALSE) { |
| fgIsReadError = TRUE; |
| break; |
| } |
| } |
| #else |
| /* x86 Linux doesn't need to override network address so far */ |
| /*return FALSE;*/ |
| /*Modify for Linux PC support NVRAM Setting*/ |
| for (i = 0; i < MAC_ADDR_LEN; i += 2) { |
| if (kalCfgDataRead16(prGlueInfo, |
| OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, |
| (PUINT_16) (((PUINT_8) prMacAddr) + i)) == FALSE) { |
| fgIsReadError = TRUE; |
| break; |
| } |
| } |
| |
| #endif |
| |
| #if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) |
| /* retrieve buffer mode efuse */ |
| if ((prAdapter->fgIsSupportPowerOnSendBufferModeCMD == TRUE) && |
| (prAdapter->rWifiVar.ucEfuseBufferModeCal == TRUE)) { |
| if (wlanExtractBufferBin(prAdapter) == WLAN_STATUS_SUCCESS) { |
| UINT_32 u4BinOffset = prAdapter->u4EfuseMacAddrOffset; |
| |
| /* Update MAC address */ |
| kalMemCopy(prMacAddr, &uacEEPROMImage[u4BinOffset], MAC_ADDR_LEN); |
| fgIsReadError = FALSE; |
| } else { |
| fgIsReadError = TRUE; |
| } |
| } |
| #endif |
| /* return retrieve result */ |
| if (fgIsReadError == TRUE) |
| return FALSE; |
| else |
| return TRUE; |
| |
| |
| } else { |
| COPY_MAC_ADDR(prMacAddr, prGlueInfo->rMacAddrOverride); |
| |
| return TRUE; |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to flush pending TX packets in glue layer |
| * |
| * \param pvGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| P_QUE_T prTxQue; |
| P_QUE_ENTRY_T prQueueEntry; |
| PVOID prPacket; |
| |
| ASSERT(prGlueInfo); |
| |
| prTxQue = &(prGlueInfo->rTxQueue); |
| |
| if (GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum) == 0) |
| return; |
| |
| if (HAL_IS_TX_DIRECT()) { |
| nicTxDirectClearSkbQ(prGlueInfo->prAdapter); |
| } else { |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| while (TRUE) { |
| GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); |
| QUEUE_REMOVE_HEAD(prTxQue, prQueueEntry, P_QUE_ENTRY_T); |
| GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); |
| |
| if (prQueueEntry == NULL) |
| break; |
| |
| prPacket = GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); |
| |
| kalSendComplete(prGlueInfo, prPacket, WLAN_STATUS_NOT_ACCEPTED); |
| } |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is get indicated media state |
| * |
| * \param pvGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval |
| */ |
| /*----------------------------------------------------------------------------*/ |
| ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| ASSERT(prGlueInfo); |
| |
| return prGlueInfo->eParamMediaStateIndicated; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to set indicated media state |
| * |
| * \param pvGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicate) |
| { |
| ASSERT(prGlueInfo); |
| |
| prGlueInfo->eParamMediaStateIndicated = eParamMediaStateIndicate; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to clear pending OID staying in command queue |
| * |
| * \param prGlueInfo Pointer of GLUE Data Structure |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo) |
| { |
| P_QUE_T prCmdQue; |
| QUE_T rTempCmdQue; |
| P_QUE_T prTempCmdQue = &rTempCmdQue; |
| QUE_T rReturnCmdQue; |
| P_QUE_T prReturnCmdQue = &rReturnCmdQue; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL; |
| |
| GLUE_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prGlueInfo); |
| |
| QUEUE_INITIALIZE(prReturnCmdQue); |
| |
| prCmdQue = &prGlueInfo-> |