lkml.org 
[lkml]   [1998]   [Nov]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[PATCH] APM fixes, workarounds and tidying
Date
From
Hi Linus,

This adds Richard Gooch's CONFIG_APM_RTC_IS_GMT patch
to my previous one.

The reiterate, this patch does:
keep /proc/apm consistant
Reset interrupt 0 timer to 100Hz after suspend
Add CONFIG_APM_IGNORE_SUSPEND_BOUNCE
Add CONFIG_APM_RTC_IS_GMT
Allow boot time disabling of APM
Make boot messages far less verbose by default
Make asm safer

Cheers,
Stephen
--
Stephen Rothwell Stephen.Rothwell@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

diff -ru linux-2.1.130/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.1.130/Documentation/Configure.help Sat Nov 28 23:57:36 1998
+++ linux/Documentation/Configure.help Mon Nov 30 23:43:59 1998
@@ -8328,6 +8328,35 @@
ignored. Without this the Thinkpad 560 has troubles with the user
level daemon apmd, and with the PCMCIA package pcmcia-cs.

+Ignore multiple suspend/resume cycles
+CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ This option is necessary on the Dell Inspiron 3200, but should be
+ safe for all other laptops. When enabled, a system suspend event
+ that occurs within one second of a resume is ignored. Without this
+ the Inspiron will shut itself off a few seconds after you open the
+ lid, requiring you to press the power button to resume it a second
+ time.
+ Say Y.
+
+RTC stores time in GMT
+CONFIG_APM_RTC_IS_GMT
+ This option can be used when your RTC (Real Time Clock aka. Hardware
+ Clock) stores the time in GMT (Greenwich Mean Time) rather than
+ localtime. When suspending/resuming, the kernel needs to know what
+ is stored in the RTC so it can update the system clock (which is
+ always GMT). Without this option the kernel attempts to measure the
+ offset between the RTC and the system clock. This means you can
+ loose one second on each suspend/resume cycle.
+ Also, on the Dell Inspiron 3200, the hardware slows down the system
+ even before the kernel can measure the RTC/system clock offset. It
+ can then take 15 seconds to do this measurement and it can be
+ incorrect by several seconds.
+ Say Y if GMT is stored in your RTC.
+ GMT is usually the best anyway, because you don't have to
+ worry about daylight savings time changes. The only reason to not
+ use GMT in your RTC is if you also run a broken OS that doesn't
+ understand GMT.
+
Watchdog Timer Support
CONFIG_WATCHDOG
If you say Y here (and to one of the following options) and create a
diff -ru linux-2.1.130/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- linux-2.1.130/arch/i386/boot/setup.S Fri Oct 9 23:43:07 1998
+++ linux/arch/i386/boot/setup.S Sun Nov 29 01:32:31 1998
@@ -396,8 +396,6 @@
cmp bx,#0x0504d ! check for "PM" signature
jne done_apm_bios ! no signature -> no APM BIOS

- mov [64],ax ! record the APM BIOS version
- mov [76],cx ! and flags
and cx,#0x02 ! Is 32 bit supported?
je done_apm_bios ! no ...

@@ -416,6 +414,26 @@
mov [74],dx ! BIOS data segment
mov [78],esi ! BIOS code segment length
mov [82],di ! BIOS data segment length
+!
+! Redo the installation check as the 32 bit connect
+! modifies the flags returned on some BIOSs
+!
+ mov ax,#0x05300 ! APM BIOS installation check
+ xor bx,bx
+ int 0x15
+ jc apm_disconnect ! error -> should not happen, tidy up
+
+ cmp bx,#0x0504d ! check for "PM" signature
+ jne apm_disconnect ! no signature -> should not happen, tidy up
+
+ mov [64],ax ! record the APM BIOS version
+ mov [76],cx ! and flags
+ jmp done_apm_bios
+
+apm_disconnect:
+ mov ax,#0x05304 ! Disconnect
+ xor bx,bx
+ int 0x15 ! ignore return code
jmp done_apm_bios

no_32_apm_bios:
diff -ru linux-2.1.130/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.1.130/arch/i386/config.in Sun Nov 29 03:51:57 1998
+++ linux/arch/i386/config.in Mon Nov 30 23:44:40 1998
@@ -72,6 +72,8 @@
bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
bool ' Power off on shutdown' CONFIG_APM_POWER_OFF
bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+ bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
fi

endmenu
diff -ru linux-2.1.130/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- linux-2.1.130/arch/i386/kernel/apm.c Fri Oct 9 23:43:07 1998
+++ linux/arch/i386/kernel/apm.c Tue Dec 1 00:02:13 1998
@@ -30,6 +30,7 @@
* Feb 1998, Version 1.4
* Aug 1998, Version 1.5
* Sep 1998, Version 1.6
+ * Nov 1998, Version 1.7
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
@@ -60,6 +61,18 @@
* Fix OOPS at power off with no APM BIOS by Jan Echternach
* <echter@informatik.uni-rostock.de>
* Stephen Rothwell
+ * 1.7: Modify driver's cached copy of the disabled/disengaged flags
+ * to reflect current state of APM BIOS.
+ * Chris Rankin <rankinc@bellsouth.net>
+ * Reset interrupt 0 timer to 100Hz after suspend
+ * Chad Miller <cmiller@surfsouth.com>
+ * Add CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ * Add CONFIG_APM_RTC_IS_GMT
+ * Richard Gooch <rgooch@atnf.csiro.au>
+ * Allow boot time disabling of APM
+ * Make boot messages far less verbose by default
+ * Make asm safer
+ * Stephen Rothwell
*
* APM 1.1 Reference:
*
@@ -167,7 +180,7 @@
*
* U: TI 4000M TravelMate: BIOS is *NOT* APM compliant
* [Confirmed by TI representative]
- * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
+ * ?: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
* [Confirmed by BIOS disassembly]
* [This may work now ...]
* P: Toshiba 1950S: battery life information only gets updated after resume
@@ -215,6 +228,19 @@
#define APM_RELAX_SEGMENTS

/*
+ * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
+ * This patched by Chad Miller <cmiller@surfsouth.com>, orig code by David
+ * Chen <chen@ctpa04.mit.edu>
+ */
+#undef INIT_TIMER_AFTER_SUSPEND
+
+#ifdef INIT_TIMER_AFTER_SUSPEND
+#include <linux/timex.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#endif
+
+/*
* Need to poll the APM BIOS every second
*/
#define APM_CHECK_TIMEOUT (HZ)
@@ -265,15 +291,22 @@
static int waiting_for_resume = 0;
#endif

+#ifdef CONFIG_APM_RTC_IS_GMT
+# define clock_cmos_diff 0
+# define got_clock_diff 1
+#else
static long clock_cmos_diff;
static int got_clock_diff = 0;
+#endif
+static int debug = 0;
+static int apm_disabled = 0;

static struct wait_queue * process_list = NULL;
static struct apm_bios_struct * user_list = NULL;

static struct timer_list apm_timer;

-static char driver_version[] = "1.6"; /* no spaces */
+static char driver_version[] = "1.7"; /* no spaces */

#ifdef APM_DEBUG
static char * apm_event_name[] = {
@@ -393,7 +426,7 @@
# define APM_DO_RESTORE_SEGS
#endif

-static inline u8 apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in,
+static u8 apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in,
u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
{
unsigned int saved_fs;
@@ -404,13 +437,17 @@
APM_DO_CLI;
APM_DO_SAVE_SEGS;
__asm__ __volatile__(APM_DO_ZERO_SEGS
+ "pushl %%edi\n\t"
+ "pushl %%ebp\n\t"
"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
"setc %%al\n\t"
+ "popl %%ebp\n\t"
+ "popl %%edi\n\t"
APM_DO_POP_SEGS
- : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
- "=S" (*esi)
+ : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
+ "=S" (*esi)
: "a" (eax_in), "b" (ebx_in), "c" (ecx_in)
- : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory", "cc");
+ : "memory", "cc");
APM_DO_RESTORE_SEGS;
__restore_flags(flags);
return *eax & 0xff;
@@ -420,7 +457,7 @@
* This version only returns one value (usually an error code)
*/

-static inline u8 apm_bios_call_simple(u32 eax_in, u32 ebx_in, u32 ecx_in,
+static u8 apm_bios_call_simple(u32 eax_in, u32 ebx_in, u32 ecx_in,
u32 *eax)
{
u8 error;
@@ -431,13 +468,22 @@
__save_flags(flags);
APM_DO_CLI;
APM_DO_SAVE_SEGS;
- __asm__ __volatile__(APM_DO_ZERO_SEGS
- "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
- "setc %%bl\n\t"
- APM_DO_POP_SEGS
- : "=a" (*eax), "=b" (error)
- : "a" (eax_in), "b" (ebx_in), "c" (ecx_in)
- : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory", "cc");
+ {
+ int cx, dx, si;
+
+ __asm__ __volatile__(APM_DO_ZERO_SEGS
+ "pushl %%edi\n\t"
+ "pushl %%ebp\n\t"
+ "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
+ "setc %%bl\n\t"
+ "popl %%ebp\n\t"
+ "popl %%edi\n\t"
+ APM_DO_POP_SEGS
+ : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx),
+ "=S" (si)
+ : "a" (eax_in), "b" (ebx_in), "c" (ecx_in)
+ : "memory", "cc");
+ }
APM_DO_RESTORE_SEGS;
__restore_flags(flags);
return error;
@@ -470,7 +516,7 @@
return APM_SUCCESS;
}

-static inline int set_power_state(u_short what, u_short state)
+static int set_power_state(u_short what, u_short state)
{
u32 eax;

@@ -499,7 +545,6 @@
#endif

#ifdef CONFIG_APM_DO_ENABLE
-/* Called by apm_setup if apm_enabled will be true. */
static int apm_enable_power_management(void)
{
u32 eax;
@@ -508,6 +553,7 @@
(apm_bios_info.version > 0x100) ? 0x0001 : 0xffff,
1, &eax))
return (eax >> 8) & 0xff;
+ apm_bios_info.flags &= ~APM_BIOS_DISABLED;
return APM_SUCCESS;
}
#endif
@@ -574,9 +620,10 @@
for (i = 0; i < ERROR_COUNT; i++)
if (error_table[i].key == err) break;
if (i < ERROR_COUNT)
- printk(KERN_NOTICE "apm_bios: %s: %s\n", str, error_table[i].msg);
+ printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
else
- printk(KERN_NOTICE "apm_bios: %s: unknown error code %#2.2x\n", str, err);
+ printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
+ str, err);
}

/* Called from console driver -- must make sure apm_enabled. */
@@ -629,7 +676,6 @@
callback_list_t ** ptr;
callback_list_t * old;

- ptr = &callback_list;
for (ptr = &callback_list; *ptr != NULL; ptr = &(*ptr)->next)
if ((*ptr)->callback == callback)
break;
@@ -663,7 +709,7 @@
static int notified;

if (notified == 0) {
- printk( "apm_bios: an event queue overflowed\n" );
+ printk(KERN_ERR "apm: an event queue overflowed\n");
notified = 1;
}
as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
@@ -707,18 +753,34 @@
unsigned long flags;
int err;

- /* Estimate time zone so that set_time can
- update the clock */
+#ifndef CONFIG_APM_RTC_IS_GMT
+ /*
+ * Estimate time zone so that set_time can
+ * update the clock
+ */
save_flags(flags);
clock_cmos_diff = -get_cmos_time();
cli();
clock_cmos_diff += CURRENT_TIME;
got_clock_diff = 1;
restore_flags(flags);
+#endif

err = apm_set_power_state(APM_STATE_SUSPEND);
if (err)
apm_error("suspend", err);
+#ifdef INIT_TIMER_AFTER_SUSPEND
+ save_flags(flags);
+ cli();
+ /* set the clock to 100 Hz */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ udelay(10);
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ udelay(10);
+ outb(LATCH >> 8 , 0x40); /* MSB */
+ udelay(10);
+ restore_flags(flags);
+#endif
set_time();
}

@@ -771,24 +833,31 @@

static void check_events(void)
{
- apm_event_t event;
+ apm_event_t event;
+#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ static unsigned long last_resume = 0;
+ static int ignore_bounce = 0;
+#endif

while ((event = get_event()) != 0) {
#ifdef APM_DEBUG
if (event <= NR_APM_EVENT_NAME)
- printk(KERN_DEBUG "APM BIOS received %s notify\n",
+ printk(KERN_DEBUG "apm: received %s notify\n",
apm_event_name[event - 1]);
else
- printk(KERN_DEBUG "APM BIOS received unknown "
+ printk(KERN_DEBUG "apm: received unknown "
"event 0x%02x\n", event);
#endif
+#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ if (ignore_bounce && ((jiffies - last_resume) > HZ))
+ ignore_bounce = 0;
+#endif
switch (event) {
case APM_SYS_STANDBY:
case APM_USER_STANDBY:
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
- if (waiting_for_resume) {
- return;
- }
+ if (waiting_for_resume)
+ return;
waiting_for_resume = 1;
#endif
send_event(event, APM_STANDBY_RESUME, NULL);
@@ -803,10 +872,13 @@
break;
#endif
case APM_SYS_SUSPEND:
+#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ if (ignore_bounce)
+ break;
+#endif
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
- if (waiting_for_resume) {
- return;
- }
+ if (waiting_for_resume)
+ return;
waiting_for_resume = 1;
#endif
send_event(event, APM_NORMAL_RESUME, NULL);
@@ -820,6 +892,10 @@
#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
waiting_for_resume = 0;
#endif
+#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
+ last_resume = jiffies;
+ ignore_bounce = 1;
+#endif
set_time();
send_event(event, 0, NULL);
break;
@@ -905,7 +981,7 @@
static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
{
if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
- printk(KERN_ERR "apm_bios: %s passed bad filp", func);
+ printk(KERN_ERR "apm: %s passed bad filp", func);
return 1;
}
return 0;
@@ -1041,7 +1117,7 @@
as1 = as1->next)
;
if (as1 == NULL)
- printk(KERN_ERR "apm_bios: filp not in user list");
+ printk(KERN_ERR "apm: filp not in user list");
else
as1->next = as->next;
}
@@ -1055,7 +1131,7 @@

as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL);
if (as == NULL) {
- printk(KERN_ERR "apm_bios: cannot allocate struct of size %d bytes",
+ printk(KERN_ERR "apm: cannot allocate struct of size %d bytes",
sizeof(*as));
return -ENOMEM;
}
@@ -1168,6 +1244,26 @@
}
#endif

+void __init apm_setup(char *str, int *dummy)
+{
+ int invert;
+
+ while ((str != NULL) && (*str != '\0')) {
+ if (strncmp(str, "off", 3) == 0)
+ apm_disabled = 1;
+ if (strncmp(str, "on", 2) == 0)
+ apm_disabled = 0;
+ invert = (strncmp(str, "no-", 3) == 0);
+ if (invert)
+ str += 3;
+ if (strncmp(str, "debug", 5) == 0)
+ debug = !invert;
+ str = strchr(str, ',');
+ if (str != NULL)
+ str += strspn(str, ", \t");
+ }
+}
+
void __init apm_bios_init(void)
{
unsigned short bx;
@@ -1178,23 +1274,18 @@
char * bat_stat;
static struct proc_dir_entry *ent;

-#ifdef __SMP__
- if (smp_num_cpus > 1) {
- printk(KERN_NOTICE "APM disabled: APM is not SMP safe.\n");
- return;
- }
-#endif
if (apm_bios_info.version == 0) {
- printk(KERN_INFO "APM BIOS not found.\n");
+ printk(KERN_INFO "apm: BIOS not found.\n");
return;
}
- printk(KERN_INFO "APM BIOS version %c.%c Flags 0x%02x (Driver version %s)\n",
- ((apm_bios_info.version >> 8) & 0xff) + '0',
- (apm_bios_info.version & 0xff) + '0',
- apm_bios_info.flags,
- driver_version);
+ printk(KERN_INFO
+ "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
+ ((apm_bios_info.version >> 8) & 0xff),
+ (apm_bios_info.version & 0xff),
+ apm_bios_info.flags,
+ driver_version);
if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
- printk(KERN_INFO " No 32 bit BIOS support\n");
+ printk(KERN_INFO "apm: no 32 bit BIOS support\n");
return;
}

@@ -1209,14 +1300,28 @@
if (apm_bios_info.version < 0x102)
apm_bios_info.cseg_16_len = 0xFFFF; /* 64k */

- printk(KERN_INFO " Entry %x:%lx cseg16 %x dseg %x",
- apm_bios_info.cseg, apm_bios_info.offset,
- apm_bios_info.cseg_16, apm_bios_info.dseg);
- if (apm_bios_info.version > 0x100)
- printk(" cseg len %x, cseg16 len %x, dseg len %x",
- apm_bios_info.cseg_len, apm_bios_info.cseg_16_len,
- apm_bios_info.dseg_len);
- printk("\n");
+ if (debug) {
+ printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
+ apm_bios_info.cseg, apm_bios_info.offset,
+ apm_bios_info.cseg_16, apm_bios_info.dseg);
+ if (apm_bios_info.version > 0x100)
+ printk(" cseg len %x, cseg16 len %x, dseg len %x",
+ apm_bios_info.cseg_len,
+ apm_bios_info.cseg_16_len,
+ apm_bios_info.dseg_len);
+ printk("\n");
+ }
+
+ if (apm_disabled) {
+ printk(KERN_NOTICE "apm: disabled on user request.\n");
+ return;
+ }
+#ifdef __SMP__
+ if (smp_num_cpus > 1) {
+ printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+ return;
+ }
+#endif

/*
* Set up a segment that references the real mode segment 0x40
@@ -1253,74 +1358,78 @@
set_limit(gdt[APM_CS_16 >> 3], apm_bios_info.cseg_16_len);
set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
#endif
- /* The APM 1.2 docs state that the apm_driver_version
- * call can fail if we try to connect as 1.2 to a 1.1 bios.
+ /*
+ * We only support BIOSs up to version 1.2
*/
- apm_bios_info.version = 0x0102;
- error = apm_driver_version(&apm_bios_info.version);
- if (error != APM_SUCCESS) { /* Fall back to an APM 1.1 connection. */
- apm_bios_info.version = 0x0101;
- error = apm_driver_version(&apm_bios_info.version);
- }
- if (error != APM_SUCCESS) /* Fall back to an APM 1.0 connection. */
+ if (apm_bios_info.version > 0x0102)
+ apm_bios_info.version = 0x0102;
+ if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) {
+ /* Fall back to an APM 1.0 connection. */
apm_bios_info.version = 0x100;
- else {
- apm_engage_power_management(0x0001);
- printk( " Connection version %d.%d\n",
- (apm_bios_info.version >> 8) & 0xff,
- apm_bios_info.version & 0xff );
}
}
-
- error = apm_get_power_status(&bx, &cx, &dx);
- if (error)
- printk(KERN_INFO " Power status not available\n");
- else {
- switch ((bx >> 8) & 0xff) {
- case 0: power_stat = "off line"; break;
- case 1: power_stat = "on line"; break;
- case 2: power_stat = "on backup power"; break;
- default: power_stat = "unknown"; break;
- }
- switch (bx & 0xff) {
- case 0: bat_stat = "high"; break;
- case 1: bat_stat = "low"; break;
- case 2: bat_stat = "critical"; break;
- case 3: bat_stat = "charging"; break;
- default: bat_stat = "unknown"; break;
- }
- printk(KERN_INFO " AC %s, battery status %s, battery life ",
- power_stat, bat_stat);
- if ((cx & 0xff) == 0xff)
- printk("unknown\n");
- else
- printk("%d%%\n", cx & 0xff);
- if (apm_bios_info.version > 0x100) {
- printk(" battery flag 0x%02x, battery life ",
- (cx >> 8) & 0xff);
- if (dx == 0xffff)
+ if (debug) {
+ printk(KERN_INFO "apm: onnection version %d.%d\n",
+ (apm_bios_info.version >> 8) & 0xff,
+ apm_bios_info.version & 0xff );
+
+ error = apm_get_power_status(&bx, &cx, &dx);
+ if (error)
+ printk(KERN_INFO "apm: power status not available\n");
+ else {
+ switch ((bx >> 8) & 0xff) {
+ case 0: power_stat = "off line"; break;
+ case 1: power_stat = "on line"; break;
+ case 2: power_stat = "on backup power"; break;
+ default: power_stat = "unknown"; break;
+ }
+ switch (bx & 0xff) {
+ case 0: bat_stat = "high"; break;
+ case 1: bat_stat = "low"; break;
+ case 2: bat_stat = "critical"; break;
+ case 3: bat_stat = "charging"; break;
+ default: bat_stat = "unknown"; break;
+ }
+ printk(KERN_INFO "apm: AC %s, battery status %s, battery life ",
+ power_stat, bat_stat);
+ if ((cx & 0xff) == 0xff)
printk("unknown\n");
- else {
- if ((dx & 0x8000))
- printk("%d minutes\n", dx & 0x7ffe );
- else
- printk("%d seconds\n", dx & 0x7fff );
+ else
+ printk("%d%%\n", cx & 0xff);
+ if (apm_bios_info.version > 0x100) {
+ printk("apm: battery flag 0x%02x, battery life ",
+ (cx >> 8) & 0xff);
+ if (dx == 0xffff)
+ printk("unknown\n");
+ else {
+ if ((dx & 0x8000))
+ printk("%d minutes\n", dx & 0x7ffe );
+ else
+ printk("%d seconds\n", dx & 0x7fff );
+ }
}
}
}

#ifdef CONFIG_APM_DO_ENABLE
- /*
- * This call causes my NEC UltraLite Versa 33/C to hang if it is
- * booted with PM disabled but not in the docking station.
- * Unfortunate ...
- */
- error = apm_enable_power_management();
- if (error)
- apm_error("enable power management", error);
- if (error == APM_DISABLED)
- return;
+ if (apm_bios_info.flags & APM_BIOS_DISABLED) {
+ /*
+ * This call causes my NEC UltraLite Versa 33/C to hang if it
+ * is booted with PM disabled but not in the docking station.
+ * Unfortunate ...
+ */
+ error = apm_enable_power_management();
+ if (error) {
+ apm_error("enable power management", error);
+ return;
+ }
+ }
#endif
+ if (((apm_bios_info.flags & APM_BIOS_DISABLED) == 0)
+ && (apm_bios_info.version > 0x0100)) {
+ if (apm_engage_power_management(0x0001) == APM_SUCCESS)
+ apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+ }

init_timer(&apm_timer);
apm_timer.function = do_apm_timer;
diff -ru linux-2.1.130/include/linux/apm_bios.h linux/include/linux/apm_bios.h
--- linux-2.1.130/include/linux/apm_bios.h Fri Oct 9 23:43:10 1998
+++ linux/include/linux/apm_bios.h Sun Nov 29 02:33:00 1998
@@ -77,6 +77,7 @@
extern struct apm_bios_info apm_bios_info;

extern void apm_bios_init(void);
+extern void apm_setup(char *, int *);

extern int apm_register_callback(int (*callback)(apm_event_t));
extern void apm_unregister_callback(int (*callback)(apm_event_t));
diff -ru linux-2.1.130/init/main.c linux/init/main.c
--- linux-2.1.130/init/main.c Sat Nov 28 23:57:40 1998
+++ linux/init/main.c Sun Nov 29 02:31:54 1998
@@ -41,6 +41,10 @@
# include <asm/mtrr.h>
#endif

+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
/*
* Versions of gcc older than that listed below may actually compile
* and link okay, but the end product can have subtle run time bugs.
@@ -864,6 +868,9 @@
#endif
#ifdef CONFIG_PARIDE_PG
{ "pg.", pg_setup },
+#endif
+#ifdef CONFIG_APM
+ { "apm=", apm_setup },
#endif
{ 0, 0 }
};
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:45    [W:0.057 / U:0.320 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site