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

2023-10-23 23:20

本文主要是介绍Linux设备驱动程序架构分析之MMC/SD(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

内核版本:3.10.1

 

MMC

MMC全称MultiMedia Card,由西门子公司和SanDisk公司1997年推出的多媒体记忆卡标准。MMC卡尺寸为32mm x24mm x 1.4mm,它将存贮单元和控制器一同做到了卡上,智能的控制器使得MMC保证兼容性和灵活性。

MMC卡具有MMC和SPI两种工作模式,MMC模式是默认工作模式,具有MMC的全部特性。而SPI模式则是MMC协议的一个子集,主要用于低速系统。

 

SD

SD卡全称Secure DigitalMemory Card,由松下、东芝和SanDisk公司于1999年8月共同开发的新一代记忆卡标准,已完全兼容MMC标准。SD卡比MMC卡多了一个进行数据著作权保护的暗号认证功能,读写速度比MMC卡快4倍。

SD卡尺寸为32mm x 24mm x2.1mm,长宽和MMC卡一样,只是比MMC卡厚了0.7mm,以容纳更大容量的存贮单元。SD卡与MMC卡保持向上兼容,也就是说,MMC卡可以被新的设有SD卡插槽的设备存取,但是SD卡却不可以被设有MMC插槽的设备存取。

 

SDIO

SDIO全称Secure DigitalInput and Output Card,SDIO是在SD标准上定义了一种外设接口,它使用SD的I/O接口来连接外围设备,并通过SD上的I/O数据接口与这些外围设备传输数据。现在已经有很多手持设备支持SDIO功能,而且许多SDIO外设也被开发出来,目前常见的SDIO外设有:WIFI Card、GPS Card、 Bluetooth Card等等。

 

eMMC

eMMC全称Embedded MultiMediaCard,是MMC协会所制定的内嵌式存储器标准规格,主要应用于智能手机和移动嵌入式产品等。eMMC是一种嵌入式非易失性存储系统,由闪存和闪存控制器两部分组成,它的一个明显优势是在封装中集成了一个闪存控制器,它采用JEDEC标准BGA封装,并采用统一闪存接口管理闪存。

eMMC结构由一个嵌入式存储解决方案组成,带有MMC接口、快闪存储设备及主控制器,所有这些由一个小型BGA封装。由于采用标准封装,eMMC也很容易升级,并不用改变硬件结构。

eMMC的这种将Nand Flash芯片和控制芯片封装在一起的设计概念,就是为了简化产品内存储器的使用,客户只需要采购eMMC芯片放进产品中,不需要处理其它复杂的Nand Flash兼容性和管理问题,减少研发成本和研发周期。

 

下面我们以Mini2440为例,分析其SDI驱动程序。

Mini2440 MMC/SD硬件接口电路原理图如下:


从Mini2440原理图可以看出,Mini2440 SDI使用的GPE7-GPE10作为4根数据信号线,使用GPE6作为命令信号线,使用GPE5作为时钟信号线。另外,使用GPG8的外部中断功能来作SD卡的插拨检测,使用GPH8来判断SD卡是否有写保护。

 

一、SDI设备的注册

先来看device注册过程,在arch/arm/mach-s3c24xx/mach-mini2440.c文件中,有如下内容:

[cpp]  view plain copy
  1. 505static struct platform_device*mini2440_devices[] __initdata = {  
  2. 506   &s3c_device_ohci,  
  3. 507   &s3c_device_wdt,  
  4. 508   &s3c_device_i2c0,  
  5. 509   &s3c_device_rtc,  
  6. 510   &s3c_device_usbgadget,  
  7. 511   &mini2440_device_eth,  
  8. 512   &mini2440_led1,  
  9. 513   &mini2440_led2,  
  10. 514   &mini2440_led3,  
  11. 515   &mini2440_led4,  
  12. 516   &mini2440_button_device,  
  13. 517   &s3c_device_nand,  
  14. 518   &s3c_device_sdi,  
  15. 519   &s3c_device_iis,  
  16. 520   &uda1340_codec,  
  17. 521   &mini2440_audio,  
  18. 522};  


这里定义了Mini2440所有的platform device,这里,我们要关注的是s3c_device_sdi,它是Mini2440的SDI控制器。

s3c_device_sdi定义在arch/arm/plat-samsung/devs.c文件中:

[cpp]  view plain copy
  1. 1172struct platform_device s3c_device_sdi ={  
  2. 1173   .name       ="s3c2410-sdi",  
  3. 1174   .id     = -1,  
  4. 1175   .num_resources  =ARRAY_SIZE(s3c_sdi_resource),  
  5. 1176   .resource   = s3c_sdi_resource,  
  6. 1177};  


回忆一下platform_device定义在include/linux/platform_device.h文件中:

[cpp]  view plain copy
  1. 22structplatform_device {  
  2. 23   const char  *name;  
  3. 24   int     id;  
  4. 25   bool        id_auto;  
  5. 26   struct device   dev;  
  6. 27   u32     num_resources;  
  7. 28   struct resource *resource;  
  8. 29  
  9. 30   const struct platform_device_id *id_entry;  
  10. 31  
  11. 32    /*MFD cell pointer */  
  12. 33   struct mfd_cell *mfd_cell;  
  13. 34  
  14. 35    /*arch specific additions */  
  15. 36   struct pdev_archdata    archdata;  
  16. 37};  


其中,s3c_sdi_resource定义在arch/arm/plat-samsung/devs.c文件中:

[cpp]  view plain copy
  1. 1167static struct resources3c_sdi_resource[] = {  
  2. 1168   [0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI),  
  3. 1169   [1] = DEFINE_RES_IRQ(IRQ_SDI),  
  4. 1170};  


struct resource定义在include/linux/ioport.h文件中:

[cpp]  view plain copy
  1. 14/* 
  2. 15 *Resources are tree-like, allowing 
  3. 16 *nesting etc.. 
  4. 17*/  
  5. 18structresource {  
  6. 19   resource_size_t start;  
  7. 20   resource_size_t end;  
  8. 21   const char *name;  
  9. 22   unsigned long flags;  
  10. 23   struct resource *parent, *sibling, *child;  
  11. 24};  


宏DEFINE_RES_MEM定义在include/linux/ioport.h文件中:

[cpp]  view plain copy
  1. 124#define DEFINE_RES_MEM(_start,_size)                   \  
  2. 125   DEFINE_RES_MEM_NAMED((_start), (_size), NULL)  
  3. ……  
  4. 122#define DEFINE_RES_MEM_NAMED(_start,_size, _name)          \  
  5. 123   DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_MEM)  
  6. ……  
  7. 109#define DEFINE_RES_NAMED(_start, _size,_name, _flags)          \  
  8. 110   {                               \  
  9. 111       .start = (_start),                 \  
  10. 112       .end = (_start) + (_size) - 1,              \  
  11. 113       .name = (_name),                   \  
  12. 114       .flags = (_flags),                 \  
  13. 115   }  


宏DEFINE_RES_IRQ宏定义在include/linux/ioport.h文件中:

[cpp]  view plain copy
  1. 129#define DEFINE_RES_IRQ(_irq)                        \  
  2. 130   DEFINE_RES_IRQ_NAMED((_irq), NULL)  
  3. ……  
  4. 127#define DEFINE_RES_IRQ_NAMED(_irq,_name)               \  
  5. 128   DEFINE_RES_NAMED((_irq), 1, (_name), IORESOURCE_IRQ)  
  6. ……  
  7. 109#define DEFINE_RES_NAMED(_start, _size,_name, _flags)          \  
  8. 110   {                               \  
  9. 111       .start = (_start),                 \  
  10. 112       .end = (_start) + (_size) - 1,              \  
  11. 113       .name = (_name),                   \  
  12. 114       .flags = (_flags),                  \  
  13. 115   }  


宏S3C24XX_PA_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:

[cpp]  view plain copy
  1. 155#define S3C24XX_PA_SDI      S3C2410_PA_SDI  


宏S3C2410_PA_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:

[cpp]  view plain copy
  1. 105#define S3C2410_PA_SDI     (0x5A000000)  


0x5A000000是S3C2440 SDICON寄存器的地址。

宏S3C24XX_SZ_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:

[cpp]  view plain copy
  1. 61#define S3C24XX_SZ_SDI      SZ_1M  


宏SZ_1M定义在include/linux/sizes.h文件中:

[cpp]  view plain copy
  1. 33#define SZ_1M               0x00100000  


宏IRQ_SDI定义在arch/arm/mach-s3c24xx/include/mach/irqs.h文件中:

[cpp]  view plain copy
  1. 48#define IRQ_SDI        S3C2410_IRQ(21)  
  2. ……  
  3. 23#define S3C2410_IRQ(x) ((x) +S3C2410_CPUIRQ_OFFSET)  
  4. ……  
  5. 21#define S3C2410_CPUIRQ_OFFSET    (16)  


至此,我们知道了Mini2440的platform_device s3c_device_sdi的定义,下面就是要注册这个平台设备,在arch/arm/mach-s3c24xx/mach-mini2440.c文件中:

[cpp]  view plain copy
  1. 622static void __init mini2440_init(void)  
  2. {  
  3.           ……  
  4. 678  platform_add_devices(mini2440_devices,ARRAY_SIZE(mini2440_devices));  
  5.           ……  
  6. }  


platform_add_devices定义在drivers/base/platform.c文件中:

[cpp]  view plain copy
  1. 139/** 
  2.  140* platform_add_devices - add a numbers of platform devices 
  3.  141* @devs: array of platform devices to add 
  4.  142* @num: number of platform devices in array 
  5.  143*/  
  6.  144int platform_add_devices(structplatform_device **devs, int num)  
  7.  145{  
  8.  146   int i, ret = 0;  
  9.  147  
  10.  148   for (i = 0; i < num; i++) {  
  11.  149       ret = platform_device_register(devs[i]);  
  12.  150       if (ret) {  
  13.  151           while (--i >= 0)  
  14.  152               platform_device_unregister(devs[i]);  
  15.  153           break;  
  16.  154       }  
  17.  155    }  
  18.  156  
  19.  157   return ret;  
  20.  158}  


149行,通过调用platform_device_register完成对平台设备的注册,其中包括s3c_device_sdi。

 

二、SDI驱动分析

Mini2440的SDI驱动定义在drivers/mmc/host/s3cmci.c文件中:

[cpp]  view plain copy
  1. 1980static struct platform_drivers3cmci_driver = {  
  2. 1981   .driver = {  
  3. 1982       .name   = "s3c-sdi",  
  4. 1983       .owner  = THIS_MODULE,  
  5. 1984       .pm = s3cmci_pm_ops,  
  6. 1985   },  
  7. 1986   .id_table   = s3cmci_driver_ids,  
  8. 1987   .probe      = s3cmci_probe,  
  9. 1988   .remove     = s3cmci_remove,  
  10. 1989   .shutdown   = s3cmci_shutdown,  
  11. 1990};  


s3cmci_driver_ids定义在drivers/mmc/host/s3cmci.c文件中:

[cpp]  view plain copy
  1. 1936static struct platform_device_ids3cmci_driver_ids[] = {  
  2. 1937   {  
  3. 1938       .name   = "s3c2410-sdi",  
  4. 1939       .driver_data    = 0,  
  5. 1940   }, {  
  6. 1941       .name   = "s3c2412-sdi",  
  7. 1942       .driver_data    = 1,  
  8. 1943   }, {  
  9. 1944       .name   = "s3c2440-sdi",  
  10. 1945       .driver_data    = 1,  
  11. 1946   },  
  12. 1947   { }  
  13. 1948};  


我们来看platform_driver s3cmci_driver 的注册,在drivers/mmc/host/s3cmci.c文件中:

[cpp]  view plain copy
  1. 1992module_platform_driver(s3cmci_driver);  


module_platform_driver是一个宏,定义在include/linux/platform_device.h文件中:

[cpp]  view plain copy
  1. 203/* module_platform_driver() - Helpermacro for drivers that don't do 
  2. 204 * anything special in moduleinit/exit.  This eliminates a lot of 
  3. 205 * boilerplate.  Each module may only use this macro once, and 
  4. 206 * calling it replaces module_init() andmodule_exit() 
  5. 207 */  
  6. 208#definemodule_platform_driver(__platform_driver) \  
  7. 209   module_driver(__platform_driver, platform_driver_register, \  
  8. 210            platform_driver_unregister)  


宏module_driver定义在include/linux/device.h文件中,其内容如下:

[cpp]  view plain copy
  1. 1108/** 
  2. 1109 * module_driver() - Helper macro fordrivers that don't do anything 
  3. 1110 * special in module init/exit. Thiseliminates a lot of boilerplate. 
  4. 1111 * Each module may only use this macroonce, and calling it replaces 
  5. 1112 * module_init() and module_exit(). 
  6. 1113 * 
  7. 1114 * @__driver: driver name 
  8. 1115 * @__register: register function forthis driver type 
  9. 1116 * @__unregister: unregister functionfor this driver type 
  10. 1117 * @...: Additional arguments to bepassed to __register and __unregister. 
  11. 1118 * 
  12. 1119 * Use this macro to construct busspecific macros for registering 
  13. 1120 * drivers, and do not use it on itsown. 
  14. 1121 */  
  15. 1122#define module_driver(__driver,__register, __unregister, ...) \  
  16. 1123static int __init __driver##_init(void)\  
  17. 1124{ \  
  18. 1125   return __register(&(__driver) , ##__VA_ARGS__); \  
  19. 1126} \  
  20. 1127module_init(__driver##_init); \  
  21. 1128static void __exit__driver##_exit(void) \  
  22. 1129{ \  
  23. 1130    __unregister(&(__driver) ,##__VA_ARGS__); \  
  24. 1131} \  
  25. 1132module_exit(__driver##_exit);  


我们知道,注册s3cmci_driver的过程中,会触发s3cmci_probe函数的执行,所以先来看s3cmci_probe函数,它定义在drivers/mmc/host/s3cmci.c文件中,其内容如下:

[cpp]  view plain copy
  1. 1622static int s3cmci_probe(structplatform_device *pdev)  
  2. 1623{  
  3. 1624   struct s3cmci_host *host;  
  4. 1625   struct mmc_host *mmc;  
  5. 1626   int ret;  
  6. 1627   int is2440;  
  7. 1628   int i;  
  8. 1629  
  9. 1630   is2440 = platform_get_device_id(pdev)->driver_data;  
  10. 1631  
  11. 1632   mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);  
  12. 1633   if (!mmc) {  
  13. 1634       ret = -ENOMEM;  
  14. 1635       goto probe_out;  
  15. 1636   }  
  16. 1637  
  17. 1638   for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) {  
  18. 1639       ret = gpio_request(i, dev_name(&pdev->dev));  
  19. 1640       if (ret) {  
  20. 1641            dev_err(&pdev->dev,"failed to get gpio %d\n", i);  
  21. 1642  
  22. 1643            for (i--; i >= S3C2410_GPE(5);i--)  
  23. 1644                gpio_free(i);  
  24. 1645  
  25. 1646            goto probe_free_host;  
  26. 1647       }  
  27. 1648   }  
  28. 1649  
  29. 1650   host = mmc_priv(mmc);  
  30. 1651   host->mmc   = mmc;  
  31. 1652   host->pdev  = pdev;  
  32. 1653   host->is2440    = is2440;  
  33. 1654  
  34. 1655   host->pdata = pdev->dev.platform_data;  
  35. 1656   if (!host->pdata) {  
  36. 1657       pdev->dev.platform_data = &s3cmci_def_pdata;  
  37. 1658       host->pdata = &s3cmci_def_pdata;  
  38. 1659   }  
  39. 1660  
  40. 1661   spin_lock_init(&host->complete_lock);  
  41. 1662   tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long)host);  
  42. 1663  
  43. 1664   if (is2440) {  
  44. 1665       host->sdiimsk   =S3C2440_SDIIMSK;  
  45. 1666       host->sdidata   =S3C2440_SDIDATA;  
  46. 1667       host->clk_div   = 1;  
  47. 1668   } else {  
  48. 1669       host->sdiimsk   =S3C2410_SDIIMSK;  
  49. 1670       host->sdidata   =S3C2410_SDIDATA;  
  50. 1671       host->clk_div   = 2;  
  51. 1672   }  
  52. 1673  
  53. 1674   host->complete_what     =COMPLETION_NONE;  
  54. 1675   host->pio_active    =XFER_NONE;  
  55. 1676  
  56. 1677#ifdef CONFIG_MMC_S3C_PIODMA  
  57. 1678   host->dodma     =host->pdata->use_dma;  
  58. 1679#endif  
  59. 1680  
  60. 1681   host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  61. 1682   if (!host->mem) {  
  62. 1683       dev_err(&pdev->dev,  
  63. 1684           "failed to get io memoryregion resource.\n");  
  64. 1685  
  65. 1686       ret = -ENOENT;  
  66. 1687       goto probe_free_gpio;  
  67. 1688   }  
  68. 1689  
  69. 1690   host->mem = request_mem_region(host->mem->start,  
  70. 1691                      resource_size(host->mem), pdev->name);  
  71. 1692  
  72. 1693   if (!host->mem) {  
  73. 1694       dev_err(&pdev->dev, "failed to request io memoryregion.\n");  
  74. 1695       ret = -ENOENT;  
  75. 1696       goto probe_free_gpio;  
  76. 1697   }  
  77. 1698  
  78. 1699   host->base = ioremap(host->mem->start,resource_size(host->mem));  
  79. 1700   if (!host->base) {  
  80. 1701       dev_err(&pdev->dev, "failed to ioremap() io memoryregion.\n");  
  81. 1702       ret = -EINVAL;  
  82. 1703       goto probe_free_mem_region;  
  83. 1704   }  
  84. 1705  
  85. 1706   host->irq = platform_get_irq(pdev, 0);  
  86. 1707   if (host->irq == 0) {  
  87. 1708       dev_err(&pdev->dev, "failed to get interruptresource.\n");  
  88. 1709       ret = -EINVAL;  
  89. 1710       goto probe_iounmap;  
  90. 1711   }  
  91. 1712  
  92. 1713   if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {  
  93. 1714       dev_err(&pdev->dev, "failed to request mciinterrupt.\n");  
  94. 1715       ret = -ENOENT;  
  95. 1716       goto probe_iounmap;  
  96. 1717   }  
  97. 1718  
  98. 1719   /* We get spurious interrupts even when we have set the IMSK 
  99. 1720    * register to ignore everything, so use disable_irq() to make 
  100. 1721    * ensure we don't lock the system with un-serviceable requests. */  
  101. 1722  
  102. 1723   disable_irq(host->irq);  
  103. 1724   host->irq_state = false;  
  104. 1725  
  105. 1726   if (!host->pdata->no_detect) {  
  106. 1727       ret = gpio_request(host->pdata->gpio_detect, "s3cmcidetect");  
  107. 1728       if (ret) {  
  108. 1729            dev_err(&pdev->dev,"failed to get detect gpio\n");  
  109. 1730            goto probe_free_irq;  
  110. 1731       }  
  111. 1732  
  112. 1733       host->irq_cd = gpio_to_irq(host->pdata->gpio_detect);  
  113. 1734  
  114. 1735       if (host->irq_cd >= 0) {  
  115. 1736            if (request_irq(host->irq_cd,s3cmci_irq_cd,  
  116. 1737                    IRQF_TRIGGER_RISING |  
  117. 1738                    IRQF_TRIGGER_FALLING,  
  118. 1739                    DRIVER_NAME, host)) {  
  119. 1740                dev_err(&pdev->dev,  
  120. 1741                    "can't get card detectirq.\n");  
  121. 1742                ret = -ENOENT;  
  122. 1743                goto probe_free_gpio_cd;  
  123. 1744            }  
  124. 1745       } else {  
  125. 1746            dev_warn(&pdev->dev,  
  126. 1747                 "host detect has no irqavailable\n");  
  127. 1748           gpio_direction_input(host->pdata->gpio_detect);  
  128. 1749       }  
  129. 1750   } else  
  130. 1751       host->irq_cd = -1;  
  131. 1752  
  132. 1753   if (!host->pdata->no_wprotect) {  
  133. 1754       ret = gpio_request(host->pdata->gpio_wprotect, "s3cmciwp");  
  134. 1755       if (ret) {  
  135. 1756            dev_err(&pdev->dev,"failed to get writeprotect\n");  
  136. 1757            goto probe_free_irq_cd;  
  137. 1758       }  
  138. 1759  
  139. 1760       gpio_direction_input(host->pdata->gpio_wprotect);  
  140. 1761   }  
  141. 1762  
  142. 1763   /* depending on the dma state, get a dma channel to use. */  
  143. 1764  
  144. 1765   if (s3cmci_host_usedma(host)) {  
  145. 1766       host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client,  
  146. 1767                        host);  
  147. 1768       if (host->dma < 0) {  
  148. 1769            dev_err(&pdev->dev,"cannot get DMA channel.\n");  
  149. 1770            if (!s3cmci_host_canpio()) {  
  150. 1771                ret = -EBUSY;  
  151. 1772                goto probe_free_gpio_wp;  
  152. 1773            } else {  
  153. 1774                dev_warn(&pdev->dev,"falling back to PIO.\n");  
  154. 1775                host->dodma = 0;  
  155. 1776            }  
  156. 1777       }  
  157. 1778   }  
  158. 1779  
  159. 1780   host->clk = clk_get(&pdev->dev, "sdi");  
  160. 1781   if (IS_ERR(host->clk)) {  
  161. 1782       dev_err(&pdev->dev, "failed to find clock source.\n");  
  162. 1783       ret = PTR_ERR(host->clk);  
  163. 1784       host->clk = NULL;  
  164. 1785       goto probe_free_dma;  
  165. 1786   }  
  166. 1787  
  167. 1788   ret = clk_enable(host->clk);  
  168. 1789   if (ret) {  
  169. 1790       dev_err(&pdev->dev, "failed to enable clocksource.\n");  
  170. 1791       goto clk_free;  
  171. 1792   }  
  172. 1793  
  173. 1794   host->clk_rate = clk_get_rate(host->clk);  
  174. 1795  
  175. 1796   mmc->ops    = &s3cmci_ops;  
  176. 1797   mmc->ocr_avail  = MMC_VDD_32_33| MMC_VDD_33_34;  
  177. 1798#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ  
  178. 1799   mmc->caps   =MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;  
  179. 1800#else  
  180. 1801   mmc->caps   =MMC_CAP_4_BIT_DATA;  
  181. 1802#endif  
  182. 1803   mmc->f_min  = host->clk_rate/ (host->clk_div * 256);  
  183. 1804   mmc->f_max  = host->clk_rate/ host->clk_div;  
  184. 1805  
  185. 1806   if (host->pdata->ocr_avail)  
  186. 1807       mmc->ocr_avail = host->pdata->ocr_avail;  
  187. 1808  
  188. 1809   mmc->max_blk_count  = 4095;  
  189. 1810   mmc->max_blk_size   = 4095;  
  190. 1811   mmc->max_req_size   = 4095 *512;  
  191. 1812   mmc->max_seg_size   =mmc->max_req_size;  
  192. 1813  
  193. 1814   mmc->max_segs       = 128;  
  194. 1815  
  195. 1816   dbg(host, dbg_debug,  
  196. 1817       "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%udma:%u.\n",  
  197. 1818       (host->is2440?"2440":""),  
  198. 1819       host->base, host->irq, host->irq_cd, host->dma);  
  199. 1820  
  200. 1821   ret = s3cmci_cpufreq_register(host);  
  201. 1822   if (ret) {  
  202. 1823       dev_err(&pdev->dev, "failed to register cpufreq\n");  
  203. 1824       goto free_dmabuf;  
  204. 1825   }  
  205. 1826  
  206. 1827   ret = mmc_add_host(mmc);  
  207. 1828   if (ret) {  
  208. 1829       dev_err(&pdev->dev, "failed to add mmc host.\n");  
  209. 1830       goto free_cpufreq;  
  210. 1831   }  
  211. 1832  
  212. 1833   s3cmci_debugfs_attach(host);  
  213. 1834  
  214. 1835   platform_set_drvdata(pdev, mmc);  
  215. 1836   dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n",mmc_hostname(mmc),  
  216. 1837        s3cmci_host_usedma(host) ? "dma" : "pio",  
  217. 1838        mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw");  
  218. 1839  
  219. 1840   return 0;  
  220. 1841  
  221. 1842 free_cpufreq:  
  222. 1843   s3cmci_cpufreq_deregister(host);  
  223. 1844  
  224. 1845 free_dmabuf:  
  225. 1846   clk_disable(host->clk);  
  226. 1847  
  227. 1848 clk_free:  
  228. 1849   clk_put(host->clk);  
  229. 1850  
  230. 1851 probe_free_dma:  
  231. 1852   if (s3cmci_host_usedma(host))  
  232. 1853       s3c2410_dma_free(host->dma, &s3cmci_dma_client);  
  233. 1854  
  234. 1855 probe_free_gpio_wp:  
  235. 1856   if (!host->pdata->no_wprotect)  
  236. 1857       gpio_free(host->pdata->gpio_wprotect);  
  237. 1858  
  238. 1859 probe_free_gpio_cd:  
  239. 1860   if (!host->pdata->no_detect)  
  240. 1861       gpio_free(host->pdata->gpio_detect);  
  241. 1862  
  242. 1863 probe_free_irq_cd:  
  243. 1864   if (host->irq_cd >= 0)  
  244. 1865       free_irq(host->irq_cd, host);  
  245. 1866  
  246. 1867 probe_free_irq:  
  247. 1868   free_irq(host->irq, host);  
  248. 1869  
  249. 1870 probe_iounmap:  
  250. 1871   iounmap(host->base);  
  251. 1872  
  252. 1873 probe_free_mem_region:  
  253. 1874   release_mem_region(host->mem->start, resource_size(host->mem));  
  254. 1875  
  255. 1876 probe_free_gpio:  
  256. 1877   for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++)  
  257. 1878       gpio_free(i);  
  258. 1879  
  259. 1880 probe_free_host:  
  260. 1881   mmc_free_host(mmc);  
  261. 1882  
  262. 1883 probe_out:  
  263. 1884   return ret;  
  264. 1885}  


1624行,定义structs3cmci_host指针变量host,struct s3cmci_host定义在drivers/mmc/host/s3cmci.h文件中,其内容如下:

[cpp]  view plain copy
  1. 20struct s3cmci_host {  
  2. 21   struct platform_device  *pdev;  
  3. 22   struct s3c24xx_mci_pdata *pdata;  
  4. 23   struct mmc_host     *mmc;  
  5. 24   struct resource     *mem;  
  6. 25   struct clk      *clk;  
  7. 26   void __iomem        *base;  
  8. 27   int         irq;  
  9. 28   int         irq_cd;  
  10. 29   int         dma;  
  11. 30  
  12. 31   unsigned long       clk_rate;  
  13. 32   unsigned long       clk_div;  
  14. 33   unsigned long       real_rate;  
  15. 34   u8          prescaler;  
  16. 35  
  17. 36   int         is2440;  
  18. 37   unsigned        sdiimsk;  
  19. 38   unsigned        sdidata;  
  20. 39   int         dodma;  
  21. 40   int         dmatogo;  
  22. 41  
  23. 42   bool            irq_disabled;  
  24. 43   bool            irq_enabled;  
  25. 44   bool            irq_state;  
  26. 45   int         sdio_irqen;  
  27. 46  
  28. 47   struct mmc_request  *mrq;  
  29. 48   int         cmd_is_stop;  
  30. 49  
  31. 50   spinlock_t      complete_lock;  
  32. 51   enum s3cmci_waitfor complete_what;  
  33. 52  
  34. 53   int         dma_complete;  
  35. 54  
  36. 55   u32         pio_sgptr;  
  37. 56   u32         pio_bytes;  
  38. 57   u32         pio_count;  
  39. 58   u32         *pio_ptr;  
  40. 59#define XFER_NONE 0  
  41. 60#define XFER_READ 1  
  42. 61#define XFER_WRITE 2  
  43. 62   u32         pio_active;  
  44. 63  
  45. 64   int         bus_width;  
  46. 65  
  47. 66   char            dbgmsg_cmd[301];  
  48. 67   char            dbgmsg_dat[301];  
  49. 68   char            *status;  
  50. 69  
  51. 70   unsigned int        ccnt, dcnt;  
  52. 71   struct tasklet_struct  pio_tasklet;  
  53. 72  
  54. 73#ifdef CONFIG_DEBUG_FS  
  55. 74   struct dentry       *debug_root;  
  56. 75   struct dentry       *debug_state;  
  57. 76   struct dentry       *debug_regs;  
  58. 77#endif  
  59. 78  
  60. 79#ifdef CONFIG_CPU_FREQ  
  61. 80   struct notifier_block  freq_transition;  
  62. 81#endif  
  63. 82};  


可以看到,struct s3cmci_host描述了整个SDI控制器。

1625行,定义了struct mmc_host指针变量mmc,structmmc_host定义在include/linux/mmc/host.h文件中,其内容如下:

[cpp]  view plain copy
  1. 198struct mmc_host {  
  2. 199   struct device       *parent;  
  3. 200   struct device       class_dev;  
  4. 201   int         index;  
  5. 202   const struct mmc_host_ops *ops;  
  6. 203   unsigned int        f_min;  
  7. 204   unsigned int        f_max;  
  8. 205   unsigned int        f_init;  
  9. 206   u32         ocr_avail;  
  10. 207   u32         ocr_avail_sdio; /*SDIO-specific OCR */  
  11. 208   u32         ocr_avail_sd;   /* SD-specific OCR */  
  12. 209   u32         ocr_avail_mmc;  /* MMC-specific OCR */  
  13. 210   struct notifier_block   pm_notify;  
  14. 211   u32         max_current_330;  
  15. 212   u32         max_current_300;  
  16. 213   u32         max_current_180;  
  17. 214  
  18. 215#define MMC_VDD_165_195     0x00000080 /* VDD voltage 1.65 - 1.95 */  
  19. 216#define MMC_VDD_20_21       0x00000100  /* VDD voltage 2.0 ~ 2.1 */  
  20. 217#define MMC_VDD_21_22       0x00000200  /* VDD voltage 2.1 ~ 2.2 */  
  21. 218#define MMC_VDD_22_23       0x00000400  /* VDD voltage 2.2 ~ 2.3 */  
  22. 219#define MMC_VDD_23_24       0x00000800  /* VDD voltage 2.3 ~ 2.4 */  
  23. 220#define MMC_VDD_24_25       0x00001000  /* VDD voltage 2.4 ~ 2.5 */  
  24. 221#define MMC_VDD_25_26       0x00002000  /* VDD voltage 2.5 ~ 2.6 */  
  25. 222#define MMC_VDD_26_27       0x00004000  /* VDD voltage 2.6 ~ 2.7 */  
  26. 223#define MMC_VDD_27_28       0x00008000  /* VDD voltage 2.7 ~ 2.8 */  
  27. 224#define MMC_VDD_28_29       0x00010000  /* VDD voltage 2.8 ~ 2.9 */  
  28. 225#define MMC_VDD_29_30       0x00020000  /* VDD voltage 2.9 ~ 3.0 */  
  29. 226#define MMC_VDD_30_31       0x00040000  /* VDD voltage 3.0 ~ 3.1 */  
  30. 227#define MMC_VDD_31_32       0x00080000  /* VDD voltage 3.1 ~ 3.2 */  
  31. 228#define MMC_VDD_32_33       0x00100000  /* VDD voltage 3.2 ~ 3.3 */  
  32. 229#define MMC_VDD_33_34       0x00200000  /* VDD voltage 3.3 ~ 3.4 */  
  33. 230#define MMC_VDD_34_35       0x00400000  /* VDD voltage 3.4 ~ 3.5 */  
  34. 231#define MMC_VDD_35_36       0x00800000  /* VDD voltage 3.5 ~ 3.6 */  
  35. 232  
  36. 233   u32         caps;       /* Host capabilities */  
  37. 234  
  38. 235#define MMC_CAP_4_BIT_DATA  (1 << 0)    /* Can the host do 4 bit transfers */  
  39. 236#define MMC_CAP_MMC_HIGHSPEED   (1 << 1)    /* Can do MMC high-speed timing */  
  40. 237#define MMC_CAP_SD_HIGHSPEED    (1 << 2)    /*Can do SD high-speed timing */  
  41. 238#define MMC_CAP_SDIO_IRQ    (1 << 3)    /* Can signal pending SDIO IRQs */  
  42. 239#define MMC_CAP_SPI     (1 << 4)    /* Talks only SPI protocols */  
  43. 240#define MMC_CAP_NEEDS_POLL  (1 << 5)    /* Needs polling for card-detection */  
  44. 241#define MMC_CAP_8_BIT_DATA  (1 << 6)    /* Can the host do 8 bit transfers */  
  45. 242  
  46. 243#define MMC_CAP_NONREMOVABLE    (1 << 8)    /* Nonremovable e.g. eMMC */  
  47. 244#define MMC_CAP_WAIT_WHILE_BUSY (1<< 9)    /* Waits while card isbusy */  
  48. 245#define MMC_CAP_ERASE       (1 << 10)   /* Allow erase/trim commands */  
  49. 246#define MMC_CAP_1_8V_DDR    (1 << 11)   /* can support */  
  50. 247                        /* DDR mode at 1.8V */  
  51. 248#define MMC_CAP_1_2V_DDR    (1 << 12)   /* can support */  
  52. 249                        /* DDR mode at 1.2V */  
  53. 250#define MMC_CAP_POWER_OFF_CARD  (1 << 13)   /* Can power off after boot */  
  54. 251#define MMC_CAP_BUS_WIDTH_TEST  (1 << 14)   /* CMD14/CMD19 bus width ok */  
  55. 252#define MMC_CAP_UHS_SDR12   (1 << 15)   /* Host supports UHS SDR12 mode */  
  56. 253#define MMC_CAP_UHS_SDR25   (1 << 16)   /* Host supports UHS SDR25 mode */  
  57. 254#define MMC_CAP_UHS_SDR50   (1 << 17)   /* Host supports UHS SDR50 mode */  
  58. 255#define MMC_CAP_UHS_SDR104  (1 << 18)   /* Host supports UHS SDR104 mode */  
  59. 256#define MMC_CAP_UHS_DDR50   (1 << 19)   /* Host supports UHS DDR50 mode */  
  60. 257#define MMC_CAP_DRIVER_TYPE_A   (1 << 23)   /* Host supports Driver Type A */  
  61. 258#define MMC_CAP_DRIVER_TYPE_C   (1 << 24)   /* Host supports Driver Type C */  
  62. 259#define MMC_CAP_DRIVER_TYPE_D   (1 << 25)   /* Host supports Driver Type D */  
  63. 260#define MMC_CAP_CMD23       (1 << 30)   /* CMD23 supported. */  
  64. 261#define MMC_CAP_HW_RESET    (1 << 31)   /* Hardware reset */  
  65. 262  
  66. 263   u32         caps2;      /* More host capabilities */  
  67. 264  
  68. 265#define MMC_CAP2_BOOTPART_NOACC (1<< 0)    /* Boot partition noaccess */  
  69. 266#define MMC_CAP2_CACHE_CTRL (1 <<1)    /* Allow cache control */  
  70. 267#define MMC_CAP2_POWEROFF_NOTIFY (1<< 2)   /* Notify poweroffsupported */  
  71. 268#define MMC_CAP2_NO_MULTI_READ  (1 << 3)    /* Multiblock reads don't work */  
  72. 269#define MMC_CAP2_NO_SLEEP_CMD   (1 << 4)    /* Don't allow sleep command */  
  73. 270#define MMC_CAP2_HS200_1_8V_SDR (1<< 5)        /* can support */  
  74. 271#define MMC_CAP2_HS200_1_2V_SDR (1<< 6)        /* can support */  
  75. 272#define MMC_CAP2_HS200      (MMC_CAP2_HS200_1_8V_SDR | \  
  76. 273                 MMC_CAP2_HS200_1_2V_SDR)  
  77. 274#define MMC_CAP2_BROKEN_VOLTAGE (1<< 7)    /* Use the broken voltage*/  
  78. 275#define MMC_CAP2_DETECT_ON_ERR  (1 << 8)    /* On I/O err check card removal */  
  79. 276#define MMC_CAP2_HC_ERASE_SZ    (1 << 9)    /* High-capacity erase size */  
  80. 277#define MMC_CAP2_CD_ACTIVE_HIGH (1<< 10)   /* Card-detect signalactive high */  
  81. 278#define MMC_CAP2_RO_ACTIVE_HIGH (1<< 11)   /* Write-protect signalactive high */  
  82. 279#define MMC_CAP2_PACKED_RD  (1 << 12)   /* Allow packed read */  
  83. 280#define MMC_CAP2_PACKED_WR  (1 << 13)   /* Allow packed write */  
  84. 281#define MMC_CAP2_PACKED_CMD(MMC_CAP2_PACKED_RD | \  
  85. 282                 MMC_CAP2_PACKED_WR)  
  86. 283#define MMC_CAP2_NO_PRESCAN_POWERUP (1<< 14)   /* Don't power up beforescan */  
  87. 284  
  88. 285   mmc_pm_flag_t       pm_caps;    /* supported pm features */  
  89. 286  
  90. 287#ifdef CONFIG_MMC_CLKGATE  
  91. 288   int         clk_requests;   /* internal reference counter */  
  92. 289   unsigned int       clk_delay;  /* number of MCI clkhold cycles */  
  93. 290   bool            clk_gated;  /* clock gated */  
  94. 291   struct delayed_work clk_gate_work; /* delayed clock gate */  
  95. 292   unsigned int        clk_old;    /* old clock value cache */  
  96. 293   spinlock_t      clk_lock;   /* lock for clk fields */  
  97. 294   struct mutex       clk_gate_mutex; /* mutex for clock gating */  
  98. 295   struct device_attribute clkgate_delay_attr;  
  99. 296   unsigned long          clkgate_delay;  
  100. 297#endif  
  101. 298  
  102. 299   /* host specific block data */  
  103. 300   unsigned int       max_seg_size;   /* seeblk_queue_max_segment_size */  
  104. 301   unsigned short      max_segs;   /* see blk_queue_max_segments */  
  105. 302   unsigned short      unused;  
  106. 303   unsigned int        max_req_size;   /* maximum number of bytes in one req */  
  107. 304   unsigned int       max_blk_size;   /* maximum size ofone mmc block */  
  108. 305   unsigned int       max_blk_count;  /* maximum numberof blocks in one req */  
  109. 306   unsigned int       max_discard_to; /* max. discard timeout in ms */  
  110. 307  
  111. 308   /* private data */  
  112. 309   spinlock_t      lock;       /* lock for claim and bus ops */  
  113. 310  
  114. 311   struct mmc_ios      ios;        /* current io bus settings */  
  115. 312   u32         ocr;        /* the current OCR setting */  
  116. 313  
  117. 314   /* group bitfields together to minimize padding */  
  118. 315   unsigned int        use_spi_crc:1;  
  119. 316   unsigned int       claimed:1;  /* host exclusivelyclaimed */  
  120. 317   unsigned int        bus_dead:1; /* bus has been released */  
  121. 318#ifdef CONFIG_MMC_DEBUG  
  122. 319   unsigned int       removed:1;  /* host is beingremoved */  
  123. 320#endif  
  124. 321  
  125. 322   int         rescan_disable; /*disable card detection */  
  126. 323   int         rescan_entered; /* usedwith nonremovable devices */  
  127. 324  
  128. 325   struct mmc_card     *card;      /* device attached to this host */  
  129. 326  
  130. 327   wait_queue_head_t   wq;  
  131. 328   struct task_struct  *claimer;   /* task that has host claimed */  
  132. 329   int         claim_cnt;  /* "claim" nesting count */  
  133. 330  
  134. 331   struct delayed_work detect;  
  135. 332   int         detect_change;  /* card detect flag */  
  136. 333   struct mmc_slot     slot;  
  137. 334  
  138. 335   const struct mmc_bus_ops *bus_ops; /* current bus driver */  
  139. 336   unsigned int        bus_refs;   /* reference counter */  
  140. 337  
  141. 338   unsigned int        sdio_irqs;  
  142. 339   struct task_struct *sdio_irq_thread;  
  143. 340   bool            sdio_irq_pending;  
  144. 341   atomic_t       sdio_irq_thread_abort;  
  145. 342  
  146. 343   mmc_pm_flag_t       pm_flags;   /* requested pm features */  
  147. 344  
  148. 345   struct led_trigger  *led;       /* activity led */  
  149. 346  
  150. 347#ifdef CONFIG_REGULATOR  
  151. 348   bool            regulator_enabled;/* regulator state */  
  152. 349#endif  
  153. 350   struct mmc_supply   supply;  
  154. 351  
  155. 352   struct dentry       *debugfs_root;  
  156. 353  
  157. 354   struct mmc_async_req   *areq;      /* active async req */  
  158. 355   struct mmc_context_info context_info;  /* async synchronization info */  
  159. 356  
  160. 357#ifdef CONFIG_FAIL_MMC_REQUEST  
  161. 358   struct fault_attr  fail_mmc_request;  
  162. 359#endif  
  163. 360  
  164. 361   unsigned int       actual_clock;   /* Actual HC clockrate */  
  165. 362  
  166. 363   unsigned int        slotno; /*used for sdio acpi binding */  
  167. 364  
  168. 365   unsigned long       private[0]____cacheline_aligned;  
  169. 366};  


1630行,调用platform_get_device_id宏,取得处理器类型,该宏定义在include/linux/platform_device.h文件中:

[cpp]  view plain copy
  1. 39#define platform_get_device_id(pdev)    ((pdev)->id_entry)  


但是,回忆一下我们注册的platform_device s3c_device_sdi,我们并没有初始化platform_device.id_entry成员,那么这里的platform_get_device_id宏返回值是NULL吗?如果不是NULL,应该是什么值呢?

答案是platform_get_device_id(pdev)->driver_data返回值为1。

原因是s3cmci_driver.id_table被设置为s3cmci_driver_ids。s3cmci_driver_ids定义在drivers/mmc/host/s3cmci.c文件中:

[cpp]  view plain copy
  1. 1936static struct platform_device_ids3cmci_driver_ids[] = {  
  2. 1937   {  
  3. 1938       .name   = "s3c2410-sdi",  
  4. 1939       .driver_data    = 0,  
  5. 1940   }, {  
  6. 1941       .name   = "s3c2412-sdi",  
  7. 1942       .driver_data    = 1,  
  8. 1943   }, {  
  9. 1944       .name   = "s3c2440-sdi",  
  10. 1945       .driver_data    = 1,  
  11. 1946   },  
  12. 1947   { }  
  13. 1948};  


struct platform_device_id定义在include/linux/mod_devicetable.h文件中:

[cpp]  view plain copy
  1. 482struct platform_device_id {  
  2. 483   char name[PLATFORM_NAME_SIZE];  
  3. 484   kernel_ulong_t driver_data;  
  4. 485};  


platform_driver.id_table是platform_driver所支持的设备列表。可以看到,s3cmci_driver支持3种设备,分别是"s3c2410-sdi"、"s3c2412-sdi"和"s3c2440-sdi"。对于"s3c2410-sdi",其driver_data成员值为0,对于其它两种设备,它们的driver_data成员值为1。

当调用platform_driver_register函数注册s3cmci_driver时,s3cmci_driver.driver.bus被设置为 platform_bus_type,structbus_type platform_bus_type定义在drivers/base/platform.c文件中:

 

[cpp]  view plain copy
  1. 895structbus_type platform_bus_type = {  
  2.  896    .name      = "platform",  
  3.  897   .dev_attrs  = platform_dev_attrs,  
  4.  898   .match      = platform_match,  
  5.  899   .uevent     = platform_uevent,  
  6.  900   .pm     =&platform_dev_pm_ops,  
  7.  901};  

根据《Linux设备模型分析之device_driver(基于3.10.1内核)》一文对Linux设备模型的分析,在s3cmci_driver.probe函数被调用执行之前,platform_bus_type.match即platform_match首先会被调用执行。platform_match函数定义在drivers/base/platform.c文件中:

[cpp]  view plain copy
  1. 710/** 
  2. 711* platform_match - bind platform device to platform driver. 
  3. 712* @dev: device. 
  4. 713* @drv: driver. 
  5. 714* 
  6. 715* Platform device IDs are assumed to be encoded like this: 
  7. 716* "<name><instance>", where <name> is a shortdescription of the type of 
  8. 717* device, like "pci" or "floppy", and <instance> isthe enumerated 
  9. 718* instance of the device, like '0' or '42'. Driver IDs are simply 
  10. 719* "<name>".  So, extractthe <name> from the platform_device structure, 
  11. 720* and compare it against the name of the driver. Return whether they match 
  12. 721* or not. 
  13. 722*/  
  14. 723static int platform_match(struct device*dev, struct device_driver *drv)  
  15. 724{  
  16. 725   struct platform_device *pdev = to_platform_device(dev);  
  17. 726   struct platform_driver *pdrv = to_platform_driver(drv);  
  18. 727  
  19. 728   /* Attempt an OF style match first */  
  20. 729   if (of_driver_match_device(dev, drv))  
  21. 730       return 1;  
  22. 731  
  23. 732   /* Then try ACPI style match */  
  24. 733   if (acpi_driver_match_device(dev, drv))  
  25. 734       return 1;  
  26. 735  
  27. 736   /* Then try to match against the id table */  
  28. 737   if (pdrv->id_table)  
  29. 738       return platform_match_id(pdrv->id_table, pdev) != NULL;  
  30. 739  
  31. 740   /* fall-back to driver name match */  
  32. 741   return (strcmp(pdev->name, drv->name) == 0);  
  33. 742}  


737行,如果pdrv->id_table不为空,则调用platform_match_id函数。而我们的platform_drivers3cmci_driver.id_table被设置为s3cmci_driver_ids,所以platform_match_id函数会被执行。

platform_match_id函数定义在drivers/base/platform.c文件中:

[cpp]  view plain copy
  1. 696staticconst struct platform_device_id *platform_match_id(  
  2. 697           const struct platform_device_id *id,  
  3. 698           struct platform_device *pdev)  
  4. 699{  
  5. 700   while (id->name[0]) {  
  6. 701        if (strcmp(pdev->name, id->name)== 0) {  
  7. 702           pdev->id_entry = id;  
  8. 703           return id;  
  9. 704       }  
  10. 705       id++;  
  11. 706    }  
  12. 707   return NULL;  
  13. 708}  


可以看到,在701行,如果platform_device.name与platform_device_id.name相同,则将id赋值给pdev->id_entry。

回到我们的platform_driver s3cmci_driver和platform_device s3c_device_sdi,s3c_device_sdi.name被初始化为"s3c2410-sdi",但是因为我们基于的平台是Mini2440,处理器是S3C2440,所以s3c244x_map_io函数会被调用,至于什么时候该函数会被调用我还没有搞清楚,呵呵!该函数定义在arch/arm/mach-s3c24xx/s3c244x.c文件中:

[cpp]  view plain copy
  1. 63void__init s3c244x_map_io(void)  
  2. 64{  
  3. 65    /* register our io-tables */  
  4. 66  
  5. 67   iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));  
  6. 68  
  7. 69    /*rename any peripherals used differing from the s3c2410 */  
  8. 70  
  9. 71   s3c_device_sdi.name  ="s3c2440-sdi";  
  10. 72   s3c_device_i2c0.name  ="s3c2440-i2c";  
  11. 73   s3c_nand_setname("s3c2440-nand");  
  12. 74   s3c_device_ts.name = "s3c2440-ts";  
  13. 75   s3c_device_usbgadget.name = "s3c2440-usbgadget";  
  14. 76}  


71行,将s3c_device_sdi.name设置为"s3c2440-sdi"

而s3cmci_driver.id_table被设置为s3cmci_driver_ids,s3cmci_driver_ids[2].name同样为"s3c2440-sdi",所以,虽然s3c_device_sdi.id_entry在初始化时没有赋值,但是在platform_match_id函数中,它会被赋值为s3cmci_driver_ids[2]。

现在我们可以回到s3cmci_probe函数了:

1630行,经过前面的分析,我们知道platform_get_device_id(pdev)->driver_data的值其实就是s3cmci_driver_ids[2].driver_data,其值为1。所以,对于Mini2440平台,is2440变量被赋值为1。

1632行,调用mmc_alloc_host函数为struct mmc_host指针变量mmc分配内存空间并初始化。注意mmc_alloc_host的第一个参数表示除了mmc_host结构体外,还要额外多分配的内存空间大小,所以这里分配的内存大小是struct mmc_host加上struct s3cmci_host。

mmc_alloc_host函数定义在drivers/mmc/core/host.c文件中,其内容如下:

[cpp]  view plain copy
  1. 420/** 
  2. 421 * mmc_alloc_host - initialise the per-host structure. 
  3. 422 * @extra: sizeof private data structure 
  4. 423 * @dev: pointer to host device model structure 
  5. 424 * 
  6. 425 * Initialise the per-host structure. 
  7. 426 */  
  8. 427struct mmc_host *mmc_alloc_host(intextra, struct device *dev)  
  9. 428{  
  10. 429   int err;  
  11. 430   struct mmc_host *host;  
  12. 431  
  13. 432   host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);  
  14. 433   if (!host)  
  15. 434       return NULL;  
  16. 435  
  17. 436   /* scanning will be enabled when we're ready */  
  18. 437   host->rescan_disable = 1;  
  19. 438   idr_preload(GFP_KERNEL);  
  20. 439   spin_lock(&mmc_host_lock);  
  21. 440   err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT);  
  22. 441   if (err >= 0)  
  23. 442       host->index = err;  
  24. 443   spin_unlock(&mmc_host_lock);  
  25. 444   idr_preload_end();  
  26. 445   if (err < 0)  
  27. 446       goto free;  
  28. 447  
  29. 448   dev_set_name(&host->class_dev, "mmc%d",host->index);  
  30. 449  
  31. 450   host->parent = dev;  
  32. 451   host->class_dev.parent = dev;  
  33. 452   host->class_dev.class = &mmc_host_class;  
  34. 453   device_initialize(&host->class_dev);  
  35. 454  
  36. 455   mmc_host_clk_init(host);  
  37. 456  
  38. 457   mutex_init(&host->slot.lock);  
  39. 458   host->slot.cd_irq = -EINVAL;  
  40. 459  
  41. 460   spin_lock_init(&host->lock);  
  42. 461   init_waitqueue_head(&host->wq);  
  43. 462   INIT_DELAYED_WORK(&host->detect, mmc_rescan);  
  44. 463#ifdef CONFIG_PM  
  45. 464   host->pm_notify.notifier_call = mmc_pm_notify;  
  46. 465#endif  
  47. 466  
  48. 467   /* 
  49. 468    * By default, hosts do not support SGIO or large requests. 
  50. 469    * They have to set these according to their abilities. 
  51. 470    */  
  52. 471   host->max_segs = 1;  
  53. 472   host->max_seg_size = PAGE_CACHE_SIZE;  
  54. 473  
  55. 474   host->max_req_size = PAGE_CACHE_SIZE;  
  56. 475   host->max_blk_size = 512;  
  57. 476   host->max_blk_count = PAGE_CACHE_SIZE / 512;  
  58. 477  
  59. 478   return host;  
  60. 479  
  61. 480free:  
  62. 481   kfree(host);  
  63. 482   return NULL;  
  64. 483}  


回到s3cmci_probe函数:

1638-1648行,通过gpio_request函数申请获取GPE5-GPE10。从Mini2440原理图可以看出,Mini2440SDI使用的GPE7-GPE10作为4根数据信号线,使用GPE6作为命令信号线,使用GPE5作为时钟信号线。另外,使用GPG8的外部中断功能来作SD卡的插拨检测,使用GPH8来判断SD卡是否有写保护。

1650行,通过调用mmc_priv(mmc)取得s3cmci_host指针变量host。

下面的内容就是初始化host的各个成员变量。

1681行,调用platform_get_resource(pdev,IORESOURCE_MEM, 0)取得IORESOURCE_MEM类型资源。IORESOURCE_MEM宏定义在include/linux/ioport.h文件中:

[cpp]  view plain copy
  1. 32#define IORESOURCE_IO       0x00000100  /* PCI/ISA I/O ports */  
  2. 33#define IORESOURCE_MEM      0x00000200  
  3. 34#define IORESOURCE_REG      0x00000300  /* Register offsets */  
  4. 35#define IORESOURCE_IRQ      0x00000400  
  5. 36#define IORESOURCE_DMA      0x00000800  
  6. 37#define IORESOURCE_BUS      0x00001000  


platform_get_resource函数定义在drivers/base/platform.c文件中:

[cpp]  view plain copy
  1.  59/** 
  2.  60* platform_get_resource - get a resource for a device 
  3.  61* @dev: platform device 
  4.  62* @type: resource type 
  5.  63* @num: resource index 
  6.  64*/  
  7. 65struct resource *platform_get_resource(struct platform_device *dev,  
  8. 66                       unsigned int type, unsigned int num)  
  9.  67{  
  10. 68    int i;  
  11.  69  
  12. 70    for (i = 0; i <dev->num_resources; i++) {  
  13. 71        struct resource *r =&dev->resource[i];  
  14.  72  
  15. 73        if (type ==resource_type(r) && num-- == 0)  
  16. 74            return r;  
  17. 75    }  
  18. 76    return NULL;  
  19.  77}  


resource_type定义在include/linux/ioport.h文件中:

[cpp]  view plain copy
  1. 168static inline unsigned longresource_type(const struct resource *res)  
  2. 169{  
  3. 170   return res->flags & IORESOURCE_TYPE_BITS;  
  4. 171}  


回忆一下,Mini2440的资源文件s3c_sdi_resource定义在arch/arm/plat-samsung/devs.c文件中:

[cpp]  view plain copy
  1. 1167static struct resources3c_sdi_resource[] = {  
  2. 1168   [0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI),  
  3. 1169   [1] = DEFINE_RES_IRQ(IRQ_SDI),  
  4. 1170};  


宏S3C24XX_PA_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:

[cpp]  view plain copy
  1. 155#define S3C24XX_PA_SDI      S3C2410_PA_SDI  


宏S3C2410_PA_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:

[cpp]  view plain copy
  1. 105#define S3C2410_PA_SDI     (0x5A000000)  


0x5A000000是S3C2440 SDICON寄存器的地址。

宏S3C24XX_SZ_SDI定义在arch/arm/mach-s3c24xx/include/mach/map.h文件中:

[cpp]  view plain copy
  1. 61#define S3C24XX_SZ_SDI      SZ_1M  


宏SZ_1M定义在include/linux/sizes.h文件中:

[cpp]  view plain copy
  1. 33#define SZ_1M               0x00100000  


所以s3cmci_probe函数1681行,platform_get_resource(pdev, IORESOURCE_MEM, 0)函数返回的就是s3c_sdi_resource[0]。

1690-1691行,调用request_mem_region(host->mem->start,resource_size(host->mem), pdev->name)函数,该函数用于获取参数指定的内存空间。request_mem_region函数定义在include/linux/ioport.h文件中:

177#define request_mem_region(start,n,name)__request_region(&iomem_resource, (start), (n), (name), 0)

__request_region定义在kernel/resource.c文件中:

[cpp]  view plain copy
  1. 931/** 
  2. 932* __request_region - create a new busy resource region 
  3. 933* @parent: parent resource descriptor 
  4. 934* @start: resource start address 
  5. 935* @n: resource region size 
  6. 936* @name: reserving caller's ID string 
  7. 937* @flags: IO resource flags 
  8. 938*/  
  9. 939struct resource * __request_region(structresource *parent,  
  10. 940                   resource_size_t start,resource_size_t n,  
  11. 941                   const char *name, int flags)  
  12. 942{  
  13. 943   DECLARE_WAITQUEUE(wait, current);  
  14. 944   struct resource *res = alloc_resource(GFP_KERNEL);  
  15. 945  
  16. 946   if (!res)  
  17. 947       return NULL;  
  18. 948  
  19. 949   res->name = name;  
  20. 950   res->start = start;  
  21. 951   res->end = start + n - 1;  
  22. 952   res->flags = IORESOURCE_BUSY;  
  23. 953   res->flags |= flags;  
  24. 954  
  25. 955   write_lock(&resource_lock);  
  26. 956  
  27. 957   for (;;) {  
  28. 958       struct resource *conflict;  
  29. 959  
  30. 960       conflict = __request_resource(parent, res);  
  31. 961       if (!conflict)  
  32. 962           break;  
  33. 963       if (conflict != parent) {  
  34. 964            parent = conflict;  
  35. 965           if (!(conflict->flags &IORESOURCE_BUSY))  
  36. 966                continue;  
  37. 967       }  
  38. 968       if (conflict->flags & flags & IORESOURCE_MUXED) {  
  39. 969           add_wait_queue(&muxed_resource_wait, &wait);  
  40. 970           write_unlock(&resource_lock);  
  41. 971           set_current_state(TASK_UNINTERRUPTIBLE);  
  42. 972           schedule();  
  43. 973           remove_wait_queue(&muxed_resource_wait, &wait);  
  44. 974           write_lock(&resource_lock);  
  45. 975           continue;  
  46. 976       }  
  47. 977       /* Uhhuh, that didn't work out.. */  
  48. 978       free_resource(res);  
  49. 979       res = NULL;  
  50. 980       break;  
  51. 981    }  
  52. 982   write_unlock(&resource_lock);  
  53. 983   return res;  
  54. 984}  


1699行,调用ioremap(host->mem->start,resource_size(host->mem))宏,该宏完成物理内存到虚拟内存的映射。ioremap宏定义在arch/arm/include/asm/io.h文件中:

[cpp]  view plain copy
  1. 328#define ioremap(cookie,size)        __arm_ioremap((cookie), (size),MT_DEVICE)  


__arm_ioremap函数定义在arch/arm/mm/ioremap.c文件中:

[cpp]  view plain copy
  1. 374void __iomem *  
  2. 375__arm_ioremap(unsigned long phys_addr,size_t size, unsigned int mtype)  
  3. 376{  
  4. 377   return arch_ioremap_caller(phys_addr, size, mtype,  
  5. 378       __builtin_return_address(0));  
  6. 379}  


1706行,调用platform_get_irq函数获取设备中断。platform_get_irq函数定义在drivers/base/platform.c文件中:

 

[cpp]  view plain copy
  1. 80/** 
  2.   81* platform_get_irq - get an IRQ for a device 
  3.   82* @dev: platform device 
  4.   83* @num: IRQ number index 
  5.   84*/  
  6.  85int platform_get_irq(struct platform_device *dev, unsigned int num)  
  7.   86{  
  8.  87#ifdef CONFIG_SPARC  
  9.  88    /* sparc does not have irqsrepresented as IORESOURCE_IRQ resources */  
  10.  89    if (!dev || num >=dev->archdata.num_irqs)  
  11.  90        return -ENXIO;  
  12.  91    returndev->archdata.irqs[num];  
  13.  92#else  
  14.  93    struct resource *r =platform_get_resource(dev, IORESOURCE_IRQ, num);  
  15.   94  
  16.  95    return r ? r->start :-ENXIO;  
  17.  96#endif  
  18.   97}  

1713行,调用request_irq(host->irq,s3cmci_irq, 0, DRIVER_NAME, host)申请中断,中断处理函数是s3cmci_irq。

1723行,调用disable_irq禁用中断。

1726-1751行,处理SD卡探测相关内容。

1753-1761行,处理SD卡写保护相关内容。

1765-1778行,处理DMA相关内容。

1780-1794行,处理时钟相关内容。

1796-1814行,初始化mmc。

需要注意的是1796行,设置mmc->ops为s3cmci_ops,s3cmci_ops定义在drivers/mmc/host/s3cmci.c文件中:

[cpp]  view plain copy
  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};  


1821行,调用s3cmci_cpufreq_register(host),提供对变频的支持。

1827行,调用mmc_add_host(mmc),向core层注册mmc_host。

1833行,调用s3cmci_debugfs_attach(host)创建debugfs相关节点。

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

这篇关于Linux设备驱动程序架构分析之MMC/SD(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/271120

相关文章

mybatis的整体架构

mybatis的整体架构分为三层: 1.基础支持层 该层包括:数据源模块、事务管理模块、缓存模块、Binding模块、反射模块、类型转换模块、日志模块、资源加载模块、解析器模块 2.核心处理层 该层包括:配置解析、参数映射、SQL解析、SQL执行、结果集映射、插件 3.接口层 该层包括:SqlSession 基础支持层 该层保护mybatis的基础模块,它们为核心处理层提供了良好的支撑。

百度/小米/滴滴/京东,中台架构比较

小米中台建设实践 01 小米的三大中台建设:业务+数据+技术 业务中台--从业务说起 在中台建设中,需要规范化的服务接口、一致整合化的数据、容器化的技术组件以及弹性的基础设施。并结合业务情况,判定是否真的需要中台。 小米参考了业界优秀的案例包括移动中台、数据中台、业务中台、技术中台等,再结合其业务发展历程及业务现状,整理了中台架构的核心方法论,一是企业如何共享服务,二是如何为业务提供便利。

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57