[PATCH] APM fixes, workarounds and tidying

Stephen Rothwell (sfr@canb.auug.org.au)
Tue, 01 Dec 1998 01:40:48 +1100


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/