summaryrefslogtreecommitdiff
path: root/drivers/staging/rtl8723bs/hal/sdio_ops.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-05 18:16:23 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-05 18:16:23 -0700
commitc6a677c6f37bb7abc85ba7e3465e82b9f7eb1d91 (patch)
tree9d0d4bb2e150837297cddc5be7f1b4950e9ab228 /drivers/staging/rtl8723bs/hal/sdio_ops.c
parente87d51ac61f88ae44fe14b34abe08566032d726b (diff)
parent11270059e8d0b6f80801fac910c4ef751ca05c4c (diff)
Merge tag 'staging-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging/IIO updates from Greg KH: "Here is the big staging tree update for 4.12-rc1. It's a big one, adding about 350k new lines of crap^Wcode, mostly all in a big dump of media drivers from Intel. But there's other new drivers in here as well, yet-another-wifi driver, new IIO drivers, and a new crypto accelerator. We also deleted a bunch of stuff, mostly in patch cleanups, but also the Android ION code has shrunk a lot, and the Android low memory killer driver was finally deleted, much to the celebration of the -mm developers. All of these have been in linux-next with a few build issues that will show up when you merge to your tree" Merge conflicts in the new rtl8723bs driver (due to the wifi changes this merge window) handled as per linux-next, courtesy of Stephen Rothwell. * tag 'staging-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1182 commits) staging: fsl-mc/dpio: add cpu <--> LE conversion for dpaa2_fd staging: ks7010: remove line continuations in quoted strings staging: vt6656: use tabs instead of spaces staging: android: ion: Fix unnecessary initialization of static variable staging: media: atomisp: fix range checking on clk_num staging: media: atomisp: fix misspelled word in comment staging: media: atomisp: kmap() can't fail staging: atomisp: remove #ifdef for runtime PM functions staging: atomisp: satm include directory is gone atomisp: remove some more unused files atomisp: remove hmm_load/store/clear indirections atomisp: kill off mmgr_free atomisp: clean up the hmm init/cleanup indirections atomisp: handle allocation calls before init in the hmm layer staging: fsl-dpaa2/eth: Add maintainer for Ethernet driver staging: fsl-dpaa2/eth: Add TODO file staging: fsl-dpaa2/eth: Add trace points staging: fsl-dpaa2/eth: Add driver specific stats staging: fsl-dpaa2/eth: Add ethtool support staging: fsl-dpaa2/eth: Add Freescale DPAA2 Ethernet driver ...
Diffstat (limited to 'drivers/staging/rtl8723bs/hal/sdio_ops.c')
-rw-r--r--drivers/staging/rtl8723bs/hal/sdio_ops.c1294
1 files changed, 1294 insertions, 0 deletions
diff --git a/drivers/staging/rtl8723bs/hal/sdio_ops.c b/drivers/staging/rtl8723bs/hal/sdio_ops.c
new file mode 100644
index 000000000000..6285b72faa9a
--- /dev/null
+++ b/drivers/staging/rtl8723bs/hal/sdio_ops.c
@@ -0,0 +1,1294 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * 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 the GNU General Public License for
+ * more details.
+ *
+ *******************************************************************************/
+#define _SDIO_OPS_C_
+
+#include <drv_types.h>
+#include <rtw_debug.h>
+#include <rtl8723b_hal.h>
+
+/* define SDIO_DEBUG_IO 1 */
+
+
+/* */
+/* Description: */
+/* The following mapping is for SDIO host local register space. */
+/* */
+/* Creadted by Roger, 2011.01.31. */
+/* */
+static void HalSdioGetCmdAddr8723BSdio(
+ struct adapter *padapter,
+ u8 DeviceID,
+ u32 Addr,
+ u32 *pCmdAddr
+)
+{
+ switch (DeviceID) {
+ case SDIO_LOCAL_DEVICE_ID:
+ *pCmdAddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (Addr & SDIO_LOCAL_MSK));
+ break;
+
+ case WLAN_IOREG_DEVICE_ID:
+ *pCmdAddr = ((WLAN_IOREG_DEVICE_ID << 13) | (Addr & WLAN_IOREG_MSK));
+ break;
+
+ case WLAN_TX_HIQ_DEVICE_ID:
+ *pCmdAddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK));
+ break;
+
+ case WLAN_TX_MIQ_DEVICE_ID:
+ *pCmdAddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK));
+ break;
+
+ case WLAN_TX_LOQ_DEVICE_ID:
+ *pCmdAddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (Addr & WLAN_FIFO_MSK));
+ break;
+
+ case WLAN_RX0FF_DEVICE_ID:
+ *pCmdAddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (Addr & WLAN_RX0FF_MSK));
+ break;
+
+ default:
+ break;
+ }
+}
+
+static u8 get_deviceid(u32 addr)
+{
+ u8 devideId;
+ u16 pseudoId;
+
+
+ pseudoId = (u16)(addr >> 16);
+ switch (pseudoId) {
+ case 0x1025:
+ devideId = SDIO_LOCAL_DEVICE_ID;
+ break;
+
+ case 0x1026:
+ devideId = WLAN_IOREG_DEVICE_ID;
+ break;
+
+/* case 0x1027: */
+/* devideId = SDIO_FIRMWARE_FIFO; */
+/* break; */
+
+ case 0x1031:
+ devideId = WLAN_TX_HIQ_DEVICE_ID;
+ break;
+
+ case 0x1032:
+ devideId = WLAN_TX_MIQ_DEVICE_ID;
+ break;
+
+ case 0x1033:
+ devideId = WLAN_TX_LOQ_DEVICE_ID;
+ break;
+
+ case 0x1034:
+ devideId = WLAN_RX0FF_DEVICE_ID;
+ break;
+
+ default:
+/* devideId = (u8)((addr >> 13) & 0xF); */
+ devideId = WLAN_IOREG_DEVICE_ID;
+ break;
+ }
+
+ return devideId;
+}
+
+/*
+ * Ref:
+ *HalSdioGetCmdAddr8723BSdio()
+ */
+static u32 _cvrt2ftaddr(const u32 addr, u8 *pdeviceId, u16 *poffset)
+{
+ u8 deviceId;
+ u16 offset;
+ u32 ftaddr;
+
+
+ deviceId = get_deviceid(addr);
+ offset = 0;
+
+ switch (deviceId) {
+ case SDIO_LOCAL_DEVICE_ID:
+ offset = addr & SDIO_LOCAL_MSK;
+ break;
+
+ case WLAN_TX_HIQ_DEVICE_ID:
+ case WLAN_TX_MIQ_DEVICE_ID:
+ case WLAN_TX_LOQ_DEVICE_ID:
+ offset = addr & WLAN_FIFO_MSK;
+ break;
+
+ case WLAN_RX0FF_DEVICE_ID:
+ offset = addr & WLAN_RX0FF_MSK;
+ break;
+
+ case WLAN_IOREG_DEVICE_ID:
+ default:
+ deviceId = WLAN_IOREG_DEVICE_ID;
+ offset = addr & WLAN_IOREG_MSK;
+ break;
+ }
+ ftaddr = (deviceId << 13) | offset;
+
+ if (pdeviceId)
+ *pdeviceId = deviceId;
+ if (poffset)
+ *poffset = offset;
+
+ return ftaddr;
+}
+
+static u8 sdio_read8(struct intf_hdl *pintfhdl, u32 addr)
+{
+ u32 ftaddr;
+ u8 val;
+
+ ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
+ val = sd_read8(pintfhdl, ftaddr, NULL);
+ return val;
+}
+
+static u16 sdio_read16(struct intf_hdl *pintfhdl, u32 addr)
+{
+ u32 ftaddr;
+ u16 val;
+ __le16 le_tmp;
+
+ ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
+ sd_cmd52_read(pintfhdl, ftaddr, 2, (u8 *)&le_tmp);
+ val = le16_to_cpu(le_tmp);
+ return val;
+}
+
+static u32 sdio_read32(struct intf_hdl *pintfhdl, u32 addr)
+{
+ struct adapter *padapter;
+ u8 bMacPwrCtrlOn;
+ u8 deviceId;
+ u16 offset;
+ u32 ftaddr;
+ u8 shift;
+ u32 val;
+ s32 err;
+ __le32 le_tmp;
+
+ padapter = pintfhdl->padapter;
+ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (
+ ((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
+ (false == bMacPwrCtrlOn) ||
+ (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
+ ) {
+ err = sd_cmd52_read(pintfhdl, ftaddr, 4, (u8 *)&le_tmp);
+#ifdef SDIO_DEBUG_IO
+ if (!err) {
+#endif
+ val = le32_to_cpu(le_tmp);
+ return val;
+#ifdef SDIO_DEBUG_IO
+ }
+
+ DBG_8192C(KERN_ERR "%s: Mac Power off, Read FAIL(%d)! addr = 0x%x\n", __func__, err, addr);
+ return SDIO_ERR_VAL32;
+#endif
+ }
+
+ /* 4 bytes alignment */
+ shift = ftaddr & 0x3;
+ if (shift == 0) {
+ val = sd_read32(pintfhdl, ftaddr, NULL);
+ } else {
+ u8 *ptmpbuf;
+
+ ptmpbuf = (u8 *)rtw_malloc(8);
+ if (NULL == ptmpbuf) {
+ DBG_8192C(KERN_ERR "%s: Allocate memory FAIL!(size =8) addr = 0x%x\n", __func__, addr);
+ return SDIO_ERR_VAL32;
+ }
+
+ ftaddr &= ~(u16)0x3;
+ sd_read(pintfhdl, ftaddr, 8, ptmpbuf);
+ memcpy(&le_tmp, ptmpbuf+shift, 4);
+ val = le32_to_cpu(le_tmp);
+
+ kfree(ptmpbuf);
+ }
+ return val;
+}
+
+static s32 sdio_readN(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pbuf)
+{
+ struct adapter *padapter;
+ u8 bMacPwrCtrlOn;
+ u8 deviceId;
+ u16 offset;
+ u32 ftaddr;
+ u8 shift;
+ s32 err;
+
+ padapter = pintfhdl->padapter;
+ err = 0;
+
+ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (
+ ((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
+ (false == bMacPwrCtrlOn) ||
+ (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
+ ) {
+ err = sd_cmd52_read(pintfhdl, ftaddr, cnt, pbuf);
+ return err;
+ }
+
+ /* 4 bytes alignment */
+ shift = ftaddr & 0x3;
+ if (shift == 0) {
+ err = sd_read(pintfhdl, ftaddr, cnt, pbuf);
+ } else {
+ u8 *ptmpbuf;
+ u32 n;
+
+ ftaddr &= ~(u16)0x3;
+ n = cnt + shift;
+ ptmpbuf = rtw_malloc(n);
+ if (NULL == ptmpbuf)
+ return -1;
+
+ err = sd_read(pintfhdl, ftaddr, n, ptmpbuf);
+ if (!err)
+ memcpy(pbuf, ptmpbuf+shift, cnt);
+ kfree(ptmpbuf);
+ }
+ return err;
+}
+
+static s32 sdio_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
+{
+ u32 ftaddr;
+ s32 err;
+
+ ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
+ sd_write8(pintfhdl, ftaddr, val, &err);
+
+ return err;
+}
+
+static s32 sdio_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
+{
+ u32 ftaddr;
+ s32 err;
+ __le16 le_tmp;
+
+ ftaddr = _cvrt2ftaddr(addr, NULL, NULL);
+ le_tmp = cpu_to_le16(val);
+ err = sd_cmd52_write(pintfhdl, ftaddr, 2, (u8 *)&le_tmp);
+
+ return err;
+}
+
+static s32 sdio_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
+{
+ struct adapter *padapter;
+ u8 bMacPwrCtrlOn;
+ u8 deviceId;
+ u16 offset;
+ u32 ftaddr;
+ u8 shift;
+ s32 err;
+ __le32 le_tmp;
+
+ padapter = pintfhdl->padapter;
+ err = 0;
+
+ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (
+ ((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
+ (!bMacPwrCtrlOn) ||
+ (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
+ ) {
+ le_tmp = cpu_to_le32(val);
+ err = sd_cmd52_write(pintfhdl, ftaddr, 4, (u8 *)&le_tmp);
+ return err;
+ }
+
+ /* 4 bytes alignment */
+ shift = ftaddr & 0x3;
+ if (shift == 0) {
+ sd_write32(pintfhdl, ftaddr, val, &err);
+ } else {
+ le_tmp = cpu_to_le32(val);
+ err = sd_cmd52_write(pintfhdl, ftaddr, 4, (u8 *)&le_tmp);
+ }
+ return err;
+}
+
+static s32 sdio_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pbuf)
+{
+ struct adapter *padapter;
+ u8 bMacPwrCtrlOn;
+ u8 deviceId;
+ u16 offset;
+ u32 ftaddr;
+ u8 shift;
+ s32 err;
+
+ padapter = pintfhdl->padapter;
+ err = 0;
+
+ ftaddr = _cvrt2ftaddr(addr, &deviceId, &offset);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (
+ ((deviceId == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) ||
+ (false == bMacPwrCtrlOn) ||
+ (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
+ ) {
+ err = sd_cmd52_write(pintfhdl, ftaddr, cnt, pbuf);
+ return err;
+ }
+
+ shift = ftaddr & 0x3;
+ if (shift == 0) {
+ err = sd_write(pintfhdl, ftaddr, cnt, pbuf);
+ } else {
+ u8 *ptmpbuf;
+ u32 n;
+
+ ftaddr &= ~(u16)0x3;
+ n = cnt + shift;
+ ptmpbuf = rtw_malloc(n);
+ if (NULL == ptmpbuf)
+ return -1;
+ err = sd_read(pintfhdl, ftaddr, 4, ptmpbuf);
+ if (err) {
+ kfree(ptmpbuf);
+ return err;
+ }
+ memcpy(ptmpbuf+shift, pbuf, cnt);
+ err = sd_write(pintfhdl, ftaddr, n, ptmpbuf);
+ kfree(ptmpbuf);
+ }
+ return err;
+}
+
+static u8 sdio_f0_read8(struct intf_hdl *pintfhdl, u32 addr)
+{
+ return sd_f0_read8(pintfhdl, addr, NULL);
+}
+
+static void sdio_read_mem(
+ struct intf_hdl *pintfhdl,
+ u32 addr,
+ u32 cnt,
+ u8 *rmem
+)
+{
+ s32 err;
+
+ err = sdio_readN(pintfhdl, addr, cnt, rmem);
+ /* TODO: Report error is err not zero */
+}
+
+static void sdio_write_mem(
+ struct intf_hdl *pintfhdl,
+ u32 addr,
+ u32 cnt,
+ u8 *wmem
+)
+{
+ sdio_writeN(pintfhdl, addr, cnt, wmem);
+}
+
+/*
+ * Description:
+ *Read from RX FIFO
+ *Round read size to block size,
+ *and make sure data transfer will be done in one command.
+ *
+ * Parameters:
+ *pintfhdl a pointer of intf_hdl
+ *addr port ID
+ *cnt size to read
+ *rmem address to put data
+ *
+ * Return:
+ *_SUCCESS(1) Success
+ *_FAIL(0) Fail
+ */
+static u32 sdio_read_port(
+ struct intf_hdl *pintfhdl,
+ u32 addr,
+ u32 cnt,
+ u8 *mem
+)
+{
+ struct adapter *padapter;
+ PSDIO_DATA psdio;
+ struct hal_com_data *phal;
+ u32 oldcnt;
+#ifdef SDIO_DYNAMIC_ALLOC_MEM
+ u8 *oldmem;
+#endif
+ s32 err;
+
+
+ padapter = pintfhdl->padapter;
+ psdio = &adapter_to_dvobj(padapter)->intf_data;
+ phal = GET_HAL_DATA(padapter);
+
+ HalSdioGetCmdAddr8723BSdio(padapter, addr, phal->SdioRxFIFOCnt++, &addr);
+
+ oldcnt = cnt;
+ if (cnt > psdio->block_transfer_len)
+ cnt = _RND(cnt, psdio->block_transfer_len);
+/* cnt = sdio_align_size(cnt); */
+
+ if (oldcnt != cnt) {
+#ifdef SDIO_DYNAMIC_ALLOC_MEM
+ oldmem = mem;
+ mem = rtw_malloc(cnt);
+ if (mem == NULL) {
+ DBG_8192C(KERN_WARNING "%s: allocate memory %d bytes fail!\n", __func__, cnt);
+ mem = oldmem;
+ oldmem == NULL;
+ }
+#else
+ /* in this case, caller should gurante the buffer is big enough */
+ /* to receive data after alignment */
+#endif
+ }
+
+ err = _sd_read(pintfhdl, addr, cnt, mem);
+
+#ifdef SDIO_DYNAMIC_ALLOC_MEM
+ if ((oldcnt != cnt) && (oldmem)) {
+ memcpy(oldmem, mem, oldcnt);
+ kfree(mem);
+ }
+#endif
+
+ if (err)
+ return _FAIL;
+ return _SUCCESS;
+}
+
+/*
+ * Description:
+ *Write to TX FIFO
+ *Align write size block size,
+ *and make sure data could be written in one command.
+ *
+ * Parameters:
+ *pintfhdl a pointer of intf_hdl
+ *addr port ID
+ *cnt size to write
+ *wmem data pointer to write
+ *
+ * Return:
+ *_SUCCESS(1) Success
+ *_FAIL(0) Fail
+ */
+static u32 sdio_write_port(
+ struct intf_hdl *pintfhdl,
+ u32 addr,
+ u32 cnt,
+ u8 *mem
+)
+{
+ struct adapter *padapter;
+ PSDIO_DATA psdio;
+ s32 err;
+ struct xmit_buf *xmitbuf = (struct xmit_buf *)mem;
+
+ padapter = pintfhdl->padapter;
+ psdio = &adapter_to_dvobj(padapter)->intf_data;
+
+ if (padapter->hw_init_completed == false) {
+ DBG_871X("%s [addr = 0x%x cnt =%d] padapter->hw_init_completed == false\n", __func__, addr, cnt);
+ return _FAIL;
+ }
+
+ cnt = _RND4(cnt);
+ HalSdioGetCmdAddr8723BSdio(padapter, addr, cnt >> 2, &addr);
+
+ if (cnt > psdio->block_transfer_len)
+ cnt = _RND(cnt, psdio->block_transfer_len);
+/* cnt = sdio_align_size(cnt); */
+
+ err = sd_write(pintfhdl, addr, cnt, xmitbuf->pdata);
+
+ rtw_sctx_done_err(
+ &xmitbuf->sctx,
+ err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS
+ );
+
+ if (err)
+ return _FAIL;
+ return _SUCCESS;
+}
+
+void sdio_set_intf_ops(struct adapter *padapter, struct _io_ops *pops)
+{
+ pops->_read8 = &sdio_read8;
+ pops->_read16 = &sdio_read16;
+ pops->_read32 = &sdio_read32;
+ pops->_read_mem = &sdio_read_mem;
+ pops->_read_port = &sdio_read_port;
+
+ pops->_write8 = &sdio_write8;
+ pops->_write16 = &sdio_write16;
+ pops->_write32 = &sdio_write32;
+ pops->_writeN = &sdio_writeN;
+ pops->_write_mem = &sdio_write_mem;
+ pops->_write_port = &sdio_write_port;
+
+ pops->_sd_f0_read8 = sdio_f0_read8;
+}
+
+/*
+ * Todo: align address to 4 bytes.
+ */
+static s32 _sdio_local_read(
+ struct adapter *padapter,
+ u32 addr,
+ u32 cnt,
+ u8 *pbuf
+)
+{
+ struct intf_hdl *pintfhdl;
+ u8 bMacPwrCtrlOn;
+ s32 err;
+ u8 *ptmpbuf;
+ u32 n;
+
+
+ pintfhdl = &padapter->iopriv.intf;
+
+ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (false == bMacPwrCtrlOn) {
+ err = _sd_cmd52_read(pintfhdl, addr, cnt, pbuf);
+ return err;
+ }
+
+ n = RND4(cnt);
+ ptmpbuf = (u8 *)rtw_malloc(n);
+ if (!ptmpbuf)
+ return (-1);
+
+ err = _sd_read(pintfhdl, addr, n, ptmpbuf);
+ if (!err)
+ memcpy(pbuf, ptmpbuf, cnt);
+
+ kfree(ptmpbuf);
+
+ return err;
+}
+
+/*
+ * Todo: align address to 4 bytes.
+ */
+s32 sdio_local_read(
+ struct adapter *padapter,
+ u32 addr,
+ u32 cnt,
+ u8 *pbuf
+)
+{
+ struct intf_hdl *pintfhdl;
+ u8 bMacPwrCtrlOn;
+ s32 err;
+ u8 *ptmpbuf;
+ u32 n;
+
+ pintfhdl = &padapter->iopriv.intf;
+
+ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (
+ (false == bMacPwrCtrlOn) ||
+ (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
+ ) {
+ err = sd_cmd52_read(pintfhdl, addr, cnt, pbuf);
+ return err;
+ }
+
+ n = RND4(cnt);
+ ptmpbuf = (u8 *)rtw_malloc(n);
+ if (!ptmpbuf)
+ return (-1);
+
+ err = sd_read(pintfhdl, addr, n, ptmpbuf);
+ if (!err)
+ memcpy(pbuf, ptmpbuf, cnt);
+
+ kfree(ptmpbuf);
+
+ return err;
+}
+
+/*
+ * Todo: align address to 4 bytes.
+ */
+s32 sdio_local_write(
+ struct adapter *padapter,
+ u32 addr,
+ u32 cnt,
+ u8 *pbuf
+)
+{
+ struct intf_hdl *pintfhdl;
+ u8 bMacPwrCtrlOn;
+ s32 err;
+ u8 *ptmpbuf;
+
+ if (addr & 0x3)
+ DBG_8192C("%s, address must be 4 bytes alignment\n", __func__);
+
+ if (cnt & 0x3)
+ DBG_8192C("%s, size must be the multiple of 4\n", __func__);
+
+ pintfhdl = &padapter->iopriv.intf;
+
+ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (
+ (false == bMacPwrCtrlOn) ||
+ (true == adapter_to_pwrctl(padapter)->bFwCurrentInPSMode)
+ ) {
+ err = sd_cmd52_write(pintfhdl, addr, cnt, pbuf);
+ return err;
+ }
+
+ ptmpbuf = (u8 *)rtw_malloc(cnt);
+ if (!ptmpbuf)
+ return (-1);
+
+ memcpy(ptmpbuf, pbuf, cnt);
+
+ err = sd_write(pintfhdl, addr, cnt, ptmpbuf);
+
+ kfree(ptmpbuf);
+
+ return err;
+}
+
+u8 SdioLocalCmd52Read1Byte(struct adapter *padapter, u32 addr)
+{
+ u8 val = 0;
+ struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
+
+ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
+ sd_cmd52_read(pintfhdl, addr, 1, &val);
+
+ return val;
+}
+
+static u16 SdioLocalCmd52Read2Byte(struct adapter *padapter, u32 addr)
+{
+ __le16 val = 0;
+ struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
+
+ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
+ sd_cmd52_read(pintfhdl, addr, 2, (u8 *)&val);
+
+ return le16_to_cpu(val);
+}
+
+static u32 SdioLocalCmd53Read4Byte(struct adapter *padapter, u32 addr)
+{
+
+ u8 bMacPwrCtrlOn;
+ u32 val = 0;
+ struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
+ __le32 le_tmp;
+
+ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (!bMacPwrCtrlOn || adapter_to_pwrctl(padapter)->bFwCurrentInPSMode) {
+ sd_cmd52_read(pintfhdl, addr, 4, (u8 *)&le_tmp);
+ val = le32_to_cpu(le_tmp);
+ } else {
+ val = sd_read32(pintfhdl, addr, NULL);
+ }
+ return val;
+}
+
+void SdioLocalCmd52Write1Byte(struct adapter *padapter, u32 addr, u8 v)
+{
+ struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
+
+ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
+ sd_cmd52_write(pintfhdl, addr, 1, &v);
+}
+
+static void SdioLocalCmd52Write4Byte(struct adapter *padapter, u32 addr, u32 v)
+{
+ struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
+ __le32 le_tmp;
+
+ HalSdioGetCmdAddr8723BSdio(padapter, SDIO_LOCAL_DEVICE_ID, addr, &addr);
+ le_tmp = cpu_to_le32(v);
+ sd_cmd52_write(pintfhdl, addr, 4, (u8 *)&le_tmp);
+}
+
+static s32 ReadInterrupt8723BSdio(struct adapter *padapter, u32 *phisr)
+{
+ u32 hisr, himr;
+ u8 val8, hisr_len;
+
+
+ if (phisr == NULL)
+ return false;
+
+ himr = GET_HAL_DATA(padapter)->sdio_himr;
+
+ /* decide how many bytes need to be read */
+ hisr_len = 0;
+ while (himr) {
+ hisr_len++;
+ himr >>= 8;
+ }
+
+ hisr = 0;
+ while (hisr_len != 0) {
+ hisr_len--;
+ val8 = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR+hisr_len);
+ hisr |= (val8 << (8*hisr_len));
+ }
+
+ *phisr = hisr;
+
+ return true;
+}
+
+/* */
+/* Description: */
+/* Initialize SDIO Host Interrupt Mask configuration variables for future use. */
+/* */
+/* Assumption: */
+/* Using SDIO Local register ONLY for configuration. */
+/* */
+/* Created by Roger, 2011.02.11. */
+/* */
+void InitInterrupt8723BSdio(struct adapter *padapter)
+{
+ struct hal_com_data *pHalData;
+
+
+ pHalData = GET_HAL_DATA(padapter);
+ pHalData->sdio_himr = (u32)( \
+ SDIO_HIMR_RX_REQUEST_MSK |
+ SDIO_HIMR_AVAL_MSK |
+/* SDIO_HIMR_TXERR_MSK | */
+/* SDIO_HIMR_RXERR_MSK | */
+/* SDIO_HIMR_TXFOVW_MSK | */
+/* SDIO_HIMR_RXFOVW_MSK | */
+/* SDIO_HIMR_TXBCNOK_MSK | */
+/* SDIO_HIMR_TXBCNERR_MSK | */
+/* SDIO_HIMR_BCNERLY_INT_MSK | */
+/* SDIO_HIMR_C2HCMD_MSK | */
+/* SDIO_HIMR_HSISR_IND_MSK | */
+/* SDIO_HIMR_GTINT3_IND_MSK | */
+/* SDIO_HIMR_GTINT4_IND_MSK | */
+/* SDIO_HIMR_PSTIMEOUT_MSK | */
+/* SDIO_HIMR_OCPINT_MSK | */
+/* SDIO_HIMR_ATIMEND_MSK | */
+/* SDIO_HIMR_ATIMEND_E_MSK | */
+/* SDIO_HIMR_CTWEND_MSK | */
+ 0);
+}
+
+/* */
+/* Description: */
+/* Initialize System Host Interrupt Mask configuration variables for future use. */
+/* */
+/* Created by Roger, 2011.08.03. */
+/* */
+void InitSysInterrupt8723BSdio(struct adapter *padapter)
+{
+ struct hal_com_data *pHalData;
+
+
+ pHalData = GET_HAL_DATA(padapter);
+
+ pHalData->SysIntrMask = ( \
+/* HSIMR_GPIO12_0_INT_EN | */
+/* HSIMR_SPS_OCP_INT_EN | */
+/* HSIMR_RON_INT_EN | */
+/* HSIMR_PDNINT_EN | */
+/* HSIMR_GPIO9_INT_EN | */
+ 0);
+}
+
+#ifdef CONFIG_WOWLAN
+/* */
+/* Description: */
+/* Clear corresponding SDIO Host ISR interrupt service. */
+/* */
+/* Assumption: */
+/* Using SDIO Local register ONLY for configuration. */
+/* */
+/* Created by Roger, 2011.02.11. */
+/* */
+void ClearInterrupt8723BSdio(struct adapter *padapter)
+{
+ struct hal_com_data *pHalData;
+ u8 *clear;
+
+
+ if (true == padapter->bSurpriseRemoved)
+ return;
+
+ pHalData = GET_HAL_DATA(padapter);
+ clear = rtw_zmalloc(4);
+
+ /* Clear corresponding HISR Content if needed */
+ *(__le32 *)clear = cpu_to_le32(pHalData->sdio_hisr & MASK_SDIO_HISR_CLEAR);
+ if (*(__le32 *)clear) {
+ /* Perform write one clear operation */
+ sdio_local_write(padapter, SDIO_REG_HISR, 4, clear);
+ }
+
+ kfree(clear);
+}
+#endif
+
+/* */
+/* Description: */
+/* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */
+/* */
+/* Assumption: */
+/* 1. Using SDIO Local register ONLY for configuration. */
+/* 2. PASSIVE LEVEL */
+/* */
+/* Created by Roger, 2011.02.11. */
+/* */
+void EnableInterrupt8723BSdio(struct adapter *padapter)
+{
+ struct hal_com_data *pHalData;
+ __le32 himr;
+ u32 tmp;
+
+ pHalData = GET_HAL_DATA(padapter);
+
+ himr = cpu_to_le32(pHalData->sdio_himr);
+ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
+
+ RT_TRACE(
+ _module_hci_ops_c_,
+ _drv_notice_,
+ (
+ "%s: enable SDIO HIMR = 0x%08X\n",
+ __func__,
+ pHalData->sdio_himr
+ )
+ );
+
+ /* Update current system IMR settings */
+ tmp = rtw_read32(padapter, REG_HSIMR);
+ rtw_write32(padapter, REG_HSIMR, tmp | pHalData->SysIntrMask);
+
+ RT_TRACE(
+ _module_hci_ops_c_,
+ _drv_notice_,
+ (
+ "%s: enable HSIMR = 0x%08X\n",
+ __func__,
+ pHalData->SysIntrMask
+ )
+ );
+
+ /* */
+ /* <Roger_Notes> There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */
+ /* So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */
+ /* 2011.10.19. */
+ /* */
+ rtw_write8(padapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
+}
+
+/* */
+/* Description: */
+/* Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */
+/* */
+/* Assumption: */
+/* Using SDIO Local register ONLY for configuration. */
+/* */
+/* Created by Roger, 2011.02.11. */
+/* */
+void DisableInterrupt8723BSdio(struct adapter *padapter)
+{
+ __le32 himr;
+
+ himr = cpu_to_le32(SDIO_HIMR_DISABLED);
+ sdio_local_write(padapter, SDIO_REG_HIMR, 4, (u8 *)&himr);
+}
+
+/* */
+/* Description: */
+/* Using 0x100 to check the power status of FW. */
+/* */
+/* Assumption: */
+/* Using SDIO Local register ONLY for configuration. */
+/* */
+/* Created by Isaac, 2013.09.10. */
+/* */
+u8 CheckIPSStatus(struct adapter *padapter)
+{
+ DBG_871X(
+ "%s(): Read 0x100 = 0x%02x 0x86 = 0x%02x\n",
+ __func__,
+ rtw_read8(padapter, 0x100),
+ rtw_read8(padapter, 0x86)
+ );
+
+ if (rtw_read8(padapter, 0x100) == 0xEA)
+ return true;
+ else
+ return false;
+}
+
+static struct recv_buf *sd_recv_rxfifo(struct adapter *padapter, u32 size)
+{
+ u32 readsize, ret;
+ u8 *preadbuf;
+ struct recv_priv *precvpriv;
+ struct recv_buf *precvbuf;
+
+
+ /* Patch for some SDIO Host 4 bytes issue */
+ /* ex. RK3188 */
+ readsize = RND4(size);
+
+ /* 3 1. alloc recvbuf */
+ precvpriv = &padapter->recvpriv;
+ precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue);
+ if (precvbuf == NULL) {
+ DBG_871X_LEVEL(_drv_err_, "%s: alloc recvbuf FAIL!\n", __func__);
+ return NULL;
+ }
+
+ /* 3 2. alloc skb */
+ if (precvbuf->pskb == NULL) {
+ SIZE_PTR tmpaddr = 0;
+ SIZE_PTR alignment = 0;
+
+ precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
+
+ if (precvbuf->pskb) {
+ precvbuf->pskb->dev = padapter->pnetdev;
+
+ tmpaddr = (SIZE_PTR)precvbuf->pskb->data;
+ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
+ }
+
+ if (precvbuf->pskb == NULL) {
+ DBG_871X("%s: alloc_skb fail! read =%d\n", __func__, readsize);
+ return NULL;
+ }
+ }
+
+ /* 3 3. read data from rxfifo */
+ preadbuf = precvbuf->pskb->data;
+ ret = sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf);
+ if (ret == _FAIL) {
+ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __func__));
+ return NULL;
+ }
+
+
+ /* 3 4. init recvbuf */
+ precvbuf->len = size;
+ precvbuf->phead = precvbuf->pskb->head;
+ precvbuf->pdata = precvbuf->pskb->data;
+ skb_set_tail_pointer(precvbuf->pskb, size);
+ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
+ precvbuf->pend = skb_end_pointer(precvbuf->pskb);
+
+ return precvbuf;
+}
+
+static void sd_rxhandler(struct adapter *padapter, struct recv_buf *precvbuf)
+{
+ struct recv_priv *precvpriv;
+ struct __queue *ppending_queue;
+
+ precvpriv = &padapter->recvpriv;
+ ppending_queue = &precvpriv->recv_buf_pending_queue;
+
+ /* 3 1. enqueue recvbuf */
+ rtw_enqueue_recvbuf(precvbuf, ppending_queue);
+
+ /* 3 2. schedule tasklet */
+ tasklet_schedule(&precvpriv->recv_tasklet);
+}
+
+void sd_int_dpc(struct adapter *padapter)
+{
+ struct hal_com_data *phal;
+ struct dvobj_priv *dvobj;
+ struct intf_hdl *pintfhdl = &padapter->iopriv.intf;
+ struct pwrctrl_priv *pwrctl;
+
+
+ phal = GET_HAL_DATA(padapter);
+ dvobj = adapter_to_dvobj(padapter);
+ pwrctl = dvobj_to_pwrctl(dvobj);
+
+ if (phal->sdio_hisr & SDIO_HISR_AVAL) {
+ u8 freepage[4];
+
+ _sdio_local_read(padapter, SDIO_REG_FREE_TXPG, 4, freepage);
+ up(&(padapter->xmitpriv.xmit_sema));
+ }
+
+ if (phal->sdio_hisr & SDIO_HISR_CPWM1) {
+ struct reportpwrstate_parm report;
+
+ u8 bcancelled;
+ _cancel_timer(&(pwrctl->pwr_rpwm_timer), &bcancelled);
+
+ report.state = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HCPWM1_8723B);
+
+ /* cpwm_int_hdl(padapter, &report); */
+ _set_workitem(&(pwrctl->cpwm_event));
+ }
+
+ if (phal->sdio_hisr & SDIO_HISR_TXERR) {
+ u8 *status;
+ u32 addr;
+
+ status = rtw_malloc(4);
+ if (status) {
+ addr = REG_TXDMA_STATUS;
+ HalSdioGetCmdAddr8723BSdio(padapter, WLAN_IOREG_DEVICE_ID, addr, &addr);
+ _sd_read(pintfhdl, addr, 4, status);
+ _sd_write(pintfhdl, addr, 4, status);
+ DBG_8192C("%s: SDIO_HISR_TXERR (0x%08x)\n", __func__, le32_to_cpu(*(u32 *)status));
+ kfree(status);
+ } else {
+ DBG_8192C("%s: SDIO_HISR_TXERR, but can't allocate memory to read status!\n", __func__);
+ }
+ }
+
+ if (phal->sdio_hisr & SDIO_HISR_TXBCNOK) {
+ DBG_8192C("%s: SDIO_HISR_TXBCNOK\n", __func__);
+ }
+
+ if (phal->sdio_hisr & SDIO_HISR_TXBCNERR) {
+ DBG_8192C("%s: SDIO_HISR_TXBCNERR\n", __func__);
+ }
+#ifndef CONFIG_C2H_PACKET_EN
+ if (phal->sdio_hisr & SDIO_HISR_C2HCMD) {
+ struct c2h_evt_hdr_88xx *c2h_evt;
+
+ DBG_8192C("%s: C2H Command\n", __func__);
+ c2h_evt = (struct c2h_evt_hdr_88xx *)rtw_zmalloc(16);
+ if (c2h_evt != NULL) {
+ if (rtw_hal_c2h_evt_read(padapter, (u8 *)c2h_evt) == _SUCCESS) {
+ if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) {
+ /* Handle CCX report here */
+ rtw_hal_c2h_handler(padapter, (u8 *)c2h_evt);
+ kfree((u8 *)c2h_evt);
+ } else {
+ rtw_c2h_wk_cmd(padapter, (u8 *)c2h_evt);
+ }
+ }
+ } else {
+ /* Error handling for malloc fail */
+ if (rtw_cbuf_push(padapter->evtpriv.c2h_queue, (void *)NULL) != _SUCCESS)
+ DBG_871X("%s rtw_cbuf_push fail\n", __func__);
+ _set_workitem(&padapter->evtpriv.c2h_wk);
+ }
+ }
+#endif
+
+ if (phal->sdio_hisr & SDIO_HISR_RXFOVW) {
+ DBG_8192C("%s: Rx Overflow\n", __func__);
+ }
+
+ if (phal->sdio_hisr & SDIO_HISR_RXERR) {
+ DBG_8192C("%s: Rx Error\n", __func__);
+ }
+
+ if (phal->sdio_hisr & SDIO_HISR_RX_REQUEST) {
+ struct recv_buf *precvbuf;
+ int alloc_fail_time = 0;
+ u32 hisr;
+
+/* DBG_8192C("%s: RX Request, size =%d\n", __func__, phal->SdioRxFIFOSize); */
+ phal->sdio_hisr ^= SDIO_HISR_RX_REQUEST;
+ do {
+ phal->SdioRxFIFOSize = SdioLocalCmd52Read2Byte(padapter, SDIO_REG_RX0_REQ_LEN);
+ if (phal->SdioRxFIFOSize != 0) {
+ precvbuf = sd_recv_rxfifo(padapter, phal->SdioRxFIFOSize);
+ if (precvbuf)
+ sd_rxhandler(padapter, precvbuf);
+ else {
+ alloc_fail_time++;
+ DBG_871X("precvbuf is Null for %d times because alloc memory failed\n", alloc_fail_time);
+ if (alloc_fail_time >= 10)
+ break;
+ }
+ phal->SdioRxFIFOSize = 0;
+ } else
+ break;
+
+ hisr = 0;
+ ReadInterrupt8723BSdio(padapter, &hisr);
+ hisr &= SDIO_HISR_RX_REQUEST;
+ if (!hisr)
+ break;
+ } while (1);
+
+ if (alloc_fail_time == 10)
+ DBG_871X("exit because alloc memory failed more than 10 times\n");
+
+ }
+}
+
+void sd_int_hdl(struct adapter *padapter)
+{
+ struct hal_com_data *phal;
+
+
+ if (
+ (padapter->bDriverStopped == true) ||
+ (padapter->bSurpriseRemoved == true)
+ )
+ return;
+
+ phal = GET_HAL_DATA(padapter);
+
+ phal->sdio_hisr = 0;
+ ReadInterrupt8723BSdio(padapter, &phal->sdio_hisr);
+
+ if (phal->sdio_hisr & phal->sdio_himr) {
+ u32 v32;
+
+ phal->sdio_hisr &= phal->sdio_himr;
+
+ /* clear HISR */
+ v32 = phal->sdio_hisr & MASK_SDIO_HISR_CLEAR;
+ if (v32) {
+ SdioLocalCmd52Write4Byte(padapter, SDIO_REG_HISR, v32);
+ }
+
+ sd_int_dpc(padapter);
+ } else {
+ RT_TRACE(_module_hci_ops_c_, _drv_err_,
+ ("%s: HISR(0x%08x) and HIMR(0x%08x) not match!\n",
+ __func__, phal->sdio_hisr, phal->sdio_himr));
+ }
+}
+
+/* */
+/* Description: */
+/* Query SDIO Local register to query current the number of Free TxPacketBuffer page. */
+/* */
+/* Assumption: */
+/* 1. Running at PASSIVE_LEVEL */
+/* 2. RT_TX_SPINLOCK is NOT acquired. */
+/* */
+/* Created by Roger, 2011.01.28. */
+/* */
+u8 HalQueryTxBufferStatus8723BSdio(struct adapter *padapter)
+{
+ struct hal_com_data *phal;
+ u32 NumOfFreePage;
+ /* _irqL irql; */
+
+
+ phal = GET_HAL_DATA(padapter);
+
+ NumOfFreePage = SdioLocalCmd53Read4Byte(padapter, SDIO_REG_FREE_TXPG);
+
+ /* spin_lock_bh(&phal->SdioTxFIFOFreePageLock); */
+ memcpy(phal->SdioTxFIFOFreePage, &NumOfFreePage, 4);
+ RT_TRACE(_module_hci_ops_c_, _drv_notice_,
+ ("%s: Free page for HIQ(%#x), MIDQ(%#x), LOWQ(%#x), PUBQ(%#x)\n",
+ __func__,
+ phal->SdioTxFIFOFreePage[HI_QUEUE_IDX],
+ phal->SdioTxFIFOFreePage[MID_QUEUE_IDX],
+ phal->SdioTxFIFOFreePage[LOW_QUEUE_IDX],
+ phal->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]));
+ /* spin_unlock_bh(&phal->SdioTxFIFOFreePageLock); */
+
+ return true;
+}
+
+/* */
+/* Description: */
+/* Query SDIO Local register to get the current number of TX OQT Free Space. */
+/* */
+u8 HalQueryTxOQTBufferStatus8723BSdio(struct adapter *padapter)
+{
+ struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
+
+ pHalData->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_OQT_FREE_PG);
+ return true;
+}
+
+#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)
+u8 RecvOnePkt(struct adapter *padapter, u32 size)
+{
+ struct recv_buf *precvbuf;
+ struct dvobj_priv *psddev;
+ PSDIO_DATA psdio_data;
+ struct sdio_func *func;
+
+ u8 res = false;
+
+ DBG_871X("+%s: size: %d+\n", __func__, size);
+
+ if (padapter == NULL) {
+ DBG_871X(KERN_ERR "%s: padapter is NULL!\n", __func__);
+ return false;
+ }
+
+ psddev = adapter_to_dvobj(padapter);
+ psdio_data = &psddev->intf_data;
+ func = psdio_data->func;
+
+ if (size) {
+ sdio_claim_host(func);
+ precvbuf = sd_recv_rxfifo(padapter, size);
+
+ if (precvbuf) {
+ /* printk("Completed Recv One Pkt.\n"); */
+ sd_rxhandler(padapter, precvbuf);
+ res = true;
+ } else {
+ res = false;
+ }
+ sdio_release_host(func);
+ }
+ DBG_871X("-%s-\n", __func__);
+ return res;
+}
+#endif /* CONFIG_WOWLAN */