wifi SDIO读写数据

主要平台imx6,wifi芯片为博通

写数据

dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
{
....
	dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
}
dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
    dhd_bus_txdata(dhdp->bus, pktbuf);
        dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
             dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
 bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes,pkt, complete, handle);
     bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
        sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr,PKTDATA(sd->osh, tmppkt), ROUNDUP(buf_len, (DMA_ALIGN_MASK+1)));
            sdio_memcpy_toio(sd->func[func], addr, buf, len);

以上主要描述了驱动主要写数据流程,下面具体分析

最后主要调用

int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
{
	struct mmc_request mrq = {0};
	struct mmc_command cmd = {0};
	struct mmc_data data = {0};
	struct scatterlist sg;

	BUG_ON(!card);
	BUG_ON(fn > 7);
	BUG_ON(blocks == 1 && blksz > 512);
	WARN_ON(blocks == 0);
	WARN_ON(blksz == 0);

	/* sanity check */
	if (addr & ~0x1FFFF)
		return -EINVAL;

	mrq.cmd = &cmd;
	mrq.data = &data;

	cmd.opcode = SD_IO_RW_EXTENDED; //cmd53
	cmd.arg = write ? 0x80000000 : 0x00000000; //读写
	cmd.arg |= fn << 28;//func->num
	cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
	cmd.arg |= addr << 9;//地址
	if (blocks == 1 && blksz <= 512)
		cmd.arg |= (blksz == 512) ? 0 : blksz;	/* byte mode */
	else
		cmd.arg |= 0x08000000 | blocks;		/* block mode */
	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;

	data.blksz = blksz;
	data.blocks = blocks;
	data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
	data.sg = &sg;
	data.sg_len = 1;

	sg_init_one(&sg, buf, blksz * blocks);//初始化sg,找到buf对应的物理页地址,为DMA传输做准备

	mmc_set_data_timeout(&data, card);

	mmc_wait_for_req(card->host, &mrq);//发送数据,并且等待返回

	if (cmd.error)  
		return cmd.error;
	if (data.error)
		return data.error;

	if (mmc_host_is_spi(card->host)) {
		/* host driver already reported errors */
	} else {  //返回数据处理R5
		if (cmd.resp[0] & R5_ERROR)
			return -EIO;
		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
			return -EINVAL;
		if (cmd.resp[0] & R5_OUT_OF_RANGE)
			return -ERANGE;
	}

	return 0;
}

调用host->ops->request(host, mrq); 

即sdhci_request发送数据  

        sdhci_send_command(host, mrq->cmd);调用

                

static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
{

	sdhci_prepare_data(host, cmd);//准备DMA数据,设置需要的寄存器
	sdhci_set_transfer_mode(host, cmd);//设置传输mo
void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd);
//0x02190000
	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);//用于传输数据
}
//
void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
{
         sdhci_pre_dma_transfer(host, data, NULL);
     sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
       /* Set the DMA boundary value and block size */
sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,data->blksz), SDHCI_BLOCK_SIZE);sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);}
static void sdhci_set_transfer_irqs(struct sdhci_host *host)
{
 sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
}

static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
{//02000008 0x00000030   110000
	u32 ier;
	ier = sdhci_readl(host, SDHCI_INT_ENABLE);
	ier &= ~clear;
	ier |= set; //02000008  0000 0010 0000 0000 0000 0000 0000 1000
	sdhci_writel(host, ier, SDHCI_INT_ENABLE);//清中断
	sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);//产生中断,使能中断了
	//sdhci_irq
}

sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
准备好DMA数据以后,写SDHCI_COMMAND为触发中断,调用host DMA中断处理数据sdhci_irq,


static irqreturn_t sdhci_irq(int irq, void *dev_id)
{
	irqreturn_t result;
	struct sdhci_host* host = dev_id;
	u32 intmask;
	int cardint = 0;

	spin_lock(&host->lock);

	intmask = sdhci_readl(host, SDHCI_INT_STATUS);

	if (!intmask || intmask == 0xffffffff) {
		result = IRQ_NONE;
		goto out;
	}

	printk("*** %s got interrupt: 0x%08x\n",
		mmc_hostname(host->mmc), intmask);

	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { //卡插入或者拔出,热插拔
		sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
			SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
		tasklet_schedule(&host->card_tasklet);
	}

	intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);


    if (intmask & SDHCI_INT_CMD_MASK) {//cmd
		sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
			SDHCI_INT_STATUS);
		sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
	}

	if (intmask & SDHCI_INT_DATA_MASK) {//data 
		sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
			SDHCI_INT_STATUS);
		sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);//DMA数据处理
	}

	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);

	intmask &= ~SDHCI_INT_ERROR;

	if (intmask & SDHCI_INT_BUS_POWER) {
		printk(KERN_ERR "%s: Card is consuming too much power!\n",
			mmc_hostname(host->mmc));
		sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
	}

	mmiowb();

mmiowb();//是为了保证编译器顺序编译,防止编译器优化打乱执行顺序

读数据和该流程类似。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值