Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 034ce90a authored by Corentin Chary's avatar Corentin Chary Committed by Len Brown
Browse files

asus-laptop: hotkeys via the generic input interface



This patch is based on eeepc-laptop.c and the patchs
from Nicolas Trangez and Daniel Nascimento (mainly for the keymap).

Signed-off-by: default avatarCorentin Chary <corentincj@iksaif.net>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 2a7dc0d8
Loading
Loading
Loading
Loading
+154 −1
Original line number Original line Diff line number Diff line
@@ -46,6 +46,7 @@
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <linux/input.h>


#define ASUS_LAPTOP_VERSION "0.42"
#define ASUS_LAPTOP_VERSION "0.42"


@@ -181,6 +182,8 @@ struct asus_hotk {
	u8 light_level;		//light sensor level
	u8 light_level;		//light sensor level
	u8 light_switch;	//light sensor switch value
	u8 light_switch;	//light sensor switch value
	u16 event_count[128];	//count for each event TODO make this better
	u16 event_count[128];	//count for each event TODO make this better
	struct input_dev *inputdev;
	u16 *keycode_map;
};
};


/*
/*
@@ -250,6 +253,37 @@ ASUS_LED(rled, "record");
ASUS_LED(pled, "phone");
ASUS_LED(pled, "phone");
ASUS_LED(gled, "gaming");
ASUS_LED(gled, "gaming");


struct key_entry {
	char type;
	u8 code;
	u16 keycode;
};

enum { KE_KEY, KE_END };

static struct key_entry asus_keymap[] = {
	{KE_KEY, 0x30, KEY_VOLUMEUP},
	{KE_KEY, 0x31, KEY_VOLUMEDOWN},
	{KE_KEY, 0x32, KEY_MUTE},
	{KE_KEY, 0x33, KEY_SWITCHVIDEOMODE},
	{KE_KEY, 0x34, KEY_SWITCHVIDEOMODE},
	{KE_KEY, 0x40, KEY_PREVIOUSSONG},
	{KE_KEY, 0x41, KEY_NEXTSONG},
	{KE_KEY, 0x43, KEY_STOP},
	{KE_KEY, 0x45, KEY_PLAYPAUSE},
	{KE_KEY, 0x50, KEY_EMAIL},
	{KE_KEY, 0x51, KEY_WWW},
	{KE_KEY, 0x5C, BTN_EXTRA},  /* Performance */
	{KE_KEY, 0x5D, KEY_WLAN},
	{KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
	{KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
	{KE_KEY, 0x82, KEY_CAMERA},
	{KE_KEY, 0x8A, KEY_TV},
	{KE_KEY, 0x95, KEY_MEDIA},
	{KE_KEY, 0x99, KEY_PHONE},
	{KE_END, 0},
};

/*
/*
 * This function evaluates an ACPI method, given an int as parameter, the
 * This function evaluates an ACPI method, given an int as parameter, the
 * method is searched within the scope of the handle, can be NULL. The output
 * method is searched within the scope of the handle, can be NULL. The output
@@ -720,8 +754,68 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
	return store_status(buf, count, NULL, GPS_ON);
	return store_status(buf, count, NULL, GPS_ON);
}
}


/*
 * Hotkey functions
 */
static struct key_entry *asus_get_entry_by_scancode(int code)
{
	struct key_entry *key;

	for (key = asus_keymap; key->type != KE_END; key++)
		if (code == key->code)
			return key;

	return NULL;
}

static struct key_entry *asus_get_entry_by_keycode(int code)
{
	struct key_entry *key;

	for (key = asus_keymap; key->type != KE_END; key++)
		if (code == key->keycode && key->type == KE_KEY)
			return key;

	return NULL;
}

static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
{
	struct key_entry *key = asus_get_entry_by_scancode(scancode);

	if (key && key->type == KE_KEY) {
		*keycode = key->keycode;
		return 0;
	}

	return -EINVAL;
}

static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
{
	struct key_entry *key;
	int old_keycode;

	if (keycode < 0 || keycode > KEY_MAX)
		return -EINVAL;

	key = asus_get_entry_by_scancode(scancode);
	if (key && key->type == KE_KEY) {
		old_keycode = key->keycode;
		key->keycode = keycode;
		set_bit(keycode, dev->keybit);
		if (!asus_get_entry_by_keycode(old_keycode))
			clear_bit(old_keycode, dev->keybit);
		return 0;
	}

	return -EINVAL;
}

static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
{
{
	static struct key_entry *key;

	/* TODO Find a better way to handle events count. */
	/* TODO Find a better way to handle events count. */
	if (!hotk)
	if (!hotk)
		return;
		return;
@@ -742,7 +836,20 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
					dev_name(&hotk->device->dev), event,
					dev_name(&hotk->device->dev), event,
					hotk->event_count[event % 128]++);
					hotk->event_count[event % 128]++);


	if (hotk->inputdev) {
		key = asus_get_entry_by_scancode(event);
		if (!key)
			return ;
			return ;

		switch (key->type) {
		case KE_KEY:
			input_report_key(hotk->inputdev, key->keycode, 1);
			input_sync(hotk->inputdev);
			input_report_key(hotk->inputdev, key->keycode, 0);
			input_sync(hotk->inputdev);
			break;
		}
	}
}
}


#define ASUS_CREATE_DEVICE_ATTR(_name)					\
#define ASUS_CREATE_DEVICE_ATTR(_name)					\
@@ -960,6 +1067,38 @@ static int asus_hotk_get_info(void)
	return AE_OK;
	return AE_OK;
}
}


static int asus_input_init(void)
{
	const struct key_entry *key;
	int result;

	hotk->inputdev = input_allocate_device();
	if (!hotk->inputdev) {
		printk(ASUS_INFO "Unable to allocate input device\n");
		return 0;
	}
	hotk->inputdev->name = "Asus Laptop extra buttons";
	hotk->inputdev->phys = ASUS_HOTK_FILE "/input0";
	hotk->inputdev->id.bustype = BUS_HOST;
	hotk->inputdev->getkeycode = asus_getkeycode;
	hotk->inputdev->setkeycode = asus_setkeycode;

	for (key = asus_keymap; key->type != KE_END; key++) {
		switch (key->type) {
		case KE_KEY:
			set_bit(EV_KEY, hotk->inputdev->evbit);
			set_bit(key->keycode, hotk->inputdev->keybit);
			break;
		}
	}
	result = input_register_device(hotk->inputdev);
	if (result) {
		printk(ASUS_INFO "Unable to register input device\n");
		input_free_device(hotk->inputdev);
	}
	return result;
}

static int asus_hotk_check(void)
static int asus_hotk_check(void)
{
{
	int result = 0;
	int result = 0;
@@ -1092,10 +1231,17 @@ static void asus_led_exit(void)
	ASUS_LED_UNREGISTER(gled);
	ASUS_LED_UNREGISTER(gled);
}
}


static void asus_input_exit(void)
{
	if (hotk->inputdev)
		input_unregister_device(hotk->inputdev);
}

static void __exit asus_laptop_exit(void)
static void __exit asus_laptop_exit(void)
{
{
	asus_backlight_exit();
	asus_backlight_exit();
	asus_led_exit();
	asus_led_exit();
	asus_input_exit();


	acpi_bus_unregister_driver(&asus_hotk_driver);
	acpi_bus_unregister_driver(&asus_hotk_driver);
	sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
	sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
@@ -1217,6 +1363,10 @@ static int __init asus_laptop_init(void)
		printk(ASUS_INFO "Brightness ignored, must be controlled by "
		printk(ASUS_INFO "Brightness ignored, must be controlled by "
		       "ACPI video driver\n");
		       "ACPI video driver\n");


	result = asus_input_init();
	if (result)
		goto fail_input;

	result = asus_led_init(dev);
	result = asus_led_init(dev);
	if (result)
	if (result)
		goto fail_led;
		goto fail_led;
@@ -1256,6 +1406,9 @@ static int __init asus_laptop_init(void)
	asus_led_exit();
	asus_led_exit();


      fail_led:
      fail_led:
	asus_input_exit();

      fail_input:
	asus_backlight_exit();
	asus_backlight_exit();


      fail_backlight:
      fail_backlight: