View previous topic :: View next topic |
Author |
Message |
.yankee Apprentice
Joined: 24 Feb 2008 Posts: 194 Location: Polska
|
Posted: Mon Feb 25, 2008 1:42 am Post subject: Dell latitude C610: doubled Suspend signal |
|
|
Hi, all!
I have a problem in using the suspend button on my laptop (the Fn+Esc combination).
ACPI receives a signal on both pressing and releasing the button:
Code: |
Feb 25 02:03:43 jan acpid: received event "button/sleep SBTN 00000080 00000134"
Feb 25 02:03:43 jan acpid: notifying client 4567[103:443]
Feb 25 02:03:43 jan acpid: executing action "/etc/acpi/default.sh button/sleep SBTN 00000080 00000134"
Feb 25 02:03:43 jan logger: ACPI event unhandled: button/sleep SBTN 00000080 00000134
Feb 25 02:03:43 jan acpid: action exited with status 0
Feb 25 02:03:43 jan acpid: completed event "button/sleep SBTN 00000080 00000134"
Feb 25 02:03:43 jan acpid: received event "button/sleep SBTN 00000080 00000135"
Feb 25 02:03:43 jan acpid: notifying client 4567[103:443]
Feb 25 02:03:43 jan acpid: executing action "/etc/acpi/default.sh button/sleep SBTN 00000080 00000135"
Feb 25 02:03:43 jan logger: ACPI event unhandled: button/sleep SBTN 00000080 00000135
Feb 25 02:03:43 jan acpid: action exited with status 0
Feb 25 02:03:43 jan acpid: completed event "button/sleep SBTN 00000080 00000135"
|
(This was the case, when the script /etc/acpi/default.sh had no section for action "sleep" - and it was treated as unhandled)
The problem is, that I need to receive only one signal - could be the release of the key - because, in other case, the acpi preforms hibernation twice (the laptop hibernates again immediately after being woken up).
As you can see from the code, the value passed with "sleep" action is just incremental - it does not indicate, whether the button is sunk, or released.
I could, of course send only one signal, by:
- pressing Fn
- pressing Esc (Suspend)
- releasing Fn
- releasing Esc (NOT interpreted as "Suspend" this time)
but this is rather unnatural, ane if I forget to do it that way, the double-hibernation problem would again occur.
So, I temporarily came up with such a solution:
/etc/acpi/default.sh (fragment) Code: |
sleep)
logger "====== Value: $value ======"
if [ -f /tmp/.acpi_suspend_lock ]
then
rm /tmp/.acpi_suspend_lock
logger "######### THE SIGNAL! #########"
/usr/sbin/hibernate
else
echo $value > /tmp/.acpi_suspend_lock
logger "####### THE LOCK IS SET #######"
fi
;;
|
Which makes the hibernate script be called every other time the "sleep" signal occurs. Still, this is neither neat nor safe solution (for example, the tmp/.acpi_suspend_lock file could be created by someone else and therefore inaccessible for acpid).
My question here is:
How should it be done in a nicer way?
Thanks in advance for any tips.
P.S. here's my full /etc/acpi/default.sh just in case someone got confused:
Code: |
#!/bin/sh
# /etc/acpi/default.sh
# Default acpi script that takes an entry for all actions
set $*
group=${1%%/*}
action=${1#*/}
device=$2
id=$3
value=$4
log_unhandled() {
logger "ACPI event unhandled: $*"
}
case "$group" in
button)
case "$action" in
power)
/sbin/init 0
;;
# if your laptop doesnt turn on/off the display via hardware
# switch and instead just generates an acpi event, you can force
# X to turn off the display via dpms. note you will have to run
# 'xhost +local:0' so root can access the X DISPLAY.
#lid)
# xset dpms force off
# ;;
sleep)
logger "====== Value: $value ======"
if [ -f /tmp/.acpi_suspend_lock ]
then
rm /tmp/.acpi_suspend_lock
logger "######### THE SIGNAL! #########"
/usr/sbin/hibernate
else
echo $value > /tmp/.acpi_suspend_lock
logger "####### THE LOCK IS SET #######"
fi
;;
*) log_unhandled $* ;;
esac
;;
ac_adapter)
case "$value" in
# Add code here to handle when the system is unplugged
# (maybe change cpu scaling to powersave mode). For
# multicore systems, make sure you set powersave mode
# for each core!
#*0)
# cpufreq-set -g powersave
# ;;
# Add code here to handle when the system is plugged in
# (maybe change cpu scaling to performance mode). For
# multicore systems, make sure you set performance mode
# for each core!
#*1)
# cpufreq-set -g performance
# ;;
*) log_unhandled $* ;;
esac
;;
*) log_unhandled $* ;;
esac
|
|
|
Back to top |
|
|
BradN Advocate
Joined: 19 Apr 2002 Posts: 2391 Location: Wisconsin (USA)
|
Posted: Mon Feb 25, 2008 6:16 am Post subject: |
|
|
Realistically, I don't think someone's going to attempt a "hibernation DOS" attack on your machine, and I suppose the only other logical approach I can think of would be making a script parse the event numbers and ignore the (even|odd) numbered events.
If you're worried about the lock file being accessed improperly, just change the location and set the permissions accordingly. Otherwise it sounds like you've found a decent solution to an irritating problem |
|
Back to top |
|
|
.yankee Apprentice
Joined: 24 Feb 2008 Posts: 194 Location: Polska
|
Posted: Mon Feb 25, 2008 8:15 pm Post subject: |
|
|
Thanks for your kind word
But I'm a rather stubborn bastard and I still think my way is not good enough.
I didn't actually mean hibernation DOS attack - one could do something more nasty. For instance, they could create the /tmp/.acpi_suspend_lock to be a link to some important system configuration file. This one would be then overwritten by the "echo $value > /tmp/.acpi_suspend_lock" command. I could of course use "touch /tmp/.acpi_suspend_lock" instead - but would that be enough..?
Anyway - I at first thought about the same thing as you mentioned - watching for odd/even values of $value. The problem is that I am too poor at shell programming to do that (I'm not asking for a howto on that though - I'm sure any online shell tutorial would help me out). This is a bit better, I believe, because it does not operate on files.
Still, the two approaches have one more drawback: If I press the button for too long, multiple signals would be sent. So the ideal solution would be one that would trigger an action only on release of the button. But I don't know where I could get the information on whether a key is down or up - I guess that would need some editing of keyboard driver/module code? Kernel-programming? I guess that would be a nice point for me to start kernel hacking
Yes, I'm a problem-inventor. That's my hobby
It makes me learn and gain satisfaction. |
|
Back to top |
|
|
BradN Advocate
Joined: 19 Apr 2002 Posts: 2391 Location: Wisconsin (USA)
|
Posted: Tue Feb 26, 2008 12:07 am Post subject: |
|
|
Well, I don't think standard keyboard rules apply here, since the event is being delivered via ACPI and not the keyboard (most laptops won't even report the fn key or some special combinations, for example). Probably you would have to alter the system ACPI code to change this behavior, so I don't think there's many better ways to go about this than what you've done.
Perhaps a time delay to ignore suspend signals after getting one rather than ignoring alternating events might work too. I don't know how easy that would be to implement if the system suspends during the delay and then comes back with the clock that much farther along. Perhaps a series of short delays would work better (since a clock advance would only affect one of them). |
|
Back to top |
|
|
.yankee Apprentice
Joined: 24 Feb 2008 Posts: 194 Location: Polska
|
Posted: Tue Feb 26, 2008 5:05 pm Post subject: |
|
|
I thought of time delay as well... Maybe I'll do it next.
It turned out, that my idea to act only on button release was not good; running showkey revealed, that each press-and-release of the button (Fn+Esc that is), sends a sequence of pressed-released-pressed-released. So this won't do.
Anyways, I dug a little in kernel sources (2.6.21-suspend2-r7), and found the code responsible for sending the acpi sleep-button signals in drivers/acpi/button.c. After a few tries, I got a solution, which suits me better, then the earlier script. Here's a patch:
Code: |
--- /usr/src/linux/drivers/acpi/button-orig.c 2008-02-26 03:42:43.000000000 +0000
+++ /usr/src/linux/drivers/acpi/button.c 2008-02-26 05:39:29.000000000 +0000
@@ -274,8 +274,12 @@
}
input_sync(input);
- acpi_bus_generate_event(button->device, event,
- ++button->pushed);
+ if ( !((button->type == ACPI_BUTTON_TYPE_SLEEP) // is NOT the sleep btn
+ || (button->type == ACPI_BUTTON_TYPE_SLEEPF))
+ || (button->pushed %2)) // or (if is), is pressed twice (?)
+ acpi_bus_generate_event(button->device, event, ++button->pushed);
+ else ++button->pushed;
+
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
This works fine so far, but I'm not sure, whether I didn't mess up anything with that modification. Can some dev give an opinion on my patch?... |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|