drivers/rpmsg/rpmsg_core.c

Source file repositories/reference/linux-study-clean/drivers/rpmsg/rpmsg_core.c

File Facts

System
Linux kernel
Corpus path
drivers/rpmsg/rpmsg_core.c
Extension
.c
Size
17658 bytes
Lines
639
Domain
Driver Families
Bucket
drivers/rpmsg
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 rpmsg_dev_match(struct device *dev, const struct device_driver *drv)
{
	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
	const struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
	const struct rpmsg_device_id *ids = rpdrv->id_table;
	unsigned int i;
	int ret;

	ret = device_match_driver_override(dev, drv);
	if (ret >= 0)
		return ret;

	if (ids)
		for (i = 0; ids[i].name[0]; i++)
			if (rpmsg_id_match(rpdev, &ids[i])) {
				rpdev->id.driver_data = ids[i].driver_data;
				return 1;
			}

	return of_driver_match_device(dev, drv);
}

static int rpmsg_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
	const struct rpmsg_device *rpdev = to_rpmsg_device(dev);
	int ret;

	ret = of_device_uevent_modalias(dev, env);
	if (ret != -ENODEV)
		return ret;

	return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
					rpdev->id.name);
}

/*
 * when an rpmsg driver is probed with a channel, we seamlessly create
 * it an endpoint, binding its rx callback to a unique local rpmsg
 * address.
 *
 * if we need to, we also announce about this channel to the remote
 * processor (needed in case the driver is exposing an rpmsg service).
 */
static int rpmsg_dev_probe(struct device *dev)
{
	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
	struct rpmsg_channel_info chinfo = {};
	struct rpmsg_endpoint *ept = NULL;
	int err;

	err = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON |
					PD_FLAG_DETACH_POWER_OFF);
	if (err)
		goto out;

	if (rpdrv->callback) {
		strscpy(chinfo.name, rpdev->id.name, sizeof(chinfo.name));
		chinfo.src = rpdev->src;
		chinfo.dst = RPMSG_ADDR_ANY;

		ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo);
		if (!ept) {
			dev_err(dev, "failed to create endpoint\n");
			err = -ENOMEM;
			goto out;
		}

		rpdev->ept = ept;
		rpdev->src = ept->addr;

		ept->flow_cb = rpdrv->flowcontrol;
	}

	err = rpdrv->probe(rpdev);
	if (err) {
		dev_err(dev, "%s: failed: %d\n", __func__, err);
		goto destroy_ept;
	}

	if (ept && rpdev->ops->announce_create) {
		err = rpdev->ops->announce_create(rpdev);
		if (err) {
			dev_err(dev, "failed to announce creation\n");
			goto remove_rpdev;
		}
	}

	return 0;

Annotation

Implementation Notes