主要平台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();//是为了保证编译器顺序编译,防止编译器优化打乱执行顺序
读数据和该流程类似。