长沙专业外贸建站公司,江西鄱阳专业做网站,自己做的网站如何让百度搜索,深圳市住房和建设网前面对SD卡控制器有了一个基本的介绍。其实SD控制器层更过的意义是为core层提供一种操作SD卡硬件的一种方法#xff0c;当然不同的控制器对硬件控制的方法不尽相同#xff0c;但是他们最终都能像core层提交一个统一的封装有操作方法的数据结构#xff0c;那便是即将闪亮登场… 前面对SD卡控制器有了一个基本的介绍。其实SD控制器层更过的意义是为core层提供一种操作SD卡硬件的一种方法当然不同的控制器对硬件控制的方法不尽相同但是他们最终都能像core层提交一个统一的封装有操作方法的数据结构那便是即将闪亮登场的struct mmc_host_ops....对应的host文件为s3cmci.c。 接下来就来揭开与之对应的struct mmc_host_ops结构的神秘面纱.... [cpp] view plaincopy static struct mmc_host_ops s3cmci_ops { .request s3cmci_request, .set_ios s3cmci_set_ios, .get_ro s3cmci_get_ro, .get_cd s3cmci_card_present, .enable_sdio_irq s3cmci_enable_sdio_irq, }; 在讲述每个方法具体的实现之前先来对struct mmc_host_ops结构中的各个成员有个简单的认识。 request方法无论是前面所说的单纯的命令传输还是带有数据的传输过程无一例外最终都是调用request来实现的那么如您所想他也将成为这个舞台万众瞩目的焦点。 set_ios方法用于设置SD卡控制器前面我们所见到的设置控制器时钟数据线宽度等等一系列操作最终就是通过他来实现的。 get_ro方法获取卡的写保护状态前面所过SD卡初始化完成以后我们进行的一个最后的工作便是检测卡的写保护状态其实就是调用get_ro方法。 get_cd方法检测卡是否在卡槽之中它所对应的函数前面已经在初始化中分析过了这里不再单独列来。 enable_sdio_irq方法就是使能SDIO卡的中断这个是对sdio卡而言的这里将不做重点分析。 有了一个初步的了解之后接下来的时间就来各个击破了本着由浅入深的原则我们先来看看s3cmci_get_ro。 一、s3cmci_get_ro 从SD卡结构上来说有个写保护的开关这就使得判断SD卡是否写保护可以从其机械特征上入手从而特殊设计的SD卡槽为我们提供了方便。在这里采用的方法正是利用了这种特殊设计的SD卡槽带来的优势因此只需要读取SD卡槽的SD写保护引脚的状态就能判定卡写保护的情况。实现的代码如下 [cpp] view plaincopy static int s3cmci_get_ro(struct mmc_host *mmc) { struct s3cmci_host *host mmc_priv(mmc); struct s3c24xx_mci_pdata *pdata host-pdata; int ret; if (pdata-no_wprotect) return 0; ret gpio_get_value(pdata-gpio_wprotect) ? 1 : 0; ret ^ pdata-wprotect_invert; return ret; } 第10行正是获取SD写保护引脚的值当然由于硬件设计上的不同可能带来状态上的取反所以这里有个pdata-wprotect_invert标记决定是否应该反相。对于只读来说应该返回1否则该方法的返回值为0。 二、s3cmci_set_ios 根据我们前面所见到的种种设置这里的ioset可能会相对烦锁一些具体的代码如下 [cpp] view plaincopy static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct s3cmci_host *host mmc_priv(mmc); u32 mci_con; /* Set the power state */ mci_con readl(host-base S3C2410_SDICON); switch (ios-power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: /* Configure GPE5...GPE10 pins in SD mode */ s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2), S3C_GPIO_PULL_NONE); if (host-pdata-set_power) host-pdata-set_power(ios-power_mode, ios-vdd); if (!host-is2440) mci_con | S3C2410_SDICON_FIFORESET; break; case MMC_POWER_OFF: default: gpio_direction_output(S3C2410_GPE(5), 0); if (host-is2440) mci_con | S3C2440_SDICON_SDRESET; if (host-pdata-set_power) host-pdata-set_power(ios-power_mode, ios-vdd); break; } s3cmci_set_clk(host, ios); /* Set CLOCK_ENABLE */ if (ios-clock) mci_con | S3C2410_SDICON_CLOCKTYPE; else mci_con ~S3C2410_SDICON_CLOCKTYPE; writel(mci_con, host-base S3C2410_SDICON); if ((ios-power_mode MMC_POWER_ON) || (ios-power_mode MMC_POWER_UP)) { dbg(host, dbg_conf, running at %lukHz (requested: %ukHz).\n, host-real_rate/1000, ios-clock/1000); } else { dbg(host, dbg_conf, powered down.\n); } host-bus_width ios-bus_width; } 8行对SD卡控制器的设置最直接的莫过于对寄存器S3C2410_SDICON的访问了为了保证后面不改变其他无关位的值这里先读取S3C2410_SDICON中的当前值保存。 10-39行是SD控制器工作状态的设定对ioset来说swith无疑是他最好的朋友当MMC_POWER_UP时SD控制器的相应管脚会得到正确的初始化。其他的如fifo也将被正确复位。 41-47行就是对sd控制器时钟的设置最终一切ioset的成功归功于49行将重新设置的S3C2410_SDICON状态写入寄存器从此新的控制器状态生效。 那么在主机驱动层中的一个请求处理是怎么通过核心层提交到块设备请求层的呢 在网上找到一副图来说明他们之间的关联和处理流程如下图 三、s3cmci_request 结构体mmc_request定义于/include/linux/mmc/core.h它主要存放两大数据结构的指针分别是cmd和data顾名思意一个为指令一个为数据 也就是说mmc_request结构体存放了进行主控制器与sd卡间通信所需要的指令和数据 [cpp] view plaincopy static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct s3cmci_host *host mmc_priv(mmc); host-status mmc request; host-cmd_is_stop 0; host-mrq mrq; if (s3cmci_card_present(mmc) 0) { dbg(host, dbg_err, %s: no medium present\n, __func__); host-mrq-cmd-error -ENOMEDIUM; mmc_request_done(mmc, mrq); } else s3cmci_send_request(mmc); } 第9行判断SD卡是否还在卡槽之中如果已经拔出那不客气mmc_request_done将帮您结束这个请求。怎么个解决法还是先看看mmc_request_done的代码: mmc_request_done [core/core.c] [cpp] view plaincopy /** * mmc_request_done - finish processing an MMC request * host: MMC host which completed request * mrq: MMC request which request * * MMC drivers should call this function when they have completed * their processing of a request. */ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) { struct mmc_command *cmd mrq-cmd; int err cmd-error; if (err cmd-retries mmc_host_is_spi(host)) { if (cmd-resp[0] R1_SPI_ILLEGAL_COMMAND) cmd-retries 0; } if (err cmd-retries !mmc_card_removed(host-card)) { /* * Request starter must handle retries - see * mmc_wait_for_req_done(). */ if (mrq-done) mrq-done(mrq); } else { mmc_should_fail_request(host, mrq); led_trigger_event(host-led, LED_OFF); pr_debug(%s: req done (CMD%u): %d: %08x %08x %08x %08x\n, mmc_hostname(host), cmd-opcode, err, cmd-resp[0], cmd-resp[1], cmd-resp[2], cmd-resp[3]); if (mrq-data) { pr_debug(%s: %d bytes transferred: %d\n, mmc_hostname(host), mrq-data-bytes_xfered, mrq-data-error); } if (mrq-stop) { pr_debug(%s: (CMD%u): %d: %08x %08x %08x %08x\n, mmc_hostname(host), mrq-stop-opcode, mrq-stop-error, mrq-stop-resp[0], mrq-stop-resp[1], mrq-stop-resp[2], mrq-stop-resp[3]); } if (mrq-done) mrq-done(mrq); mmc_host_clk_release(host); } } 14行如果是SPI传输出现错误而且还有重试的机会那么只要SPI不忽略这个命令那么就还是给他重试的机会也就到了85-91行继续调用host-ops-request(host, mrq);提交请求否则既然是SPI忽略了这个命令无论重试多少次都不会有结果那么就干脆一不做二不休cmd-retries 0; 14-16行就是只要设备有重生的机会就还是继续拯救... 26-51行如果传输无误或者重试次数到了就会执行。其中多半是调试信息。 50-51行许下的承诺就好比欠下的债前面我们讨论mmc_wait_for_req的时候有这么两句 mrq-done_data complete; mrq-done mmc_wait_done; 然后我们说N年以后的某一天我们会和mmc_wait_done 再聚首这里51 行便是调用的mmc_wait_done。内容如下 mmc_wait_done [core/core.c] [cpp] view plaincopy static void mmc_wait_done(struct mmc_request *mrq) { complete(mrq-done_data); } 还记得mmc_wait_for_req中为了你苦苦等待的那个wait_for_completion(complete)因为等待所以她进入了睡眠。现在事情做完了他重新回来调用complete(mrq-done_data)唤醒这个沉睡的内核精灵。说到这好奇的人难免会问那要是一直出错又该是谁来唤醒他呢带着疑问我们继续向前.... 回到s3cmci_request,如果卡还存在的话s3cmci_send_request将真正开始这个请求的处理。 s3cmci_send_request [host/s3cmci.c] [cpp] view plaincopy static void s3cmci_send_request(struct mmc_host *mmc) { struct s3cmci_host *host mmc_priv(mmc); struct mmc_request *mrq host-mrq; struct mmc_command *cmd host-cmd_is_stop ? mrq-stop : mrq-cmd; host-ccnt; prepare_dbgmsg(host, cmd, host-cmd_is_stop); /* Clear command, data and fifo status registers Fifo clear only necessary on 2440, but doesnt hurt on 2410 */ writel(0xFFFFFFFF, host-base S3C2410_SDICMDSTAT); writel(0xFFFFFFFF, host-base S3C2410_SDIDSTA); writel(0xFFFFFFFF, host-base S3C2410_SDIFSTA); if (cmd-data) { int res s3cmci_setup_data(host, cmd-data); host-dcnt; if (res) { dbg(host, dbg_err, setup data error %d\n, res); cmd-error res; cmd-data-error res; mmc_request_done(mmc, mrq); return; } if (s3cmci_host_usedma(host)) res s3cmci_prepare_dma(host, cmd-data); else res s3cmci_prepare_pio(host, cmd-data); if (res) { dbg(host, dbg_err, data prepare error %d\n, res); cmd-error res; cmd-data-error res; mmc_request_done(mmc, mrq); return; } } /* Send command */ s3cmci_send_command(host, cmd); /* Enable Interrupt */ s3cmci_enable_irq(host, true); } 13-15行全部写入1是为了清除之前传输的SDI命令状态寄存器、SDI数据状态寄存器以及SDI FIFO状态寄存器。这是在一次新的传输之前所必须有的初始化工作否则可能出现未知的状态错误。 17行cmd-data实际上就是mmc_request-data前面没少对他进行介绍。与之相类似的还有stop-data。这里我们姑且不说带有数据的传输过程先来看看SD卡命令的实现。也就是1171行s3cmci_send_command(host, cmd); 命令、数据发送流程如下图 1、发送命令 s3cmci_send_command(host, cmd) [host/s3cmci.c] [cpp] view plaincopy static void s3cmci_send_command(struct s3cmci_host *host, struct mmc_command *cmd) { u32 ccon, imsk; imsk S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT | S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT | S3C2410_SDIIMSK_RESPONSECRC; enable_imask(host, imsk); if (cmd-data) host-complete_what COMPLETION_XFERFINISH_RSPFIN; else if (cmd-flags MMC_RSP_PRESENT) host-complete_what COMPLETION_RSPFIN; else host-complete_what COMPLETION_CMDSENT; writel(cmd-arg, host-base S3C2410_SDICMDARG); ccon cmd-opcode S3C2410_SDICMDCON_INDEX; ccon | S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART; if (cmd-flags MMC_RSP_PRESENT) ccon | S3C2410_SDICMDCON_WAITRSP; if (cmd-flags MMC_RSP_136) ccon | S3C2410_SDICMDCON_LONGRSP; writel(ccon, host-base S3C2410_SDICMDCON); } 6-8行是使能相应的中断其中包括CRC校验错误、命令超时、收到命令响应等等。具体的中断屏蔽寄存器的内容可以参考S3C2440用户手册。 12-17行实际上指当前的这个命令结束时候应该所处的状态中断处理函数将实际硬件的完成情况与这个状态相比较最终得到这个命令执行的结果。而cmd-flags正是前面提交命令之前根据不同命令的实际情况来设置的比如具有应答数据的命令可能需要设置cmd-flags | MMC_RSP_PRESENT。然后对应的结束状态也就应该是COMPLETION_RSPFIN收到应答。前面说过host-complete_what是个枚举类型的变量包含了整个命令过程的各个阶段内容如下 [cpp] view plaincopy enum s3cmci_waitfor { COMPLETION_NONE, COMPLETION_FINALIZE, COMPLETION_CMDSENT, COMPLETION_RSPFIN, COMPLETION_XFERFINISH, COMPLETION_XFERFINISH_RSPFIN, }; 一般的命令可能无应答阶段我们默认数据传输正确完成以后即认为命令执行完成也就是17行对应的host-complete_what COMPLETION_CMDSENT; 19行是对命令命令参数寄存器的设置cmd-arg是一个32bit的整数这里如实填写即可。 21行之后的内容就是对控制寄存器的设置了由于控制寄存器比较重要这里列出他寄存器位的信息如下对照上表应该不难分析函数中所设置的每一位的具体含义这里就不再一一解释了。SDICmdCon[8]的置位使得SD控制器开始发送命令。回到s3cmci_send_request.... 前一段第50行s3cmci_enable_irq(host, true); 就是使能SDI 控制器的中断。然而s3cmci_send_command 中间的944 行设置imr|S3C2410_SDIIMSK_CMDSENT命中注定命令发出以后产生一个相应的中断接下来就进入probe 阶段所注册的那个SDI 中断request_irq(host-irq, s3cmci_irq, 0, DRIVER_NAME, host)。 request_irq(host-irq, s3cmci_irq, 0, DRIVER_NAME, host) [host/s3cmci.c] [cpp] view plaincopy /* * ISR for SDI Interface IRQ * Communication between driver and ISR works as follows: * host-mrq points to current request * host-complete_what Indicates when the request is considered done * COMPLETION_CMDSENT when the command was sent * COMPLETION_RSPFIN when a response was received * COMPLETION_XFERFINISH when the data transfer is finished * COMPLETION_XFERFINISH_RSPFIN both of the above. * host-complete_request is the completion-object the driver waits for * * 1) Driver sets up host-mrq and host-complete_what * 2) Driver prepares the transfer * 3) Driver enables interrupts * 4) Driver starts transfer * 5) Driver waits for host-complete_rquest * 6) ISR checks for request status (errors and success) * 6) ISR sets host-mrq-cmd-error and host-mrq-data-error * 7) ISR completes host-complete_request * 8) ISR disables interrupts * 9) Driver wakes up and takes care of the request * * Note: -error-fields are expected to be set to 0 before the request * was issued by mmc.c - therefore they are only set, when an error * contition comes up */ static irqreturn_t s3cmci_irq(int irq, void *dev_id) { struct s3cmci_host *host dev_id; struct mmc_command *cmd; u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk; u32 mci_cclear 0, mci_dclear; unsigned long iflags; mci_dsta readl(host-base S3C2410_SDIDSTA); mci_imsk readl(host-base host-sdiimsk); if (mci_dsta S3C2410_SDIDSTA_SDIOIRQDETECT) { if (mci_imsk S3C2410_SDIIMSK_SDIOIRQ) { mci_dclear S3C2410_SDIDSTA_SDIOIRQDETECT; writel(mci_dclear, host-base S3C2410_SDIDSTA); mmc_signal_sdio_irq(host-mmc); return IRQ_HANDLED; } } spin_lock_irqsave(host-complete_lock, iflags); mci_csta readl(host-base S3C2410_SDICMDSTAT); mci_dcnt readl(host-base S3C2410_SDIDCNT); mci_fsta readl(host-base S3C2410_SDIFSTA); 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; } 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 (!s3cmci_host_usedma(host)) { 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; } 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; } 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; } /* errors handled after this point are only relevant when a data transfer is in progress */ if (!cmd-data) goto clear_status_bits; /* Check for FIFO failure */ if (host-is2440) { 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; } } else { if (mci_dsta S3C2410_SDIDSTA_FIFOFAIL) { dbg(host, dbg_err, FIFO failure\n); cmd-data-error -EILSEQ; host-status error: fifo failure; goto fail_transfer; } } 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; } 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; } 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; } 36-48行是判断SDIO所触发的中断与我们说说的无关。飘过.... 30-34行分别读取命令状态、尚未完成传输的数据大小以及FIFO的状态的值。 56-61行就是之前所分析的host-complete_what如果设备无欲无求host-complete_what COMPLETION_NONE即使连最基本的命令发送也不要求完成的话那就没什么意义了直接清除IMASK返回。 [cpp] view plaincopy static inline void clear_imask(struct s3cmci_host *host) { u32 mask readl(host-base host-sdiimsk); /* preserve the SDIO IRQ mask state */ mask S3C2410_SDIIMSK_SDIOIRQ; writel(mask, host-base host-sdiimsk); } 上面的代码只保留了SDIO IRQ状态其他的中断都是被屏蔽了的。由此足见其对SDIO设备的偏心程度。 585-589 行尽然玩丢了host-mrq无论是命令还是数据请求我们都是递交了struct mmc_request结构的所以驱动很气愤直接返回。 591行前面我们看到struct mmc_request中包含了两种类型的struct mmc_cmd一个是所谓的cmd另外一个就是stop了当然选择哪一个也不是他自己说来算了当然有主机host- cmd_is_stop来决定了。 63-67行是PIO模式下数据传输的我们姑且先放着等说完CMD回头再看。 98-103行命令超时以后就会跳转到fail_transfer至于fail_transfer又干了些啥好事我们走到那里了再说继续前进... 105-109行命令发送成功以后所产生的中断如果host-complete_what也正好只要求传输成功即COMPLETION_CMDSENT那正好完成工作goto close_transfer。 114-129行是CRC错误忽略。 134-138行命令相应接收成功那么依旧goto close_transfer。 140-143行至今尚未发现一个所谓的COMPLETION_XFERFINISH_RSPFIN最多也就数据传输成功那么修改一下这个脑残host-complete_what COMPLETION_XFERFINISH; 149-150行如果没有数据传输那么接下来就可以进行状态清理工作了。 153-200行是检查FIFO信息的回头说到PIO传输的时候在来分析它。 203-204行意图很明确显然是毁尸灭迹清除状态。最后可以看到无论是先前的fail_transfer:还是后来的close_transfer最总都会去调用 215行的tasklet_schedule(host-pio_tasklet)是什么赋予这个函数如此强大的魅力且听下回分解... 2、数据传输 s3cmci_setup_data 是时候该看点实际的数据传输了前面说过s3cmci_send_request中的if (cmd-data)是区分命令是否有数据阶段的关键标志。如果有数据传输的那么就到了 s3cmci_setup_data。 [cpp] view plaincopy static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) { u32 dcon, imsk, stoptries 3; /* write DCON register */ if (!data) { writel(0, host-base S3C2410_SDIDCON); return 0; } if ((data-blksz 3) ! 0) { /* We cannot deal with unaligned blocks with more than * one block being transferred. */ if (data-blocks 1) { pr_warning(%s: cant do non-word sized block transfers (blksz %d)\n, __func__, data-blksz); return -EINVAL; } } while (readl(host-base S3C2410_SDIDSTA) (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) { dbg(host, dbg_err, mci_setup_data() transfer stillin progress.\n); writel(S3C2410_SDIDCON_STOP, host-base S3C2410_SDIDCON); s3cmci_reset(host); if ((stoptries--) 0) { dbg_dumpregs(host, DRF); return -EINVAL; } } dcon data-blocks S3C2410_SDIDCON_BLKNUM_MASK; if (s3cmci_host_usedma(host)) dcon | S3C2410_SDIDCON_DMAEN; if (host-bus_width MMC_BUS_WIDTH_4) dcon | S3C2410_SDIDCON_WIDEBUS; if (!(data-flags MMC_DATA_STREAM)) dcon | S3C2410_SDIDCON_BLOCKMODE; if (data-flags MMC_DATA_WRITE) { dcon | S3C2410_SDIDCON_TXAFTERRESP; dcon | S3C2410_SDIDCON_XFER_TXSTART; } if (data-flags MMC_DATA_READ) { dcon | S3C2410_SDIDCON_RXAFTERCMD; dcon | S3C2410_SDIDCON_XFER_RXSTART; } if (host-is2440) { dcon | S3C2440_SDIDCON_DS_WORD; dcon | S3C2440_SDIDCON_DATSTART; } writel(dcon, host-base S3C2410_SDIDCON); /* write BSIZE register */ writel(data-blksz, host-base S3C2410_SDIBSIZE); /* add to IMASK register */ imsk S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC | S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH; enable_imask(host, imsk); /* write TIMER register */ if (host-is2440) { writel(0x007FFFFF, host-base S3C2410_SDITIMER); } else { writel(0x0000FFFF, host-base S3C2410_SDITIMER); /* FIX: set slow clock to prevent timeouts on read */ if (data-flags MMC_DATA_READ) writel(0xFF, host-base S3C2410_SDIPRE); } return 0; } 7-10行如果data不存在接下来就无事可做了。 12-20行块大小是4字节对齐的如果data-blksz不满足那么返回错误。 22-35行读取数据状态寄存器如果正在发送或接收数据则s3cmci_reset(host);复位SD控制器。 [cpp] view plaincopy static void s3cmci_reset(struct s3cmci_host *host) { u32 con readl(host-base S3C2410_SDICON); con | S3C2440_SDICON_SDRESET; writel(con, host-base S3C2410_SDICON); } 37-63行根据数据特征、主机总线宽度等信息设置数据控制寄存器。 67行设置SD控制器块大小寄存器。这是上层设置下来的值一般为512。 70-73行设置中断屏蔽寄存器使能数据传输完成中断、超时等。 77-84行是关于读写超时的处理。接着返回到s3cmci_send_request.... 如果不出什么问题应该就到了85行。 s3cmci_prepare_dma(host, cmd-data);是DMA传输的处理 s3cmci_prepare_pio(host, cmd-data);是PIO方式的处理下面我们先来关注PIO方式的数据传输。