Linux设备驱动子系统第二弹- SD卡 - 图文(5)

2019-08-31 13:59

host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; if (data->flags & MMC_DATA_READ) {

host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); } else {

host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; }

host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); }

host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP; wmb();

DDADR(host->dma) = host->sg_dma; DCSR(host->dma) = DCSR_RUN; }

for()循环里的内容是整个SD卡主控制器设备驱动的实质,通过DMA的方式实现主控制器与SD卡之间数据的读写操作。

3) pxamci_start_cmd 实现主控制器与SD卡之间指令的传输

static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) {

host->cmd = cmd;

if (cmd->flags & MMC_RSP_BUSY) cmdat |= CMDAT_BUSY;

#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) switch (RSP_TYPE(mmc_resp_type(cmd))) { case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */ cmdat |= CMDAT_RESP_SHORT; break;

case RSP_TYPE(MMC_RSP_R3): cmdat |= CMDAT_RESP_R3; break;

case RSP_TYPE(MMC_RSP_R2): cmdat |= CMDAT_RESP_R2;

break; default: break; }

writel(cmd->opcode, host->base + MMC_CMD); writel(cmd->arg >> 16, host->base + MMC_ARGH); writel(cmd->arg & 0xffff, host->base + MMC_ARGL); writel(cmdat, host->base + MMC_CMDAT); pxamci_start_clock(host);

pxamci_enable_irq(host, END_CMD_RES); }

-> response类型

根据SD卡的协议,当SD卡收到从控制器发来的cmd指令后,SD卡会发出response相应,而response的类型分为R1,R1b,R2,R3,R6,R7,这些类型分别对应不同的指令,各自的数据包结构也不同(具体内容参考SD卡协议)。这里,通过RSP_TYPE对指令cmd的opcode的解析得到相对应的reponse类型,再通过swich赋给寄存器MMC_CMDAT对应的[1:0]位。

-> 将指令和参数写入寄存器

4行writel()是整个SD卡主控制器设备驱动的实质,通过对主控制器芯片寄存器MMC_CMD,MMC_ARGH,MMC_ARGL,MMC_CMDAT的设置,实现主控制器发送指令到SD卡的功能。 4) 调用(*request) 以上通过pxamci_request()实现了主控制器的通信功能,之后只须通过host->ops->request(host, mrq);回调函数即可。

协议层里,每条指令都会通过mmc_wait_for_req(host, &mrq)调用到host->ops->request(host, mrq)来发送指令和数据。 /* core/core.c */

void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) {

DECLARE_COMPLETION_ONSTACK(complete); mrq->done_data = &complete; mrq->done = mmc_wait_done; mmc_start_request(host, mrq); wait_for_completion(&complete); }

mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { ... ...

host->ops->request(host, mrq); }

2.2.4 申请中断

pxamci_probe(struct platform_device *pdev)中有两个中断,一个为SD主控制器芯片内电路固有的内部中断,另一个为探测引脚的探测到外部有SD卡插拔引起的中断。 1) 由主控芯片内部电路引起的中断

request_irq(host->irq, pxamci_irq, 0, \回顾一下,host->irq就是刚才从platform_device里得到的中断号, irq = platform_get_irq(pdev, 0); host->irq = irq;

接下来,pxamci_irq便是为该中断host->irq申请的中断函数, static irqreturn_t pxamci_irq(int irq, void *devid) {

struct pxamci_host *host = devid; // 得到主控制器的数据 unsigned int ireg; int handled = 0;

ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK); // 读取中断寄存器的值 if (ireg) {

unsigned stat = readl(host->base + MMC_STAT); // 读取状态寄存器的值 if (ireg & END_CMD_RES)

handled |= pxamci_cmd_done(host, stat); if (ireg & DATA_TRAN_DONE)

handled |= pxamci_data_done(host, stat); if (ireg & SDIO_INT) {

mmc_signal_sdio_irq(host->mmc); } }

return IRQ_RETVAL(handled); }

当调用(*request),即host->ops->request(host, mrq),即上文中的pxamci_request()后,控制器与SD卡之间开始进行一次指令或数据传输,通信完毕后,主控芯片将产生一个内部

中断,以告知此次指令或数据传输完毕。这个中断的具体值将保存在一个名为MMC_I_REG的中断寄存器中以供读取,中断寄存器MMC_I_REG中相关描述如下,

如果中断寄存器MMC_I_REG中的第0位有值,则意味着数据传输完成,执行pxamci_cmd_done(host, stat);

如果中断寄存器MMC_I_REG中的第2位有值,则意味着指令传输完成,执行pxamci_data_done(host, stat);

其中stat是从状态寄存器MMC_STAT中读取的值,在代码里主要起到处理错误状态的作用。

-> pxamci_cmd_done 收到结束指令的内部中断信号,主控制器从SD卡那里得到response,结束这次指令传输

这里需要注意,寄存器MMC_RES里已经存放了来自SD卡发送过来的response,以供读取。

static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) {

struct mmc_command *cmd = host->cmd;

cmd->resp[i] = readl(host->base + MMC_RES) & 0xffff; if (stat & STAT_TIME_OUT_RESPONSE) { cmd->error = -ETIMEDOUT;

} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { cmd->error = -EILSEQ; }

pxamci_disable_irq(host, END_CMD_RES); if (host->data && !cmd->error) {

pxamci_enable_irq(host, DATA_TRAN_DONE); } else {

pxamci_finish_request(host, host->mrq); // 结束一次传输,清空主控制器中的指令和数据 }

return 1; }

-> pxamci_data_done 收到结束数据的内部中断信号,得到传输数据的大小,结束这次数据传输

static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) {

struct mmc_data *data = host->data; DCSR(host->dma) = 0;

dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, host->dma_dir); if (stat & STAT_READ_TIME_OUT) data->error = -ETIMEDOUT;

else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) data->error = -EILSEQ; if (!data->error)

data->bytes_xfered = data->blocks * data->blksz; // 数据传输量=块的数量*每个块的大小(一般为512字节) else

data->bytes_xfered = 0;

pxamci_disable_irq(host, DATA_TRAN_DONE); host->data = NULL;

pxamci_finish_request(host, host->mrq); ... ... }

static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) {

host->mrq = NULL; host->cmd = NULL; host->data = NULL;

mmc_request_done(host->mmc, mrq); set_mmc_cken(host, 0); unset_dvfm_constraint(); }

/* drivers/mmc/core/core.c */

void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) {


Linux设备驱动子系统第二弹- SD卡 - 图文(5).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:太阳能热水器控制仪使用说明书资料

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: