/drivers/net/wireless/mwifiex/sdio.c
C | 1754 lines | 1147 code | 278 blank | 329 comment | 197 complexity | b13016b7d391ccdad57ce787a30ff060 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
- /*
- * Marvell Wireless LAN device driver: SDIO specific handling
- *
- * Copyright (C) 2011, Marvell International Ltd.
- *
- * This software file (the "File") is distributed by Marvell International
- * Ltd. under the terms of the GNU General Public License Version 2, June 1991
- * (the "License"). You may use, redistribute and/or modify this File in
- * accordance with the terms and conditions of the License, a copy of which
- * is available by writing to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
- * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
- *
- * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
- * this warranty disclaimer.
- */
- #include <linux/firmware.h>
- #include "decl.h"
- #include "ioctl.h"
- #include "util.h"
- #include "fw.h"
- #include "main.h"
- #include "wmm.h"
- #include "11n.h"
- #include "sdio.h"
- #define SDIO_VERSION "1.0"
- static struct mwifiex_if_ops sdio_ops;
- static struct semaphore add_remove_card_sem;
- /*
- * SDIO probe.
- *
- * This function probes an mwifiex device and registers it. It allocates
- * the card structure, enables SDIO function number and initiates the
- * device registration and initialization procedure by adding a logical
- * interface.
- */
- static int
- mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
- {
- int ret;
- struct sdio_mmc_card *card = NULL;
- pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
- func->vendor, func->device, func->class, func->num);
- card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
- if (!card) {
- pr_err("%s: failed to alloc memory\n", __func__);
- return -ENOMEM;
- }
- card->func = func;
- func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
- sdio_claim_host(func);
- ret = sdio_enable_func(func);
- sdio_release_host(func);
- if (ret) {
- pr_err("%s: failed to enable function\n", __func__);
- kfree(card);
- return -EIO;
- }
- if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) {
- pr_err("%s: add card failed\n", __func__);
- kfree(card);
- sdio_claim_host(func);
- ret = sdio_disable_func(func);
- sdio_release_host(func);
- ret = -1;
- }
- return ret;
- }
- /*
- * 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;
- pr_debug("info: SDIO func num=%d\n", func->num);
- if (func) {
- card = sdio_get_drvdata(func);
- if (card) {
- mwifiex_remove_card(card->adapter,
- &add_remove_card_sem);
- kfree(card);
- }
- }
- }
- /*
- * 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 hs_actived = 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 */
- hs_actived = mwifiex_enable_hs(adapter);
- if (hs_actived) {
- pr_debug("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;
- }
- /*
- * 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;
- 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);
- /* Disable Host Sleep */
- mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
- MWIFIEX_ASYNC_CMD);
- return 0;
- }
- /* Device ID for SD8787 */
- #define SDIO_DEVICE_ID_MARVELL_8787 (0x9119)
- /* WLAN IDs */
- static const struct sdio_device_id mwifiex_ids[] = {
- {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)},
- {},
- };
- MODULE_DEVICE_TABLE(sdio, mwifiex_ids);
- static const struct dev_pm_ops mwifiex_sdio_pm_ops = {
- .suspend = mwifiex_sdio_suspend,
- .resume = mwifiex_sdio_resume,
- };
- static struct sdio_driver mwifiex_sdio = {
- .name = "mwifiex_sdio",
- .id_table = mwifiex_ids,
- .probe = mwifiex_sdio_probe,
- .remove = mwifiex_sdio_remove,
- .drv = {
- .owner = THIS_MODULE,
- .pm = &mwifiex_sdio_pm_ops,
- }
- };
- /*
- * This function writes data into SDIO card register.
- */
- static int