Ejemplo n.º 1
0
/*
 * 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);
}
Ejemplo n.º 2
0
/*
 * 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);
}
Ejemplo n.º 3
0
/* 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);
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
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));
}
Ejemplo n.º 6
0
Archivo: usb.c Proyecto: 7799/linux
/* 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);
}
Ejemplo n.º 7
0
/*
 * 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;
}
Ejemplo n.º 9
0
Archivo: usb.c Proyecto: Lyude/linux
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));
}
Ejemplo n.º 10
0
/*
 * 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);
}
Ejemplo n.º 11
0
/* 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;
}
Ejemplo n.º 12
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);
}
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
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;
	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;
}
Ejemplo n.º 15
0
/* 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;
}
Ejemplo n.º 16
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);
}
Ejemplo n.º 17
0
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;
}
Ejemplo n.º 18
0
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;
}
Ejemplo n.º 19
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);
}
Ejemplo n.º 20
0
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);
}
Ejemplo n.º 21
0
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");
}
Ejemplo n.º 22
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;
	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;
}
Ejemplo n.º 23
0
/*
 * 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;
}
Ejemplo n.º 24
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;
}
Ejemplo n.º 25
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;
	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;
}