参考http://blog.csdn.net/wavemcu/article/details/7366852
//
/
///
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卡的硬件接口电路。
四.中SD/MMC设备驱动流程
4.1.MMC子系统的基本框架
4.1.1.MMC子系统的代码在kernel/driver/MMC下面,目前MMC子系统支持一些形式的记忆卡:SD,SDIO,MMC。
4.1.2.HOST:针对不同主机的驱动程序,这一部分需要根据自己的特定平台来完成。
4.1.3.CORE:这是整个MMC的核心层,这部分完成了不同协议和规范的实现,并且为HOST层的驱动提供接口函数。
4.1.4.CARD:因为这些记忆卡都是块设备,当然需要提供块设备的驱动程序,这部分就是实现了将SD卡如何实现为块设备的。
drivers/mmc/core/core.c
//子系统初始化
subsys_initcall(mmc_init);
module_exit(mmc_exit);
//drivers/mmc/core/core.c
static void __exit mmc_exit(void)
{
sdio_unregister_bus();
mmc_unregister_host_class();
mmc_unregister_bus();
destroy_workqueue(workqueue);
}
drivers/mmc/core/core.c
static int __init mmc_init(void)
{
int ret;
//用于创建workqueue,只创建一个内核线程的工作队列
workqueue = create_singlethread_workqueue(“kmmcd”);
if (!workqueue)
return -ENOMEM;
//总线类型 mmc_bus_type注册(SD/MMC)
ret = mmc_register_bus();注册总线
if (ret)
goto destroy_workqueue;
为控制器设备注册一个类mmc_host_class
ret = mmc_register_host_class();
if (ret)
goto unregister_bus;
//总线类型 sdio_bus_type注册(SDIO)
ret = sdio_register_bus();
if (ret)
goto unregister_host_class;
return 0;
unregister_host_class:
mmc_unregister_host_class();
unregister_bus:
mmc_unregister_bus();
destroy_workqueue:
destroy_workqueue(workqueue);
return ret;
}
drivers/mmc/core/bus.c
int mmc_register_bus(void)
{
//总线类型 mmc_bus_type注册(SD/MMC)
return bus_register(&mmc_bus_type);
}
/
drivers/mmc/core/bus.c
static struct bus_type mmc_bus_type = {
.name = “mmc”,
.dev_attrs = mmc_dev_attrs,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
.suspend = mmc_bus_suspend,
.resume = mmc_bus_resume,
};
/
static ssize_t mmc_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mmc_card *card = dev_to_mmc_card(dev);
//看看是如何区分出是MMC,SD,SDIO卡的。
switch (card->type) {
case MMC_TYPE_MMC:
return sprintf(buf, “MMC\n”);
case MMC_TYPE_SD:
return sprintf(buf, “SD\n”);
case MMC_TYPE_SDIO:
return sprintf(buf, “SDIO\n”);
default:
return -EFAULT;
}
}
//static struct bus_type mmc_bus_type里的 .dev_attrs = mmc_dev_attrs,
static struct device_attribute mmc_dev_attrs[] = {
__ATTR(type, S_IRUGO, mmc_type_show, NULL),
__ATTR_NULL,
};
//
//
mmc_host_class
/
driver/mmc/core/host.c
int mmc_register_host_class(void)
{
return class_register(&mmc_host_class);
}
//
static struct class mmc_host_class = {
.name = “mmc_host”,
.dev_release = mmc_host_classdev_release,
};
//driver/mmc/core/host.c
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
kfree(host);
}
//
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
//
include/linux/mmc/host.h
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_ON_BOARD (1 << 7) / Do not need to rescan after bootup /
#define MMC_CAP_BOOT_ONTHEFLY (1 << 8) / Can detect device at boot time /
/ 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
struct mmc_card card; / device attached to this host */
wait_queue_head_t wq;
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;
#ifdef CONFIG_LEDS_TRIGGERS
struct led_trigger led; / activity led */
#endif
struct dentry *debugfs_root;
unsigned long private[0] ____cacheline_aligned;
};
/
end mmc_host_class
/
sdio_bus_type
drivers/mmc/core/sdio_bus.c
int sdio_register_bus(void)
{
//总线类型 sdio_bus_type注册(SDIO)
return bus_register(&sdio_bus_type);
}
//drivers/mmc/core/sdio_bus.c
static struct bus_type sdio_bus_type = {
.name = “sdio”,
.dev_attrs = sdio_dev_attrs,
.match = sdio_bus_match,
.uevent = sdio_bus_uevent,
.probe = sdio_bus_probe,
.remove = sdio_bus_remove,
};
/
end sdio_bus_type
本结构表述一张MMC卡
/*
-
MMC device
*/
struct mmc_card {
//隶属的mmc控制器
struct mmc_host host; / the host this device belongs to /
//当前设备
struct device dev; / the device /
//卡地址
unsigned int rca; / relative card address of device /
//卡类型
unsigned int type; / card type /
#define MMC_TYPE_MMC 0 / MMC card /
#define MMC_TYPE_SD 1 / SD card /
#define MMC_TYPE_SDIO 2 / SDIO card /
//卡状态
unsigned int state; / (our) card state /
#define MMC_STATE_PRESENT (1<<0) / present in sysfs /
#define MMC_STATE_READONLY (1<<1) / card is read-only /
#define MMC_STATE_HIGHSPEED (1<<2) / card is in high speed mode /
#define MMC_STATE_BLOCKADDR (1<<3) / card uses block-addressing /
//卡CID 未解码
u32 raw_cid[4]; / raw card CID /
//卡CSD 未解码
u32 raw_csd[4]; / raw card CSD /
//卡SCR 未解码
u32 raw_scr[2]; / raw card SCR /
//卡 身份 已解码
struct mmc_cid cid; / card identification /
//卡的特殊数据 已解码
struct mmc_csd csd; / card specific /
struct mmc_ext_csd ext_csd; / mmc v4 extended card specific /
//额外的SD卡数据 已解码
struct sd_scr scr; / extra SD information /
struct sd_switch_caps sw_caps; / switch (CMD6) caps */unsigned int sdio_funcs; /* number of SDIO functions /
struct sdio_cccr cccr; / common card info /
struct sdio_cis cis; / common tuple info */
struct sdio_func sdio_func[SDIO_MAX_FUNCS]; / SDIO functions (devices) /
unsigned num_info; / number of info strings */
const char *info; / info strings */
struct sdio_func_tuple tuples; / unknown common tuples */struct dentry *debugfs_root;
};
/
/*
- MMC device driver (e.g., Flash card, I/O card…)
*/
struct mmc_driver {
struct device_driver drv;
int (*probe)(struct mmc_card *);
void (*remove)(struct mmc_card *);
int (*suspend)(struct mmc_card *, pm_message_t);
int (*resume)(struct mmc_card *);
};
///