3. [mmc subsystem] mmc core(第三章)——bus模块说明

2019-05-25 18:30:24 浏览数 (1)

一、API总览

1、mmc bus相关

  • mmc_register_bus & mmc_unregister_bus

用于注册和卸载mmc bus(虚拟mmc总线)到设备驱动模型中。

代码语言:javascript复制
    原型:int mmc_register_bus(void)
    原型:void mmc_unregister_bus(void)

2、mmc driver相关

  • mmc_alloc_card & mmc_release_card

3、mmc card相关

  • mmc_alloc_card & mmc_release_card

用于分配或者释放一个struct mmc_card结构体,创建其于mmc host以及mmc bus之间的关联。

代码语言:javascript复制
原型:struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
    参数说明:host——》要分配的card所属的mmc_host,type——》对应的device type。

    原型:static void mmc_release_card(struct device *dev)
  • mmc_add_card & mmc_remove_card

用于注册或者卸载struct mmc_card到mmc_bus上。

代码语言:javascript复制
原型:int mmc_add_card(struct mmc_card *card)
原型:void mmc_remove_card(struct mmc_card *card)

二、数据结构

1、mmc_bus_type

mmc_bus_type代表了mmc虚拟总线。其内容如下:

代码语言:javascript复制
static struct bus_type mmc_bus_type = {
    .name       = "mmc",                        // 相应会在/sys/bus下生成mmc目录
    .dev_attrs  = mmc_dev_attrs,                  // bus下的device下继承的属性,可以看到/sys/bus/mmc/devices/mmc0:0001/type属性就是这里来的
    .match      = mmc_bus_match,       // 用于mmc bus上device和driver的匹配
    .uevent     = mmc_bus_uevent,
    .probe      = mmc_bus_probe,       // 当match成功的时候,执行的probe操作
    .remove     = mmc_bus_remove,
    .shutdown        = mmc_bus_shutdown,
    .pm     = &mmc_bus_pm_ops,         // 挂在mmc bus上的device的电源管理操作集合
};

/***************************match方法***************************/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
    return 1;      // 无条件返回1,说明挂载mmc bus上的device(mmc_card)和driver(mmc_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_driver中的probe操作,对于block.c来说就是mmc_blk_probe
}

补充说明,通过上述mmc_bus的match方法实现,我们可以知道挂载mmc bus上的mmc_card和mmc_driver是无条件匹配的。

三、接口代码说明

1、mmc_register_bus实现

用于注册mmc bus(虚拟mmc总线)到设备驱动模型中。

代码语言:javascript复制
int mmc_register_bus(void)
{
    return bus_register(&mmc_bus_type);    // 以mmc_bus_type为bus_type注册一条虚拟bus,关于mmc_bus_type上面已经说明过了
}

后续我们将mmc_bus_type的这条bus称之为mmc_bus。

相关节点:/sys/bus/mmc。

2、mmc_register_driver实现

用于注册struct mmc_driver *drv到mmc_bus上。mmc_driver就是mmc core抽象出来的card设备driver。

代码语言:javascript复制
int mmc_register_driver(struct mmc_driver *drv)
{
    drv->drv.bus = &mmc_bus_type;    // 通过设置mmc_driver——》device_driver——》bus_type来设置mmc_driver所属bus为mmc_bus
    return driver_register(&drv->drv);    // 这样就将mmc_driver挂在了mmc_bus上了。
}

相关节点:/sys/bus/mmc/drivers.

3、mmc_alloc_card实现

用于分配一个struct mmc_card结构体,创建其于mmc host以及mmc bus之间的关联。

代码语言:javascript复制
struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
{
    struct mmc_card *card;

    card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);    // 分配一个mmc_card
    if (!card)
        return ERR_PTR(-ENOMEM);

    card->host = host;        // 关联mmc_card与mmc_host 

    device_initialize(&card->dev);

    card->dev.parent = mmc_classdev(host);    
        // 设置card的device的parent device为mmc_host的classdev,
        // 注册到设备驱动模型中之后,会在/sys/class/mmc_host/mmc0目录下生成相应card的节点,如mmc0:0001
    card->dev.bus = &mmc_bus_type;
        // 设置card的bus为mmc_bus_type,这样,mmc_card注册到设备驱动模型中之后就会挂在mmc_bus下。
        // 会在/sys/bus/mmc/devices/目录下生成相应card的节点,如mmc0:0001
    card->dev.release = mmc_release_card;
    card->dev.type = type;    // 设置device type

    spin_lock_init(&card->bkops_info.bkops_stats.lock);    // 初始化spin_lock
    spin_lock_init(&card->wr_pack_stats.lock);                   // 初始化spin_lock

    return card;
}

4、mmc_add_card实现

用于注册struct mmc_card到mmc_bus上。

代码语言:javascript复制
/*
 * Register a new MMC card with the driver model.
 */
int mmc_add_card(struct mmc_card *card)
{
    int ret;

/* 以下用于打印card的注册信息 */
    const char *type;
    const char *uhs_bus_speed_mode = "";
        // 设置速度模式的字符串,为了后面打印出card信息
        //......

    if (mmc_host_is_spi(card->host)) {
        pr_info("%s: new %s%s%s card on SPIn",
            mmc_hostname(card->host),
            mmc_card_highspeed(card) ? "high speed " : "",
            mmc_card_ddr_mode(card) ? "DDR " : "",
            type);
    } else {
        pr_info("%s: new %s%s%s%s%s%s card at address xn",
            mmc_hostname(card->host),
            mmc_card_uhs(card) ? "ultra high speed " :
            (mmc_card_highspeed(card) ? "high speed " : ""),
            (mmc_card_hs400(card) ? "HS400 " : ""),
            (mmc_card_hs200(card) ? "HS200 " : ""),
            mmc_card_ddr_mode(card) ? "DDR " : "",
            uhs_bus_speed_mode, type, card->rca);
    }
        // 在这里会打印出card信息的字符串
        // eg:mmc0: new HS200 MMC card at address 0001

/* 设置card的debug节点 */
#ifdef CONFIG_DEBUG_FS
    mmc_add_card_debugfs(card);
        // 创建card对应的debug节点,对应路径例如:/sys/kernel/debug/mmc0/mmc0:0001
#endif
    mmc_init_context_info(card->host);   // 初始化同步的文本信息

/* 以下使能card device的pm runtime的功能 */
    ret = pm_runtime_set_active(&card->dev);   
    if (ret)
        pr_err("%s: %s: failed setting runtime active: ret: %dn",
               mmc_hostname(card->host), __func__, ret);
    else if (!mmc_card_sdio(card) && mmc_use_core_runtime_pm(card->host))
        pm_runtime_enable(&card->dev);

/* 添加到设备驱动模型中 */
    ret = device_add(&card->dev);
        // 会创建/sys/bus/mmc/devices/mmc0:0001节点和/sys/class/mmc_host/mmc0/mmc0:0001节点

/* 使能异步device suspend,初始化runtime_pm_timeout属性 */
    device_enable_async_suspend(&card->dev);
    if (mmc_use_core_runtime_pm(card->host) && !mmc_card_sdio(card)) {
        card->rpm_attrib.show = show_rpm_delay;
        card->rpm_attrib.store = store_rpm_delay;
        sysfs_attr_init(&card->rpm_attrib.attr);
        card->rpm_attrib.attr.name = "runtime_pm_timeout";
        card->rpm_attrib.attr.mode = S_IRUGO | S_IWUSR;

        ret = device_create_file(&card->dev, &card->rpm_attrib);
        if (ret)
            pr_err("%s: %s: creating runtime pm sysfs entry: failed: %dn",
                   mmc_hostname(card->host), __func__, ret);
        /* Default timeout is 10 seconds */
        card->idle_timeout = RUNTIME_SUSPEND_DELAY_MS;
    }

/* 设置mmc card的state标识 */
    mmc_card_set_present(card);
        // 设置card的MMC_STATE_PRESENT状态
        // #define MMC_STATE_PRESENT    (1<<0)      /* present in sysfs */
        // 表示card已经合入到sysfs中了

    return 0;
}

0 人点赞