2009-03-31 21:46:08

by Matthew Garrett

[permalink] [raw]
Subject: [PATCH 1/2] 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 <[email protected]>
---
drivers/platform/x86/toshiba_acpi.c | 207 +++++++++++++++++++++++++++++++++-
1 files changed, 200 insertions(+), 7 deletions(-)

diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 40e60fc..fb87b57 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;
@@ -702,6 +737,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 & ~0x80);
+ if (!key) {
+ printk(MY_INFO "Unknown key %x\n",
+ value & ~0x80);
+ 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) {
@@ -709,12 +892,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)
@@ -738,11 +927,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 | [email protected]


2009-03-31 21:48:23

by Matthew Garrett

[permalink] [raw]
Subject: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

Despite toshiba_acpi exporting TOS1900 as a modalias, it doesn't appear to
support these machines. They have their HCI method implemented in a
different but compatible manner and so need a different method address.

Signed-off-by: Matthew Garrett <[email protected]>
---
drivers/platform/x86/toshiba_acpi.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index fb87b57..9fb4873 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -67,6 +67,7 @@ MODULE_LICENSE("GPL");
#define TOSH_INTERFACE_2 "\\_SB_.VALZ"
#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
#define GHCI_METHOD ".GHCI"
+#define SPFC_METHOD ".SPFC"

/* Toshiba HCI interface definitions
*
@@ -935,6 +936,10 @@ static int __init toshiba_acpi_init(void)
method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
printk(MY_INFO "Unable to activate hotkeys\n");
+ } else if (is_valid_acpi_path(TOSH_INTERFACE_2 SPFC_METHOD)) {
+ method_hci = TOSH_INTERFACE_2 SPFC_METHOD;
+ if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
+ printk(MY_INFO "Unable to activate hotkeys\n");
} else
return -ENODEV;

--
Matthew Garrett | [email protected]

2009-03-31 22:06:28

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

Hi there,

On Wed, Apr 1, 2009 at 2:47 PM, Matthew Garrett <[email protected]> wrote:
> Despite toshiba_acpi exporting TOS1900 as a modalias, it doesn't appear to
> support these machines. They have their HCI method implemented in a
> different but compatible manner and so need a different method address.

Indeed, my Satellite X205-9800 uses that method, however, it only provides
HCI call 0x001E (Hotkey Events) and no System Event FIFO (0x0016),
instead, hotkeys are entered on a variable called TOHK (TOshiba HotKeys?).
Located in my model in

PCI0.LPCB.EC0.TOHK

and it appears that it can be _polled_ tru' method INFO
(TOSH_INTERFACE_2 ".INFO"),
perhaps a small change in the polling to reflect to that method for
TOS1900 devices would be necessary.


On my model the complete call would be:

\\_SB.VALZ.SPFC
\\_SB.VALZ.INFO

Is it different from \\_SB_.VALZ.SPFC or it simply doesn't matter?

Saludos
Azael



--
-- El mundo apesta y vosotros apestais tambien --

2009-03-31 22:11:30

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Wed, Apr 01, 2009 at 03:06:12PM +1700, Azael Avalos wrote:

> Indeed, my Satellite X205-9800 uses that method, however, it only provides
> HCI call 0x001E (Hotkey Events) and no System Event FIFO (0x0016),
> instead, hotkeys are entered on a variable called TOHK (TOshiba HotKeys?).
> Located in my model in
>
> PCI0.LPCB.EC0.TOHK

Ok, interesting. Looking at the DSDTs I have here, TOHK isn't always
present on TOS1900 devices. However:

> and it appears that it can be _polled_ tru' method INFO
> (TOSH_INTERFACE_2 ".INFO"),
> perhaps a small change in the polling to reflect to that method for
> TOS1900 devices would be necessary.

The INFO method is, so this looks like a good call.

>
> On my model the complete call would be:
>
> \\_SB.VALZ.SPFC
> \\_SB.VALZ.INFO
>
> Is it different from \\_SB_.VALZ.SPFC or it simply doesn't matter?

Yeah, that shouldn't matter. So it simply looks like in the notification
function on these systems we should call the INFO method and that'll
give us the key back? I'll send a test patch later (don't have any
hardware to test right now).

--
Matthew Garrett | [email protected]

2009-03-31 22:19:43

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Wed, Apr 1, 2009 at 3:11 PM, Matthew Garrett <[email protected]> wrote:
> On Wed, Apr 01, 2009 at 03:06:12PM +1700, Azael Avalos wrote:
>
>> Indeed, my Satellite X205-9800 uses that method, however, it only provides
>> HCI call 0x001E (Hotkey Events) and no System Event FIFO (0x0016),
>> instead, hotkeys are entered on a variable called TOHK (TOshiba HotKeys?).
>> Located in my model in
>>
>> PCI0.LPCB.EC0.TOHK
>
> Ok, interesting. Looking at the DSDTs I have here, TOHK isn't always
> present on TOS1900 devices. However:
>
>> and it appears that it can be _polled_ tru' method INFO
>> (TOSH_INTERFACE_2 ".INFO"),
>> perhaps a small change in the polling to reflect to that method for
>> TOS1900 devices would be necessary.
>
> The INFO method is, so this looks like a good call.
>
>>
>> On my model the complete call would be:
>>
>> \\_SB.VALZ.SPFC
>> \\_SB.VALZ.INFO
>>
>> Is it different from \\_SB_.VALZ.SPFC or it simply doesn't matter?
>
> Yeah, that shouldn't matter. So it simply looks like in the notification
> function on these systems we should call the INFO method and that'll
> give us the key back? I'll send a test patch later (don't have any
> hardware to test right now).

Well, on my model after enabling Hotkey Events, Fn-Fx events are entered
to that variable according to Toshiba, eg.: Fn-Esc would give me 0x101, etc.

I'm at work right now, and will be in the next 2 hours, when I get
home I'll test
whatever patch you send.

By the way, you can find a copy of my DSDT here:

http://cig.uacj.mx/~azael/Toshiba/Satellite_X205-S9800.dsl

>
> --
> Matthew Garrett | [email protected]
>

Saludos
Azael



--
-- El mundo apesta y vosotros apestais tambien --

2009-03-31 23:02:50

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

Ok, can you try this and let me know what codes it generates (if it
generates any)? It should go on top of the previous patches.

diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 9fb4873..8552e1a 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -185,7 +185,6 @@ static int write_acpi_int(const char *methodName, int val)
return (status == AE_OK);
}

-#if 0
static int read_acpi_int(const char *methodName, int *pVal)
{
struct acpi_buffer results;
@@ -200,7 +199,6 @@ static int read_acpi_int(const char *methodName, int *pVal)

return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER);
}
-#endif

static const char *method_hci /*= 0*/ ;

@@ -802,6 +800,13 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void **data)

if (event != 0x80)
return;
+
+ if (is_valid_acpi_path(TOSH_INTERFACE_2 SPFC_METHOD)) {
+ read_acpi_int(TOSH_INTERFACE_2 SPFC_METHOD, &value);
+ printk("Received 0x%x\n", value);
+ return;
+ }
+
do {
hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
if (hci_result == HCI_SUCCESS) {

--
Matthew Garrett | [email protected]

2009-04-01 16:51:21

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Wed, Apr 1, 2009 at 4:02 PM, Matthew Garrett <[email protected]> wrote:
> Ok, can you try this and let me know what codes it generates (if it
> generates any)? It should go on top of the previous patches.

Nothing gets generated, even if I change the method to ".INFO" and hotkey
events enabled with hci_write2(HCI_HOTKEY_EVENT, 1, 1, &hci_result) and
TECF set to 1 (see my DSDT).

I was playing with the code yesterday trying to get some events reported, but no
luck so far.

It appears that TOHK variable is _volatile_ and it just stores hotkey events
temporarily and they don't get _stored_ like in the System Event FIFO.

On the patches I sent to the omnibook module I'm able to get events but they
seem to get repeated 3 times, or perhaps I'm polling to often.


Saludos
Azael


--
-- El mundo apesta y vosotros apestais tambien --

2009-04-01 16:54:16

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Thu, Apr 02, 2009 at 09:50:59AM +1700, Azael Avalos wrote:
> On Wed, Apr 1, 2009 at 4:02 PM, Matthew Garrett <[email protected]> wrote:
> > Ok, can you try this and let me know what codes it generates (if it
> > generates any)? It should go on top of the previous patches.
>
> Nothing gets generated, even if I change the method to ".INFO" and hotkey
> events enabled with hci_write2(HCI_HOTKEY_EVENT, 1, 1, &hci_result) and
> TECF set to 1 (see my DSDT).
>
> I was playing with the code yesterday trying to get some events reported, but no
> luck so far.
>
> It appears that TOHK variable is _volatile_ and it just stores hotkey events
> temporarily and they don't get _stored_ like in the System Event FIFO.

Yes, you shouldn't be reading directly from TOHK at any point. It seems
to be a purely internal variable - I'm fairly sure that the INFO method
is the only one that should be called on event generation.

> On the patches I sent to the omnibook module I'm able to get events but they
> seem to get repeated 3 times, or perhaps I'm polling to often.

Hm. I don't have test hardware right now, I'm afraid. I'll look at some
DSDTs a bit more and see if anything springs to mind.

--
Matthew Garrett | [email protected]

2009-04-01 17:03:50

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Thu, Apr 2, 2009 at 9:53 AM, Matthew Garrett <[email protected]> wrote:
> On Thu, Apr 02, 2009 at 09:50:59AM +1700, Azael Avalos wrote:
>> On Wed, Apr 1, 2009 at 4:02 PM, Matthew Garrett <[email protected]> wrote:
>> > Ok, can you try this and let me know what codes it generates (if it
>> > generates any)? It should go on top of the previous patches.
>>
>> Nothing gets generated, even if I change the method to ".INFO" and hotkey
>> events enabled with hci_write2(HCI_HOTKEY_EVENT, 1, 1, &hci_result) and
>> TECF set to 1 (see my DSDT).
>>
>> I was playing with the code yesterday trying to get some events reported, but no
>> luck so far.
>>
>> It appears that TOHK variable is _volatile_ and it just stores hotkey events
>> temporarily and they don't get _stored_ like in the System Event FIFO.
>
> Yes, you shouldn't be reading directly from TOHK at any point. It seems
> to be a purely internal variable - I'm fairly sure that the INFO method
> is the only one that should be called on event generation.

Well, on the patches sent to the omnibook module I was polling TOHK directly,
it is until now that I realized that I can poll the events via INFO
method, that is,
if I enable TECF first via method \\_SB.PCI0.LPCB.EC0.NTFY

>
>> On the patches I sent to the omnibook module I'm able to get events but they
>> seem to get repeated 3 times, or perhaps I'm polling to often.
>
> Hm. I don't have test hardware right now, I'm afraid. I'll look at some
> DSDTs a bit more and see if anything springs to mind.

Well, I brought my laptop to work (I'm a sysadmin so I got plenty of time :-P)
and I can test if that helps

>
> --
> Matthew Garrett | [email protected]
>

Saludos
Azael


--
-- El mundo apesta y vosotros apestais tambien --

2009-04-01 17:07:49

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Thu, Apr 02, 2009 at 10:03:05AM +1700, Azael Avalos wrote:
> On Thu, Apr 2, 2009 at 9:53 AM, Matthew Garrett <[email protected]> wrote:
> > Yes, you shouldn't be reading directly from TOHK at any point. It seems
> > to be a purely internal variable - I'm fairly sure that the INFO method
> > is the only one that should be called on event generation.
>
> Well, on the patches sent to the omnibook module I was polling TOHK directly,
> it is until now that I realized that I can poll the events via INFO
> method, that is,
> if I enable TECF first via method \\_SB.PCI0.LPCB.EC0.NTFY

Mm. None of the TOS1900 DSDTs I have here have TECF or NTFY methods, so
again that doesn't sound like the right way of driving them. Does the
ENAB method not do this?

> >
> >> On the patches I sent to the omnibook module I'm able to get events but they
> >> seem to get repeated 3 times, or perhaps I'm polling to often.
> >
> > Hm. I don't have test hardware right now, I'm afraid. I'll look at some
> > DSDTs a bit more and see if anything springs to mind.
>
> Well, I brought my laptop to work (I'm a sysadmin so I got plenty of time :-P)
> and I can test if that helps

I'll dig some more and let you know. Thanks!

--
Matthew Garrett | [email protected]

2009-04-01 17:13:47

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Thu, Apr 2, 2009 at 10:07 AM, Matthew Garrett <[email protected]> wrote:
> On Thu, Apr 02, 2009 at 10:03:05AM +1700, Azael Avalos wrote:
>> On Thu, Apr 2, 2009 at 9:53 AM, Matthew Garrett <[email protected]> wrote:
>> > Yes, you shouldn't be reading directly from TOHK at any point. It seems
>> > to be a purely internal variable - I'm fairly sure that the INFO method
>> > is the only one that should be called on event generation.
>>
>> Well, on the patches sent to the omnibook module I was polling TOHK directly,
>> it is until now that I realized that I can poll the events via INFO
>> method, that is,
>> if I enable TECF first via method \\_SB.PCI0.LPCB.EC0.NTFY
>
> Mm. None of the TOS1900 DSDTs I have here have TECF or NTFY methods, so
> again that doesn't sound like the right way of driving them. Does the
> ENAB method not do this?

At least not in my model, the ENAB method is empty, heres a snippet of the DSDT:

Method (ENAB, 0, NotSerialized)
{
}

Method (INFO, 0, NotSerialized)
{
If (TECF)
{
Store (Zero, TECF)
Store (^^PCI0.LPCB.EC0.TOHK, Local0)
Store (Zero, ^^PCI0.LPCB.EC0.TOHK)
}
Else
{
Store (Zero, Local0)
}

Return (Local0)
}

And above scope _SB you can find

Method (NTFY, 0, NotSerialized)
{
Store (One, ^^^^VALZ.TECF)
Notify (VALZ, 0x80)
Return (0xAA)
}

Saludos
Azael


--
-- El mundo apesta y vosotros apestais tambien --

2009-04-08 06:44:47

by Len Brown

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

applied to acpi-test

thanks,
Len Brown, Intel Open Source Technology Center

2009-04-11 19:50:50

by Frans Pop

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

Matthew Garrett wrote:
> 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.

Hi Matthew,

On my Satellite A40-241 the patch works fine for the Fn keys, but it does
not work for the multimedia keys next to the power button. No event is
generated (I tested this by directly reading the /dev/input/eventX file).

Any chance those could be made to work too?

Cheers,
FJP

2009-04-13 14:50:33

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

On Sat, Apr 11, 2009 at 09:50:35PM +0200, Frans Pop wrote:
> Matthew Garrett wrote:
> > 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.
>
> Hi Matthew,
>
> On my Satellite A40-241 the patch works fine for the Fn keys, but it does
> not work for the multimedia keys next to the power button. No event is
> generated (I tested this by directly reading the /dev/input/eventX file).
>
> Any chance those could be made to work too?

Can you send me the acpidump?

--
Matthew Garrett | [email protected]

2009-04-13 19:29:22

by Frans Pop

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

On Monday 13 April 2009, Matthew Garrett wrote:
> On Sat, Apr 11, 2009 at 09:50:35PM +0200, Frans Pop wrote:
> > On my Satellite A40-241 the patch works fine for the Fn keys, but it
> > does not work for the multimedia keys next to the power button. No
> > event is generated (I tested this by directly reading the
> > /dev/input/eventX file).
> >
> > Any chance those could be made to work too?
>
> Can you send me the acpidump?

Attached. Thanks for having a look.


Attachments:
(No filename) (468.00 B)
acpi.dump (90.40 kB)
Download all attachments

2009-04-13 19:43:59

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

Hm. Do you get events for the multimedia keys without this patch and
using the old interface?

--
Matthew Garrett | [email protected]

2009-04-13 20:38:24

by Frans Pop

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

On Monday 13 April 2009, Matthew Garrett wrote:
> Hm. Do you get events for the multimedia keys without this patch and
> using the old interface?

Yes, 2.6.28 gives in /proc/acpi/toshiba/keys as value for 'hotkey':
previous track: 0x0b31
next track: 0x0b32
play/pause: 0x0b33
stop: 0x0b30

And fnfx-client in debug mode shows the four keys as well.

2009-04-13 21:18:19

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

On Mon, Apr 13, 2009 at 10:38:09PM +0200, Frans Pop wrote:
> On Monday 13 April 2009, Matthew Garrett wrote:
> > Hm. Do you get events for the multimedia keys without this patch and
> > using the old interface?
>
> Yes, 2.6.28 gives in /proc/acpi/toshiba/keys as value for 'hotkey':
> previous track: 0x0b31
> next track: 0x0b32
> play/pause: 0x0b33
> stop: 0x0b30

Without running any software, does hitting these keys cause the acpi
interrupt in /proc/interrupts to increment?

--
Matthew Garrett | [email protected]

2009-04-13 21:26:48

by Frans Pop

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

On Monday 13 April 2009, Matthew Garrett wrote:
> On Mon, Apr 13, 2009 at 10:38:09PM +0200, Frans Pop wrote:
> > On Monday 13 April 2009, Matthew Garrett wrote:
> > > Hm. Do you get events for the multimedia keys without this patch
> > > and using the old interface?
> >
> > Yes, 2.6.28 gives in /proc/acpi/toshiba/keys as value for 'hotkey':
> > previous track: 0x0b31
> > next track: 0x0b32
> > play/pause: 0x0b33
> > stop: 0x0b30
>
> Without running any software, does hitting these keys cause the acpi
> interrupt in /proc/interrupts to increment?

Yes (with 2.6.28; fnfx* purged before system boot).

2009-04-13 21:32:14

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

On Mon, Apr 13, 2009 at 11:26:34PM +0200, Frans Pop wrote:
> On Monday 13 April 2009, Matthew Garrett wrote:
> > On Mon, Apr 13, 2009 at 10:38:09PM +0200, Frans Pop wrote:
> > > On Monday 13 April 2009, Matthew Garrett wrote:
> > > > Hm. Do you get events for the multimedia keys without this patch
> > > > and using the old interface?
> > >
> > > Yes, 2.6.28 gives in /proc/acpi/toshiba/keys as value for 'hotkey':
> > > previous track: 0x0b31
> > > next track: 0x0b32
> > > play/pause: 0x0b33
> > > stop: 0x0b30
> >
> > Without running any software, does hitting these keys cause the acpi
> > interrupt in /proc/interrupts to increment?
>
> Yes (with 2.6.28; fnfx* purged before system boot).

Ok - can you build with ACPI debugging, set /proc/acpi/debug_level and
debug_layer to 0xffff, hit one of the keys, turn the debugging back off
and then send me the log? Easiest is to do something like:

echo 0xffff >/proc/acpi/debug_level; echo 0xffff
>/proc/acpi/debug_layer; sleep 3; echo 0 blah blah

so you don't have to try to disable them while stuff's appearing all
over your screen. There'll be a lot of output, so if you could send it
to me rather than the list then that would be great.

--
Matthew Garrett | [email protected]

2009-04-18 04:01:54

by Len Brown

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

drivers/platform/x86/toshiba_acpi.c:854: warning: passing argument 3 of
?acpi_install_notify_handler? from incompatible pointer type
drivers/platform/x86/toshiba_acpi.c:903: warning: passing argument 3 of
?acpi_remove_notify_handler? from incompatible pointer type

2009-04-18 05:47:49

by Andrey Borzenkov

[permalink] [raw]
Subject: Re: [PATCH 1/2] toshiba-acpi: Add support for hotkey notifications

Len Brown wrote:

> drivers/platform/x86/toshiba_acpi.c:854: warning: passing argument 3 of
> ‘acpi_install_notify_handler’ from incompatible pointer type
> drivers/platform/x86/toshiba_acpi.c:903: warning: passing argument 3 of
> ‘acpi_remove_notify_handler’ from incompatible pointer type

Patch was here:

http://marc.info/?l=linux-acpi&m=123636477425172&w=2

2009-06-02 14:04:19

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

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.

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.

commit 6edd24bf5ef664e8ac8d5f53774cb9ada8b11a37
Author: Matthew Garrett <[email protected]>
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 <[email protected]>

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 | [email protected]

2009-06-09 16:42:12

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

Hi there:

Sorry for the late reply, lotsa work lately.

On Tue, Jun 2, 2009 at 8:03 AM, Matthew Garrett<[email protected]> 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 <[email protected]>
> 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 <[email protected]>
>
> 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 | [email protected]
>



--
-- El mundo apesta y vosotros apestais tambien --

2009-06-09 16:45:51

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Tue, Jun 09, 2009 at 10:42:00AM -0600, Azael Avalos wrote:

> 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.

Right, but _Q43 should be called when you hit a hotkey. The fact that
it's not is what's causing the problem here.

> 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...

When you hit a hotkey, what happens in /proc/interrupts? Do you see an
i8042 event or an acpi event?
--
Matthew Garrett | [email protected]

2009-06-10 00:19:14

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Tue, Jun 9, 2009 at 10:45 AM, Matthew Garrett<[email protected]> wrote:

> When you hit a hotkey, what happens in /proc/interrupts? Do you see an
> i8042 event or an acpi event?

Indeed an i8042 event pops up, actually dmesg shows the following
regardless of the hotkey pressed, even by only pressing the Fn key:

atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.


Saludos
Azael


--
-- El mundo apesta y vosotros apestais tambien --

2009-06-10 00:22:46

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Tue, Jun 09, 2009 at 06:18:59PM -0600, Azael Avalos wrote:

> Indeed an i8042 event pops up, actually dmesg shows the following
> regardless of the hotkey pressed, even by only pressing the Fn key:
>
> atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
> atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.

On press or on release? We could potentially grab that inside
toshiba_acpi and use that to trigger the poll, but we'd still need to
clear the value again. That's kind of ugly. The _Q43 method is clearly
what should be being executed, so maybe there's another call we can make
that enables it. I'll dig into your DSDT some more.

--
Matthew Garrett | [email protected]

2009-06-10 00:30:01

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

On Tue, Jun 9, 2009 at 6:22 PM, Matthew Garrett<[email protected]> wrote:
> On Tue, Jun 09, 2009 at 06:18:59PM -0600, Azael Avalos wrote:
>
>> Indeed an i8042 event pops up, actually dmesg shows the following
>> regardless of the hotkey pressed, even by only pressing the Fn key:
>>
>> atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
>> atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.
>
> On press or on release? We could potentially grab that inside
> toshiba_acpi and use that to trigger the poll, but we'd still need to
> clear the value again.

On both actually

> That's kind of ugly. The _Q43 method is clearly
> what should be being executed, so maybe there's another call we can make
> that enables it. I'll dig into your DSDT some more.
>

Cool, hopefully you can find something useful there that I missed,
which by the way, that DSDT is incomplete, I can't compile it w/
Intel's compiler...


Saludos
Azael


--
-- El mundo apesta y vosotros apestais tambien --

2009-06-18 00:36:15

by Azael Avalos

[permalink] [raw]
Subject: Re: [PATCH 2/2] toshiba-acpi: Support TOS1900-type devices

I've been playing w/ the omnibook module these days and I got hotkeys
"working".

I don't know why _Q43 is not being triggered, however I got the NTFY
method to activate the TECF variable and so I can finally poll the TOHK
variable to get the hotkey. I'm not sure is this is the correct way of doing
things but we are in business.

Basically this is what I did:

1. Activate HCI Hotkey Events call 0x1E
2. Pressing a hotkey generates an i8042 event (0x6e)
3. Evaluate NTFY method, so TECF is at one
4. Poll INFO method to get last pressed hotkey (once ;-) )
5. Generate keycode for that hotkey

Here's the output of the omnibook module while pressing Fn alone
and then Fn-Esc:

atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.
omnibook: detected scancode 0x100.
omnibook: generating keycode 464.
atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.
omnibook: detected scancode 0x17f.
omnibook: generating keycode 464.
atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.
omnibook: detected scancode 0x100.
omnibook: generating keycode 464.
atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.
omnibook: detected scancode 0x17f.
omnibook: generating keycode 464.
atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.
omnibook: detected scancode 0x101.
omnibook: generating keycode 113.
atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.
omnibook: detected scancode 0x101.
omnibook: generating keycode 113.
atkbd.c: Unknown key released (translated set 2, code 0x6e on isa0060/serio0).
atkbd.c: Use 'setkeycodes 6e <keycode>' to make it known.
omnibook: detected scancode 0x100.
omnibook: generating keycode 464.


Saludos
Azael


--
-- El mundo apesta y vosotros apestais tambien --