Beispiel #1
0
static ssize_t 
mt6620_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) {
	size_t newSize;
	ssize_t ret;

	if(size > MAX_RW_SIZE)
		return -EINVAL;

#if	(TX_PATH_BLKSZ_WORKAROUND == 1)
	if(size > mt6620_t.func->blk_sz) {
        unsigned blksz = mt6620_t.func->blk_sz;

		newSize = (size + (blksz - 1)) / blksz * blksz;
	}
	else
		newSize = size;
#else
	newSize = size;
#endif

	if(copy_from_user(mt6620_t.buf, buf, size))
		return -EFAULT;

	if(newSize > size) // pad with zero
		memset(&mt6620_t.buf[size], 0, sizeof(char) * newSize - size);

	if(down_interruptible(&mt6620_sem)) {
		return -ERESTARTSYS;
	}

    ret = mtk_wcn_hif_sdio_write_buf(mt6620_t.cltCtx, mt6620_t.addr, (PUINT32)(mt6620_t.buf), newSize);

	if(ret == 0) {
		ret = size;
    }
	else {
		printk(KERN_INFO "%s(): io error code = %d\n", __func__, (int)ret);
		ret = -EIO;
	}

	up(&mt6620_sem);

	return ret;
}
Beispiel #2
0
/*----------------------------------------------------------------------------*/
BOOL
kalDevPortWrite(IN P_GLUE_INFO_T prGlueInfo,
		IN UINT_16 u2Port, IN UINT_32 u4Len, IN PUINT_8 pucBuf, IN UINT_32 u4ValidInBufSize)
{
	P_GL_HIF_INFO_T prHifInfo = NULL;
	PUINT_8 pucSrc = NULL;
	int count = u4Len;
	int ret = 0;
	int bNum = 0;

#if (MTK_WCN_HIF_SDIO == 0)
	struct sdio_func *prSdioFunc = NULL;
#endif

#if DBG
	/* printk(KERN_INFO DRV_NAME"++kalDevPortWrite++ buf:0x%p, port:0x%x, length:%d\n", pucBuf, u2Port, u2Len); */
#endif

	ASSERT(prGlueInfo);
	prHifInfo = &prGlueInfo->rHifInfo;

	ASSERT(pucBuf);
	pucSrc = pucBuf;

	ASSERT(u4Len <= u4ValidInBufSize);

#if (MTK_WCN_HIF_SDIO == 0)
	prSdioFunc = prHifInfo->func;
	ASSERT(prSdioFunc->cur_blksize > 0);

	if (!in_interrupt) {
		sdio_claim_host(prSdioFunc);
	}

	/* Split buffer into multiple single block to workaround hifsys */
	while (count >= prSdioFunc->cur_blksize) {
		count -= prSdioFunc->cur_blksize;
		bNum++;
	}
	if (count > 0 && bNum > 0) {
		bNum++;
	}

	if (bNum > 0) {		/* block mode */
		ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, prSdioFunc->cur_blksize * bNum);

#ifdef CONFIG_X86
		/* ENE workaround */
		{
			int tmp;
			sdio_writel(prSdioFunc, 0x0, SDIO_X86_WORKAROUND_WRITE_MCR, &tmp);
		}
#endif

	} else {		/* byte mode */

		ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, count);
	}

	if (!in_interrupt) {
		sdio_release_host(prSdioFunc);
	}
#else
	/* Split buffer into multiple single block to workaround hifsys */
	while (count >= ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz)) {
		count -= ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz);
		bNum++;
	}
	if (count > 0 && bNum > 0) {
		bNum++;
	}

	if (bNum > 0) {		/* block mode */
		ret =
		    mtk_wcn_hif_sdio_write_buf(prGlueInfo->rHifInfo.cltCtx, u2Port,
					       (PUINT32) pucSrc,
					       ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz) * bNum);
	} else {		/* byte mode */
		ret =
		    mtk_wcn_hif_sdio_write_buf(prGlueInfo->rHifInfo.cltCtx, u2Port,
					       (PUINT32) pucSrc, count);
	}
#endif

	if (ret) {
		kalSendAeeWarning(HIF_SDIO_ERR_TITLE_STR,
				  HIF_SDIO_ERR_DESC_STR "sdio_writesb() reports error: %x", ret);
		DBGLOG(HAL, ERROR, ("sdio_writesb() reports error: %x", ret));
	}

	return (ret) ? FALSE : TRUE;
}				/* end of kalDevPortWrite() */
static void if_sdio_host_to_card_worker(struct work_struct *work)
{
	struct if_sdio_card *card = NULL;
	struct rda5890_private *priv = NULL;
	struct if_sdio_packet *packet = NULL;
	int ret;
	unsigned long flags;
	u16 size;
	u32 retries = 500;
	u8 size_l, size_h, write_status = 0;
#define SDIO_HOST_WRITE_BATCH_SIZE   512
	u16 bytes_left, offset, batch;

	card = container_of(work, struct if_sdio_card, packet_worker);
	priv = card->priv;

	//mask_all_sdio_irq(priv->cltCtx);
#ifdef WIFI_POWER_MANAGER    
	if(is_sdio_init_complete())
	{   
		if(atomic_read(&card->sleep_work_is_active))
		{
		    cancel_delayed_work(&card->sleep_work);
#ifdef WIFI_UNLOCK_SYSTEM    
		    rda5990_wakeUnlock();
#endif 
		    atomic_set(&card->sleep_work_is_active, 0);
		}
	}
#endif

	while (1) 
	{  
		retries = 500;
		  
		spin_lock_irqsave(&card->lock, flags);
		packet = card->packets;
		if (packet)
			card->packets = packet->next;
		spin_unlock_irqrestore(&card->lock, flags);

		if (!packet)
			break;
		
#ifdef WIFI_POWER_MANAGER		
		if (atomic_read(&priv->sleep_flag)) 
		{
			/* Deivce maybe sleep, wakeup it. */
			RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM, "Wakeup\n");
			ret = if_sdio_wakeup_card(card);
			if (ret) 
			{
				RDA5890_ERRP("wakeup card fail\n");
				goto out;
			}
		}
#endif
		while(retries && is_sdio_patch_complete()) //check write flow ctrl
		{
			ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, &write_status);
			if(ret)
			{
				RDA5890_ERRP("read IF_SDIO_FUN1_INT_PEND failed\n");
				goto release;
			}
			if((write_status & IF_SDIO_INT_RXCMPL) == 0)
			{
				//RDA5890_ERRP("**** sdio is busy retry next time \n ");
				retries --;
				schedule();
			}
		    	else
			{
				ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, IF_SDIO_INT_RXCMPL);
				if(ret)
				{
					RDA5890_ERRP("write IF_SDIO_FUN1_INT_PEND failed\n");
					goto release;
				}
				break;
			}
		}
	      
		RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
		"if_sdio_host_to_card_worker, send one packet, size = %d\n", packet->nb);
		/* write length */
		size = packet->nb/4;
		size_l = (u8)(size & 0xff);
		size_h = (u8)((size >> 8) & 0x7f);
		size_h |= 0x80;

		ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_SDIO2AHB_PKTLEN_L, size_l);
		if (ret) {
			RDA5890_ERRP("write PKTLEN_L reg fail\n");
			goto release;
		}
		ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_SDIO2AHB_PKTLEN_H, size_h);
		if (ret) {
			RDA5890_ERRP("write PKTLEN_H reg fail\n");
			goto release;
		}

		/* write data */
		bytes_left = packet->nb;
		offset = 0;
		while(bytes_left) 
		{
			batch = (bytes_left < SDIO_HOST_WRITE_BATCH_SIZE)?
			bytes_left:SDIO_HOST_WRITE_BATCH_SIZE;
			ret = mtk_wcn_hif_sdio_write_buf(priv->cltCtx, IF_SDIO_FUN1_FIFO_WR,
			packet->buffer + offset, batch);
			if (ret) {
				RDA5890_ERRP("sdio_writesb fail, ret = %d\n", ret);
				goto release;
			}
			RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
			"write batch %d, offset = %d\n", batch, offset);
			offset += batch;
			bytes_left -= batch;
		}

		RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
		"if_sdio_host_to_card_worker, send one packet done\n");

		release:

		kfree(packet);
		packet = NULL;
	}

	out:

	if(is_sdio_init_complete()) //init complete should start sleep_work
	{
#ifdef WIFI_UNLOCK_SYSTEM    
		rda5990_wakeLock();
#endif   

#ifdef WIFI_POWER_MANAGER
#ifdef WIFI_TEST_MODE
		if(rda_5990_wifi_in_test_mode())
		    return;
#endif  //end WIFI_TEST_MODE
		atomic_set(&card->sleep_work_is_active, 1);
	    queue_delayed_work(priv->work_thread, &card->sleep_work, rda5890_assoc_in_progress ? 30 * HZ : HZ/5);  // 100ms
		//queue_delayed_work(priv->work_thread, &card->sleep_work, HZ/5);  // 100ms
#endif	    
	}
}