static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state) { struct mwifiex_adapter *adapter; struct pcie_service_card *card; int hs_actived, 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; hs_actived = mwifiex_enable_hs(adapter); adapter->is_suspended = true; for (i = 0; i < adapter->priv_num; i++) netif_carrier_off(adapter->priv[i]->netdev); return 0; }
/* Proc hscfg file write handler * This function can be used to configure the host sleep parameters. */ static ssize_t mwifiex_hscfg_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct mwifiex_private *priv = (void *)file->private_data; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1); int ret, arg_num; struct mwifiex_ds_hs_cfg hscfg; int conditions = HS_CFG_COND_DEF; u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; if (!buf) return -ENOMEM; if (copy_from_user(buf, ubuf, buf_size)) { ret = -EFAULT; goto done; } arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); if (arg_num > 3) { mwifiex_dbg(priv->adapter, ERROR, "Too many arguments\n"); ret = -EINVAL; goto done; } if (arg_num >= 1 && arg_num < 3) mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, MWIFIEX_SYNC_CMD, &hscfg); if (arg_num) { if (conditions == HS_CFG_CANCEL) { mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD); ret = count; goto done; } hscfg.conditions = conditions; } if (arg_num >= 2) hscfg.gpio = gpio; if (arg_num == 3) hscfg.gap = gap; hscfg.is_invoke_hostcmd = false; mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, &hscfg); mwifiex_enable_hs(priv->adapter); priv->adapter->hs_enabling = false; ret = count; done: free_page(addr); return ret; }
/* 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 suspended, this function allocates and sends a * 'host sleep activate' request to the firmware and turns off the traffic. */ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; struct usb_tx_data_port *port; int i, j; /* Might still be loading firmware */ wait_for_completion(&card->fw_done); adapter = card->adapter; if (!adapter) { dev_err(&intf->dev, "card is not valid\n"); return 0; } if (unlikely(adapter->is_suspended)) mwifiex_dbg(adapter, WARN, "Device already suspended\n"); /* Enable the Host Sleep */ if (!mwifiex_enable_hs(adapter)) { mwifiex_dbg(adapter, ERROR, "cmd: failed to suspend\n"); adapter->hs_enabling = false; return -EFAULT; } /* 'is_suspended' flag indicates device is suspended. * It must be set here before the usb_kill_urb() calls. Reason * is in the complete handlers, urb->status(= -ENOENT) and * this flag is used in combination to distinguish between a * 'suspended' state and a 'disconnect' one. */ adapter->is_suspended = true; adapter->hs_enabling = false; if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb) usb_kill_urb(card->rx_cmd.urb); if (atomic_read(&card->rx_data_urb_pending)) for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) if (card->rx_data_list[i].urb) usb_kill_urb(card->rx_data_list[i].urb); for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { port = &card->port[i]; for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { if (port->tx_data_list[j].urb) usb_kill_urb(port->tx_data_list[j].urb); } } if (card->tx_cmd.urb) usb_kill_urb(card->tx_cmd.urb); return 0; }
/* Proc hscfg file write handler * This function can be used to configure the host sleep parameters. */ static ssize_t mwifiex_hscfg_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct mwifiex_private *priv = (void *)file->private_data; char *buf; int ret, arg_num; struct mwifiex_ds_hs_cfg hscfg; int conditions = HS_CFG_COND_DEF; u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); if (IS_ERR(buf)) return PTR_ERR(buf); arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); if (arg_num > 3) { mwifiex_dbg(priv->adapter, ERROR, "Too many arguments\n"); ret = -EINVAL; goto done; } if (arg_num >= 1 && arg_num < 3) mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, MWIFIEX_SYNC_CMD, &hscfg); if (arg_num) { if (conditions == HS_CFG_CANCEL) { mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD); ret = count; goto done; } hscfg.conditions = conditions; } if (arg_num >= 2) hscfg.gpio = gpio; if (arg_num == 3) hscfg.gap = gap; hscfg.is_invoke_hostcmd = false; mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, &hscfg); mwifiex_enable_hs(priv->adapter); priv->adapter->hs_enabling = false; ret = count; done: kfree(buf); return ret; }
/* 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 suspended, this function allocates and sends a * 'host sleep activate' request to the firmware and turns off the traffic. */ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message) { struct usb_card_rec *card = usb_get_intfdata(intf); struct mwifiex_adapter *adapter; struct usb_tx_data_port *port; int i, j; 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)) mwifiex_dbg(adapter, WARN, "Device already suspended\n"); mwifiex_enable_hs(adapter); /* 'is_suspended' flag indicates device is suspended. * It must be set here before the usb_kill_urb() calls. Reason * is in the complete handlers, urb->status(= -ENOENT) and * this flag is used in combination to distinguish between a * 'suspended' state and a 'disconnect' one. */ adapter->is_suspended = true; adapter->hs_enabling = false; if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb) usb_kill_urb(card->rx_cmd.urb); if (atomic_read(&card->rx_data_urb_pending)) for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) if (card->rx_data_list[i].urb) usb_kill_urb(card->rx_data_list[i].urb); for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { port = &card->port[i]; for (j = 0; j < MWIFIEX_TX_DATA_URB; j++) { if (port->tx_data_list[j].urb) usb_kill_urb(port->tx_data_list[j].urb); } } if (card->tx_cmd.urb) usb_kill_urb(card->tx_cmd.urb); return 0; }
/* * SDIO suspend. * * 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 suspended, this function allocates and sends a host * sleep activate request to the firmware and turns off the traffic. */ static int mwifiex_sdio_suspend(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; int ret = 0; if (func) { pm_flag = sdio_get_host_pm_caps(func); pr_debug("cmd: %s: suspend: PM flag = 0x%x\n", sdio_func_id(func), pm_flag); if (!(pm_flag & MMC_PM_KEEP_POWER)) { pr_err("%s: cannot remain alive while host is" " suspended\n", sdio_func_id(func)); return -ENOSYS; } card = sdio_get_drvdata(func); if (!card || !card->adapter) { pr_err("suspend: invalid card or adapter\n"); return 0; } } else { pr_err("suspend: sdio_func is not specified\n"); return 0; } adapter = card->adapter; /* Enable the Host Sleep */ if (!mwifiex_enable_hs(adapter)) { dev_err(adapter->dev, "cmd: failed to suspend\n"); return -EFAULT; } dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n"); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); /* Indicate device suspended */ adapter->is_suspended = true; for (i = 0; i < adapter->priv_num; i++) netif_carrier_off(adapter->priv[i]->netdev); return ret; }
/* 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 suspended, this function allocates and sends a * 'host sleep activate' request to the firmware and turns off the traffic. */ static int mwifiex_usb_suspend(struct usb_interface *intf, pm_message_t message) { 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 suspended\n"); mwifiex_enable_hs(adapter); /* 'is_suspended' flag indicates device is suspended. * It must be set here before the usb_kill_urb() calls. Reason * is in the complete handlers, urb->status(= -ENOENT) and * this flag is used in combination to distinguish between a * 'suspended' state and a 'disconnect' one. */ adapter->is_suspended = true; for (i = 0; i < adapter->priv_num; i++) netif_carrier_off(adapter->priv[i]->netdev); if (atomic_read(&card->rx_cmd_urb_pending) && card->rx_cmd.urb) usb_kill_urb(card->rx_cmd.urb); if (atomic_read(&card->rx_data_urb_pending)) for (i = 0; i < MWIFIEX_RX_DATA_URB; i++) if (card->rx_data_list[i].urb) usb_kill_urb(card->rx_data_list[i].urb); for (i = 0; i < MWIFIEX_TX_DATA_URB; i++) if (card->tx_data_list[i].urb) usb_kill_urb(card->tx_data_list[i].urb); if (card->tx_cmd.urb) usb_kill_urb(card->tx_cmd.urb); return 0; }