From chen@ctpa04.mit.edu Tue Jun 24 13:45:52 1997 Date: Tue, 24 Jun 1997 13:41:45 -0400 (EDT) From: Dong Chen To: teuben@astro.umd.edu Subject: Re: clock and APM problem on AST J50 notebook (linux) Hi, Peter: The slow clock problem after suspend is solved. I included the patch I sent to the linux-kernel mailing list at the end. To do the patch, go to /usr/src/linux, do patch -p0 < apm_bios.c.patch and recompile your kernel. Though the patch is for kernel 2.0.30, I think apm_bios.c is the same from 2.0.22 . Now there is only one problem remaining. The PCMCIA module i82365.o actually slows down the computer if you run a program longer than 1 second and do not touch the keyboard or mouse. This happens when kernel APM is enabled. I haven't figured what went wrong there. So when you recompile your kernel, either stop PCMCIA first or hold down the shift key continuously until it is done. Your P100 should be much faster than a 486. Have a nice day. Dong ----------------------------------------------------------------------- Message to the linux kernel mailing list ----------------------------------------------------------------------- Hi, This is a patch for "drivers/char/apm_bios.c", it fixes the following problems: (1) On some notebook (AST J series, for example), the timer on interrupt 0 is reset to DOS default: 18 Hz. This patch re-initialize it to 100 Hz. Thanks to Pavel (pavel@Elf.mj.gts.cz) for pointing out to me that I should add some delays after the outb_p() and outb() calls. (2) The clock is not correctly restored after a standby(). There are still some problems with not getting the correct time after APM suspend or standby, namely before the first suspend() or standby() call, if the clock is already slowed by CPU_IDLE call, then the estimate time zone "clock_cmos_diff" would be wrong. Ideally, "clock_cmos_diff" should be setup at boot time after the time zone is set. But that will require changing code other than "apm_bios.c". Also, APM will not correct for the change between daylight savings time and normal time. Dong Chen chen@ctp.mit.edu ---------------------------CUT HERE------------------------------------- --- drivers/char/apm_bios.c.orig Mon May 26 11:05:15 1997 +++ drivers/char/apm_bios.c Tue Jun 24 12:09:06 1997 @@ -73,6 +73,18 @@ #include #include +/* + * INIT_TIMER_AFTER_SUSPEND: define to re-initialize the interrupt 0 timer + * to 100 Hz after a suspend. + */ +#define INIT_TIMER_AFTER_SUSPEND + +#ifdef INIT_TIMER_AFTER_SUSPEND +#include +#include +#include +#endif + static struct symbol_table apm_syms = { #include X(apm_register_callback), @@ -627,28 +639,53 @@ unsigned long flags; int err; - /* 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); + if (!got_clock_diff) { + /* Estimate time zone */ + save_flags(flags); + clock_cmos_diff = -get_cmos_time(); + cli(); + clock_cmos_diff += CURRENT_TIME; + got_clock_diff = 1; + restore_flags(flags); + } err = apm_set_power_state(APM_STATE_SUSPEND); if (err) apm_error("suspend", err); + +#ifdef INIT_TIMER_AFTER_SUSPEND + 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); +#endif + set_time(); } static void standby(void) { + unsigned long flags; int err; + if (!got_clock_diff) { + /* Estimate time zone */ + save_flags(flags); + clock_cmos_diff = -get_cmos_time(); + cli(); + clock_cmos_diff += CURRENT_TIME; + got_clock_diff = 1; + restore_flags(flags); + } + err = apm_set_power_state(APM_STATE_STANDBY); if (err) apm_error("standby", err); + set_time(); } static apm_event_t get_event(void)