sd卡驱动分析之相关硬件操作和总结

SD控制器之真正的硬件操作

早在SD控制器之初始化篇中,就对SD卡控制器有了一个基本的介绍。其实SD控制器层更过的意义是为core层提供一种操作SD卡硬件的一种方法,当然不同的控制器对硬件控制的方法不尽相同,但是他们最终都能像core层提交一个统一的封装有操作方法的数据结构,那便是即将闪亮登场的struct mmc_host_ops....

依旧是以s3c2440为例,对应的host文件为s3cmci.c。接下来就来揭开与之对应的struct mmc_host_ops结构的神秘面纱....

[host/s3cmci.c]

1355      static struct mmc_host_ops s3cmci_ops = {               

1356             .request   = s3cmci_request,  

1357             .set_ios    = s3cmci_set_ios,  

1358             .get_ro           = s3cmci_get_ro,

1359             .get_cd           = s3cmci_card_present,

1360             .enable_sdio_irq = s3cmci_enable_sdio_irq,       

1361      };   

在讲述每个方法具体的实现之前,先来对struct mmc_host_ops结构中的各个成员有个简单的认识。

request方法:无论是前面所说的单纯的命令传输,还是带有数据的传输过程,无一例外最终都是调用request来实现的,那么如您所想,他也将成为这个舞台万众瞩目的焦点。

set_ios方法:用于设置SD卡控制器,前面我们所见到的设置控制器时钟,数据线宽度等等一系列操作最终就是通过他来实现的。

get_ro方法:获取卡的写保护状态,前面所过,SD卡初始化完成以后,我们进行的一个最后的工作便是检测卡的写保护状态,其实就是调用get_ro方法。

get_cd方法:检测卡是否在卡槽之中,它所对应的函数前面已经在初始化中分析过了,这里不再单独列来。

enable_sdio_irq方法:就是使能SDIO卡的中断,这个是对sdio卡而言的,这里将不做重点分析。

       有了一个初步的了解之后,接下来的时间就来各个击破了,本着由浅入深的原则我们先来看看s3cmci_get_ro

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.     s3cmci_get_ro

SD卡结构上来说有个写保护的开关,这就使得判断SD卡是否写保护可以从其机械特征上入手,从而特殊设计的SD卡槽为我们提供了方便。在这里采用的方法正是利用了这种特殊设计的SD卡槽带来的优势,因此只需要读取SD卡槽的SD写保护引脚的状态就能判定卡写保护的情况。实现的代码如下:

[host/s3cmci.c]

1298      static int s3cmci_get_ro(struct mmc_host *mmc)       

1299      {           

1300             struct s3cmci_host *host = mmc_priv(mmc);      

1301             struct s3c24xx_mci_pdata *pdata = host->pdata; 

1302             int ret;    

1303                    

1304             if (pdata->no_wprotect)

1305                    return 0;

1306                    

1307             ret = s3c2410_gpio_getpin(pdata->gpio_wprotect);    

1308                    

1309             if (pdata->wprotect_invert)  

1310                    ret = !ret;

1311                    

1312             return ret;      

1313      }    

1307行正是获取SD写保护引脚的值,当然由于硬件设计上的不同可能带来状态上的取反,所以这里有个pdata->wprotect_invert标记决定是否应该反相。对于只读来说应该返回1,否则该方法的返回值为0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.     s3cmci_set_ios

根据我们前面所见到的种种设置,这里的ioset可能会相对烦锁一些,具体的代码如下:

[host/s3cmci.c]

1229      static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)                

1230      {                  

1231             struct s3cmci_host *host = mmc_priv(mmc);             

1232             u32 mci_con;        

1233                           

1234             /* Set the power state */       

1235                           

1236             mci_con = readl(host->base + S3C2410_SDICON);          

1237                           

1238             switch (ios->power_mode) {       

1239             case MMC_POWER_ON:           

1240             case MMC_POWER_UP:            

1241                    s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK);      

1242                    s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD);     

1243                    s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0);     

1244                    s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);     

1245                    s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2);     

1246                    s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3); 

1247                           

1248                    if (host->pdata->set_power) 

1249                           host->pdata->set_power(ios->power_mode, ios->vdd);

1250                           

1251                    if (!host->is2440)  

1252                           mci_con |= S3C2410_SDICON_FIFORESET;

1253                           

1254                    break;    

1255                           

1256             case MMC_POWER_OFF:          

1257             default:         

1258                    gpio_direction_output(S3C2410_GPE(5), 0);     

1259                           

1260                    if (host->is2440)   

1261                           mci_con |= S3C2440_SDICON_SDRESET;

1262                           

1263                    if (host->pdata->set_power) 

1264                           host->pdata->set_power(ios->power_mode, ios->vdd);

1265                           

1266                    break;    

1267             }           

1268                           

1269             s3cmci_set_clk(host, ios);            

1270                           

1271             /* Set CLOCK_ENABLE */        

1272             if (ios->clock)       

1273                    mci_con |= S3C2410_SDICON_CLOCKTYPE;  

1274             else        

1275                    mci_con &= ~S3C2410_SDICON_CLOCKTYPE;     

1276                           

1277             writel(mci_con, host->base + S3C2410_SDICON);           

1278                           

1279             if ((ios->power_mode == MMC_POWER_ON) ||             

1280                 (ios->power_mode == MMC_POWER_UP)) {          

1281                    dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",    

1282                           host->real_rate/1000, ios->clock/1000);

1283             } else {         

1284                    dbg(host, dbg_conf, "powered down.\n");   

1285             }           

1286                           

1287             host->bus_width = ios->bus_width;            

1288      }           

1236行对SD卡控制器的设置最直接的莫过于对寄存器S3C2410_SDICON的访问了,为了保证后面不改变其他无关位的值,这里先读取S3C2410_SDICON中的当前值保存。

1238-1267行是SD控制器工作状态的设定,对ioset来说,swith无疑是他最好的朋友,当MMC_POWER_UP时,SD控制器的相应管脚会得到正确的初始化。其他的如fifo也将被正确复位。

1269-1275行就是对sd控制器时钟的设置,最终一切ioset的成功归功于1277行将重新设置的S3C2410_SDICON状态写入寄存器,从此新的控制器状态生效。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3.     s3cmci_request之命令处理

都说前世的五百次回眸,才换来今生的一次擦肩而过。我们苦苦等待的s3cmci_request,在历经千百次的磨难之后也终究在我们面前揭开了她神秘的面纱....

[host/s3cmci.c]

1190      static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)               

1191      {                                                     

1192             struct s3cmci_host *host = mmc_priv(mmc);                                                

1193                                                              

1194             host->status = "mmc request";                                               

1195             host->cmd_is_stop = 0;                                           

1196             host->mrq = mrq;                                            

1197                                                              

1198             if (s3cmci_card_present(mmc) == 0) {                                          

1199                    dbg(host, dbg_err, "%s: no medium present\n", __func__);                            

1200                    host->mrq->cmd->error = -ENOMEDIUM;                                   

1201                    mmc_request_done(mmc, mrq);                                      

1202             } else                                               

1203                    s3cmci_send_request(mmc);                                    

1204      }                                                     

1198行判断SD卡是否还在卡槽之中,如果已经拔出,那不客气mmc_request_done将帮您结束这个请求。怎么个解决法还是先看看mmc_request_done的代码:

[core/core.c]

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

76   {                         

77   ): %d, retrying...\n",            

87                        mmc_hostname(host), cmd->opcode, err);  

88                               

89                 cmd->retries--;             

90                 cmd->error = 0;           

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

92          } else {                

93                 led_trigger_event(host->led, LED_OFF);           

94                               

95                 pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",           

96                        mmc_hostname(host), cmd->opcode, err,    

97                        cmd->resp[0], cmd->resp[1],

98                        cmd->resp[2], cmd->resp[3]);     

99                               

100               if (mrq->data) {           

101                      pr_debug("%s:     %d bytes transferred: %d\n",     

102                             mmc_hostname(host),

103                             mrq->data->bytes_xfered, mrq->data->error);

104               }           

105                             

106               if (mrq->stop) {           

107                      pr_debug("%s:     (CMD%u): %d: %08x %08x %08x %08x\n",  

108                             mmc_hostname(host), mrq->stop->opcode,

109                             mrq->stop->error,

110                             mrq->stop->resp[0], mrq->stop->resp[1],

111                             mrq->stop->resp[2], mrq->stop->resp[3]);

112               }           

113                             

114               if (mrq->done)             

115                      mrq->done(mrq);  

116        }                  

117 }           

80-83行如果是SPI传输出现错误,而且还有重试的机会,那么只要SPI不忽略这个命令,那么就还是给他重试的机会,也就到了85-91行继续调用host->ops->request(host, mrq);提交请求,否则既然是SPI忽略了这个命令,无论重试多少次都不会有结果,那么就干脆一不做二不休cmd->retries = 0;

85-91行就是只要设备有重生的机会就还是继续拯救...

92-115行如果传输无误或者重试次数到了,就会执行。其中多半是调试信息。

114-115行许下的承诺就好比欠下的债,前面我们讨论mmc_wait_for_req的时候有这么两句:

197        mrq->done_data = &complete;    

198        mrq->done = mmc_wait_done;    

然后我们说N年以后的某一天我们会和mmc_wait_done再聚首,这里115行便是调用的mmc_wait_done。内容如下:

[core/core.c]

179 static void mmc_wait_done(struct mmc_request *mrq)      

180 {    

181        complete(mrq->done_data);

182 }    

还记得mmc_wait_for_req中为了你苦苦等待的那个wait_for_completion(&complete),因为等待,所以她进入了睡眠。现在事情做完了,他重新回来调用complete(mrq->done_data)唤醒这个沉睡的内核精灵。说到这好奇的人难免会问,那要是一直出错又该是谁来唤醒他呢?带着疑问我们继续向前....

       回到s3cmci_request如果卡还存在的话1203s3cmci_send_request将真正开始这个请求的处理。

[host/s3cmci.c]

1125      static void s3cmci_send_request(struct mmc_host *mmc)                 

1126      {                  

1127             struct s3cmci_host *host = mmc_priv(mmc);             

1128             struct mmc_request *mrq = host->mrq;             

1129             struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;          

1130                           

1131             host->ccnt++;       

1132             prepare_dbgmsg(host, cmd, host->cmd_is_stop);       

1133                           

1134             /* Clear command, data and fifo status registers         

1135                Fifo clear only necessary on 2440, but doesn't hurt on 2410        

1136             */          

1137             writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);         

1138             writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);         

1139             writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA);         

1140                           

1141             if (cmd->data) {           

1142                    int res = s3cmci_setup_data(host, cmd->data);    

1143                           

1144                    host->dcnt++;

1145                           

1146                    if (res) { 

1147                           dbg(host, dbg_err, "setup data error %d\n", res);

1148                           cmd->error = res;

1149                           cmd->data->error = res;

1150                           

1151                           mmc_request_done(mmc, mrq);

1152                           return;

1153                    }    

1154                           

1155                    if (s3cmci_host_usedma(host))     

1156                           res = s3cmci_prepare_dma(host, cmd->data);

1157                    else 

1158                           res = s3cmci_prepare_pio(host, cmd->data);

1159                           

1160                    if (res) { 

1161                           dbg(host, dbg_err, "data prepare error %d\n", res);

1162                           cmd->error = res;

1163                           cmd->data->error = res;

1164                           

1165                           mmc_request_done(mmc, mrq);

1166                           return;

1167                    }    

1168             }           

1169                           

1170             /* Send command */            

1171             s3cmci_send_command(host, cmd);            

1172                           

1173             /* Enable Interrupt */          

1174             s3cmci_enable_irq(host, true);            

1175      }

1137-1139行全部写入1,是为了清除之前传输的SDI命令状态寄存器、SDI数据状态寄存器以及SDI FIFO状态寄存器。这是在一次新的传输之前所必须有的初始化工作,否则可能出现未知的状态错误。

1141cmd->data实际上就是mmc_request->data,前面没少对他进行介绍。与之相类似的还有stop->data。这里我们姑且不说带有数据的传输过程,先来看看SD卡命令的实现。也就是1171       s3cmci_send_command(host, cmd);

[host/s3cmci.c]

939 static void s3cmci_send_command(struct s3cmci_host *host,                                 

940                                    struct mmc_command *cmd)

941 {                                

942        u32 ccon, imsk;                          

943                                    

944        imsk  = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |

945               S3C2410_SDIIMSK_RESPONSEND |S3C2410_SDIIMSK_CMDSENT |     

946               S3C2410_SDIIMSK_RESPONSECRC;                    

947                                    

948        enable_imask(host, imsk);                         

949                                    

950        if (cmd->data)                           

951               host->complete_what = COMPLETION_XFERFINISH_RSPFIN;                  

952        else if (cmd->flags & MMC_RSP_PRESENT)                        

953               host->complete_what = COMPLETION_RSPFIN;                   

954        else                      

955               host->complete_what = COMPLETION_CMDSENT;              

956                                    

957        writel(cmd->arg, host->base + S3C2410_SDICMDARG);                      

958                                    

959        ccon  = cmd->opcode & S3C2410_SDICMDCON_INDEX;                         

960 ccon|=S3C2410_SDICMDCON_SENDERHOST|S3C2410_SDICMDCON_CMDSTART;

961                                    

962        if (cmd->flags & MMC_RSP_PRESENT)                       

963               ccon |= S3C2410_SDICMDCON_WAITRSP;                   

964                                    

965        if (cmd->flags & MMC_RSP_136)                          

966               ccon |= S3C2410_SDICMDCON_LONGRSP;                  

967                                    

968        writel(ccon, host->base + S3C2410_SDICMDCON);                      

969 }                                

944-948行是使能相应的中断,其中包括CRC校验错误、命令超时、收到命令响应等等。具体的中断屏蔽寄存器的内容可以参考S3C2440用户手册。

950-955行实际上指当前的这个命令结束时候应该所处的状态,中断处理函数将实际硬件的完成情况与这个状态相比较,最终得到这个命令执行的结果。而cmd->flags正是前面提交命令之前根据不同命令的实际情况来设置的,比如具有应答数据的命令可能需要设置cmd->flags |= MMC_RSP_PRESENT。然后对应的结束状态也就应该是COMPLETION_RSPFIN收到应答。前面说过host->complete_what是个枚举类型的变量包含了整个命令过程的各个阶段,内容如下:

11   enum s3cmci_waitfor {                             

12          COMPLETION_NONE,                           

13          COMPLETION_FINALIZE,                     

14          COMPLETION_CMDSENT,                     

15          COMPLETION_RSPFIN,                         

16          COMPLETION_XFERFINISH,                        

17          COMPLETION_XFERFINISH_RSPFIN,                        

18   };

一般的命令可能无应答阶段,我们默认数据传输正确完成以后即认为命令执行完成也就是955行对应的host->complete_what = COMPLETION_CMDSENT;       

957行是对命令命令参数寄存器的设置,cmd->arg是一个32bit的整数,这里如实填写即可。

959行之后的内容就是对控制寄存器的设置了,由于控制寄存器比较重要,这里列出他寄存器位的信息如下:

对照上表应该不难分析函数中所设置的每一位的具体含义,这里就不再一一解释了。SDICmdCon[8]的置位使得SD控制器开始发送命令。回到s3cmci_send_request....

1174s3cmci_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)

 

[host/s3cmci.c]

550 static irqreturn_t s3cmci_irq(int irq, void *dev_id)                         

551 {                         

552        struct s3cmci_host *host = dev_id;                    

553        struct mmc_command *cmd;              

554        u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk;                  

555        u32 mci_cclear = 0, mci_dclear;                

556        unsigned long iflags;                   

557                             

558        mci_dsta = readl(host->base + S3C2410_SDIDSTA);               

559        mci_imsk = readl(host->base + host->sdiimsk);                

560                             

561        if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {                    

562               if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) {           

563                      mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT;    

564                      writel(mci_dclear, host->base + S3C2410_SDIDSTA);      

565                             

566                      mmc_signal_sdio_irq(host->mmc);     

567                      return IRQ_HANDLED;      

568               }           

569        }                  

570                             

571        spin_lock_irqsave(&host->complete_lock, iflags);                   

572                             

573        mci_csta = readl(host->base + S3C2410_SDICMDSTAT);               

574        mci_dcnt = readl(host->base + S3C2410_SDIDCNT);              

575        mci_fsta = readl(host->base + S3C2410_SDIFSTA);                

576        mci_dclear = 0;                   

577                             

578        if ((host->complete_what == COMPLETION_NONE) ||                  

579            (host->complete_what == COMPLETION_FINALIZE)) {               

580               host->status ="nothing to complete";         

581               clear_imask(host);        

582               goto irq_out;         

583        }                  

584                             

585        if (!host->mrq) {                 

586               host->status = "no active mrq";           

587               clear_imask(host);        

588               goto irq_out;         

589        }                  

590                             

591        cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd;                   

592                             

593        if (!cmd) {                  

594               host->status = "no active cmd";           

595               clear_imask(host);        

596               goto irq_out;         

597        }                  

598                             

599        if (!s3cmci_host_usedma(host)) {               

600               if ((host->pio_active == XFER_WRITE) &&           

601                   (mci_fsta & S3C2410_SDIFSTA_TFDET)) {            

602                             

603                      disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);

604                      tasklet_schedule(&host->pio_tasklet);  

605                      host->status = "pio tx"; 

606               }           

607                             

608               if ((host->pio_active == XFER_READ) &&             

609                   (mci_fsta & S3C2410_SDIFSTA_RFDET)) {           

610                             

611                      disable_imask(host,      

612                                   S3C2410_SDIIMSK_RXFIFOHALF |

613                                   S3C2410_SDIIMSK_RXFIFOLAST);

614                             

615                      tasklet_schedule(&host->pio_tasklet);  

616                      host->status = "pio rx"; 

617               }           

618        }                  

619                             

620        if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {                  

621               dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n");       

622               cmd->error = -ETIMEDOUT;            

623               host->status = "error: command timeout";          

624               goto fail_transfer;         

625        }                  

626                             

627        if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) {                 

628               if (host->complete_what == COMPLETION_CMDSENT) {            

629                      host->status ="ok: command sent";     

630                      goto close_transfer;      

631               }           

632                             

633               mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;        

634        }                  

635                             

636        if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) {                    

637               if (cmd->flags & MMC_RSP_CRC) {        

638                      if (host->mrq->cmd->flags & MMC_RSP_136) {      

639                             dbg(host, dbg_irq,

640                                 "fixup: ignore CRC fail with long rsp\n");

641                      } else {  

642                             /* note, we used to fail the transfer

643                             * here, but it seems that this is just

644                             * the hardware getting it wrong.

645                             *

646                             * cmd->error = -EILSEQ;

647                             * host->status = "error: bad command crc";

648                             * goto fail_transfer;

649                             */

650                      }    

651               }           

652                             

653               mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;          

654        }                  

655                             

656        if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) {               

657               if (host->complete_what == COMPLETION_RSPFIN) {         

658                      host->status = "ok: command response received";      

659                      goto close_transfer;      

660               }           

661                             

662               if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)           

663                      host->complete_what = COMPLETION_XFERFINISH;   

664                             

665               mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN;            

666        }                  

667                             

668        /* errors handled after this point are only relevant                    

669           when a data transfer is in progress */                   

670                             

671        if (!cmd->data)                   

672               goto clear_status_bits;          

673                             

674        /* Check for FIFO failure */               

675        if (host->is2440) {              

676               if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) {            

677                      dbg(host, dbg_err, "FIFO failure\n");  

678                      host->mrq->data->error = -EILSEQ;   

679                      host->status = "error: 2440 fifo failure";     

680                      goto fail_transfer;  

681               }           

682        } else {                

683               if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) {           

684                      dbg(host, dbg_err, "FIFO failure\n");  

685                      cmd->data->error = -EILSEQ;    

686                      host->status = "error:  fifo failure";   

687                      goto fail_transfer;  

688               }           

689        }                  

690                             

691        if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {              

692               dbg(host, dbg_err, "bad data crc (outgoing)\n");        

693               cmd->data->error = -EILSEQ;           

694               host->status = "error: bad data crc (outgoing)";         

695               goto fail_transfer;         

696        }                  

697                             

698        if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) {                   

699               dbg(host, dbg_err, "bad data crc (incoming)\n");       

700               cmd->data->error = -EILSEQ;           

701               host->status = "error: bad data crc (incoming)";         

702               goto fail_transfer;         

703        }                  

704                             

705        if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {                 

706               dbg(host, dbg_err, "data timeout\n");          

707               cmd->data->error = -ETIMEDOUT;          

708               host->status = "error: data timeout";           

709               goto fail_transfer;         

710        }                  

711                             

712        if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) {                    

713               if (host->complete_what == COMPLETION_XFERFINISH) {        

714                      host->status = "ok: data transfer completed";      

715                      goto close_transfer;      

716               }           

717                             

718               if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)           

719                      host->complete_what = COMPLETION_RSPFIN;     

720                            

721               mci_dclear |= S3C2410_SDIDSTA_XFERFINISH;          

722        }                  

723                             

724 clear_status_bits:                        

725        writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);                    

726        writel(mci_dclear, host->base + S3C2410_SDIDSTA);                    

727                             

728        goto irq_out;                

729                             

730 fail_transfer:                       

731        host->pio_active = XFER_NONE;                    

732                             

733 close_transfer:                     

734        host->complete_what = COMPLETION_FINALIZE;               

735                             

736        clear_imask(host);               

737        tasklet_schedule(&host->pio_tasklet);                

738                             

739        goto irq_out;                

740                             

741 irq_out:                       

742        dbg(host, dbg_irq,               

743            "csta:0x%08x dsta:0x%08x fsta:0x%08x dcnt:0x%08x status:%s.\n",              

744            mci_csta, mci_dsta, mci_fsta, mci_dcnt, host->status);                    

745                             

746        spin_unlock_irqrestore(&host->complete_lock, iflags);                   

747        return IRQ_HANDLED;                    

748                             

749 }

558-570行是判断SDIO所触发的中断,与我们说说的无关。飘过....

573-576行分别读取命令状态、尚未完成传输的数据大小以及FIFO的状态的值。

578-583行就是之前所分析的host->complete_what,如果设备无欲无求host->complete_what == COMPLETION_NONE,即使连最基本的命令发送也不要求完成的话,那就没什么意义了,直接清除IMASK,返回。

[host/s3cmci.c]

226 static inline void clear_imask(struct s3cmci_host *host)                   

227 {                  

228        u32 mask = readl(host->base + host->sdiimsk);         

229                      

230        /* preserve the SDIO IRQ mask state */             

231        mask &= S3C2410_SDIIMSK_SDIOIRQ;         

232        writel(mask, host->base + host->sdiimsk);         

233 }                  

上面的代码只保留了SDIO IRQ状态,其他的中断都是被屏蔽了的。由此足见其对SDIO设备的偏心程度

585-589行尽然玩丢了host->mrq,无论是命令还是数据请求,我们都是递交了struct mmc_request结构的,所以驱动很气愤,直接返回。

591行前面我们看到struct mmc_request中包含了两种类型的struct mmc_cmd一个是所谓的cmd另外一个就是stop了,当然选择哪一个也不是他自己说来算了,当然有主机的host->cmd_is_stop来决定了。

599-618行是PIO模式下数据传输的,我们姑且先放着,等说完CMD回头再看。

620-625行命令超时以后就会跳转到fail_transfer,至于fail_transfer又干了些啥好事我们走到那里了再说,继续前进...

627-631行命令发送成功以后所产生的中断,如果host->complete_what也正好只要求传输成功即COMPLETION_CMDSENT,那正好完成工作,goto close_transfer

636-654行是CRC错误,忽略。

656-660命令相应接收成功,那么依旧goto close_transfer

662-665行至今尚未发现一个所谓的COMPLETION_XFERFINISH_RSPFIN最多也就数据传输成功那么修改一下这个脑残host->complete_what = COMPLETION_XFERFINISH;

671-672行如果没有数据传输,那么接下来就可以进行状态清理工作了。

675-722行是检查FIFO信息的,回头说到PIO传输的时候在来分析它。

725-726行意图很明确,显然是毁尸灭迹,清除状态。

       最后可以看到无论是先前的fail_transfer:还是后来的close_transfer,最总都会去调用737行的tasklet_schedule(&host->pio_tasklet),是什么赋予这个函数如此强大的魅力,且听下回分解...

      

 

 

 

 

 

 

4.     s3cmci_request之数据传输

是时候该看点实际的数据传输了,前面说过s3cmci_send_request中的if (cmd->data)是区分命令是否有数据阶段的关键标志。如果有数据传输的,那么就到了1142s3cmci_setup_data

[host/s3cmci.c]

971 static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)               

972 {                  

973        u32 dcon, imsk, stoptries = 3;             

974                      

975        /* write DCON register */           

976                      

977        if (!data) {            

978               writel(0, host->base + S3C2410_SDIDCON);    

979               return 0; 

980        }           

981                      

982        if ((data->blksz & 3) != 0) {       

983               /* We cannot deal with unaligned blocks with more than   

984               * one block being transfered. */ 

985                      

986               if (data->blocks > 1) {  

987 pr_warning("%s:can'tdonon-wordsizedblock transfers (blksz %d)\n", __func__, data->blksz);

988                      return -EINVAL;

989               }    

990        }           

991                      

992        while (readl(host->base + S3C2410_SDIDSTA) &            

993               (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {

994                     

995               dbg(host, dbg_err, 

996                   "mci_setup_data() transfer stillin progress.\n");  

997                      

998               writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); 

999               s3cmci_reset(host);

1000                           

1001                    if ((stoptries--) == 0) { 

1002                           dbg_dumpregs(host, "DRF");

1003                           return -EINVAL;

1004                    }    

1005             }           

1006                           

1007             dcon  = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK;         

1008                           

1009             if (s3cmci_host_usedma(host))            

1010                    dcon |= S3C2410_SDIDCON_DMAEN;     

1011                           

1012             if (host->bus_width == MMC_BUS_WIDTH_4)       

1013                    dcon |= S3C2410_SDIDCON_WIDEBUS;  

1014                           

1015             if (!(data->flags & MMC_DATA_STREAM))            

1016                    dcon |= S3C2410_SDIDCON_BLOCKMODE;   

1017                           

1018             if (data->flags & MMC_DATA_WRITE) {         

1019                    dcon |= S3C2410_SDIDCON_TXAFTERRESP; 

1020                    dcon |= S3C2410_SDIDCON_XFER_TXSTART;      

1021             }           

1022                           

1023             if (data->flags & MMC_DATA_READ) {          

1024                    dcon |= S3C2410_SDIDCON_RXAFTERCMD; 

1025                    dcon |= S3C2410_SDIDCON_XFER_RXSTART;      

1026             }           

1027                           

1028             if (host->is2440) {       

1029                    dcon |= S3C2440_SDIDCON_DS_WORD; 

1030                    dcon |= S3C2440_SDIDCON_DATSTART; 

1031             }           

1032                           

1033             writel(dcon, host->base + S3C2410_SDIDCON);             

1034                           

1035             /* write BSIZE register */           

1036                           

1037             writel(data->blksz, host->base + S3C2410_SDIBSIZE);           

1038                           

1039             /* add to IMASK register */        

1040             imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |          

1041                    S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;          

1042                           

1043             enable_imask(host, imsk);           

1044                           

1045             /* write TIMER register */          

1046                           

1047             if (host->is2440) {       

1048                    writel(0x007FFFFF, host->base + S3C2410_SDITIMER); 

1049             } else {         

1050                    writel(0x0000FFFF, host->base + S3C2410_SDITIMER); 

1051                           

1052                    /* FIX: set slow clock to prevent timeouts on read */ 

1053                    if (data->flags & MMC_DATA_READ)      

1054                           writel(0xFF, host->base + S3C2410_SDIPRE);

1055             }           

1056                           

1057             return 0;        

1058      }                  

977-980行如果data不存在,接下来就无事可做了。

982-991行块大小是4字节对齐的,如果data->blksz不满足,那么返回错误。

992-1005行读取数据状态寄存器,如果正在发送或接收数据,则s3cmci_reset(host);复位SD控制器。

[host/s3cmci.c]

1290      static void s3cmci_reset(struct s3cmci_host *host)             

1291      {           

1292             u32 con = readl(host->base + S3C2410_SDICON);    

1293                    

1294             con |= S3C2440_SDICON_SDRESET;

1295             writel(con, host->base + S3C2410_SDICON);    

1296      }           

1007-1033行根据数据特征、主机总线宽度等信息设置数据控制寄存器

1037行设置SD控制器块大小寄存器。这是上层设置下来的值,一般为512

1040-1043行设置中断屏蔽寄存器,使能数据传输完成中断、超时等。

1047-1054行是关于读写超时的处理。接着返回到s3cmci_send_request....

如果不出什么问题,应该就到了1155行。

s3cmci_prepare_dma(host, cmd->data);DMA传输的处理,

s3cmci_prepare_pio(host, cmd->data);PIO方式的处理,下面我们先来关注PIO方式的数据传输。

[host/s3cmci.c]

1062      static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)             

1063      {                  

1064             int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;            

1065                           

1066             BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);          

1067                           

1068             host->pio_sgptr = 0;            

1069             host->pio_bytes = 0;            

1070             host->pio_count = 0;           

1071             host->pio_active = rw ? XFER_WRITE : XFER_READ;         

1072                           

1073             if (rw) {        

1074                    do_pio_write(host);      

1075                    enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); 

1076             } else {         

1077                    enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF   

1078                                | S3C2410_SDIIMSK_RXFIFOLAST);

1079             }           

1080                           

1081             return 0;        

1082      }    

Ø  PIO写数据

这个函数分两部分来看,首先对于写来说会调用1074do_pio_write(host);来做写入的前期工作,如果是读SD卡就只需要使能接收FIFO相关的中断即可。那么我们先对写的情况做简单的分析:

[host/s3cmci.c]

443 static void do_pio_write(struct s3cmci_host *host)                                               

444 {                                              

445        void __iomem *to_ptr;                                    

446        int res;                                      

447        u32 fifo;                                    

448        u32 *ptr;                                   

449                                                  

450        to_ptr = host->base + host->sdidata;                                       

451                                                  

452        while ((fifo = fifo_free(host)) > 3) {                                      

453               if (!host->pio_bytes) {                              

454                      res = get_data_buffer(host, &host->pio_bytes,                         

455                                                  &host->pio_ptr);

456                      if (res) {                      

457                             dbg(host, dbg_pio,              

458                                 "pio_write(): complete (no more data).\n");              

459                             host->pio_active = XFER_NONE;                    

460                                                  

461                             return;                  

462                      }                         

463                                                  

464                      dbg(host, dbg_pio,                     

465                          "pio_write(): new source: [%i]@[%p]\n",                        

466                          host->pio_bytes, host->pio_ptr);                       

467                                                  

468               }                                

469                                                  

470               /* If we have reached the end of the block, we have to                                  

471               * write exactly the remaining number of bytes.  If we                                

472               * in the middle of the block, we have to write full                               

473               * words, so round down to an even multiple of 4. */                            

474               if (fifo >= host->pio_bytes)                              

475                      fifo = host->pio_bytes;                      

476               else                             

477                      fifo -= fifo & 3;                         

478                                                  

479               host->pio_bytes -= fifo;                            

480               host->pio_count += fifo;                                  

481                                                  

482               fifo = (fifo + 3) >> 2;                               

483               ptr = host->pio_ptr;                                  

484               while (fifo--)                             

485                      writel(*ptr++, to_ptr);                       

486               host->pio_ptr = ptr;                                  

487        }                                       

488                                                  

489        enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);                                    

490 }

452行是对发送FIFO剩余空间的判断,方法比较简单直接读取FIFO状态寄存器即可获得。

[host/s3cmci.c]

294 static inline u32 fifo_free(struct s3cmci_host *host)                                             

295 {                                              

296        u32 fifostat = readl(host->base + S3C2410_SDIFSTA);                                        

297                                                  

298        fifostat &= S3C2410_SDIFSTA_COUNTMASK;                                         

299        return 63 - fifostat;                                   

300 }

当发送FIFO的容量大于三个字节时程序将向FIFO中写入数据,此时while循环得以执行。

454取出要发送的数据地址以及数据长度get_data_buffer的内容如下:

[host/s3cmci.c]

257 static inline int get_data_buffer(struct s3cmci_host *host,                       

258                               u32 *bytes, u32 **pointer)

259 {                         

260        struct scatterlist *sg;                   

261                             

262        if (host->pio_active == XFER_NONE)                    

263               return -EINVAL;          

264                             

265        if ((!host->mrq) || (!host->mrq->data))              

266               return -EINVAL;          

267                             

268        if (host->pio_sgptr >= host->mrq->data->sg_len) {                 

269               dbg(host, dbg_debug, "no more buffers (%i/%i)\n",         

270                     host->pio_sgptr, host->mrq->data->sg_len);          

271               return -EBUSY;           

272        }                  

273        sg = &host->mrq->data->sg[host->pio_sgptr];                  

274                             

275        *bytes = sg->length;                   

276        *pointer = sg_virt(sg);                

277                             

278        host->pio_sgptr++;              

279                             

280        dbg(host, dbg_sg, "new buffer (%i/%i)\n",               

281            host->pio_sgptr, host->mrq->data->sg_len);              

282                             

283        return 0;               

284 }    

273行很明显是对每个散列表单独操作的,275行对应当前散列项的长度,276sg_virt用于获取其所对应的内核虚拟地址,最后host->pio_sgptr++移动指针到下一项。

       回到do_pio_write474-477行就是取出剩余的空间,如果剩余空间大于要发送的长度就直接全部发送,否则留三个字节空闲。

4824个字节对齐的,也就是说后面实际上传输的字节数应该是(((fifo + 3) >> 2)<<2),那么这个值与host->pio_bytes -= fifo;中的fifo相比是很有可能不相等的。换句话说实际传输的字节说与记录的大小不等,看上去是个bug,其实前面我们说过,所有走到这一步的数据长度都已经是4字节对齐了,所以这里这样处理就不会有问题了。

       s3cmci_prepare_pio返回以后就到了1171s3cmci_send_command(host, cmd);这里发送的将是写扇区命令,从而开启了真正的PIO数据传输

       对于PIO方式来说,一旦命令写入,数据传输立即就开始了。如果发送FIFO中的数据低于FIFO空闲中断的阈值,将触发控制器产生中断,从而就满足了s3cmci_irq中断处理函数的599-606行的条件。

[s3cmci_irq]

599 if (!s3cmci_host_usedma(host)) {                                           

600        if ((host->pio_active == XFER_WRITE) &&                                       

601            (mci_fsta & S3C2410_SDIFSTA_TFDET)) {                                        

602                                                  

603               disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);                            

604               tasklet_schedule(&host->pio_tasklet);                              

605               host->status = "pio tx";                             

606        }                                       

于是tasklet_schedule(&host->pio_tasklet)被调用,同时724-728行将帮助清除中断标志。

724 clear_status_bits:                        

725        writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);                    

726        writel(mci_dclear, host->base + S3C2410_SDIDSTA);                    

727                             

728        goto irq_out;

       又见了tasklet_schedule(&host->pio_tasklet),他不是什么天外飞仙,一切因果只因s3cmci.c中的1588  tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);          

从中断函数返回以后,目光投向pio_tasklet,对应的内容如下:

[host/s3cmci.c]

492 static void pio_tasklet(unsigned long data)                       

493 {                         

494        struct s3cmci_host *host = (struct s3cmci_host *) data;                    

495                             

496        s3cmci_disable_irq(host, true);                  

497        udelay(50);                  

498                             

499        if (host->pio_active == XFER_WRITE)                   

500               do_pio_write(host);             

501                             

502        if (host->pio_active == XFER_READ)              

503               do_pio_read(host);       

504                             

505        if (host->complete_what == COMPLETION_FINALIZE) {                    

506               clear_imask(host);        

507               if (host->pio_active != XFER_NONE) {           

508                      dbg(host, dbg_err, "unfinished %s "    

509                          "- pio_count:[%u] pio_bytes:[%u]\n", 

510                          (host->pio_active == XFER_READ) ? "read" : "write",    

511                          host->pio_count, host->pio_bytes);     

512                             

513                      if (host->mrq->data)     

514                             host->mrq->data->error = -EINVAL;

515               }           

516                             

517               s3cmci_enable_irq(host, false);           

518               finalize_request(host);          

519        } else                   

520               s3cmci_enable_irq(host, true);            

521 }                         

函数格式比较工整,如果host->pio_active继续保持XFER_WRITE的话,就会再次调用do_pio_write(host)来继续向发送FIFO中填入数据。

505行是传输完成以后设置的,传输完成以后会调用finalize_request(host);束这次请求。

[host/s3cmci.c]

822 static void finalize_request(struct s3cmci_host *host)                      

823 {                         

824        struct mmc_request *mrq = host->mrq;                    

825        struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;          

826        int debug_as_failure = 0;                    

827                             

828        if (host->complete_what != COMPLETION_FINALIZE)                

829               return;           

830                             

831        if (!mrq)              

832               return;           

833                            

834        if (cmd->data && (cmd->error == 0) &&                

835            (cmd->data->error == 0)) {                

836               if (s3cmci_host_usedma(host) && (!host->dma_complete)) {          

837                      dbg(host, dbg_dma, "DMA Missing (%d)!\n",    

838                          host->dma_complete);  

839                      return;    

840               }           

841        }                  

842                             

843        /* Read response from controller. */                  

844        cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);                

845        cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);                

846        cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);                

847        cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);                

848                             

849        writel(host->prescaler, host->base + S3C2410_SDIPRE);                

850                             

851        if (cmd->error)                   

852               debug_as_failure = 1;          

853                             

854        if (cmd->data && cmd->data->error)         

855               debug_as_failure = 1;   

856                      

857        dbg_dumpcmd(host, cmd, debug_as_failure);            

858                      

859        /* Cleanup controller */       

860        writel(0, host->base + S3C2410_SDICMDARG);             

861        writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);        

862        writel(0, host->base + S3C2410_SDICMDCON);             

863        clear_imask(host);        

864                      

865        if (cmd->data && cmd->error)           

866               cmd->data->error = cmd->error;  

867                      

868        if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) {           

869               host->cmd_is_stop = 1; 

870               s3cmci_send_request(host->mmc);      

871               return;    

872        }           

873                      

874        /* If we have no data transfer we are finished here */        

875        if (!mrq->data)            

876               goto request_done;

877                      

878        /* Calulate the amout of bytes transfer if there was no error */         

879        if (mrq->data->error == 0) {       

880               mrq->data->bytes_xfered =  

881                      (mrq->data->blocks * mrq->data->blksz);

882        } else {         

883               mrq->data->bytes_xfered = 0;     

884        }           

885                      

886        /* If we had an error while transfering data we flush the           

887        * DMA channel and the fifo to clear out any garbage. */         

888        if (mrq->data->error != 0) {        

889               if (s3cmci_host_usedma(host))     

890                      s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);

891                      

892               if (host->is2440) {

893                      /* Clear failure register and reset fifo. */

894                      writel(S3C2440_SDIFSTA_FIFORESET |

895                             S3C2440_SDIFSTA_FIFOFAIL,

896                             host->base + S3C2410_SDIFSTA);

897               } else {  

898                      u32 mci_con;

899                      

900                      /* reset fifo */

901                      mci_con = readl(host->base + S3C2410_SDICON);

902                      mci_con |= S3C2410_SDICON_FIFORESET;

903                      

904                      writel(mci_con, host->base + S3C2410_SDICON);

905               }    

906        }           

907                      

908 request_done:               

909        host->complete_what = COMPLETION_NONE;       

910        host->mrq = NULL;            

911                      

912        s3cmci_check_sdio_irq(host);             

913        mmc_request_done(host->mmc, mrq);        

914 }    

843-847行是发送读写命令以后SD卡回复的信息,这个信息在block层中将作为请求完成情况的一个依据。

860-863行是完成任务后对控制器做清理工作。

868-872行这个是对于多扇区的读写还应该有一个结束命令,以结束此次操作。在mmc_blk_issue_rq中就已经对这个stop命令设置好了,如下:

[card/block.c]

259               brq.stop.opcode = MMC_STOP_TRANSMISSION;                 

260               brq.stop.arg = 0;                 

261               brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;  

。。。。。

284                      if (!mmc_host_is_spi(card->host)        

285                                    || rq_data_dir(req) == READ)

286                             brq.mrq.stop = &brq.stop;    

287                      readcmd = MMC_READ_MULTIPLE_BLOCK;        

288                      writecmd = MMC_WRITE_MULTIPLE_BLOCK;            

289               } else {                

290                      brq.mrq.stop = NULL;         

291                      readcmd = MMC_READ_SINGLE_BLOCK;            

292                      writecmd = MMC_WRITE_BLOCK;          

293               }                  

259MMC_STOP_TRANSMISSION就正好是CMD12命令,最终结束命令也就是由s3cmci_send_request发出了。

879-884行如果传输没有发生错误,传输的字节数将被正确记载,否则传输数据长度将为0,暗示此次数据传输失败。

888-904行传输有错误,便要重新刷新DMA控制器或者是复位FIFO

909-901host的工作完成以后host内部相应的对象应该复位,以便重新接受请求。

913mmc_request_done前面分析过,如果出错可能会引发重试,否则调用complete(mrq->done_data);通知等待该请求的进程

       好了,以上说分析的就是PIO写数据部分的情况了,接下来看下PIO读是如何工作的。。。

 

 

Ø  PIO读数据

依然回到s3cmci_send_request中,还是看s3cmci_prepare_pio的内容。

前面的分析我们知道对于PIO的写数据来说必须先填充其FIFO,否则可能写命令发出以后,主机无法发送数据导致命令失败。然而读数据却只能有中断引发,因此当主机发送读命令之前s3cmci_prepare_pio必须设置好相应的中断使能,enable_imask(host,

S3C2410_SDIIMSK_RXFIFOHALF|S3C2410_SDIIMSK_RXFIFOLAST);当接收FIFO有较多数据时将以中断形式通知主机。同样s3cmci_send_request中的s3cmci_send_command(host, cmd);发送读命令开启了读SD卡数据的新时代。

一旦FIFO中的数据达到接收阈值将触发中断,接下来就进入了s3cmci_irq608-609行。

608               if ((host->pio_active == XFER_READ) &&             

609                   (mci_fsta & S3C2410_SDIFSTA_RFDET)) {           

610                             

611                      disable_imask(host,      

612                                   S3C2410_SDIIMSK_RXFIFOHALF |

613                                   S3C2410_SDIIMSK_RXFIFOLAST);

614                             

615                      tasklet_schedule(&host->pio_tasklet);  

616                      host->status = "pio rx"; 

617               }           

618        }                  

与写SD相同,读SD卡也将调用tasklet_schedule,然后进入pio_tasklet502-503行。do_pio_read(host);将读取fifo中的数据。

[host/s3cmci.c]

360 static void do_pio_read(struct s3cmci_host *host)                                  

361 {                                

362        int res;                        

363        u32 fifo;                      

364        u32 *ptr;                     

365        u32 fifo_words;                         

366        void __iomem *from_ptr;                         

367                                    

368        /* write real prescaler to host, it might be set slow to fix */                     

369        writel(host->prescaler, host->base + S3C2410_SDIPRE);                       

370                                    

371        from_ptr = host->base + host->sdidata;                     

372                                    

373        while ((fifo = fifo_count(host))) {                           

374               if (!host->pio_bytes) {                

375                      res = get_data_buffer(host, &host->pio_bytes,           

376                                          &host->pio_ptr);

377                      if (res) {        

378                             host->pio_active = XFER_NONE;      

379                             host->complete_what = COMPLETION_FINALIZE; 

380                                    

381                             dbg(host, dbg_pio, "pio_read(): " 

382                                 "complete (no more data).\n");    

383                             return;    

384                      }           

385                                    

386                      dbg(host, dbg_pio,       

387                          "pio_read(): new target: [%i]@[%p]\n",            

388                          host->pio_bytes, host->pio_ptr);         

389               }                  

390                                    

391               dbg(host, dbg_pio,              

392                   "pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n",                 

393                   fifo, host->pio_bytes,                 

394                   readl(host->base + S3C2410_SDIDCNT));                

395                                    

396               /* If we have reached the end of the block, we can                   

397               * read a word and get 1 to 3 bytes.  If we in the                   

398               * middle of the block, we have to read full words,                 

399               * otherwise we will write garbage, so round down to              

400               * an even multiple of 4. */                

401               if (fifo >= host->pio_bytes)                

402                      fifo = host->pio_bytes;        

403               else               

404                      fifo -= fifo & 3;           

405                                    

406               host->pio_bytes -= fifo;              

407               host->pio_count += fifo;                    

408                                    

409               fifo_words = fifo >> 2;               

410               ptr = host->pio_ptr;                    

411               while (fifo_words--)                   

412                      *ptr++ = readl(from_ptr);           

413               host->pio_ptr = ptr;                    

414                                    

415               if (fifo & 3) {              

416                      u32 n = fifo & 3;         

417                      u32 data = readl(from_ptr);         

418                      u8 *p = (u8 *)host->pio_ptr;       

419                                    

420                      while (n--) {         

421                             *p++ = data;  

422                             data >>= 8;    

423                      }           

424               }                  

425        }                         

426                                    

427        if (!host->pio_bytes) {                       

428               res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr);                    

429               if (res) {               

430                      dbg(host, dbg_pio,       

431                          "pio_read(): complete (no more buffers).\n");           

432                      host->pio_active = XFER_NONE;             

433                      host->complete_what = COMPLETION_FINALIZE;        

434                                    

435                      return;           

436               }                  

437        }                         

438                                    

439        enable_imask(host,                     

440        S3C2410_SDIIMSK_RXFIFOHALF| S3C2410_SDIIMSK_RXFIFOLAST);

441 }                                

373行读取FIFO中数据的长度。

[host/s3cmci.c]

286 static inline u32 fifo_count(struct s3cmci_host *host)                             

287 {                                

288        u32 fifostat = readl(host->base + S3C2410_SDIFSTA);                          

289                                    

290        fifostat &= S3C2410_SDIFSTA_COUNTMASK;                           

291        return fifostat;                     

292 }

375-376行和写操作中的作用是相同的,获取scatterlist表项对应的数据长度及内核虚拟地址。

401-425行整个过程与PIO写的过程是完全相反的,代码比较简单就不再分析了。其他的内容就和写过程是一样的了。

Ø  DMA传输

最后还有关于DMA方式下的代码,其中只有s3cmci_prepare_dma和中断处理不一致。对于DMA来说内核为其维护了一个回调函数。这里我们只是简单分析一下,就不深入到S3C2440 DMA的管理机制里面去了。首先还是来看s3cmci_prepare_dma

[host/s3cmci.c]

1018      static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)     

1019      {                                

1020             int dma_len, i;                           

1021             int rw = data->flags & MMC_DATA_WRITE;                         

1022                                         

1023             BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);                        

1024                                         

1025             s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW);                      

1026             s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);                         

1027                                         

1028             dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,                      

1029                                rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);             

1030                                         

1031             if (dma_len == 0)                       

1032                    return -ENOMEM;              

1033                                         

1034             host->dma_complete = 0;                          

1035             host->dmatogo = dma_len;                        

1036                                         

1037             for (i = 0; i < dma_len; i++) {                          

1038                    int res;                 

1039                                         

1040                    dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i,                

1041                        sg_dma_address(&data->sg[i]),                  

1042                        sg_dma_len(&data->sg[i]));               

1043                                         

1044                    res = s3c2410_dma_enqueue(host->dma, host,                  

1045                                           sg_dma_address(&data->sg[i]),

1046                                           sg_dma_len(&data->sg[i]));

1047                                         

1048                    if (res) {               

1049                           s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);           

1050                           return -EBUSY;           

1051                    }                  

1052             }                         

1053                                         

1054             s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START);                          

1055                                        

1056             return 0;                      

1057      }    

1025行对申请到的DMA通道进行设置。代码如下:

[host/s3cmci.c]

916 static void s3cmci_dma_setup(struct s3cmci_host *host,                                

917                           enum s3c2410_dmasrc source)          

918 {                                

919        static enum s3c2410_dmasrc last_source = -1;                         

920        static int setup_ok;                      

921                                    

922        if (last_source == source)                          

923               return;                  

924                                    

925        last_source = source;                          

926                                    

927        s3c2410_dma_devconfig(host->dma, source,                           

928                            host->mem->start + host->sdidata);        

929                                    

930        if (!setup_ok) {                          

931               s3c2410_dma_config(host->dma, 4);                 

932               s3c2410_dma_set_buffdone_fn(host->dma,               

933                                        s3cmci_dma_done_callback);

934               s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);             

935               setup_ok = 1;               

936        }                         

937 }

927行配置了DMA的源和目的的硬件地址及类型。     

931行配置了DMA传输的单元大小为4字节。

932-933行设置DMA通道对应的回调函数s3cmci_dma_done_callback,这个我们后面再说。回到s3cmci_prepare_dma...

1092行刷新DMA通道,清除状态信息。

1094行映射一个发散/汇聚列表的DMA的映射,对于2440来说DMA不支持散列地址,所以1103-1118行对每段映射进行了处理,将其加入到DMA队列当中。

1120行开启了DMA传输通道,一旦SD控制发送命令以后,DMA通道不断地将数据发送到(或接收从)SD控制器的数据寄存器中,最终完成数据的传输。

一旦DMA数据传输完成,回调函数s3cmci_dma_done_callback将开始工作。

[host/s3cmci.c]

766 static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch,                  

767                                  void *buf_id, int size,

768                                  enum s3c2410_dma_buffresult result)

769 {                         

770        struct s3cmci_host *host = buf_id;                    

771        unsigned long iflags;                   

772        u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt;                    

773                             

774        mci_csta = readl(host->base + S3C2410_SDICMDSTAT);               

775        mci_dsta = readl(host->base + S3C2410_SDIDSTA);               

776        mci_fsta = readl(host->base + S3C2410_SDIFSTA);                

777        mci_dcnt = readl(host->base + S3C2410_SDIDCNT);              

778                             

779        BUG_ON(!host->mrq);               

780        BUG_ON(!host->mrq->data);                    

781        BUG_ON(!host->dmatogo);               

782                                    

783        spin_lock_irqsave(&host->complete_lock, iflags);                          

784                                    

785        if (result != S3C2410_RES_OK) {                           

786               dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "                 

787                      fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n,             

788                      mci_csta, mci_dsta, mci_fsta,             

789                      mci_dcnt, result, host->dmatogo);       

790                                    

791               goto fail_request;                

792        }                         

793                                    

794        host->dmatogo--;                       

795        if (host->dmatogo) {                         

796               dbg(host, dbg_dma, "DMA DONE  Size:%i DSTA:[%08x] "                

797                      DCNT:[%08x] toGo:%u\n,          

798                      size, mci_dsta, mci_dcnt, host->dmatogo);  

799                             

800               goto out;       

801        }                  

802                             

803        dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",              

804               size, mci_dsta, mci_dcnt);           

805                             

806        host->dma_complete = 1;                   

807        host->complete_what = COMPLETION_FINALIZE;               

808                             

809 out:                      

810        tasklet_schedule(&host->pio_tasklet);                

811        spin_unlock_irqrestore(&host->complete_lock, iflags);                   

812        return;                  

813                             

814 fail_request:                        

815        host->mrq->data->error = -EINVAL;                

816        host->complete_what = COMPLETION_FINALIZE;               

817        clear_imask(host);               

818                             

819        goto out;              

820 }                         

实际长上面的函数中我们不难发现DMA完成以后,仍然是调用tasklet_schedule(&host->pio_tasklet);来完成结束工作。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

小结

       到目前为止,linux2.6.32内核下的SD卡子系统的分析就算基本完成了。回顾整个SD卡子系统所采用的驱动开发的技巧主要有:

Ø  内核线程:用于处理上层块设备的请求

Ø  Completions 机制:用于block层与底层硬件的同步。典型例子为mmc_wait_for_req;

Ø  内核工作队列:用于轮询SD卡是否插入

Ø  待队列:在申请SD控制器时,我们使用了工作队列来保证内核的同步

Ø  Tasklets 机制:在底层硬件的中断处理中,Tasklets软中断为中断的相应赢得的足够的时间。

当然上面大多是内核同步和时间处理的策略,在内存管理方面也使用了不少技巧,比如通篇可见的scatterlist散列表等等。

       最后,谈到这三个目录的作用及其之间的关系主要有:

card目录:主要完成与块设备层的接口,向core层提供正确可靠的struct mmc_request结构。

core目录:维护了SD卡与host之间的联系,实现了SD,MMCSDIO等设备初始化的通用代码,并调用host提供的struct mmc_host_ops完成设备相关的初始化操作。

host目录:像core层提供必要的设备操作方法,特别是完成struct mmc_host_ops结构,以及初始化控制等,另外与card相关联的一点是当处理完成时利用Completions唤醒block

http://m.blog.csdn.net/blog/rain0993/8476755

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值