//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) ; } 转自:http://blog.chinaunix.net/u3/101649/showart_2246773.html |