Re: Powerbutton not detected/handled on Dell Venue 11 Pro (7140)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Today I have modified the patch slightly to apply to 4.4.1 kernel and
built a kernel with it applied - power button now works for me. The
patch is attached. I can probably make a similar one for master branch
and for earlier releases too, let me know what I should do. Thanks!

2016-02-03 19:04 GMT+03:00 Dmitry Sutyagin <f3flight@xxxxxxxxx>:
> Dear all,
>
> I am writing to ask for the attached patch to be reviewed and merged
> into linux kernel (preferably starting from 3.18 but at least for 4.4
> and up).
> The patch was created by Jan-Michael Brummer, I took it from here -
> https://bugzilla.kernel.org/show_bug.cgi?id=102281
>
> Please let me know if I can help in any way.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 1089eaa..c519d2e 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -944,4 +944,10 @@ config SURFACE_PRO3_BUTTON
 	depends on ACPI && INPUT
 	---help---
 	  This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3 tablet.
+
+config DV11P_POWER_BUTTON
+	tristate "Dell Venue 11 Pro Power Button Driver"
+	depends on ACPI
+	---help---
+	  This driver provides power button support for the Dell Venue 11 Pro tablet.
 endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 3ca78a3..338b0fc 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -62,3 +62,4 @@ obj-$(CONFIG_PVPANIC)           += pvpanic.o
 obj-$(CONFIG_ALIENWARE_WMI)	+= alienware-wmi.o
 obj-$(CONFIG_INTEL_PMC_IPC)	+= intel_pmc_ipc.o
 obj-$(CONFIG_SURFACE_PRO3_BUTTON)	+= surfacepro3_button.o
+obj-$(CONFIG_DV11P_POWER_BUTTON)	+= dv11p_power_button.o
diff --git a/drivers/platform/x86/dv11p_power_button.c b/drivers/platform/x86/dv11p_power_button.c
new file mode 100644
index 0000000..03250ae
--- /dev/null
+++ b/drivers/platform/x86/dv11p_power_button.c
@@ -0,0 +1,196 @@
+/*
+ * Power button support for Dell Venue 11 Pro
+ *
+ * (C) Copyright 2015 Jan-Michael Brummer
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/acpi.h>
+#include <acpi/button.h>
+
+#define DV11P_BUTTON_HID		"INT33D6"
+#define DV11P_BUTTON_CLASS		"button"
+#define DV11P_BUTTON_SUB_CLASS		"ec"
+#define DV11P_BUTTON_DEVICE_NAME	"EC"
+
+#define DV11P_BUTTON_NOTIFY_PRESS_POWER		0xc0
+#define DV11P_BUTTON_NOTIFY_RELEASE_POWER	0xc1
+
+ACPI_MODULE_NAME("dv11p power button");
+
+#define _COMPONENT              ACPI_BUTTON_COMPONENT
+
+MODULE_AUTHOR("Jan-Michael Brummer");
+MODULE_DESCRIPTION("Dell Venue 11 Pro Power Button Driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Power button are handled by EC
+ */
+static const struct acpi_device_id dv11p_power_button_device_ids[] = {
+	{DV11P_BUTTON_HID,    0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, dv11p_power_button_device_ids);
+
+static int dv11p_power_button_add(struct acpi_device *device);
+static int dv11p_power_button_remove(struct acpi_device *device);
+static void dv11p_power_button_notify(struct acpi_device *device, u32 event);
+
+#ifdef CONFIG_PM_SLEEP
+static int dv11p_power_button_suspend(struct device *dev);
+static int dv11p_power_button_resume(struct device *dev);
+#else
+#define dv11p_power_button_suspend NULL
+#define dv11p_power_button_resume NULL
+#endif
+
+static SIMPLE_DEV_PM_OPS(dv11p_power_button_pm,
+		dv11p_power_button_suspend, dv11p_power_button_resume);
+
+static struct acpi_driver dv11p_power_button_driver = {
+	.name = "dell venue 11 pro button",
+	.class = DV11P_BUTTON_CLASS,
+	.ids = dv11p_power_button_device_ids,
+	.ops = {
+		.add = dv11p_power_button_add,
+		.remove = dv11p_power_button_remove,
+		.notify = dv11p_power_button_notify,
+	},
+	.drv.pm = &dv11p_power_button_pm,
+};
+
+struct dv11p_power_button {
+	unsigned int type;
+	struct input_dev *input;
+	char phys[32];			/* for input device */
+	unsigned long pushed;
+	bool suspended;
+};
+
+static void dv11p_power_button_notify(struct acpi_device *device, u32 event)
+{
+	struct dv11p_power_button *button = acpi_driver_data(device);
+	struct input_dev *input;
+	int key_code = KEY_RESERVED, pressed = 0;
+
+	switch (event) {
+	case DV11P_BUTTON_NOTIFY_PRESS_POWER:
+		pressed = 1;
+	case DV11P_BUTTON_NOTIFY_RELEASE_POWER:
+		key_code = KEY_POWER;
+		break;
+
+	default:
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Unsupported event [0x%x]\n", event));
+		break;
+	}
+
+	input = button->input;
+
+	if (KEY_RESERVED == key_code)
+		return;
+
+	if (pressed)
+		pm_wakeup_event(&device->dev, 0);
+
+	if (button->suspended)
+		return;
+
+	input_report_key(input, key_code, pressed);
+	input_sync(input);
+
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dv11p_power_button_suspend(struct device *dev)
+{
+	struct acpi_device *device = to_acpi_device(dev);
+	struct dv11p_power_button *button = acpi_driver_data(device);
+
+	button->suspended = true;
+	return 0;
+}
+
+static int dv11p_power_button_resume(struct device *dev)
+{
+	struct acpi_device *device = to_acpi_device(dev);
+	struct dv11p_power_button *button = acpi_driver_data(device);
+
+	button->suspended = false;
+	return 0;
+}
+#endif
+
+static int dv11p_power_button_add(struct acpi_device *device)
+{
+	struct dv11p_power_button *button;
+	struct input_dev *input;
+	const char *hid = acpi_device_hid(device);
+	char *name, *class;
+	int error;
+
+	button = kzalloc(sizeof(struct dv11p_power_button), GFP_KERNEL);
+	if (!button)
+		return -ENOMEM;
+
+	device->driver_data = button;
+
+	button->input = input = input_allocate_device();
+	if (!input) {
+		error = -ENOMEM;
+		goto err_free_power_button;
+	}
+
+	name = acpi_device_name(device);
+	class = acpi_device_class(device);
+
+	strcpy(name, DV11P_BUTTON_DEVICE_NAME);
+	sprintf(class, "%s/%s",
+		DV11P_BUTTON_CLASS, DV11P_BUTTON_SUB_CLASS);
+
+	snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
+
+	input->name = name;
+	input->phys = button->phys;
+	input->id.bustype = BUS_HOST;
+	input->dev.parent = &device->dev;
+
+	input_set_capability(input, EV_KEY, KEY_POWER);
+
+
+	error = input_register_device(input);
+	if (error)
+		goto err_free_input;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+			"%s [%s]\n", name, acpi_device_bid(device)));
+	return 0;
+
+ err_free_input:
+	input_free_device(input);
+ err_free_power_button:
+	kfree(button);
+	return error;
+}
+
+static int dv11p_power_button_remove(struct acpi_device *device)
+{
+	struct dv11p_power_button *button = acpi_driver_data(device);
+
+	input_unregister_device(button->input);
+	kfree(button);
+	return 0;
+}
+
+module_acpi_driver(dv11p_power_button_driver);

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux