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

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

 



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.
From e6c31f7bcc54fea317bebc34945e8ccd03b1fbe5 Mon Sep 17 00:00:00 2001
From: Jan-Michael Brummer <jan.brummer@xxxxxxxxx>
Date: Wed, 5 Aug 2015 02:07:11 +0200
Subject: [PATCH] dell venue 11 pro: add support for power button handling

---
 drivers/platform/x86/Kconfig              |   6 +
 drivers/platform/x86/Makefile             |   1 +
 drivers/platform/x86/dv11p_power_button.c | 196 ++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+)
 create mode 100644 drivers/platform/x86/dv11p_power_button.c

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 6dc13e4..041a302 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -919,4 +919,10 @@ config INTEL_PMC_IPC
 	The PMC is an ARC processor which defines IPC commands for communication
 	with other entities in the CPU.
 
+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 dda95a9..a69e511 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -60,3 +60,4 @@ obj-$(CONFIG_INTEL_SMARTCONNECT)	+= intel-smartconnect.o
 obj-$(CONFIG_PVPANIC)           += pvpanic.o
 obj-$(CONFIG_ALIENWARE_WMI)	+= alienware-wmi.o
 obj-$(CONFIG_INTEL_PMC_IPC)	+= intel_pmc_ipc.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);
-- 
2.5.0


[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