Linux驱动——mmc bus浅析(五)

Linux驱动——mmc bus浅析(五)

备注:
  1. Kernel版本:5.4
  2. 使用工具:Source Insight 4.0
  3. 参考博客:
3. [mmc subsystem] mmc core(第三章)——bus模块说明

概述

对应代码

drivers/mmc/core/bus.c
drivers/mmc/core/sdio_bus.c

抽象出虚拟mmc/sdio bus,实现mmc/sdio bus的操作。

API预览

bus相关

  • mmc_register_bus & mmc_unregister_bus
    用于注册和卸载mmc bus(虚拟mmc总线)到设备驱动模型中。
int mmc_register_bus(void);
void mmc_unregister_bus(void);
  • sdio_register_bus & sdio_unregister_bus
int sdio_register_bus(void);
void sdio_unregister_bus(void);

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);
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);

数据结构

mmc bus数据结构

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

static struct bus_type mmc_bus_type = {
	.name		= "mmc",			// 相应会在/sys/bus下生成mmc目录
	// bus下的device下继承的属性,
	// 可以看到/sys/bus/mmc/devices/mmc0:0001/type属性就是这里来的
	.dev_groups	= mmc_dev_groups,
	.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的电源管理操作集合
};
  • mmc bus match方法
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
	// 无条件返回1,说明挂载mmc bus上的
	// device(mmc_card)和driver(mmc_driver)是无条件匹配的。
	return 1;
}
  • mmc bus 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);

	// 直接调用mmc_driver中的probe操作,
	// 对于block.c来说就是mmc_blk_probe
	return drv->probe(card);
}

sdio bus数据结构

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

static struct bus_type c = {
	.name		= "sdio",			// 相应会在/sys/bus下生成sdio目录
	.dev_groups	= sdio_dev_groups,
	.match		= sdio_bus_match,	// 用于sdio bus上device和driver的匹配
	.uevent		= sdio_bus_uevent,
	.probe		= sdio_bus_probe,	// 当match成功的时候,执行的probe操作
	.remove		= sdio_bus_remove,
	.pm		= &sdio_bus_pm_ops,		// 挂在sdio bus上的device的电源管理操作集合
};
  • sdio bus match方法
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
	const struct sdio_device_id *id)
{
	if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
		return NULL;
	if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
		return NULL;
	if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
		return NULL;
	return id;
}

static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
	struct sdio_driver *sdrv)
{
	const struct sdio_device_id *ids;

	// 获取sdio device 的ID table
	ids = sdrv->id_table;

	if (ids) {
		while (ids->class || ids->vendor || ids->device) {
			if (sdio_match_one(func, ids))//逐一排查class、vendor、device等ID
				return ids;
			ids++;
		}
	}

	return NULL;
}

static int sdio_bus_match(struct device *dev, struct device_driver *drv)
{
	struct sdio_func *func = dev_to_sdio_func(dev);
	struct sdio_driver *sdrv = to_sdio_driver(drv);

	// 通过id_table来匹配
	if (sdio_match_device(func, sdrv))
		return 1;

	return 0;
}
  • sdio bus probe方法
static int sdio_bus_probe(struct device *dev)
{
	struct sdio_driver *drv = to_sdio_driver(dev->driver);
	struct sdio_func *func = dev_to_sdio_func(dev);
	const struct sdio_device_id *id;
	int ret;

	id = sdio_match_device(func, drv);//获取sdio device id
	if (!id)
		return -ENODEV;

	ret = dev_pm_domain_attach(dev, false);
	if (ret)
		return ret;

	atomic_inc(&func->card->sdio_funcs_probed);

	/* Unbound SDIO functions are always suspended.
	 * During probe, the function is set active and the usage count
	 * is incremented.  If the driver supports runtime PM,
	 * it should call pm_runtime_put_noidle() in its probe routine and
	 * pm_runtime_get_noresume() in its remove routine.
	 */
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
		ret = pm_runtime_get_sync(dev);
		if (ret < 0)
			goto disable_runtimepm;
	}

	/* Set the default block size so the driver is sure it's something
	 * sensible. */
	sdio_claim_host(func);				// 获取host使用权
	if (mmc_card_removed(func->card))	// 移除card
		ret = -ENOMEDIUM;
	else
		ret = sdio_set_block_size(func, 0);
	sdio_release_host(func);			// 释放host使用权
	if (ret)
		goto disable_runtimepm;

	ret = drv->probe(func, id);			// 调用driver probe方法
	if (ret)
		goto disable_runtimepm;

	return 0;

disable_runtimepm:
	atomic_dec(&func->card->sdio_funcs_probed);
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
		pm_runtime_put_noidle(dev);
	dev_pm_domain_detach(dev, false);
	return ret;
}

核心接口实现

mmc_register_bus实现

int mmc_register_bus(void)
{
	return bus_register(&mmc_bus_type);
}

void mmc_unregister_bus(void)
{
	bus_unregister(&mmc_bus_type);
}

我们将mmc_bus_type的这条bus称之为mmc_bus。
相关节点:/sys/bus/mmc。

sdio_register_bus实现

int sdio_register_bus(void)
{
	return bus_register(&sdio_bus_type);
}

void sdio_unregister_bus(void)
{
	bus_unregister(&sdio_bus_type);
}

我们将sdio_bus_type的这条bus称之为sdio_bus。
相关节点:/sys/bus/sdio。

mmc_register_driver实现

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

/**
 *	mmc_register_driver - register a media driver
 *	@drv: MMC media driver
 */
int mmc_register_driver(struct mmc_driver *drv)
{
	drv->drv.bus = &mmc_bus_type;
	return driver_register(&drv->drv);
}

EXPORT_SYMBOL(mmc_register_driver);

/**C
 *	mmc_unregister_driver - unregister a media driver
 *	@drv: MMC media driver
 */
void mmc_unregister_driver(struct mmc_driver *drv)
{
	drv->drv.bus = &mmc_bus_type;
	driver_unregister(&drv->drv);
}

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

sdio_register_driver实现

int sdio_register_bus(void)
{
	return bus_register(&sdio_bus_type);
}

void sdio_unregister_bus(void)
{
	bus_unregister(&sdio_bus_type);
}

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

mmc_alloc_card实现

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

/*
 * Allocate and initialise a new MMC card structure.
 */
struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
{
	struct mmc_card *card;

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

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

	device_initialize(&card->dev);
	// 设置card的device的parent device为mmc_host的classdev,
	// 注册到设备驱动模型中之后,
	// 会在/sys/class/mmc_host/mmc0目录下生成相应card的节点,如mmc0:0001
	card->dev.parent = mmc_classdev(host);

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

	// 设置device type
	card->dev.type = type;

	return card;
}

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;
	const char *type;
	const char *uhs_bus_speed_mode = "";
	static const char *const uhs_speeds[] = {
		[UHS_SDR12_BUS_SPEED] = "SDR12 ",
		[UHS_SDR25_BUS_SPEED] = "SDR25 ",
		[UHS_SDR50_BUS_SPEED] = "SDR50 ",
		[UHS_SDR104_BUS_SPEED] = "SDR104 ",
		[UHS_DDR50_BUS_SPEED] = "DDR50 ",
	};


	// 配置card dev name,将体现在/sys/bus/mmc/device/mmcx:xxx上
	dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);

	// 匹配 card 类型
	switch (card->type) {
	case MMC_TYPE_MMC:
		type = "MMC";
		break;
	case MMC_TYPE_SD:
		type = "SD";
		if (mmc_card_blockaddr(card)) {
			if (mmc_card_ext_capacity(card))
				type = "SDXC";
			else
				type = "SDHC";
		}
		break;
	case MMC_TYPE_SDIO:
		type = "SDIO";
		break;
	case MMC_TYPE_SD_COMBO:
		type = "SD-combo";
		if (mmc_card_blockaddr(card))
			type = "SDHC-combo";
		break;
	default:
		type = "?";
		break;
	}

	if (mmc_card_uhs(card) &&
		(card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
		uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];

	// 打印 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_hs(card) ? "high speed " : "",
			mmc_card_ddr52(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_hs(card) ? "high speed " : ""),
			mmc_card_hs400(card) ? "HS400 " :
			(mmc_card_hs200(card) ? "HS200 " : ""),
			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
			mmc_card_ddr52(card) ? "DDR " : "",
			uhs_bus_speed_mode, type, card->rca);
	}

#ifdef CONFIG_DEBUG_FS
	// 创建card对应的debug节点,对应路径例如:/sys/kernel/debug/mmc0/mmc0:0001
	mmc_add_card_debugfs(card);
#endif
	card->dev.of_node = mmc_of_find_child_device(card->host, 0);

	device_enable_async_suspend(&card->dev);

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

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

	return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值