drivers/mmc/core/sdio_bus.c

Source file repositories/reference/linux-study-clean/drivers/mmc/core/sdio_bus.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/core/sdio_bus.c
Extension
.c
Size
10251 bytes
Lines
424
Domain
Driver Families
Bucket
drivers/mmc
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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

	if (sdio_match_device(func, sdrv))
		return 1;

	return 0;
}

static int
sdio_bus_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
	const struct sdio_func *func = dev_to_sdio_func(dev);
	unsigned int i;

	if (add_uevent_var(env,
			"SDIO_CLASS=%02X", func->class))
		return -ENOMEM;

	if (add_uevent_var(env,
			"SDIO_ID=%04X:%04X", func->vendor, func->device))
		return -ENOMEM;

	if (add_uevent_var(env,
			"SDIO_REVISION=%u.%u", func->major_rev, func->minor_rev))
		return -ENOMEM;

	for (i = 0; i < func->num_info; i++) {
		if (add_uevent_var(env, "SDIO_INFO%u=%s", i+1, func->info[i]))
			return -ENOMEM;
	}

	if (add_uevent_var(env,
			"MODALIAS=sdio:c%02Xv%04Xd%04X",
			func->class, func->vendor, func->device))
		return -ENOMEM;

	return 0;
}

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);
	if (!id)
		return -ENODEV;

	ret = dev_pm_domain_attach(dev, 0);
	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);
	if (mmc_card_removed(func->card))
		ret = -ENOMEDIUM;
	else
		ret = sdio_set_block_size(func, 0);
	sdio_release_host(func);
	if (ret)
		goto disable_runtimepm;

	ret = drv->probe(func, id);
	if (ret)
		goto disable_runtimepm;

	return 0;

disable_runtimepm:
	atomic_dec(&func->card->sdio_funcs_probed);

Annotation

Implementation Notes