diff options
Diffstat (limited to 'drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c')
-rw-r--r-- | drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c | 2106 |
1 files changed, 2106 insertions, 0 deletions
diff --git a/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c new file mode 100644 index 000000000000..4312b452f689 --- /dev/null +++ b/drivers/net/wireless/nxp/mxm_wifiex/wlan_src/mlinux/moal_sdio_mmc.c @@ -0,0 +1,2106 @@ +/** @file moal_sdio_mmc.c + * + * @brief This file contains SDIO MMC IF (interface) module + * related functions. + * + * + * Copyright 2014-2020 NXP + * + * This software file (the File) is distributed by NXP + * under the terms of the GNU General Public License Version 2, June 1991 + * (the License). You may use, redistribute and/or modify the File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/**************************************************** +Change log: + 02/25/09: Initial creation - + This file supports SDIO MMC only +****************************************************/ + +#include <linux/firmware.h> + +#include "moal_sdio.h" + +/** define nxp vendor id */ +#define NXP_VENDOR_ID 0x02df + +/******************************************************** + Local Variables +********************************************************/ +/* moal interface ops */ +static moal_if_ops sdiommc_ops; +/******************************************************** + Global Variables +********************************************************/ + +#ifdef SD8887 +/** Device ID for SD8887 */ +#define SD_DEVICE_ID_8887 (0x9135) +#endif +#ifdef SD8897 +/** Device ID for SD8897 */ +#define SD_DEVICE_ID_8897 (0x912d) +#endif +#ifdef SD8977 +/** Device ID for SD8977 */ +#define SD_DEVICE_ID_8977 (0x9145) +#endif +#ifdef SD8978 +/** Device ID for SD8978 */ +#define SD_DEVICE_ID_8978 (0x9159) +#endif +#ifdef SD8997 +/** Device ID for SD8997 */ +#define SD_DEVICE_ID_8997 (0x9141) +#endif +#ifdef SD8987 +/** Device ID for SD8987 */ +#define SD_DEVICE_ID_8987 (0x9149) +#endif +#ifdef SD9098 +/** Device ID for SD9098 */ +#define SD_DEVICE_ID_9098_FN1 (0x914D) +/** Device ID for SD9098 */ +#define SD_DEVICE_ID_9098_FN2 (0x914E) +#endif +#ifdef SD9097 +/** Device ID for SD9097 */ +#define SD_DEVICE_ID_9097 (0x9155) +#endif +/** Device ID any */ +#ifndef SD_DEVICE_ANY +#define SD_DEVICE_ANY (0xffff) +#endif /* SD_DEVICE_ANY */ + +/** WLAN IDs */ +static const struct sdio_device_id wlan_ids[] = { +#ifdef SD8887 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8887)}, +#endif +#ifdef SD8897 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8897)}, +#endif +#ifdef SD8977 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8977)}, +#endif +#ifdef SD8978 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8978)}, +#endif +#ifdef SD8997 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8997)}, +#endif +#ifdef SD8987 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_8987)}, +#endif +#ifdef SD9098 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_9098_FN1)}, + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_9098_FN2)}, +#endif +#ifdef SD9097 + {SDIO_DEVICE(NXP_VENDOR_ID, SD_DEVICE_ID_9097)}, +#endif + {}, +}; + +int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id); +void woal_sdio_remove(struct sdio_func *func); +#ifdef SDIO +static void woal_sdiommc_reg_dbg(pmoal_handle handle); +#endif + +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER +int woal_sdio_suspend(struct device *dev); +int woal_sdio_resume(struct device *dev); + +static struct dev_pm_ops wlan_sdio_pm_ops = { + .suspend = woal_sdio_suspend, + .resume = woal_sdio_resume, +}; + +void woal_sdio_shutdown(struct device *dev); +#endif +#endif + +// clang-format off +static struct sdio_driver REFDATA wlan_sdio = { + .name = "wlan_sdio", + .id_table = wlan_ids, + .probe = woal_sdio_probe, + .remove = woal_sdio_remove, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) + .drv = { + .owner = THIS_MODULE, +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER + .pm = &wlan_sdio_pm_ops, + .shutdown = woal_sdio_shutdown, +#endif +#endif + + } +#else +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER + .drv = { + .pm = &wlan_sdio_pm_ops, + .shutdown = woal_sdio_shutdown, + } +#endif +#endif +#endif +}; +// clang-format on + +/******************************************************** + Local Functions +********************************************************/ +static void woal_sdiommc_dump_fw_info(moal_handle *phandle); + +/** @brief This function dump the sdio register + * + * @param handle A Pointer to the moal_handle structure + * @return N/A + */ +void woal_dump_sdio_reg(moal_handle *handle) +{ + int ret = 0; + t_u8 data, i; + int fun0_reg[] = {0x05, 0x04}; + t_u8 array_size = 0; +#ifdef SD8897 + int fun1_reg_8897[] = {0x03, 0x04, 0x05, 0x06, 0x07, 0xC0, 0xC1}; +#endif + int fun1_reg_other[] = {0x03, 0x04, 0x05, 0x60, 0x61}; + int *fun1_reg = NULL; + + for (i = 0; i < ARRAY_SIZE(fun0_reg); i++) { + data = sdio_f0_readb( + ((struct sdio_mmc_card *)handle->card)->func, + fun0_reg[i], &ret); + PRINTM(MMSG, "fun0: reg 0x%02x=0x%02x ret=%d\n", fun0_reg[i], + data, ret); + } + +#ifdef SD8897 + if (IS_SD8897(handle->card_type)) { + fun1_reg = fun1_reg_8897; + array_size = sizeof(fun1_reg_8897) / sizeof(int); + } else { +#endif + fun1_reg = fun1_reg_other; + array_size = sizeof(fun1_reg_other) / sizeof(int); +#ifdef SD8897 + } +#endif + for (i = 0; i < array_size; i++) { + data = sdio_readb(((struct sdio_mmc_card *)handle->card)->func, + fun1_reg[i], &ret); + PRINTM(MMSG, "fun1: reg 0x%02x=0x%02x ret=%d\n", fun1_reg[i], + data, ret); + } + return; +} +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief This function handles the interrupt. + * + * @param func A pointer to the sdio_func structure + * @return N/A + */ +static void woal_sdio_interrupt(struct sdio_func *func) +{ + moal_handle *handle; + struct sdio_mmc_card *card; + + ENTER(); + + card = sdio_get_drvdata(func); + if (!card || !card->handle) { + PRINTM(MINFO, + "sdio_mmc_interrupt(func = %p) card or handle is NULL, card=%p\n", + func, card); + LEAVE(); + return; + } + handle = card->handle; + if (handle->surprise_removed == MTRUE) { + LEAVE(); + return; + } + handle->main_state = MOAL_RECV_INT; + PRINTM(MINFO, "*** IN SDIO IRQ ***\n"); + PRINTM(MINTR, "*\n"); + + /* call mlan_interrupt to read int status */ + mlan_interrupt(0, handle->pmlan_adapter); +#ifdef SDIO_SUSPEND_RESUME + if (handle->is_suspended) { + PRINTM(MINTR, "Receive interrupt in hs_suspended\n"); + LEAVE(); + return; + } +#endif + handle->main_state = MOAL_START_MAIN_PROCESS; + /* Call MLAN main process */ + mlan_main_process(handle->pmlan_adapter); + handle->main_state = MOAL_END_MAIN_PROCESS; + LEAVE(); +} + +/** @brief This function updates the card types + * + * @param handle A Pointer to the moal_handle structure + * @param card A Pointer to card + * + * @return N/A + */ +static t_u16 woal_update_card_type(t_void *card) +{ + struct sdio_mmc_card *cardp_sd = (struct sdio_mmc_card *)card; + t_u16 card_type = 0; + + /* Update card type */ +#ifdef SD8887 + if (cardp_sd->func->device == SD_DEVICE_ID_8887) { + card_type = CARD_TYPE_SD8887; + moal_memcpy_ext(NULL, driver_version, CARD_SD8887, + strlen(CARD_SD8887), strlen(driver_version)); + moal_memcpy_ext( + NULL, + driver_version + strlen(INTF_CARDTYPE) + + strlen(KERN_VERSION), + V15, strlen(V15), + strlen(driver_version) - + (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); + } +#endif +#ifdef SD8897 + if (cardp_sd->func->device == SD_DEVICE_ID_8897) { + card_type = CARD_TYPE_SD8897; + moal_memcpy_ext(NULL, driver_version, CARD_SD8897, + strlen(CARD_SD8897), strlen(driver_version)); + moal_memcpy_ext( + NULL, + driver_version + strlen(INTF_CARDTYPE) + + strlen(KERN_VERSION), + V15, strlen(V15), + strlen(driver_version) - + (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); + } +#endif +#ifdef SD8977 + if (cardp_sd->func->device == SD_DEVICE_ID_8977) { + card_type = CARD_TYPE_SD8977; + moal_memcpy_ext(NULL, driver_version, CARD_SD8977, + strlen(CARD_SD8977), strlen(driver_version)); + moal_memcpy_ext( + NULL, + driver_version + strlen(INTF_CARDTYPE) + + strlen(KERN_VERSION), + V16, strlen(V16), + strlen(driver_version) - + (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); + } +#endif +#ifdef SD8978 + if (cardp_sd->func->device == SD_DEVICE_ID_8978) { + card_type = CARD_TYPE_SD8978; + moal_memcpy_ext(NULL, driver_version, CARD_SD8978, + strlen(CARD_SD8978), strlen(driver_version)); + moal_memcpy_ext( + NULL, + driver_version + strlen(INTF_CARDTYPE) + + strlen(KERN_VERSION), + V16, strlen(V16), + strlen(driver_version) - + (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); + } +#endif +#ifdef SD8997 + if (cardp_sd->func->device == SD_DEVICE_ID_8997) { + card_type = CARD_TYPE_SD8997; + moal_memcpy_ext(NULL, driver_version, CARD_SD8997, + strlen(CARD_SD8997), strlen(driver_version)); + moal_memcpy_ext( + NULL, + driver_version + strlen(INTF_CARDTYPE) + + strlen(KERN_VERSION), + V16, strlen(V16), + strlen(driver_version) - + (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); + } +#endif +#ifdef SD8987 + if (cardp_sd->func->device == SD_DEVICE_ID_8987) { + card_type = CARD_TYPE_SD8987; + moal_memcpy_ext(NULL, driver_version, CARD_SD8987, + strlen(CARD_SD8987), strlen(driver_version)); + moal_memcpy_ext( + NULL, + driver_version + strlen(INTF_CARDTYPE) + + strlen(KERN_VERSION), + V16, strlen(V16), + strlen(driver_version) - + (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); + } +#endif +#ifdef SD9097 + if (cardp_sd->func->device == SD_DEVICE_ID_9097) { + card_type = CARD_TYPE_SD9097; + moal_memcpy_ext(NULL, driver_version, CARD_SD9097, + strlen(CARD_SD9097), strlen(driver_version)); + moal_memcpy_ext( + NULL, + driver_version + strlen(INTF_CARDTYPE) + + strlen(KERN_VERSION), + V17, strlen(V17), + strlen(driver_version) - + (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); + } +#endif +#ifdef SD9098 + if (cardp_sd->func->device == SD_DEVICE_ID_9098_FN1 || + cardp_sd->func->device == SD_DEVICE_ID_9098_FN2) { + card_type = CARD_TYPE_SD9098; + moal_memcpy_ext(NULL, driver_version, CARD_SD9098, + strlen(CARD_SD9098), strlen(driver_version)); + moal_memcpy_ext( + NULL, + driver_version + strlen(INTF_CARDTYPE) + + strlen(KERN_VERSION), + V17, strlen(V17), + strlen(driver_version) - + (strlen(INTF_CARDTYPE) + strlen(KERN_VERSION))); + } +#endif + return card_type; +} + +/** @brief This function handles client driver probe. + * + * @param func A pointer to sdio_func structure. + * @param id A pointer to sdio_device_id structure. + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE/error code + */ +int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret = MLAN_STATUS_SUCCESS; + struct sdio_mmc_card *card = NULL; + t_u16 card_type = 0; + + ENTER(); + + PRINTM(MMSG, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", + func->vendor, func->device, func->class, func->num); + + card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); + if (!card) { + PRINTM(MFATAL, + "Failed to allocate memory in probe function!\n"); + LEAVE(); + return -ENOMEM; + } + + card->func = func; + +#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE + /* The byte mode patch is available in kernel MMC driver + * which fixes one issue in MP-A transfer. + * bit1: use func->cur_blksize for byte mode + */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) + /* wait for chip fully wake up */ + if (!func->enable_timeout) + func->enable_timeout = 200; +#endif + sdio_claim_host(func); + ret = sdio_enable_func(func); + if (ret) { + sdio_release_host(func); + PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret); + ret = -EIO; + goto err; + } + sdio_release_host(func); + + card_type = woal_update_card_type(card); + if (!card_type) { + PRINTM(MERROR, "sdmmc probe: woal_update_card_type() failed\n"); + ret = MLAN_STATUS_FAILURE; + goto err; + } + + if (NULL == + woal_add_card(card, &card->func->dev, &sdiommc_ops, card_type)) { + PRINTM(MERROR, "woal_add_card failed\n"); + ret = MLAN_STATUS_FAILURE; + goto err; + } + + LEAVE(); + return ret; +err: + kfree(card); + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + + LEAVE(); + return ret; +} + +/** @brief This function handles client driver remove. + * + * @param func A pointer to sdio_func structure. + * @return N/A + */ +void woal_sdio_remove(struct sdio_func *func) +{ + struct sdio_mmc_card *card; + + ENTER(); + + if (func) { + PRINTM(MINFO, "SDIO func=%d\n", func->num); + card = sdio_get_drvdata(func); + if (card) { + woal_remove_card(card); + kfree(card); + } + } + + LEAVE(); +} + +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER +#ifdef MMC_PM_FUNC_SUSPENDED +/** @brief This function tells lower driver that WLAN is suspended + * + * @param handle A Pointer to the moal_handle structure + * @return N/A + */ +void woal_wlan_is_suspended(moal_handle *handle) +{ + ENTER(); + if (handle->suspend_notify_req == MTRUE) { + handle->is_suspended = MTRUE; + sdio_func_suspended( + ((struct sdio_mmc_card *)handle->card)->func); + } + LEAVE(); +} +#endif + +#define SHUTDOWN_HOST_SLEEP_DEF_GAP 100 +#define SHUTDOWN_HOST_SLEEP_DEF_GPIO 0x3 +#define SHUTDOWN_HOST_SLEEP_DEF_COND 0x0 + +/** @brief This function handles client driver shutdown + * + * @param dev A pointer to device structure + * @return N/A + */ +void woal_sdio_shutdown(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + moal_handle *handle = NULL; + struct sdio_mmc_card *cardp; + mlan_ds_ps_info pm_info; + int timeout = 0; + int i, retry_num = 8; + + ENTER(); + PRINTM(MCMND, "<--- Enter woal_sdio_shutdown --->\n"); + cardp = sdio_get_drvdata(func); + if (!cardp || !cardp->handle) { + PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); + LEAVE(); + return; + } + handle = cardp->handle; + for (i = 0; i < handle->priv_num; i++) + netif_device_detach(handle->priv[i]->netdev); + + if (moal_extflg_isset(handle, EXT_SHUTDOWN_HS)) { + handle->shutdown_hs_in_process = MTRUE; + memset(&pm_info, 0, sizeof(pm_info)); + for (i = 0; i < retry_num; i++) { + if (MLAN_STATUS_SUCCESS == + woal_get_pm_info(woal_get_priv(handle, + MLAN_BSS_ROLE_ANY), + &pm_info)) { + if (pm_info.is_suspend_allowed == MTRUE) + break; + else + PRINTM(MMSG, + "Shutdown not allowed and retry again\n"); + } + woal_sched_timeout(100); + } + if (pm_info.is_suspend_allowed == MFALSE) { + PRINTM(MMSG, "Shutdown not allowed\n"); + goto done; + } + woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY)); + + timeout = wait_event_interruptible_timeout( + handle->hs_activate_wait_q, + handle->hs_activate_wait_q_woken, HS_ACTIVE_TIMEOUT); + if (handle->hs_activated == MTRUE) + PRINTM(MMSG, "HS actived in shutdown\n"); + else + PRINTM(MMSG, "Fail to enable HS in shutdown\n"); + } else { + for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { + if (handle->priv[i]) { + if (handle->priv[i]->media_connected == MTRUE +#ifdef UAP_SUPPORT + || (GET_BSS_ROLE(handle->priv[i]) == + MLAN_BSS_ROLE_UAP) +#endif + ) { + PRINTM(MIOCTL, + "disconnect on suspend\n"); + woal_disconnect(handle->priv[i], + MOAL_NO_WAIT, NULL, + DEF_DEAUTH_REASON_CODE); + } + } + } + } + +done: + PRINTM(MCMND, "<--- Leave woal_sdio_shutdown --->\n"); + LEAVE(); + return; +} + +/** @brief This function handles client driver suspend + * + * @param dev A pointer to device structure + * @return MLAN_STATUS_SUCCESS or error code + */ +int woal_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + mmc_pm_flag_t pm_flags = 0; + moal_handle *handle = NULL; + struct sdio_mmc_card *cardp; + int i, retry_num = 8; + int ret = MLAN_STATUS_SUCCESS; + int hs_actived = 0; + mlan_ds_ps_info pm_info; + + ENTER(); + PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n"); + pm_flags = sdio_get_host_pm_caps(func); + PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), + pm_flags); + cardp = sdio_get_drvdata(func); + if (!cardp || !cardp->handle) { + PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + + handle = cardp->handle; + + if (moal_extflg_isset(handle, EXT_PM_KEEP_POWER) && + !(pm_flags & MMC_PM_KEEP_POWER)) { + PRINTM(MERROR, + "%s: cannot remain alive while host is suspended\n", + sdio_func_id(func)); + LEAVE(); + return -ENOSYS; + } + if (handle->is_suspended == MTRUE) { + PRINTM(MWARN, "Device already suspended\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + if (handle->fw_dump) { + PRINTM(MMSG, "suspend not allowed while FW dump!"); + ret = -EBUSY; + goto done; + } +#ifdef STA_SUPPORT + for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { + if (handle->priv[i] && + (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) + woal_cancel_scan(handle->priv[i], MOAL_IOCTL_WAIT); + } +#endif + handle->suspend_fail = MFALSE; + memset(&pm_info, 0, sizeof(pm_info)); + for (i = 0; i < retry_num; i++) { + if (MLAN_STATUS_SUCCESS == + woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), + &pm_info)) { + if (pm_info.is_suspend_allowed == MTRUE) + break; + else + PRINTM(MMSG, + "Suspend not allowed and retry again\n"); + } + woal_sched_timeout(100); + } + if (pm_info.is_suspend_allowed == MFALSE) { + PRINTM(MMSG, "Suspend not allowed\n"); + ret = -EBUSY; + goto done; + } + + for (i = 0; i < handle->priv_num; i++) + netif_device_detach(handle->priv[i]->netdev); + + if (moal_extflg_isset(handle, EXT_PM_KEEP_POWER)) { + /* Enable the Host Sleep */ +#ifdef MMC_PM_FUNC_SUSPENDED + handle->suspend_notify_req = MTRUE; +#endif + hs_actived = woal_enable_hs( + woal_get_priv(handle, MLAN_BSS_ROLE_ANY)); +#ifdef MMC_PM_FUNC_SUSPENDED + handle->suspend_notify_req = MFALSE; +#endif + if (hs_actived) { +#ifdef MMC_PM_SKIP_RESUME_PROBE + PRINTM(MCMND, + "suspend with MMC_PM_KEEP_POWER and MMC_PM_SKIP_RESUME_PROBE\n"); + ret = sdio_set_host_pm_flags( + func, + MMC_PM_KEEP_POWER | MMC_PM_SKIP_RESUME_PROBE); +#else + PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); +#endif + } else { + PRINTM(MMSG, "HS not actived, suspend fail!"); + handle->suspend_fail = MTRUE; + for (i = 0; i < handle->priv_num; i++) + netif_device_attach(handle->priv[i]->netdev); + ret = -EBUSY; + goto done; + } + } + + /* Indicate device suspended */ + handle->is_suspended = MTRUE; +done: + PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n"); + LEAVE(); + return ret; +} + +/** @brief This function handles client driver resume + * + * @param dev A pointer to device structure + * @return MLAN_STATUS_SUCCESS + */ +int woal_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + mmc_pm_flag_t pm_flags = 0; + moal_handle *handle = NULL; + struct sdio_mmc_card *cardp; + int i; + + ENTER(); + PRINTM(MCMND, "<--- Enter woal_sdio_resume --->\n"); + pm_flags = sdio_get_host_pm_caps(func); + PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func), + pm_flags); + cardp = sdio_get_drvdata(func); + if (!cardp || !cardp->handle) { + PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + handle = cardp->handle; + + if (handle->is_suspended == MFALSE) { + PRINTM(MWARN, "Device already resumed\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + handle->is_suspended = MFALSE; + if (woal_check_driver_status(handle)) { + PRINTM(MERROR, "Resuem, device is in hang state\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + for (i = 0; i < handle->priv_num; i++) + netif_device_attach(handle->priv[i]->netdev); + + /* Disable Host Sleep */ + woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT); + PRINTM(MCMND, "<--- Leave woal_sdio_resume --->\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} +#endif +#endif /* SDIO_SUSPEND_RESUME */ + +/** + * @brief This function writes data into card register + * + * @param handle A Pointer to the moal_handle structure + * @param reg Register offset + * @param data Value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status woal_sdiommc_write_reg(moal_handle *handle, t_u32 reg, + t_u32 data) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); + sdio_writeb(((struct sdio_mmc_card *)handle->card)->func, (t_u8)data, + reg, (int *)&ret); + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); + return ret; +} + +/** + * @brief This function reads data from card register + * + * @param handle A Pointer to the moal_handle structure + * @param reg Register offset + * @param data Value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status woal_sdiommc_read_reg(moal_handle *handle, t_u32 reg, + t_u32 *data) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 val; + sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); + val = sdio_readb(((struct sdio_mmc_card *)handle->card)->func, reg, + (int *)&ret); + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); + *data = val; + + return ret; +} + +/** + * @brief This function writes data into card register + * + * @param handle A Pointer to the moal_handle structure + * @param reg Register offset + * @param data Value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status woal_sdio_writeb(moal_handle *handle, t_u32 reg, t_u8 data) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); + sdio_writeb(((struct sdio_mmc_card *)handle->card)->func, (t_u8)data, + reg, (int *)&ret); + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); + return ret; +} + +/** + * @brief This function reads data from card register + * + * @param handle A Pointer to the moal_handle structure + * @param reg Register offset + * @param data Value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status woal_sdio_readb(moal_handle *handle, t_u32 reg, t_u8 *data) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 val; + sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); + val = sdio_readb(((struct sdio_mmc_card *)handle->card)->func, reg, + (int *)&ret); + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); + *data = val; + + return ret; +} + +/** + * @brief This function reads data from card register FN0 + * + * @param handle A Pointer to the moal_handle structure + * @param reg Register offset + * @param data Value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status woal_sdio_f0_readb(moal_handle *handle, t_u32 reg, t_u8 *data) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 val; + sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); + val = sdio_f0_readb(((struct sdio_mmc_card *)handle->card)->func, reg, + (int *)&ret); + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); + *data = val; + + return ret; +} + +/** + * @brief This function use SG mode to read/write data into card memory + * + * @param handle A Pointer to the moal_handle structure + * @param pmbuf_list Pointer to a linked list of mlan_buffer structure + * @param port Port + * @param write write flag + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status woal_sdio_rw_mb(moal_handle *handle, pmlan_buffer pmbuf_list, + t_u32 port, t_u8 write) +{ + struct scatterlist sg_list[SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX]; + int num_sg = pmbuf_list->use_count; + int i = 0; + mlan_buffer *pmbuf = NULL; + struct mmc_request mmc_req; + struct mmc_command mmc_cmd; + struct mmc_data mmc_dat; + struct sdio_func *func = ((struct sdio_mmc_card *)handle->card)->func; + t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK); + t_u32 blkcnt = pmbuf_list->data_len / MLAN_SDIO_BLOCK_SIZE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) + int status; +#endif + + if (num_sg > SDIO_MP_AGGR_DEF_PKT_LIMIT_MAX) { + PRINTM(MERROR, "ERROR: num_sg=%d", num_sg); + return MLAN_STATUS_FAILURE; + } + sg_init_table(sg_list, num_sg); + pmbuf = pmbuf_list->pnext; + for (i = 0; i < num_sg; i++) { + if (pmbuf == pmbuf_list) + break; + sg_set_buf(&sg_list[i], pmbuf->pbuf + pmbuf->data_offset, + pmbuf->data_len); + pmbuf = pmbuf->pnext; + } + memset(&mmc_req, 0, sizeof(struct mmc_request)); + memset(&mmc_cmd, 0, sizeof(struct mmc_command)); + memset(&mmc_dat, 0, sizeof(struct mmc_data)); + + mmc_dat.sg = sg_list; + mmc_dat.sg_len = num_sg; + mmc_dat.blksz = MLAN_SDIO_BLOCK_SIZE; + mmc_dat.blocks = blkcnt; + mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + + mmc_cmd.opcode = SD_IO_RW_EXTENDED; + mmc_cmd.arg = write ? 1 << 31 : 0; + mmc_cmd.arg |= (func->num & 0x7) << 28; + mmc_cmd.arg |= 1 << 27; /* block basic */ + mmc_cmd.arg |= 0; /* fix address */ + mmc_cmd.arg |= (ioport & 0x1FFFF) << 9; + mmc_cmd.arg |= blkcnt & 0x1FF; + mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; + + mmc_req.cmd = &mmc_cmd; + mmc_req.data = &mmc_dat; + + sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); + mmc_set_data_timeout( + &mmc_dat, ((struct sdio_mmc_card *)handle->card)->func->card); + mmc_wait_for_req( + ((struct sdio_mmc_card *)handle->card)->func->card->host, + &mmc_req); + + if (mmc_cmd.error || mmc_dat.error) { + PRINTM(MERROR, "CMD53 %s cmd_error = %d data_error=%d\n", + write ? "write" : "read", mmc_cmd.error, mmc_dat.error); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) + /* issue abort cmd52 command through F0*/ + sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func, + 0x01, SDIO_CCCR_ABORT, &status); +#endif + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); + return MLAN_STATUS_FAILURE; + } + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function writes multiple bytes into card memory + * + * @param handle A Pointer to the moal_handle structure + * @param pmbuf Pointer to mlan_buffer structure + * @param port Port + * @param timeout Time out value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status woal_sdiommc_write_data_sync(moal_handle *handle, + mlan_buffer *pmbuf, t_u32 port, + t_u32 timeout) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 *buffer = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset); + t_u8 blkmode = + (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1; + t_u32 blkcnt = (blkmode == BLOCK_MODE) ? + (pmbuf->data_len / MLAN_SDIO_BLOCK_SIZE) : + pmbuf->data_len; + t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK); + int status = 0; + if (pmbuf->use_count > 1) + return woal_sdio_rw_mb(handle, pmbuf, port, MTRUE); +#ifdef SDIO_MMC_DEBUG + handle->cmd53w = 1; +#endif + sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); + status = sdio_writesb(((struct sdio_mmc_card *)handle->card)->func, + ioport, buffer, blkcnt * blksz); + if (!status) + ret = MLAN_STATUS_SUCCESS; + else { + PRINTM(MERROR, "cmd53 write error=%d\n", status); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) + /* issue abort cmd52 command through F0*/ + sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func, + 0x01, SDIO_CCCR_ABORT, &status); +#endif + } + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); +#ifdef SDIO_MMC_DEBUG + handle->cmd53w = 2; +#endif + return ret; +} + +/** + * @brief This function reads multiple bytes from card memory + * + * @param handle A Pointer to the moal_handle structure + * @param pmbuf Pointer to mlan_buffer structure + * @param port Port + * @param timeout Time out value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status woal_sdiommc_read_data_sync(moal_handle *handle, + mlan_buffer *pmbuf, t_u32 port, + t_u32 timeout) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 *buffer = (t_u8 *)(pmbuf->pbuf + pmbuf->data_offset); + t_u8 blkmode = + (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1; + t_u32 blkcnt = (blkmode == BLOCK_MODE) ? + (pmbuf->data_len / MLAN_SDIO_BLOCK_SIZE) : + pmbuf->data_len; + t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK); + int status = 0; + if (pmbuf->use_count > 1) + return woal_sdio_rw_mb(handle, pmbuf, port, MFALSE); +#ifdef SDIO_MMC_DEBUG + handle->cmd53r = 1; +#endif + sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); + status = sdio_readsb(((struct sdio_mmc_card *)handle->card)->func, + buffer, ioport, blkcnt * blksz); + if (!status) { + ret = MLAN_STATUS_SUCCESS; + } else { + PRINTM(MERROR, "cmd53 read error=%d\n", status); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) + /* issue abort cmd52 command through F0*/ + sdio_f0_writeb(((struct sdio_mmc_card *)handle->card)->func, + 0x01, SDIO_CCCR_ABORT, &status); +#endif + } + sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); +#ifdef SDIO_MMC_DEBUG + handle->cmd53r = 2; +#endif + return ret; +} + +/** + * @brief This function registers the IF module in bus driver + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status woal_sdiommc_bus_register(void) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + + ENTER(); + + /* SDIO Driver Registration */ + if (sdio_register_driver(&wlan_sdio)) { + PRINTM(MFATAL, "SDIO Driver Registration Failed \n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + LEAVE(); + return ret; +} + +/** + * @brief This function de-registers the IF module in bus driver + * + * @return N/A + */ +void woal_sdiommc_bus_unregister(void) +{ + ENTER(); + + /* SDIO Driver Unregistration */ + sdio_unregister_driver(&wlan_sdio); + + LEAVE(); +} + +/** + * @brief This function de-registers the device + * + * @param handle A pointer to moal_handle structure + * @return N/A + */ +static void woal_sdiommc_unregister_dev(moal_handle *handle) +{ + ENTER(); + if (handle->card) { + struct sdio_mmc_card *card = handle->card; + /* Release the SDIO IRQ */ + sdio_claim_host(card->func); + sdio_release_irq(card->func); + sdio_disable_func(card->func); + sdio_release_host(card->func); + + sdio_set_drvdata(card->func, NULL); + + PRINTM(MWARN, "Making the sdio dev card as NULL\n"); + card->handle = NULL; + } + + LEAVE(); +} + +/** + * @brief This function registers the device + * + * @param handle A pointer to moal_handle structure + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status woal_sdiommc_register_dev(moal_handle *handle) +{ + int ret = MLAN_STATUS_SUCCESS; + struct sdio_mmc_card *card = handle->card; + struct sdio_func *func; + + ENTER(); + + /* save adapter pointer in card */ + card->handle = handle; + func = card->func; + sdio_claim_host(func); + /* Request the SDIO IRQ */ + ret = sdio_claim_irq(func, woal_sdio_interrupt); + if (ret) { + PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret); + goto release_host; + } + + /* Set block size */ + ret = sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE); + if (ret) { + PRINTM(MERROR, + "sdio_set_block_seize(): cannot set SDIO block size\n"); + ret = MLAN_STATUS_FAILURE; + goto release_irq; + } + + sdio_release_host(func); + sdio_set_drvdata(func, card); + + LEAVE(); + return MLAN_STATUS_SUCCESS; + +release_irq: + sdio_release_irq(func); +release_host: + sdio_release_host(func); + handle->card = NULL; + + LEAVE(); + return MLAN_STATUS_FAILURE; +} + +/** + * @brief This function set bus clock on/off + * + * @param handle A pointer to moal_handle structure + * @param option TRUE--on , FALSE--off + * @return MLAN_STATUS_SUCCESS + */ +int woal_sdio_set_bus_clock(moal_handle *handle, t_u8 option) +{ + struct sdio_mmc_card *cardp = (struct sdio_mmc_card *)handle->card; + struct mmc_host *host = cardp->func->card->host; + + ENTER(); + if (option == MTRUE) { + /* restore value if non-zero */ + if (cardp->host_clock) + host->ios.clock = cardp->host_clock; + } else { + /* backup value if non-zero, then clear */ + if (host->ios.clock) + cardp->host_clock = host->ios.clock; + host->ios.clock = 0; + } + + host->ops->set_ios(host, &host->ios); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function updates card reg based on the Cmd52 value in dev + * structure + * + * @param handle A pointer to moal_handle structure + * @param func A pointer to store func variable + * @param reg A pointer to store reg variable + * @param val A pointer to store val variable + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +int woal_sdio_read_write_cmd52(moal_handle *handle, int func, int reg, int val) +{ + int ret = MLAN_STATUS_SUCCESS; + struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card; + + ENTER(); + /* Save current func and reg for read */ + handle->cmd52_func = func; + handle->cmd52_reg = reg; + sdio_claim_host(card->func); + if (val >= 0) { + /* Perform actual write only if val is provided */ + if (func) + sdio_writeb(card->func, val, reg, &ret); + else + sdio_f0_writeb(card->func, val, reg, &ret); + if (ret) { + PRINTM(MERROR, + "Cannot write value (0x%x) to func %d reg 0x%x\n", + val, func, reg); + } else { + PRINTM(MMSG, "write value (0x%x) to func %d reg 0x%x\n", + (u8)val, func, reg); + handle->cmd52_val = val; + } + } else { + if (func) + val = sdio_readb(card->func, reg, &ret); + else + val = sdio_f0_readb(card->func, reg, &ret); + if (ret) { + PRINTM(MERROR, + "Cannot read value from func %d reg 0x%x\n", + func, reg); + } else { + PRINTM(MMSG, + "read value (0x%x) from func %d reg 0x%x\n", + (u8)val, func, reg); + handle->cmd52_val = val; + } + } + sdio_release_host(card->func); + LEAVE(); + return ret; +} + +/** + * @brief This function check if this is second mac + * + * @param handle A pointer to moal_handle structure + * @return MTRUE/MFALSE + * + */ +static t_u8 woal_sdiommc_is_second_mac(moal_handle *handle) +{ +#ifdef SD9098 + struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card; + if (card->func->device == SD_DEVICE_ID_9098_FN2) + return MTRUE; +#endif + return MFALSE; +} + +static mlan_status woal_sdiommc_get_fw_name(moal_handle *handle) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; +#ifdef SD9098 + struct sdio_mmc_card *card = (struct sdio_mmc_card *)handle->card; +#endif + t_u32 revision_id = 0; + t_u32 rev_id_reg = handle->card_info->rev_id_reg; + +#if defined(SD8987) || defined(SD8997) || defined(SD9098) || \ + defined(SD9097) || defined(SD8978) + t_u32 magic_reg = handle->card_info->magic_reg; + t_u32 magic = 0; + t_u32 host_strap_reg = handle->card_info->host_strap_reg; + t_u32 strap = 0; +#endif + + ENTER(); + + if (handle->params.fw_name) + goto done; + /** Revision ID register */ + woal_sdiommc_read_reg(handle, rev_id_reg, &revision_id); + PRINTM(MCMND, "revision_id=0x%x\n", revision_id); + +#if defined(SD8987) || defined(SD8997) || defined(SD9098) || \ + defined(SD9097) || defined(SD8978) + /** Revision ID register */ + woal_sdiommc_read_reg(handle, magic_reg, &magic); + /** Revision ID register */ + woal_sdiommc_read_reg(handle, host_strap_reg, &strap); + strap &= 0x1; + magic &= 0xFF; + /* 1 = SDSD, 0 --SD UART */ + PRINTM(MCMND, "magic=0x%x strap=0x%x\n", magic, strap); +#endif +#if defined(SD8977) + if (IS_SD8977(handle->card_type)) { + switch (revision_id) { + case SD8977_V0: + strcpy(handle->card_info->fw_name, SD8977_V0_FW_NAME); + strcpy(handle->card_info->fw_name_wlan, + SD8977_WLAN_V0_FW_NAME); + break; + case SD8977_V1: + strcpy(handle->card_info->fw_name, SD8977_V1_FW_NAME); + strcpy(handle->card_info->fw_name_wlan, + SD8977_WLAN_V1_FW_NAME); + break; + case SD8977_V2: + strcpy(handle->card_info->fw_name, SD8977_V2_FW_NAME); + strcpy(handle->card_info->fw_name_wlan, + SD8977_WLAN_V2_FW_NAME); + break; + default: + break; + } + } +#endif +#if defined(SD8887) + if (IS_SD8887(handle->card_type)) { + /* Check revision ID */ + switch (revision_id) { + case SD8887_A0: + strcpy(handle->card_info->fw_name, SD8887_A0_FW_NAME); + strcpy(handle->card_info->fw_name_wlan, + SD8887_WLAN_A0_FW_NAME); + break; + case SD8887_A2: + strcpy(handle->card_info->fw_name, SD8887_A2_FW_NAME); + strcpy(handle->card_info->fw_name_wlan, + SD8887_WLAN_A2_FW_NAME); + break; + default: + break; + } + } +#endif + +#ifdef SD8997 + if (IS_SD8997(handle->card_type)) { + if (magic == CHIP_MAGIC_VALUE) { + if (strap == CARD_TYPE_SD_UART) + strcpy(handle->card_info->fw_name, + SDUART8997_DEFAULT_COMBO_FW_NAME); + else + strcpy(handle->card_info->fw_name, + SDSD8997_DEFAULT_COMBO_FW_NAME); + } + } +#endif + +#ifdef SD8987 + if (IS_SD8987(handle->card_type)) { + if (magic == CHIP_MAGIC_VALUE) { + if (strap == CARD_TYPE_SD_UART) + strcpy(handle->card_info->fw_name, + SDUART8987_DEFAULT_COMBO_FW_NAME); + else + strcpy(handle->card_info->fw_name, + SDSD8987_DEFAULT_COMBO_FW_NAME); + } + } +#endif + +#ifdef SD8978 + if (IS_SD8978(handle->card_type)) { + if (magic == CHIP_MAGIC_VALUE) { + if (strap == CARD_TYPE_SD_UART) + strcpy(handle->card_info->fw_name, + SDUART8978_DEFAULT_COMBO_FW_NAME); + else + strcpy(handle->card_info->fw_name, + SDSD8978_DEFAULT_COMBO_FW_NAME); + } + } +#endif + +#ifdef SD9098 + if (IS_SD9098(handle->card_type) && + (card->func->device == SD_DEVICE_ID_9098_FN1)) { + switch (revision_id) { + case SD9098_Z1Z2: + if (magic == CHIP_MAGIC_VALUE) { + if (strap == CARD_TYPE_SD_UART) + strcpy(handle->card_info->fw_name, + SDUART9098_DEFAULT_COMBO_FW_NAME); + else + strcpy(handle->card_info->fw_name, + SDSD9098_DEFAULT_COMBO_FW_NAME); + } + strcpy(handle->card_info->fw_name_wlan, + SD9098_DEFAULT_WLAN_FW_NAME); + break; + case SD9098_A0: + case SD9098_A1: + case SD9098_A2: + if (magic == CHIP_MAGIC_VALUE) { + if (strap == CARD_TYPE_SD_UART) + strcpy(handle->card_info->fw_name, + SDUART9098_COMBO_V1_FW_NAME); + else + strcpy(handle->card_info->fw_name, + SDSD9098_COMBO_V1_FW_NAME); + } + strcpy(handle->card_info->fw_name_wlan, + SD9098_WLAN_V1_FW_NAME); + break; + default: + break; + } + } +#endif +#ifdef SD9097 + if (IS_SD9097(handle->card_type)) { + switch (revision_id) { + case SD9097_B0: + case SD9097_B1: + if (magic == CHIP_MAGIC_VALUE) { + if (strap == CARD_TYPE_SD_UART) + strcpy(handle->card_info->fw_name, + SDUART9097_COMBO_V1_FW_NAME); + else + strcpy(handle->card_info->fw_name, + SDSD9097_COMBO_V1_FW_NAME); + } + strcpy(handle->card_info->fw_name_wlan, + SD9097_WLAN_V1_FW_NAME); + break; + default: + break; + } + } +#endif +done: + PRINTM(MCMND, "combo fw:%s wlan fw:%s \n", handle->card_info->fw_name, + handle->card_info->fw_name_wlan); + LEAVE(); + return ret; +} + +#define DEBUG_FW_DONE 0xFF +#define DEBUG_MEMDUMP_FINISH 0xFE +#define MAX_POLL_TRIES 100 + +typedef enum { + DUMP_TYPE_ITCM = 0, + DUMP_TYPE_DTCM = 1, + DUMP_TYPE_SQRAM = 2, + DUMP_TYPE_APU_REGS = 3, + DUMP_TYPE_CIU_REGS = 4, + DUMP_TYPE_ICU_REGS = 5, + DUMP_TYPE_MAC_REGS = 6, + DUMP_TYPE_EXTEND_7 = 7, + DUMP_TYPE_EXTEND_8 = 8, + DUMP_TYPE_EXTEND_9 = 9, + DUMP_TYPE_EXTEND_10 = 10, + DUMP_TYPE_EXTEND_11 = 11, + DUMP_TYPE_EXTEND_12 = 12, + DUMP_TYPE_EXTEND_13 = 13, + DUMP_TYPE_EXTEND_LAST = 14 +} dumped_mem_type; + +#define MAX_NAME_LEN 8 +#define MAX_FULL_NAME_LEN 32 + +typedef struct { + t_u8 mem_name[MAX_NAME_LEN]; + t_u8 *mem_Ptr; + struct file *pfile_mem; + t_u8 done_flag; + t_u8 type; +} memory_type_mapping; + +memory_type_mapping mem_type_mapping_tbl[] = { + {"ITCM", NULL, NULL, 0xF0, FW_DUMP_TYPE_MEM_ITCM}, + {"DTCM", NULL, NULL, 0xF1, FW_DUMP_TYPE_MEM_DTCM}, + {"SQRAM", NULL, NULL, 0xF2, FW_DUMP_TYPE_MEM_SQRAM}, + {"APU", NULL, NULL, 0xF3, FW_DUMP_TYPE_REG_APU}, + {"CIU", NULL, NULL, 0xF4, FW_DUMP_TYPE_REG_CIU}, + {"ICU", NULL, NULL, 0xF5, FW_DUMP_TYPE_REG_ICU}, + {"MAC", NULL, NULL, 0xF6, FW_DUMP_TYPE_REG_MAC}, + {"EXT7", NULL, NULL, 0xF7, 0}, + {"EXT8", NULL, NULL, 0xF8, 0}, + {"EXT9", NULL, NULL, 0xF9, 0}, + {"EXT10", NULL, NULL, 0xFA, 0}, + {"EXT11", NULL, NULL, 0xFB, 0}, + {"EXT12", NULL, NULL, 0xFC, 0}, + {"EXT13", NULL, NULL, 0xFD, 0}, + {"EXTLAST", NULL, NULL, 0xFE, 0}, +}; +memory_type_mapping mem_type_mapping_tbl_8977_8997 = {"DUMP", NULL, NULL, 0xDD, + 0}; + +typedef enum { + RDWR_STATUS_SUCCESS = 0, + RDWR_STATUS_FAILURE = 1, + RDWR_STATUS_DONE = 2 +} rdwr_status; + +/** + * @brief This function read/write firmware via cmd52 + * + * @param phandle A pointer to moal_handle + * @param doneflag A flag + * + * @return MLAN_STATUS_SUCCESS + */ +rdwr_status woal_cmd52_rdwr_firmware(moal_handle *phandle, t_u8 doneflag) +{ + int ret = 0; + int tries = 0; + t_u8 ctrl_data = 0; + t_u8 dbg_dump_ctrl_reg = phandle->card_info->dump_fw_ctrl_reg; + t_u8 debug_host_ready = phandle->card_info->dump_fw_host_ready; + + ret = woal_sdio_writeb(phandle, dbg_dump_ctrl_reg, debug_host_ready); + if (ret) { + PRINTM(MERROR, "SDIO Write ERR\n"); + return RDWR_STATUS_FAILURE; + } + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ret = woal_sdio_readb(phandle, dbg_dump_ctrl_reg, &ctrl_data); + if (ret) { + PRINTM(MERROR, "SDIO READ ERR\n"); + return RDWR_STATUS_FAILURE; + } + if (ctrl_data == DEBUG_FW_DONE) + break; + if (doneflag && ctrl_data == doneflag) + return RDWR_STATUS_DONE; + if (ctrl_data != debug_host_ready) { + PRINTM(MMSG, + "The ctrl reg was changed, re-try again!\n"); + ret = woal_sdio_writeb(phandle, dbg_dump_ctrl_reg, + debug_host_ready); + if (ret) { + PRINTM(MERROR, "SDIO Write ERR\n"); + return RDWR_STATUS_FAILURE; + } + } + udelay(100); + } + if (ctrl_data == debug_host_ready) { + PRINTM(MERROR, "Fail to pull ctrl_data\n"); + return RDWR_STATUS_FAILURE; + } + return RDWR_STATUS_SUCCESS; +} + +/** + * @brief This function dump firmware memory to file + * + * @param phandle A pointer to moal_handle + * + * @return N/A + */ +void woal_dump_firmware_info_v2(moal_handle *phandle) +{ + int ret = 0; + unsigned int reg, reg_start, reg_end; + t_u8 *dbg_ptr = NULL; + t_u32 sec, usec; + t_u8 dump_num = 0; + t_u8 idx = 0; + t_u8 doneflag = 0; + rdwr_status stat; + t_u8 i = 0; + t_u8 read_reg = 0; + t_u32 memory_size = 0; + t_u8 path_name[64], file_name[32], firmware_dump_file[128]; + t_u8 *end_ptr = NULL; + t_u8 dbg_dump_start_reg = 0; + t_u8 dbg_dump_end_reg = 0; + t_u8 dbg_dump_ctrl_reg = 0; + + if (!phandle) { + PRINTM(MERROR, "Could not dump firmwware info\n"); + return; + } + + dbg_dump_start_reg = phandle->card_info->dump_fw_start_reg; + dbg_dump_end_reg = phandle->card_info->dump_fw_end_reg; + dbg_dump_ctrl_reg = phandle->card_info->dump_fw_ctrl_reg; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) + /** Create dump directort*/ + woal_create_dump_dir(phandle, path_name, sizeof(path_name)); +#else + memset(path_name, 0, sizeof(path_name)); + strcpy(path_name, "/data"); +#endif + PRINTM(MMSG, "Directory name is %s\n", path_name); + + woal_dump_drv_info(phandle, path_name); + + /* start dump fw memory */ + moal_get_system_time(phandle, &sec, &usec); + PRINTM(MMSG, "==== DEBUG MODE OUTPUT START: %u.%06u ====\n", sec, usec); + /* read the number of the memories which will dump */ + if (RDWR_STATUS_FAILURE == woal_cmd52_rdwr_firmware(phandle, doneflag)) + goto done; + reg = dbg_dump_start_reg; + ret = woal_sdio_readb(phandle, reg, &dump_num); + if (ret) { + PRINTM(MMSG, "SDIO READ MEM NUM ERR\n"); + goto done; + } + + /* read the length of every memory which will dump */ + for (idx = 0; idx < dump_num; idx++) { + if (RDWR_STATUS_FAILURE == + woal_cmd52_rdwr_firmware(phandle, doneflag)) + goto done; + memory_size = 0; + reg = dbg_dump_start_reg; + for (i = 0; i < 4; i++) { + ret = woal_sdio_readb(phandle, reg, &read_reg); + if (ret) { + PRINTM(MMSG, "SDIO READ ERR\n"); + goto done; + } + memory_size |= (read_reg << i * 8); + reg++; + } + if (memory_size == 0) { + PRINTM(MMSG, "Firmware Dump Finished!\n"); + ret = woal_sdiommc_write_reg(phandle, dbg_dump_ctrl_reg, + DEBUG_MEMDUMP_FINISH); + if (ret) { + PRINTM(MERROR, + "SDIO Write MEMDUMP_FINISH ERR\n"); + goto done; + } + break; + } else { + PRINTM(MMSG, "%s_SIZE=0x%x\n", + mem_type_mapping_tbl[idx].mem_name, memory_size); + ret = moal_vmalloc( + phandle, memory_size + 1, + (t_u8 **)&mem_type_mapping_tbl[idx].mem_Ptr); + if ((ret != MLAN_STATUS_SUCCESS) || + !mem_type_mapping_tbl[idx].mem_Ptr) { + PRINTM(MERROR, + "Error: vmalloc %s buffer failed!!!\n", + mem_type_mapping_tbl[idx].mem_name); + goto done; + } + dbg_ptr = mem_type_mapping_tbl[idx].mem_Ptr; + end_ptr = dbg_ptr + memory_size; + } + doneflag = mem_type_mapping_tbl[idx].done_flag; + moal_get_system_time(phandle, &sec, &usec); + PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n", + mem_type_mapping_tbl[idx].mem_name, sec, usec); + do { + stat = woal_cmd52_rdwr_firmware(phandle, doneflag); + if (RDWR_STATUS_FAILURE == stat) + goto done; + reg_start = dbg_dump_start_reg; + reg_end = dbg_dump_end_reg; + for (reg = reg_start; reg <= reg_end; reg++) { + ret = woal_sdio_readb(phandle, reg, dbg_ptr); + if (ret) { + PRINTM(MMSG, "SDIO READ ERR\n"); + goto done; + } + if (dbg_ptr < end_ptr) + dbg_ptr++; + else + PRINTM(MMSG, + "pre-allocced buf is not enough\n"); + } + if (RDWR_STATUS_DONE == stat) { + PRINTM(MMSG, + "%s done:" +#ifdef MLAN_64BIT + "size = 0x%lx\n", +#else + "size = 0x%x\n", +#endif + mem_type_mapping_tbl[idx].mem_name, + dbg_ptr - mem_type_mapping_tbl[idx] + .mem_Ptr); + memset(file_name, 0, sizeof(file_name)); + sprintf(file_name, "%s%s", "file_sdio_", + mem_type_mapping_tbl[idx].mem_name); + if (MLAN_STATUS_SUCCESS != + woal_save_dump_info_to_file( + path_name, file_name, + mem_type_mapping_tbl[idx].mem_Ptr, + memory_size)) + PRINTM(MERROR, + "Can't save dump file %s in %s\n", + file_name, path_name); + moal_vfree(phandle, + mem_type_mapping_tbl[idx].mem_Ptr); + mem_type_mapping_tbl[idx].mem_Ptr = NULL; + break; + } + } while (1); + } + moal_get_system_time(phandle, &sec, &usec); + PRINTM(MMSG, "==== DEBUG MODE OUTPUT END: %u.%06u ====\n", sec, usec); + /* end dump fw memory */ + memset(firmware_dump_file, 0, sizeof(firmware_dump_file)); + sprintf(firmware_dump_file, "%s/%s", path_name, file_name); + moal_memcpy_ext(phandle, phandle->firmware_dump_file, + firmware_dump_file, sizeof(firmware_dump_file), + sizeof(phandle->firmware_dump_file)); +done: + for (idx = 0; idx < dump_num; idx++) { + if (mem_type_mapping_tbl[idx].mem_Ptr) { + moal_vfree(phandle, mem_type_mapping_tbl[idx].mem_Ptr); + mem_type_mapping_tbl[idx].mem_Ptr = NULL; + } + } + PRINTM(MMSG, "==== DEBUG MODE END ====\n"); + return; +} + +/** + * @brief This function dump firmware memory to file + * + * @param phandle A pointer to moal_handle + * + * @return N/A + */ +void woal_dump_firmware_info_v3(moal_handle *phandle) +{ + int ret = 0; + int tries = 0; + unsigned int reg, reg_start, reg_end; + t_u8 *dbg_ptr = NULL; + t_u8 *temp_Ptr = NULL; + t_u32 sec, usec; + t_u8 start_flag = 0; + t_u8 doneflag = 0; + rdwr_status stat; + t_u32 memory_size = 0; + t_u8 path_name[64], file_name[32], firmware_dump_file[128]; + moal_handle *ref_handle; + t_u8 *end_ptr = NULL; + t_u8 dbg_dump_start_reg = 0; + t_u8 dbg_dump_end_reg = 0; + memory_type_mapping *pmem_type_mapping_tbl = + &mem_type_mapping_tbl_8977_8997; + + if (!phandle) { + PRINTM(MERROR, "Could not dump firmwware info\n"); + return; + } + + dbg_dump_start_reg = phandle->card_info->dump_fw_start_reg; + dbg_dump_end_reg = phandle->card_info->dump_fw_end_reg; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) + /** Create dump directort*/ + woal_create_dump_dir(phandle, path_name, sizeof(path_name)); +#else + memset(path_name, 0, sizeof(path_name)); + strcpy(path_name, "/data"); +#endif + PRINTM(MMSG, "Directory name is %s\n", path_name); + ref_handle = (moal_handle *)phandle->pref_mac; + if (ref_handle) + woal_dump_drv_info(ref_handle, path_name); + woal_dump_drv_info(phandle, path_name); + + /* start dump fw memory */ + moal_get_system_time(phandle, &sec, &usec); + PRINTM(MMSG, "==== DEBUG MODE OUTPUT START: %u.%06u ====\n", sec, usec); + /* read the number of the memories which will dump */ + if (RDWR_STATUS_FAILURE == woal_cmd52_rdwr_firmware(phandle, doneflag)) + goto done; + + /** check the reg which indicate dump starting */ + for (reg = dbg_dump_start_reg; reg <= dbg_dump_end_reg; reg++) { + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ret = woal_sdio_readb(phandle, reg, &start_flag); + if (ret) { + PRINTM(MMSG, "SDIO READ ERR\n"); + goto done; + } + /** 0 means dump starting*/ + if (start_flag == 0) + break; + udelay(100); + } + if (tries == MAX_POLL_TRIES) { + PRINTM(MMSG, "FW not ready to dump\n"); + goto done; + } + } + memory_size = 0xF0000; + PRINTM(MMSG, "%s_SIZE=0x%x\n", pmem_type_mapping_tbl->mem_name, + memory_size); + ret = moal_vmalloc(phandle, memory_size + 1, + (t_u8 **)&pmem_type_mapping_tbl->mem_Ptr); + if ((ret != MLAN_STATUS_SUCCESS) || !pmem_type_mapping_tbl->mem_Ptr) { + PRINTM(MERROR, "Error: vmalloc %s buffer failed!!!\n", + pmem_type_mapping_tbl->mem_name); + goto done; + } + dbg_ptr = pmem_type_mapping_tbl->mem_Ptr; + end_ptr = dbg_ptr + memory_size; + doneflag = pmem_type_mapping_tbl->done_flag; + moal_get_system_time(phandle, &sec, &usec); + PRINTM(MMSG, "Start %s output %u.%06u, please wait...\n", + pmem_type_mapping_tbl->mem_name, sec, usec); + do { + stat = woal_cmd52_rdwr_firmware(phandle, doneflag); + if (RDWR_STATUS_FAILURE == stat) + goto done; + reg_start = dbg_dump_start_reg; + reg_end = dbg_dump_end_reg; + for (reg = reg_start; reg <= reg_end; reg++) { + ret = woal_sdio_readb(phandle, reg, dbg_ptr); + if (ret) { + PRINTM(MMSG, "SDIO READ ERR\n"); + goto done; + } + dbg_ptr++; + if (dbg_ptr >= end_ptr) { + PRINTM(MMSG, + "pre-allocced buf is not enough\n"); + ret = moal_vmalloc(phandle, + memory_size + 0x4000 + 1, + (t_u8 **)&temp_Ptr); + if ((ret != MLAN_STATUS_SUCCESS) || !temp_Ptr) { + PRINTM(MERROR, + "Error: vmalloc buffer failed!!!\n"); + goto done; + } + moal_memcpy_ext(phandle, temp_Ptr, + pmem_type_mapping_tbl->mem_Ptr, + memory_size, + memory_size + 0x4000); + moal_vfree(phandle, + pmem_type_mapping_tbl->mem_Ptr); + pmem_type_mapping_tbl->mem_Ptr = temp_Ptr; + temp_Ptr = NULL; + dbg_ptr = pmem_type_mapping_tbl->mem_Ptr + + memory_size; + memory_size += 0x4000; + end_ptr = pmem_type_mapping_tbl->mem_Ptr + + memory_size; + } + } + if (RDWR_STATUS_DONE == stat) { + PRINTM(MMSG, + "%s done:" +#ifdef MLAN_64BIT + "size = 0x%lx\n", +#else + "size = 0x%x\n", +#endif + pmem_type_mapping_tbl->mem_name, + dbg_ptr - pmem_type_mapping_tbl->mem_Ptr); + memset(file_name, 0, sizeof(file_name)); + sprintf(file_name, "%s%s", "file_sdio_", + pmem_type_mapping_tbl->mem_name); + if (MLAN_STATUS_SUCCESS != + woal_save_dump_info_to_file( + path_name, file_name, + pmem_type_mapping_tbl->mem_Ptr, + dbg_ptr - pmem_type_mapping_tbl->mem_Ptr)) + PRINTM(MERROR, + "Can't save dump file %s in %s\n", + file_name, path_name); + moal_vfree(phandle, pmem_type_mapping_tbl->mem_Ptr); + pmem_type_mapping_tbl->mem_Ptr = NULL; + break; + } + } while (1); + moal_get_system_time(phandle, &sec, &usec); + PRINTM(MMSG, "==== DEBUG MODE OUTPUT END: %u.%06u ====\n", sec, usec); + /* end dump fw memory */ + memset(firmware_dump_file, 0, sizeof(firmware_dump_file)); + sprintf(firmware_dump_file, "%s/%s", path_name, file_name); + moal_memcpy_ext(phandle, phandle->firmware_dump_file, + firmware_dump_file, sizeof(firmware_dump_file), + sizeof(phandle->firmware_dump_file)); +done: + if (pmem_type_mapping_tbl->mem_Ptr) { + moal_vfree(phandle, pmem_type_mapping_tbl->mem_Ptr); + pmem_type_mapping_tbl->mem_Ptr = NULL; + } + PRINTM(MMSG, "==== DEBUG MODE END ====\n"); + return; +} + +/** + * @brief This function reads and displays SDIO registers for debugging + * + * @param phandle A pointer to moal_handle + * + * @return N/A + */ +static void woal_sdiommc_reg_dbg(moal_handle *phandle) +{ + int ret = 0; + t_u8 loop, index = 0, func, data; + unsigned int reg, reg_start, reg_end; + unsigned int scratch_reg = phandle->card_info->scratch_reg; + t_u8 *reg_table = phandle->card_info->dump_reg.reg_table; + t_u8 reg_table_size = phandle->card_info->dump_reg.reg_table_size; + char buf[256], *ptr; + + mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE); + for (loop = 0; loop < 5; loop++) { + memset(buf, 0, sizeof(buf)); + ptr = buf; + if (loop == 0) { + /* Read the registers of SDIO function0 */ + func = loop; + reg_start = 0; + reg_end = 9; + } else if (loop == 1) { + /* Read the registers of SDIO function1 */ + func = loop; + reg_start = phandle->card_info->func1_reg_start; + reg_end = phandle->card_info->func1_reg_end; + } else if (loop == 2) { + /* Read specific registers of SDIO function1 */ + index = 0; + func = 1; + reg_start = reg_table[index++]; + reg_end = reg_table[reg_table_size - 1]; + } else { + /* Read the scratch registers of SDIO function1 */ + if (loop == 4) + mdelay(100); + func = 1; + reg_start = scratch_reg; + reg_end = scratch_reg + 10; + } + if (loop != 2) + ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func, + reg_start, reg_end); + else + ptr += sprintf(ptr, "SDIO Func%d: ", func); + for (reg = reg_start; reg <= reg_end;) { + if (func == 0) + ret = woal_sdio_f0_readb(phandle, reg, &data); + else + ret = woal_sdio_readb(phandle, reg, &data); + if (loop == 2) + ptr += sprintf(ptr, "(%#x) ", reg); + if (!ret) + ptr += sprintf(ptr, "%02x ", data); + else { + ptr += sprintf(ptr, "ERR"); + break; + } + if (loop == 2 && reg < reg_end) + reg = reg_table[index++]; + else + reg++; + } + PRINTM(MMSG, "%s\n", buf); + } + mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE); +} + +/** + * @brief This function dump firmware memory to file + * + * @param phandle A pointer to moal_handle + * + * @return N/A + */ +static void woal_sdiommc_dump_fw_info(moal_handle *phandle) +{ + if (!phandle) { + PRINTM(MERROR, "Could not dump firmwware info\n"); + return; + } + mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE); + phandle->fw_dump = MTRUE; + if (phandle->card_info->dump_fw_info == DUMP_FW_SDIO_V2) { + woal_dump_firmware_info_v2(phandle); + } else if (phandle->card_info->dump_fw_info == DUMP_FW_SDIO_V3) { + woal_dump_firmware_info_v3(phandle); + } + phandle->fw_dump = MFALSE; + mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE); + queue_work(phandle->workqueue, &phandle->main_work); + return; +} + +/** + * @brief This function save sdio reg info + * + * @param phandle A pointer to moal_handle + * @param buf A pointer buffer saving log + * + * @return The length of this log + */ +static int woal_sdiommc_dump_reg_info(moal_handle *phandle, t_u8 *drv_buf) +{ + char *drv_ptr = (char *)drv_buf; + int ret = 0; + t_u8 loop, index = 0, func, data; + unsigned int reg, reg_start, reg_end; + unsigned int scratch_reg = 0; + t_u8 *reg_table = NULL; + t_u8 reg_table_size = 0; + char buf[256], *ptr; + + ENTER(); + + if (!phandle || !drv_buf) { + PRINTM(MMSG, "%s: can't retreive info\n", __func__); + LEAVE(); + return 0; + } + + scratch_reg = phandle->card_info->scratch_reg; + reg_table = phandle->card_info->dump_reg.reg_table; + reg_table_size = phandle->card_info->dump_reg.reg_table_size; + + mlan_pm_wakeup_card(phandle->pmlan_adapter, MTRUE); + + drv_ptr += sprintf(drv_ptr, "--------sdio_reg_debug_info---------\n"); + for (loop = 0; loop < 5; loop++) { + memset(buf, 0, sizeof(buf)); + ptr = buf; + if (loop == 0) { + /* Read the registers of SDIO function0 */ + func = loop; + reg_start = 0; + reg_end = 9; + + } else if (loop == 1) { + /* Read the registers of SDIO function1 */ + func = loop; + reg_start = phandle->card_info->func1_reg_start; + reg_end = phandle->card_info->func1_reg_end; + } else if (loop == 2) { + /* Read specific registers of SDIO function1 */ + index = 0; + func = 1; + reg_start = reg_table[index++]; + reg_end = reg_table[reg_table_size - 1]; + } else { + /* Read the scratch registers of SDIO function1 */ + if (loop == 4) + mdelay(100); + func = 1; + reg_start = scratch_reg; + reg_end = scratch_reg + 10; + } + if (loop != 2) + ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func, + reg_start, reg_end); + else + ptr += sprintf(ptr, "SDIO Func%d: ", func); + for (reg = reg_start; reg <= reg_end;) { + if (func == 0) + ret = woal_sdio_f0_readb(phandle, reg, &data); + else + ret = woal_sdio_readb(phandle, reg, &data); + + if (loop == 2) + ptr += sprintf(ptr, "(%#x) ", reg); + if (!ret) + ptr += sprintf(ptr, "%02x ", data); + else { + ptr += sprintf(ptr, "ERR"); + break; + } + if (loop == 2 && reg < reg_end) + reg = reg_table[index++]; + else + reg++; + } + drv_ptr += sprintf(drv_ptr, "%s\n", buf); + } + + drv_ptr += + sprintf(drv_ptr, "--------sdio_reg_debug_info End---------\n"); + mlan_pm_wakeup_card(phandle->pmlan_adapter, MFALSE); + + LEAVE(); + return drv_ptr - (char *)drv_buf; +} + +static moal_if_ops sdiommc_ops = { + .register_dev = woal_sdiommc_register_dev, + .unregister_dev = woal_sdiommc_unregister_dev, + .read_reg = woal_sdiommc_read_reg, + .write_reg = woal_sdiommc_write_reg, + .read_data_sync = woal_sdiommc_read_data_sync, + .write_data_sync = woal_sdiommc_write_data_sync, + .get_fw_name = woal_sdiommc_get_fw_name, + .dump_fw_info = woal_sdiommc_dump_fw_info, + .dump_reg_info = woal_sdiommc_dump_reg_info, + .reg_dbg = woal_sdiommc_reg_dbg, + .is_second_mac = woal_sdiommc_is_second_mac, +}; |