drivers/platform/wmi/core.c

Source file repositories/reference/linux-study-clean/drivers/platform/wmi/core.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/wmi/core.c
Extension
.c
Size
40264 bytes
Lines
1606
Domain
Driver Families
Bucket
drivers/platform
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 const struct bus_type wmi_bus_type;

static const struct device_type wmi_type_event;

static const struct device_type wmi_type_method;

static int wmi_device_enable(struct wmi_device *wdev, bool enable)
{
	struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
	char method[WMI_ACPI_METHOD_NAME_SIZE];
	acpi_handle handle;
	acpi_status status;

	if (wblock->dev.dev.type == &wmi_type_method)
		return 0;

	if (wblock->dev.dev.type == &wmi_type_event) {
		/*
		 * Windows always enables/disables WMI events, even when they are
		 * not marked as being expensive. We follow this behavior for
		 * compatibility reasons.
		 */
		snprintf(method, sizeof(method), "WE%02X", wblock->gblock.notify_id);
	} else {
		if (!(wblock->gblock.flags & ACPI_WMI_EXPENSIVE))
			return 0;

		get_acpi_method_name(wblock, 'C', method);
	}

	/*
	 * Not all WMI devices marked as expensive actually implement the
	 * necessary ACPI method. Ignore this missing ACPI method to match
	 * the behaviour of the Windows driver.
	 */
	status = acpi_get_handle(wblock->acpi_device->handle, method, &handle);
	if (ACPI_FAILURE(status))
		return 0;

	status = acpi_execute_simple_method(handle, NULL, enable);
	if (ACPI_FAILURE(status))
		return -EIO;

	return 0;
}

static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
{
	struct device *dev;
	guid_t guid;
	int ret;

	ret = guid_parse(guid_string, &guid);
	if (ret < 0)
		return ERR_PTR(ret);

	dev = bus_find_device(&wmi_bus_type, NULL, &guid, wmidev_match_guid);
	if (!dev)
		return ERR_PTR(-ENODEV);

	return to_wmi_device(dev);
}

static void wmi_device_put(struct wmi_device *wdev)
{
	put_device(&wdev->dev);
}

/*
 * Exported WMI functions
 */

/**
 * wmi_instance_count - Get number of WMI object instances
 * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
 *
 * Get the number of WMI object instances.
 *
 * Returns: Number of WMI object instances or negative error code.
 */
int wmi_instance_count(const char *guid_string)
{
	struct wmi_device *wdev;
	int ret;

	wdev = wmi_find_device_by_guid(guid_string);
	if (IS_ERR(wdev))
		return PTR_ERR(wdev);

	ret = wmidev_instance_count(wdev);

Annotation

Implementation Notes