[PATCH 2/3] UBUNTU: Using event driving method hotkey function

Ike Panhc ike.pan at canonical.com
Thu Aug 27 15:00:43 UTC 2009


Event driving method hotkey function, the source of event comes from interrupt
of ACPI/EC

Signed-off-by: Ike Panhc <ike.pan at canonical.com>
---
 ubuntu/lenovo-sl-laptop/lenovo-sl-laptop.c |  196 ++++++++++++----------------
 1 files changed, 81 insertions(+), 115 deletions(-)

diff --git a/ubuntu/lenovo-sl-laptop/lenovo-sl-laptop.c b/ubuntu/lenovo-sl-laptop/lenovo-sl-laptop.c
index c09b5ba..d011d86 100644
--- a/ubuntu/lenovo-sl-laptop/lenovo-sl-laptop.c
+++ b/ubuntu/lenovo-sl-laptop/lenovo-sl-laptop.c
@@ -39,7 +39,6 @@
 #include <linux/platform_device.h>
 
 #include <linux/input.h>
-#include <linux/kthread.h>
 #include <linux/freezer.h>
 
 #include <linux/proc_fs.h>
@@ -894,11 +893,6 @@ static int hwmon_init(void)
     hotkeys
  *************************************************************************/
 
-static int hkey_poll_hz = 5;
-static u8 hkey_ec_prev_offset;
-static struct mutex hkey_poll_mutex;
-static struct task_struct *hkey_poll_task;
-
 struct key_entry {
 	char type;
 	u8 scancode;
@@ -984,128 +978,103 @@ static int hkey_inputdev_setkeycode(struct input_dev *dev, int scancode,
 	return -EINVAL;
 }
 
-static int hkey_ec_get_offset(void)
+static int hkey_action(void *data)
 {
-	/* Hotkey events are stored in EC registers 0x0A .. 0x11
-	 * Address of last event is stored in EC registers 0x12 and
-	 * 0x14; if address is 0x01, last event is in register 0x0A;
-	 * if address is 0x07, last event is in register 0x10;
-	 * if address is 0x00, last event is in register 0x11 */
-
-	u8 offset;
+	int keycode;
+	int level;
 
-	if (ec_read(0x12, &offset))
+	if (!data)
 		return -EINVAL;
-	if (!offset)
-		offset = 8;
-	offset -= 1;
-	if (offset > 7)
-		return -EINVAL;
-	return offset;
+	keycode = *(int *)data;
+
+	/* Special handling for brightness keys. We do it here and not
+	   via an ACPI notifier in order to prevent possible conflicts
+	   with video.c */
+	if (keycode == KEY_BRIGHTNESSDOWN) {
+		if (control_backlight && backlight) {
+			level = lensl_bd_get_brightness(backlight);
+			if (0 <= --level)
+				lensl_bd_set_brightness_int(level);
+		}
+	} else if (keycode == KEY_BRIGHTNESSUP) {
+		if (control_backlight && backlight) {
+			level = lensl_bd_get_brightness(backlight);
+			if (backlight_levels.count > ++level)
+				lensl_bd_set_brightness_int(level);
+		}
+	}
+
+	if (keycode != KEY_RESERVED) {
+		input_report_key(hkey_inputdev, keycode, 1);
+		input_sync(hkey_inputdev);
+		input_report_key(hkey_inputdev, keycode, 0);
+		input_sync(hkey_inputdev);
+	}
+
+	return 0;
 }
 
-static int hkey_poll_kthread(void *data)
+typedef int (*acpi_ec_query_func) (void *data);
+extern int acpi_ec_add_query_handler(void *ec, u8 query_bit, acpi_handle handle,
+	acpi_ec_query_func func, void *data);
+static int hkey_add(struct acpi_device *device)
 {
-	unsigned long t = 0;
-	int offset, level;
-	unsigned int keycode;
-	u8 scancode;
-
-	mutex_lock(&hkey_poll_mutex);
+	int result;
+	struct key_entry *key;
 
-	offset = hkey_ec_get_offset();
-	if (offset < 0) {
-		vdbg_printk(LENSL_WARNING,
-			"Failed to read hotkey register offset from EC\n");
-		hkey_ec_prev_offset = 0;
-	} else
-		hkey_ec_prev_offset = offset;
-
-	while (!kthread_should_stop() && hkey_poll_hz) {
-		if (t == 0)
-			t = 1000/hkey_poll_hz;
-		t = msleep_interruptible(t);
-		if (unlikely(kthread_should_stop()))
-			break;
-		try_to_freeze();
-		if (t > 0)
-			continue;
-		offset = hkey_ec_get_offset();
-		if (offset < 0) {
-			vdbg_printk(LENSL_WARNING,
-			   "Failed to read hotkey register offset from EC\n");
-			continue;
+	for (key = ec_keymap; key->type != KE_END; key++) {
+		result = acpi_ec_add_query_handler(
+			acpi_driver_data(device->parent),
+			key->scancode, NULL, hkey_action,
+			&(key->keycode));
+		if (result) {
+			vdbg_printk(LENSL_ERR,
+				"Failed to register hotkey notification.\n");
+			return -ENODEV;
 		}
-		if (offset == hkey_ec_prev_offset)
-			continue;
+	}
+	return 0;
+}
 
-		if (ec_read(0x0A + offset, &scancode)) {
-			vdbg_printk(LENSL_WARNING,
-				"Failed to read hotkey code from EC\n");
-			continue;
-		}
-		keycode = ec_scancode_to_keycode(scancode);
-		vdbg_printk(LENSL_DEBUG,
-		   "Got hotkey keycode %d (scancode %d)\n", keycode, scancode);
-
-		/* Special handling for brightness keys. We do it here and not
-		   via an ACPI notifier in order to prevent possible conflicts
-		   with video.c */
-		if (keycode == KEY_BRIGHTNESSDOWN) {
-			if (control_backlight && backlight) {
-				level = lensl_bd_get_brightness(backlight);
-				if (0 <= --level)
-					lensl_bd_set_brightness_int(level);
-			} else
-				keycode = KEY_RESERVED;
-		} else if (keycode == KEY_BRIGHTNESSUP) {
-			if (control_backlight && backlight) {
-				level = lensl_bd_get_brightness(backlight);
-				if (backlight_levels.count > ++level)
-					lensl_bd_set_brightness_int(level);
-			} else
-				keycode = KEY_RESERVED;
-		}
+extern void acpi_ec_remove_query_handler(void *ec, u8 query_bit);
+static int hkey_remove(struct acpi_device *device, int type)
+{
+	struct key_entry *key;
 
-		if (keycode != KEY_RESERVED) {
-			input_report_key(hkey_inputdev, keycode, 1);
-			input_sync(hkey_inputdev);
-			input_report_key(hkey_inputdev, keycode, 0);
-			input_sync(hkey_inputdev);
-		}
-		hkey_ec_prev_offset = offset;
+	for (key = ec_keymap; key->type != KE_END; key++) {
+		acpi_ec_remove_query_handler(acpi_driver_data(device->parent),
+			key->scancode);
 	}
-
-	mutex_unlock(&hkey_poll_mutex);
 	return 0;
 }
 
-static void hkey_poll_start(void)
+static const struct acpi_device_id hkey_ids[] = {
+	{"LEN0014", 0},
+	{"", 0},
+};
+
+static struct acpi_driver hkey_driver = {
+	.name = "lenovo-sl-laptop-hotkey",
+	.class = "lenovo",
+	.ids = hkey_ids,
+	.ops = {
+		.add = hkey_add,
+		.remove = hkey_remove,
+	},
+};
+
+static void hkey_register_notify(void)
 {
-	hkey_ec_prev_offset = 0;
-	mutex_lock(&hkey_poll_mutex);
-	hkey_poll_task = kthread_run(hkey_poll_kthread,
-		NULL, LENSL_HKEY_POLL_KTHREAD_NAME);
-	if (IS_ERR(hkey_poll_task)) {
-		hkey_poll_task = NULL;
-		vdbg_printk(LENSL_ERR,
-			"Could not create kernel thread for hotkey polling\n");
-	}
-	mutex_unlock(&hkey_poll_mutex);
+	int result;
+	result = acpi_bus_register_driver(&hkey_driver);
+	if (result)
+		vdbg_printk(LENSL_ERR, "Failed to register hotkey driver\n");
+	return;
 }
 
-static void hkey_poll_stop(void)
+static void hkey_unregister_notify(void)
 {
-	if (hkey_poll_task) {
-		if (frozen(hkey_poll_task) || freezing(hkey_poll_task))
-			thaw_process(hkey_poll_task);
-
-		kthread_stop(hkey_poll_task);
-		hkey_poll_task = NULL;
-		mutex_lock(&hkey_poll_mutex);
-		/* at this point, the thread did exit */
-		mutex_unlock(&hkey_poll_mutex);
-	}
+	acpi_bus_unregister_driver(&hkey_driver);
 }
 
 static void hkey_inputdev_exit(void)
@@ -1246,10 +1215,8 @@ static int __init lenovo_sl_laptop_init(void)
 	int ret;
 	acpi_status status;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
 	if (!acpi_video_backlight_support())
 		control_backlight = 1;
-#endif
 
 	hkey_handle = ec0_handle = NULL;
 
@@ -1295,8 +1262,7 @@ static int __init lenovo_sl_laptop_init(void)
 		backlight_init();
 
 	led_init();
-	mutex_init(&hkey_poll_mutex);
-	hkey_poll_start();
+	hkey_register_notify();
 	hwmon_init();
 
 	if (debug_ec)
@@ -1310,7 +1276,7 @@ static void __exit lenovo_sl_laptop_exit(void)
 {
 	lenovo_sl_procfs_exit();
 	hwmon_exit();
-	hkey_poll_stop();
+	hkey_unregister_notify();
 	led_exit();
 	backlight_exit();
 	radio_exit(LENSL_UWB);
-- 
1.6.0.4





More information about the kernel-team mailing list