Linux的设备驱动程序架构分析之MMC / SD(二)

LINUX 专栏收录该内容
103 篇文章 3 订阅

转自:http : //blog.csdn.net/liuhaoyutz

内核版本:3.10.1

 
一,s3cmci_ops分析

在上一篇文章中我们分析了Mini2440 MMC / SD驱动的探针函数s3cmci_probe。在该函数中初始化了结构mmc_host指针变量mmc,其中,设置mmc-> ops为s3cmci_ops,s3cmci_ops定义在drivers / mmc / host / s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1427static  struct  mmc_host_ops s3cmci_ops = {  
  2. 1428 .request = s3cmci_request,  
  3. 1429.set_ios = s3cmci_set_ios,  
  4. 1430 .get_ro = s3cmci_get_ro,  
  5. 1431 .get_cd = s3cmci_card_present,  
  6. 1432.enable_sdio_irq = s3cmci_enable_sdio_irq,  
  7. 1433};  


struct mmc_host是mmc core层与主机层的接口,mmc_host.ops是控制主机完成用户请求的接口函数集,其类型是struct mmc_host_ops,该结构体定义在include / linux / mmc / host.h文件中:

[cpp]  查看纯 文本  
  1.  83structmmc_host_ops {  
  2.  84     / * 
  3.  85 *“启用”在主机被声明时被调用,并且“禁用”被调用 
  4.  86 *当主机被释放时。“启用”和“禁用”已被弃用。 
  5.  87 * /  
  6.  88    int  (* enable)(struct  mmc_host * host);  
  7.  89    int  (* disable)(struct  mmc_host * host);  
  8.  90     / * 
  9.  91 *主机可以实现pre_req和post_req 
  10.  92 *命令来支持请求的双缓冲(准备一个 
  11.  93 *请求,而另一个请求是活动的)。 
  12.  94 * pre_req()必须后跟post_req()。 
  13.  95 *撤消对pre_req()的调用,调用post_req() 
  14.  96 *非零错误条件。 
  15.  97 * /  
  16.  98    void     (* post_req)(structmmc_host * host,  struct  mmc_request * req,  
  17.  99                 int  err);  
  18. 100    void     (* pre_req)(struct  mmc_host * host,  struct  mmc_request * req,  
  19. 101                bool  is_first_req);  
  20. 102    void     (* request)(struct  mmc_host * host,  struct  mmc_request * req);  
  21. 103    / * 
  22. 104 *避免频繁地调用这三个函数,或者在“fastpath”中, 
  23. 105 *因为底层控制器可能会以昂贵的方式实施它们 
  24. 106 *和/或缓慢的方式。 
  25. 107 * 
  26. 108 *另请注意,这些功能可能会休眠,所以不要打电话给他们 
  27. 109 *在原子语境中! 
  28. 110 * 
  29. 111 * get_ro回调函数的返回值应为: 
  30. 112 * 0用于读/写卡 
  31. 113 * 1用于只读卡 
  32. 114 * -ENOSYS不支持时(等于NULL回调) 
  33. 115 *或错误发生错误的负errno值 
  34. 116 * 
  35. 117 * get_cd回调的返回值应为: 
  36. 118 * 0为缺席卡 
  37. 119 * 1为现在的卡 
  38. 不支持120 * -ENOSYS(等于NULL回调) 
  39. 121 *或错误发生错误的负errno值 
  40. 122 * /  
  41. 123    void     (* set_ios)(struct  mmc_host * host,  struct  mmc_ios * ios);  
  42. 124    int  (* get_ro)(struct  mmc_host * host);  
  43. 125    int  (* get_cd)(struct  mmc_host * host);  
  44. 126  
  45. 127    void     (* enable_sdio_irq)(structmmc_host * host,  int  enable);  
  46. 128  
  47. 129    / *可选回调HC怪癖* /  
  48. 130    void     (* init_card)(struct  mmc_host * host,  struct  mmc_card * card);  
  49. 131  
  50. 132    int  (* start_signal_voltage_switch)(struct  mmc_host * host,  struct  mmc_ios * ios);  
  51. 133  
  52. 134    / *检查卡是否正在拉dat [0:3]低*  
  53. 135    int  (* card_busy)(struct  mmc_host * host);  
  54. 136  
  55. 137    / * SD和eMMC卡的调谐命令操作码值不同* /  
  56. 138    int  (* execute_tuning)(struct  mmc_host * host,u32 opcode);  
  57. 139    int  (* select_drive_strength)(unsigned  int  max_dtr,  int  host_drv,intcard_drv);  
  58. 140    void     (* hw_reset)(struct  mmc_host * host);  
  59. 141    void     (* card_event)(structmmc_host * host);  
  60. 142};  


请求函数用于处理用户的请求。

set_ios函数用于设置SDI的控制参数,如时钟,总线宽度等等。

get_ro函数用于探测SD卡是否有写保护。

get_cd函数用于探测卡是否已插入插槽。

enable_sdio_irq函数用于启动或禁用SDI中断。

需要注意的是,为什么没有对MMC / SD进行读写的读取和写入函数呢?这是因为Linux的块设备的读写操作是通过请求函数完成的。

那么对于mini2440的,它的s3cmci_ops中的成员函数在什么时候会被调用呢举例如下?

在驱动器/ MMC /核心/ core.c文件中:

 

[cpp]  查看纯 文本  
  1. 194staticvoid  
  2.  195mmc_start_request(struct  mmc_host * host,struct  mmc_request * mrq)  
  3.  196 {  
  4.  197#ifdef CONFIG_MMC_DEBUG  
  5.  198 unsigned  int  i,sz;  
  6.  199    struct  scatterlist * sg;  
  7.  200#ENDIF  
  8.  201  
  9.  202    if  (mrq-> sbc){  
  10.  203 pr_debug(“<%s:starting CMD%u arg%08x flags%08x> \ n” ,  
  11.  204 mmc_hostname(host),mrq-> sbc-> opcode,  
  12.  205 mrq-> sbc-> arg,mrq-> sbc-> flags);  
  13.  206}  
  14.  207  
  15.  208 pr_debug(“%s:starting CMD%u arg%08x flags%08x \ n” ,  
  16.  209 mmc_hostname(host),mrq-> cmd-> opcode,  
  17.  210 mrq-> cmd-> arg,mrq-> cmd-> flags);  
  18.  211  
  19.  212    if  (mrq-> data){  
  20.  213 pr_debug(“%s:blksz%dblocks%d flags%08x”  
  21.  214            “tsac%d ms nsac%d \ n” ,  
  22.  215 mmc_hostname(host),mrq-> data-> blksz,  
  23.  216 mrq-> data-> blocks,mrq-> data-> flags,  
  24.  217 mrq-> data-> timeout_ns / 1000000,  
  25.  218 mrq-> data-> timeout_clks);  
  26.  219}  
  27.  220 221     if  (mrq-> stop){  
  28.  222 pr_debug(“%s:CMD%u arg%08x flags%08x \ n” ,  
  29.  223 mmc_hostname(host),mrq-> stop-> opcode,  
  30.  224 mrq-> stop-> arg,mrq-> stop-> flags);  
  31.  225}  
  32.  226  
  33.  227 WARN_ON(!host-> claim);  
  34.  228  
  35.  229 mrq-> cmd-> error = 0;  
  36.  230 mrq-> cmd-> mrq = mrq;  
  37.  231    if  (mrq-> data){  
  38.  232 BUG_ON(mrq-> data-> blksz> host-> max_blk_size);  
  39.  233 BUG_ON(mrq-> data-> blocks> host-> max_blk_count);  
  40.  234 BUG_ON(mrq-> data-> blocks * mrq-> data-> blksz>  
  41.  235 host-> max_req_size);  
  42.  236  
  43.  237#ifdef CONFIG_MMC_DEBUG  
  44.  238 sz = 0;  
  45.  239 for_each_sg(mrq-> data-> sg,sg,mrq-> data-> sg_len,i)  
  46.  240 sz + = sg-> length;  
  47.  241 BUG_ON(sz!= mrq-> data-> blocks * mrq-> data-> blksz);  
  48.  242#ENDIF  
  49.  243  
  50.  244 mrq-> cmd-> data = mrq-> data;  
  51.  245 mrq-> data-> error = 0;  
  52.  246 mrq-> data-> mrq = mrq;  
  53.  247        if  (mrq-> stop){  
  54.  248 mrq-> data-> stop = mrq-> stop;  
  55.  249 mrq-> stop-> error = 0;  
  56.  250 mrq-> stop-> mrq = mrq;  
  57.  251}  
  58.  252}  
  59.  253 mmc_host_clk_hold(host);  
  60.  254 led_trigger_event(host-> led,LED_FULL);  
  61.  255 host-> ops-> request(host,mrq);  
  62.  256}  

可以看到255行,调用了宿主 - > ops->请求函数,即s3cmci_request函数。

再比如,在驱动器/ MMC /核心/ core.c文件中:

[cpp]  查看纯 文本  
  1. 954 / * 
  2. 955 *内部功能,实际的ios调用主机驱动程序, 
  3. 956 *可选择打印一些调试输出。 
  4. 957 * /  
  5. 958static  inline void  mmc_set_ios(structmmc_host * host)   
  6. 959 {  
  7. 960    struct  mmc_ios * ios =&host-> ios;  
  8. 961  
  9. 962 pr_debug(“%s:clock%uHz busmode%u powermode%u cs%u Vdd%u”  
  10. 963        “width%u timing%u \ n” ,  
  11. 964 mmc_hostname(host),ios-> clock,ios-> bus_mode,  
  12. 965 ios-> power_mode,ios-> chip_select,ios-> vdd,  
  13. 966 ios-> bus_width,ios-> timing);  
  14. 967  
  15. 968    if  (ios-> clock> 0)  
  16. 969 mmc_set_ungated(host);  
  17. 970 host-> ops-> set_ios(host,ios);  
  18. 971}  


可以看到,970行,调用了宿主 - > ops-> set_ios函数,即s3cmci_set_ios函数。

下面我们就来看一下s3cmci_ops的各个成员函数的实现。

s3cmci_get_ro函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1372static  int  s3cmci_get_ro(structmmc_host * mmc)  
  2. 1373 {  
  3. 1374    struct  s3cmci_host * host = mmc_priv(mmc);  
  4. 1375    struct  s3c24xx_mci_pdata * pdata = host-> pdata;  
  5. 1376    int  ret;  
  6. 1377  
  7. 1378    if  (pdata-> no_wprotect)  
  8. 1379        返回 0;  
  9. 1380  
  10. 1381 ret = gpio_get_value(pdata-> gpio_wprotect)?1:0;  
  11. 1382 ret ^ = pdata-> wprotect_invert;  
  12. 1383  
  13. 1384    返回 RET;  
  14. 1385}  


1374行,由mmc_host取得s3cmci_host。

1375行,取得s3c24xx_mci_pdata,其它保存着SDI的平台数据。

1378行,如果s3c24xx_mci_pdata.no_wprotect为1,表明没有写保护开关,直接退出。例如MMC卡就没有写保护开关,只有SD卡才有写保护开关。

1381行,读取gpio_wprotect引脚电平,对于MINI2440,即GPH8引脚。

1382行,与pdata-> wprotect_invert执行异或操作,即反转上步得到GPH8引脚电平值。

s3cmci_card_present函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1254static  int  s3cmci_card_present(structmmc_host * mmc)  
  2. 1255 {  
  3. 1256    struct  s3cmci_host * host = mmc_priv(mmc);  
  4. 1257    struct  s3c24xx_mci_pdata * pdata = host-> pdata;  
  5. 1258    int  ret;  
  6. 1259  
  7. 1260    if  (pdata-> no_detect)  
  8. 1261        返回 -ENOSYS;  
  9. 1262  
  10. 1263 ret = gpio_get_value(pdata-> gpio_detect)?0:1;  
  11. 1264    return  ret ^ pdata-> detect_invert;  
  12. 1265}  


1256行,由mmc_host取得s3cmci_host。

1257行,取得s3c24xx_mci_pdata,其它保存着SDI的平台数据。

1260行,如果s3c24xx_mci_pdata.no_detect为1,表明没有卡探测引脚,直接退出。

1263行,读取gpio_detect引脚电平值,对于MINI2440,即GPG8引脚。

1264行,与pdata-> detect_invert进行异或操作,即反转上步得到的GPG8引脚电平值。

s3cmci_enable_sdio_irq函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1387static voids3cmci_enable_sdio_irq(struct  mmc_host * mmc,  int  enable)  
  2. 1388 {  
  3. 1389    struct  s3cmci_host * host = mmc_priv(mmc);  
  4. 1390无符号   旗  
  5. 1391 u32 con  
  6. 1392  
  7. 1393 local_irq_save(flags);  
  8. 1394  
  9. 1395 con = readl(host-> base + S3C2410_SDICON);  
  10. 1396 host-> sdio_irqen = enable;  
  11. 1397  
  12. 1398    if  (enable == host-> sdio_irqen)  
  13. 1399        goto  same_state;  
  14. 1400  
  15. 1401    if  (enable){  
  16. 1402 con | = S3C2410_SDICON_SDIOIRQ;  
  17. 1403 enable_imask(host,S3C2410_SDIIMSK_SDIOIRQ);  
  18. 1404  
  19. 1405        if  (!host-> irq_state &&!host-> irq_disabled){  
  20. 1406 host-> irq_state =  true ;  
  21. 1407 enable_irq(host-> irq);  
  22. 1408}  
  23. 1409}  else  {  
  24. 1410 disable_imask(host,S3C2410_SDIIMSK_SDIOIRQ);  
  25. 1411 con&=〜S3C2410_SDICON_SDIOIRQ;  
  26. 1412  
  27. 1413        if  (!host-> irq_enabled && host-> irq_state){  
  28. 1414 disable_irq_nosync(host-> irq);  
  29. 1415 host-> irq_state =  false ;  
  30. 1416}  
  31. 1417}  
  32. 1418  
  33. 1419 writel(con,host-> base + S3C2410_SDICON);  
  34. 1420  
  35. 1421 same_state:  
  36. 1422 local_irq_restore(flags);  
  37. 1423  
  38. 1424 s3cmci_check_sdio_irq(host);  
  39. 1425}  


1389行,由mmc_host取得s3cmci_host。

1395行,读取SDICON即SDI控制寄存器的内容,保存在CON中。

1396行,我觉得这一行不应该存在,因为这一行将参数启用的值赋值给宿主>​​ sdio_irqen,但是1398行又接着判断启用与主机 - > sdio_irqen是否相等,如果相等就退出了。

1401年至1408年行,启用为1,使能SDIO中断。

1402行,S3C2410_SDICON_SDIOIRQ定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

57#define S3C2410_SDICON_SDIOIRQ(1 << 3)

对照S3C2440数据手册,可知这个宏用来设置SDICON寄存器的第3位,该位决定是否接收SDIO中断。

1403行,S3C2410_SDIIMSK_SDIOIRQ定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

105#define S3C2410_SDIIMSK_SDIOIRQ(1 << 12)

对照S3C2440数据手册,可知这个宏用来设置SDIIntMsk寄存器的第13位,该位决定当读等待请求发生时,SDI是否产生一个中断。

enable_imask函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 279staticinline u32 enable_imask(struct  s3cmci_host * host,u32 imask)  
  2. 280 {  
  3. 281 u32 newmask;  
  4. 282  
  5. 283 newmask = readl(host-> base + host-> sdiimsk);  
  6. 284 newmask | = imask;  
  7. 285  
  8. 286 writel(newmask,host-> base + host-> sdiimsk);  
  9. 287  
  10. 288    返回 newmask;  
  11. 289}  


该函数用来设置SDIIntMsk寄存器。

1409至1416年行,使为0,禁用SDIO中断。

1419行,用新的骗子设置SDICON即SDI控制寄存器。

s3cmci_set_ios函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1306static  void  s3cmci_set_ios(structmmc_host * mmc,  struct  mmc_ios * ios)  
  2. 1307 {  
  3. 1308    struct  s3cmci_host * host = mmc_priv(mmc);  
  4. 1309 u32 mci_con;  
  5. 1310  
  6. 1311    / *设置电源状态* /  
  7. 1312  
  8. 1313 mci_con = readl(host-> base + S3C2410_SDICON);  
  9. 1314  
  10. 1315    开关 (ios-> power_mode){  
  11. 1316    案例 MMC_POWER_ON:  
  12. 1317     MMC_POWER_UP:  
  13. 1318        / *在SD模式下配置GPE5 ... GPE10引脚* /  
  14. 1319 s3c_gpio_cfgall_range(S3C2410_GPE(5),6,S3C_GPIO_SFN(2),  
  15. 1320 S3C_GPIO_PULL_NONE);  
  16. 1321  
  17. 1322        if  (host-> pdata-> set_power)  
  18. 1323 host-> pdata-> set_power(ios-> power_mode,ios-> vdd);  
  19. 1324  
  20. 1325        if  (!host-> is2440)  
  21. 1326 mci_con | = S3C2410_SDICON_FIFORESET;  
  22. 1327  
  23. 1328        突破;  
  24. 1329  
  25. 1330     MMC_POWER_OFF:  
  26. 1331    默认值:  
  27. 1332 gpio_direction_output(S3C2410_GPE(5),0);  
  28. 1333  
  29. 1334        if  (host-> is2440)  
  30. 1335 mci_con | = S3C2440_SDICON_SDRESET;  
  31. 1336  
  32. 1337        if  (host-> pdata-> set_power)  
  33. 1338 host-> pdata-> set_power(ios-> power_mode,ios-> vdd);  
  34. 1339  
  35. 1340        突破;  
  36. 1341}  
  37. 1342  
  38. 1343 s3cmci_set_clk(host,ios);  
  39. 1344  
  40. 1345    / *设置CLOCK_ENABLE * /  
  41. 1346    if  (ios-> clock)  
  42. 1347 mci_con | = S3C2410_SDICON_CLOCKTYPE;  
  43. 1348    其他  
  44. 1349 mci_con&=〜S3C2410_SDICON_CLOCKTYPE;  
  45. 1350  
  46. 1351 writel(mci_con,host-> base + S3C2410_SDICON);  
  47. 1352  
  48. 1353    if  ((ios-> power_mode == MMC_POWER_ON)||  
  49. 1354(ios-> power_mode == MMC_POWER_UP)){  
  50. 1355 dbg(host,dbg_conf,  “以%lukHz运行(请求:%ukHz)\ n” ,  
  51. 1356 host-> real_rate / 1000,ios-> clock / 1000);  
  52. 1357}  else  {  
  53. 1358 dbg(host,dbg_conf,  “掉电。\ n” );  
  54. 1359}  
  55. 1360  
  56. 1361 host-> bus_width = ios-> bus_width;  
  57. 1362}  


1306行,参数ios是structmmc_ios类型指针.struct mmc_ios定义在include / linux / mmc / host.h文件中:

[cpp]  查看纯 文本  
  1. 22structmmc_ios {  
  2. 23 unsigned  int     clock;          / *时钟频率* /  
  3. 24 unsigned  short   vdd;  
  4. 25  
  5. 26 / * vdd从下方存储所选电压范围的位数。* /  
  6. 27  
  7. 28 unsigned  char    bus_mode;       / *命令输出模式* /  
  8. 29  
  9. 30#define MMC_BUSMODE_OPENDRAIN 1  
  10. 31#define MMC_BUSMODE_PUSHPULL 2  
  11. 32  
  12. 33 unsigned  char    chip_select;        / * SPI芯片选择* /  
  13. 34  
  14. 35#define MMC_CS_DONTCARE 0  
  15. 36#define MMC_CS_HIGH 1  
  16. 37#define MMC_CS_LOW 2  
  17. 38  
  18. 39 unsigned  char    power_mode;     / *电源模式* /  
  19. 40  
  20. 41#define MMC_POWER_OFF 0  
  21. 42#define MMC_POWER_UP 1  
  22. 43#define MMC_POWER_ON 2  
  23. 44  
  24. 45 unsigned  char    bus_width;      / *数据总线宽度* /  
  25. 46  
  26. 47#define MMC_BUS_WIDTH_1 0  
  27. 48#define MMC_BUS_WIDTH_4 2  
  28. 49#define MMC_BUS_WIDTH_8 3  
  29. 50  
  30. 51无符号  字符   时序         / *使用时间规格* /  
  31. 52  
  32. 53#define MMC_TIMING_LEGACY 0  
  33. 54#define MMC_TIMING_MMC_HS 1  
  34. 55#define MMC_TIMING_SD_HS 2  
  35. 56#define MMC_TIMING_UHS_SDR12 3  
  36. 57#define MMC_TIMING_UHS_SDR25 4  
  37. 58#define MMC_TIMING_UHS_SDR50 5  
  38. 59#define MMC_TIMING_UHS_SDR104 6  
  39. 60#define MMC_TIMING_UHS_DDR50 7  
  40. 61#define MMC_TIMING_MMC_HS200 8  
  41. 62  
  42. 63#define MMC_SDR_MODE 0  
  43. 64#define MMC_1_2V_DDR_MODE 1  
  44. 65#define MMC_1_8V_DDR_MODE 2  
  45. 66#define MMC_1_2V_SDR_MODE 3  
  46. 67#define MMC_1_8V_SDR_MODE 4  
  47. 68  
  48. 69 unsigned  char   signal_voltage;     / *信号电压(1.8V或3.3V)* /  
  49. 70  
  50. 71#define MMC_SIGNAL_VOLTAGE_330 0  
  51. 72#defineMMC_SIGNAL_VOLTAGE_180 1  
  52. 73#define MMC_SIGNAL_VOLTAGE_120 2  
  53. 74  
  54. 75 unsigned  char    drv_type;       / *驱动程序类型(A,B,C,D)* /  
  55. 76  
  56. 77#define MMC_SET_DRIVER_TYPE_B 0  
  57. 78#define MMC_SET_DRIVER_TYPE_A 1  
  58. 79#define MMC_SET_DRIVER_TYPE_C 2  
  59. 80#define MMC_SET_DRIVER_TYPE_D 3  
  60. 81};  


1308行,由mmc_host取得s3cmci_host。

1313行,读取SDICON即SDI控制寄存器的值,保存在mci_con中。

1316至1328年行,如果ios-> power_mode为MMC_POWER_ON或MMC_POWER_UP,则执行这个分支。

S3C_GPIO_SFN宏定义在拱/臂/高原三星/包含/高原/ GPIO-cfg.h文件中:

[cpp]  查看纯 文本  
  1. 66#defineS3C_GPIO_SPECIAL_MARK(0xfffffff0)  
  2. 67#define S3C_GPIO_SPECIAL(x)(S3C_GPIO_SPECIAL_MARK |(x))  
  3. 68  
  4. 69 / *定义通用引脚配置* /  
  5. 70#define S3C_GPIO_INPUT(S3C_GPIO_SPECIAL(0))  
  6. 71#define S3C_GPIO_OUTPUT(S3C_GPIO_SPECIAL(1))  
  7. 72#defineS3C_GPIO_SFN(x)(S3C_GPIO_SPECIAL(x))  


S3C_GPIO_PULL_NONE宏定义在拱/臂/高原三星/包含/高原/ GPIO-cfg.h文件中:

[cpp]  查看纯 文本  
  1. 126 / *定义每个gpio引脚可用的pull-{up,down}的值。 
  2. 127 * 
  3. 128 *这些值控制弱上拉电阻的状态 
  4. 129 *可用于S3C系列的大多数引脚。并不是所有的芯片都支持 
  5. 130 *上或下设置,它可能依赖于正在使用的芯片 
  6. 131 *用于特定模式是否可用。 
  7. 132 * /  
  8. 133#define S3C_GPIO_PULL_NONE((__force samsung_gpio_pull_t)0x00)  
  9. 134#define S3C_GPIO_PULL_DOWN((__force samsung_gpio_pull_t)0x01)  
  10. 135#define S3C_GPIO_PULL_UP((__force samsung_gpio_pull_t)0x02)  


s3c_gpio_cfgall_range函数定义在驱动器/ GPIO / GPIO-samsung.c文件中:

[cpp]  查看纯 文本  
  1. 3150int s3c_gpio_cfgall_range(unsigned intstart,unsigned  int  nr,  
  2. 3151 unsigned  int  cfg,samsung_gpio_pull_t pull)  
  3. 3152 {  
  4. 3153    int  ret;  
  5. 3154  
  6. 3155    for  (; nr> 0; nr--,start ++){  
  7. 3156 s3c_gpio_setpull(start,pull);  
  8. 3157 ret = s3c_gpio_cfgpin(start,cfg);  
  9. 3158        if  (ret!= 0)  
  10. 3159             返回 RET;  
  11. 3160}  
  12. 3161  
  13. 3162    返回 0;  
  14. 3163}  


可以看到,s3c_gpio_cfgall_range函数设置从GPE5开始的6个GPIO,即GPE5,GPE6,GPE7,GPE8,GPE9,GPE10。使用参数CFG设置GPECON寄存器,使用参数拉设置GPEUP寄存器。

GPECON寄存器对应的位置被设置为01,即使能相关SDI功能。

一三三○年至1341年行,如果ios-> power_mode为MMC_POWER_OFF或者默认情况下,则执行这个分支。

1332行,调用gpio_direction_output(S3C2410_GPE(5),0)关闭SDI时钟。

1335行,mci_con | = S3C2440_SDICON_SDRESET,根据S3C2440数据手册,这句用于重置整个sd / mmc模块。

1343行,调用s3cmci_set_clk(主机,IOS)设置时钟,s3cmci_set_clk定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1283static  void  s3cmci_set_clk(structs3cmci_host * host,  struct  mmc_ios * ios)  
  2. 1284 {  
  3. 1285 u32 mci_psc;  
  4. 1286  
  5. 1287    / *设置时钟* /  
  6. 1288     (mci_psc = 0; mci_psc <255; mci_psc ++){  
  7. 1289 host-> real_rate = host-> clk_rate /(host-> clk_div *(mci_psc + 1));  
  8. 1290  
  9. 1291        if  (host-> real_rate <= ios-> clock)  
  10. 1292             突破;  
  11. 1293}  
  12. 1294  
  13. 1295    if  (mci_psc> 255)  
  14. 1296 mci_psc = 255;  
  15. 1297  
  16. 1298 host-> prescaler = mci_psc;  
  17. 1299 writel(host->预分频器,host-> base + S3C2410_SDIPRE);  
  18. 1300  
  19. 1301    / *如果请求的时钟为0,real_rate也将为0 *  
  20. 1302    if  (ios-> clock == 0)  
  21. 1303 host-> real_rate = 0;  
  22. 1304}                                                                    


1346至1349年行,如果ios->时钟不为0时,使能时钟,否则禁用时钟。

1351行,将mci_con写回SDICON寄存器。

1361行,用ios-> bus_width设置数据总线宽度宿主 - > bus_width。

s3cmci_request函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1267static voids3cmci_request(struct  mmc_host * mmc,  struct  mmc_request * mrq)  
  2. 1268 {  
  3. 1269     struct  s3cmci_host * host = mmc_priv(mmc);  
  4. 1270  
  5. 1271 host-> status =  “mmc request” ;  
  6. 1272 host-> cmd_is_stop = 0;  
  7. 1273 host-> mrq = mrq;  
  8. 1274  
  9. 1275     if  (s3cmci_card_present(mmc)== 0){  
  10. 1276 dbg(host,dbg_err,  “%s:no mediumpresent \ n” ,__func__);  
  11. 1277 host-> mrq-> cmd-> error = -ENOMEDIUM;  
  12. 1278 mmc_request_done(mmc,mrq);  
  13. 1279}  else  
  14. 1280 s3cmci_send_request(mmc);  
  15. 1281}  


struct mmc_request代表一个请求,该结构体定义在include / linux / mmc / core.h文件中:

[cpp]  查看纯 文本  
  1. 127structmmc_request {  
  2. 128     struct  mmc_command * sbc;      / * SET_BLOCK_COUNT for multiblock * /  
  3. 129     struct  mmc_command * cmd;  
  4. 130     struct  mmc_data * data;  
  5. 131     struct  mmc_command * stop;  
  6. 132  
  7. 133     结构 完成;  
  8. 134     void             (* done)(struct  mmc_request *); / *完成功能* /  
  9. 135     struct  mmc_host * host;  
  10. 136};  


1271行,将宿主>状态设置为 “mmcrequest”,主机 - >状态主要用于记录请求处理所处的阶段及状态,方便调试使用。

1272行,设置宿主> cmd_is_stop为0,从字面上理解,我认为宿主> cmd_is_stop代表命令是否是停止命令(即有一个命令是停止),0表示不是停止命令。

1273行,将mmc_requestmrp保存在主机 - > MRQ中,方便以后使用。

1275年至1280年行,如果卡不存在,则调用mmc_request_done(MMC,MRQ)结束这次请求处理,否则,调用s3cmci_send_request(MMC)。

s3cmci_send_request函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1202static voids3cmci_send_request(struct  mmc_host * mmc)  
  2. 1203 {  
  3. 1204     struct  s3cmci_host * host = mmc_priv(mmc);  
  4. 1205     struct  mmc_request * mrq = host-> mrq;  
  5. 1206     struct  mmc_command * cmd = host-> cmd_is_stop?mrq-> stop:mrq-> cmd;  
  6. 1207  
  7. 1208 host-> ccnt ++;  
  8. 1209 prepare_dbgmsg(host,cmd,host-> cmd_is_stop);  
  9. 1210  
  10. 1211     / *清除命令,数据和fifo状态注册 
  11. 1212五十目清除只有在2440,但不会在2410受伤 
  12. 1213 * /  
  13. 1214 writel(0xFFFFFFFF,host-> base + S3C2410_SDICMDSTAT);  
  14. 1215 writel(0xFFFFFFFF,host-> base + S3C2410_SDIDSTA);  
  15. 1216 writel(0xFFFFFFFF,host-> base + S3C2410_SDIFSTA);  
  16. 1217  
  17. 1218     if  (cmd-> data){  
  18. 1219         int  res = s3cmci_setup_data(host,cmd-> data);  
  19. 1220  
  20. 1221 host-> dcnt ++;  
  21. 1222  
  22. 1223         if  (res){  
  23. 1224 dbg(host,dbg_err,  “setup dataerror%d \ n” ,res);  
  24. 1225 cmd-> error = res;  
  25. 1226 cmd-> data-> error = res;  
  26. 1227  
  27. 1228 mmc_request_done(mmc,mrq);  
  28. 1229             回报;  
  29. 1230}  
  30. 1231  
  31. 1232         if  (s3cmci_host_usedma(host))  
  32. 1233 res = s3cmci_prepare_dma(host,cmd-> data);  
  33. 1234         else  
  34. 1235 res = s3cmci_prepare_pio(host,cmd-> data);  
  35. 1236  
  36. 1237         if  (res){  
  37. 1238 dbg(host,dbg_err,“data prepareerror  %d \ n” ,res);  
  38. 1239 cmd-> error = res;  
  39. 1240 cmd-> data-> error = res;  
  40. 1241  
  41. 1242 mmc_request_done(mmc,mrq);  
  42. 1243             回报;  
  43. 1244}  
  44. 1245}  
  45. 1246  
  46. 1247     / *发送命令* /  
  47. 1248 s3cmci_send_command(host,cmd);  
  48. 1249  
  49. 1250     / *使能中断* /  
  50. 1251 s3cmci_enable_irq(host,  true );  
  51. 1252}  


1204行,由structmmc_host得到结构s3cmci_host。

1205行,从宿主> MRQ取出mmc_request以便使用。

1206行,因为宿主> cmd_is_stop被设置为0,所以CMD被设置为mrq-> CMD。

1214-1216行,清空SDICmdSta寄存器,SDIDatSta寄存器和SDIFSTA寄存器。

1216至1245年行,如果CMD->数据不为0,即当前命令带有要处理的数据,则执行这个如果语句块,进行数据处理的准备工作。

1219行,调用s3cmci_setup_data(主机,CMD->数据),该函数定义在驱动/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1048static ints3cmci_setup_data(struct  s3cmci_host * host,  struct  mmc_data * data)  
  2. 1049 {  
  3. 1050 u32 dcon,imsk,stoptries = 3;  
  4. 1051  
  5. 1052     / *写DCON寄存器* /  
  6. 1053  
  7. 1054     if  (!data){  
  8. 1055 writel(0,host-> base + S3C2410_SDIDCON);  
  9. 1056         返回 0;  
  10. 1057}  
  11. 1058  
  12. 1059     if  ((data-> blksz&3)!= 0){  
  13. 1060         / *我们不能处理不对齐的块 
  14. 1061 *一个块被转移。* /  
  15. 1062  
  16. 1063         if  (data-> blocks> 1){  
  17. 1064 pr_warning(“%s:can not donon-word sizes block transfer(blksz%d)\ n” ,__func__,data-> blksz);  
  18. 1065             返回 -EINVAL;  
  19. 1066}  
  20. 1067}  
  21. 1068  
  22. 1069     while  (readl(host-> base + S3C2410_SDIDSTA)&  
  23. 1070(S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)){  
  24. 1071  
  25. 1072 dbg(host,dbg_err,  
  26. 1073             “mci_setup_data()transferstillin progress。\ n” );  
  27. 1074  
  28. 1075 writel(S3C2410_SDIDCON_STOP,host-> base + S3C2410_SDIDCON);  
  29. 1076 s3cmci_reset(host);  
  30. 1077  
  31. 1078         if  ((stoptries--)== 0){  
  32. 1079 dbg_dumpregs(host,“DRF” );  
  33. 1080             返回 -EINVAL;  
  34. 1081}  
  35. 1082}  
  36. 1083  
  37. 1084 dcon = data-> blocks&S3C2410_SDIDCON_BLKNUM_MASK;  
  38. 1085  
  39. 1086     if  (s3cmci_host_usedma(host))  
  40. 1087 dcon | = S3C2410_SDIDCON_DMAEN;  
  41. 1088  
  42. 1089     if  (host-> bus_width == MMC_BUS_WIDTH_4)  
  43. 1090 dcon | = S3C2410_SDIDCON_WIDEBUS;  
  44. 1091  
  45. 1092     if  (!(data-> flags&MMC_DATA_STREAM))  
  46. 1093 dcon | = S3C2410_SDIDCON_BLOCKMODE;  
  47. 1094  
  48. 1095     if  (data-> flags&MMC_DATA_WRITE){  
  49. 1096 dcon | = S3C2410_SDIDCON_TXAFTERRESP;  
  50. 1097 dcon | = S3C2410_SDIDCON_XFER_TXSTART;  
  51. 1098}  
  52. 1099  
  53. 1100     if  (data-> flags&MMC_DATA_READ){  
  54. 1101 dcon | = S3C2410_SDIDCON_RXAFTERCMD;  
  55. 1102 dcon | = S3C2410_SDIDCON_XFER_RXSTART;  
  56. 1103}  
  57. 1104  
  58. 1105     if  (host-> is2440){  
  59. 1106 dcon | = S3C2440_SDIDCON_DS_WORD;  
  60. 1107 dcon | = S3C2440_SDIDCON_DATSTART;  
  61. 1108}  
  62. 1109  
  63. 1110 writel(dcon,host-> base + S3C2410_SDIDCON);  
  64. 1111  
  65. 1112     / *写入BSIZE寄存器* /  
  66. 1113  
  67. 1114 writel(data-> blksz,host-> base + S3C2410_SDIBSIZE);  
  68. 1115  
  69. 1116     / *加入IMASK注册* /  
  70. 1117 imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |  
  71. 1118 S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;  
  72. 1119  
  73. 1120 enable_imask(host,imsk);  
  74. 1121  
  75. 1122     / *写入TIMER寄存器* /  
  76. 1123  
  77. 1124     if  (host-> is2440){  
  78. 1125 writel(0x007FFFFF,host-> base + S3C2410_SDITIMER);  
  79. 1126}  else  {  
  80. 1127 writel(0x0000FFFF,host-> base + S3C2410_SDITIMER);  
  81. 1128  
  82. 1129         / * FIX:设置缓慢的时钟,以防止超时读*  
  83. 1130         if  (data-> flags&MMC_DATA_READ)  
  84. 1131 writel(0xFF,host-> base + S3C2410_SDIPRE);  
  85. 1132}  
  86. 1133  
  87. 1134     返回 0;  
  88. 1135}  


1054-1057行,如果命令数据为空,则清零SDIDatCon寄存器。

1059至1067年行,根据数据表的描述,如果在多模块下必须分配字大小,即BLKSIZE [1:0] = 00,所以这里“与” 3来判断是不是单模块如果在单模块处理的情况下,模块数大于1,则出错退出。

1069至1082年行,循环判断是否有数据正在发送或接收,如果有,则停止传输,并复位时钟。最多循环3次。

1086年至1087年行,如果使用DMA传输,则使能SDIDatCon寄存器的第15位的DMA功能。

1089至1090年行,如果数据总线宽度为4线,则使能SDIDatCon寄存器的第16位宽总线WideBus功能。

一〇九二年至1093年行,配置SDIDatCon寄存器的第17位,数据传输模式为块传输模式。

1095至1098年行,如果是写数据,配置SDIDatCon寄存器的第20位,收到回应后开始写数据。然后配置SDIDatCon寄存器的第12,13位,设置为写模式。

一一〇〇年至1103年行,如果是读数据,配置SDIDatCon寄存器的第19位,命令发送后开始读数据。

然后配置SDIDatCon寄存器的第12,13位,设置为读模式。

1105至1108年行,如果是S3C2440,配置SDIDatCon寄存器的第22,23位为10,即传输单位为字。然后配置SDIDatCon寄存器的第14位,开始数据传输。

1110行,将DCON写入SDIDatCon寄存器。

1114行,将数据 - > blksz写入SDIBSize寄存器。

1117至1118年行,设置出现FIFO失败SDI中断使能;数据接收CRC错误SDI中断使能;数据接收超时SDI中断使能;数据计时为0SDI中断使能。

1120行,调用enable_imask使能设置的中断。

1124年至1132年行,设置SDIDTimer寄存器。

回到s3cmci_send_request函数:

1223-1230行,如果s3cmci_setup_data出错,则打印信息并退出。

1232年至1233年行,如果使用DMA,则调用s3cmci_prepare_dma函数,该函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中,关于DMA相关的函数,我们不再详细跟踪了。

1235行,如果没有使用DMA数据传输方式,则调用s3cmci_prepare_pio函数,即使用FIFO数据传输方式,具体来说,就是调用do_pio_write向FIFO中填充数据,当64字节的FIFO少于33字节时就会产生中断;或者从SD读数据,则先使能中断,当FIFO多于31字节时,则会调用中断服务程序,中断服务程序会调用do_pio_read读出FIFO的数据。

s3cmci_prepare_pio函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1139static ints3cmci_prepare_pio(struct  s3cmci_host * host,  struct  mmc_data * data)  
  2. 1140 {  
  3. 1141     int  rw =(data-> flags&MMC_DATA_WRITE)?1:0;  
  4. 1142  
  5. 1143 BUG_ON((data-> flags&BOTH_DIR)== BOTH_DIR);  
  6. 1144  
  7. 1145 host-> pio_sgptr = 0;  
  8. 1146 host-> pio_bytes = 0;  
  9. 1147 host-> pio_count = 0;  
  10. 1148 host-> pio_active = rw?XFER_WRITE:XFER_READ;  
  11. 1149  
  12. 1150     if  (rw){  
  13. 1151 do_pio_write(host);  
  14. 1152 enable_imask(host,S3C2410_SDIIMSK_TXFIFOHALF);  
  15. 1153}  else  {  
  16. 1154 enable_imask(host,S3C2410_SDIIMSK_RXFIFOHALF  
  17. 1155 | S3C2410_SDIIMSK_RXFIFOLAST);  
  18. 1156}  
  19. 1157  
  20. 1158     返回 0;  
  21. 1159}  


1141行,根据数据 - >标志确定是读还是写。

1151行,如果是写,则调用do_pio_write函数.do_pio_write函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 520static  void  do_pio_write(struct  s3cmci_host * host)  
  2. 521 {  
  3. 522    void  __iomem * to_ptr;  
  4. 523    int  res  
  5. 524 u32 fifo;  
  6. 525 u32 * ptr;  
  7. 526  
  8. 527 to_ptr = host-> base + host-> sdidata;  
  9. 528  
  10. 529    while  ((fifo = fifo_free(host))> 3){  
  11. 530        if  (!host-> pio_bytes){  
  12. 531 res = get_data_buffer(host,&host-> pio_bytes,  
  13. 532&host-> pio_ptr);  
  14. 533            if  (res){  
  15. 534 dbg(host,dbg_pio,  
  16. 535                     “pio_write():complete(no more data)。\ n” );  
  17. 536 host-> pio_active = XFER_NONE;  
  18. 537  
  19. 538                 ;  
  20. 539}  
  21. 540  
  22. 541 dbg(host,dbg_pio,  
  23. 542                 “pio_write():new source:[%i] @ [%p] \ n” ,  
  24. 543 host-> pio_bytes,host-> pio_ptr);  
  25. 544  
  26. 545}  
  27. 546  
  28. 547        / *如果我们已经到了最后,我们必须 
  29. 548 *写入剩余的字节数。要是我们 
  30. 549 *在块的中间,我们必须写满 
  31. 550 *字,所以四舍五入到4. * /  
  32. 551        if  (fifo> = host-> pio_bytes)  
  33. 552 fifo = host-> pio_bytes;  
  34. 553        其他  
  35. 554 fifo - = fifo&3;  
  36. 555  
  37. 556 host-> pio_bytes - = fifo;  
  38. 557 host-> pio_count + = fifo;  
  39. 558  
  40. 559 fifo =(fifo + 3)>> 2;  
  41. 560 ptr = host-> pio_ptr;  
  42. 561         (fifo--)  
  43. 562 writel(* ptr ++,to_ptr);  
  44. 563 host-> pio_ptr = ptr;  
  45. 564}  
  46. 565  
  47. 566 enable_imask(host,S3C2410_SDIIMSK_TXFIFOHALF);  
  48. 567}  


527行,取得SDIDAT寄存器的物理地址保存在to_ptr变量中。

529行,调用fifo_free(主机)函数取得FIFO的剩余可用空间的字节数保存在FIFO变量中,这里,FIFO变量代表这次而循环最多可写的字节个数。如果剩余空间大于3个字节,即最小写一个字,则循环条件成立。

530-532行,如果宿主> pio_bytes为0,则调用get_data_buffer从分散聚集列表中取得保存要写的数据的缓冲区,缓冲区的长度和起始地址分别保存在get_data_buffer的2个参数宿主> pio_bytes和第3个参数宿主> pio_ptr中。

533-539行,如果get_data_buffer出错,打印信息退出。

551-552行,如果FIFO大于等于宿主> pio_bytes,即FIFO的可用空间大于等于保存要写数据的缓冲区长度,则将FIFO设置为主机 - > pio_bytes。

554行,如果fifo小于主机 - > pio_bytes,即FIFO的可用空间小于要写数据的缓冲区长度,则将fifo设置为fifo - (fifo&3)。从注释可以看到,这是为了保证以字为单位进行写操作。

556行,主机 - > pio_bytes- = fifo,保存这次写操作后,剩余的要写的字节数。

557行,主机 - > pio_count + = fifo,保存已经写了多个个字节。

559行,将字节数转化为字数。

561-562行,写数据到SDIDAT寄存器。

563行,主机 - > pio_ptr = ptr,保存当前还剩余要写数据的位置。 

564行,结束这次虽然循环,回到529行重新执行上述过程。     

566行,使能SDIIntMsk第4位,如果Tx FIFO填充满半,就产生中断。

回到s3cmci_prepare_pio函数中:

1152行,使能SDIIntMsk第4位,如果Tx FIFO填充满半,就产生中断。

1154行,使能SDIIntMsk第0位,如果Rx FIFO填充满半,就生产中断。

1155行,使能SDIIntMsk第2位,如果Rx FIFO读取了最后的数据,就产生中断。

回到s3cmci_send_request函数:

1248行,调用s3cmci_send_command(主机,CMD)发送命令。

该函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 1016static voids3cmci_send_command(struct  s3cmci_host * host,  
  2. 1017                     struct  mmc_command * cmd)  
  3. 1018 {  
  4. 1019 u32 ccon,imsk;  
  5. 1020  
  6. 1021 imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |  
  7. 1022 S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT |  
  8. 1023 S3C2410_SDIIMSK_RESPONSECRC;  
  9. 1024  
  10. 1025 enable_imask(host,imsk);  
  11. 1026  
  12. 1027     if  (cmd-> data)  
  13. 1028 host-> complete_what = COMPLETION_XFERFINISH_RSPFIN;  
  14. 1029     else if  (cmd-> flags&MMC_RSP_PRESENT)   
  15. 1030 host-> complete_what = COMPLETION_RSPFIN;  
  16. 1031     其他  
  17. 1032 host-> complete_what = COMPLETION_CMDSENT;  
  18. 1033  
  19. 1034 writel(cmd-> arg,host-> base + S3C2410_SDICMDARG);  
  20. 1035  
  21. 1036 ccon = cmd-> opcode&S3C2410_SDICMDCON_INDEX;  
  22. 1037 ccon | = S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;  
  23. 1038  
  24. 1039     if  (cmd-> flags&MMC_RSP_PRESENT)  
  25. 1040 ccon | = S3C2410_SDICMDCON_WAITRSP;  
  26. 1041  
  27. 1042     if  (cmd-> flags&MMC_RSP_136)  
  28. 1043 ccon | = S3C2410_SDICMDCON_LONGRSP;  
  29. 1044  
  30. 1045 writel(ccon,host-> base + S3C2410_SDICMDCON);  
  31. 1046}  


一○二一年至1025年行,出现CRC状态错误,命令响应超时,接收命令响应,命令发送,响应CRC校验失败时,将产生SDI中断。

一零二七年至1032年行,设置宿主> complete_what。

在驱动器/ MMC /主机/ s3cmci.h文件中,有如下定义:

[cpp]  查看纯 文本  
  1. 11enum s3cmci_waitfor {  
  2. 12 COMPLETION_NONE,  
  3. 13 COMPLETION_FINALIZE,  
  4. 14 COMPLETION_CMDSENT,  
  5. 15 COMPLETION_RSPFIN,  
  6. 16 COMPLETION_XFERFINISH,  
  7. 17 COMPLETION_XFERFINISH_RSPFIN,  
  8. 18};  


另外,在驱动器/ MMC /主机/ s3cmci.c文件的s3cmci_irq函数的注释中,有如下内容:

[cpp]  查看纯 文本  
  1. 603 * host-> complete_what指示请求何时被认为完成  
  2. 604 * COMPLETION_CMDSENT当命令发送时  
  3. 605 * COMPLETION_RSPFIN当接收到响应  
  4. 606 * COMPLETION_XFERFINISH数据传输完成  
  5. 607 * COMPLETION_XFERFINISH_RSPFIN上述两者。  


1034行,用CMD-> ARG设置设置SDICmdArg寄存器。

1036年至1045年行,配置SDICmdCon寄存器。

1036行,取得命令索引。

1037行,命令启动。

1039年至1040年行,配置主机等待响应。

1042至1043年行,配置主机接收136位长响应。

回到s3cmci_send_request函数:

1251行,使能中断。

至此,s3cmci_send_request函数我们就分析完了。

s3cmci_request函数我们也就分析完了。

s3cmci_ops结构体我们也就分析完了。

 

二,中断处理函数s3cmci_irq分析

SDI中断处理函数s3cmci_irq定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 599 / * 
  2. 600 * ISR用于SDI接口IRQ 
  3. 601 *驱动程序与ISRworks之间的通讯如下: 
  4. 602 * host-> mrq指向电流请求 
  5. 603 * host-> complete_what指示请求何时被认为完成 
  6. 604 * COMPLETION_CMDSENT当命令发送时 
  7. 605 * COMPLETION_RSPFIN当接收到响应 
  8. 606 * COMPLETION_XFERFINISH数据传输完成 
  9. 607 * COMPLETION_XFERFINISH_RSPFIN上述两者。 
  10. 608 * host-> complete_request是驱动程序等待的完成对象 
  11. 609 * 
  12. 610 * 1)驱动程序设置host-> mrq andhost-> complete_what 
  13. 611 * 2)司机准备转移 
  14. 612 * 3)驱动器使能中断 
  15. 613 * 4)驱动程序开始转移 
  16. 614 * 5)驱动程序等待forhost-> complete_rquest 
  17. 615 * 6)ISR检查请求状态(错误和成功) 
  18. 616 * 6)ISR setshost-> mrq-> cmd-> error and host-> mrq-> data-> error 
  19. 617 * 7)ISR completedhost-> complete_request 
  20. 618 * 8)ISR禁止中断 
  21. 619 * 9)司机醒来,照顾好了 
  22. 620 * 
  23. 621 *注意:“ - >错误”-fields在请求之前要设置为0 
  24. 622 *由mmc.c发布 - 因此它们只能设置一个错误 
  25. 623 *争执出现 
  26. 624 * /  
  27. 625  
  28. 626static irqreturn_t s3cmci_irq(int  irq,  void * dev_id)  
  29. 627 {  
  30. 628    struct  s3cmci_host * host = dev_id;  
  31. 629    struct  mmc_command * cmd;  
  32. 630 u32 mci_csta,mci_dsta,mci_fsta,mci_dcnt,mci_imsk;  
  33. 631 u32 mci_cclear = 0,mci_dclear;  
  34. 632 unsigned  long  iflags;  
  35. 633  
  36. 634 mci_dsta = readl(host-> base + S3C2410_SDIDSTA);  
  37. 635 mci_imsk = readl(host-> base + host-> sdiimsk);  
  38. 636  
  39. 637    if  (mci_dsta&S3C2410_SDIDSTA_SDIOIRQDETECT){  
  40. 638        if  (mci_imsk&S3C2410_SDIIMSK_SDIOIRQ){  
  41. 639 mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT;  
  42. 640 writel(mci_dclear,host-> base + S3C2410_SDIDSTA);  
  43. 641  
  44. 642 mmc_signal_sdio_irq(host-> mmc);  
  45. 643            返回 IRQ_HANDLED;  
  46. 644}  
  47. 645}  
  48. 646  
  49. 647 spin_lock_irqsave(&host-> complete_lock,iflags);  
  50. 648  
  51. 649 mci_csta = readl(host-> base + S3C2410_SDICMDSTAT);  
  52. 650 mci_dcnt = readl(host-> base + S3C2410_SDIDCNT);  
  53. 651 mci_fsta = readl(host-> base + S3C2410_SDIFSTA);  
  54. 652 mci_dclear = 0;  
  55. 653  
  56. 654    if  ((host-> complete_what == COMPLETION_NONE)||  
  57. 655(host-> complete_what == COMPLETION_FINALIZE)){  
  58. 656 host-> status =  “nothing to complete” ;  
  59. 657 clear_imask(host);  
  60. 658        goto  irq_out;  
  61. 659}  
  62. 660  
  63. 661    if  (!host-> mrq){  
  64. 662 host-> status =  “no active mrq” ;  
  65. 663 clear_imask(host);  
  66. 664        goto  irq_out;  
  67. 665}  
  68. 666  
  69. 667 cmd = host-> cmd_is_stop?host-> mrq-> stop:host-> mrq-> cmd;  
  70. 668  
  71. 669    if  (!cmd){  
  72. 670 host-> status =  “no active cmd” ;  
  73. 671 clear_imask(host);  
  74. 672        goto  irq_out;  
  75. 673}  
  76. 674  
  77. 675    if  (!s3cmci_host_usedma(host)){  
  78. 676        if  ((host-> pio_active == XFER_WRITE)&&  
  79. 677(mci_fsta&S3C2410_SDIFSTA_TFDET)){  
  80. 678  
  81. 679 disable_imask(host,S3C2410_SDIIMSK_TXFIFOHALF);  
  82. 680 tasklet_schedule(&host-> pio_tasklet);  
  83. 681 host-> status =  “pio tx” ;  
  84. 682}  
  85. 683  
  86. 684        if  ((host-> pio_active == XFER_READ)&&  
  87. 685(mci_fsta&S3C2410_SDIFSTA_RFDET)){  
  88. 686  
  89. 687 disable_imask(host,  
  90. 688 S3C2410_SDIIMSK_RXFIFOHALF |  
  91. 689 S3C2410_SDIIMSK_RXFIFOLAST);  
  92. 690  
  93. 691 tasklet_schedule(&host-> pio_tasklet);  
  94. 692 host-> status =  “pio rx” ;  
  95. 693}  
  96. 694}  
  97. 695  
  98. 696    if  (mci_csta&S3C2410_SDICMDSTAT_CMDTIMEOUT){  
  99. 697 dbg(host,dbg_err,  “CMDSTAT:error CMDTIMEOUT \ n” );  
  100. 698 cmd-> error = -ETIMEDOUT;  
  101. 699 host-> status =  “error:command timeout” ;  
  102. 700        goto  fail_transfer;  
  103. 701}  
  104. 702  
  105. 703    if  (mci_csta&S3C2410_SDICMDSTAT_CMDSENT){  
  106. 704        if  (host-> complete_what == COMPLETION_CMDSENT){  
  107. 705 host-> status =  “ok:command sent” ;  
  108. 706            goto  close_transfer;  
  109. 707}  
  110. 708  
  111. 709 mci_cclear | = S3C2410_SDICMDSTAT_CMDSENT;  
  112. 710}  
  113. 711  
  114. 712    if  (mci_csta&S3C2410_SDICMDSTAT_CRCFAIL){  
  115. 713        if  (cmd-> flags&MMC_RSP_CRC){  
  116. 714            if  (host-> mrq-> cmd-> flags&MMC_RSP_136){  
  117. 715 dbg(host,dbg_irq,  
  118. 716                     “fixup:忽略具有长rsp \ n的CRCfail” );  
  119. 717}  else  {  
  120. 718                 / *注意,我们以前是转载失败 
  121. 719 *在这里,但似乎这只是 
  122. 720 *硬件得到它。 
  123. 721 * 
  124. 722 * cmd-> error = -EILSEQ; 
  125. 723 * host-> status =“error:bad command crc”; 
  126. 724 * goto fail_transfer; 
  127. 725 * /  
  128. 726}  
  129. 727}  
  130. 728  
  131. 729 mci_cclear | = S3C2410_SDICMDSTAT_CRCFAIL;  
  132. 730}  
  133. 731  
  134. 732     if  (mci_csta&S3C2410_SDICMDSTAT_RSPFIN){  
  135. 733        if  (host-> complete_what == COMPLETION_RSPFIN){  
  136. 734 host-> status =  “ok:收到命令响应” ;  
  137. 735            goto  close_transfer;  
  138. 736}  
  139. 737  
  140. 738        if  (host-> complete_what == COMPLETION_XFERFINISH_RSPFIN)  
  141. 739 host-> complete_what = COMPLETION_XFERFINISH;  
  142. 740  
  143. 741 mci_cclear | = S3C2410_SDICMDSTAT_RSPFIN;  
  144. 742}  
  145. 743  
  146. 744    / *之后处理的错误只是相关的 
  147. 745当数据传输正在进行时* /  
  148. 746  
  149. 747    if  (!cmd-> data)  
  150. 748        goto  clear_status_bits;  
  151. 749  
  152. 750    / *检查FIFO故障* /  
  153. 751    if  (host-> is2440){  
  154. 752        if  (mci_fsta&S3C2440_SDIFSTA_FIFOFAIL){  
  155. 753 dbg(host,dbg_err,  “FIFO failure \ n” );  
  156. 754 host-> mrq-> data-> error = -EILSEQ;  
  157. 755 host-> status =  “error:2440 fifo failure” ;  
  158. 756            goto  fail_transfer;  
  159. 757}  
  160. 758} else  {  
  161. 759        if  (mci_dsta&S3C2410_SDIDSTA_FIFOFAIL){  
  162. 760 dbg(host,dbg_err,  “FIFOfailure \ n” );  
  163. 761 cmd-> data-> error = -EILSEQ;  
  164. 762 host-> status =  “error:fifo failure” ;  
  165. 763            goto  fail_transfer;  
  166. 764}  
  167. 765}  
  168. 766  
  169. 767    if  (mci_dsta&S3C2410_SDIDSTA_RXCRCFAIL){  
  170. 768 dbg(host,dbg_err,  “bad data crc(outgoing)\ n” );  
  171. 769 cmd-> data-> error = -EILSEQ;  
  172. 770 host-> status =  “error:bad data crc(outgoing)” ;  
  173. 771        goto  fail_transfer;  
  174. 772}  
  175. 773  
  176. 774    if  (mci_dsta&S3C2410_SDIDSTA_CRCFAIL){  
  177. 775 dbg(host,dbg_err,  “bad data crc(incoming)\ n” );  
  178. 776 cmd-> data-> error = -EILSEQ;  
  179. 777 host-> status =  “error:bad data crc(incoming)” ;  
  180. 778        goto  fail_transfer;  
  181. 779}  
  182. 780  
  183. 781    if  (mci_dsta&S3C2410_SDIDSTA_DATATIMEOUT){  
  184. 782 dbg(host,dbg_err,  “data timeout \ n” );  
  185. 783 cmd-> data-> error = -ETIMEDOUT;  
  186. 784 host-> status =  “error:data timeout” ;  
  187. 785        goto  fail_transfer;  
  188. 786}  
  189. 787  
  190. 788    if  (mci_dsta&S3C2410_SDIDSTA_XFERFINISH){  
  191. 789        if  (host-> complete_what == COMPLETION_XFERFINISH){  
  192. 790 host-> status =  “ok:data transfer completed” ;  
  193. 791            goto  close_transfer;  
  194. 792}  
  195. 793  
  196. 794        if  (host-> complete_what == COMPLETION_XFERFINISH_RSPFIN)  
  197. 795 host-> complete_what = COMPLETION_RSPFIN;  
  198. 796  
  199. 797 mci_dclear | = S3C2410_SDIDSTA_XFERFINISH;  
  200. 798}  
  201. 799  
  202. 800clear_status_bits:  
  203. 801 writel(mci_cclear,host-> base + S3C2410_SDICMDSTAT);  
  204. 802 writel(mci_dclear,host-> base + S3C2410_SDIDSTA);  
  205. 803  
  206. 804    goto  irq_out;  
  207. 805  
  208. 806fail_transfer:  
  209. 807 host-> pio_active = XFER_NONE;  
  210. 808  
  211. 809close_transfer:  
  212. 810 host-> complete_what = COMPLETION_FINALIZE;  
  213. 811  
  214. 812 clear_imask(host);  
  215. 813 tasklet_schedule(&host-> pio_tasklet);  
  216. 814  
  217. 815    goto  irq_out;  
  218. 816  
  219. 817irq_out:  
  220. 818 dbg(host,dbg_irq,  
  221. 819        “CSTA:0X%08X DSTA:0X%08X FSTA:0X%08X DCNT:0X%08xstatus:%S \ n”个,  
  222. 820 mci_csta,mci_dsta,mci_fsta,mci_dcnt,host-> status);  
  223. 821  
  224. 822 spin_unlock_irqrestore(&host-> complete_lock,iflags);  
  225. 823    返回 IRQ_HANDLED;  
  226. 824  
  227. 825}  


在分析这个函数之前,请先看一下599-624行的注释。

628行,的dev_id是中断处理函数传递过来的structs3cmci_host指针。

634行,读取SDIDatSta寄存器,保存在mci_dsta变量中。

635行,读取SDIIntMsk寄存器,保存在mci_imsk变量中。

637行,S3C2410_SDIDSTA_SDIOIRQDETECT宏标志着SDIDatSta寄存器的第9位被置位,说明有SDIO中断被检测到。

638行,S3C2410_SDIIMSK_SDIOIRQ宏标志着SDIIntMsk寄存器的第12位被置位,表示使能SDI产生SDIO中断。

行639-640,根据数据表,这两句的作用是清零SDIDatSta寄存器的第9位。

642行,调用mmc_signal_sdio_irq函数处理SDIO中断,该函数定义在包括/ LINUX / MMC / host.h文件中:

[cpp]  查看纯 文本  
  1. 396static inlinevoid mmc_signal_sdio_irq(struct  mmc_host * host)  
  2. 397 {  
  3. 398 host-> ops-> enable_sdio_irq(host,0);  
  4. 399 host-> sdio_irq_pending =  true ;  
  5. 400 wake_up_process(host-> sdio_irq_thread);  
  6. 401}  


649行,读取SDICmdSta寄存器,保存在mci_csta变量中。

650行,读取SDIDatCnt寄存器,保存在mci_dcnt变量中。

651行,读取SDIFSTA寄存器,保存在mci_fsta变量中。

654-665行,做一些检查工作。

667行,设置CMD。

675-694行,如果没有使用DMA,则执行这个如果分支。

676-677行,如果宿主> pio_active为XFER_WRITE,并且SDIFSTA寄存器的第13位被置位,表明FIFO可以用于写操作。

679行,禁用TFHalf中断。

680行,调用主机 - > pio_tasklet。

681行,设置主机 - >状态为 “piotx”。

684-685行,如果宿主> pio_active为XFER_READ,并且SDIFSTA寄存器的第12位被置位,表明FIFO可以用于读操作。

687-689行,禁用Rx FIFO相关中断。

691行,调用主机 - > pio_tasklet。

692行,设置主机 - >状态为 “piorx”。

696-701行,处理命令超时。

703-710行,命令发送完成(不论是否得到应答)。

712-730行,处理CRC校验错误。

732-742行,处理收到命令应答。

750-798行,处理数据传输相关错误。

751-765行,处理FIFO相关错误。

767-772行,处理读数据CRC校验错误。

774-779行,处理发送数据时CRC校验错误。

781-786行,处理数据超时。

788-798行,处理数据传输结束。

下面我们来看宿主> pio_tasklet,在s3cmci_probe函数中,有如下语句:

1662 tasklet_init(&host-> pio_tasklet,pio_tasklet,(unsigned long)host);

可以看到,宿主> pio_tasklet对应的微进程函数为pio_tasklet,并将主机做为参数传递给该函数.pio_tasklet函数定义在驱动/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 569static  void  pio_tasklet(unsigned  long  data)  
  2. 570 {  
  3. 571    struct  s3cmci_host * host =(struct  s3cmci_host *)数据;  
  4. 572  
  5. 573 s3cmci_disable_irq(host,  true );  
  6. 574  
  7. 575    if  (host-> pio_active == XFER_WRITE)  
  8. 576 do_pio_write(host);  
  9. 577  
  10. 578    if  (host-> pio_active == XFER_READ)  
  11. 579 do_pio_read(host);  
  12. 580  
  13. 581    if  (host-> complete_what == COMPLETION_FINALIZE){  
  14. 582 clear_imask(host);  
  15. 583        if  (host-> pio_active!= XFER_NONE){  
  16. 584 dbg(host,dbg_err,  “未完成%s”  
  17. 585                 “ - pio_count:[%u] pio_bytes:[%u] \ n” ,  
  18. 586(host-> pio_active == XFER_READ)? “读”  :  “写” ,  
  19. 587 host-> pio_count,host-> pio_bytes);  
  20. 588  
  21. 589            if  (host-> mrq-> data)  
  22. 590 host-> mrq-> data-> error = -EINVAL;  
  23. 591}  
  24. 592  
  25. 593 s3cmci_enable_irq(host,  false );  
  26. 594 finalize_request(host);  
  27. 595} else  
  28. 596 s3cmci_enable_irq(host,  true );  
  29. 597}  


575-576行,如果宿主> pio_active为XFER_WRITE,即写数据,则调用do_pio_write(主机)函数,该函数我们前面已经分析过了。

578-579行,如果宿主> pio_active为XFER_READ,即读数据,则调用do_pio_read(主机)函数,该函数定义在驱动/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 437static  void  do_pio_read(struct  s3cmci_host * host)  
  2. 438 {  
  3. 439    int  res  
  4. 440 u32 fifo;  
  5. 441 u32 * ptr;  
  6. 442 u32 fifo_words;  
  7. 443    void  __iomem * from_ptr;  
  8. 444  
  9. 445    / *写真实的预分频器到主机,它可能设置缓慢修复* /  
  10. 446 writel(host->预分频器,host-> base + S3C2410_SDIPRE);  
  11. 447  
  12. 448 from_ptr = host-> base + host-> sdidata;  
  13. 449  
  14. 450     ((FIFO = fifo_count(主机))){  
  15. 451        if  (!host-> pio_bytes){  
  16. 452 res = get_data_buffer(host,&host-> pio_bytes,  
  17. 453&host-> pio_ptr);  
  18. 454            if  (res){  
  19. 455 host-> pio_active = XFER_NONE;  
  20. 456 host-> complete_what = COMPLETION_FINALIZE;  
  21. 457  
  22. 458 dbg(host,dbg_pio,“pio_read():”  
  23. 459                     “complete(no moredata)。\ n” );  
  24. 460                 ;  
  25. 461}  
  26. 462  
  27. 463 dbg(host,dbg_pio,  
  28. 464                 “pio_read():new target:[%i] @ [%p] \ n” ,  
  29. 465 host-> pio_bytes,host-> pio_ptr);  
  30. 466}  
  31. 467  
  32. 468 dbg(host,dbg_pio,  
  33. 469            “pio_read():FIFO:[%02i]缓冲液:[%03i] DCNT:[%08X] \ n”个,  
  34. 470 fifo,host-> pio_bytes,  
  35. 471 readl(host-> base + S3C2410_SDIDCNT));  
  36. 472  
  37. 473        / *如果我们到了最后的块,我们可以 
  38. 474 *读一个字,得到1到3个字节。如果我们在 
  39. 475 *中间的块,我们必须阅读全文, 
  40. 476 *否则我们会写垃圾,这样一来就可以了 
  41. 477 *甚至倍数4. * /  
  42. 478        if  (fifo> = host-> pio_bytes)  
  43. 479 fifo = host-> pio_bytes;  
  44. 480        其他  
  45. 481 fifo - = fifo&3;  
  46. 482  
  47. 483 host-> pio_bytes - = fifo;  
  48. 484 host-> pio_count + = fifo;  
  49. 485  
  50. 486 fifo_words = fifo >> 2;  
  51. 487 ptr = host-> pio_ptr;  
  52. 488         (fifo_words--)  
  53. 489 * ptr ++ = readl(from_ptr);  
  54. 490 host-> pio_ptr = ptr;  
  55. 491  
  56. 492        if  (fifo&3){  
  57. 493 u32 n = fifo&3;  
  58. 494 u32 data = readl(from_ptr);  
  59. 495 u8 * p =(u8 *)host-> pio_ptr;  
  60. 496  
  61. 497             (N--){  
  62. 498 * p ++ = data;  
  63. 499数据>> = 8;  
  64. 500}  
  65. 501}  
  66. 502}  
  67. 503  
  68. 504    if  (!host-> pio_bytes){  
  69. 505 res = get_data_buffer(host,&host-> pio_bytes,&host-> pio_ptr);  
  70. 506        if  (res){  
  71. 507 dbg(host,dbg_pio,  
  72. 508                “pio_read():complete(no more buffers)。\ n” );  
  73. 509 host-> pio_active = XFER_NONE;  
  74. 510 host-> complete_what = COMPLETION_FINALIZE;  
  75. 511  
  76. 512            ;  
  77. 513}  
  78. 514}  
  79. 515  
  80. 516 enable_imask(host,  
  81. 517 S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST);  
  82. 518}  


446行,设置波特率预分频器寄存器SDIPRE。

448行,将SDI数据寄存器SDIDAT的虚拟地址保存在from_ptr变量中。

450行,调用fifo_count得到FIFO中可读取数据的字节数,保存在FIFO变量中。

451-466行,调用get_data_buffer函数,从分散聚集列表中获取用于存放被读取数据的缓冲区的相关信息,缓冲区的长度保存在主机 - > pio_bytes中,缓冲区的起始地址保存在主机 - > pio_ptr中如果get_data_buffer函数返回非0值,表示读操作完成。

478-481行,如果FIFO中可读取数据的字节数大于host-> pio_bytes(即缓冲区的大小),则将fifo设置为host-> pio_bytes,否则fifo - = fifo&3.从473- 477行的注释可以看出,这样做是为了按字来读取数据。

483行,修改主机 - > pio_bytes的值,缓冲区还有多少字节的空间。

484行,已经读取的数据的字节数保存在主机 - > pio_count变量中。

486行,以字为单位,要读取的数据个数保存在fifo_words变量中。

488-489行,循环读取数据。

490行,保存下次要读取的数据的起始位置到宿主> pio_ptr中。

492-501行,读取剩余的非字节对齐部分。

502行,结束这次而循环,回到450行,判断FIFO中是否还有可读的数据,如果有的话,继续进行读取操作。

504-514行,如果宿主> pio_bytes为0,并且get_data_buffer函数返回非0值,表示没有可用的缓冲区空间,读结束。

516-517行,便能读取中断。

至此,do_pio_read函数我们就分析完了。

回到pio_tasklet函数:

581-596行,如果命令处理结束,则调用finalize_request进行最后的处理否则,打开中断,继续监听中断.finalize_request函数定义在驱动程序/ MMC /主机/ s3cmci.c文件中:

[cpp]  查看纯 文本  
  1. 898static  void  finalize_request(structs3cmci_host * host)  
  2. 899 {  
  3. 900    struct  mmc_request * mrq = host-> mrq;  
  4. 901    struct  mmc_command * cmd;  
  5. 902 intdebug_as_failure = 0;  
  6. 903  
  7. 904    if  (host-> complete_what!= COMPLETION_FINALIZE)  
  8. 905        ;  
  9. 906  
  10. 907    if  (!mrq)  
  11. 908        ;  
  12. 909 cmd = host-> cmd_is_stop?mrq-> stop:mrq-> cmd;  
  13. 910  
  14. 911    if  (cmd-> data &&(cmd-> error == 0)&&  
  15. 912(cmd-> data-> error == 0)){  
  16. 913        if  (s3cmci_host_usedma(host)&&(!host-> dma_complete)){  
  17. 914 dbg(host,dbg_dma,  “DMA Missing(%d)!\ n” ,  
  18. 915 host-> dma_complete);  
  19. 916            ;  
  20. 917}  
  21. 918}  
  22. 919  
  23. 920    / *从控制器读取响应。* /  
  24. 921 cmd-> resp [0] = readl(host-> base + S3C2410_SDIRSP0);  
  25. 922 cmd-> resp [1] = readl(host-> base + S3C2410_SDIRSP1);  
  26. 923 cmd-> resp [2] = readl(host-> base + S3C2410_SDIRSP2);  
  27. 924 cmd-> resp [3] = readl(host-> base + S3C2410_SDIRSP3);  
  28. 925  
  29. 926 writel(host->预分频器,host-> base + S3C2410_SDIPRE);  
  30. 927  
  31. 928    if  (cmd-> error)  
  32. 929 debug_as_failure = 1;  
  33. 930  
  34. 931    if  (cmd-> data && cmd-> data-> error)  
  35. 932 debug_as_failure = 1;  
  36. 933  
  37. 934 dbg_dumpcmd(host,cmd,debug_as_failure);  
  38. 935  
  39. 936    / *清理控制器* /  
  40. 937 writel(0,host-> base + S3C2410_SDICMDARG);  
  41. 938 writel(S3C2410_SDIDCON_STOP,host-> base + S3C2410_SDIDCON);  
  42. 939 writel(0,host-> base + S3C2410_SDICMDCON);  
  43. 940 clear_imask(host);  
  44. 941  
  45. 942    if  (cmd-> data && cmd-> error)  
  46. 943 cmd-> data-> error = cmd-> error;  
  47. 944  
  48. 945    if  (cmd-> data && cmd-> data-> stop &&(!host-> cmd_is_stop)){  
  49. 946 host-> cmd_is_stop = 1;  
  50. 947 s3cmci_send_request(host-> mmc);  
  51. 948        ;  
  52. 949}  
  53. 950  
  54. 951    / *如果我们没有数据传输,我们在这里完成* /  
  55. 952    if  (!mrq-> data)  
  56. 953        goto  request_done;  
  57. 954  
  58. 955    / *如果没有错误,则计算字节传输的数量* /  
  59. 956    if  (mrq-> data-> error == 0){  
  60. 957 mrq-> data-> bytes_xfered =  
  61. 958(mrq-> data-> blocks * mrq-> data-> blksz);  
  62. 959} else  {  
  63. 960 mrq-> data-> bytes_xfered = 0;  
  64. 961}  
  65. 962  
  66. 963    / *如果我们在传输数据时发生错误,我们刷新 
  67. 964 * DMA通道和fifo清除任何垃圾。* /  
  68. 965    if  (mrq-> data-> error!= 0){  
  69. 966        if  (s3cmci_host_usedma(host))  
  70. 967 s3c2410_dma_ctrl(host-> dma,S3C2410_DMAOP_FLUSH);  
  71. 968  
  72. 969        if  (host-> is2440){  
  73. 970            / *清除故障寄存器并复位fifo。* /  
  74. 971 writel(S3C2440_SDIFSTA_FIFORESET |  
  75. 972 S3C2440_SDIFSTA_FIFOFAIL,  
  76. 973 host-> base + S3C2410_SDIFSTA);  
  77. 974}  else  {  
  78. 975 u32 mci_con;  
  79. 976  
  80. 977            / * reset fifo * /  
  81. 978 mci_con = readl(host-> base + S3C2410_SDICON);  
  82. 979 mci_con | = S3C2410_SDICON_FIFORESET;  
  83. 980  
  84. 981 writel(mci_con,host-> base + S3C2410_SDICON);  
  85. 982}  
  86. 983}  
  87. 984  
  88. 985request_done:  
  89. 986 host-> complete_what = COMPLETION_NONE;  
  90. 987 host-> mrq = NULL;  
  91. 988  
  92. 989 s3cmci_check_sdio_irq(host);  
  93. 990 mmc_request_done(host-> mmc,mrq);  
  94. 991}  


920-924行,读取SDIRSP0 -SDIRSP3寄存器,保存在cmd-> resp中。

926行,将宿主>预分频器写入SDIPRE寄存器。

937行,清零SDICmdArg寄存器。

938行,清零SDIDatCon寄存器,除了第14位设置为1,表示启动数据传输。

939行,清零SDICmdCon寄存器。

940行,清零SDIIntMsk寄存器,只允许SDIO中断。

945-949行,发送停止命令。

955-961行,计算传输的字节总数。

965-983行,如果数据传输过程出错,刷新DMA通道和FIFO,清除垃圾数据。

至此,finalize_request函数我们就分析完了,pio_tasklet函数我们也就分析完了,同时中断处理函数s3cmci_irq函数我们也就分析完了。

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 点我我会动 设计师:白松林 返回首页