From owner-linux-laptop-outgoing@vger.rutgers.edu Mon May 12 09:17:21 1997 Return-Path: Delivered-To: dgaudet-list-linux-laptop@arctic.org Received: (qmail 9364 invoked from network); 12 May 1997 09:17:20 -0000 Received: from nic.funet.fi (128.214.248.6) by twinlark.arctic.org with SMTP; 12 May 1997 09:17:20 -0000 Received: from root@vger.rutgers.edu (port 60011 [128.6.190.2]) by nic.funet.fi with ESMTP id <1019-27721>; Mon, 12 May 1997 12:17:10 +0300 Received: by vger.rutgers.edu id <971729-262>; Mon, 12 May 1997 05:15:37 -0400 Received: from twinlark.arctic.org ([204.62.130.91]) by vger.rutgers.edu with SMTP id <971697-262>; Mon, 12 May 1997 05:15:21 -0400 Received: (qmail 9319 invoked by uid 500); 12 May 1997 09:15:56 -0000 Date: Mon, 12 May 1997 02:15:56 -0700 (PDT) From: Dean Gaudet To: linux-laptop@vger.rutgers.edu Subject: [PATCH] suspend/resume improvements (thinkpad 560) Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-linux-laptop@vger.rutgers.edu Precedence: bulk Status: RO X-Status: I finally found the time to debug the suspend/resume problems on my Thinkpad 560. I discovered that the APM BIOS has some weird anomaly that makes it report suspend events over and over again. This causes weird interactions with pcmcia-cs, and apmd. The patch that follows seems to correct all this behaviour. (It even fixes the bug where using the floppy would break the suspend/resume function.) I'm guessing some other laptops might make use of this. The symptoms that might indicate the need for this are: - if apmd is running the laptop won't suspend, but does suspend as soon as apmd is killed (i.e. during machine shutdown) - kernel error message: "cs: received extra suspend event" repeated over and over - ability to suspend only once per reboot Note that I still have to manually suspend the pcmcia devices before the system will suspend, if I don't it just goes into standby. The bios itself only issues standby events when the cards aren't suspended. The patch is against 2.0.30 but I'm sure it'll apply against earlier kernels. If you're unfamiliar with patching your kernel take a peek at the Kernel HOWTO for example. This and other data at . Tell me how it goes, especially if you find this useful on other laptops. Dean Index: apm_bios.c =================================================================== RCS file: /home/dgaudet/Repository/linux/drivers/char/apm_bios.c,v retrieving revision 1.2 diff -u -r1.2 apm_bios.c --- linux/drivers/char/apm_bios.c 1997/05/09 09:22:19 1.2 +++ linux/drivers/char/apm_bios.c 1997/05/12 08:51:38 @@ -178,6 +178,13 @@ #define APM_RELAX_SEGMENTS /* + * The IBM TP560 bios seems to insist on returning suspend/standby events + * for a long long time whenever one occurs. We really only need one at + * a time, so just ignore any beyond the first. + */ +#define IGNORE_EXTRA_SUSPEND_STANDBY + +/* * Need to poll the APM BIOS every second */ #define APM_CHECK_TIMEOUT (HZ) @@ -330,6 +337,9 @@ #endif static int suspends_pending = 0; static int standbys_pending = 0; +#ifdef IGNORE_EXTRA_SUSPEND_STANDBY +static int waiting_for_resume = 0; +#endif static long clock_cmos_diff; static int got_clock_diff = 0; @@ -586,8 +596,15 @@ if (as == sender) continue; as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; - if (as->event_head == as->event_tail) + if (as->event_head == as->event_tail) { + static int notified; + + if (notified == 0) { + printk( "apm_bios: an event queue overflowed\n" ); + notified = 1; + } as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + } as->events[as->event_head] = event; if (!as->suser) continue; @@ -699,9 +716,23 @@ apm_event_t event; while ((event = get_event()) != 0) { +#ifdef APM_DEBUG + if (event <= NR_APM_EVENT_NAME) + printk("APM BIOS received %s notify\n", + apm_event_name[event - 1]); + else + printk("APM BIOS received unknown event 0x%02x\n", + event); +#endif switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: +#ifdef IGNORE_EXTRA_SUSPEND_STANDBY + if (waiting_for_resume) { + return; + } + waiting_for_resume = 1; +#endif send_event(event, APM_STANDBY_RESUME, NULL); if (standbys_pending <= 0) standby(); @@ -714,6 +745,12 @@ break; #endif case APM_SYS_SUSPEND: +#ifdef IGNORE_EXTRA_SUSPEND_STANDBY + if (waiting_for_resume) { + return; + } + waiting_for_resume = 1; +#endif send_event(event, APM_NORMAL_RESUME, NULL); if (suspends_pending <= 0) suspend(); @@ -722,6 +759,9 @@ case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: case APM_STANDBY_RESUME: +#ifdef IGNORE_EXTRA_SUSPEND_STANDBY + waiting_for_resume = 0; +#endif set_time(); send_event(event, 0, NULL); break; @@ -739,14 +779,6 @@ suspend(); break; } -#ifdef APM_DEBUG - if (event <= NR_APM_EVENT_NAME) - printk("APM BIOS received %s notify\n", - apm_event_name[event - 1]); - else - printk("APM BIOS received unknown event 0x%02x\n", - event); -#endif } }