diff mbox

toshiba_acpi: Add full hotkey support

Message ID 20090306005234.GA32539@srcf.ucam.org (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Matthew Garrett March 6, 2009, 12:52 a.m. UTC
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@redhat.com>

---

Oops - previous version included a broken Kconfig hunk and I messed up 
Len's address. This one should be good.

Comments

Richard Hughes March 6, 2009, 9:08 a.m. UTC | #1
On Fri, 2009-03-06 at 00:52 +0000, 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.

Great news - no polling!

Definitely +1 from me.

Richard.




--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Daniel Silverstone March 6, 2009, 9:47 a.m. UTC | #2
On Fri, 2009-03-06 at 09:08 +0000, Richard Hughes wrote:
> On Fri, 2009-03-06 at 00:52 +0000, 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.
> Great news - no polling!

No polling is definitely a good thing.

> Definitely +1 from me.

I'll be a touch less gung-ho than Richard though.

Have you looked at whether or not this method functions on more than the
one laptop? Toshiba are notoriously good at getting their own interfaces
wrong from one laptop to another. In addition, the fn+whatever keymaps
are often different between laptops, especially for things like the WWW
or MAIL buttons. Presumably if the hotkeys fail to activate then the
normal /proc/acpi/toshiba/keys thing will continue?

How will it interact with software stacks like HAL when the lock button
is pressed?

The patch itself looks clean and nice, I'm just concerned about its
behaviour from laptop-to-laptop. Particularly the key-map thing.

D.
Matthew Garrett March 6, 2009, 9:56 a.m. UTC | #3
On Fri, Mar 06, 2009 at 09:47:23AM +0000, Daniel Silverstone wrote:

> Have you looked at whether or not this method functions on more than the
> one laptop? Toshiba are notoriously good at getting their own interfaces
> wrong from one laptop to another.

It's present on every Toshiba DSDT I have that has a VALD/VALZ method.

> In addition, the fn+whatever keymaps are often different between 
> laptops, especially for things like the WWW or MAIL buttons. 
> Presumably if the hotkeys fail to activate then the normal 
> /proc/acpi/toshiba/keys thing will continue?

Yes, it'll be as functional as it was previously. They can be remapped 
on machines that have a different keymap.
 
> How will it interact with software stacks like HAL when the lock button
> is pressed?

I don't really understand the question?
Daniel Silverstone March 6, 2009, 10:04 a.m. UTC | #4
On Fri, 2009-03-06 at 09:56 +0000, Matthew Garrett wrote:
> > Have you looked at whether or not this method functions on more than the
> > one laptop? Toshiba are notoriously good at getting their own interfaces
> > wrong from one laptop to another.
> It's present on every Toshiba DSDT I have that has a VALD/VALZ method.

Nod, I shall have to have a check through the ones here if I can.

> > In addition, the fn+whatever keymaps are often different between 
> > laptops, especially for things like the WWW or MAIL buttons. 
> > Presumably if the hotkeys fail to activate then the normal 
> > /proc/acpi/toshiba/keys thing will continue?
> Yes, it'll be as functional as it was previously. They can be remapped 
> on machines that have a different keymap.

Since I don't understand the input layer well enough yet, can you
confirm if it is possible to add new mappings in without changing the
source? I.E. if laptop <foo> has another hotkey not yet considered, is
it just an FDI for hal, or is it a source change in the kernel?

> > How will it interact with software stacks like HAL when the lock button
> > is pressed?
> I don't really understand the question?

It was more: will events come out of both the notify method *and*
the /proc/acpi/toshiba/keys stuff, or will they only come out of the
notify method if it can be enabled? (I'm just trying to establish that
things polling /proc/acpi/toshiba/keys won't end up causing duplicated
events).

Assuming I'm just being over-paranoid or not understanding the minutae,
then I give this a +1 because the behaviour is certainly desirable since
it'll allow the tosh laptops to not wake up regularly to check for
hotkeys.

D.
Matthew Garrett March 6, 2009, 10:09 a.m. UTC | #5
On Fri, Mar 06, 2009 at 10:04:21AM +0000, Daniel Silverstone wrote:
> On Fri, 2009-03-06 at 09:56 +0000, Matthew Garrett wrote:
> > Yes, it'll be as functional as it was previously. They can be remapped 
> > on machines that have a different keymap.
> 
> Since I don't understand the input layer well enough yet, can you
> confirm if it is possible to add new mappings in without changing the
> source? I.E. if laptop <foo> has another hotkey not yet considered, is
> it just an FDI for hal, or is it a source change in the kernel?

Yes, the remapping can be done from userspace.

> > > How will it interact with software stacks like HAL when the lock button
> > > is pressed?
> > I don't really understand the question?
> 
> It was more: will events come out of both the notify method *and*
> the /proc/acpi/toshiba/keys stuff, or will they only come out of the
> notify method if it can be enabled? (I'm just trying to establish that
> things polling /proc/acpi/toshiba/keys won't end up causing duplicated
> events).

Either the kernel or userspace will get the event, but not both. There's 
an argument for disabling the input code if /proc/acpi/toshiba/keys is 
open in order to avoid breaking anything that expects to get the code 
itself.
Daniel Silverstone March 6, 2009, 10:12 a.m. UTC | #6
On Fri, 2009-03-06 at 10:09 +0000, Matthew Garrett wrote:
> > > > How will it interact with software stacks like HAL when the lock button
> > > > is pressed?
> > > I don't really understand the question?
> > It was more: will events come out of both the notify method *and*
> > the /proc/acpi/toshiba/keys stuff, or will they only come out of the
> > notify method if it can be enabled? (I'm just trying to establish that
> > things polling /proc/acpi/toshiba/keys won't end up causing duplicated
> > events).
> Either the kernel or userspace will get the event, but not both. There's 
> an argument for disabling the input code if /proc/acpi/toshiba/keys is 
> open in order to avoid breaking anything that expects to get the code 
> itself.

I see. One other thing occurred to me. Is there any way for Hal to know
that the notify stuff is in place and thus doesn't need to
poll /proc/acpi/toshiba/keys? Otherwise it's going to poll it anyway
which fails to remove the periodic wakeups.

D.
Matthew Garrett March 6, 2009, 10:15 a.m. UTC | #7
On Fri, Mar 06, 2009 at 10:12:56AM +0000, Daniel Silverstone wrote:

> I see. One other thing occurred to me. Is there any way for Hal to know
> that the notify stuff is in place and thus doesn't need to
> poll /proc/acpi/toshiba/keys? Otherwise it's going to poll it anyway
> which fails to remove the periodic wakeups.

No. Distributions should build without --enable-toshiba if they ship a 
kernel with this functionaliy.
Daniel Silverstone March 6, 2009, 10:21 a.m. UTC | #8
On Fri, 2009-03-06 at 10:15 +0000, Matthew Garrett wrote:
> > I see. One other thing occurred to me. Is there any way for Hal to know
> > that the notify stuff is in place and thus doesn't need to
> > poll /proc/acpi/toshiba/keys? Otherwise it's going to poll it anyway
> > which fails to remove the periodic wakeups.
> No. Distributions should build without --enable-toshiba if they ship a 
> kernel with this functionaliy.

This only makes sense if all the rest of /proc/acpi/toshiba/* is now
implemented in proper modern kernel facilities. I noticed rfkill
switches (although I'll have to see if another is needed for the HSDPA
modems in modern laptops) and a proper brightness control. I assume
xrandr does what video did, which just leaves the fan control.

D.
Andrey Borzenkov March 6, 2009, 6:49 p.m. UTC | #9
Daniel Silverstone wrote:

> On Fri, 2009-03-06 at 10:15 +0000, Matthew Garrett wrote:
>> > I see. One other thing occurred to me. Is there any way for Hal to know
>> > that the notify stuff is in place and thus doesn't need to
>> > poll /proc/acpi/toshiba/keys? Otherwise it's going to poll it anyway
>> > which fails to remove the periodic wakeups.
>> No. Distributions should build without --enable-toshiba if they ship a
>> kernel with this functionaliy.
> 
> This only makes sense if all the rest of /proc/acpi/toshiba/* is now
> implemented in proper modern kernel facilities.

I guess Matthew refers to HAL build switch. In which case only 
/proc/acpi/toshiba/keys is relevant, other files are not used by this HAL 
add-on.

In any case, as I mentioned, this file has to be removed if patch is 
implemented as it is effectively no-op then.

> I noticed rfkill
> switches (although I'll have to see if another is needed for the HSDPA
> modems in modern laptops) and a proper brightness control. I assume
> xrandr does what video did, which just leaves the fan control.
> 

There are two ways to control fan here - standard ACPI and HCI. ACPI does 
not work. Is there any standard framework for fan control (a la 
power_supply) where HCI version could be plugged in?
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Matthew Garrett March 6, 2009, 6:53 p.m. UTC | #10
On Fri, Mar 06, 2009 at 09:49:36PM +0300, Andrey Borzenkov wrote:

> There are two ways to control fan here - standard ACPI and HCI. ACPI does 
> not work. Is there any standard framework for fan control (a la 
> power_supply) where HCI version could be plugged in?

Yes, it could be hooked into the thermal or hwmon layers. Thermal is 
probably best - it'll then automatically be exported as an hwmon device 
as well.
Andrey Borzenkov March 7, 2009, 7:27 a.m. UTC | #11
Matthew Garrett wrote:

> +	{KE_KEY, 0x13d, KEY_SLEEP},
> +	{KE_KEY, 0x13e, KEY_SUSPEND},

I have two buttons marked with memory and disk pictures. When I press the 
first one HAL emits "sleep" button event, for the the second one HAL emits 
"hibernate" event. I am using KDE4 and neither works :) According to KDE4 
developer, they implement "suspend" button as suspend to RAM. Just trying to 
clarify which key this should be and whether HAL should be fixed.  (I opened 
bug report for KDE4)

> +	{KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},

I wonder, who is supposed to act upon it? Is there any generic user space 
agent who implements video output switching?

> +	{KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
> +	{KE_KEY, 0x141, KEY_BRIGHTNESSUP},
> +	{KE_KEY, 0x142, KEY_WLAN},

Ditto. Theoretically Toshiba even supports turning off radio via HCI, but it 
is again not clear who should actually initiate it.

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Matthew Garrett March 7, 2009, 3:06 p.m. UTC | #12
On Sat, Mar 07, 2009 at 10:27:09AM +0300, Andrey Borzenkov wrote:
> Matthew Garrett wrote:
> 
> > +	{KE_KEY, 0x13d, KEY_SLEEP},
> > +	{KE_KEY, 0x13e, KEY_SUSPEND},
> 
> I have two buttons marked with memory and disk pictures. When I press the 
> first one HAL emits "sleep" button event, for the the second one HAL emits 
> "hibernate" event. I am using KDE4 and neither works :) According to KDE4 
> developer, they implement "suspend" button as suspend to RAM. Just trying to 
> clarify which key this should be and whether HAL should be fixed.  (I opened 
> bug report for KDE4)

Yeah, I'm not really a KDE guy, so I'm not sure what's happening there.

> > +	{KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
> 
> I wonder, who is supposed to act upon it? Is there any generic user space 
> agent who implements video output switching?

At present I don't believe so, no.

> > +	{KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
> > +	{KE_KEY, 0x141, KEY_BRIGHTNESSUP},
> > +	{KE_KEY, 0x142, KEY_WLAN},
> 
> Ditto. Theoretically Toshiba even supports turning off radio via HCI, but it 
> is again not clear who should actually initiate it.

Right. In some of these cases there's nothing that currently handles 
them, but userspace should probably get round to it at some point.
Andrey Borzenkov March 7, 2009, 3:38 p.m. UTC | #13
On 7 марта 2009 18:06:40 Matthew Garrett wrote:
> On Sat, Mar 07, 2009 at 10:27:09AM +0300, Andrey Borzenkov wrote:
> > Matthew Garrett wrote:
> > > +	{KE_KEY, 0x13d, KEY_SLEEP},
> > > +	{KE_KEY, 0x13e, KEY_SUSPEND},
> >
> > I have two buttons marked with memory and disk pictures. When I
> > press the first one HAL emits "sleep" button event, for the the
> > second one HAL emits "hibernate" event. I am using KDE4 and neither
> > works :) According to KDE4 developer, they implement "suspend"
> > button as suspend to RAM. Just trying to clarify which key this
> > should be and whether HAL should be fixed.  (I opened bug report
> > for KDE4)
>
> Yeah, I'm not really a KDE guy, so I'm not sure what's happening
> there.
>

Please see reply to another thread titled "Re: suspend / hibernate 
nomenclature".  What happens here is

- addon-acpi-buttons-toshiba emitted "suspend" for Fn-F3 and "hibernate" 
for Fn-F4

- your patch makes HAL emit "sleep" for Fn-F3 and "hibernate" for Fn-F4

So the patch is incompatible change w.r.t. user space. To restore 
previous behaviour we need

- patch toshiba_acpi to return KEY_SUSPEND/KEY_HIBERNATE instead of 
KEY_SLEEP/KEY_SUSPEND. This depends on commit 
6932b918e05b06165ed3457a9f3aa279099a7cbd in linux-next.

- patch HAL to recognize KEY_HIBERNATE and return "suspend" for 
KEY_SUSPEND; right now it is:

        [KEY_SLEEP] = "sleep",
        [KEY_SUSPEND] = "hibernate",

In any case this means that combination of old HAL and new kernel (or 
vice versa) becomes broken. Not sure how to handle it.
Matthew Garrett March 7, 2009, 3:44 p.m. UTC | #14
On Sat, Mar 07, 2009 at 06:38:53PM +0300, Andrey Borzenkov wrote:

> - patch toshiba_acpi to return KEY_SUSPEND/KEY_HIBERNATE instead of 
> KEY_SLEEP/KEY_SUSPEND. This depends on commit 
> 6932b918e05b06165ed3457a9f3aa279099a7cbd in linux-next.
> 
> - patch HAL to recognize KEY_HIBERNATE and return "suspend" for 
> KEY_SUSPEND; right now it is:
> 
>         [KEY_SLEEP] = "sleep",
>         [KEY_SUSPEND] = "hibernate",

Ugh. Why are we changing this? The semantics were pretty clear before. 
The KEY_SUSPEND to hibernate mapping was decided years ago, and it's 
clearly an incompatible change as far as userspace goes.
Richard Hughes March 7, 2009, 8:19 p.m. UTC | #15
On Sat, Mar 7, 2009 at 3:44 PM, Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> On Sat, Mar 07, 2009 at 06:38:53PM +0300, Andrey Borzenkov wrote:
>
>> - patch toshiba_acpi to return KEY_SUSPEND/KEY_HIBERNATE instead of
>> KEY_SLEEP/KEY_SUSPEND. This depends on commit
>> 6932b918e05b06165ed3457a9f3aa279099a7cbd in linux-next.
>>
>> - patch HAL to recognize KEY_HIBERNATE and return "suspend" for
>> KEY_SUSPEND; right now it is:
>>
>>         [KEY_SLEEP] = "sleep",
>>         [KEY_SUSPEND] = "hibernate",
>
> Ugh. Why are we changing this? The semantics were pretty clear before.
> The KEY_SUSPEND to hibernate mapping was decided years ago, and it's
> clearly an incompatible change as far as userspace goes.

See my mails to linux-acpi. Hibernate = sleep to disk, suspend = sleep
to ram, and sleep = sleep type not indicated or unknown. This is how
it is in Xorg and the session now.

Mapping KEY_SUSPEND to hibernate is just insane. Can you please change
the toshiba driver to use KEY_HIBERNATE and KEY_SUSPEND as thinkpad
now does? Thanks.

Richard.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Matthew Garrett March 7, 2009, 8:26 p.m. UTC | #16
On Sat, Mar 07, 2009 at 08:19:51PM +0000, Richard Hughes wrote:

> Mapping KEY_SUSPEND to hibernate is just insane. Can you please change
> the toshiba driver to use KEY_HIBERNATE and KEY_SUSPEND as thinkpad
> now does? Thanks.

Mapping KEY_SUSPEND to hibernate is what we've been doing for years. 
It's what hal *still does*. KEY_SLEEP has been the suspend to RAM key 
forever. How are we supposed to perform this transition? We've no idea 
how much of userspace makes the same assumption.
Richard Hughes March 8, 2009, 8:33 a.m. UTC | #17
On Sat, Mar 7, 2009 at 8:26 PM, Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> On Sat, Mar 07, 2009 at 08:19:51PM +0000, Richard Hughes wrote:
>
>> Mapping KEY_SUSPEND to hibernate is just insane. Can you please change
>> the toshiba driver to use KEY_HIBERNATE and KEY_SUSPEND as thinkpad
>> now does? Thanks.
>
> Mapping KEY_SUSPEND to hibernate is what we've been doing for years.
> It's what hal *still does*.

Sure, but how much userspace now listens to HAL for these events? Xorg
and evdev has taken over that role for all the session. We can ship a
trivial patch as an fdi file to HAL to remap this if required.

> KEY_SLEEP has been the suspend to RAM key forever.

Except if you're a USB keyboard. Grep through the kernel sources and
see how many drivers get this wrong. We can't map three sleep states
to two buttons in any sane way. For instance, is the sleep acpi button
supposed to trigger a suspend of hibernate? Surely this is user policy
as it is not specified on the the exterior of the machine.

> How are we supposed to perform this transition? We've no idea
> how much of userspace makes the same assumption.

FWIW, I think emitting KEY_ events (not switch events) in HAL is crazy
as now we can just use the fixed Xorg in the session. FWIW, HAL gets
other keys wrong too, for instance KEY_BATTERY is mapped to
display_off, but nobody has noticed as we've been using Xorg since
ages.

Richard.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Andrey Borzenkov March 8, 2009, 2:29 p.m. UTC | #18
On 8 марта 2009 11:33:48 Richard Hughes wrote:
> On Sat, Mar 7, 2009 at 8:26 PM, Matthew Garrett <mjg59@srcf.ucam.org> 
wrote:
> > On Sat, Mar 07, 2009 at 08:19:51PM +0000, Richard Hughes wrote:
> >> Mapping KEY_SUSPEND to hibernate is just insane. Can you please
> >> change the toshiba driver to use KEY_HIBERNATE and KEY_SUSPEND as
> >> thinkpad now does? Thanks.
> >
> > Mapping KEY_SUSPEND to hibernate is what we've been doing for
> > years. It's what hal *still does*.
>
> Sure, but how much userspace now listens to HAL for these events?

Apparently KDE still does. At least it does not seem to pay any 
attention to KEY_SUSPEND (nor KEY_SLEEP BTW).

And KDE seems to be important enough customer to not wish to break HAL.

> Xorg and evdev has taken over that role for all the session.

Oh, wait. But even Xorg 1.6.0 interprets KEY_SUSPEND as "hibernate".

KeyPress event, serial 31, synthetic NO, window 0x3e00001,
    root 0xbc, subw 0x0, time 87299792, (81,-11), root:(817,290),
    state 0x0, keycode 213 (keysym 0x1008ffa8, XF86Hibernate), 
same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

So redefining KEY_SUSPEND is going to break Xorg too (as long as anyone 
is using those keysyms).

> We can
> ship a trivial patch as an fdi file to HAL to remap this if required.
>
> > KEY_SLEEP has been the suspend to RAM key forever.

Ehh ... actually at least in Toshiba case it was not :) hald Toshiba 
add-on always emitted exactly "suspend" and "hibernate" D-Bus events. 
Not "sleep".
Matthew Garrett March 8, 2009, 2:36 p.m. UTC | #19
On Sun, Mar 08, 2009 at 08:33:48AM +0000, Richard Hughes wrote:
> On Sat, Mar 7, 2009 at 8:26 PM, Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> > Mapping KEY_SUSPEND to hibernate is what we've been doing for years.
> > It's what hal *still does*.
> 
> Sure, but how much userspace now listens to HAL for these events? Xorg
> and evdev has taken over that role for all the session. We can ship a
> trivial patch as an fdi file to HAL to remap this if required.

I've no idea. But I lean towards not gratuitously breaking it for no 
reason other than aesthetics.

> > KEY_SLEEP has been the suspend to RAM key forever.
> 
> Except if you're a USB keyboard. Grep through the kernel sources and
> see how many drivers get this wrong. We can't map three sleep states
> to two buttons in any sane way. For instance, is the sleep acpi button
> supposed to trigger a suspend of hibernate? Surely this is user policy
> as it is not specified on the the exterior of the machine.

We do it the same way we've previously done it (and the same way it 
works outside the Linux world) - the "suspend to RAM" key has 
configurable behaviour. As far as I can tell, the USB driver does the 
right thing here?

> > How are we supposed to perform this transition? We've no idea
> > how much of userspace makes the same assumption.
> 
> FWIW, I think emitting KEY_ events (not switch events) in HAL is crazy
> as now we can just use the fixed Xorg in the session. FWIW, HAL gets
> other keys wrong too, for instance KEY_BATTERY is mapped to
> display_off, but nobody has noticed as we've been using Xorg since
> ages.

I'm happy with obvious bugs being fixed, but this isn't an obvious bug - 
it's purely an aesthetic issue. We don't need to draw a distinction 
between generic sleep and suspend to RAM keys, especially if the cost of 
doing so is having to fix up an undefined quantity of userspace.
Len Brown March 9, 2009, 5:11 p.m. UTC | #20
On Sun, 8 Mar 2009, Richard Hughes wrote:

> On Sat, Mar 7, 2009 at 8:26 PM, Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> > On Sat, Mar 07, 2009 at 08:19:51PM +0000, Richard Hughes wrote:
> >
> >> Mapping KEY_SUSPEND to hibernate is just insane. Can you please change
> >> the toshiba driver to use KEY_HIBERNATE and KEY_SUSPEND as thinkpad
> >> now does? Thanks.
> >
> > Mapping KEY_SUSPEND to hibernate is what we've been doing for years.
> > It's what hal *still does*.
> 
> Sure, but how much userspace now listens to HAL for these events? Xorg
> and evdev has taken over that role for all the session. We can ship a
> trivial patch as an fdi file to HAL to remap this if required.
> 
> > KEY_SLEEP has been the suspend to RAM key forever.
> 
> Except if you're a USB keyboard. Grep through the kernel sources and
> see how many drivers get this wrong. We can't map three sleep states
> to two buttons in any sane way. For instance, is the sleep acpi button
> supposed to trigger a suspend of hibernate? Surely this is user policy
> as it is not specified on the the exterior of the machine.

While hot-keys are totally platform dependent and non-standard,
the ACPI spec does describe the power and sleep button.

Unfortunately, it doesn't answer this question for us --
stating that the sleep button enters G1, which can be
any of S1-S4.

Len Brown, Intel Open Source Technology Center
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 40e60fc..604f9fa 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,36 @@  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, 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 +284,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 +736,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 +891,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 +926,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",