/** * @brief Handle suspend * * @param intf Pointer to usb_interface * @param message Pointer to pm_message_t structure * * @return MLAN_STATUS_SUCCESS */ static int woal_usb_suspend(struct usb_interface *intf, pm_message_t message) { struct usb_card_rec *cardp = usb_get_intfdata(intf); moal_handle *handle = NULL; int i; ENTER(); if (!cardp || !cardp->phandle) { PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle = cardp->phandle; /* Enable Host Sleep */ woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY)); /* Indicate device suspended */ /* The flag must be set here before the usb_kill_urb() calls. Reason: In the complete handlers, urb->status(= -ENOENT) and 'is_suspended' flag is used in combination to distinguish between a suspended state and a 'disconnect' one. */ handle->is_suspended = MTRUE; for (i = 0; i < handle->priv_num; i++) netif_carrier_off(handle->priv[i]->netdev); /* Unlink Rx cmd URB */ if (atomic_read(&cardp->rx_cmd_urb_pending) && cardp->rx_cmd.urb) { usb_kill_urb(cardp->rx_cmd.urb); } /* Unlink Rx data URBs */ if (atomic_read(&cardp->rx_data_urb_pending)) { for (i = 0; i < MVUSB_RX_DATA_URB; i++) { if (cardp->rx_data_list[i].urb) usb_kill_urb(cardp->rx_data_list[i].urb); } } /* Unlink Tx data URBs */ for (i = 0; i < MVUSB_TX_HIGH_WMARK; i++) { if (cardp->tx_data_list[i].urb) { usb_kill_urb(cardp->tx_data_list[i].urb); } } /* Unlink Tx cmd URB */ if (cardp->tx_cmd.urb) { usb_kill_urb(cardp->tx_cmd.urb); } handle->suspend_wait_q_woken = MTRUE; wake_up_interruptible(&handle->suspend_wait_q); LEAVE(); return MLAN_STATUS_SUCCESS; }
/** @brief This function handles client driver suspend * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ 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; int ret = MLAN_STATUS_SUCCESS; int hs_actived = 0; ENTER(); if (func) { pm_flags = sdio_get_host_pm_caps(func); PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); if (!(pm_flags & MMC_PM_KEEP_POWER)) { PRINTM(MERROR, "%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); LEAVE(); return -ENOSYS; } 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; } } else { PRINTM(MERROR, "sdio_func is not specified\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle = cardp->handle; if (pm_keep_power) { /* Enable the Host Sleep */ hs_actived = woal_enable_hs(woal_get_priv(handle, MLAN_BSS_TYPE_ANY)); if (hs_actived) { PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n"); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); } } /* Indicate device suspended */ handle->is_suspended = MTRUE; for (i = 0; i < handle->priv_num; i++) netif_carrier_off(handle->priv[i]->netdev); LEAVE(); return ret; }
/** @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); if (!(pm_flags & MMC_PM_KEEP_POWER)) { PRINTM(MERROR, "%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); LEAVE(); return -ENOSYS; } 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 == 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; } 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 (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; }