零、說明 對應代碼drivers/mmc/core/bus.c。 抽象出虛擬mmc bus,實現mmc bus的操作。 一、API總覽 1、mmc bus相關 mmc_register_bus & mmc_unregister_bus 用於註冊和卸載mmc bus(虛擬mmc匯流排)到設備驅動模型中。 ...
零、說明
對應代碼drivers/mmc/core/bus.c。
抽象出虛擬mmc bus,實現mmc bus的操作。
一、API總覽
1、mmc bus相關
- mmc_register_bus & mmc_unregister_bus
用於註冊和卸載mmc bus(虛擬mmc匯流排)到設備驅動模型中。
原型: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之間的關聯。
原型: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上。
原型:int mmc_add_card(struct mmc_card *card)
原型:void mmc_remove_card(struct mmc_card *card)
二、數據結構
1、mmc_bus_type
mmc_bus_type代表了mmc虛擬匯流排。其內容如下:
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匯流排)到設備驅動模型中。
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。
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之間的關聯。
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上。
/*
* 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 SPI\n",
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 %04x\n",
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: %d\n",
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: %d\n",
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;
}
相關節點:
/sys/bus/mmc/devices/mmc0:0001
/sys/class/mmc_host/mmc0/mmc0:0001
/sys/kernel/debug/mmc0/mmc0:0001