天天看點

linux2.6核心SD Card Driver詳細解析之一

linux2.6核心SD Card Driver詳細解析之一 版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。

***************************************************************************************************************************

作者:EasyWave                                                                                 時間:2012.03.18

類别:Linux驅動開發                                                                           聲明:轉載,請保留連結

***************************************************************************************************************************

一:MMC/SD/SDIO的概念

  1. MMC:(Multi Media Card)由西門子公司和首推CF的SanDisk于1997年推出的多媒體記憶卡标準。
  2. SD:(Secure Digital Memory Card)由日本松下、東芝及美國SanDisk公司于1999年8月共同開發研制的新一代記憶卡标準,已完全相容MMC标準。
  3. SDIO:(Secure Digital Input and Output Card)安全數字輸入輸出卡。SDIO是在SD标準上定義了一種外設接口,通過SD的I/O接腳來連接配接外圍裝置,并且通過SD上的 I/O資料接位與這些外圍裝置進行資料傳輸。是目前較熱門的技術,如下圖中的一些裝置:GPS、相機、Wi-Fi、調頻廣播、條形碼讀卡器、藍牙等。
  4. 工作模式:工作模式是針對主機控制器來說的。SDI控制器可以在符合MMC的标準下工作,或者可以在符合SD的标準下工作,或者可以在符合SDIO的标準下工作。故就分别簡稱為:MMC模式、SD模式和SDIO模式。
  5. 傳輸模式:傳輸模式也是針對主機控制器來說的,指控制器與卡之間資料的傳輸模式,或者說是總線類型。SDI控制器可支援SPI、1位和4位的三種傳輸模式(總線類型)。至于1位和4位又是什麼意思呢?他們是指傳輸資料總線的線寬,具體參考資料手冊。

下面使用表格列出了MMC、SD、SDIO的電氣特性及性能和不同工作模式下支援的傳輸模式情況:

linux2.6核心SD Card Driver詳細解析之一

二:MMC/SD協定

根據協定,MMC/SD卡的驅動被分為:卡識别階段和資料傳輸階段。在卡識别階段通過指令使MMC/SD處于:空閑(idle)、準備(ready)、識别(ident)、等待(stby)、不活動(ina)幾種不同的狀态;而在資料傳輸階段通過指令使MMC/SD處于:發送(data)、傳輸(tran)、接收(rcv)、程式(prg)、斷開連接配接(dis)幾種不同的狀态。是以可以總結MMC/SD在工作的整個過程中分為兩個階段和十種狀态。下面使用圖形來描述一下在兩個階段中這十種狀态之間的轉換關系。

卡識别階段,如下圖:

linux2.6核心SD Card Driver詳細解析之一

【圖是從網絡上抓取】

資料傳輸階段,如下圖:

linux2.6核心SD Card Driver詳細解析之一

【圖是從網絡上抓取】

MMC/SD裝置驅動代碼在Linux源碼中的位置/linux-2.6.35.4/drivers/mmc/,分别有card、core和host三個檔案夾,他們都是MMC/SD卡的驅動。在實際驅動開發中,隻需要在host檔案夾下實作你具體的MMC/SD裝置驅動部分代碼,也就是控制器(支援對MMC/SD卡的控制,俗稱MMC/SD主機控制器)和SDI控制器與MMC/SD卡的硬體接口電路。同時card、core和host這三層的關系,我們用一幅圖來進行描述,圖如下:

linux2.6核心SD Card Driver詳細解析之一

【圖是從網絡上抓取】

從圖中的關系可以看出,整個MMC/SD子產品中最重要的部分是Core核心層,他提供了一系列的接口函數,對上提供了将主機驅動注冊到系統,給應用程式提供裝置通路接口,對下提供了對主機控制器控制的方法及塊裝置請求的支援。

三: 分析MMC/SD卡裝置驅動程式

  1. MMC/SD卡驅動程式的重要資料結構mmc_host,該結構位于Core核心層,主要用于核心層與主機驅動層的資料交換處理。定義在/include/linux/mmc/host.h中:

[plain] view plain copy print ?

  1. struct mmc_host {  
  2.     struct device       *parent;  
  3.     struct device       class_dev;  
  4.     int         index;  
  5.     const struct mmc_host_ops *ops;  
  6.     unsigned int        f_min;  
  7.     unsigned int        f_max;  
  8.     u32         ocr_avail;  
  9. #define MMC_VDD_165_195     0x00000080    
  10. #define MMC_VDD_20_21       0x00000100    
  11. #define MMC_VDD_21_22       0x00000200    
  12. #define MMC_VDD_22_23       0x00000400    
  13. #define MMC_VDD_23_24       0x00000800    
  14. #define MMC_VDD_24_25       0x00001000    
  15. #define MMC_VDD_25_26       0x00002000    
  16. #define MMC_VDD_26_27       0x00004000    
  17. #define MMC_VDD_27_28       0x00008000    
  18. #define MMC_VDD_28_29       0x00010000    
  19. #define MMC_VDD_29_30       0x00020000    
  20. #define MMC_VDD_30_31       0x00040000    
  21. #define MMC_VDD_31_32       0x00080000    
  22. #define MMC_VDD_32_33       0x00100000    
  23. #define MMC_VDD_33_34       0x00200000    
  24. #define MMC_VDD_34_35       0x00400000    
  25. #define MMC_VDD_35_36       0x00800000    
  26.     unsigned long       caps;         
  27. #define MMC_CAP_4_BIT_DATA  (1 << 0)    
  28. #define MMC_CAP_MMC_HIGHSPEED   (1 << 1)    
  29. #define MMC_CAP_SD_HIGHSPEED    (1 << 2)    
  30. #define MMC_CAP_SDIO_IRQ    (1 << 3)    
  31. #define MMC_CAP_SPI     (1 << 4)    
  32. #define MMC_CAP_NEEDS_POLL  (1 << 5)    
  33. #define MMC_CAP_8_BIT_DATA  (1 << 6)    
  34. #define MMC_CAP_DISABLE     (1 << 7)    
  35. #define MMC_CAP_NONREMOVABLE    (1 << 8)    
  36. #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9)    
  37.     mmc_pm_flag_t       pm_caps;      
  38.     unsigned int        max_seg_size;     
  39.     unsigned short      max_hw_segs;      
  40.     unsigned short      max_phys_segs;    
  41.     unsigned short      unused;  
  42.     unsigned int        max_req_size;     
  43.     unsigned int        max_blk_size;     
  44.     unsigned int        max_blk_count;    
  45.     spinlock_t      lock;         
  46.     struct mmc_ios      ios;          
  47.     u32         ocr;          
  48.     unsigned int        use_spi_crc:1;  
  49.     unsigned int        claimed:1;    
  50.     unsigned int        bus_dead:1;   
  51. #ifdef CONFIG_MMC_DEBUG  
  52.     unsigned int        removed:1;    
  53. #endif  
  54.     int         enabled;      
  55.     int         nesting_cnt;      
  56.     int         en_dis_recurs;    
  57.     unsigned int        disable_delay;    
  58.     struct delayed_work disable;      
  59.     struct mmc_card     *card;        
  60.     wait_queue_head_t   wq;  
  61.     struct task_struct  *claimer;     
  62.     int         claim_cnt;    
  63.     struct delayed_work detect;  
  64.     const struct mmc_bus_ops *bus_ops;    
  65.     unsigned int        bus_refs;     
  66.     unsigned int        sdio_irqs;  
  67.     struct task_struct  *sdio_irq_thread;  
  68.     atomic_t        sdio_irq_thread_abort;  
  69.     mmc_pm_flag_t       pm_flags;     
  70. #ifdef CONFIG_LEDS_TRIGGERS  
  71.     struct led_trigger  *led;         
  72. #endif  
  73.     struct dentry       *debugfs_root;  
  74.     unsigned long       private[0] ____cacheline_aligned;  
  75. };  
linux2.6核心SD Card Driver詳細解析之一
struct mmc_host {
	struct device		*parent;
	struct device		class_dev;
	int			index;
	const struct mmc_host_ops *ops;
	unsigned int		f_min;
	unsigned int		f_max;
	u32			ocr_avail;

#define MMC_VDD_165_195		0x00000080	/* VDD voltage 1.65 - 1.95 */
#define MMC_VDD_20_21		0x00000100	/* VDD voltage 2.0 ~ 2.1 */
#define MMC_VDD_21_22		0x00000200	/* VDD voltage 2.1 ~ 2.2 */
#define MMC_VDD_22_23		0x00000400	/* VDD voltage 2.2 ~ 2.3 */
#define MMC_VDD_23_24		0x00000800	/* VDD voltage 2.3 ~ 2.4 */
#define MMC_VDD_24_25		0x00001000	/* VDD voltage 2.4 ~ 2.5 */
#define MMC_VDD_25_26		0x00002000	/* VDD voltage 2.5 ~ 2.6 */
#define MMC_VDD_26_27		0x00004000	/* VDD voltage 2.6 ~ 2.7 */
#define MMC_VDD_27_28		0x00008000	/* VDD voltage 2.7 ~ 2.8 */
#define MMC_VDD_28_29		0x00010000	/* VDD voltage 2.8 ~ 2.9 */
#define MMC_VDD_29_30		0x00020000	/* VDD voltage 2.9 ~ 3.0 */
#define MMC_VDD_30_31		0x00040000	/* VDD voltage 3.0 ~ 3.1 */
#define MMC_VDD_31_32		0x00080000	/* VDD voltage 3.1 ~ 3.2 */
#define MMC_VDD_32_33		0x00100000	/* VDD voltage 3.2 ~ 3.3 */
#define MMC_VDD_33_34		0x00200000	/* VDD voltage 3.3 ~ 3.4 */
#define MMC_VDD_34_35		0x00400000	/* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36		0x00800000	/* VDD voltage 3.5 ~ 3.6 */

	unsigned long		caps;		/* Host capabilities */

#define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
#define MMC_CAP_MMC_HIGHSPEED	(1 << 1)	/* Can do MMC high-speed timing */
#define MMC_CAP_SD_HIGHSPEED	(1 << 2)	/* Can do SD high-speed timing */
#define MMC_CAP_SDIO_IRQ	(1 << 3)	/* Can signal pending SDIO IRQs */
#define MMC_CAP_SPI		(1 << 4)	/* Talks only SPI protocols */
#define MMC_CAP_NEEDS_POLL	(1 << 5)	/* Needs polling for card-detection */
#define MMC_CAP_8_BIT_DATA	(1 << 6)	/* Can the host do 8 bit transfers */
#define MMC_CAP_DISABLE		(1 << 7)	/* Can the host be disabled */
#define MMC_CAP_NONREMOVABLE	(1 << 8)	/* Nonremovable e.g. eMMC */
#define MMC_CAP_WAIT_WHILE_BUSY	(1 << 9)	/* Waits while card is busy */

	mmc_pm_flag_t		pm_caps;	/* supported pm features */

	/* host specific block data */
	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
	unsigned short		max_hw_segs;	/* see blk_queue_max_hw_segments */
	unsigned short		max_phys_segs;	/* see blk_queue_max_phys_segments */
	unsigned short		unused;
	unsigned int		max_req_size;	/* maximum number of bytes in one req */
	unsigned int		max_blk_size;	/* maximum size of one mmc block */
	unsigned int		max_blk_count;	/* maximum number of blocks in one req */

	/* private data */
	spinlock_t		lock;		/* lock for claim and bus ops */

	struct mmc_ios		ios;		/* current io bus settings */
	u32			ocr;		/* the current OCR setting */

	/* group bitfields together to minimize padding */
	unsigned int		use_spi_crc:1;
	unsigned int		claimed:1;	/* host exclusively claimed */
	unsigned int		bus_dead:1;	/* bus has been released */
#ifdef CONFIG_MMC_DEBUG
	unsigned int		removed:1;	/* host is being removed */
#endif

	/* Only used with MMC_CAP_DISABLE */
	int			enabled;	/* host is enabled */
	int			nesting_cnt;	/* "enable" nesting count */
	int			en_dis_recurs;	/* detect recursion */
	unsigned int		disable_delay;	/* disable delay in msecs */
	struct delayed_work	disable;	/* disabling work */

	struct mmc_card		*card;		/* device attached to this host */

	wait_queue_head_t	wq;
	struct task_struct	*claimer;	/* task that has host claimed */
	int			claim_cnt;	/* "claim" nesting count */

	struct delayed_work	detect;

	const struct mmc_bus_ops *bus_ops;	/* current bus driver */
	unsigned int		bus_refs;	/* reference counter */

	unsigned int		sdio_irqs;
	struct task_struct	*sdio_irq_thread;
	atomic_t		sdio_irq_thread_abort;

	mmc_pm_flag_t		pm_flags;	/* requested pm features */

#ifdef CONFIG_LEDS_TRIGGERS
	struct led_trigger	*led;		/* activity led */
#endif

	struct dentry		*debugfs_root;

	unsigned long		private[0] ____cacheline_aligned;
};
           
  1. MMC/SD卡驅動程式的重要資料結構mmc_host_ops,主要用于HOST端指令請求,直接跟晶片中SD卡寄存器打交道,定義在/include/linux/mmc/host.h中:

[plain] view plain copy print ?

  1. struct mmc_host_ops {  
  2.     int (*enable)(struct mmc_host *host);  
  3.     int (*disable)(struct mmc_host *host, int lazy);  
  4.     void    (*request)(struct mmc_host *host, struct mmc_request *req);  
  5.     void    (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);  
  6.     int (*get_ro)(struct mmc_host *host);  
  7.     int (*get_cd)(struct mmc_host *host);  
  8.     void    (*enable_sdio_irq)(struct mmc_host *host, int enable);  
  9.     void    (*init_card)(struct mmc_host *host, struct mmc_card *card);  
  10. };  
linux2.6核心SD Card Driver詳細解析之一
struct mmc_host_ops {
	/*
	 * Hosts that support power saving can use the 'enable' and 'disable'
	 * methods to exit and enter power saving states. 'enable' is called
	 * when the host is claimed and 'disable' is called (or scheduled with
	 * a delay) when the host is released. The 'disable' is scheduled if
	 * the disable delay set by 'mmc_set_disable_delay()' is non-zero,
	 * otherwise 'disable' is called immediately. 'disable' may be
	 * scheduled repeatedly, to permit ever greater power saving at the
	 * expense of ever greater latency to re-enable. Rescheduling is
	 * determined by the return value of the 'disable' method. A positive
	 * value gives the delay in milliseconds.
	 *
	 * In the case where a host function (like set_ios) may be called
	 * with or without the host claimed, enabling and disabling can be
	 * done directly and will nest correctly. Call 'mmc_host_enable()' and
	 * 'mmc_host_lazy_disable()' for this purpose, but note that these
	 * functions must be paired.
	 *
	 * Alternatively, 'mmc_host_enable()' may be paired with
	 * 'mmc_host_disable()' which calls 'disable' immediately.  In this
	 * case the 'disable' method will be called with 'lazy' set to 0.
	 * This is mainly useful for error paths.
	 *
	 * Because lazy disable may be called from a work queue, the 'disable'
	 * method must claim the host when 'lazy' != 0, which will work
	 * correctly because recursion is detected and handled.
	 */
	int (*enable)(struct mmc_host *host);
	int (*disable)(struct mmc_host *host, int lazy);
	void	(*request)(struct mmc_host *host, struct mmc_request *req);
	/*
	 * Avoid calling these three functions too often or in a "fast path",
	 * since underlaying controller might implement them in an expensive
	 * and/or slow way.
	 *
	 * Also note that these functions might sleep, so don't call them
	 * in the atomic contexts!
	 *
	 * Return values for the get_ro callback should be:
	 *   0 for a read/write card
	 *   1 for a read-only card
	 *   -ENOSYS when not supported (equal to NULL callback)
	 *   or a negative errno value when something bad happened
	 *
	 * Return values for the get_cd callback should be:
	 *   0 for a absent card
	 *   1 for a present card
	 *   -ENOSYS when not supported (equal to NULL callback)
	 *   or a negative errno value when something bad happened
	 */
	void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
	int	(*get_ro)(struct mmc_host *host);
	int	(*get_cd)(struct mmc_host *host);

	void	(*enable_sdio_irq)(struct mmc_host *host, int enable);

	/* optional callback for HC quirks */
	void	(*init_card)(struct mmc_host *host, struct mmc_card *card);
};
           

對于mmc_host_ops需要重點講一下: [plain] view plain copy print ?

  1. void    (*request)(struct mmc_host *host, struct mmc_request *req);  
linux2.6核心SD Card Driver詳細解析之一
void	(*request)(struct mmc_host *host, struct mmc_request *req);
           

這個函數主要用于SD卡指令的傳輸,比如發送和接收指令,CMD0,CMD8,ACMD41諸如此類的都是在這個函數去實作。 [plain] view plain copy print ?

  1. void    (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);  
linux2.6核心SD Card Driver詳細解析之一
void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
           

這個函數主要用于設定SD卡的CLK,MMC_POWER_OFF,MMC_POWER_ON的一些初始化。 [plain] view plain copy print ?

  1. int (*get_ro)(struct mmc_host *host);  
linux2.6核心SD Card Driver詳細解析之一
int	(*get_ro)(struct mmc_host *host);
           

這個函數主要用于檢測SD卡的寫保護是否打開。 [plain] view plain copy print ?

  1. int (*get_cd)(struct mmc_host *host);  
linux2.6核心SD Card Driver詳細解析之一
int	(*get_cd)(struct mmc_host *host);
           

這個函數主要用于SD卡的檢測,是否有卡插入和彈出。

  1. MMC/SD卡驅動程式的重要函數mmc_alloc_host,用于配置設定mmc_host結構體指針的記憶體空間大小,定義在host.c中:

[plain] view plain copy print ?

  1. struct mmc_host *mmc_alloc_host(int extra, struct device *dev)  
  2. {  
  3.     int err;  
  4.     struct mmc_host *host;  
  5.     if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))  
  6.         return NULL;  
  7.     host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);  
  8.     if (!host)  
  9.         return NULL;  
  10.     spin_lock(&mmc_host_lock);  
  11.     err = idr_get_new(&mmc_host_idr, host, &host->index);  
  12.     spin_unlock(&mmc_host_lock);  
  13.     if (err)  
  14.         goto free;  
  15.     dev_set_name(&host->class_dev, "mmc%d", host->index);  
  16.     host->parent = dev;  
  17.     host->class_dev.parent = dev;  
  18.     host->class_dev.class = &mmc_host_class;  
  19.     device_initialize(&host->class_dev);  
  20.     spin_lock_init(&host->lock);  
  21.     init_waitqueue_head(&host->wq);  
  22.     INIT_DELAYED_WORK(&host->detect, mmc_rescan);  
  23.     INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);  
  24.     host->max_hw_segs = 1;  
  25.     host->max_phys_segs = 1;  
  26.     host->max_seg_size = PAGE_CACHE_SIZE;  
  27.     host->max_req_size = PAGE_CACHE_SIZE;  
  28.     host->max_blk_size = 512;  
  29.     host->max_blk_count = PAGE_CACHE_SIZE / 512;  
  30.     return host;  
  31. free:  
  32.     kfree(host);  
  33.     return NULL;  
linux2.6核心SD Card Driver詳細解析之一
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
	int err;
	struct mmc_host *host;

	if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
		return NULL;

	host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
	if (!host)
		return NULL;

	spin_lock(&mmc_host_lock);
	err = idr_get_new(&mmc_host_idr, host, &host->index);
	spin_unlock(&mmc_host_lock);
	if (err)
		goto free;

	dev_set_name(&host->class_dev, "mmc%d", host->index);

	host->parent = dev;
	host->class_dev.parent = dev;
	host->class_dev.class = &mmc_host_class;
	device_initialize(&host->class_dev);

	spin_lock_init(&host->lock);
	init_waitqueue_head(&host->wq);
	INIT_DELAYED_WORK(&host->detect, mmc_rescan);
	INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);

	/*
	 * By default, hosts do not support SGIO or large requests.
	 * They have to set these according to their abilities.
	 */
	host->max_hw_segs = 1;
	host->max_phys_segs = 1;
	host->max_seg_size = PAGE_CACHE_SIZE;

	host->max_req_size = PAGE_CACHE_SIZE;
	host->max_blk_size = 512;
	host->max_blk_count = PAGE_CACHE_SIZE / 512;

	return host;

free:
	kfree(host);
	return NULL;

           

而在mmc_alloc_host函數中被調用的mmc_rescan函數,這個是需要 重點關注的,因為SD卡協定中的檢測,以及卡識别等都是在此函數中實作,具體的代碼如下: [plain] view plain copy print ?

  1. void mmc_rescan(struct work_struct *work)  
  2. {  
  3.     struct mmc_host *host =  
  4.         container_of(work, struct mmc_host, detect.work);  
  5.     u32 ocr;  
  6.     int err;  
  7.     mmc_bus_get(host);  
  8.     if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)  
  9.         host->bus_ops->detect(host);  
  10.     mmc_bus_put(host);  
  11.     mmc_bus_get(host);  
  12.     if (host->bus_ops != NULL) {  
  13.         mmc_bus_put(host);  
  14.         goto out;  
  15.     }  
  16.     mmc_bus_put(host);  
  17.     if (host->ops->get_cd && host->ops->get_cd(host) == 0)  
  18.         goto out;  
  19.     mmc_claim_host(host);  
  20.     mmc_power_up(host);  
  21.     sdio_reset(host);  
  22.     mmc_go_idle(host); //讓SD卡處于IDL_STATUS  
  23.     mmc_send_if_cond(host, host->ocr_avail); //檢測SD卡是否支援SD2.0  
  24.     err = mmc_send_io_op_cond(host, 0, &ocr); //檢測是否是支援SDIO的卡,比如:SDIO WIFI等.  
  25.     if (!err) {  
  26.         if (mmc_attach_sdio(host, ocr))  
  27.             mmc_power_off(host);  
  28.         goto out;  
  29.     }  
  30.     err = mmc_send_app_op_cond(host, 0, &ocr); //檢測是否是支援标準的SD卡.  
  31.     if (!err) {  
  32.         if (mmc_attach_sd(host, ocr))  
  33.             mmc_power_off(host);  
  34.         goto out;  
  35.     }  
  36.     err = mmc_send_op_cond(host, 0, &ocr); //最後才是檢測是否是支援MMC的卡  
  37.     if (!err) {  
  38.         if (mmc_attach_mmc(host, ocr))  
  39.             mmc_power_off(host);  
  40.         goto out;  
  41.     }  
  42.     mmc_release_host(host);  
  43.     mmc_power_off(host);  
  44. out:  
  45.     if (host->caps & MMC_CAP_NEEDS_POLL)  
  46.         mmc_schedule_delayed_work(&host->detect, HZ);  
  47. }  
linux2.6核心SD Card Driver詳細解析之一
void mmc_rescan(struct work_struct *work)
{
	struct mmc_host *host =
		container_of(work, struct mmc_host, detect.work);
	u32 ocr;
	int err;

	mmc_bus_get(host);

	/* if there is a card registered, check whether it is still present */
	if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead)
		host->bus_ops->detect(host);

	mmc_bus_put(host);


	mmc_bus_get(host);

	/* if there still is a card present, stop here */
	if (host->bus_ops != NULL) {
		mmc_bus_put(host);
		goto out;
	}

	/* detect a newly inserted card */

	/*
	 * Only we can add a new handler, so it's safe to
	 * release the lock here.
	 */
	mmc_bus_put(host);

	if (host->ops->get_cd && host->ops->get_cd(host) == 0)
		goto out;

	mmc_claim_host(host);

	mmc_power_up(host);
	sdio_reset(host);
	mmc_go_idle(host); //讓SD卡處于IDL_STATUS

	mmc_send_if_cond(host, host->ocr_avail); //檢測SD卡是否支援SD2.0

	/*
	 * First we search for SDIO...
	 */
	err = mmc_send_io_op_cond(host, 0, &ocr); //檢測是否是支援SDIO的卡,比如:SDIO WIFI等.
	if (!err) {
		if (mmc_attach_sdio(host, ocr))
			mmc_power_off(host);
		goto out;
	}

	/*
	 * ...then normal SD...
	 */
	err = mmc_send_app_op_cond(host, 0, &ocr); //檢測是否是支援标準的SD卡.
	if (!err) {
		if (mmc_attach_sd(host, ocr))
			mmc_power_off(host);
		goto out;
	}

	/*
	 * ...and finally MMC.
	 */
	err = mmc_send_op_cond(host, 0, &ocr); //最後才是檢測是否是支援MMC的卡
	if (!err) {
		if (mmc_attach_mmc(host, ocr))
			mmc_power_off(host);
		goto out;
	}

	mmc_release_host(host);
	mmc_power_off(host);

out:
	if (host->caps & MMC_CAP_NEEDS_POLL)
		mmc_schedule_delayed_work(&host->detect, HZ);
}
           
  1. MMC/SD卡驅動程式的重要函數mmc_add_host,用于挂載一個mmc_host到核心,定義在host.c中:

[plain] view plain copy print ?

  1. int mmc_add_host(struct mmc_host *host)  
  2. {  
  3.     int err;  
  4.     WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&  
  5.         !host->ops->enable_sdio_irq);  
  6.     led_trigger_register_simple(dev_name(&host->class_dev), &host->led);  
  7.     err = device_add(&host->class_dev);  
  8.     if (err)  
  9.         return err;  
  10. #ifdef CONFIG_DEBUG_FS  
  11.     mmc_add_host_debugfs(host);  
  12. #endif  
  13.     mmc_start_host(host);  
  14.     return 0;  
  15. }  
linux2.6核心SD Card Driver詳細解析之一
int mmc_add_host(struct mmc_host *host)
{
	int err;

	WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
		!host->ops->enable_sdio_irq);

	led_trigger_register_simple(dev_name(&host->class_dev), &host->led);

	err = device_add(&host->class_dev);
	if (err)
		return err;

#ifdef CONFIG_DEBUG_FS
	mmc_add_host_debugfs(host);
#endif

	mmc_start_host(host);

	return 0;
}
           

可以從SD卡平台驅動看到上面函數的調用情況: static int __devinit s3cmci_probe(struct platform_device *pdev)

{

    struct s3cmci_host *host;

    //執行個體一個名為mmc的結構體指針,用于與Core核心層中的mmc_host結構體指針相關聯

    struct mmc_host    *mmc;

    int ret;

    spin_lock_init(&host->complete_lock);

    //配置設定mmc_host結構體指針的記憶體空間大小,該函數在host.c中實作,這裡要注意一點,為什麼參數

    //是s3cmci_host結構體的大小,到host.c中看,實際這裡配置設定的是mmc_host加s3cmci_host的大小。

    mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);

    if (!mmc) 

    {

        ret = -ENOMEM;

        goto probe_out;

    }

    //調用mmc_priv函數将mmc_host和s3cmci_host結構體的對象關聯起來,mmc_priv定義在host.h中

    host = mmc_priv(mmc);

    //下面就開始初始化s3cmci_host結構體的各成員

    host->mmc     = mmc;

    host->pdev    = pdev;

    host->pdata   = pdev->dev.platform_data;   

    ..................................

    ..................................

    ..................................

    //下面對mmc_host進行初始化

    mmc->ops       = &s3cmci_ops;    //SDI主機控制器操作結構體

    mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;   //設定工作電壓範圍

    mmc->caps      = MMC_CAP_4_BIT_DATA;              //設定總線寬度為4位

    mmc->f_min     = host->clk_rate / (host->clk_div * 256); //設定最小工作頻率

    mmc->f_max     = host->clk_rate / host->clk_div;  //設定最大工作頻率

    mmc->max_blk_count  = 4095;

    mmc->max_blk_size   = 4095;

    mmc->max_req_size   = 4095 * 512;

    mmc->max_seg_size   = mmc->max_req_size;

    mmc->max_phys_segs  = 128;

    mmc->max_hw_segs    = 128;

    //将SDI host裝置注冊到系統中

    ret = mmc_add_host(mmc);

    if (ret) 

    {

        dev_err(&pdev->dev, "failed to add mmc host./n");

        goto free_cpufreq;

    }

    //将SDI host裝置的資料指派給系統平台裝置

    platform_set_drvdata(pdev, mmc);

    return 0;

   ..................................

   ..................................

   ..................................

 probe_free_host:

    mmc_free_host(mmc);

 probe_out:

    return ret;

}

未完待續.............................

繼續閱讀