//MMC/SD卡中断服务程序 static
irqreturn_t s3cmci_irq(int irq, void *dev_id) { //dev_id参数是申请中断的时候传递过来的s3cmci_host结构
体,void类型的指针可以存放任何的数据类型 struct s3cmci_host *host
= dev_id; struct
mmc_command *cmd; u32 mci_csta, mci_dsta, mci_fsta,
mci_dcnt, mci_imsk; u32 mci_cclear, mci_dclear; unsigned
long iflags;
//关中断并保持状态字 spin_lock_irqsave(&host->complete_lock, iflags);
//分别读命令状态、数据状态、数据保留计数器、FIFO状态、中断屏蔽寄存器的
值 mci_csta =
readl(host->base +
S3C2410_SDICMDSTAT); mci_dsta = readl(host->base + S3C2410_SDIDSTA); mci_dcnt
= readl(host->base + S3C2410_SDIDCNT); mci_fsta
= readl(host->base + S3C2410_SDIFSTA); mci_imsk
= readl(host->base + host->sdiimsk); mci_cclear
= 0; mci_dclear = 0;
//如果当前没有请求状态或者请求已经完成了,则恢复中断什么都不做 if ((host->complete_what == COMPLETION_NONE) || (host->complete_what
== COMPLETION_FINALIZE)) { host->status = "nothing to complete"; clear_imask(host); goto irq_out; }
//如果核心层无MMC/SD请求,则恢复中断什么都不做 if (!host->mrq) { host->status = "no active mrq"; clear_imask(host); goto irq_out; }
//获取当前发送命令有无完成 cmd = host->cmd_is_stop
? host->mrq->stop :
host->mrq->cmd;
//
如果发送命令完成了,则恢复中断什么都不做 if
(!cmd) { host->status = "no active cmd"; clear_imask(host); goto irq_out; }
//判断在数据传输状态时使用的传输方式 if (!host->dodma) { //不是DMA传输。如果是FIFO写,则切换到底半部去进行FIFO的写操作 if ((host->pio_active == XFER_WRITE) && (mci_fsta &
S3C2410_SDIFSTA_TFDET)) { disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); tasklet_schedule(&host->pio_tasklet); host->status = "pio
tx"; }
//如果是FIFO读,则切换到底半部去进行FIFO的读操作 if ((host->pio_active == XFER_READ) && (mci_fsta &
S3C2410_SDIFSTA_RFDET)) { disable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST); tasklet_schedule(&host->pio_tasklet); host->status = "pio
rx"; } }
//命令响应超时 if
(mci_csta &
S3C2410_SDICMDSTAT_CMDTIMEOUT)
{ dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n"); cmd->error = -ETIMEDOUT; host->status = "error: command timeout"; goto
fail_transfer; }
//命令发送结束 if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) { if (host->complete_what == COMPLETION_CMDSENT) { host->status
= "ok: command sent"; goto
close_transfer; }
mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT; }
//收到命令响应,CRC校验失败 if (mci_csta &
S3C2410_SDICMDSTAT_CRCFAIL)
{ if (cmd->flags & MMC_RSP_CRC) { if (host->mrq->cmd->flags &
MMC_RSP_136) { dbg(host, dbg_irq, "fixup: ignore CRC fail with long
rsp\n"); } else { /* note, we used
to fail the transfer * here, but it seems that this
is just * the hardware getting it wrong.
* * cmd->error = -EILSEQ; *
host->status = "error: bad command crc"; * goto
fail_transfer; */ } }
mci_cclear |=
S3C2410_SDICMDSTAT_CRCFAIL; }
//收到命令响应,响应结束 if (mci_csta
&
S3C2410_SDICMDSTAT_RSPFIN) { //如果当前任务是完成,接收命令响应 if (host->complete_what == COMPLETION_RSPFIN)
{ host->status = "ok: command response received"; goto close_transfer;//停止传输
} //当前任务是完成数据传输和接收命令响应 if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) //
标记当前任务为完成数据传输 host->complete_what
= COMPLETION_XFERFINISH;
//清除收到命令响应标志 mci_cclear
|= S3C2410_SDICMDSTAT_RSPFIN; }
if (!cmd->data) goto clear_status_bits;
//FIFO失败 if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) { dbg(host, dbg_err, "FIFO failure\n"); host->mrq->data->error = -EILSEQ; host->status = "error: 2440 fifo failure"; goto fail_transfer; }
//接收CRC错误 if (mci_dsta &
S3C2410_SDIDSTA_RXCRCFAIL) { dbg(host, dbg_err, "bad data crc (outgoing)\n"); cmd->data->error = -EILSEQ; host->status = "error: bad data crc (outgoing)"; goto fail_transfer; }
//发送数据后,CRC状态错误 if (mci_dsta &
S3C2410_SDIDSTA_CRCFAIL) { dbg(host, dbg_err, "bad data crc (incoming)\n"); cmd->data->error = -EILSEQ; host->status = "error: bad data crc (incoming)"; goto fail_transfer; }
//数据/忙接收超时 if (mci_dsta &
S3C2410_SDIDSTA_DATATIMEOUT)
{ dbg(host, dbg_err, "data timeout\n"); cmd->data->error = -ETIMEDOUT; host->status = "error: data timeout"; goto fail_transfer; }
//数据计数器为0,和本次请求的全部数据传输结束 if (mci_dsta &
S3C2410_SDIDSTA_XFERFINISH)
{ //如果当前任务是完成数据传输则结束数据传输 if (host->complete_what == COMPLETION_XFERFINISH) { host->status = "ok: data transfer completed"; goto close_transfer; }
//如果当前任务是完成数据传输和接收命令响应 if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN) //标记当前任务为完成 接收命令响应 host->complete_what =
COMPLETION_RSPFIN;
//清除数据传输完标志 mci_dclear
|= S3C2410_SDIDSTA_XFERFINISH; }
//清除状态字 clear_status_bits: writel(mci_cclear, host->base + S3C2410_SDICMDSTAT); writel(mci_dclear, host->base + S3C2410_SDIDSTA);
goto irq_out;
//
传输失败 fail_transfer: host->pio_active =
XFER_NONE;
//传输结束 close_transfer: host->complete_what
= COMPLETION_FINALIZE;
clear_imask(host); tasklet_schedule(&host->pio_tasklet);
goto
irq_out;
irq_out: dbg(host,
dbg_irq, "csta:0x%08x dsta:0x%08x fsta:0x%08x
dcnt:0x%08x status:%s.\n",
mci_csta, mci_dsta, mci_fsta, mci_dcnt,
host->status);
//开中断并恢复状态字 spin_unlock_irqrestore(&host->complete_lock, iflags); return IRQ_HANDLED; }
//MMC/SD卡
中断底半部程序 static void pio_tasklet(unsigned long
data) { //data
参数是在s3cmci_probe中的tasklet_init的时候传递过来的 struct s3cmci_host *host = (struct s3cmci_host *) data;
//在
执行底半部程序的时候屏蔽中断 disable_irq(host->irq);
//判断如果当前存在FIFO的写状态,则进行FIFO的写操作 if (host->pio_active ==
XFER_WRITE) do_pio_write(host);
//判断如果当前存在FIFO的读状态,则进行FIFO的读操作 if (host->pio_active ==
XFER_READ) do_pio_read(host);
//判断如果当前的请求状态为完成状态,则准备进行完成请求处理 if (host->complete_what == COMPLETION_FINALIZE)
{ //清空中断屏蔽寄存器 clear_imask(host); //FIFO状态验证 if (host->pio_active !=
XFER_NONE) { if (host->mrq->data) host->mrq->data->error = -EINVAL; }
//完成请求处理 finalize_request(host); } else //当前请求状态为其他,则使能中断继续请求处理 enable_irq(host->irq); }
//完成请求处理 static void
finalize_request(struct s3cmci_host *host) { struct mmc_request *mrq = host->mrq; struct
mmc_command *cmd = host->cmd_is_stop
? mrq->stop
: mrq->cmd; int debug_as_failure = 0;
//如果当前请求状态不为完成状态,则为错误 if (host->complete_what != COMPLETION_FINALIZE) return;
if
(!mrq) return;
if
(cmd->data
&& (cmd->error == 0) && (cmd->data->error == 0)) { if (host->dodma && (!host->dma_complete)) { dbg(host,
dbg_dma, "DMA Missing!\n"); return; } }
//读响应寄存器 cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0); cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1); cmd->resp[2] = readl(host->base +
S3C2410_SDIRSP2); cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);
writel(host->prescaler,
host->base +
S3C2410_SDIPRE);
if (cmd->error) debug_as_failure = 1;
if
(cmd->data
&& cmd->data->error) debug_as_failure = 1;
dbg_dumpcmd(host, cmd,
debug_as_failure);
//清空命令参数、数据配置、命令配置、中断屏蔽寄存器 writel(0, host->base + S3C2410_SDICMDARG); writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); writel(0, host->base + S3C2410_SDICMDCON); writel(0, host->base + host->sdiimsk);
if
(cmd->data
&& cmd->error) cmd->data->error = cmd->error;
//有数据请求,有传输停止命令,数据传输命令已发送 if (cmd->data &&
cmd->data->stop &&
(!host->cmd_is_stop)) { host->cmd_is_stop =
1; s3cmci_send_request(host->mmc);//传输停止命令
return; }
if (!mrq->data) goto request_done;
//计算已传
输的数据量 if (mrq->data->error == 0) { mrq->data->bytes_xfered = (mrq->data->blocks
* mrq->data->blksz); } else
{ mrq->data->bytes_xfered = 0; }
if (mrq->data->error != 0) { if (host->dodma) s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
//
清除和复位FIFO状态寄存器 writel(S3C2440_SDIFSTA_FIFORESET | S3C2440_SDIFSTA_FIFOFAIL, host->base + S3C2410_SDIFSTA); }
//完成请求 request_done: host->complete_what
= COMPLETION_NONE; host->mrq
= NULL; mmc_request_done(host->mmc, mrq); }
|