Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices
From: Azael Avalos
Date: Tue Jun 09 2009 - 12:42:17 EST
Hi there:
Sorry for the late reply, lotsa work lately.
On Tue, Jun 2, 2009 at 8:03 AM, Matthew Garrett<mjg59@xxxxxxxxxxxxx> wrote:
> Ok. From looking at your DSDT I'm still a little bit confused, but
> anyway. As far as I can tell the correct way to drive TOS1900-type
> devices is to call ENAB (which doesn't do anything on your machine) and
> then call the INFO method when we receive notifications. Your DSDT
> includes a NTFY method that doesn't appear to be called from anywhere.
> The path that we should be following is the one triggered by the _Q43
> EC query, which then generates a notification and flags that there's a
> hotkey waiting. The INFO method then unflags that, saves the value of
> TOHK and writes a zero into there.
>
Indeed, thats how I managed to see where the hotkeys were being "stored"
in my first attempts at getting hotkeys working on my Toshiba model.
However, everytime you poll the INFO method, the TECF variable receives
a zero, so the next time you want to poll the INFO method, you
receive a zero also, unless you "activate" the TECF variable again
perhaps tru' _Q43 or by directly writing a one into it.
> So, from what I can tell, the following patch should work for you
> (against clean upstream). If it doesn't then we need to figure out
> what's happening when you press a hotkey in the first place.
>
Not at all, the patch per se doesn't do anything on my model, even if
I activate the HCI Hotkey Events call 0x1E.
Just when I activate that HCI command the hotkeys start being "stored"
on the TOHK variable, however, not even w/ that patch you sent I'm
not able to get any events reported.
So, in my point of view and the experiments w/ the code I've been
doing here's the workflow that I found to be partially working:
1. Activate Hotkey Events call 0x1E.
2. It activates something internally causing Hotkey Events being
stored in TOHK.
3. Whenever I press an Fn-Key combo let's say Fn-Esc, the actual key gets
stored in TOHK, in this case 0x101, but just lasting a couple seconds
(or even less...), it seems it's volatile.
4. Polling TOHK via the INFO method or directly gets me the actual hotkey,
but again, must real quick since it will disappear (I used 100 ms polling).
5. Figure out a way of getting those Hotkey Events in a nice manner...
I managed to get them, but sometimes I got them repeated due to the
polling timer...
Saludos
Azael
> commit 6edd24bf5ef664e8ac8d5f53774cb9ada8b11a37
> Author: Matthew Garrett <mjg@xxxxxxxxxx>
> Date: Â Fri Mar 6 00:25:45 2009 +0000
>
> Â Â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 9f18726..45c1fb0 100644
> --- a/drivers/platform/x86/toshiba_acpi.c
> +++ b/drivers/platform/x86/toshiba_acpi.c
> @@ -46,6 +46,7 @@
> Â#include <linux/platform_device.h>
> Â#include <linux/rfkill.h>
> Â#include <linux/input-polldev.h>
> +#include <linux/input.h>
>
> Â#include <asm/uaccess.h>
>
> @@ -62,9 +63,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 +118,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
> Â*/
>
> @@ -252,6 +285,8 @@ struct toshiba_acpi_dev {
> Â Â Â Âstruct platform_device *p_dev;
> Â Â Â Âstruct rfkill *rfk_dev;
> Â Â Â Âstruct input_polled_dev *poll_dev;
> + Â Â Â struct input_dev *hotkey_dev;
> + Â Â Â acpi_handle handle;
>
> Â Â Â Âconst char *bt_name;
> Â Â Â Âconst char *rfk_name;
> @@ -700,6 +735,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.poll_dev) {
> @@ -707,12 +890,18 @@ static void toshiba_acpi_exit(void)
> Â Â Â Â Â Â Â Âinput_free_polled_device(toshiba_acpi.poll_dev);
> Â Â Â Â}
>
> + Â Â Â if (toshiba_acpi.hotkey_dev)
> + Â Â Â Â Â Â Â input_unregister_device(toshiba_acpi.hotkey_dev);
> +
> Â Â Â Âif (toshiba_acpi.rfk_dev)
> Â Â Â Â Â Â Â Ârfkill_unregister(toshiba_acpi.rfk_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)
> @@ -736,11 +925,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",
>
> --
> Matthew Garrett | mjg59@xxxxxxxxxxxxx
>
--
-- El mundo apesta y vosotros apestais tambien --
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/