Re: Status of 'toshiba-acpi: Add support for hotkey notifications' patch?

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

 



On Tue, Jan 26, 2010 at 05:59:00PM +0100, Frans Pop wrote:
> Hi Matthew,
> 
> What's the status of the patch below [1]? IIRC you were waiting for feedback
> from a particular user?
> 
> The patch works fine for me on my Satellite A40 and I'd like to see
> it included.
> 
> Cheers,
> FJP
> 

I'd recommend using the new sparse keymap feature instead of introducing
struct key_entry and scancode/keycode functions already in place in this
new feature.

Regards,
Cascardo.

> [1] Patch has been rebased for current mainline.
> 
> Author: Matthew Garrett <mjg59@xxxxxxxxxxxxx>
> ~Subject: toshiba-acpi: Add support for hotkey notifications
> 
> Calling the ENAB method on Toshiba laptops results in notifications being
> sent when laptop hotkeys are pressed. This patch simply calls that method
> and sets up an input device if it's successful.
> 
> Signed-off-by: Matthew Garrett <mjg@xxxxxxxxxx>
> 
> diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
> index 77bf5d8..13344b1 100644
> --- a/drivers/platform/x86/toshiba_acpi.c
> +++ b/drivers/platform/x86/toshiba_acpi.c
> @@ -46,6 +46,8 @@
>  #include <linux/backlight.h>
>  #include <linux/platform_device.h>
>  #include <linux/rfkill.h>
> +#include <linux/input-polldev.h>
> +#include <linux/input.h>
>  
>  #include <asm/uaccess.h>
>  
> @@ -62,9 +64,10 @@ MODULE_LICENSE("GPL");
>  
>  /* Toshiba ACPI method paths */
>  #define METHOD_LCD_BRIGHTNESS	"\\_SB_.PCI0.VGA_.LCD_._BCM"
> -#define METHOD_HCI_1		"\\_SB_.VALD.GHCI"
> -#define METHOD_HCI_2		"\\_SB_.VALZ.GHCI"
> +#define TOSH_INTERFACE_1	"\\_SB_.VALD"
> +#define TOSH_INTERFACE_2	"\\_SB_.VALZ"
>  #define METHOD_VIDEO_OUT	"\\_SB_.VALX.DSSX"
> +#define GHCI_METHOD		".GHCI"
>  
>  /* Toshiba HCI interface definitions
>   *
> @@ -116,6 +119,37 @@ static const struct acpi_device_id toshiba_device_ids[] = {
>  };
>  MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
>  
> +struct key_entry {
> +	char type;
> +	u16 code;
> +	u16 keycode;
> +};
> +
> +enum {KE_KEY, KE_END};
> +
> +static struct key_entry toshiba_acpi_keymap[]  = {
> +	{KE_KEY, 0x101, KEY_MUTE},
> +	{KE_KEY, 0x13b, KEY_COFFEE},
> +	{KE_KEY, 0x13c, KEY_BATTERY},
> +	{KE_KEY, 0x13d, KEY_SLEEP},
> +	{KE_KEY, 0x13e, KEY_SUSPEND},
> +	{KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
> +	{KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
> +	{KE_KEY, 0x141, KEY_BRIGHTNESSUP},
> +	{KE_KEY, 0x142, KEY_WLAN},
> +	{KE_KEY, 0x143, KEY_PROG1},
> +	{KE_KEY, 0x17f, KEY_BRIGHTNESSDOWN},
> +	{KE_KEY, 0xb05, KEY_PROG2},
> +	{KE_KEY, 0xb06, KEY_WWW},
> +	{KE_KEY, 0xb07, KEY_MAIL},
> +	{KE_KEY, 0xb30, KEY_STOP},
> +	{KE_KEY, 0xb31, KEY_PREVIOUSSONG},
> +	{KE_KEY, 0xb32, KEY_NEXTSONG},
> +	{KE_KEY, 0xb33, KEY_PLAYPAUSE},
> +	{KE_KEY, 0xb5a, KEY_MEDIA},
> +	{KE_END, 0, 0},
> +};
> +
>  /* utility
>   */
>  
> @@ -251,6 +285,9 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 
> *result)
>  struct toshiba_acpi_dev {
>  	struct platform_device *p_dev;
>  	struct rfkill *bt_rfk;
> +	struct input_polled_dev *poll_dev;
> +	struct input_dev *hotkey_dev;
> +	acpi_handle handle;
>  
>  	const char *bt_name;
>  
> @@ -711,6 +748,154 @@ static struct backlight_ops toshiba_backlight_data = {
>          .update_status  = set_lcd_status,
>  };
>  
> +static struct key_entry *toshiba_acpi_get_entry_by_scancode(int code)
> +{
> +	struct key_entry *key;
> +
> +	for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
> +		if (code == key->code)
> +			return key;
> +
> +	return NULL;
> +}
> +
> +static struct key_entry *toshiba_acpi_get_entry_by_keycode(int code)
> +{
> +	struct key_entry *key;
> +
> +	for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
> +		if (code == key->keycode && key->type == KE_KEY)
> +			return key;
> +
> +	return NULL;
> +}
> +
> +static int toshiba_acpi_getkeycode(struct input_dev *dev, int scancode,
> +				   int *keycode)
> +{
> +	struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
> +
> +	if (key && key->type == KE_KEY) {
> +		*keycode = key->keycode;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int toshiba_acpi_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 = toshiba_acpi_get_entry_by_scancode(scancode);
> +	if (key && key->type == KE_KEY) {
> +		old_keycode = key->keycode;
> +		key->keycode = keycode;
> +		set_bit(keycode, dev->keybit);
> +		if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
> +			clear_bit(old_keycode, dev->keybit);
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static void toshiba_acpi_notify(acpi_handle handle, u32 event, void **data)
> +{
> +	u32 hci_result, value;
> +	struct key_entry *key;
> +
> +	if (event != 0x80)
> +		return;
> +	do {
> +		hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
> +		if (hci_result == HCI_SUCCESS) {
> +			if (value == 0x100)
> +				continue;
> +			else if (!(value & 0x80)) {
> +				key = toshiba_acpi_get_entry_by_scancode
> +					(value);
> +				if (!key) {
> +					printk(MY_INFO "Unknown key %x\n",
> +					       value);
> +					continue;
> +				}
> +				input_report_key(toshiba_acpi.hotkey_dev,
> +						 key->keycode, 1);
> +				input_sync(toshiba_acpi.hotkey_dev);
> +				input_report_key(toshiba_acpi.hotkey_dev,
> +						 key->keycode, 0);
> +				input_sync(toshiba_acpi.hotkey_dev);
> +			}
> +		} else if (hci_result == HCI_NOT_SUPPORTED) {
> +			/* This is a workaround for an unresolved issue on
> +			 * some machines where system events sporadically
> +			 * become disabled. */
> +			hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
> +			printk(MY_NOTICE "Re-enabled hotkeys\n");
> +		}
> +	} while (hci_result != HCI_EMPTY);
> +}
> +
> +static int toshiba_acpi_setup_keyboard(char *device)
> +{
> +	acpi_status status;
> +	acpi_handle handle;
> +	int result;
> +	const struct key_entry *key;
> +
> +	status = acpi_get_handle(NULL, device, &handle);
> +	if (ACPI_FAILURE(status)) {
> +		printk(MY_INFO "Unable to get notification device\n");
> +		return -ENODEV;
> +	}
> +
> +	toshiba_acpi.handle = handle;
> +
> +	status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
> +	if (ACPI_FAILURE(status)) {
> +		printk(MY_INFO "Unable to enable hotkeys\n");
> +		return -ENODEV;
> +	}
> +
> +	status = acpi_install_notify_handler (handle, ACPI_DEVICE_NOTIFY,
> +					      toshiba_acpi_notify, NULL);
> +	if (ACPI_FAILURE(status)) {
> +		printk(MY_INFO "Unable to install hotkey notification\n");
> +		return -ENODEV;
> +	}
> +
> +	toshiba_acpi.hotkey_dev = input_allocate_device();
> +	if (!toshiba_acpi.hotkey_dev) {
> +		printk(MY_INFO "Unable to register input device\n");
> +		return -ENOMEM;
> +	}
> +
> +	toshiba_acpi.hotkey_dev->name = "Toshiba input device";
> +	toshiba_acpi.hotkey_dev->phys = device;
> +	toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
> +	toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
> +	toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
> +
> +	for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
> +		set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
> +		set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
> +	}
> +
> +	result = input_register_device(toshiba_acpi.hotkey_dev);
> +	if (result) {
> +		printk(MY_INFO "Unable to register input device\n");
> +		return result;
> +	}
> +
> +	return 0;
> +}
> +
>  static void toshiba_acpi_exit(void)
>  {
>  	if (toshiba_acpi.bt_rfk) {
> @@ -718,9 +903,15 @@ static void toshiba_acpi_exit(void)
>  		rfkill_destroy(toshiba_acpi.bt_rfk);
>  	}
>  
> +	if (toshiba_acpi.hotkey_dev)
> +		input_unregister_device(toshiba_acpi.hotkey_dev);
> +
>  	if (toshiba_backlight_device)
>  		backlight_device_unregister(toshiba_backlight_device);
>  
> +	acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
> +				   toshiba_acpi_notify);
> +
>  	remove_device();
>  
>  	if (toshiba_proc_dir)
> @@ -742,11 +933,15 @@ static int __init toshiba_acpi_init(void)
>  		return -ENODEV;
>  
>  	/* simple device detection: look for HCI method */
> -	if (is_valid_acpi_path(METHOD_HCI_1))
> -		method_hci = METHOD_HCI_1;
> -	else if (is_valid_acpi_path(METHOD_HCI_2))
> -		method_hci = METHOD_HCI_2;
> -	else
> +	if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) {
> +		method_hci = TOSH_INTERFACE_1 GHCI_METHOD;
> +		if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1))
> +			printk(MY_INFO "Unable to activate hotkeys\n");
> +	} else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) {
> +		method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
> +		if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
> +			printk(MY_INFO "Unable to activate hotkeys\n");
> +	} else
>  		return -ENODEV;
>  
>  	printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

Attachment: signature.asc
Description: Digital signature


[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