基于QualComm的mmc driver解析(Kernel-3.10)——(1)mmc bus

来源:互联网 发布:linux禅道启动命令 编辑:程序博客网 时间:2024/05/18 01:26

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,};
  1. 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,};
  1. mmc_bus_match 是总线匹配函数,一直返回1:
static int mmc_bus_match(struct device *dev, struct device_driver *drv){    return 1;}
  1. mmc_bus_uevent 当卡拔插等事件发生的时候,内核向用户空间发送事件,使得用户空间可以动态加载驱动模块:
static intmmc_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;}
  1. 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);}
  1. 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;}
  1. 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);}
0 0