drivers/hv/vmbus_drv.c

Source file repositories/reference/linux-study-clean/drivers/hv/vmbus_drv.c

File Facts

System
Linux kernel
Corpus path
drivers/hv/vmbus_drv.c
Extension
.c
Size
84087 bytes
Lines
3072
Domain
Driver Families
Bucket
drivers/hv
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 ssize_t hibernation_show(const struct bus_type *bus, char *buf)
{
	return sprintf(buf, "%d\n", !!hv_is_hibernation_supported());
}

static BUS_ATTR_RO(hibernation);

static struct attribute *vmbus_bus_attrs[] = {
	&bus_attr_hibernation.attr,
	NULL,
};
static const struct attribute_group vmbus_bus_group = {
	.attrs = vmbus_bus_attrs,
};
__ATTRIBUTE_GROUPS(vmbus_bus);

/*
 * vmbus_uevent - add uevent for our device
 *
 * This routine is invoked when a device is added or removed on the vmbus to
 * generate a uevent to udev in the userspace. The udev will then look at its
 * rule and the uevent generated here to load the appropriate driver
 *
 * The alias string will be of the form vmbus:guid where guid is the string
 * representation of the device guid (each byte of the guid will be
 * represented with two hex characters.
 */
static int vmbus_uevent(const struct device *device, struct kobj_uevent_env *env)
{
	const struct hv_device *dev = device_to_hv_device(device);
	const char *format = "MODALIAS=vmbus:%*phN";

	return add_uevent_var(env, format, UUID_SIZE, &dev->dev_type);
}

static const struct hv_vmbus_device_id *
hv_vmbus_dev_match(const struct hv_vmbus_device_id *id, const guid_t *guid)
{
	if (id == NULL)
		return NULL; /* empty device table */

	for (; !guid_is_null(&id->guid); id++)
		if (guid_equal(&id->guid, guid))
			return id;

	return NULL;
}

static const struct hv_vmbus_device_id *
hv_vmbus_dynid_match(struct hv_driver *drv, const guid_t *guid)
{
	const struct hv_vmbus_device_id *id = NULL;
	struct vmbus_dynid *dynid;

	spin_lock(&drv->dynids.lock);
	list_for_each_entry(dynid, &drv->dynids.list, node) {
		if (guid_equal(&dynid->id.guid, guid)) {
			id = &dynid->id;
			break;
		}
	}
	spin_unlock(&drv->dynids.lock);

	return id;
}

static const struct hv_vmbus_device_id vmbus_device_null;

/*
 * Return a matching hv_vmbus_device_id pointer.
 * If there is no match, return NULL.
 */
static const struct hv_vmbus_device_id *hv_vmbus_get_id(const struct hv_driver *drv,
							struct hv_device *dev)
{
	const guid_t *guid = &dev->dev_type;
	const struct hv_vmbus_device_id *id;
	int ret;

	/* If a driver override is set, only bind to the matching driver */
	ret = device_match_driver_override(&dev->device, &drv->driver);
	if (ret == 0)
		return NULL;

	/* Look at the dynamic ids first, before the static ones */
	id = hv_vmbus_dynid_match((struct hv_driver *)drv, guid);
	if (!id)
		id = hv_vmbus_dev_match(drv->id_table, guid);

	/*

Annotation

Implementation Notes