Date: Wed, 7 Apr 1999 11:22:55 -0500                                            
From: "Jon A. Christopher" <jon@quorum.tamu.edu>                                
Subject: apmd patch                                                             
To: Avery Pennarun <apenwarr@worldvisions.ca>                                   
cc: apmd-list@worldvisions.ca

I have a laptop with a fairly short battery life, so I like to keep the
APM timeouts fairly low and suspend/standby after only a few minutes.
This is fine for running off the battery, but an annoyance when running on
AC power.  When on AC power, I'd prefer for system-generated APM suspend
and standby events to be ignored.

There's no support in the 2.0.x kernel driver for such conditional behavior.   

I've patched the 2.0.36 kernel driver and the apm program to implement the
following change:

The kernel driver:

  The kernel APM driver now responds to the ioctls APM_IOC_IGNORE and
  APM_IOC_NOIGNORE.  APM_IOC_IGNORE tells the kernel to ignore
  system-generated SUSPEND/STANDBY requests *if running on an AC power
  source*.  If running on the battery, such reqests are processed as
  normal.  APM_IOC_NOIGNORE tells the kernel to go back to the default
  behavior of always processing system SUSPEND/STANDBY requests.

  Note that *user* generated suspend/standby requests are not affected by
  the above change, so that even on AC power I can suspend my machine with
  the hotkey if I choose to do so.

  These kernel changes are a compile-time option CONFIG_APM_IGNORE_ON_MAINS, 
  so that if this is not selected in the kernel configuration process, the
  new code will not be compiled.

apm.c:

  Even if the kernel is compiled with support for
  CONFIG_APM_IGNORE_ON_MAINS, the new behavior is off by default.  If you
  want this behavior, you must turn it on explicitly.  I've modified apm.c
  to do this.  You can now call "apm -i" or "apm --ignore" to send the
  kernel the correct ioctl to tell it to ignore sustem-generated
  suspend/standby.  "apm -n" or "apm --noignore" restores the default
  behavior if for some reason you decide you want the kernel to start
  processing apm standby/sleep even when on AC power.

  Note that the patch to apm.c is only applied if the APM_IOC_IGNORE token
  is defined in apm_bios.h.  This is so that the apm will still compile
  even on machines whose kernel headers haven't been patched.

The patches include all necessary changes to the documentation and kernel
configuration files.

Summary of how to use the new behavior:

	0) compile a new kernel with APM_IGNORE_ON_MAINS support, and
           recompile apm, boot the new kernel.  (Of course).

	1) run "apm -i" to turn on the ignore feature.  You may wish to
           add this to your boot scripts (/etc/rc.d/rc.local, perhaps?).

Finally:  this patch does not apply cleanly to the 2.2.x kernel tree,
since the location and structure of the APM file has changed somewhat
from 2.0.x to 2.2.x.  I don't use 2.2 yet, so I can't verify this, but
from applying the patch for apm_bios.h to 2.2 source for
arch/i386/kernel/apm.c,  there's one rejected hunk that's easy enough to
put in manually, and it looks like it should work.  Any 2.2 users, please
feel free to port this over.

I've been using the patched kernel for about a week now with no problems
at all.  Please consider including the patch in the apmd sources for the
next version, and forwarding the kernel patch to Alan Cox for inclusion in
the 2.0.x tree.

Regards,
Jon Christopher
jac8792@tamu.edu

-- 
Dr. Jon A. Christopher              / jac8792@tamu.edu |  Project URLs:
Department of Biochem./Biophys.    /  spock: http://quorum.tamu.edu/spock
Texas A&M University MS-2128      / lesstif: http://www.lesstif.org/
College Station, TX, 77843       / personal: http://quorum.tamu.edu/jon



*** drivers/char/apm_bios.c.orig	Fri Apr  2 02:33:22 1999
--- drivers/char/apm_bios.c	Fri Apr  2 15:23:15 1999
***************
*** 131,136 ****
--- 131,144 ----
   * really only need one at a time, so just ignore any beyond the first.
   * This is probably safe on most laptops.
   *
+  * CONFIG_APM_IGNORE_ON_MAINS
+  *  This option will build APM support which will (optionally) ignore
+  *  system-generated suspend and standby messages when on an AC adapter.
+  *  This gives the benefits of APM on battery power, without the hassle of
+  *  APM when on AC power.  By default, even if enabled, this behavior is off.
+  *  You must turn this option on by sending the appropriate message via
+  *  an external program (i.e. apm).
+  *
   * If you are debugging the APM support for your laptop, note that code for
   * all of these options is contained in this file, so you can #define or
   * #undef these on the next line to avoid recompiling the whole kernel.
***************
*** 152,158 ****
  /*
   * Define to have debug messages.
   */
! #undef APM_DEBUG
  
  /*
   * Define to always call the APM BIOS busy routine even if the clock was
--- 160,166 ----
  /*
   * Define to have debug messages.
   */
! #define APM_DEBUG
  
  /*
   * Define to always call the APM BIOS busy routine even if the clock was
***************
*** 351,356 ****
--- 359,368 ----
  
  static char			driver_version[] = "1.2";/* no spaces */
  
+ #ifdef CONFIG_APM_IGNORE_ON_MAINS
+ static int apm_ignore=0; 
+ #endif
+ 
  #ifdef APM_DEBUG
  static char *	apm_event_name[] = {
  	"system standby",
***************
*** 712,717 ****
--- 724,748 ----
  	queue_event(event, sender);
  }
  
+ #ifdef CONFIG_APM_IGNORE_ON_MAINS
+ static int on_mains(void)
+ {
+   unsigned short	bx;
+   unsigned short	cx;
+   unsigned short	dx;
+   unsigned short	error;
+   unsigned short  ac_line_status = 0xff;
+   
+   if (!(error = apm_get_power_status(&bx, &cx, &dx))) {
+     ac_line_status = (bx >> 8) & 0xff;
+     if (ac_line_status==1) {
+       return 1;
+     }
+   }
+   return 0;
+ }
+ #endif
+ 
  static void check_events(void)
  {
  	apm_event_t	event;
***************
*** 728,733 ****
--- 759,770 ----
  		switch (event) {
  		case APM_SYS_STANDBY:
  		case APM_USER_STANDBY:
+ #ifdef CONFIG_APM_IGNORE_ON_MAINS
+ 		  if (event == APM_SYS_STANDBY && apm_ignore && on_mains()) {
+ 		      return;
+ 		  }
+ #endif
+ 
  #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
  			if (waiting_for_resume) {
  			    return;
***************
*** 746,751 ****
--- 783,793 ----
  			break;
  #endif
  		case APM_SYS_SUSPEND:
+ #ifdef CONFIG_APM_IGNORE_ON_MAINS
+ 		  if (event == APM_SYS_SUSPEND && apm_ignore && on_mains()) {
+ 		    return;
+ 		  }
+ #endif
  #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
  			if (waiting_for_resume) {
  			    return;
***************
*** 957,962 ****
--- 999,1014 ----
  		if (suspends_pending <= 0)
  			suspend();
  		break;
+ #ifdef CONFIG_APM_IGNORE_ON_MAINS
+ 	case APM_IOC_IGNORE:
+                 printk("APM: ignoring events when on AC mains\n");
+    	        apm_ignore=1;
+ 	        break;	
+ 	case APM_IOC_NOIGNORE:
+ 	        printk("APM: not ignoring events when on AC mains\n");
+ 	        apm_ignore=0;
+ 	        break;
+ #endif
  	default:
  		return -EINVAL;
  	}
*** drivers/char/Config.in.orig	Tue Oct 13 21:15:41 1998
--- drivers/char/Config.in	Fri Apr  2 10:50:34 1999
***************
*** 61,66 ****
--- 61,67 ----
    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 APM when on AC line' CONFIG_APM_IGNORE_ON_MAINS
  fi
  if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
    bool 'Tadpole ANA H8 Support'	CONFIG_H8
*** include/linux/apm_bios.h.orig	Fri Apr  2 19:04:59 1999
--- include/linux/apm_bios.h	Fri Apr  2 14:52:12 1999
***************
*** 137,141 ****
--- 137,143 ----
  
  #define APM_IOC_STANDBY		_IO('A', 1)
  #define APM_IOC_SUSPEND		_IO('A', 2)
+ #define APM_IOC_NOIGNORE        _IO('A', 3)
+ #define APM_IOC_IGNORE	        _IO('A', 4)
  
  #endif	/* LINUX_APM_H */
*** Documentation/Configure.help.orig	Mon Apr  5 21:19:33 1999
--- Documentation/Configure.help	Fri Apr  2 14:48:07 1999
***************
*** 4161,4166 ****
--- 4161,4175 ----
    events while one is already being processed they will be ignored.
    Without this the Thinkpad 560 has troubles with apmd, and pcmcia-cs.
  
+ Ignore system suspend/standby when on AC
+ CONFIG_APM_IGNORE_ON_MAINS
+   This option will build APM support which will (optionally) ignore
+   system-generated suspend and standby messages when on an AC adapter.
+   This gives the benefits of APM on battery power, without the hassle of
+   APM when on AC power.  By default, even if enabled, this behavior is off,
+   You must turn this option on by sending the appropriate message via
+   an external program (i.e. apm).
+ 
  Watchdog Timer Support
  CONFIG_WATCHDOG
    If you enable this option and create a character special file
