MMC:MMC就是 MultiMediaCard 的缩写,即多媒体卡
SD:SD卡为Secure Digital Memory Card, 即安全数码卡,(另TF卡又称microSD)
SDIO:SDIO是在SD标准上定义了一种外设接口
MCI:MCI是Multimedia Card Interface的简称,即多媒体卡接口。上述的MMC,SD,SDI卡定义的接口都属于MCI接口
SD卡引脚:
一根指令线CMD,4根数据线DAT0~DAT3,一个 SDCARD_DET_N 检测引脚。
MMC driver有3个层次,包括card,core和host layer。这三个层次的源码在以下的目录下:
kernel/drivers/mmc
我们可以看makefile来确定哪些文件被编译了。
各个目录的功能:
- core:提供了mmc_bus、sdio_bus以及mmc和sd卡的操作的实现代码;
- host:基于硬件平台的emmc controller的驱动代码;
- card:对块操作封装的驱动;
MMC bus
在core/core.c
中的mmc_init
函数中注册了mmc_bus 和 sdio bus:
static int __init mmc_init(void)
{
int ret;
workqueue = alloc_ordered_workqueue("kmmcd", 0);
if (!workqueue)
return -ENOMEM;
ret = mmc_register_bus();//注册mmc bus
if (ret)
goto destroy_workqueue;
ret = mmc_register_host_class();//创建/sys/class/mmc_host节点
if (ret)
goto unregister_bus;
ret = sdio_register_bus();//注册sdio 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;
}
mmc_register_bus
在bus.c 文件中:
int mmc_register_bus(void)
{
return bus_register(&mmc_bus_type);
}
该函数向总线注册了mmc总线,结构体是mmc_bus_type
:
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,
.shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
mmc_dev_attrs
注册了一个type接口,可以返回当前卡的类型:mmc、SD、SDIO、SDcombo,
static ssize_t mmc_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mmc_card *card = mmc_dev_to_card(dev);
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");
case MMC_TYPE_SD_COMBO:
return sprintf(buf, "SDcombo\n");
default:
return -EFAULT;
}
}
static struct device_attribute mmc_dev_attrs[] = {
__ATTR(type, S_IRUGO, mmc_type_show, NULL),
__ATTR_NULL,
};
mmc_bus_match
是总线匹配函数,一直返回1:
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
mmc_bus_uevent
当卡拔插等事件发生的时候,内核向用户空间发送事件,使得用户空间可以动态加载驱动模块:
static int
mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct mmc_card *card = mmc_dev_to_card(dev);
const char *type;
int retval = 0;
switch (card->type) {
case MMC_TYPE_MMC:
type = "MMC";
break;
case MMC_TYPE_SD:
type = "SD";
break;
case MMC_TYPE_SDIO:
type = "SDIO";
break;
case MMC_TYPE_SD_COMBO:
type = "SDcombo";
break;
default:
type = NULL;
}
if (type) {
retval = add_uevent_var(env, "MMC_TYPE=%s", type);
if (retval)
return retval;
}
retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
if (retval)
return retval;
/*
* Request the mmc_block device. Note: that this is a direct request
* for the module it carries no information as to what is inserted.
*/
retval = add_uevent_var(env, "MODALIAS=mmc:block");
return retval;
}
mmc_bus_probe
调用driver的probe 函数:
static int mmc_bus_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
return drv->probe(card);
}
mmc_bus_remove
remove bus:
static int mmc_bus_remove(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
drv->remove(card);
return 0;
}
mmc_bus_shutdown
调用driver的shutdown 函数:
static void mmc_bus_shutdown(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
if (!drv) {
pr_debug("%s: %s: drv is NULL\n", dev_name(dev), __func__);
return;
}
if (!card) {
pr_debug("%s: %s: card is NULL\n", dev_name(dev), __func__);
return;
}
if (drv->shutdown)
drv->shutdown(card);
}