Esempio n. 1
0
static ssize_t 
mt6620_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) {
	size_t newSize;
	ssize_t ret;

	if(size > MAX_RW_SIZE)
		return -EINVAL;

#if	(RX_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(down_interruptible(&mt6620_sem)) {
		return -ERESTARTSYS;
	}

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

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

	up(&mt6620_sem);

	return ret;
}
Esempio n. 2
0
/*----------------------------------------------------------------------------*/
BOOL
kalDevPortRead(IN P_GLUE_INFO_T prGlueInfo,
	       IN UINT_16 u2Port,
	       IN UINT_32 u4Len, OUT PUINT_8 pucBuf, IN UINT_32 u4ValidOutBufSize)
{
	P_GL_HIF_INFO_T prHifInfo = NULL;
	PUINT_8 pucDst = 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"++kalDevPortRead++ buf:0x%p, port:0x%x, length:%d\n", pucBuf, u2Port, u4Len); */
#endif

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

	ASSERT(pucBuf);
	pucDst = pucBuf;

	ASSERT(u4Len <= u4ValidOutBufSize);

#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) {
		ret = sdio_readsb(prSdioFunc, pucDst, u2Port, prSdioFunc->cur_blksize * bNum);

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

	} else {
		ret = sdio_readsb(prSdioFunc, pucDst, u2Port, 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) {
		ret =
		    mtk_wcn_hif_sdio_read_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucDst,
					      ((prGlueInfo->rHifInfo).prFuncInfo->blk_sz) * bNum);
	} else {
		ret =
		    mtk_wcn_hif_sdio_read_buf(prGlueInfo->rHifInfo.cltCtx, u2Port, (PUINT32) pucDst,
					      count);
	}
#endif

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

	return (ret) ? FALSE : TRUE;
}				/* end of kalDevPortRead() */
int if_sdio_card_to_host(struct if_sdio_card *card)
{
	int ret = 0;
	struct rda5890_private *priv = card->priv;
	u8 size_l = 0, size_h = 0;
	u16 size, chunk;

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
		"%s <<< \n", __func__);

	ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_AHB2SDIO_PKTLEN_L, &size_l);
	if (ret) {
		RDA5890_ERRP("read PKTLEN_L reg fail\n");
		goto out;
	}
	else
		RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,"read PKTLEN_L reg size_l:%d \n", size_l);

	ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_AHB2SDIO_PKTLEN_H, &size_h);
	if (ret) {
		RDA5890_ERRP("read PKTLEN_H reg fail\n");
		goto out;
	}
	else
		RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,"read PKTLEN_H reg size_h:%d\n",size_h);	

	size = (size_l | ((size_h & 0x7f) << 8)) * 4;
	if (size < 4) {
		RDA5890_ERRP("invalid packet size (%d bytes) from firmware\n", size);
		ret = -EINVAL;
		goto out;
	}

	/* alignment is handled on firmside */
	//chunk = sdio_align_size(card->func, size);
	chunk = size;

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,
		"if_sdio_card_to_host, size = %d, aligned size = %d\n", size, chunk);

	/* TODO: handle multiple packets here */
	ret = mtk_wcn_hif_sdio_read_buf(priv->cltCtx, IF_SDIO_FUN1_FIFO_RD, (u32)card->buffer, chunk);
	if (ret) {
		RDA5890_ERRP("sdio_readsb fail, ret = %d, size = %d, aligned size = %d\n", ret, size, chunk);
		goto out;
	}

#if 1
    if(priv->version == 7)
    {
        mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, 0x20);
        if(ret) {
           RDA5890_ERRP("clear SDIO Tx Complete flag failed\n");
           goto out;
        }
    }
#endif

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_VERB,
		"if_sdio_card_to_host, read done\n");

    if(ret) 
    {
        RDA5890_ERRP("clear SDIO Tx Complete flag failed\n");
        goto out;
    }

	if (sdio_test_flag) {
		rda5890_sdio_test_card_to_host(card->buffer, chunk);
		goto out;
	}

	/* TODO: this chunk size need to be handled here */
	rda5890_card_to_host(priv, card->buffer, chunk);

out:
	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
		"if_sdio_card_to_host >>>\n");
	return ret;
}
Esempio n. 4
0
static long
mt6620_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
	int err = 0;
	int retval = 0;
	u8 data;
	unsigned int tmp;

	if(_IOC_TYPE(cmd) != MT6620_IOC_MAGIC) 
		return -ENOTTY;
	else if(_IOC_NR(cmd) > MT6620_IOC_MAXNR) return -ENOTTY;

	if(_IOC_DIR(cmd) & _IOC_READ)
		err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
	else if (_IOC_DIR(cmd) & _IOC_WRITE)
		err =  !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
	if (err) 
		return -EFAULT;

	switch(cmd) {
	case MT6620_IOC_GET_FUNC_FOCUS:
	case MT6620_IOC_SET_FUNC_FOCUS:
	case MT6620_IOC_GET_SDBUS_WIDTH:
	case MT6620_IOC_SET_SDBUS_WIDTH:
	case MT6620_IOC_GET_BUS_CLOCK:
	case MT6620_IOC_SET_BUS_CLOCK:
        retval = -EINVAL;
		break;

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

		retval = mtk_wcn_hif_sdio_readb(mt6620_t.cltCtx, mt6620_t.addr, &data);

		up(&mt6620_sem);

		if(retval == 0)
			retval = __put_user(data, (u8 __user *)arg);

		break;

	case MT6620_IOC_WRITE_DIRECT:
		__get_user(data, (u8 __user *)arg);

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

		retval = mtk_wcn_hif_sdio_writeb(mt6620_t.cltCtx, mt6620_t.addr, data);

		up(&mt6620_sem);

		break;

	case MT6620_IOC_GET_ADDR:
		tmp = mt6620_t.addr;
		__put_user(tmp, (u32 __user *)arg);
		break;

	case MT6620_IOC_SET_ADDR:
		__get_user(tmp, (u32 __user *)arg);
		if(tmp <= 0xFF)
			mt6620_t.addr = tmp;
		else
			retval = -EINVAL;
		break;

	case MT6620_IOC_SET_FIFO_MODE:
	case MT6620_IOC_SET_INCR_MODE:
	case MT6620_IOC_GET_BLOCK_SIZE:
	case MT6620_IOC_SET_BLOCK_SIZE:
        retval = -EINVAL;
		break;

	case MT6620_IOC_QUERY_IRQ_LEVEL:
		if(down_interruptible(&mt6620_sem))
			retval = -ERESTARTSYS;
		else if(mt6620_t.irq.irq == 1) {
			unsigned char buffer[88];

			if(mt6620_t.enhance_int.totalBytes != 0) {
				int i, offset = 0;

				if(mtk_wcn_hif_sdio_read_buf(mt6620_t.cltCtx, MCR_WHISR, 
						(PUINT32)(buffer), mt6620_t.enhance_int.totalBytes + sizeof(unsigned int))) {
                    /* I/O error */
        			up(&mt6620_sem);
                    return -EIO;
                }

				mt6620_t.irq.u4HISR |= *(uint32_t *)(&(buffer[offset]));
				offset += sizeof(uint32_t);

				// WTSR0/WTSR1
				if(mt6620_t.enhance_int.totalBytes >= (12)) {
					int tqStatus[2];
					memcpy(&(tqStatus[0]), &(buffer[offset]), 8);

					// increase
					mt6620_t.irq.rTxInfo.u.ucTQ0Cnt += ((tqStatus[0] >>  0) & 0xff);
					mt6620_t.irq.rTxInfo.u.ucTQ1Cnt += ((tqStatus[0] >>  8) & 0xff);
					mt6620_t.irq.rTxInfo.u.ucTQ2Cnt += ((tqStatus[0] >> 16) & 0xff);
					mt6620_t.irq.rTxInfo.u.ucTQ3Cnt += ((tqStatus[0] >> 24) & 0xff);
					mt6620_t.irq.rTxInfo.u.ucTQ4Cnt += ((tqStatus[1] >>  0) & 0xff);
					mt6620_t.irq.rTxInfo.u.ucTQ5Cnt += ((tqStatus[1] >>  8) & 0xff);

					offset += 8;
				}

				// RX0NUM/RX1NUM
				if(mt6620_t.enhance_int.totalBytes >= (16)) {
					memcpy(&(mt6620_t.irq.rRxInfo.au4RxStatusRaw[0]), &(buffer[offset]), 4);
					offset += 4;
				}

				// RX0 LEN0-15 / RX1 LEN0-15
				if(mt6620_t.enhance_int.totalBytes >= (16 + mt6620_t.enhance_int.rxNum * 4)) {
					for(i = 0 ; i < mt6620_t.enhance_int.rxNum ; i++) {
						mt6620_t.irq.rRxInfo.u.au2Rx0Len[i] = *(uint16_t *)(&(buffer[offset]));
						offset += sizeof(uint16_t);
					}

					for(i = 0 ; i < mt6620_t.enhance_int.rxNum ; i++) {
						mt6620_t.irq.rRxInfo.u.au2Rx1Len[i] = *(uint16_t *)(&(buffer[offset]));
						offset += sizeof(uint16_t);
					}
				}

				// D2HRM0R / D2HRM1R
				if(mt6620_t.enhance_int.totalBytes >= (16 + mt6620_t.enhance_int.rxNum * 4 + 8)) {
					memcpy(&(mt6620_t.irq.u4RcvMailbox0), &(buffer[offset]), 4);
					offset += 4;

					memcpy(&(mt6620_t.irq.u4RcvMailbox1), &(buffer[offset]), 4);
					offset += 4;
				}

				//@FIXME: WHISR could be configured as write-1-clear .... 
				//if so, we need to clear WHISR here ..
			}