/** @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_hs_cfg hscfg; int timeout = 0; int i; 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 (shutdown_hs) { memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg)); hscfg.is_invoke_hostcmd = MFALSE; hscfg.conditions = SHUTDOWN_HOST_SLEEP_DEF_COND; hscfg.gap = SHUTDOWN_HOST_SLEEP_DEF_GAP; hscfg.gpio = SHUTDOWN_HOST_SLEEP_DEF_GPIO; if (woal_set_get_hs_params (woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MLAN_ACT_SET, MOAL_IOCTL_WAIT, &hscfg) == MLAN_STATUS_FAILURE) { PRINTM(MERROR, "Fail to set HS parameter in shutdown: 0x%x 0x%x 0x%x\n", hscfg.conditions, hscfg.gap, hscfg.gpio); goto done; } /* Enable Host Sleep */ handle->hs_activate_wait_q_woken = MFALSE; memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg)); hscfg.is_invoke_hostcmd = MTRUE; if (woal_set_get_hs_params (woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MLAN_ACT_SET, MOAL_NO_WAIT, &hscfg) == MLAN_STATUS_FAILURE) { PRINTM(MERROR, "Request HS enable failed in shutdown\n"); goto done; } 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"); } done: PRINTM(MCMND, "<--- Leave woal_sdio_shutdown --->\n"); LEAVE(); return; }
/** * @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 reset AP or GO parameters * * @param wiphy A pointer to wiphy structure * @param dev A pointer to net_device structure * * @return 0 -- success, otherwise fail */ int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) { moal_private *priv = (moal_private *)woal_get_netdev_priv(dev); int ret = 0; #ifdef STA_SUPPORT moal_private *pmpriv = NULL; #endif ENTER(); PRINTM(MMSG, "wlan: Stoping AP\n"); woal_deauth_all_station(priv); /* if the bss is still running, then stop it */ if (priv->bss_started == MTRUE) { if (MLAN_STATUS_SUCCESS != woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT_TIMEOUT, UAP_BSS_STOP)) { ret = -EFAULT; goto done; } if (MLAN_STATUS_SUCCESS != woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_RESET)) { ret = -EFAULT; goto done; } /* Set WLAN MAC addresses */ if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) { PRINTM(MERROR, "Set MAC address failed\n"); ret = -EFAULT; goto done; } } woal_clear_all_mgmt_ies(priv, MOAL_IOCTL_WAIT); #ifdef STA_SUPPORT if (!woal_is_any_interface_active(priv->phandle)) { pmpriv = woal_get_priv((moal_handle *)priv->phandle, MLAN_BSS_ROLE_STA); if (pmpriv) woal_set_scan_time(pmpriv, ACTIVE_SCAN_CHAN_TIME, PASSIVE_SCAN_CHAN_TIME, SPECIFIC_SCAN_CHAN_TIME); } #endif priv->cipher = 0; memset(priv->uap_wep_key, 0, sizeof(priv->uap_wep_key)); priv->channel = 0; PRINTM(MMSG, "wlan: AP stopped\n"); done: LEAVE(); return ret; }
/** @brief This function handles client driver resume * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ 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(); if (func) { 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; } } else { PRINTM(MERROR, "sdio_func is not specified\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; for (i = 0; i < handle->priv_num; i++) netif_carrier_on(handle->priv[i]->netdev); /* Disable Host Sleep */ woal_hs_cfg_cancel(woal_get_priv(handle, MLAN_BSS_TYPE_ANY), MOAL_NO_WAIT); LEAVE(); return MLAN_STATUS_SUCCESS; }
/** @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"); wifi_enable_hostwake_irq(MFALSE); 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; }
/** @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; }
/** * @brief Handle resume * * @param intf Pointer to usb_interface * * @return MLAN_STATUS_SUCCESS */ static int woal_usb_resume(struct usb_interface *intf) { struct usb_card_rec *cardp = usb_get_intfdata(intf); moal_handle *handle = NULL; int i; ENTER(); if (!cardp || !cardp->phandle) { PRINTM(MERROR, "Card or adapter structure is not valid\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle = cardp->phandle; if (handle->is_suspended == MFALSE) { PRINTM(MWARN, "Device already resumed\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } /* Indicate device resumed. The netdev queue will be resumed only after the urbs have been resubmitted */ handle->is_suspended = MFALSE; if (!atomic_read(&cardp->rx_data_urb_pending)) { /* Submit multiple Rx data URBs */ woal_usb_submit_rx_data_urbs(handle); } if (!atomic_read(&cardp->rx_cmd_urb_pending)) { if ((cardp->rx_cmd.pmbuf = woal_alloc_mlan_buffer(handle, MLAN_RX_CMD_BUF_SIZE))) woal_usb_submit_rx_urb(&cardp->rx_cmd, MLAN_RX_CMD_BUF_SIZE); } for (i = 0; i < handle->priv_num; i++) if (handle->priv[i]->media_connected == MTRUE) netif_carrier_on(handle->priv[i]->netdev); /* Disable Host Sleep */ if (handle->hs_activated) woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) #ifdef CONFIG_PM /* Resume handler may be called due to remote wakeup, force to exit suspend anyway */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) cardp->udev->autosuspend_disabled = 1; #else cardp->udev->dev.power.runtime_auto = 0; #endif /* < 2.6.35 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) cardp->udev->autoresume_disabled = 0; #endif /* < 2.6.33 */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) atomic_inc(&(cardp->udev)->dev.power.usage_count); #endif /* >= 2.6.34 */ #endif /* CONFIG_PM */ #endif /* >= 2.6.24 */ LEAVE(); return MLAN_STATUS_SUCCESS; }
/** * @brief config proc write function * * @param f file pointer * @param buf pointer to data buffer * @param cnt data number to write * @param data data to write * @return number of data */ static int woal_config_write(struct file *f, const char *buf, unsigned long cnt, void *data) { char databuf[101]; char *line; t_u32 config_data = 0; moal_handle *handle = (moal_handle *) data; int func, reg, val; int copy_len; moal_private *priv = NULL; ENTER(); if (!MODULE_GET) { LEAVE(); return 0; } if (cnt >= sizeof(databuf)) { MODULE_PUT; LEAVE(); return (int) cnt; } memset(databuf, 0, sizeof(databuf)); copy_len = MIN((sizeof(databuf) - 1), cnt); if (copy_from_user(databuf, buf, copy_len)) { MODULE_PUT; LEAVE(); return 0; } line = databuf; if (!strncmp(databuf, "soft_reset", strlen("soft_reset"))) { line += strlen("soft_reset") + 1; config_data = (t_u32) woal_string_to_number(line); PRINTM(MINFO, "soft_reset: %d\n", (int) config_data); if (woal_request_soft_reset(handle) == MLAN_STATUS_SUCCESS) { handle->hardware_status = HardwareStatusReset; } else { PRINTM(MERROR, "Could not perform soft reset\n"); } } if (!strncmp(databuf, "drv_mode", strlen("drv_mode"))) { line += strlen("drv_mode") + 1; config_data = (t_u32) woal_string_to_number(line); PRINTM(MINFO, "drv_mode: %d\n", (int) config_data); if (config_data != (t_u32) drv_mode) if (woal_switch_drv_mode(handle, config_data) != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "Could not switch drv mode\n"); } } if (!strncmp(databuf, "sdcmd52rw=", strlen("sdcmd52rw="))) { parse_cmd52_string(databuf, (size_t) cnt, &func, ®, &val); woal_sdio_read_write_cmd52(handle, func, reg, val); } if (!strncmp(databuf, "debug_dump", strlen("debug_dump"))) { priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY); if (priv) { woal_mlan_debug_info(priv); woal_moal_debug_info(priv, NULL, MFALSE); woal_dump_firmware_info(priv); } } MODULE_PUT; LEAVE(); return (int) cnt; }