Hi,
I've been converting the various acpi drivers to use the input subsystem
rather than using acpi events or other random proc interfaces.
So far sony-laptop and thinkpad_acpi have been converted, and I would
like to also suggest asus-acpi does the same as well.
Doing so have the following advantages:
* we can get rid of vendor specific acpi event daemons that have to be
configured
* we can simplify and have one single reporting stack
* we can remap keys using the existing infrastructure at the quirk
pages: http://people.freedesktop.org/~hughsient/quirk/
* the buttons "just work" without configuration
I've attached a patch for review. I've compile tested it, but I haven't
got any asus hardware to test it on. Comments, suggestions and
criticisms welcome.
Making asus acpi using input allows us to use HAL to report some
buttons, and eventually use a evdev X to automatically make buttons
work, no matter if they are on a true keyboard or acpi generated events.
Thanks for review,
Richard.
--- asus-laptop-orig.c 2007-07-30 10:01:26.000000000 +0100
+++ asus-laptop.c 2007-07-30 09:34:58.000000000 +0100
@@ -44,6 +44,8 @@
#include <linux/fb.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/pci_ids.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
@@ -175,6 +177,7 @@ ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX
struct asus_hotk {
char *name; //laptop name
struct acpi_device *device; //the device we are in
+ struct input_dev *inputdev; //the input device we emit from
acpi_handle handle; //the handle of the hotk device
char status; //status of the hotk, for LEDs, ...
u32 ledd_status; //status of the LED display
@@ -183,6 +186,53 @@ struct asus_hotk {
u16 event_count[128]; //count for each event TODO make this better
};
+
+/* The MSC_SCAN numbers emitted from the driver.
+ * We remap them to 15 from 128 sparse states to keep the size of the
+ * keymap table sane */
+#define ASUS_SCAN_UNKNOWN 0x00
+#define ASUS_SCAN_SUSPEND 0x01
+#define ASUS_SCAN_WLAN 0x02
+#define ASUS_SCAN_BRIGHTNESS_UP 0x03
+#define ASUS_SCAN_BRIGHTNESS_DOWN 0x04
+#define ASUS_SCAN_VOLUME_DOWN 0x05
+#define ASUS_SCAN_LCD_TOGGLE 0x06
+#define ASUS_SCAN_VOLUME_UP 0x07
+#define ASUS_SCAN_MUTE_TOGGLE 0x08
+#define ASUS_SCAN_CDROM 0x09
+#define ASUS_SCAN_EMAIL 0x0a
+#define ASUS_SCAN_INTERNET 0x0b
+#define ASUS_SCAN_MESSAGING 0x0c
+#define ASUS_SCAN_VIDEO_TOGGLE 0x0d
+#define ASUS_SCAN_TRACKPAD_TOGGLE 0x0e
+#define ASUS_SCAN_NEXT 0x0f
+#define ASUS_SCAN_PREV 0x10
+#define ASUS_SCAN_STOP 0x11
+#define ASUS_SCAN_PLAYPAUSE 0x12
+
+/* we don't yet know what event id corresponds to each scancode */
+static u16 hotkey_keycode_map[] = {
+ KEY_RESERVED,
+ KEY_SUSPEND, /* 0x01 */
+ KEY_WLAN, /* 0x02 */
+ KEY_BRIGHTNESSUP, /* 0x03 */
+ KEY_BRIGHTNESSDOWN, /* 0x04 */
+ KEY_VOLUMEDOWN, /* 0x05 */
+ KEY_SWITCHVIDEOMODE, /* 0x06 */
+ KEY_VOLUMEUP, /* 0x07 */
+ KEY_MUTE, /* 0x08 */
+ KEY_PLAYCD, /* 0x09 */
+ KEY_MAIL, /* 0x0a */
+ KEY_NEWS, /* 0x0b */
+ KEY_MESSENGER, /* 0x0c */
+ KEY_SWITCHVIDEOMODE, /* 0x0d */
+ KEY_F22, /* 0x0e */
+ KEY_NEXTSONG, /* 0x0f */
+ KEY_PREVIOUSSONG, /* 0x10 */
+ KEY_STOP, /* 0x11 */
+ KEY_PLAYPAUSE, /* 0x12 */
+};
+
/*
* This header is made available to allow proper configuration given model,
* revision number , ... this info cannot go in struct asus_hotk because it is
@@ -714,8 +764,92 @@ static ssize_t store_gps(struct device *
return store_status(buf, count, NULL, GPS_ON);
}
+static void asus_input_send_key(unsigned int scancode, unsigned int keycode)
+{
+ if (keycode != KEY_RESERVED) {
+ input_report_key(hotk->inputdev, keycode, 1);
+ input_event(hotk->inputdev, EV_MSC, MSC_SCAN, scancode);
+ input_sync(hotk->inputdev);
+
+ input_report_key(hotk->inputdev, keycode, 0);
+ input_event(hotk->inputdev, EV_MSC, MSC_SCAN, scancode);
+ input_sync(hotk->inputdev);
+ }
+}
+
+/* Convert the hardware scancode table to ids that we can export as ABI
+ * stable. This means we can add more events as they are discovered without
+ * breaking userspace. */
+static unsigned int asus_convert_scancode_to_id(u32 event)
+{
+ unsigned int id;
+
+ /* these change every timethe brightnes level is altered */
+ if (event >= 0x11 && event <= 0x1f)
+ return ASUS_SCAN_BRIGHTNESS_UP;
+ if (event >= 0x20 && event <= 0x2e)
+ return ASUS_SCAN_BRIGHTNESS_DOWN;
+
+ switch (event) {
+ case 0x30:
+ id = ASUS_SCAN_VOLUME_UP;
+ break;
+ case 0x31:
+ id = ASUS_SCAN_VOLUME_DOWN;
+ break;
+ case 0x33:
+ case 0x34:
+ id = ASUS_SCAN_LCD_TOGGLE;
+ break;
+ case 0x32:
+ id = ASUS_SCAN_MUTE_TOGGLE;
+ break;
+ case 0x40:
+ id = ASUS_SCAN_PREV;
+ break;
+ case 0x41:
+ id = ASUS_SCAN_NEXT;
+ break;
+ case 0x43:
+ id = ASUS_SCAN_STOP;
+ break;
+ case 0x45:
+ id = ASUS_SCAN_PLAYPAUSE;
+ break;
+ case 0x4c:
+ id = ASUS_SCAN_CDROM;
+ break;
+ case 0x50:
+ id = ASUS_SCAN_EMAIL;
+ break;
+ case 0x51:
+ id = ASUS_SCAN_INTERNET;
+ break;
+ case 0x5c:
+ id = ASUS_SCAN_MESSAGING;
+ break;
+ case 0x5f:
+ id = ASUS_SCAN_WLAN;
+ break;
+ case 0x61:
+ id = ASUS_SCAN_VIDEO_TOGGLE;
+ break;
+ case 0x6a:
+ case 0x6b:
+ id = ASUS_SCAN_TRACKPAD_TOGGLE;
+ break;
+ default:
+ id = ASUS_SCAN_UNKNOWN;
+ }
+ return id;
+}
+
static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
{
+ unsigned int scancode;
+ unsigned int keycode;
+ int sendacpi = 1;
+
/* TODO Find a better way to handle events count. */
if (!hotk)
return;
@@ -732,8 +866,24 @@ static void asus_hotk_notify(acpi_handle
lcd_blank(FB_BLANK_POWERDOWN);
}
- acpi_bus_generate_event(hotk->device, event,
- hotk->event_count[event % 128]++);
+ /* convert the sparse 128 byte map to a 16 byte map */
+ scancode = asus_convert_scancode_to_id(event);
+ if (scancode == ASUS_SCAN_UNKNOWN) {
+ printk(KERN_WARNING " Scancode '0x%x' cannot be mapped to keycode.\n", event);
+ } else {
+ /* We have to emit a keycode via INPUT */
+ keycode = hotkey_keycode_map[scancode];
+ printk(KERN_INFO " Scancode '0x%x' mapped to keycode '%d'.\n", event, keycode);
+ if (keycode != KEY_UNKNOWN) {
+ asus_input_send_key(scancode, keycode);
+ sendacpi = 0;
+ }
+ }
+
+ /* we have not emitted an input event so do the event as normal */
+ if (sendacpi == 1)
+ acpi_bus_generate_event(hotk->device, event,
+ hotk->event_count[event % 128]++);
return;
}
@@ -1059,6 +1209,11 @@ static int asus_hotk_remove(struct acpi_
if (ACPI_FAILURE(status))
printk(ASUS_ERR "Error removing notify handler\n");
+ if (hotk->inputdev) {
+ input_unregister_device(hotk->inputdev);
+ input_free_device(hotk->inputdev);
+ }
+
kfree(hotk->name);
kfree(hotk);
@@ -1179,6 +1334,7 @@ static int __init asus_laptop_init(void)
{
struct device *dev;
int result;
+ int i;
if (acpi_disabled)
return -ENODEV;
@@ -1229,8 +1385,46 @@ static int __init asus_laptop_init(void)
if (result)
goto fail_sysfs;
+ /* registe an input event source */
+ hotk->inputdev = input_allocate_device();
+ if (!hotk->inputdev) {
+ printk(ASUS_ERR "Unable to allocate input device\n");
+ result = -ENOMEM;
+ goto fail_sysfs;
+ }
+
+ /* Prepare input device, but don't register */
+ hotk->inputdev->name = "ASUS Extra Buttons";
+ hotk->inputdev->phys = "asus_acpi/input0";
+ hotk->inputdev->id.bustype = BUS_HOST;
+ hotk->inputdev->id.vendor = PCI_VENDOR_ID_ASUSTEK;
+ hotk->inputdev->id.product = 0x5054; /* "TP" */
+ hotk->inputdev->id.version = 0x4101;
+
+ result = input_register_device(hotk->inputdev);
+ if (result < 0) {
+ printk(ASUS_ERR "Unable to register input device\n");
+ goto fail_register;
+ }
+
+ /* set up the setkeycodes map */
+ set_bit(EV_KEY, hotk->inputdev->evbit);
+ set_bit(EV_MSC, hotk->inputdev->evbit);
+ set_bit(MSC_SCAN, hotk->inputdev->mscbit);
+ hotk->inputdev->keycodesize = sizeof(hotkey_keycode_map[0]);
+ hotk->inputdev->keycodemax = ARRAY_SIZE(hotkey_keycode_map);
+ hotk->inputdev->keycode = &hotkey_keycode_map;
+ for (i = 0; i < ARRAY_SIZE(hotkey_keycode_map); i++) {
+ if (hotkey_keycode_map[i] != KEY_RESERVED) {
+ set_bit(hotkey_keycode_map[i], hotk->inputdev->keybit);
+ }
+ }
+
return 0;
+ fail_register:
+ input_free_device(hotk->inputdev);
+
fail_sysfs:
platform_device_del(asuspf_device);
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Acpi4asus-user mailing list
Acpi4asus-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/acpi4asus-user