[PATCH] APM updates for 2.2.18pre4

From: Stephen Rothwell (sfr@linuxcare.com.au)
Date: Mon Sep 11 2000 - 01:15:19 EST


Hi Alan,

This is a backport of relevent changes to the 2.3 APM driver. It
also includes the previous patch I sent you today.

This patch does:
        - Remove CONFIG_APM_SUSPEND_BOUNCE. The bounce ignore
        interval is now configurable.
        - Disable interrupts while we are suspended.
        - Notify drivers on critical suspend.
        - remove zero initialisations.
        - general resync with 2.3/4 driver.

It also (as a side effect) makes 2.2.18pre4 boot - if you enable
APM support :-)).

Cheers,
Stephen

-- 
Stephen Rothwell, Open Source Researcher, Linuxcare, Inc.
+61-2-62628990 tel, +61-2-62628991 fax 
sfr@linuxcare.com, http://www.linuxcare.com/ 
Linuxcare. Support for the revolution.

diff -ruN 2.2.18pre4/arch/i386/config.in 2.2.18pre4-APM.1/arch/i386/config.in --- 2.2.18pre4/arch/i386/config.in Mon Sep 11 10:17:09 2000 +++ 2.2.18pre4-APM.1/arch/i386/config.in Mon Sep 11 16:22:50 2000 @@ -111,7 +111,6 @@ bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK - bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF diff -ruN 2.2.18pre4/arch/i386/kernel/apm.c 2.2.18pre4-APM.1/arch/i386/kernel/apm.c --- 2.2.18pre4/arch/i386/kernel/apm.c Mon Sep 11 10:17:09 2000 +++ 2.2.18pre4-APM.1/arch/i386/kernel/apm.c Mon Sep 11 16:19:47 2000 @@ -36,6 +36,7 @@ * Oct 1999, Version 1.10 * Nov 1999, Version 1.11 * Jan 2000, Version 1.12 + * Feb 2000, Version 1.13 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -55,7 +56,7 @@ * The new replacment for it is, but Linux doesn't yet support this. * Alan Cox Linux 2.1.55 * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's - * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by + * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by * Dean Gaudet <dgaudet@arctic.org>. * C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87 * 1.5: Fix segment register reloading (in case of bad segments saved @@ -127,8 +128,13 @@ * scripts that check for it before doing power off * work (Jim Avera <jima@hal.com>). * 1.13: Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS - * is now the way life works). + * is now the way life works). * Fix thinko in suspend() (wrong return). + * Notify drivers on critical suspend. + * Disable interrupts while we are suspended (Andy Henroid + * <andy_henroid@yahoo.com> fixed by sfr). + * Remove CONFIG_APM_SUSPEND_BOUNCE. The bounce ignore + * interval is now configurable. * * APM 1.1 Reference: * @@ -170,10 +176,6 @@ #include <asm/desc.h> #include <asm/softirq.h> -/* 2.2-2.3 Compatability defines */ -#define __setup(x, y) -#define module_init(x) - EXPORT_SYMBOL(apm_register_callback); EXPORT_SYMBOL(apm_unregister_callback); @@ -199,9 +201,12 @@ * See Documentation/Config.help for the configuration options. * * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) * apm=on/off enable/disable APM * [no-]debug log some debugging messages - * [no-]power-off power off on shutdown + * [no-]power[-_]off power off on shutdown + * bounce[-_]interval ignore suspend bounces for this many + * ticks */ /* KNOWN PROBLEM MACHINES: @@ -245,8 +250,8 @@ /* * 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> + * This patched by Chad Miller <cmiller@surfsouth.com>, original code by + * David Chen <chen@ctpa04.mit.edu> */ #undef INIT_TIMER_AFTER_SUSPEND @@ -262,10 +267,9 @@ #define APM_CHECK_TIMEOUT (HZ) /* - * If CONFIG_APM_IGNORE_SUSPEND_BOUNCE is defined then - * ignore suspend events for this amount of time after a resume + * Ignore suspend events for this amount of time after a resume */ -#define BOUNCE_INTERVAL (3 * HZ) +#define DEFAULT_BOUNCE_INTERVAL (3 * HZ) /* * Save a segment register away @@ -309,25 +313,27 @@ unsigned short segment; } apm_bios_entry; #ifdef CONFIG_APM_CPU_IDLE -static int clock_slowed = 0; +static int clock_slowed; #endif -static int suspends_pending = 0; -static int standbys_pending = 0; -static int waiting_for_resume = 0; +static int suspends_pending; +static int standbys_pending; +static int waiting_for_resume; +static int ignore_normal_resume; +static int bounce_interval = DEFAULT_BOUNCE_INTERVAL; #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; +static int got_clock_diff; #endif -static int debug = 0; -static int apm_disabled = 0; +static int debug; +static int apm_disabled; #ifdef CONFIG_SMP -static int power_off_enabled = 0; +static int power_off; #else -static int power_off_enabled = 1; +static int power_off = 1; #endif static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); @@ -407,7 +413,7 @@ #ifndef CONFIG_APM_ALLOW_INTS # define APM_DO_CLI __cli() #else -# define APM_DO_CLI +# define APM_DO_CLI __sti() #endif #ifdef APM_ZERO_SEGS # define APM_DECL_SEGS \ @@ -622,7 +628,7 @@ * This may be called on an SMP machine. */ #ifdef CONFIG_SMP - /* Many bioses don't like being called from CPU != 0 */ + /* Some bioses don't like being called from CPU != 0 */ while (cpu_number_map[smp_processor_id()] != 0) { kernel_thread(apm_magic, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); @@ -636,6 +642,7 @@ #endif } +#ifdef CONFIG_APM_DO_ENABLE static int apm_enable_power_management(int enable) { u32 eax; @@ -651,6 +658,7 @@ apm_bios_info.flags |= APM_BIOS_DISABLED; return APM_SUCCESS; } +#endif static int apm_get_power_status(u_short *status, u_short *bat, u_short *life) { @@ -873,12 +881,35 @@ #endif } +static int send_event(apm_event_t event, apm_event_t undo) +{ + callback_list_t * call; + callback_list_t * fix; + + for (call = callback_list; call != NULL; call = call->next) { + if (call->callback(event) && undo) { + for (fix = callback_list; fix != call; fix = fix->next) + fix->callback(undo); + if (event == APM_CRITICAL_SUSPEND) { + printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" ); + return 0; + } + if (apm_bios_info.version > 0x100) + apm_set_power_state(APM_STATE_REJECT); + return 0; + } + } + + return 1; +} + static int suspend(void) { int err; struct apm_user *as; get_time_diff(); + cli(); err = apm_set_power_state(APM_STATE_SUSPEND); reinit_timer(); set_time(); @@ -886,10 +917,14 @@ err = APM_SUCCESS; if (err != APM_SUCCESS) apm_error("suspend", err); + send_event(APM_NORMAL_RESUME, 0); + sti(); + queue_event(APM_NORMAL_RESUME, NULL); for (as = user_list; as != NULL; as = as->next) { as->suspend_wait = 0; as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO); } + ignore_normal_resume = 1; wake_up_interruptible(&apm_suspend_waitqueue); return err; } @@ -910,7 +945,7 @@ apm_event_t event; apm_eventinfo_t info; - static int notified = 0; + static int notified; /* we don't use the eventinfo */ error = apm_get_event(&event, &info); @@ -923,33 +958,11 @@ return 0; } -static int send_event(apm_event_t event, apm_event_t undo, - struct apm_user *sender) -{ - callback_list_t * call; - callback_list_t * fix; - - for (call = callback_list; call != NULL; call = call->next) { - if (call->callback(event) && undo) { - for (fix = callback_list; fix != call; fix = fix->next) - fix->callback(undo); - if (apm_bios_info.version > 0x100) - apm_set_power_state(APM_STATE_REJECT); - return 0; - } - } - - queue_event(event, sender); - return 1; -} - static void check_events(void) { apm_event_t event; -#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE - static unsigned long last_resume = 0; - static int ignore_bounce = 0; -#endif + static unsigned long last_resume; + static int ignore_bounce; while ((event = get_event()) != 0) { if (debug) { @@ -960,15 +973,17 @@ printk(KERN_DEBUG "apm: received unknown " "event 0x%02x\n", event); } -#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE if (ignore_bounce - && ((jiffies - last_resume) > BOUNCE_INTERVAL)) + && ((jiffies - last_resume) > bounce_interval)) ignore_bounce = 0; -#endif + if (ignore_normal_resume && (event != APM_NORMAL_RESUME)) + ignore_normal_resume = 0; + switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: - if (send_event(event, APM_STANDBY_RESUME, NULL)) { + if (send_event(event, APM_STANDBY_RESUME)) { + queue_event(event, NULL); if (standbys_pending <= 0) standby(); } @@ -981,10 +996,11 @@ break; #endif case APM_SYS_SUSPEND: -#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE - if (ignore_bounce) + if (ignore_bounce) { + if (apm_bios_info.version > 0x100) + apm_set_power_state(APM_STATE_REJECT); break; -#endif + } /* * If we are already processing a SUSPEND, * then further SUSPEND events from the BIOS @@ -995,7 +1011,8 @@ */ if (waiting_for_resume) return; - if (send_event(event, APM_NORMAL_RESUME, NULL)) { + if (send_event(event, APM_NORMAL_RESUME)) { + queue_event(event, NULL); waiting_for_resume = 1; if (suspends_pending <= 0) (void) suspend(); @@ -1006,18 +1023,21 @@ case APM_CRITICAL_RESUME: case APM_STANDBY_RESUME: waiting_for_resume = 0; -#ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE last_resume = jiffies; ignore_bounce = 1; -#endif - set_time(); - send_event(event, 0, NULL); + if ((event != APM_NORMAL_RESUME) + || (ignore_normal_resume == 0)) { + set_time(); + send_event(event, 0); + queue_event(event, NULL); + } break; case APM_CAPABILITY_CHANGE: case APM_LOW_BATTERY: case APM_POWER_STATUS_CHANGE: - send_event(event, 0, NULL); + send_event(event, 0); + queue_event(event, NULL); break; case APM_UPDATE_TIME: @@ -1025,6 +1045,11 @@ break; case APM_CRITICAL_SUSPEND: + send_event(event, 0); + /* + * We can only hope it worked - we are not allowed + * to reject a critical suspend. + */ (void) suspend(); break; } @@ -1084,7 +1109,7 @@ schedule(); goto repeat; } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&apm_waitqueue, &wait); } i = count; @@ -1146,8 +1171,10 @@ as->standbys_read--; as->standbys_pending--; standbys_pending--; - } else if (!send_event(APM_USER_STANDBY, APM_STANDBY_RESUME, as)) + } else if (!send_event(APM_USER_STANDBY, APM_STANDBY_RESUME)) return -EAGAIN; + else + queue_event(APM_USER_STANDBY, as); if (standbys_pending <= 0) standby(); break; @@ -1156,8 +1183,10 @@ as->suspends_read--; as->suspends_pending--; suspends_pending--; - } else if (!send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME, as)) + } else if (!send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME)) return -EAGAIN; + else + queue_event(APM_USER_SUSPEND, as); if (suspends_pending <= 0) { if (suspend() != APM_SUCCESS) return -EIO; @@ -1171,7 +1200,7 @@ break; schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&apm_suspend_waitqueue, &wait); return as->suspend_result; } @@ -1417,7 +1446,7 @@ } /* Install our power off handler.. */ - if (power_off_enabled) + if (power_off) acpi_power_off = apm_power_off; #ifdef CONFIG_MAGIC_SYSRQ sysrq_power_off = apm_power_off; @@ -1430,7 +1459,7 @@ return 0; } -void __init apm_setup(char *str, int *dummy) +static int __init apm_setup(char *str) { int invert; @@ -1444,12 +1473,17 @@ str += 3; if (strncmp(str, "debug", 5) == 0) debug = !invert; - if (strncmp(str, "power-off", 9) == 0) - power_off_enabled = !invert; + if ((strncmp(str, "power-off", 9) == 0) || + (strncmp(str, "power_off", 9) == 0)) + power_off = !invert; + if ((strncmp(str, "bounce-interval=", 16) == 0) || + (strncmp(str, "bounce_interval=", 16) == 0)) + bounce_interval = simple_strtol(str + 16, NULL, 0); str = strchr(str, ','); if (str != NULL) str += strspn(str, ", \t"); } + return 1; } __setup("apm=", apm_setup); @@ -1464,17 +1498,16 @@ static struct miscdevice apm_device = { APM_MINOR_DEV, - "apm", + "apm_bios", &apm_bios_fops }; -#define APM_INIT_ERROR_RETURN return -void __init apm_init(void) +static int __init apm_init(void) { if (apm_bios_info.version == 0) { printk(KERN_INFO "apm: BIOS not found.\n"); - APM_INIT_ERROR_RETURN; + return -ENODEV; } printk(KERN_INFO "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", @@ -1484,7 +1517,7 @@ driver_version); if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) { printk(KERN_INFO "apm: no 32 bit BIOS support\n"); - APM_INIT_ERROR_RETURN; + return -ENODEV; } /* @@ -1513,11 +1546,11 @@ if (apm_disabled) { printk(KERN_NOTICE "apm: disabled on user request.\n"); - APM_INIT_ERROR_RETURN; + return -ENODEV; } - if ((smp_num_cpus > 1) && !power_off_enabled) { + if ((smp_num_cpus > 1) && !power_off) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); - APM_INIT_ERROR_RETURN; + return -ENODEV; } /* @@ -1560,12 +1593,12 @@ apm(0); - create_proc_info_entry("apm", 0, 0, apm_get_info); + create_proc_info_entry("apm", 0, NULL, apm_get_info); if (smp_num_cpus > 1) { printk(KERN_NOTICE "apm: disabled - APM is not SMP safe (power off active).\n"); - APM_INIT_ERROR_RETURN; + return 0; } init_timer(&apm_timer); @@ -1578,6 +1611,7 @@ #ifdef CONFIG_APM_CPU_IDLE acpi_idle = apm_cpu_idle; #endif + return 0; } module_init(apm_init) diff -ruN 2.2.18pre4/drivers/char/misc.c 2.2.18pre4-APM.1/drivers/char/misc.c --- 2.2.18pre4/drivers/char/misc.c Sun Sep 10 17:05:16 2000 +++ 2.2.18pre4-APM.1/drivers/char/misc.c Mon Sep 11 12:26:39 2000 @@ -43,9 +43,6 @@ #include <linux/proc_fs.h> #include <linux/stat.h> #include <linux/init.h> -#ifdef CONFIG_APM -#include <linux/apm_bios.h> -#endif #include <linux/tty.h> #include <linux/selection.h> @@ -240,9 +237,6 @@ #endif #ifdef CONFIG_DTLK dtlk_init(); -#endif -#ifdef CONFIG_APM - apm_init(); #endif #ifdef CONFIG_H8 h8_init(); diff -ruN 2.2.18pre4/include/linux/apm_bios.h 2.2.18pre4-APM.1/include/linux/apm_bios.h --- 2.2.18pre4/include/linux/apm_bios.h Thu May 4 10:16:51 2000 +++ 2.2.18pre4-APM.1/include/linux/apm_bios.h Mon Sep 11 12:26:12 2000 @@ -95,9 +95,6 @@ */ extern struct apm_bios_info apm_bios_info; -extern void apm_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 -ruN 2.2.18pre4/init/main.c 2.2.18pre4-APM.1/init/main.c --- 2.2.18pre4/init/main.c Mon Sep 11 10:17:48 2000 +++ 2.2.18pre4-APM.1/init/main.c Mon Sep 11 12:31:17 2000 @@ -43,10 +43,6 @@ # include <asm/mtrr.h> #endif -#ifdef CONFIG_APM -#include <linux/apm_bios.h> -#endif - #ifdef CONFIG_DASD #include <asm/dasd.h> #endif @@ -1095,9 +1091,6 @@ #endif #ifdef CONFIG_PARIDE_PG { "pg.", pg_setup }, -#endif -#ifdef CONFIG_APM - { "apm=", apm_setup }, #endif #ifdef CONFIG_N2 { "n2=", n2_setup }, - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Sep 15 2000 - 21:00:14 EST