/* * This function processes the received buffer. * * Main responsibility of this function is to parse the RxPD to * identify the correct interface this packet is headed for and * forwarding it to the associated handling function, where the * packet will be further processed and sent to kernel/upper layer * if required. */ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); struct rxpd *local_rx_pd; struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); local_rx_pd = (struct rxpd *) (skb->data); /* Get the BSS number from rxpd, get corresponding priv */ priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & BSS_NUM_MASK, local_rx_pd->bss_type); if (!priv) priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); if (!priv) { dev_err(adapter->dev, "data: priv not found. Drop RX packet\n"); dev_kfree_skb_any(skb); return -1; } rx_info->bss_num = priv->bss_num; rx_info->bss_type = priv->bss_type; if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) return mwifiex_process_uap_rx_packet(priv, skb); return mwifiex_process_sta_rx_packet(priv, skb); }
/* * This function cleans up the SDIO driver. * * The following major steps are followed for cleanup - * - Resume the device if its suspended * - Disconnect the device if connected * - Shutdown the firmware * - Unregister the device from SDIO bus. */ static void mwifiex_sdio_cleanup_module(void) { struct mwifiex_adapter *adapter = g_adapter; int i; if (down_interruptible(&add_remove_card_sem)) goto exit_sem_err; if (!adapter || !adapter->priv_num) goto exit; if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); if (!adapter->surprise_removed) mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); exit: up(&add_remove_card_sem); exit_sem_err: sdio_unregister_driver(&mwifiex_sdio); }
/* This function cleans up the USB driver. * * The following major steps are followed in .disconnect for cleanup: * - Resume the device if its suspended * - Disconnect the device if connected * - Shutdown the firmware * - Unregister the device from USB bus. */ static void mwifiex_usb_cleanup_module(void) { if (!down_interruptible(&add_remove_card_sem)) up(&add_remove_card_sem); if (usb_card) { struct mwifiex_adapter *adapter = usb_card->adapter; int i; /* In case driver is removed when asynchronous FW downloading is * in progress */ wait_for_completion(&adapter->fw_load); #ifdef CONFIG_PM if (adapter->is_suspended) mwifiex_usb_resume(usb_card->intf); #endif for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); } usb_deregister(&mwifiex_usb_driver); }
static int mwifiex_pcie_resume(struct pci_dev *pdev) { struct mwifiex_adapter *adapter; struct pcie_service_card *card; int i; if (pdev) { card = (struct pcie_service_card *) pci_get_drvdata(pdev); if (!card || !card->adapter) { pr_err("Card or adapter structure is not valid\n"); return 0; } } else { pr_err("PCIE device is not specified\n"); return 0; } adapter = card->adapter; if (!adapter->is_suspended) { dev_warn(adapter->dev, "Device already resumed\n"); return 0; } adapter->is_suspended = false; for (i = 0; i < adapter->priv_num; i++) if (adapter->priv[i]->media_connected) netif_carrier_on(adapter->priv[i]->netdev); mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_ASYNC_CMD); return 0; }
static void mwifiex_usb_disconnect(struct usb_interface *intf) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; wait_for_completion(&card->fw_done); adapter = card->adapter; if (!adapter || !adapter->priv_num) return; if (card->udev->state != USB_STATE_NOTATTACHED && !adapter->mfg_mode) { mwifiex_deauthenticate_all(adapter); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); } mwifiex_usb_free(card); mwifiex_dbg(adapter, FATAL, "%s: removing card\n", __func__); mwifiex_remove_card(adapter); usb_put_dev(interface_to_usbdev(intf)); }
/* This function cleans up the USB driver. * * The following major steps are followed in .disconnect for cleanup: * - Resume the device if its suspended * - Disconnect the device if connected * - Shutdown the firmware * - Unregister the device from USB bus. */ static void mwifiex_usb_cleanup_module(void) { if (!down_interruptible(&add_remove_card_sem)) up(&add_remove_card_sem); if (usb_card && usb_card->adapter) { struct mwifiex_adapter *adapter = usb_card->adapter; /* In case driver is removed when asynchronous FW downloading is * in progress */ wait_for_completion(&adapter->fw_load); #ifdef CONFIG_PM if (adapter->is_suspended) mwifiex_usb_resume(usb_card->intf); #endif mwifiex_deauthenticate_all(adapter); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); } usb_deregister(&mwifiex_usb_driver); }
/* * SDIO resume. * * Kernel needs to suspend all functions separately. Therefore all * registered functions must have drivers with suspend and resume * methods. Failing that the kernel simply removes the whole card. * * If already not resumed, this function turns on the traffic and * sends a host sleep cancel request to the firmware. */ static int mwifiex_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; if (func) { pm_flag = sdio_get_host_pm_caps(func); card = sdio_get_drvdata(func); if (!card || !card->adapter) { pr_err("resume: invalid card or adapter\n"); return 0; } } else { pr_err("resume: sdio_func is not specified\n"); return 0; } adapter = card->adapter; if (!adapter->is_suspended) { dev_warn(adapter->dev, "device already resumed\n"); return 0; } adapter->is_suspended = false; /* Disable Host Sleep */ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_ASYNC_CMD); return 0; }
/* * Sends IOCTL request to cancel the existing Host Sleep configuration. * * This function allocates the IOCTL request buffer, fills it * with requisite parameters and calls the IOCTL handler. */ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) { struct mwifiex_ds_hs_cfg hscfg; if (adapter->hs_activated) { dev_dbg(adapter->dev, "cmd: HS Already actived\n"); return true; } adapter->hs_activate_wait_q_woken = false; memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param)); hscfg.is_invoke_hostcmd = true; if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, &hscfg)) { dev_err(adapter->dev, "IOCTL request HS enable failed\n"); return false; } wait_event_interruptible(adapter->hs_activate_wait_q, adapter->hs_activate_wait_q_woken); return true; }
static void mwifiex_usb_coredump(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); struct usb_card_rec *card = usb_get_intfdata(intf); mwifiex_fw_dump_event(mwifiex_get_priv(card->adapter, MWIFIEX_BSS_ROLE_ANY)); }
/* * This function processes the received buffer. * * Main responsibility of this function is to parse the RxPD to * identify the correct interface this packet is headed for and * forwarding it to the associated handling function, where the * packet will be further processed and sent to kernel/upper layer * if required. */ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) { struct mwifiex_private *priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); struct rxpd *local_rx_pd; struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); local_rx_pd = (struct rxpd *) (skb->data); /* Get the BSS number from rxpd, get corresponding priv */ priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num & BSS_NUM_MASK, local_rx_pd->bss_type); if (!priv) priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); rx_info->bss_index = priv->bss_index; return mwifiex_process_sta_rx_packet(adapter, skb); }
/* Kernel needs to suspend all functions separately. Therefore all * registered functions must have drivers with suspend and resume * methods. Failing that the kernel simply removes the whole card. * * If already not resumed, this function turns on the traffic and * sends a 'host sleep cancel' request to the firmware. */ static int mwifiex_usb_resume(struct usb_interface *intf) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; int i; if (!card || !card->adapter) { pr_err("%s: card or card->adapter is NULL\n", __func__); return 0; } adapter = card->adapter; if (unlikely(!adapter->is_suspended)) { dev_warn(adapter->dev, "Device already resumed\n"); return 0; } /* Indicate device resumed. The netdev queue will be resumed only * after the urbs have been re-submitted */ adapter->is_suspended = false; if (!atomic_read(&card->rx_data_urb_pending)) for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], MWIFIEX_RX_DATA_BUF_SIZE); if (!atomic_read(&card->rx_cmd_urb_pending)) { card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); if (card->rx_cmd.skb) mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE); } for (i = 0; i < adapter->priv_num; i++) if (adapter->priv[i]->media_connected) netif_carrier_on(adapter->priv[i]->netdev); /* Disable Host Sleep */ if (adapter->hs_activated) mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_ASYNC_CMD); #ifdef CONFIG_PM /* Resume handler may be called due to remote wakeup, * force to exit suspend anyway */ usb_disable_autosuspend(card->udev); #endif /* CONFIG_PM */ return 0; }
/* * SDIO remove. * * This function removes the interface and frees up the card structure. */ static void mwifiex_sdio_remove(struct sdio_func *func) { struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; int i; pr_debug("info: SDIO func num=%d\n", func->num); card = sdio_get_drvdata(func); if (!card) return; adapter = card->adapter; if (!adapter || !adapter->priv_num) return; if (user_rmmod) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) */ for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); mwifiex_disable_auto_ds(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY)); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); } mwifiex_remove_card(card->adapter, &add_remove_card_sem); kfree(card); }
static void mwifiex_usb_disconnect(struct usb_interface *intf) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; int i; if (!card || !card->adapter) { pr_err("%s: card or card->adapter is NULL\n", __func__); return; } adapter = card->adapter; if (!adapter->priv_num) return; /* In case driver is removed when asynchronous FW downloading is * in progress */ wait_for_completion(&adapter->fw_load); if (user_rmmod) { #ifdef CONFIG_PM if (adapter->is_suspended) mwifiex_usb_resume(intf); #endif for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); } mwifiex_usb_free(card); dev_dbg(adapter->dev, "%s: removing card\n", __func__); mwifiex_remove_card(adapter, &add_remove_card_sem); usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); kfree(card); return; }
/* * Sends IOCTL request to cancel the existing Host Sleep configuration. * * This function allocates the IOCTL request buffer, fills it * with requisite parameters and calls the IOCTL handler. */ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) { struct mwifiex_ds_hs_cfg hscfg; struct mwifiex_private *priv; int i; if (disconnect_on_suspend) { for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; if (priv) mwifiex_deauthenticate(priv, NULL); } } if (adapter->hs_activated) { dev_dbg(adapter->dev, "cmd: HS Already activated\n"); return true; } adapter->hs_activate_wait_q_woken = false; memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); hscfg.is_invoke_hostcmd = true; adapter->hs_enabling = true; mwifiex_cancel_all_pending_cmd(adapter); if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, &hscfg)) { dev_err(adapter->dev, "IOCTL request HS enable failed\n"); return false; } if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q, adapter->hs_activate_wait_q_woken, (10 * HZ)) <= 0) { dev_err(adapter->dev, "hs_activate_wait_q terminated\n"); return false; } return true; }
/* Kernel needs to suspend all functions separately. Therefore all * registered functions must have drivers with suspend and resume * methods. Failing that the kernel simply removes the whole card. * * If already not resumed, this function turns on the traffic and * sends a 'host sleep cancel' request to the firmware. */ static int mwifiex_usb_resume(struct usb_interface *intf) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; int i; if (!card->adapter) { dev_err(&intf->dev, "%s: card->adapter is NULL\n", __func__); return 0; } adapter = card->adapter; if (unlikely(!adapter->is_suspended)) { mwifiex_dbg(adapter, WARN, "Device already resumed\n"); return 0; } /* Indicate device resumed. The netdev queue will be resumed only * after the urbs have been re-submitted */ adapter->is_suspended = false; if (!atomic_read(&card->rx_data_urb_pending)) for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) mwifiex_usb_submit_rx_urb(&card->rx_data_list[i], MWIFIEX_RX_DATA_BUF_SIZE); if (!atomic_read(&card->rx_cmd_urb_pending)) { card->rx_cmd.skb = dev_alloc_skb(MWIFIEX_RX_CMD_BUF_SIZE); if (card->rx_cmd.skb) mwifiex_usb_submit_rx_urb(&card->rx_cmd, MWIFIEX_RX_CMD_BUF_SIZE); } /* Disable Host Sleep */ if (adapter->hs_activated) mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_ASYNC_CMD); return 0; }
/* * CFG802.11 operation handler to set Tx power. */ static int mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, int mbm) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct mwifiex_power_cfg power_cfg; int dbm = MBM_TO_DBM(mbm); if (type == NL80211_TX_POWER_FIXED) { power_cfg.is_power_auto = 0; power_cfg.power_level = dbm; } else { power_cfg.is_power_auto = 1; } priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); return mwifiex_set_tx_power(priv, &power_cfg); }
static void mwifiex_usb_disconnect(struct usb_interface *intf) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; if (!card || !card->adapter) { pr_err("%s: card or card->adapter is NULL\n", __func__); return; } adapter = card->adapter; if (!adapter->priv_num) return; if (user_rmmod) { #ifdef CONFIG_PM if (adapter->is_suspended) mwifiex_usb_resume(intf); #endif mwifiex_deauthenticate_all(adapter); mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY), MWIFIEX_FUNC_SHUTDOWN); } mwifiex_usb_free(card); mwifiex_dbg(adapter, FATAL, "%s: removing card\n", __func__); mwifiex_remove_card(adapter, &add_remove_card_sem); usb_set_intfdata(intf, NULL); usb_put_dev(interface_to_usbdev(intf)); kfree(card); return; }
static int mwifiex_sdio_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; int i; if (func) { pm_flag = sdio_get_host_pm_caps(func); card = sdio_get_drvdata(func); if (!card || !card->adapter) { pr_err("resume: invalid card or adapter\n"); return 0; } } else { pr_err("resume: sdio_func is not specified\n"); return 0; } adapter = card->adapter; if (!adapter->is_suspended) { dev_warn(adapter->dev, "device already resumed\n"); return 0; } adapter->is_suspended = false; for (i = 0; i < adapter->priv_num; i++) if (adapter->priv[i]->media_connected) netif_carrier_on(adapter->priv[i]->netdev); mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_ASYNC_CMD); return 0; }
/* * SDIO remove. * * This function removes the interface and frees up the card structure. */ static void mwifiex_sdio_remove(struct sdio_func *func) { struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; struct mwifiex_private *priv; int i; pr_debug("info: SDIO func num=%d\n", func->num); card = sdio_get_drvdata(func); if (!card) return; adapter = card->adapter; if (!adapter || !adapter->priv_num) return; /* In case driver is removed when asynchronous FW load is in progress */ wait_for_completion(&adapter->fw_load); if (user_rmmod) { if (adapter->is_suspended) mwifiex_sdio_resume(adapter->dev); for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); mwifiex_disable_auto_ds(priv); mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); } mwifiex_remove_card(card->adapter, &add_remove_card_sem); kfree(card); }
static void mwifiex_pcie_remove(struct pci_dev *pdev) { struct pcie_service_card *card; struct mwifiex_adapter *adapter; struct mwifiex_private *priv; int i; card = pci_get_drvdata(pdev); if (!card) return; adapter = card->adapter; if (!adapter || !adapter->priv_num) return; if (user_rmmod) { #ifdef CONFIG_PM if (adapter->is_suspended) mwifiex_pcie_resume(pdev); #endif for (i = 0; i < adapter->priv_num; i++) if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) && adapter->priv[i]->media_connected) mwifiex_deauthenticate(adapter->priv[i], NULL); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); mwifiex_disable_auto_ds(priv); mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); } mwifiex_remove_card(card->adapter, &add_remove_card_sem); kfree(card); }
void mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter) { struct usb_card_rec *card = adapter->card; struct mwifiex_private *priv; u16 tx_buf_size; int i, ret; card->mc_resync_flag = true; for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { if (atomic_read(&card->port[i].tx_data_urb_pending)) { mwifiex_dbg(adapter, WARN, "pending data urb in sys\n"); return; } } card->mc_resync_flag = false; tx_buf_size = 0xffff; priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, HostCmd_ACT_GEN_SET, 0, &tx_buf_size, false); if (ret) mwifiex_dbg(adapter, ERROR, "send reconfig tx buf size cmd err\n"); }
/* * The main process. * * This function is the main procedure of the driver and handles various driver * operations. It runs in a loop and provides the core functionalities. * * The main responsibilities of this function are - * - Ensure concurrency control * - Handle pending interrupts and call interrupt handlers * - Wake up the card if required * - Handle command responses and call response handlers * - Handle events and call event handlers * - Execute pending commands * - Transmit pending data packets */ int mwifiex_main_process(struct mwifiex_adapter *adapter) { int ret = 0; unsigned long flags; struct sk_buff *skb; spin_lock_irqsave(&adapter->main_proc_lock, flags); /* Check if already processing */ if (adapter->mwifiex_processing) { spin_unlock_irqrestore(&adapter->main_proc_lock, flags); goto exit_main_proc; } else { adapter->mwifiex_processing = true; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); } process_start: do { if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) || (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) break; /* Handle pending interrupt if any */ if (adapter->int_status) { if (adapter->hs_activated) mwifiex_process_hs_config(adapter); if (adapter->if_ops.process_int_status) adapter->if_ops.process_int_status(adapter); } /* Need to wake up the card ? */ if ((adapter->ps_state == PS_STATE_SLEEP) && (adapter->pm_wakeup_card_req && !adapter->pm_wakeup_fw_try) && (is_command_pending(adapter) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; adapter->if_ops.wakeup(adapter); continue; } if (IS_CARD_RX_RCVD(adapter)) { adapter->pm_wakeup_fw_try = false; if (adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; } else { /* We have tried to wakeup the card already */ if (adapter->pm_wakeup_fw_try) break; if (adapter->ps_state != PS_STATE_AWAKE || adapter->tx_lock_flag) break; if ((adapter->scan_processing && !adapter->scan_delay_cnt) || adapter->data_sent || mwifiex_wmm_lists_empty(adapter)) { if (adapter->cmd_sent || adapter->curr_cmd || (!is_command_pending(adapter))) break; } } /* Check Rx data for USB */ if (adapter->iface_type == MWIFIEX_USB) while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) mwifiex_handle_rx_packet(adapter, skb); /* Check for Cmd Resp */ if (adapter->cmd_resp_received) { adapter->cmd_resp_received = false; mwifiex_process_cmdresp(adapter); /* call mwifiex back when init_fw is done */ if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { adapter->hw_status = MWIFIEX_HW_STATUS_READY; mwifiex_init_fw_complete(adapter); } } /* Check for event */ if (adapter->event_received) { adapter->event_received = false; mwifiex_process_event(adapter); } /* Check if we need to confirm Sleep Request received previously */ if (adapter->ps_state == PS_STATE_PRE_SLEEP) { if (!adapter->cmd_sent && !adapter->curr_cmd) mwifiex_check_ps_cond(adapter); } /* * The ps_state may have been changed during processing of * Sleep Request event. */ if ((adapter->ps_state == PS_STATE_SLEEP) || (adapter->ps_state == PS_STATE_PRE_SLEEP) || (adapter->ps_state == PS_STATE_SLEEP_CFM) || adapter->tx_lock_flag) continue; if (!adapter->cmd_sent && !adapter->curr_cmd) { if (mwifiex_exec_next_cmd(adapter) == -1) { ret = -1; break; } } if ((!adapter->scan_processing || adapter->scan_delay_cnt) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { adapter->is_hs_configured = false; mwifiex_hs_activated_event (mwifiex_get_priv (adapter, MWIFIEX_BSS_ROLE_ANY), false); } } if (adapter->delay_null_pkt && !adapter->cmd_sent && !adapter->curr_cmd && !is_command_pending(adapter) && mwifiex_wmm_lists_empty(adapter)) { if (!mwifiex_send_null_packet (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) { adapter->delay_null_pkt = false; adapter->ps_state = PS_STATE_SLEEP; } break; } } while (true); if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter)) goto process_start; spin_lock_irqsave(&adapter->main_proc_lock, flags); adapter->mwifiex_processing = false; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); exit_main_proc: if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) mwifiex_shutdown_drv(adapter); return ret; }
/* * This function sends domain information to the firmware. * * The following information are passed to the firmware - * - Country codes * - Sub bands (first channel, number of channels, maximum Tx power) */ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) { u8 no_of_triplet = 0; struct ieee80211_country_ie_triplet *t; u8 no_of_parsed_chan = 0; u8 first_chan = 0, next_chan = 0, max_pwr = 0; u8 i, flag = 0; enum ieee80211_band band; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; /* Set country code */ domain_info->country_code[0] = adapter->country_code[0]; domain_info->country_code[1] = adapter->country_code[1]; domain_info->country_code[2] = ' '; band = mwifiex_band_to_radio_type(adapter->config_bands); if (!wiphy->bands[band]) { wiphy_err(wiphy, "11D: setting domain info in FW\n"); return -1; } sband = wiphy->bands[band]; for (i = 0; i < sband->n_channels ; i++) { ch = &sband->channels[i]; if (ch->flags & IEEE80211_CHAN_DISABLED) continue; if (!flag) { flag = 1; first_chan = (u32) ch->hw_value; next_chan = first_chan; max_pwr = ch->max_power; no_of_parsed_chan = 1; continue; } if (ch->hw_value == next_chan + 1 && ch->max_power == max_pwr) { next_chan++; no_of_parsed_chan++; } else { t = &domain_info->triplet[no_of_triplet]; t->chans.first_channel = first_chan; t->chans.num_channels = no_of_parsed_chan; t->chans.max_power = max_pwr; no_of_triplet++; first_chan = (u32) ch->hw_value; next_chan = first_chan; max_pwr = ch->max_power; no_of_parsed_chan = 1; } } if (flag) { t = &domain_info->triplet[no_of_triplet]; t->chans.first_channel = first_chan; t->chans.num_channels = no_of_parsed_chan; t->chans.max_power = max_pwr; no_of_triplet++; } domain_info->no_of_triplet = no_of_triplet; priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "11D: setting domain info in FW\n"); return -1; } return 0; }
/* * The main process. * * This function is the main procedure of the driver and handles various driver * operations. It runs in a loop and provides the core functionalities. * * The main responsibilities of this function are - * - Ensure concurrency control * - Handle pending interrupts and call interrupt handlers * - Wake up the card if required * - Handle command responses and call response handlers * - Handle events and call event handlers * - Execute pending commands * - Transmit pending data packets */ int mwifiex_main_process(struct mwifiex_adapter *adapter) { int ret = 0; unsigned long flags; spin_lock_irqsave(&adapter->main_proc_lock, flags); /* Check if already processing */ if (adapter->mwifiex_processing) { spin_unlock_irqrestore(&adapter->main_proc_lock, flags); goto exit_main_proc; } else { adapter->mwifiex_processing = true; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); } process_start: do { if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) || (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)) break; /* For non-USB interfaces, If we process interrupts first, it * would increase RX pending even further. Avoid this by * checking if rx_pending has crossed high threshold and * schedule rx work queue and then process interrupts. * For USB interface, there are no interrupts. We already have * HIGH_RX_PENDING check in usb.c */ if (atomic_read(&adapter->rx_pending) >= HIGH_RX_PENDING && adapter->iface_type != MWIFIEX_USB) { adapter->delay_main_work = true; if (!adapter->rx_processing) queue_work(adapter->rx_workqueue, &adapter->rx_work); break; } /* Handle pending interrupt if any */ if (adapter->int_status) { if (adapter->hs_activated) mwifiex_process_hs_config(adapter); if (adapter->if_ops.process_int_status) adapter->if_ops.process_int_status(adapter); } if (adapter->rx_work_enabled && adapter->data_received) queue_work(adapter->rx_workqueue, &adapter->rx_work); /* Need to wake up the card ? */ if ((adapter->ps_state == PS_STATE_SLEEP) && (adapter->pm_wakeup_card_req && !adapter->pm_wakeup_fw_try) && (is_command_pending(adapter) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; adapter->if_ops.wakeup(adapter); continue; } if (IS_CARD_RX_RCVD(adapter)) { adapter->data_received = false; adapter->pm_wakeup_fw_try = false; if (adapter->ps_state == PS_STATE_SLEEP) adapter->ps_state = PS_STATE_AWAKE; } else { /* We have tried to wakeup the card already */ if (adapter->pm_wakeup_fw_try) break; if (adapter->ps_state != PS_STATE_AWAKE || adapter->tx_lock_flag) break; if ((!adapter->scan_chan_gap_enabled && adapter->scan_processing) || adapter->data_sent || mwifiex_wmm_lists_empty(adapter)) { if (adapter->cmd_sent || adapter->curr_cmd || (!is_command_pending(adapter))) break; } } /* Check for event */ if (adapter->event_received) { adapter->event_received = false; mwifiex_process_event(adapter); } /* Check for Cmd Resp */ if (adapter->cmd_resp_received) { adapter->cmd_resp_received = false; mwifiex_process_cmdresp(adapter); /* call mwifiex back when init_fw is done */ if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) { adapter->hw_status = MWIFIEX_HW_STATUS_READY; mwifiex_init_fw_complete(adapter); } } /* Check if we need to confirm Sleep Request received previously */ if (adapter->ps_state == PS_STATE_PRE_SLEEP) { if (!adapter->cmd_sent && !adapter->curr_cmd) mwifiex_check_ps_cond(adapter); } /* * The ps_state may have been changed during processing of * Sleep Request event. */ if ((adapter->ps_state == PS_STATE_SLEEP) || (adapter->ps_state == PS_STATE_PRE_SLEEP) || (adapter->ps_state == PS_STATE_SLEEP_CFM) || adapter->tx_lock_flag) continue; if (!adapter->cmd_sent && !adapter->curr_cmd) { if (mwifiex_exec_next_cmd(adapter) == -1) { ret = -1; break; } } if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { adapter->is_hs_configured = false; mwifiex_hs_activated_event (mwifiex_get_priv (adapter, MWIFIEX_BSS_ROLE_ANY), false); } } if (adapter->delay_null_pkt && !adapter->cmd_sent && !adapter->curr_cmd && !is_command_pending(adapter) && mwifiex_wmm_lists_empty(adapter)) { if (!mwifiex_send_null_packet (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET | MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) { adapter->delay_null_pkt = false; adapter->ps_state = PS_STATE_SLEEP; } break; } } while (true); spin_lock_irqsave(&adapter->main_proc_lock, flags); if (!adapter->delay_main_work && (adapter->int_status || IS_CARD_RX_RCVD(adapter))) { spin_unlock_irqrestore(&adapter->main_proc_lock, flags); goto process_start; } adapter->mwifiex_processing = false; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); exit_main_proc: if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) mwifiex_shutdown_drv(adapter); return ret; }
/* * Sends IOCTL request to cancel the existing Host Sleep configuration. * * This function allocates the IOCTL request buffer, fills it * with requisite parameters and calls the IOCTL handler. */ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) { struct mwifiex_ds_hs_cfg hscfg; struct mwifiex_private *priv; int i; if (disconnect_on_suspend) { for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; if (priv) mwifiex_deauthenticate(priv, NULL); } } priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); if (priv && priv->sched_scanning) { #ifdef CONFIG_PM if (priv->wdev.wiphy->wowlan_config && !priv->wdev.wiphy->wowlan_config->nd_config) { #endif mwifiex_dbg(adapter, CMD, "aborting bgscan!\n"); mwifiex_stop_bg_scan(priv); cfg80211_sched_scan_stopped(priv->wdev.wiphy); #ifdef CONFIG_PM } #endif } if (adapter->hs_activated) { mwifiex_dbg(adapter, CMD, "cmd: HS Already activated\n"); return true; } adapter->hs_activate_wait_q_woken = false; memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); hscfg.is_invoke_hostcmd = true; adapter->hs_enabling = true; mwifiex_cancel_all_pending_cmd(adapter); if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, &hscfg)) { mwifiex_dbg(adapter, ERROR, "IOCTL request HS enable failed\n"); return false; } if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q, adapter->hs_activate_wait_q_woken, (10 * HZ)) <= 0) { mwifiex_dbg(adapter, ERROR, "hs_activate_wait_q terminated\n"); return false; } return true; }