[PATCH] Make APM work on Thinkpads again

From: Stephen Rothwell (sfr@linuxcare.com)
Date: Mon May 22 2000 - 19:50:57 EST


Hi Alan,

Well, Rusty finally collared me and showed me that he could not
suspend his Thinkpad since upgrading to 2.2.15. Below is the fix
against 2.2.16pre4. This patch actually eliminates the CONFIG
option that was there just for the Thinkpads and makes the fix
they require the behaviour for everyone (it does not hurt).

Along the way, I fixed a couple of typos and an incorrect return
code from the suspend() routine.

Please apply this for 2.2.16.

Cheers,
Stephen

-- 
Stephen Rothwell, Open Source Project Engineer, 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.16-pre4/Documentation/Configure.help 2.2.16-pre4-APM/Documentation/Configure.help --- 2.2.16-pre4/Documentation/Configure.help Mon May 22 16:52:12 2000 +++ 2.2.16-pre4-APM/Documentation/Configure.help Mon May 22 16:53:10 2000 @@ -9305,14 +9305,6 @@ backlight at all, or it might print a lot of errors to the console, especially if you are using gpm. -Ignore multiple suspend/standby events -CONFIG_APM_IGNORE_MULTIPLE_SUSPEND - This option is necessary on the IBM Thinkpad 560, but should work on - all other laptops. When the APM BIOS returns multiple suspend or - standby events while one is already being processed they will be - 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 and others, but diff -ruN 2.2.16-pre4/arch/i386/config.in 2.2.16-pre4-APM/arch/i386/config.in --- 2.2.16-pre4/arch/i386/config.in Thu May 4 12:20:30 2000 +++ 2.2.16-pre4-APM/arch/i386/config.in Tue May 23 10:22:20 2000 @@ -109,7 +109,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' 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 bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS diff -ruN 2.2.16-pre4/arch/i386/kernel/apm.c 2.2.16-pre4-APM/arch/i386/kernel/apm.c --- 2.2.16-pre4/arch/i386/kernel/apm.c Thu May 4 12:20:30 2000 +++ 2.2.16-pre4-APM/arch/i386/kernel/apm.c Tue May 23 10:31:15 2000 @@ -126,6 +126,9 @@ * Register the /proc/apm entry even on SMP so that * 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). + * Fix thinko in suspend() (wrong return). * * APM 1.1 Reference: * @@ -318,9 +321,7 @@ #endif static int suspends_pending = 0; static int standbys_pending = 0; -#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND static int waiting_for_resume = 0; -#endif #ifdef CONFIG_APM_RTC_IS_GMT # define clock_cmos_diff 0 @@ -343,7 +344,7 @@ static struct timer_list apm_timer; -static char driver_version[] = "1.12"; /* no spaces */ +static char driver_version[] = "1.13"; /* no spaces */ static char * apm_event_name[] = { "system standby", @@ -883,19 +884,19 @@ static int suspend(void) { int err; - int ret; struct apm_user *as; get_time_diff(); err = apm_set_power_state(APM_STATE_SUSPEND); reinit_timer(); set_time(); - ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR); - if (!ret) + if (err == APM_NO_ERROR) + err = APM_SUCCESS; + if (err != APM_SUCCESS) apm_error("suspend", err); for (as = user_list; as != NULL; as = as->next) { as->suspend_wait = 0; - as->suspend_result = (ret ? 0 : -EIO); + as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO); } wake_up_interruptible(&apm_suspend_waitqueue); return err; @@ -975,14 +976,7 @@ switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: -#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND - if (waiting_for_resume) - break; -#endif if (send_event(event, APM_STANDBY_RESUME, NULL)) { -#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND - waiting_for_resume = 1; -#endif if (standbys_pending <= 0) standby(); } @@ -999,14 +993,18 @@ if (ignore_bounce) break; #endif -#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + /* + * If we are already processing a SUSPEND, + * then further SUSPEND events from the BIOS + * will be ignored. We also return here to + * cope with the fact that the Thinkpads keep + * sending a SUSPEND event until something else + * happens! + */ if (waiting_for_resume) - break; -#endif + return; if (send_event(event, APM_NORMAL_RESUME, NULL)) { -#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND waiting_for_resume = 1; -#endif if (suspends_pending <= 0) (void) suspend(); } @@ -1015,9 +1013,7 @@ case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: case APM_STANDBY_RESUME: -#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND waiting_for_resume = 0; -#endif #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE last_resume = jiffies; ignore_bounce = 1; @@ -1049,8 +1045,10 @@ int err; if ((standbys_pending > 0) || (suspends_pending > 0)) { - if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) { + if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) { pending_count = 4; + if (debug) + printk(KERN_DEBUG "apm: setting state busy\n"); err = apm_set_power_state(APM_STATE_BUSY); if (err) apm_error("busy", err); @@ -1066,7 +1064,7 @@ static int check_apm_user(struct apm_user *as, const char *func) { if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { - printk(KERN_ERR "apm: %s passed bad filp", func); + printk(KERN_ERR "apm: %s passed bad filp\n", func); return 1; } return 0; @@ -1169,7 +1167,7 @@ } else if (!send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME, as)) return -EAGAIN; if (suspends_pending <= 0) { - if (!suspend()) + if (suspend() != APM_SUCCESS) return -EIO; } else { as->suspend_wait = 1; @@ -1220,7 +1218,7 @@ as1 = as1->next) ; if (as1 == NULL) - printk(KERN_ERR "apm: filp not in user list"); + printk(KERN_ERR "apm: filp not in user list\n"); else as1->next = as->next; } @@ -1234,7 +1232,7 @@ as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); if (as == NULL) { - printk(KERN_ERR "apm: cannot allocate struct of size %d bytes", + printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", sizeof(*as)); return -ENOMEM; }

- 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/



This archive was generated by hypermail 2b29 : Tue May 23 2000 - 21:00:23 EST