This patch fixes a problem with Sony Vaio laptops where they don't notify
the kernel of power source change events. That means apmd is never told
and many of the apmd features can't be used.
The Sony Vaio that I have doesn't send APM events to the kernel telling it
about 'going on battery' or 'going on AC power' events. It will register
them correctly if they're queried but it won't asynchronously send an event
so the kernel never tells apmd about it.
This patch fixes the situation by checking against the last known power
state (and power source) in the check_status() call.
This was tested on a Sony Vaio z505js, model PCG-5201 and it works
beautifully. I'm told other Vaio notebooks have this same problem. Now,
Vaio users can setup apmd to aggressively try to save power when on battery
or perform other crazy tasks.
This patch is against v2.4.16 but applies to newer kernels as well.
diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c Fri Jul 26 14:29:55 2002
+++ b/arch/i386/kernel/apm.c Fri Jul 26 14:29:55 2002
@@ -1313,6 +1313,34 @@
break;
}
}
+
+ /*
+ * The Sony Vaio doesn't seem to want to send us a notify
+ * about AC line power status changes. So, we have to keep track
+ * of it by hand and emulate it here.
+ * -- Cort <[email protected]>
+ */
+ if ( is_sony_vaio_laptop ) {
+ static int last_status = 0;
+ u_short status, bat, life;
+
+ /* get the current power state */
+ if ( apm_get_power_status(&status, &bat, &life) !=
+ APM_SUCCESS ) {
+ printk("%s:%s error checking power status\n",
+ __FILE__,__FUNCTION__);
+ }
+
+ /* has the status changed since we were last here? */
+ if (((status >> 8) & 0xff) != last_status) {
+ last_status = (status >> 8) & 0xff;
+
+ /* fake a APM_POWER_STATUS_CHANGE event */
+ send_event(APM_POWER_STATUS_CHANGE);
+ queue_event(APM_POWER_STATUS_CHANGE, NULL);
+ }
+
+ }
}
static void apm_event_handler(void)
Fine with me. As long as my vaio model works right :)
I can dig through there and create a blacklist that has one entry for now.
} But not all Vaio's. My z600 (which is what they sold the z505 series as in .eu)
} for example behaves correctly when I plug in/pull out the power cord
} repeatedly.
}
} We might be better off special casing 'known bad' models in the
} DMI blacklist instead of assuming carte blanche that all vaio's are bad.
} Might even come down to a specific BIOS version that's at fault.
On Fri, Jul 26, 2002 at 02:33:45PM -0600, Cort Dougan wrote:
> This was tested on a Sony Vaio z505js, model PCG-5201 and it works
> beautifully. I'm told other Vaio notebooks have this same problem.
But not all Vaio's. My z600 (which is what they sold the z505 series as in .eu)
for example behaves correctly when I plug in/pull out the power cord
repeatedly.
We might be better off special casing 'known bad' models in the
DMI blacklist instead of assuming carte blanche that all vaio's are bad.
Might even come down to a specific BIOS version that's at fault.
Dave
--
| Dave Jones. http://www.codemonkey.org.uk
| SuSE Labs
Can you check to make sure for me? If you stick a 'wall my power changed $*'
into /etc/apmd_proxy or /etc/sysconfig/apm-scripts/scripts (or where-ever
SuSE puts it) then pull the power from your Vaio what does it give you? I
can get the 'apm' commant to tell me the power state (same with the gnome
applets) but apmd is never asynchronously notified.
I'm trying to find which versions/models do this so I can properly
characterize the check agains the DMI data.
} But not all Vaio's. My z600 (which is what they sold the z505 series as in .eu)
} for example behaves correctly when I plug in/pull out the power cord
} repeatedly.
}
} We might be better off special casing 'known bad' models in the
} DMI blacklist instead of assuming carte blanche that all vaio's are bad.
} Might even come down to a specific BIOS version that's at fault.
}
} Dave
}
} --
} | Dave Jones. http://www.codemonkey.org.uk
} | SuSE Labs
On Fri, Jul 26, 2002 at 04:26:45PM -0600, Cort Dougan wrote:
> Can you check to make sure for me? If you stick a 'wall my power changed $*'
> into /etc/apmd_proxy or /etc/sysconfig/apm-scripts/scripts (or where-ever
> SuSE puts it) then pull the power from your Vaio what does it give you? I
> can get the 'apm' commant to tell me the power state (same with the gnome
> applets) but apmd is never asynchronously notified.
Ah, I completely misunderstood the problem. The Gnome-applets are
polling, and hence seeing the change I guess. Your suspicion seems to
be correct, and I was wrong, my z600 needs your patch too.
Dave (eating words)
--
| Dave Jones. http://www.codemonkey.org.uk
| SuSE Labs
I tried it on another Vaio here and found my explanation was unclear when
he misunderstood me, too.
} Ah, I completely misunderstood the problem. The Gnome-applets are
} polling, and hence seeing the change I guess. Your suspicion seems to
} be correct, and I was wrong, my z600 needs your patch too.
The patch with the DMI checking is below. It's probably better done this
way anyway since there are likely other systems out there that do this as
well. It's a rarely used feature it seems.
If you could try it out and see if it works for you I'd appreciate it. I'd
like to get it included in 2.4 with Marcelo so I don't have to keep it around.
diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c Fri Jul 26 16:48:55 2002
+++ b/arch/i386/kernel/apm.c Fri Jul 26 16:48:55 2002
@@ -1313,6 +1313,34 @@
break;
}
}
+
+ /*
+ * The Sony Vaio doesn't seem to want to send us a notify
+ * about AC line power status changes. So, we have to keep track
+ * of it by hand and emulate it here.
+ * -- Cort <[email protected]>
+ */
+ if ( apm_bios_power_change_bug ) {
+ static int last_status = 0;
+ u_short status, bat, life;
+
+ /* get the current power state */
+ if ( apm_get_power_status(&status, &bat, &life) !=
+ APM_SUCCESS ) {
+ printk("%s:%s error checking power status\n",
+ __FILE__,__FUNCTION__);
+ }
+
+ /* has the status changed since we were last here? */
+ if (((status >> 8) & 0xff) != last_status) {
+ last_status = (status >> 8) & 0xff;
+
+ /* fake a APM_POWER_STATUS_CHANGE event */
+ send_event(APM_POWER_STATUS_CHANGE);
+ queue_event(APM_POWER_STATUS_CHANGE, NULL);
+ }
+
+ }
}
static void apm_event_handler(void)
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c Fri Jul 26 16:48:55 2002
+++ b/arch/i386/kernel/dmi_scan.c Fri Jul 26 16:48:55 2002
@@ -12,6 +12,7 @@
unsigned long dmi_broken;
int is_sony_vaio_laptop;
+int apm_bios_power_change_bug = 0;
struct dmi_header
{
@@ -346,6 +347,27 @@
return 0;
}
+
+/*
+ * Some Vaio laptops don't notify the kernel of a power status change
+ * such as on-AC/on-battery. This detects some of the faulty machines
+ * and sets a variable that lets arch/i386/kernel/apm.c deal with it.
+ *
+ * I've seen this with the Vaio z505js PCG-5201 and PCG-SR33:
+
+ * model PCG-Z505JS(UC), bios Phoenix Technologies LTD version R0121Z1
+ * model PCG-SR33(UC), bios Phoenix Technologies LTD version R0211D1
+ * -- Cort <[email protected]>
+ */
+static __init int sony_vaio_apm_change(struct dmi_blacklist *d)
+{
+ apm_bios_power_change_bug = 1;
+ printk(KERN_WARNING "%s detected: APM power status change workaround enabled\n",
+ d->ident);
+ return 0;
+}
+
+
/*
* The Intel 440GX hall of shame.
*
@@ -611,6 +633,12 @@
{ set_apm_ints, "IBM", { /* Allow interrupts during suspend on IBM laptops */
MATCH(DMI_SYS_VENDOR, "IBM"),
NO_MATCH, NO_MATCH, NO_MATCH
+ } },
+
+ { sony_vaio_apm_change, "Sony Vaio", { /* APM won't send power change events */
+ MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+ NO_MATCH, NO_MATCH
} },
{ NULL, }
diff -Nru a/include/asm-i386/system.h b/include/asm-i386/system.h
--- a/include/asm-i386/system.h Fri Jul 26 16:48:55 2002
+++ b/include/asm-i386/system.h Fri Jul 26 16:48:55 2002
@@ -356,6 +356,7 @@
extern unsigned long dmi_broken;
extern int is_sony_vaio_laptop;
+extern int apm_bios_power_change_bug;
#define BROKEN_ACPI_Sx 0x0001
#define BROKEN_INIT_AFTER_S1 0x0002
Hi there Cort,
It looks like my Vaio will need it as well -- loading the apm module
with debug=1 doesn't show any on/off battery events when I yank the
power. (It does log other events, though.)
A comment on the patch? How about pushing the specifics of the
apm_bios_power_change_bug from check_events() down into either the
get_event() or apm_get_event() routines? That way the specifics are
abstracted a bit from the main event dispatch loop, and one gets to
inherit the debug logging and whatnot.
And, in case you decide to tighten up the dmi matching, my laptop info
follows:
BIOS Information Block
Vendor: Phoenix Technologies LTD
Version: R0117A0
Release: 04/25/00
System Information Block
Vendor: Sony Corporation
Product: PCG-XG29(UC)
Thanks,
Ray
Thanks for the report, I'll add that to the comments for completeness.
I think this affects all Vaio laptops. With enough reports maybe
we'll find out something different, though.
Thanks for the suggestion to move the get_event(). I'll see about moving
that (but not on a friday night).
} It looks like my Vaio will need it as well -- loading the apm module
} with debug=1 doesn't show any on/off battery events when I yank the
} power. (It does log other events, though.)
}
} A comment on the patch? How about pushing the specifics of the
} apm_bios_power_change_bug from check_events() down into either the
} get_event() or apm_get_event() routines? That way the specifics are
} abstracted a bit from the main event dispatch loop, and one gets to
} inherit the debug logging and whatnot.
}
} And, in case you decide to tighten up the dmi matching, my laptop info
} follows:
}
} BIOS Information Block
} Vendor: Phoenix Technologies LTD
} Version: R0117A0
} Release: 04/25/00
} System Information Block
} Vendor: Sony Corporation
} Product: PCG-XG29(UC)
On Fri, 2002-07-26 at 19:17, [email protected] wrote:
> I think this affects all Vaio laptops. With enough reports maybe
> we'll find out something different, though.
Agreed to both.
> Thanks for the suggestion to move the get_event(). I'll see about moving
> that (but not on a friday night).
Heh, you mean you have a life? I'm jealous :-)
Below is my suggestion for the patch. Mostly it's just a rework of the
structure, but one thing that cropped up is that 2.4.18 got rid of the
send_event() call. Also, as you'll note from the patch I'm suggesting we
back off from identifying systems one by one, and instead just always do
the right thing: if the BIOS decides to step up and take responsibility
for power change events, then disable the workaround code. Otherwise,
let it be and send a notification as if the BIOS had done it correctly
to begin with.
Comments?
diff -NurX dontdiff linux/arch/i386/kernel/apm.c apm-fixes/arch/i386/kernel/apm.c
--- linux/arch/i386/kernel/apm.c 2002-06-08 08:31:24.000000000 -0700
+++ apm-fixes/arch/i386/kernel/apm.c 2002-07-28 17:48:42.000000000 -0700
@@ -385,6 +385,7 @@
static int ignore_sys_suspend;
static int ignore_normal_resume;
static int bounce_interval = DEFAULT_BOUNCE_INTERVAL;
+static u_short last_power_status;
#ifdef CONFIG_APM_RTC_IS_GMT
# define clock_cmos_diff 0
@@ -1240,15 +1241,40 @@
apm_eventinfo_t info;
static int notified;
+ static u_short power_event_state = 0;
/* we don't use the eventinfo */
error = apm_get_event(&event, &info);
- if (error == APM_SUCCESS)
+ if (error == APM_SUCCESS) {
+ /* if BIOS reports power changes, disable workaround */
+ if (event == APM_POWER_STATUS_CHANGE)
+ power_event_state = 2;
return event;
+ }
if ((error != APM_NO_EVENTS) && (notified++ == 0))
apm_error("get_event", error);
+ /*
+ * Sony Vaios don't seem to want to notify us about AC line power
+ * status changes. So for those and any others like them, we keep
+ * track of it by hand and emulate it here.
+ */
+ if (power_event_state < 2) {
+ u_short status, bat, life;
+ error = apm_get_power_status(&status, &bat, &life);
+ if (error == APM_SUCCESS && (status ^ last_power_status) & 0xff00) {
+ /* fake an APM_POWER_STATUS_CHANGE event */
+ last_power_status = status;
+ if (power_event_state == 0) {
+ printk(KERN_WARNING "apm: power status notification workaround enabled\n");
+ power_event_state = 1;
+ }
+ return APM_POWER_STATUS_CHANGE;
+ } else if (error != APM_SUCCESS)
+ power_event_state=2;
+ }
+
return 0;
}
@@ -1758,6 +1784,7 @@
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
console_blank_hook = apm_console_blank;
#endif
+ apm_get_power_status(&last_power_status, &cx, &dx);
apm_mainloop();
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
console_blank_hook = NULL;
Hi all,
Below is a rework of Cort Dougan's APM patch of last Thursday and
Friday. As a reminder, the issue is that some laptops, notably Vaios,
don't send notification when the power status changes to AC or to
on-battery. The below patch fixes this such that it always just works.
There are three cases. First, the BIOS doesn't send any notifications;
this is fixed. Second, the BIOS sends notifications. In this case, the
code notes that, and disables the workaround. Third, the BIOS sends
notifications, but somehow we managed to notice the power change before
the BIOS could tell us. This seems highly unlikely, but what the heck,
it could theoretically happen. In that case, we disable the workaround,
and drop the notification that the BIOS generated, as we already sent it
onward up the call chain.
The rework was for a couple of small reasons. First, Cort's patch was
against 2.4.16, and 2.4.18 changed a few things in apm.c. Second, this
pushes the specifics of the workaround down to the get_event() routine,
which exists pretty much solely as an abstraction point between the
actual BIOS call (apm_get_event()) and the event dispatch function
(check_events()). Lastly, I see no need to do dmi matching. The code can
be structured to always do the right thing, so that's what we do.
I'm on the road from Thursday to Monday, and won't be reading email, but
comments are welcome. The patch is pretty darn straight-forward, though.
Please consider for the next -ac patch, and 2.4.20-preX. Actual patch
generated against 2.4.19-rc3-ac5.
Ray Lee
diff -NurX /usr/src/dontdiff linux-2.4.19-rc3-ac5/arch/i386/kernel/apm.c linux-2.4.19-rc3-ac5-apm-fixes/arch/i386/kernel/apm.c
--- linux-2.4.19-rc3-ac5/arch/i386/kernel/apm.c 2002-07-31 11:27:39.000000000 -0700
+++ linux-2.4.19-rc3-ac5-apm-fixes/arch/i386/kernel/apm.c 2002-07-31 11:30:19.000000000 -0700
@@ -385,6 +385,7 @@
static int ignore_sys_suspend;
static int ignore_normal_resume;
static int bounce_interval = DEFAULT_BOUNCE_INTERVAL;
+static u_short last_power_status;
#ifdef CONFIG_APM_RTC_IS_GMT
# define clock_cmos_diff 0
@@ -1239,17 +1240,46 @@
int error;
apm_event_t event;
apm_eventinfo_t info;
-
+ static u_short power_event_workaround_enabled = 1;
static int notified;
/* we don't use the eventinfo */
error = apm_get_event(&event, &info);
- if (error == APM_SUCCESS)
+ if (error == APM_SUCCESS) {
+ /* if BIOS reports power changes, disable workaround */
+ if (event == APM_POWER_STATUS_CHANGE) {
+ /* check to see if we jumped the gun and reported a
+ * power change event that the BIOS would have (and
+ * just did) on its own. If so, drop the duplicate.
+ */
+ if (power_event_workaround_enabled)
+ event=get_event();
+ power_event_workaround_enabled = 0;
+ }
return event;
+ }
if ((error != APM_NO_EVENTS) && (notified++ == 0))
apm_error("get_event", error);
+ /*
+ * Sony Vaios don't seem to want to notify us about AC line power
+ * status changes. So for those and any others like them, we keep
+ * track of it by hand and emulate it here.
+ */
+ if (power_event_workaround_enabled) {
+ u_short status, bat, life;
+ error = apm_get_power_status(&status, &bat, &life);
+ if (error == APM_SUCCESS) {
+ if ((status ^ last_power_status) & 0xff00) {
+ /* fake an APM_POWER_STATUS_CHANGE event */
+ last_power_status = status;
+ return APM_POWER_STATUS_CHANGE;
+ }
+ } else
+ power_event_workaround_enabled=0;
+ }
+
return 0;
}
@@ -1758,6 +1788,7 @@
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
console_blank_hook = apm_console_blank;
#endif
+ apm_get_power_status(&last_power_status, &cx, &dx);
apm_mainloop();
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
console_blank_hook = NULL;
On 31 Jul 2002, Ray Lee wrote:
> There are three cases. First, the BIOS doesn't send any notifications;
> this is fixed. Second, the BIOS sends notifications. In this case, the
> code notes that, and disables the workaround. Third, the BIOS sends
> notifications, but somehow we managed to notice the power change before
> the BIOS could tell us. This seems highly unlikely, but what the heck,
> it could theoretically happen. In that case, we disable the workaround,
> and drop the notification that the BIOS generated, as we already sent it
> onward up the call chain.
Actually there is one more case, where the BIOS unreliably tells you
something has changed. I have an old Toshiba which I bought with Windows
installed, and it always noticed pulling the plug and going line=>battery,
but only sometimes noticed battery=>line. Of course this might be an o/s
bug. Can't test that any more, the battery failed and the transition is
now line=>dead.
Anyway, if you are paranoid you could just ignore the "I knew that" cases
and leave the workaround in place, unless that would generate other
issues.
--
bill davidsen <[email protected]>
CTO, TMR Associates, Inc
Doing interesting things with little computers since 1979.
[Trimmed the cc:]
On Wed, 2002-07-31 at 13:10, Bill Davidsen wrote:
> Actually there is one more case, where the BIOS unreliably tells you
> something has changed. I have an old Toshiba which I bought with Windows
> installed, and it always noticed pulling the plug and going line=>battery,
> but only sometimes noticed battery=>line. Of course this might be an o/s
> bug.
Well, that's just special. I wonder where the blame lies in that case.
> Can't test that any more, the battery failed and the transition is
> now line=>dead.
Heh.
> Anyway, if you are paranoid you could just ignore the "I knew that" cases
> and leave the workaround in place, unless that would generate other
> issues.
Hmm. I don't think that would cover everything. Taking your example
case, and assuming it's the BIOS being flaky, we'd have to just ignore
all transitions from the BIOS apm and just poll ourselves. Otherwise,
we'd have line->battery (signaled), battery->line (not signaled),
line->battery (signaled) and *then* we'd know to be paranoid. In the
meantime, we lost the second transition, which could have been hours
ago. The solution in that case would be to infrequently poll (say, twice
a minute) to verify what the BIOS told us. If it's out of sync, give it
a bit of a grace period, double-check, then take over the reins for
reporting.
The bottom line is that I didn't want to incur an extra set of BIOS
calls on systems that don't need it, on general principle. <Shrug> Heck,
maybe it's fast and the overhead is unnoticeable, but I don't know (ISTR
some low-latency issues when doing BIOS calls). Considering the APM
thread is only getting invoked once a second, it's seems that it would
be unnoticeable and zero risk, but hey, what do I know.
Anyway, a patch to do double-checking would be fairly straight-forward,
but without any reports of hardware out there that fails like that...
dunno. I'll work up a patch when I'm back from my road trip and see if
it's as clean.
Ray
On 1 Aug 2002, Ray Lee wrote:
> [Trimmed the cc:]
> On Wed, 2002-07-31 at 13:10, Bill Davidsen wrote:
> > Actually there is one more case, where the BIOS unreliably tells you
> > something has changed. I have an old Toshiba which I bought with Windows
> > installed, and it always noticed pulling the plug and going line=>battery,
> > but only sometimes noticed battery=>line. Of course this might be an o/s
> > bug.
>
> Well, that's just special. I wonder where the blame lies in that case.
>
> > Can't test that any more, the battery failed and the transition is
> > now line=>dead.
>
> Heh.
>
> > Anyway, if you are paranoid you could just ignore the "I knew that" cases
> > and leave the workaround in place, unless that would generate other
> > issues.
>
> Hmm. I don't think that would cover everything. Taking your example
> case, and assuming it's the BIOS being flaky, we'd have to just ignore
> all transitions from the BIOS apm and just poll ourselves. Otherwise,
> we'd have line->battery (signaled), battery->line (not signaled),
> line->battery (signaled) and *then* we'd know to be paranoid. In the
> meantime, we lost the second transition, which could have been hours
> ago. The solution in that case would be to infrequently poll (say, twice
> a minute) to verify what the BIOS told us. If it's out of sync, give it
> a bit of a grace period, double-check, then take over the reins for
> reporting.
Okay, I said "other issues" and that certainly is one.
> The bottom line is that I didn't want to incur an extra set of BIOS
> calls on systems that don't need it, on general principle. <Shrug> Heck,
> maybe it's fast and the overhead is unnoticeable, but I don't know (ISTR
> some low-latency issues when doing BIOS calls). Considering the APM
> thread is only getting invoked once a second, it's seems that it would
> be unnoticeable and zero risk, but hey, what do I know.
>
> Anyway, a patch to do double-checking would be fairly straight-forward,
> but without any reports of hardware out there that fails like that...
> dunno. I'll work up a patch when I'm back from my road trip and see if
> it's as clean.
Bear in mind that I was being pedantic to mention the other case, I would
think that if this is worth doing at all (is it?) just an option to ignore
the BIOS might be fine:
modprobe apm my_bios_sucks=sad_but_true
or some such. If anyone was convinced there was such an issue they could
do it. Again, it could have been the o/s just losing the int when running
slow on battery. M$ losing ints? Nah, can't happen ;-)
--
bill davidsen <[email protected]>
CTO, TMR Associates, Inc
Doing interesting things with little computers since 1979.