示例#1
0
static ssize_t rda5890_debuglevel_write(struct file *file,
				const char __user *user_buf, size_t count,
				loff_t *ppos)
{
	//struct rda5890_private *priv = file->private_data;
	ssize_t ret;
	int debug_level;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

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

	if (copy_from_user(buf, user_buf, count)) {
		ret = -EFAULT;
		goto out_unlock;
	}
	ret = sscanf(buf, "%x", &debug_level);
	if (ret != 1) {
		ret = -EINVAL;
		goto out_unlock;
	}

    rda5890_dbg_level = debug_level;
	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		"set debug_level = 0x%x\n",rda5890_dbg_level);

	ret = count;
out_unlock:
	free_page(addr);
	return ret;
}
示例#2
0
static ssize_t rda5890_debug_write(struct file *file,
				const char __user *user_buf, size_t count,
				loff_t *ppos)
{
	//struct rda5890_private *priv = file->private_data;
	ssize_t ret;
	int p1, p2, p3, p4;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;

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

	if (copy_from_user(buf, user_buf, count)) {
		ret = -EFAULT;
		goto out_unlock;
	}
	ret = sscanf(buf, "%d %d %d %d", &p1, &p2, &p3, &p4);
	if (ret != 4) {
		ret = -EINVAL;
		goto out_unlock;
	}

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		"input p1 = %d, p2 = %d, p3 = %d, p4 = %d\n",
		p1, p2, p3, p4);

	ret = count;
out_unlock:
	free_page(addr);
	return ret;
}
u32 rda_hif_sdio_remove(MTK_WCN_HIF_SDIO_CLTCTX cltCtx)
{
    struct if_sdio_card *card;
    struct if_sdio_packet *packet;
    unsigned char count = 20; 

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

    if(!gCard)
        return -EPERM;
    
    printk(KERN_INFO "RDA5890: SDIO card detached\n");

    card = gCard;  

    while(card->priv->scan_running && count--)
    {
        rda5890_shedule_timeout(100);
        printk("remove card wait scan complete \n");
    }

#ifdef WIFI_POWER_MANAGER
    cancel_delayed_work_sync(&card->sleep_work);
#endif
    cancel_work_sync(&card->packet_worker);
    
    if (atomic_read(&card->wid_complete_flag) && card->priv)
    {
        complete(&card->priv->wid_done);
        printk(KERN_INFO "*****RDA5890: send wid complete\n");
    }

    netif_stop_queue(card->priv->dev);
    netif_carrier_off(card->priv->dev);
    rda5890_stop_card(card->priv);
    rda5890_debugfs_remove_one(card->priv);
    destroy_workqueue(card->work_thread);
    rda5890_remove_card(card->priv);
    
    while (card->packets) {
    	packet = card->packets;
    	card->packets = card->packets->next;
    	kfree(packet);
    } 
    
    kfree(card);
    gCard = NULL;

#ifdef WIFI_UNLOCK_SYSTEM 
    rda5990_wakeLock_destroy();
#endif  

    printk(KERN_INFO "RDA5890: SDIO card removed\n");

    RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
    	"%s <<<\n", __func__); 
    return 0;   
}
u32 rda_hif_sdio_irq(MTK_WCN_HIF_SDIO_CLTCTX cltCtx)
{ 
    int ret = 0;
    struct if_sdio_card *card;
    struct rda5890_private *priv;
    u8 status;

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

    if(!gCard)
    {
	    return -EIO;
    }  
   
    card = gCard;
    priv = card->priv;
	
    ret = mtk_wcn_hif_sdio_readb(priv->cltCtx, IF_SDIO_FUN1_INT_STAT, &status);
    if (ret)
    	goto out;
    
    RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_VERB,
    	"if_sdio_interrupt, status = 0x%02x\n", status);

    if (status & IF_SDIO_INT_AHB2SDIO)
    	if_sdio_card_to_host(card);

    if (status & IF_SDIO_INT_ERROR) {
    	ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND ,IF_SDIO_INT_ERROR);
    	if (ret) {
    		RDA5890_ERRP("write FUN1_INT_STAT reg fail\n");
    		goto out;
    	}

    	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
    		"%s, INT_ERROR\n", __func__);
    }

#ifdef WIFI_CLOCK_ALWAYS_ON
	export_msdc_clk_always_on_off();
#endif

    out:
    RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
    	"%s <<< ret=%d \n", __func__, ret);   
    return ret;
}
void if_sdio_sleep_worker(struct work_struct *work)
{
	struct if_sdio_card *card = NULL;
	int ret = 0;
    struct rda5890_private *priv = NULL;

	card = container_of(work, struct if_sdio_card,
                sleep_work.work);
	
	if(card)
		priv = card->priv;
	else
		goto out;

	if(!priv)
		goto out;

	RDA5890_DBGLAP(RDA5890_DA_PM, RDA5890_DL_CRIT, "Sleep\n");

	/* clear IF_SDIO_FUN1_INT_PEND, this allow device to sleep */
	ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_PEND, IF_SDIO_HOST_TX_FLAG);
	if (ret)
	{
		RDA5890_ERRP("clear IF_SDIO_HOST_TX_FLAG failed\n");
	}
	atomic_inc(&card->priv->sleep_flag); 

out:

    atomic_set(&card->sleep_work_is_active, 0);
#ifdef WIFI_UNLOCK_SYSTEM
    rda5990_wakeUnlock();
#endif
	return;
}
static int if_sdio_wakeup_card(struct if_sdio_card *card)
{
	struct rda5890_private *priv = card->priv;
	int ret = 0;

#ifdef WIFI_TEST_MODE
    if(rda_5990_wifi_in_test_mode())
        return 0;
#endif
    
#ifdef WIFI_CLOCK_ALWAYS_ON
	export_msdc_clk_always_on();
#endif	

	ret = mtk_wcn_hif_sdio_writeb(priv->cltCtx, IF_SDIO_FUN1_INT_TO_DEV,1);
	if (ret) {
		RDA5890_ERRP("if_sdio_wakeup_card write FUN1_INT_TO_DEV reg fail\n");
		goto out;
	}
    atomic_set(&priv->sleep_flag, 0);
      
	RDA5890_DBGLAP(RDA5890_DA_PM, RDA5890_DL_CRIT, "wake up \n");
	// wait 15ms, hardware need 13ms to wakeup
    rda5890_shedule_timeout(8);
out:
	return ret;
}
示例#7
0
static ssize_t rda5890_sdio_read(struct file *file, 
				const char __user *user_buf, size_t count,
				loff_t *ppos)
{
	//struct rda5890_private *priv = file->private_data;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
	int ret;

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

	if (copy_from_user(buf, user_buf, count)) {
		ret = -EFAULT;
		goto out_unlock;
	}
	ret = sscanf(buf, "%d", &debug_read_flag);
	if (ret != 1) {
		ret = -EINVAL;
		goto out_unlock;
	}

out_unlock:
	free_page(addr);
	return count;
}
示例#8
0
void rda5890_debugfs_init_one(struct rda5890_private *priv)
{
	int i;
	struct rda5890_debugfs_files *files;
	if (!rda5890_dir)
		goto exit;

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

	priv->debugfs_dir = debugfs_create_dir("rda5890_dev", rda5890_dir);
	if (!priv->debugfs_dir)
		goto exit;

	for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
		files = &debugfs_files[i];
		priv->debugfs_files[i] = debugfs_create_file(files->name,
							     files->perm,
							     priv->debugfs_dir,
							     priv,
							     &files->fops);
	}

exit:
	return;
}
示例#9
0
void rda5890_debugfs_remove(void)
{
	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
		"%s\n", __func__);

	if (rda5890_dir)
		 debugfs_remove(rda5890_dir);

	return;
}
示例#10
0
void rda5890_debugfs_init(void)
{
	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
		"%s\n", __func__);

	if (!rda5890_dir)
		rda5890_dir = debugfs_create_dir("rda5890", NULL);

	return;
}
示例#11
0
void rda5890_debugfs_remove_one(struct rda5890_private *priv)
{
	int i;

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

	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
		debugfs_remove(priv->debugfs_files[i]);
	debugfs_remove(priv->debugfs_dir);
}
示例#12
0
static void sdio_tput_test_write(struct rda5890_private *priv, int iter, int len)
{
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf_1 = (char *)addr;
	char *buf_2 = (char *)addr + PAGE_SIZE/2;
	char cmd[SDIO_TEST_CMD_LEN];
	int i;
	int ret;

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		"%s, iter = %d, len = %d\n", __func__, iter, len);

	for (i=0; i<len; i++) {
		buf_1[i] = len - i - 1;
		buf_2[i] = i;
	}

	(*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC;
	(*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_H2C_START;
	(*(volatile unsigned long *)(cmd + 8)) = iter;
	(*(volatile unsigned long *)(cmd + 12)) = len;
	ret = priv->hw_host_to_card(priv, cmd, len,SDIO_TEST_CMD_LEN);
	if (ret) {
		RDA5890_ERRP("START cmd send fail, ret = %d\n", ret);
		goto out;
	}

	send_time_start = jiffies;
	for (i=0;i<iter;i++) {
		if (!(i & 1))
			ret = priv->hw_host_to_card(priv, buf_1, len, DATA_REQUEST_PACKET);
		else
			ret = priv->hw_host_to_card(priv, buf_2, len, DATA_REQUEST_PACKET);
		if (ret) {
			RDA5890_ERRP("packet %d send fail, ret = %d\n", i, ret);
			goto out;
		}
	}
	send_time_end = jiffies;

	(*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC;
	(*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_H2C_STOP;
	(*(volatile unsigned long *)(cmd + 8)) = iter;
	(*(volatile unsigned long *)(cmd + 12)) = len;
	ret = priv->hw_host_to_card(priv, cmd, len, SDIO_TEST_CMD_LEN);
	if (ret) {
		RDA5890_ERRP("START cmd send fail, ret = %d\n", ret);
		goto out;
	}

out:
	free_page(addr);
}
示例#13
0
static ssize_t rda5890_sdio_tput(struct file *file,
				const char __user *user_buf, size_t count,
				loff_t *ppos)
{
	struct rda5890_private *priv = file->private_data;
	int ret;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
	int wr, iter, len;

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

	if (copy_from_user(buf, user_buf, count)) {
		ret = -EFAULT;
		goto out_unlock;
	}
	ret = sscanf(buf, "%d %d %d", &wr, &iter, &len);
	if (ret != 3) {
		RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
			"Error Input, format shall be [wr iter len]\n");
		ret = -EINVAL;
		goto out_unlock;
	}

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		"input wr = %d, iter = %d, len = %d\n",
		wr, iter, len);

	if (wr)
		sdio_tput_test_write(priv, iter, len);
	else
		sdio_tput_test_read(priv, iter, len);

	ret = count;
out_unlock:
	free_page(addr);
	return ret;
}
示例#14
0
void dump_buf(char *data, size_t len)
{
    char temp_buf[64];
    size_t i, off = 0;

    memset(temp_buf, 0, 64);
    for (i=0;i<len;i++) {
        if(i%8 == 0) {
            sprintf(&temp_buf[off], "  ");
            off += 2;
        }
        sprintf(&temp_buf[off], "%02x ", data[i]);
        off += 3;
        if((i+1)%16 == 0) {
            RDA5890_DBGLAP(RDA5890_DA_ALL, RDA5890_DL_TRACE,
                "%s\n", temp_buf);
            memset(temp_buf, 0, 64);
            off = 0;
        }
    }
    RDA5890_DBGLAP(RDA5890_DA_ALL, RDA5890_DL_TRACE, "\n");
}
示例#15
0
static ssize_t rda5890_debuglevel_read(struct file *file, char __user *userbuf,
				  size_t count, loff_t *ppos)
{
	//struct rda5890_private *priv = file->private_data;
	size_t pos = 0;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
	ssize_t res;

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

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		"get debug_level = 0x%x\n",rda5890_dbg_level);

	pos += snprintf(buf+pos, PAGE_SIZE - pos, "%x\n",
				rda5890_dbg_level);

	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);

	free_page(addr);
	return res;
}
示例#16
0
static ssize_t rda5890_sdio_write(struct file *file,
				const char __user *user_buf, size_t count,
				loff_t *ppos)
{
	struct rda5890_private *priv = file->private_data;
	unsigned long addr = get_zeroed_page(GFP_KERNEL);
	char *buf = (char *)addr;
	int iter, len, i;
	int ret;

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

	if (copy_from_user(buf, user_buf, count)) {
		ret = -EFAULT;
		goto out_unlock;
	}
	ret = sscanf(buf, "%d %d", &iter, &len);
	if (ret != 2) {
		ret = -EINVAL;
		goto out_unlock;
	}

	if (len > 1660) {
		ret = -EINVAL;
		goto out_unlock;
	}

	for (i=0; i<len; i++) {
		buf[i] = len - i - 1;
	}

	for (i=0;i<iter;i++) {
		//RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		//	"Host to Card, len = %d\n", len);

		ret = priv->hw_host_to_card(priv, buf, len, DATA_REQUEST_PACKET);

		//RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		//	"Host to Card done, ret = %d\n", ret);
	}

out_unlock:
	free_page(addr);
	return count;
}
示例#17
0
static void sdio_tput_test_read(struct rda5890_private *priv, int iter, int len)
{
	char cmd[SDIO_TEST_CMD_LEN];
	int ret;

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		"%s, iter = %d, len = %d\n", __func__, iter, len);

	(*(volatile unsigned long *)(cmd + 0)) = SDIO_TEST_CMD_MAGIC;
	(*(volatile unsigned long *)(cmd + 4)) = SDIO_TEST_CMD_TYPE_C2H_START;
	(*(volatile unsigned long *)(cmd + 8)) = iter;
	(*(volatile unsigned long *)(cmd + 12)) = len;
	ret = priv->hw_host_to_card(priv, cmd, len ,SDIO_TEST_CMD_LEN);
	if (ret) {
		RDA5890_ERRP("START cmd send fail, ret = %d\n", ret);
	}
}
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;
}
示例#19
0
void rda5890_sdio_test_card_to_host(char *buf, unsigned short len)
{
	int i;
	int cmd, cmd_iter, cmd_len;
	int time_ms;
	static int recv_pattern = 0;
	static int recv_tput_flag = 0;
	static int recv_pkts = 0;
	static int recv_bytes = 0;

	//RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
	//	"SDIO TEST Card to Host, len = %d\n", len);

	if (debug_read_flag) {
		RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
			"DEBUG RX, len = %d\n", len);
		dump_buf(buf, len);
	}

	if ((*(volatile unsigned long *)buf == SDIO_TEST_CMD_MAGIC)
			&& len == SDIO_TEST_CMD_LEN) {
		cmd = (int)(*(volatile unsigned long *)(buf + 4));
		cmd_iter = (int)(*(volatile unsigned long *)(buf + 8));
		cmd_len = (int)(*(volatile unsigned long *)(buf + 12));
		//RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
		//		"SDIO TEST CMD: cmd = %d, iter = %d, len = %d\n", 
		//		cmd, cmd_iter, cmd_len);
		switch (cmd) {
		case SDIO_TEST_CMD_TYPE_H2C_STATUS:
			RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
				"H2C STATUS CMD \n");
			time_ms = jiffies_to_msecs(send_time_end - send_time_start);
			RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
				"SDIO H2C STATUS: pkts = %d, bytes = %d, time = %d ms\n",
				cmd_iter, cmd_len, time_ms);
			break;
		case SDIO_TEST_CMD_TYPE_C2H_PILOT:
			//RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
			//	"C2H PILOT CMD \n");
			recv_pattern = 0;
			recv_tput_flag = 1;
			recv_pkts = 0;
			recv_bytes = 0;
			recv_time_start = jiffies;
			break;
		case SDIO_TEST_CMD_TYPE_C2H_END:
			//RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
			//	"C2H END CMD \n");
			recv_time_end = jiffies;
			recv_tput_flag = 0;
			time_ms = jiffies_to_msecs(recv_time_end - recv_time_start);
			RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
				"SDIO C2H STATUS: pkts = %d, bytes = %d, time = %d ms\n",
				recv_pkts, recv_bytes, time_ms);
			break;
		case SDIO_TEST_CMD_TYPE_H2C_START:
		case SDIO_TEST_CMD_TYPE_H2C_STOP:
		case SDIO_TEST_CMD_TYPE_C2H_START:
		default:
			RDA5890_ERRP("SDIO TEST CMD: Invalid cmd %d\n", cmd);
		break;
		}
		return;
	}

	for (i=0;i<len;i++) {
		if (recv_pattern == 0) {
			if (buf[i] != (char)(i)) {
				RDA5890_ERRP("data[%d] error, 0x%02x, should be 0x%02x, len = %d\n", 
					i, buf[i], (char)(i), len);
				break;
			}
		}
		else {
			if (buf[i] != (char)(len - i - 1)) {
				RDA5890_ERRP("data[%d] error, 0x%02x, should be 0x%02x, len = %d\n", 
					i, buf[i], (char)(len - i - 1), len);
				break;
			}
		}
	}

	if (recv_tput_flag)
		recv_pattern = !recv_pattern;

	if (recv_tput_flag && i==len) {
		recv_pkts ++;
		recv_bytes += len;
	}
}
u32 rda_hif_sdio_probe(MTK_WCN_HIF_SDIO_CLTCTX cltCtx, MTK_WCN_HIF_SDIO_FUNCINFO* funcInfo)
{   
    struct if_sdio_card *card = NULL;
    struct rda5890_private *priv = NULL;
    struct if_sdio_packet *packet = NULL; 
    int ret = -1;
    unsigned long flags;

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

    printk(KERN_INFO "20120905 RDA5890: SDIO card attached func num %d block size %d \n", funcInfo->func_num, funcInfo->blk_sz);

    if(gCard)
    {
	    RDA5890_ERRP("rda5890 sdio has probed \n");
	    return 0;
    }
    card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
    if (!card) {
    	RDA5890_ERRP("kzalloc fail\n");
    	return -ENOMEM;
    }
    

    card->func = NULL;
    spin_lock_init(&card->lock);  
    atomic_set(&card->wid_complete_flag, 0);
    INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
    card->work_thread = create_singlethread_workqueue("rda5890_if_sdio_worker");
    
#ifdef WIFI_POWER_MANAGER   
    atomic_set(&card->sleep_work_is_active, 0);
    INIT_DELAYED_WORK(&card->sleep_work, if_sdio_sleep_worker); 
#endif

#ifdef WIFI_UNLOCK_SYSTEM 
    atomic_set(&wake_lock_counter, 0);
    wake_lock_init(&sleep_worker_wake_lock, WAKE_LOCK_SUSPEND, "RDA_sleep_worker_wake_lock");
#endif
    
    priv = rda5890_add_card(card);
	if (!priv) {
		RDA5890_ERRP("rda5890_add_card fail\n");
		ret = -ENOMEM;
		goto remove_card;
	}
    rda5890_debugfs_init_one(priv);

    card->priv = priv;
    priv->card = card;
    priv->hw_host_to_card = if_sdio_host_to_card;
    priv->cltCtx = cltCtx;
    
    priv->version = rda_wlan_version();
    priv->version &= 0x1f;
    if(priv->version  != 4 && priv->version  != 7
    	&& priv->version != 5)
    {
        RDA5890_ERRP("no correct version exit wlan initiate \n");
        goto remove_card;
    }

    /*
     * Enable interrupts now that everything is set up
     */
    printk(KERN_INFO " mtk_wcn_hif_sdio_writeb IF_SDIO_FUN1_INT_MASK \n");
    ret = mtk_wcn_hif_sdio_writeb(cltCtx, IF_SDIO_FUN1_INT_MASK, 0x07); 
    if (ret) {
    	RDA5890_ERRP("enable func interrupt fail\n");
    	goto remove_card;
    }

#ifdef WIFI_TEST_MODE
    if(!rda_5990_wifi_in_test_mode())
        {
#endif        
            ret = rda5890_sdio_init(priv);
            if(ret < 0)
                goto remove_card;
			
            gCard = card;
        	ret=rda5890_disable_self_cts(priv);   
            if(ret < 0)
                goto remove_card;

        	ret=rda5890_disable_block_bt(priv);
            if(ret < 0)
                goto remove_card;

            ret = rda5890_set_scan_timeout(priv);
            if (ret) {
                	RDA5890_ERRP("rda5890_set_scan_timeout fail, ret = %d\n", ret);
                	goto remove_card;
            }
        		
            ret= rda5890_set_listen_interval(priv, WIFI_LISTEN_INTERVAL);
            if(ret < 0)
                goto remove_card;

            ret = rda5890_set_link_loss_threshold(priv, WIFI_LINK_LOSS_THRESHOLD);
            if(ret < 0)
                goto remove_card;
            
            ret = rda5890_init_pm(priv);
            if(ret < 0)
                goto remove_card;
            
#ifdef WIFI_TEST_MODE            
        }
    else
        {
            ret = rda5890_set_test_mode(priv);
            if(ret < 0)
                goto remove_card;

			gCard = card;
		}
#endif
#ifdef WIFI_SELECT_CHANNEL    
    // Add for choose operation band, 3rd parameter indicate which band will be used.
    // 0/1: channel1-11, 2:channel1-13, 3:channel1-14, other values: channel1-13
#ifdef  CHANNEL_11
    if (rda5890_generic_set_uchar(priv, 0x0047, 1) < 0)
#elif defined CHANNEL_14
    if (rda5890_generic_set_uchar(priv, 0x0047, 3) < 0)    	
#else /* CHANNEL_13 && others */
    if (rda5890_generic_set_uchar(priv, 0x0047, 2) < 0)    
#endif   		
    {
        RDA5890_ERRP("set op_band failed!\n");
        goto remove_card;
    }
    else
    {
#ifdef  CHANNEL_11    	
		channel_nums = 11;
#elif defined CHANNEL_12
		channel_nums = 12;
#elif defined CHANNEL_14
		channel_nums = 14;
#else /* CHANNEL_13 && others */
		channel_nums = 13;
#endif  		
    }
#endif  
    if (sdio_test_flag) {
        unsigned char mac_addr[6];
        RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_TRACE,
        "SDIO TESTING MODE\n");


        ret = rda5890_get_mac_addr(priv, mac_addr);
        printk(KERN_INFO "Test rda5890_get_mac_addr %x:%x:%x:%x:%x:%x", mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],mac_addr[4],mac_addr[5]);
        goto done;
    }

    ret = rda5890_start_card(priv);
    if (ret) {
    	RDA5890_ERRP("rda5890_start_card fail, ret = %d\n", ret);
    	goto remove_card;
    }
done:
    printk(KERN_INFO "RDA5890: SDIO card started\n");

out:
    RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_DEBUG,
    	"%s ret:%d <<<\n", __func__, ret);
    return ret;

remove_card:   
    
    if (atomic_read(&card->wid_complete_flag) && priv)
    {
        complete(&priv->wid_done);
        printk(KERN_INFO "*****RDA5890: probe send wid complete\n");
    }
    flush_work(&card->packet_worker);
    cancel_work_sync(&card->packet_worker);
    
#ifdef WIFI_POWER_MANAGER
    cancel_delayed_work(&card->sleep_work);
#endif
    destroy_workqueue(card->work_thread);
    
    if(priv)
        rda5890_remove_card(priv);

    while (card->packets) {
    	packet = card->packets;
    	card->packets = card->packets->next;
    	kfree(packet);	
    }
    
    kfree(card);
    gCard = NULL;
    goto out;
}
static int if_sdio_host_to_card(struct rda5890_private *priv,
		u8 *buf, u16 nb, unsigned char packet_type)
{
	int ret = 0;
	struct if_sdio_card *card;
	struct if_sdio_packet *packet, *cur;
	u16 size;
	unsigned long flags;

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

	card = priv->card;
    nb += 2; //for chip packet head
	if (nb > (65536 - sizeof(struct if_sdio_packet))) {
		ret = -EINVAL;
		goto out;
	}

	//size = sdio_align_size(card->func, nb);
	size = nb;
	size = ((size + 3)/4)*4;

	RDA5890_DBGLAP(RDA5890_DA_SDIO, RDA5890_DL_NORM,
		"if_sdio_host_to_card, size = %d, aligned size = %d\n", nb, size);

	packet = kzalloc(sizeof(struct if_sdio_packet) + size,
			GFP_ATOMIC);
	if (!packet) {
		ret = -ENOMEM;
		goto out;
	}

	packet->next = NULL;
	packet->nb = size;
    packet->packet_type = packet_type;
    packet->buffer[0] = (char)((nb)&0xFF);
	packet->buffer[1] = (char)(((nb)>>8)&0x0F);
    if(packet_type == DATA_REQUEST_PACKET)
	    packet->buffer[1] |= 0x10;  // for DataOut 0x1
	else 
        packet->buffer[1] |= 0x40;  //for request
	memcpy(packet->buffer + 2, buf, nb - 2);

	spin_lock_irqsave(&card->lock, flags);

	if (!card->packets)
		card->packets = packet;
	else {
		cur = card->packets;
		while (cur->next)
			cur = cur->next;
		cur->next = packet;
	}

	spin_unlock_irqrestore(&card->lock, flags);

    queue_work(card->work_thread, &card->packet_worker);

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

	ret = 0;

out:
	return ret;
}
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	    
	}
}