drivers/platform/x86/intel/vbtn.c

Source file repositories/reference/linux-study-clean/drivers/platform/x86/intel/vbtn.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/x86/intel/vbtn.c
Extension
.c
Size
11568 bytes
Lines
398
Domain
Driver Families
Bucket
drivers/platform
Inferred role
Driver Families: implementation source
Status
source 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

struct intel_vbtn_priv {
	struct mutex mutex; /* Avoid notify_handler() racing with itself */
	struct input_dev *buttons_dev;
	struct input_dev *switches_dev;
	bool dual_accel;
	bool has_buttons;
	bool has_switches;
	bool wakeup_mode;
};

static void detect_tablet_mode(struct device *dev)
{
	struct intel_vbtn_priv *priv = dev_get_drvdata(dev);
	acpi_handle handle = ACPI_HANDLE(dev);
	unsigned long long vgbs;
	acpi_status status;
	int m;

	status = acpi_evaluate_integer(handle, "VGBS", NULL, &vgbs);
	if (ACPI_FAILURE(status))
		return;

	m = !(vgbs & VGBS_TABLET_MODE_FLAGS);
	input_report_switch(priv->switches_dev, SW_TABLET_MODE, m);
	m = (vgbs & VGBS_DOCK_MODE_FLAG) ? 1 : 0;
	input_report_switch(priv->switches_dev, SW_DOCK, m);

	input_sync(priv->switches_dev);
}

/*
 * Note this unconditionally creates the 2 input_dev-s and sets up
 * the sparse-keymaps. Only the registration is conditional on
 * have_buttons / have_switches. This is done so that the notify
 * handler can always call sparse_keymap_entry_from_scancode()
 * on the input_dev-s do determine the event type.
 */
static int intel_vbtn_input_setup(struct platform_device *device)
{
	struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
	int ret;

	priv->buttons_dev = devm_input_allocate_device(&device->dev);
	if (!priv->buttons_dev)
		return -ENOMEM;

	ret = sparse_keymap_setup(priv->buttons_dev, intel_vbtn_keymap, NULL);
	if (ret)
		return ret;

	priv->buttons_dev->dev.parent = &device->dev;
	priv->buttons_dev->name = "Intel Virtual Buttons";
	priv->buttons_dev->id.bustype = BUS_HOST;

	if (priv->has_buttons) {
		ret = input_register_device(priv->buttons_dev);
		if (ret)
			return ret;
	}

	priv->switches_dev = devm_input_allocate_device(&device->dev);
	if (!priv->switches_dev)
		return -ENOMEM;

	ret = sparse_keymap_setup(priv->switches_dev, intel_vbtn_switchmap, NULL);
	if (ret)
		return ret;

	priv->switches_dev->dev.parent = &device->dev;
	priv->switches_dev->name = "Intel Virtual Switches";
	priv->switches_dev->id.bustype = BUS_HOST;

	if (priv->has_switches) {
		ret = input_register_device(priv->switches_dev);
		if (ret)
			return ret;
	}

	return 0;
}

static void notify_handler(acpi_handle handle, u32 event, void *context)
{
	struct platform_device *device = context;
	struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
	unsigned int val = !(event & 1); /* Even=press, Odd=release */
	const struct key_entry *ke, *ke_rel;
	struct input_dev *input_dev;
	bool autorelease;
	int ret;

Annotation

Implementation Notes