예제 #1
0
static int wl1271_suspend(struct device *dev)
{
	/* Tell MMC/SDIO core it's OK to power down the card
	 * (if it isn't already), but not to remove it completely */
	struct sdio_func *func = dev_to_sdio_func(dev);
	struct wl1271 *wl = sdio_get_drvdata(func);
	mmc_pm_flag_t sdio_flags;
	int ret = 0;

	wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d",
		     wl->wow_enabled);

	/* check whether sdio should keep power */
	if (wl->wow_enabled) {
		sdio_flags = sdio_get_host_pm_caps(func);

		if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
			wl1271_error("can't keep power while host "
				     "is suspended");
			ret = -EINVAL;
			goto out;
		}

		printk("\n\nSetting MMC_PM_KEEP_POWER\n");
		/* keep power while host suspended */
		ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
		if (ret) {
			wl1271_error("error while trying to keep power");
			goto out;
		}

		/* release host */
		sdio_release_host(func);
	}
out:
	return ret;
}
예제 #2
0
static int bcmsdh_sdmmc_suspend(struct device *pdev)
{
	int err;
	sdioh_info_t *sdioh;
	struct sdio_func *func = dev_to_sdio_func(pdev);
	mmc_pm_flag_t sdio_flags;

	dev_err(pdev,"%s(%d) [%08x]\n",__func__, __LINE__,(unsigned int*) pdev);
	sd_err(("%s Enter\n", __FUNCTION__));
	if (func->num != 2)
		return 0;

	sdioh = sdio_get_drvdata(func);
	err = bcmsdh_suspend(sdioh->bcmsdh);
	if (err)
		return err;

	sdio_flags = sdio_get_host_pm_caps(func);
	if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
		sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__));
		return  -EINVAL;
	}

	/* keep power while host suspended */
	err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
	if (err) {
		sd_err(("%s: error while trying to keep power\n", __FUNCTION__));
		return err;
	}
#if defined(OOB_INTR_ONLY)
	bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE);
#endif
	dhd_mmc_suspend = TRUE;
	smp_mb();

	return 0;
}
예제 #3
0
static void r8712s_dev_remove(struct sdio_func *func)
{
	_adapter *padapter = (_adapter*) (((struct dvobj_priv*)sdio_get_drvdata(func))->padapter);
	struct net_device *pnetdev = (struct net_device *)padapter->pnetdev;

_func_exit_;

	if (padapter)
	{
		RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n"));

//		padapter->bSurpriseRemoved = _TRUE;

		if (pnetdev)
			unregister_netdev(pnetdev); //will call netdev_close()

		cancel_all_timer(padapter);
		
		r871x_dev_unload(padapter);

		rtw_free_drv_sw(padapter);

		sdio_claim_host(func);
		RT_TRACE(_module_hci_intfs_c_,_drv_err_,(" in dev_remove():sdio_claim_host !\n"));
		sdio_release_irq(func);
		RT_TRACE(_module_hci_intfs_c_,_drv_err_,(" in dev_remove():sdio_release_irq !\n"));
		sdio_disable_func(func);
		RT_TRACE(_module_hci_intfs_c_,_drv_err_,(" in dev_remove():sdio_disable_func !\n"));
		sdio_release_host(func);
		RT_TRACE(_module_hci_intfs_c_,_drv_err_,(" in dev_remove():sdio_release_host !\n"));
	}
	RT_TRACE(_module_hci_intfs_c_,_drv_err_,("-dev_remove()\n"));

_func_exit_;

	return;
}
예제 #4
0
/**  @brief This function handles client driver resume
 *  
 *  @param dev	   A pointer to device structure
 *  @return 	   BT_STATUS_SUCCESS
 */
int
bt_sdio_resume(struct device *dev)
{
    struct sdio_func *func = dev_to_sdio_func(dev);
    mmc_pm_flag_t pm_flags = 0;
    bt_private *priv = NULL;
    struct sdio_mmc_card *cardp;
    struct hci_dev *hcidev;

    ENTER();
    if (func) {
        pm_flags = sdio_get_host_pm_caps(func);
        PRINTM(CMD, "BT: %s: resume: PM flags = 0x%x\n", sdio_func_id(func),
               pm_flags);
        cardp = sdio_get_drvdata(func);
        if (!cardp || !cardp->priv) {
            PRINTM(ERROR, "BT: Card or priv structure is not valid\n");
            LEAVE();
            return BT_STATUS_SUCCESS;
        }
    } else {
        PRINTM(ERROR, "BT: sdio_func is not specified\n");
        LEAVE();
        return BT_STATUS_SUCCESS;
    }
    priv = cardp->priv;
    priv->adapter->is_suspended = FALSE;
    hcidev = priv->bt_dev.hcidev;
    PRINTM(CMD, "BT %s: SDIO resume\n", hcidev->name);
    hci_resume_dev(hcidev);
    sbi_wakeup_firmware(priv);
    priv->adapter->hs_state = HS_DEACTIVATED;
    PRINTM(CMD, "BT:%s: HS DEACTIVATED in Resume!\n", hcidev->name);
    LEAVE();
    return BT_STATUS_SUCCESS;
}
예제 #5
0
/*
 * Process an interrupt from the SDIO card
 *
 * FIXME: need to process other events that are not just ready-to-read
 *
 * Checks there is data ready and then proceeds to read it.
 */
static
void i2400ms_irq(struct sdio_func *func)
{
	int ret;
	struct i2400ms *i2400ms = sdio_get_drvdata(func);
	struct device *dev = &func->dev;
	int val;

	d_fnstart(6, dev, "(i2400ms %p)\n", i2400ms);
	val = sdio_readb(func, I2400MS_INTR_STATUS_ADDR, &ret);
	if (ret < 0) {
		dev_err(dev, "RX: Can't read interrupt status: %d\n", ret);
		goto error_no_irq;
	}
	if (!val) {
		dev_err(dev, "RX: BUG? got IRQ but no interrupt ready?\n");
		goto error_no_irq;
	}
	sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret);
	i2400ms_rx(i2400ms);
error_no_irq:
	d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms);
	return;
}
예제 #6
0
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;

	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);
}
예제 #7
0
static void smssdio_interrupt(struct sdio_func *func)
{
    int ret, isr;

    struct smssdio_device *smsdev;
    struct smscore_buffer_t *cb;
    struct SmsMsgHdr_ST *hdr;
    size_t size;

    smsdev = sdio_get_drvdata(func);

    /*
     * The interrupt register has no defined meaning. It is just
     * a way of turning of the level triggered interrupt.
     */
    isr = sdio_readb(func, SMSSDIO_INT, &ret);
    if (ret) {
        dev_err(&smsdev->func->dev,
                "Unable to read interrupt register!\n");
        return;
    }

    if (smsdev->split_cb == NULL) {
        cb = smscore_getbuffer(smsdev->coredev);
        if (!cb) {
            dev_err(&smsdev->func->dev,
                    "Unable to allocate data buffer!\n");
            return;
        }

        ret = sdio_read_blocks(smsdev->func, cb->p, SMSSDIO_DATA, 1);
        if (ret) {
            dev_err(&smsdev->func->dev,
                    "Error %d reading initial block!\n", ret);
            return;
        }

        hdr = cb->p;

        if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
            smsdev->split_cb = cb;
            return;
        }

        size = hdr->msgLength - smsdev->func->cur_blksize;
    } else {
        cb = smsdev->split_cb;
        hdr = cb->p;

        size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);

        smsdev->split_cb = NULL;
    }

    if (hdr->msgLength > smsdev->func->cur_blksize) {
        void *buffer;

        size = ALIGN(size, 128);
        buffer = cb->p + hdr->msgLength;

        BUG_ON(smsdev->func->cur_blksize != 128);

        /*
         * First attempt to transfer all of it in one go...
         */
        ret = sdio_read_blocks(smsdev->func, buffer,
                               SMSSDIO_DATA, size / 128);
        if (ret && ret != -EINVAL) {
            smscore_putbuffer(smsdev->coredev, cb);
            dev_err(&smsdev->func->dev,
                    "Error %d reading data from card!\n", ret);
            return;
        }

        /*
         * ..then fall back to one block at a time if that is
         * not possible...
         *
         * (we have to do this manually because of the
         * problem with the "increase address" bit)
         */
        if (ret == -EINVAL) {
            while (size) {
                ret = sdio_read_blocks(smsdev->func,
                                       buffer, SMSSDIO_DATA, 1);
                if (ret) {
                    smscore_putbuffer(smsdev->coredev, cb);
                    dev_err(&smsdev->func->dev,
                            "Error %d reading "
                            "data from card!\n", ret);
                    return;
                }

                buffer += smsdev->func->cur_blksize;
                if (size > smsdev->func->cur_blksize)
                    size -= smsdev->func->cur_blksize;
                else
                    size = 0;
            }
        }
    }

    cb->size = hdr->msgLength;
    cb->offset = 0;

    smscore_onresponse(smsdev->coredev, cb);
}
예제 #8
0
/**  @brief This function handles client driver suspend
 *  
 *  @param dev	   A pointer to device structure
 *  @return 	   BT_STATUS_SUCCESS or other error no.
 */
int
bt_sdio_suspend(struct device *dev)
{
    struct sdio_func *func = dev_to_sdio_func(dev);
    mmc_pm_flag_t pm_flags = 0;
    bt_private *priv = NULL;
    struct sdio_mmc_card *cardp;
    struct hci_dev *hcidev;

    ENTER();

    if (func) {
        pm_flags = sdio_get_host_pm_caps(func);
        PRINTM(CMD, "BT: %s: suspend: PM flags = 0x%x\n", sdio_func_id(func),
               pm_flags);
        if (!(pm_flags & MMC_PM_KEEP_POWER)) {
            PRINTM(ERROR,
                   "BT: %s: cannot remain alive while host is suspended\n",
                   sdio_func_id(func));
            return -ENOSYS;
        }
        cardp = sdio_get_drvdata(func);
        if (!cardp || !cardp->priv) {
            PRINTM(ERROR, "BT: Card or priv structure is not valid\n");
            LEAVE();
            return BT_STATUS_SUCCESS;
        }
    } else {
        PRINTM(ERROR, "BT: sdio_func is not specified\n");
        LEAVE();
        return BT_STATUS_SUCCESS;
    }
    priv = cardp->priv;

    if ((pm_keep_power) && (priv->adapter->hs_state != HS_ACTIVATED)) {
        if (BT_STATUS_SUCCESS != bt_enable_hs(priv)) {
            PRINTM(CMD, "BT: HS not actived, suspend fail!\n");
            LEAVE();
            return -EBUSY;
        }
    }
    hcidev = priv->bt_dev.hcidev;
    PRINTM(CMD, "BT %s: SDIO suspend\n", hcidev->name);
    hci_suspend_dev(hcidev);
    skb_queue_purge(&priv->adapter->tx_queue);

    priv->adapter->is_suspended = TRUE;
    LEAVE();
    /* We will keep the power when hs enabled successfully */
    if ((pm_keep_power) && (priv->adapter->hs_state == HS_ACTIVATED)) {
#ifdef MMC_PM_SKIP_RESUME_PROBE
        PRINTM(CMD, "BT: suspend with MMC_PM_KEEP_POWER and "
               "MMC_PM_SKIP_RESUME_PROBE\n");
        return sdio_set_host_pm_flags(func,
                                      MMC_PM_KEEP_POWER |
                                      MMC_PM_SKIP_RESUME_PROBE);
#else
        PRINTM(CMD, "BT: suspend with MMC_PM_KEEP_POWER\n");
        return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
#endif
    } else {
        PRINTM(CMD, "BT: suspend without MMC_PM_KEEP_POWER\n");
        return BT_STATUS_SUCCESS;
    }
}
예제 #9
0
파일: sdio.c 프로젝트: CSCLOG/beaglebone
static void iwm_sdio_isr(struct sdio_func *func)
{
	struct iwm_priv *iwm;
	struct iwm_sdio_priv *hw;
	struct iwm_rx_info *rx_info;
	struct sk_buff *skb;
	unsigned long buf_size, read_size;
	int ret;
	u8 val;

	hw = sdio_get_drvdata(func);
	iwm = hw_to_iwm(hw);

	buf_size = hw->blk_size;

	/* We're checking the status */
	val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret);
	if (val == 0 || ret < 0) {
		IWM_ERR(iwm, "Wrong INTR_STATUS\n");
		return;
	}

	/* See if we have free buffers */
	if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) {
		IWM_ERR(iwm, "No buffer for more Rx frames\n");
		return;
	}

	/* We first read the transaction size */
	read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret);
	read_size = read_size << 8;

	if (ret < 0) {
		IWM_ERR(iwm, "Couldn't read the xfer size\n");
		return;
	}

	/* We need to clear the INT register */
	sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret);
	if (ret < 0) {
		IWM_ERR(iwm, "Couldn't clear the INT register\n");
		return;
	}

	while (buf_size < read_size)
		buf_size <<= 1;

	skb = dev_alloc_skb(buf_size);
	if (!skb) {
		IWM_ERR(iwm, "Couldn't alloc RX skb\n");
		return;
	}
	rx_info = skb_to_rx_info(skb);
	rx_info->rx_size = read_size;
	rx_info->rx_buf_size = buf_size;

	/* Now we can read the actual buffer */
	ret = sdio_memcpy_fromio(func, skb_put(skb, read_size),
				 IWM_SDIO_DATA_ADDR, read_size);

	/* The skb is put on a driver's specific Rx SKB list */
	skb_queue_tail(&iwm->rx_list, skb);

	/* We can now schedule the actual worker */
	queue_work(hw->isr_wq, &hw->isr_worker);
}
예제 #10
0
static void ks_sdio_interrupt(struct sdio_func *func)
{
	int retval;
	struct ks_sdio_card *card;
	struct ks_wlan_private *priv;
	unsigned char status, rsize, rw_data;

	card = sdio_get_drvdata(func);
	priv = card->priv;
	DPRINTK(4, "\n");

	if (priv->dev_state >= DEVICE_STATE_BOOT) {
		retval =
		    ks7010_sdio_read(priv, INT_PENDING, &status,
				     sizeof(status));
		if (retval) {
			DPRINTK(1, "read INT_PENDING Failed!!(%d)\n", retval);
			goto intr_out;
		}
		DPRINTK(4, "INT_PENDING=%02X\n", rw_data);

		/* schedule task for interrupt status */
		/* bit7 -> Write General Communication B register */
		/* read (General Communication B register) */
		/* bit5 -> Write Status Idle */
		/* bit2 -> Read Status Busy  */
		if (status & INT_GCR_B
		    || atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
			retval =
			    ks7010_sdio_read(priv, GCR_B, &rw_data,
					     sizeof(rw_data));
			if (retval) {
				DPRINTK(1, " error : GCR_B=%02X\n", rw_data);
				goto intr_out;
			}
			/* DPRINTK(1, "GCR_B=%02X\n", rw_data); */
			if (rw_data == GCR_B_ACTIVE) {
				if (atomic_read(&priv->psstatus.status) ==
				    PS_SNOOZE) {
					atomic_set(&priv->psstatus.status,
						   PS_WAKEUP);
					priv->wakeup_count = 0;
				}
				complete(&priv->psstatus.wakeup_wait);
			}

		}

		do {
			/* read (WriteStatus/ReadDataSize FN1:00_0014) */
			retval =
			    ks7010_sdio_read(priv, WSTATUS_RSIZE, &rw_data,
					     sizeof(rw_data));
			if (retval) {
				DPRINTK(1, " error : WSTATUS_RSIZE=%02X\n",
					rw_data);
				goto intr_out;
			}
			DPRINTK(4, "WSTATUS_RSIZE=%02X\n", rw_data);
			rsize = rw_data & RSIZE_MASK;
			if (rsize) {	/* Read schedule */
				ks_wlan_hw_rx((void *)priv,
					      (uint16_t) (((rsize) << 4)));
			}
			if (rw_data & WSTATUS_MASK) {
#if 0
				if (status & INT_WRITE_STATUS
				    && !cnt_txqbody(priv)) {
					/* dummy write for interrupt clear */
					rw_data = 0;
					retval =
					    ks7010_sdio_write(priv, DATA_WINDOW,
							      &rw_data,
							      sizeof(rw_data));
					if (retval) {
						DPRINTK(1,
							"write DATA_WINDOW Failed!!(%d)\n",
							retval);
					}
					status &= ~INT_WRITE_STATUS;
				} else {
#endif
					if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
						if (cnt_txqbody(priv)) {
							ks_wlan_hw_wakeup_request(priv);
							queue_delayed_work
							    (priv->ks_wlan_hw.
							     ks7010sdio_wq,
							     &priv->ks_wlan_hw.
							     rw_wq, 1);
							return;
						}
					} else {
						tx_device_task((void *)priv);
					}
#if 0
				}
#endif
			}
		} while (rsize);
	}

 intr_out:
	queue_delayed_work(priv->ks_wlan_hw.ks7010sdio_wq,
			   &priv->ks_wlan_hw.rw_wq, 0);
	return;
}
예제 #11
0
static void iwm_sdio_isr(struct sdio_func *func)
{
	struct iwm_priv *iwm;
	struct iwm_sdio_priv *hw;
	struct iwm_rx_info *rx_info;
	struct sk_buff *skb;
	unsigned long buf_size, read_size;
	int ret;
	u8 val;

	hw = sdio_get_drvdata(func);
	iwm = hw_to_iwm(hw);

	buf_size = hw->blk_size;

	
	val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret);
	if (val == 0 || ret < 0) {
		IWM_ERR(iwm, "Wrong INTR_STATUS\n");
		return;
	}

	
	if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) {
		IWM_ERR(iwm, "No buffer for more Rx frames\n");
		return;
	}

	
	read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret);
	read_size = read_size << 8;

	if (ret < 0) {
		IWM_ERR(iwm, "Couldn't read the xfer size\n");
		return;
	}

	
	sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret);
	if (ret < 0) {
		IWM_ERR(iwm, "Couldn't clear the INT register\n");
		return;
	}

	while (buf_size < read_size)
		buf_size <<= 1;

	skb = dev_alloc_skb(buf_size);
	if (!skb) {
		IWM_ERR(iwm, "Couldn't alloc RX skb\n");
		return;
	}
	rx_info = skb_to_rx_info(skb);
	rx_info->rx_size = read_size;
	rx_info->rx_buf_size = buf_size;

	
	ret = sdio_memcpy_fromio(func, skb_put(skb, read_size),
				 IWM_SDIO_DATA_ADDR, read_size);

	
	skb_queue_tail(&iwm->rx_list, skb);

	
	queue_work(hw->isr_wq, &hw->isr_worker);
}
예제 #12
0
파일: hif.c 프로젝트: CSCLOG/beaglebone
static struct hif_device *ath6kl_get_hifdev(struct sdio_func *func)
{
	return (struct hif_device *) sdio_get_drvdata(func);
}
예제 #13
0
static void ks7010_sdio_remove(struct sdio_func *func)
{
	int ret;
	struct ks_sdio_card *card;
	struct ks_wlan_private *priv;
	struct net_device *netdev;
	DPRINTK(1, "ks7010_sdio_remove()\n");

	card = sdio_get_drvdata(func);

	if (card == NULL)
		return;

	DPRINTK(1, "priv = card->priv\n");
	priv = card->priv;
	netdev = priv->net_dev;
	if (priv) {
		ks_wlan_net_stop(netdev);
		DPRINTK(1, "ks_wlan_net_stop\n");

		/* interrupt disable */
		sdio_claim_host(func);
		sdio_writeb(func, 0, INT_ENABLE, &ret);
		sdio_writeb(func, 0xff, INT_PENDING, &ret);
		sdio_release_host(func);
		DPRINTK(1, "interrupt disable\n");

		/* send stop request to MAC */
		{
			struct hostif_stop_request_t *pp;
			pp = (struct hostif_stop_request_t *)
			    kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL);
			if (pp == NULL) {
				DPRINTK(3, "allocate memory failed..\n");
				return;	/* to do goto ni suru */
			}
			pp->header.size =
			    cpu_to_le16((uint16_t)
					(sizeof(*pp) -
					 sizeof(pp->header.size)));
			pp->header.event = cpu_to_le16((uint16_t) HIF_STOP_REQ);

			sdio_claim_host(func);
			write_to_device(priv, (unsigned char *)pp,
					hif_align_size(sizeof(*pp)));
			sdio_release_host(func);
			kfree(pp);
		}
		DPRINTK(1, "STOP Req\n");

		if (priv->ks_wlan_hw.ks7010sdio_wq) {
			flush_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);
			destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);
		}
		DPRINTK(1,
			"destroy_workqueue(priv->ks_wlan_hw.ks7010sdio_wq);\n");

		hostif_exit(priv);
		DPRINTK(1, "hostif_exit\n");

		unregister_netdev(netdev);

		trx_device_exit(priv);
		if (priv->ks_wlan_hw.read_buf) {
			kfree(priv->ks_wlan_hw.read_buf);
		}
		free_netdev(priv->net_dev);
		card->priv = NULL;
	}

	sdio_claim_host(func);
	sdio_release_irq(func);
	DPRINTK(1, "sdio_release_irq()\n");
	sdio_disable_func(func);
	DPRINTK(1, "sdio_disable_func()\n");
	sdio_release_host(func);

	sdio_set_drvdata(func, NULL);

	kfree(card);
	DPRINTK(1, "kfree()\n");

	DPRINTK(5, " Bye !!\n");
	return;
}
예제 #14
0
static void rtw_dev_remove(struct sdio_func *func)
{
	PADAPTER padapter;
	struct net_device *pnetdev;
#ifdef CONFIG_IOCTL_CFG80211
	struct wireless_dev *wdev;
#endif

_func_enter_;

	RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("+rtw_dev_remove\n"));

	padapter = ((struct dvobj_priv*)sdio_get_drvdata(func))->padapter;
#ifdef CONFIG_IOCTL_CFG80211
	wdev = padapter->rtw_wdev;
#endif

#if defined(CONFIG_HAS_EARLYSUSPEND ) || defined(CONFIG_ANDROID_POWER)
	rtw_unregister_early_suspend(&padapter->pwrctrlpriv);
#endif

	if (padapter->bSurpriseRemoved == _FALSE)
	{
		// test surprise remove
		int err;

		sdio_claim_host(func);
		sdio_readb(func, 0, &err);
		sdio_release_host(func);
		if (err == -ENOMEDIUM) {
			padapter->bSurpriseRemoved = _TRUE;
			DBG_871X(KERN_NOTICE "%s: device had been removed!\n", __func__);
		}
	}

#ifdef CONFIG_HOSTAPD_MLME
	hostapd_mode_unload(padapter);
#endif
	LeaveAllPowerSaveMode(padapter);

	pnetdev = (struct net_device*)padapter->pnetdev;
	if (pnetdev) {
		unregister_netdev(pnetdev); //will call netdev_close()
		RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("rtw_dev_remove: unregister netdev\n"));
#ifdef CONFIG_PROC_DEBUG
		rtw_proc_remove_one(pnetdev);
#endif
	} else {
		RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("rtw_dev_remove: NO padapter->pnetdev!\n"));
	}

	rtw_cancel_all_timer(padapter);

	rtw_dev_unload(padapter);

	// interface deinit
	sdio_deinit(padapter);
	RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("rtw_dev_remove: deinit intf complete!\n"));

	rtw_free_drv_sw(padapter);

#ifdef CONFIG_IOCTL_CFG80211
	rtw_wdev_free(wdev);
#endif

	RT_TRACE(_module_hci_intfs_c_, _drv_notice_, ("-rtw_dev_remove\n"));

_func_exit_;
}
예제 #15
0
static int sqn_handle_mac_addr_tag(struct sdio_func *func, u8 *data, u32 length)
{
	int rv = 0;
	struct sqn_private *priv =
		((struct sqn_sdio_card *)sdio_get_drvdata(func))->priv;

	sqn_pr_enter();

	/*
	 * This tag could contain one or two mac addresses in string
	 * form, delimited by some symbol (space or something else).
	 * Each mac address written as a string has constant length.
	 * Thus we can determine the number of mac addresses by the
	 * length of the tag:
	 *
	 * mac addr length in string form: XX:XX:XX:XX:XX:XX = 17 bytes
	 * tag length: 17 bytes [ + 1 byte + 17 bytes ]
	 */

#define MAC_ADDR_STRING_LEN	17

	/*
	 * If we have only one mac addr we should increment it by one
	 * and use it.
	 * If we have two mac addresses we should use a second one.
	 */

	if (MAC_ADDR_STRING_LEN <= length
		&& length < 2 * MAC_ADDR_STRING_LEN + 1)
	{
		sqn_pr_dbg("single mac address\n");
		/* we have only one mac addr */
		get_mac_addr_from_str(data, length, priv->mac_addr);

		// Andrew 0720
		// ++(priv->mac_addr[ETH_ALEN - 1])
		// real MAC: 38:E6:D8:86:00:00 
		// hboot will store: 38:E6:D8:85:FF:FF (minus 1)
		// sdio need to recovery it by plusing 1: 38:E6:D8:86:00:00 (plus 1)

		if ((++(priv->mac_addr[ETH_ALEN - 1])) == 0x00)
			if ((++(priv->mac_addr[ETH_ALEN - 2])) == 0x00)
				if ((++(priv->mac_addr[ETH_ALEN - 3])) == 0x00)
					if ((++(priv->mac_addr[ETH_ALEN - 4])) == 0x00)
						if ((++(priv->mac_addr[ETH_ALEN - 5])) == 0x00)
							++(priv->mac_addr[ETH_ALEN - 6]);

	}
	else if (2 * MAC_ADDR_STRING_LEN + 1 == length) { /* we have two macs */
		sqn_pr_dbg("two mac addresses, using second\n");
		get_mac_addr_from_str(data + MAC_ADDR_STRING_LEN + 1
			, length - (MAC_ADDR_STRING_LEN + 1), priv->mac_addr);
	}
	else { /* incorrect data length */
		sqn_pr_err("can't get mac address from bootloader"
			" - incorrect mac address length\n");
		rv = -1;
		goto out;
	}

	sqn_pr_info("setting MAC address from bootloader: "
		"%02x:%02x:%02x:%02x:%02x:%02x\n", priv->mac_addr[0]
		, priv->mac_addr[1], priv->mac_addr[2], priv->mac_addr[3]
		, priv->mac_addr[4], priv->mac_addr[5]);

out:
	sqn_pr_leave();
	return rv;
}
예제 #16
0
static void iwmct_irq(struct sdio_func *func)
{
	struct iwmct_priv *priv;
	int val, ret;
	int iosize;
	int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR;
	struct iwmct_work_struct *read_req;

	priv = sdio_get_drvdata(func);

	LOG_TRACE(priv, IRQ, "enter iwmct_irq\n");

	/* read the function's status register */
	val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret);

	LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);

	if (!val) {
		LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n");
		goto exit_clear_intr;
	}


	/*
	 * read 2 bytes of the transaction size
	 * IMPORTANT: sdio transaction size has to be read before clearing
	 * sdio interrupt!!!
	 */
	val = sdio_readb(priv->func, addr++, &ret);
	iosize = val;
	val = sdio_readb(priv->func, addr++, &ret);
	iosize += val << 8;

	LOG_INFO(priv, IRQ, "READ size %d\n", iosize);

	if (iosize == 0) {
		LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize);
		goto exit_clear_intr;
	}

	/* allocate a work structure to pass iosize to the worker */
	read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL);
	if (!read_req) {
		LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n");
		goto exit_clear_intr;
	}

	INIT_LIST_HEAD(&read_req->list);
	read_req->iosize = iosize;

	list_add_tail(&priv->read_req_list, &read_req->list);

	/* clear the function's interrupt request bit (write 1 to clear) */
	sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);

	queue_work(priv->wq, &priv->isr_worker);

	LOG_TRACE(priv, IRQ, "exit iwmct_irq\n");

	return;

exit_clear_intr:
	/* clear the function's interrupt request bit (write 1 to clear) */
	sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
}
예제 #17
0
/** @brief This function handles client driver suspend
 *
 *  @param dev	   A pointer to device structure
 *  @return        BT_STATUS_SUCCESS or other error no.
 */
int
bt_sdio_suspend(struct device *dev)
{
	struct sdio_func *func = dev_to_sdio_func(dev);
	mmc_pm_flag_t pm_flags = 0;
	bt_private *priv = NULL;
	struct sdio_mmc_card *cardp;
	struct m_dev *m_dev = NULL;

	ENTER();

	pm_flags = sdio_get_host_pm_caps(func);
	PRINTM(CMD, "BT: %s: suspend: PM flags = 0x%x\n", sdio_func_id(func),
	       pm_flags);
	if (!(pm_flags & MMC_PM_KEEP_POWER)) {
		PRINTM(ERROR,
		       "BT: %s: cannot remain alive while host is suspended\n",
		       sdio_func_id(func));
		return -ENOSYS;
	}
	cardp = sdio_get_drvdata(func);
	if (!cardp || !cardp->priv) {
		PRINTM(ERROR, "BT: Card or priv structure is not valid\n");
		LEAVE();
		return BT_STATUS_SUCCESS;
	}

	priv = cardp->priv;

	if ((mbt_pm_keep_power) && (priv->adapter->hs_state != HS_ACTIVATED)) {
		/* disable FM event mask */
		if ((priv->bt_dev.m_dev[FM_SEQ].dev_type == FM_TYPE) &&
		    test_bit(HCI_RUNNING, &(priv->bt_dev.m_dev[FM_SEQ].flags)))
			fm_set_intr_mask(priv, FM_DISABLE_INTR_MASK);
		if (BT_STATUS_SUCCESS != bt_enable_hs(priv)) {
			PRINTM(CMD, "BT: HS not actived, suspend fail!\n");
			if (BT_STATUS_SUCCESS != bt_enable_hs(priv)) {
				PRINTM(CMD,
				       "BT: HS not actived the second time, force to suspend!\n");
			}
		}
	}
	m_dev = &(priv->bt_dev.m_dev[BT_SEQ]);
	PRINTM(CMD, "BT %s: SDIO suspend\n", m_dev->name);
	mbt_hci_suspend_dev(m_dev);
	skb_queue_purge(&priv->adapter->tx_queue);

	priv->adapter->is_suspended = TRUE;

	LEAVE();
	/* We will keep the power when hs enabled successfully */
	if ((mbt_pm_keep_power) && (priv->adapter->hs_state == HS_ACTIVATED)) {
#ifdef MMC_PM_SKIP_RESUME_PROBE
		PRINTM(CMD, "BT: suspend with MMC_PM_KEEP_POWER and "
		       "MMC_PM_SKIP_RESUME_PROBE\n");
		return sdio_set_host_pm_flags(func,
					      MMC_PM_KEEP_POWER |
					      MMC_PM_SKIP_RESUME_PROBE);
#else
		PRINTM(CMD, "BT: suspend with MMC_PM_KEEP_POWER\n");
		return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
#endif
	} else {
		PRINTM(CMD, "BT: suspend without MMC_PM_KEEP_POWER\n");
		return BT_STATUS_SUCCESS;
	}
}
예제 #18
0
static void ks_sdio_interrupt(struct sdio_func *func)
{
	int ret;
	struct ks_sdio_card *card;
	struct ks_wlan_private *priv;
	unsigned char status, rsize, byte;

	card = sdio_get_drvdata(func);
	priv = card->priv;
	DPRINTK(4, "\n");

	if (priv->dev_state < DEVICE_STATE_BOOT)
		goto queue_delayed_work;

	ret = ks7010_sdio_readb(priv, INT_PENDING, &status);
	if (ret) {
		DPRINTK(1, "error : INT_PENDING\n");
		goto queue_delayed_work;
	}
	DPRINTK(4, "INT_PENDING=%02X\n", status);

	/* schedule task for interrupt status */
	/* bit7 -> Write General Communication B register */
	/* read (General Communication B register) */
	/* bit5 -> Write Status Idle */
	/* bit2 -> Read Status Busy  */
	if (status & INT_GCR_B ||
	    atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
		ret = ks7010_sdio_readb(priv, GCR_B, &byte);
		if (ret) {
			DPRINTK(1, " error : GCR_B\n");
			goto queue_delayed_work;
		}
		if (byte == GCR_B_ACTIVE) {
			if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
				atomic_set(&priv->psstatus.status, PS_WAKEUP);
				priv->wakeup_count = 0;
			}
			complete(&priv->psstatus.wakeup_wait);
		}
	}

	do {
		/* read (WriteStatus/ReadDataSize FN1:00_0014) */
		ret = ks7010_sdio_readb(priv, WSTATUS_RSIZE, &byte);
		if (ret) {
			DPRINTK(1, " error : WSTATUS_RSIZE\n");
			goto queue_delayed_work;
		}
		DPRINTK(4, "WSTATUS_RSIZE=%02X\n", byte);
		rsize = byte & RSIZE_MASK;
		if (rsize != 0)		/* Read schedule */
			ks_wlan_hw_rx(priv, (uint16_t)(rsize << 4));

		if (byte & WSTATUS_MASK) {
			if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) {
				if (cnt_txqbody(priv)) {
					ks_wlan_hw_wakeup_request(priv);
					queue_delayed_work(priv->wq, &priv->rw_dwork, 1);
					return;
				}
			} else {
				tx_device_task(priv);
			}
		}
	} while (rsize);

queue_delayed_work:
	queue_delayed_work(priv->wq, &priv->rw_dwork, 0);
}
예제 #19
0
static void ks7010_sdio_remove(struct sdio_func *func)
{
	int ret;
	struct ks_sdio_card *card;
	struct ks_wlan_private *priv;

	card = sdio_get_drvdata(func);

	if (!card)
		return;

	DPRINTK(1, "priv = card->priv\n");
	priv = card->priv;
	if (priv) {
		struct net_device *netdev = priv->net_dev;

		ks_wlan_net_stop(netdev);
		DPRINTK(1, "ks_wlan_net_stop\n");

		/* interrupt disable */
		sdio_claim_host(func);
		sdio_writeb(func, 0, INT_ENABLE, &ret);
		sdio_writeb(func, 0xff, INT_PENDING, &ret);
		sdio_release_host(func);
		DPRINTK(1, "interrupt disable\n");

		ret = send_stop_request(func);
		if (ret)	/* memory allocation failure */
			return;

		DPRINTK(1, "STOP Req\n");

		if (priv->wq) {
			flush_workqueue(priv->wq);
			destroy_workqueue(priv->wq);
		}
		DPRINTK(1, "destroy_workqueue(priv->wq);\n");

		hostif_exit(priv);
		DPRINTK(1, "hostif_exit\n");

		unregister_netdev(netdev);

		trx_device_exit(priv);
		free_netdev(priv->net_dev);
		card->priv = NULL;
	}

	sdio_claim_host(func);
	sdio_release_irq(func);
	DPRINTK(1, "sdio_release_irq()\n");
	sdio_disable_func(func);
	DPRINTK(1, "sdio_disable_func()\n");
	sdio_release_host(func);

	sdio_set_drvdata(func, NULL);

	kfree(card);
	DPRINTK(1, "kfree()\n");

	DPRINTK(5, " Bye !!\n");
}
예제 #20
0
static void esp_sdio_remove(struct sdio_func *func) 
{
        struct esp_sdio_ctrl *sctrl = NULL;

	esp_dbg(ESP_SHOW, "%s enter\n", __func__);

        sctrl = sdio_get_drvdata(func);

        if (sctrl == NULL) {
                esp_dbg(ESP_DBG_ERROR, "%s no sctrl\n", __func__);
                return;
        }

        do {
                if (sctrl->epub == NULL) {
                        esp_dbg(ESP_DBG_ERROR, "%s epub null\n", __func__);
                        break;
                }
		sctrl->epub->sdio_state = sif_sdio_state;
		if(sif_sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT){
                	if (sctrl->epub->sip) {
                        	sip_detach(sctrl->epub->sip);
                        	sctrl->epub->sip = NULL;
                        	esp_dbg(ESP_DBG_TRACE, "%s sip detached \n", __func__);
                	}
#ifdef USE_EXT_GPIO	
			if (sif_get_ate_config() == 0)
				ext_gpio_deinit();
#endif
		} else {
			//sif_disable_target_interrupt(sctrl->epub);
			atomic_set(&sctrl->epub->sip->state, SIP_STOP);
			sif_disable_irq(sctrl->epub);
		}

#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0))
                esdio_power_off(sctrl);
                esp_dbg(ESP_DBG_TRACE, "%s power off \n", __func__);
#endif /* kernel < 3.3.0 */

#ifdef TEST_MODE
                test_exit_netlink();
#endif /* TEST_MODE */
		if(sif_sdio_state != ESP_SDIO_STATE_FIRST_NORMAL_EXIT){
                	esp_pub_dealloc_mac80211(sctrl->epub);
                	esp_dbg(ESP_DBG_TRACE, "%s dealloc mac80211 \n", __func__);
			
			if (sctrl->dma_buffer) {
				kfree(sctrl->dma_buffer);
				sctrl->dma_buffer = NULL;
				esp_dbg(ESP_DBG_TRACE, "%s free dma_buffer \n", __func__);
			}

			kfree(sctrl);
		}

        } while (0);
        
	sdio_set_drvdata(func,NULL);
	
        esp_dbg(ESP_DBG_TRACE, "eagle sdio remove complete\n");
}
예제 #21
0
static void smssdio_interrupt(struct sdio_func *func)
{
	int ret;

	struct smssdio_device *smsdev;
	struct smscore_buffer_t *cb;
	struct sms_msg_hdr *hdr;
	size_t size;

	smsdev = sdio_get_drvdata(func);

	/*
	 * The interrupt register has no defined meaning. It is just
	 * a way of turning of the level triggered interrupt.
	 */
	(void)sdio_readb(func, SMSSDIO_INT, &ret);
	if (ret) {
		pr_err("Unable to read interrupt register!\n");
		return;
	}

	if (smsdev->split_cb == NULL) {
		cb = smscore_getbuffer(smsdev->coredev);
		if (!cb) {
			pr_err("Unable to allocate data buffer!\n");
			return;
		}

		ret = sdio_memcpy_fromio(smsdev->func,
					 cb->p,
					 SMSSDIO_DATA,
					 SMSSDIO_BLOCK_SIZE);
		if (ret) {
			pr_err("Error %d reading initial block!\n", ret);
			return;
		}

		hdr = cb->p;

		if (hdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG) {
			smsdev->split_cb = cb;
			return;
		}

		if (hdr->msg_length > smsdev->func->cur_blksize)
			size = hdr->msg_length - smsdev->func->cur_blksize;
		else
			size = 0;
	} else {
		cb = smsdev->split_cb;
		hdr = cb->p;

		size = hdr->msg_length - sizeof(struct sms_msg_hdr);

		smsdev->split_cb = NULL;
	}

	if (size) {
		void *buffer;

		buffer = cb->p + (hdr->msg_length - size);
		size = ALIGN(size, SMSSDIO_BLOCK_SIZE);

		BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE);

		/*
		 * First attempt to transfer all of it in one go...
		 */
		ret = sdio_memcpy_fromio(smsdev->func,
					 buffer,
					 SMSSDIO_DATA,
					 size);
		if (ret && ret != -EINVAL) {
			smscore_putbuffer(smsdev->coredev, cb);
			pr_err("Error %d reading data from card!\n", ret);
			return;
		}

		/*
		 * ..then fall back to one block at a time if that is
		 * not possible...
		 *
		 * (we have to do this manually because of the
		 * problem with the "increase address" bit)
		 */
		if (ret == -EINVAL) {
			while (size) {
				ret = sdio_memcpy_fromio(smsdev->func,
						  buffer, SMSSDIO_DATA,
						  smsdev->func->cur_blksize);
				if (ret) {
					smscore_putbuffer(smsdev->coredev, cb);
					pr_err("Error %d reading data from card!\n",
					       ret);
					return;
				}

				buffer += smsdev->func->cur_blksize;
				if (size > smsdev->func->cur_blksize)
					size -= smsdev->func->cur_blksize;
				else
					size = 0;
			}
		}
	}

	cb->size = hdr->msg_length;
	cb->offset = 0;

	smsendian_handle_rx_message((struct sms_msg_data *) cb->p);
	smscore_onresponse(smsdev->coredev, cb);
}
예제 #22
0
/**  @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;
}
예제 #23
0
static int rtw_sdio_suspend(struct device *dev)
{
	struct sdio_func *func =dev_to_sdio_func(dev);
	struct dvobj_priv *psdpriv = sdio_get_drvdata(func);
	_adapter *padapter = psdpriv->padapter;
	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
	struct net_device *pnetdev = padapter->pnetdev;
	int ret = 0;
	u32 start_time = rtw_get_current_time();
	
	_func_enter_;

	DBG_871X("==> %s (%s:%d)\n",__FUNCTION__, current->comm, current->pid);

	if((!padapter->bup) || (padapter->bDriverStopped)||(padapter->bSurpriseRemoved))
	{
		DBG_871X("%s bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", __FUNCTION__
			,padapter->bup, padapter->bDriverStopped,padapter->bSurpriseRemoved);
		goto exit;
	}
	
	pwrpriv->bInSuspend = _TRUE;		
	rtw_cancel_all_timer(padapter);		
	LeaveAllPowerSaveMode(padapter);
	
	//padapter->net_closed = _TRUE;
	//s1.
	if(pnetdev)
	{
		netif_carrier_off(pnetdev);
		netif_stop_queue(pnetdev);
	}
#ifdef CONFIG_WOWLAN
	padapter->pwrctrlpriv.bSupportWakeOnWlan=_TRUE;
#else		
	//s2.
	//s2-1.  issue rtw_disassoc_cmd to fw
	disconnect_hdl(padapter, NULL);
	//rtw_disassoc_cmd(padapter);
#endif

#ifdef CONFIG_LAYER2_ROAMING_RESUME
	if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) )
	{
		DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n",__FUNCTION__,
				pmlmepriv->cur_network.network.Ssid.Ssid,
				MAC_ARG(pmlmepriv->cur_network.network.MacAddress),
				pmlmepriv->cur_network.network.Ssid.SsidLength,
				pmlmepriv->assoc_ssid.SsidLength);
		
		pmlmepriv->to_roaming = 1;
	}
#endif
	//s2-2.  indicate disconnect to os
	rtw_indicate_disconnect(padapter);
	//s2-3.
	rtw_free_assoc_resources(padapter, 1);

	//s2-4.
	rtw_free_network_queue(padapter, _TRUE);

	rtw_led_control(padapter, LED_CTL_POWER_OFF);

	rtw_dev_unload(padapter);

exit:
	DBG_871X("<===  %s return %d.............. in %dms\n", __FUNCTION__
		, ret, rtw_get_passing_time_ms(start_time));

/*depends on sunxi power control */
#if defined(CONFIG_MMC_SUNXI_POWER_CONTROL)
// 	sunximmc_rescan_card(SDIOID, 0);
//	rtl8723as_sdio_poweroff();
	printk("[rtl8723as] %s: suspend end.\n", __FUNCTION__);
#endif

	_func_exit_;
	return ret;
}
예제 #24
0
/**  @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;
}
예제 #25
0
int sqn_wakeup_fw(struct sdio_func *func)
{
	int rv = 0;
	int ver = 0;
	int counter = 0;

	int retry_cnt = 3;
	u32 wakeup_delay = 0;
	unsigned long timeout = msecs_to_jiffies(800);

	unsigned long irq_flags = 0;
	struct sqn_private *priv = ((struct sqn_sdio_card *)sdio_get_drvdata(func))->priv;
	struct sqn_sdio_card *card = priv->card;
	u8 need_to_unlock_wakelock = 0;

	sqn_pr_enter();
	sqn_pr_info("waking up the card...\n");

	if (!wake_lock_active(&card->wakelock_tx)) {
		if (mmc_wimax_get_sdio_wakelock_log()) {
			printk(KERN_INFO "[WIMAX] lock wl_tx2,");
			PRINTRTC;
		}
		wake_lock(&card->wakelock_tx);
		need_to_unlock_wakelock = 1;
	}

retry:
	if (priv->removed)
		goto out;

	sdio_claim_host(func);

#define  SDIO_CCCR_CCCR_SDIO_VERSION_VALUE	0x11

    wakeup_delay = 2;
	counter = 5;
	do {
		sqn_pr_dbg("CMD52 #%d, delay %d msec\n", counter, wakeup_delay);
		ver = sdio_readb(func, SDIO_CCCR_CCCR_SDIO_VERSION, &rv);
		// To avoid FW sutck in PLLOFF, SDIO isn't able to wake up it.
		mdelay(wakeup_delay);
		--counter;
	} while((rv || ver != SDIO_CCCR_CCCR_SDIO_VERSION_VALUE) && counter > 0);

	if (rv) {
		sqn_pr_err("error when reading SDIO_VERSION\n");

		if (mmc_wimax_get_wimax_FW_freeze_WK_TX()) {
			sqn_pr_info("[ste]set is_card_sleeps 0 to avoid TX polling\n");
			card->is_card_sleeps = 0;
		}

		sdio_release_host(func);
		goto out;
	} else
		sqn_pr_dbg("SDIO_VERSION has been read successfully\n");

	sqn_pr_dbg("send wake-up signal to card\n");
	sdio_writeb(func, 1, SQN_SOC_SIGS_LSBS, &rv);

	if (rv)
		sqn_pr_err("error when writing to SQN_SOC_SIGS_LSBS: %d\n", rv);

	sdio_release_host(func);

	sqn_pr_info("wait for completion (timeout %d msec)...\n"
		, jiffies_to_msecs(timeout));

	rv = wait_event_interruptible_timeout(g_card_sleep_waitq
		, 0 == card->is_card_sleeps || priv->removed, timeout);

	if (priv->removed)
		goto out;

	if (-ERESTARTSYS == rv) {
		sqn_pr_warn("got a signal from kernel %d\n", rv);
	} else if (0 == rv) {
		rv = -1;
		sqn_pr_err("can't wake up the card - timeout elapsed\n");

		if (retry_cnt-- > 0 && card->is_card_sleeps) {
			sqn_pr_info("retry wake up\n");
			goto retry;
    	}
		sqn_pr_info("giving up to wake up the card\n");

		spin_lock_irqsave(&priv->drv_lock, irq_flags);
		card->is_card_sleeps = 0;
		spin_unlock_irqrestore(&priv->drv_lock, irq_flags);
	} else {
		rv = 0;
		sqn_pr_info("card is waked up successfully\n");
	}

out:
	if (need_to_unlock_wakelock && wake_lock_active(&card->wakelock_tx)) {
		if (mmc_wimax_get_sdio_wakelock_log()) {
			printk(KERN_INFO "[WIMAX] release wake_lock_tx in %s,", __func__);
			PRINTRTC;
		}
		wake_unlock(&card->wakelock_tx); /* TX */
	}
	sqn_pr_leave();
	return rv;
}
예제 #26
0
파일: hif.c 프로젝트: AvalueAES/rev-sa01
static HIF_DEVICE *
getHifDevice(struct sdio_func *func)
{
    AR_DEBUG_ASSERT(func != NULL);
    return (HIF_DEVICE *)sdio_get_drvdata(func);
}
예제 #27
0
static int write_data(struct sdio_func *func, u32 addr, void *data
	, u32 size, u32 access_size)
{
	int rv = 0;
	struct sqn_sdio_card *sqn_card = sdio_get_drvdata(func);

	sqn_pr_enter();
	sdio_claim_host(func);

	if (is_good_ahb_address(addr, sqn_card->version)
		&& 0 == (size % 4) && 4 == access_size)
	{
		/* write data using AHB */

		u8 *data_cp = 0;
#ifdef DEBUG
		u8 *read_data  = 0;
#endif

		sqn_pr_dbg("write data using AHB\n");
		sdio_writel(func, addr, SQN_SDIO_ADA_ADDR, &rv);
		if (rv) {
			sqn_pr_dbg("can't set SQN_SDIO_ADA_ADDR register\n");
			goto out;
		}
		sqn_pr_dbg("after SQN_SDIO_ADA_ADDR\n");

		data_cp = kmalloc(size, GFP_KERNEL | GFP_DMA);
		memcpy(data_cp, data, size);
		rv = sdio_writesb(func, SQN_SDIO_ADA_RDWR, data_cp, size);
		if (rv) {
			sqn_pr_dbg("can't write to SQN_SDIO_ADA_RDWR register\n");
			goto out;
		}
		kfree(data_cp);

		/*
		 * Workaround when sdio_writesb doesn't work because DMA
		 * alignment
		 */
		/*
		int i = 0;
		for (; i < size/4; ++i) {
			sdio_writel(func, *((u32*)data + i), SQN_SDIO_ADA_RDWR, &rv);
			if (rv) {
				sqn_pr_dbg("can't write to SQN_SDIO_ADA_RDWR register\n");
				goto out;
			}
		}
		*/

		sqn_pr_dbg("after SQN_SDIO_ADA_RDWR\n");

		/* ******** only for debugging ******** */
		/* validate written data */
/* #ifdef DEBUG */
#if 0
		sqn_pr_dbg("reading data using AHB\n");
		sdio_writel(func, addr, SQN_SDIO_ADA_ADDR, &rv);
		if (rv) {
			sqn_pr_dbg("can't set SQN_SDIO_ADA_ADDR register\n");
			goto out;
		}
		sqn_pr_dbg("after SQN_SDIO_ADA_ADDR\n");

		read_data = kmalloc(size, GFP_KERNEL);
		rv = sdio_readsb(func, read_data, SQN_SDIO_ADA_RDWR, size);
		if (rv) {
			sqn_pr_dbg("can't read from SQN_SDIO_ADA_RDWR register\n");
			kfree(read_data);
			goto out;
		}

		if (memcmp(data, read_data, size))
			sqn_pr_dbg("WARNING: written data are __not__ equal\n");
		else
			sqn_pr_dbg("OK: written data are equal\n");

		kfree(read_data);
#endif /* DEBUG */
		/* ******** only for debugging ******** */

	} else if (4 == access_size && size >= 4) {
		/* write data using CMD53 */
		sqn_pr_dbg("write data using CMD53\n");
		rv = sdio_memcpy_toio(func, addr, data , size);
	} else {
		/* write data using CMD52 */
		/* not implemented yet, so we use CMD53 */
		/* rv = sdio_memcpy_toio(func, addr, data , size); */
		int i = 0;
		sqn_pr_dbg("write data using CMD52\n");
		for (i = 0; i < size; ++i) {
			sdio_writeb(func, *((u8*)data + i), addr + i, &rv);
			if (rv) {
				sqn_pr_dbg("can't write 1 byte to %xh addr using CMD52\n"
					, addr + i);
				goto out;
			}
		}
	}

out:
	sdio_release_host(func);
	sqn_pr_leave();
	return rv;
}