Index: PAO/sys/i386/apm/apm.c
diff -c PAO/sys/i386/apm/apm.c:1.1.1.3 PAO/sys/i386/apm/apm.c:1.1.1.3.4.3
*** PAO/sys/i386/apm/apm.c:1.1.1.3	Fri Jul 24 19:15:06 1998
--- PAO/sys/i386/apm/apm.c	Tue Dec 22 17:27:52 1998
***************
*** 4,9 ****
--- 4,10 ----
   * Copyright (c) 1994 UKAI, Fumitoshi.
   * Copyright (c) 1994-1995 by HOSOKAWA, Tatsumi <hosokawa@jp.FreeBSD.org>
   * Copyright (c) 1996 Nate Williams <nate@FreeBSD.org>
+  * Copyright (c) 1998 NAKAGAWA, Yoshihisa <nakagawa@jp.FreeBSD.org>
   *
   * This software may be used, modified, copied, and distributed, in
   * both source and binary form provided that the above copyright and
***************
*** 25,30 ****
--- 26,32 ----
  #endif /*DEVFS*/
  #include <sys/systm.h>
  #include <sys/time.h>
+ #include <sys/reboot.h>
  #include <i386/isa/isa_device.h>
  #include <machine/apm_bios.h>
  #include <machine/segments.h>
***************
*** 34,52 ****
  #include <vm/pmap.h>
  #include <sys/syslog.h>
  #include <i386/apm/apm_setup.h>
  
  static int apm_display __P((int newstate));
! static int apm_int __P((u_long *eax, u_long *ebx, u_long *ecx));
  static void apm_resume __P((void));
  
  /* static data */
  struct apm_softc {
  	int	initialized, active;
  	int	always_halt_cpu, slow_idle_cpu;
  	int	disabled, disengaged;
  	u_int	minorversion, majorversion;
  	u_int	cs32_base, cs16_base, ds_base;
! 	u_int	cs_limit, ds_limit;
  	u_int	cs_entry;
  	u_int	intversion;
  	struct apmhook sc_suspend;
--- 36,66 ----
  #include <vm/pmap.h>
  #include <sys/syslog.h>
  #include <i386/apm/apm_setup.h>
+ #ifdef NECMG
+ #include <necmg/necmg/necmg.h>
+ #endif /* NECMG */
  
  static int apm_display __P((int newstate));
! static int apm_int __P((u_long *eax, u_long *ebx, u_long *ecx, u_long *edx));
  static void apm_resume __P((void));
+ #ifdef PC98
+ static int get_batt_life_pc98 __P((u_char status));
+ static int apm_get_info_pc98 __P((apm_info_t aip));
+ #endif
+ 
+ #define	APM_FORCE_APM10_FLAG		0x02
+ #define	APM_NO_CLOCK_ADJUST_FLAG	0x04
+ 
  
  /* static data */
  struct apm_softc {
  	int	initialized, active;
  	int	always_halt_cpu, slow_idle_cpu;
  	int	disabled, disengaged;
+ 	int	suspending;
  	u_int	minorversion, majorversion;
  	u_int	cs32_base, cs16_base, ds_base;
! 	u_int	cs16_limit, cs32_limit, ds_limit;
  	u_int	cs_entry;
  	u_int	intversion;
  	struct apmhook sc_suspend;
***************
*** 77,91 ****
  
  /* setup APM GDT discriptors */
  static void
! setup_apm_gdt(u_int code32_base, u_int code16_base, u_int data_base, u_int code_limit, u_int data_limit)
  {
  	/* setup 32bit code segment */
  	gdt_segs[GAPMCODE32_SEL].ssd_base  = code32_base;
! 	gdt_segs[GAPMCODE32_SEL].ssd_limit = code_limit;
  
  	/* setup 16bit code segment */
  	gdt_segs[GAPMCODE16_SEL].ssd_base  = code16_base;
! 	gdt_segs[GAPMCODE16_SEL].ssd_limit = code_limit;
  
  	/* setup data segment */
  	gdt_segs[GAPMDATA_SEL  ].ssd_base  = data_base;
--- 91,105 ----
  
  /* setup APM GDT discriptors */
  static void
! setup_apm_gdt(u_int code32_base, u_int code16_base, u_int data_base, u_int code32_limit, u_int code16_limit, u_int data_limit)
  {
  	/* setup 32bit code segment */
  	gdt_segs[GAPMCODE32_SEL].ssd_base  = code32_base;
! 	gdt_segs[GAPMCODE32_SEL].ssd_limit = code32_limit;
  
  	/* setup 16bit code segment */
  	gdt_segs[GAPMCODE16_SEL].ssd_base  = code16_base;
! 	gdt_segs[GAPMCODE16_SEL].ssd_limit = code16_limit;
  
  	/* setup data segment */
  	gdt_segs[GAPMDATA_SEL  ].ssd_base  = data_base;
***************
*** 97,132 ****
  	ssdtosd(gdt_segs + GAPMDATA_SEL  , &gdt[GAPMDATA_SEL  ].sd);
  }
  
! /* 48bit far pointer */
! static struct addr48 {
  	u_long		offset;
  	u_short		segment;
  } apm_addr;
  
  static int apm_errno;
  
! __inline
! int
! apm_int(u_long *eax, u_long *ebx, u_long *ecx)
! {
! 	u_long cf;
! 	__asm __volatile("
! 		pushfl
! 		cli
! 		lcall	_apm_addr
! 		movl	$0, %3
! 		jnc	1f
! 		incl	%3
! 	1:
! 		popfl
! 		"
! 		: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=D" (cf)
! 		: "0" (*eax),  "1" (*ebx),  "2" (*ecx)
! 		: "dx", "si", "memory"
! 		);
  	apm_errno = ((*eax) >> 8) & 0xff;
  	return cf;
  }
  
  
  /* enable/disable power management */
--- 111,146 ----
  	ssdtosd(gdt_segs + GAPMDATA_SEL  , &gdt[GAPMDATA_SEL  ].sd);
  }
  
! /* 48bit far pointer. Do not staticize - used from apm_setup.s */
! struct addr48 {
  	u_long		offset;
  	u_short		segment;
  } apm_addr;
  
  static int apm_errno;
  
! #ifdef NECMG
! #  define apm_int(eax, ebx, ecx, edx) necmg_apm_int(eax, ebx, ecx)
! #else /* NECMG */
! static int
! apm_int(u_long *eax, u_long *ebx, u_long *ecx, u_long *edx)
! {
! 	struct apm_bios_arg apa;
! 	int cf;
! 
! 	apa.eax = *eax;
! 	apa.ebx = *ebx;
! 	apa.ecx = *ecx;
! 	apa.edx = *edx;
! 	cf = apm_bios_call(&apa);
! 	*eax = apa.eax;
! 	*ebx = apa.ebx;
! 	*ecx = apa.ecx;
! 	*edx = apa.edx;
  	apm_errno = ((*eax) >> 8) & 0xff;
  	return cf;
  }
+ #endif /* NECMG */
  
  
  /* enable/disable power management */
***************
*** 135,141 ****
  {
  	struct apm_softc *sc = &apm_softc;
  
! 	u_long eax, ebx, ecx;
  
  	eax = (APM_BIOS << 8) | APM_ENABLEDISABLEPM;
  
--- 149,155 ----
  {
  	struct apm_softc *sc = &apm_softc;
  
! 	u_long eax, ebx, ecx, edx;
  
  	eax = (APM_BIOS << 8) | APM_ENABLEDISABLEPM;
  
***************
*** 144,163 ****
  	else
  		ebx  = 0xffff;	/* APM version 1.0 only */
  	ecx  = enable;
! 	return apm_int(&eax, &ebx, &ecx);
  }
  
  /* Tell APM-BIOS that WE will do 1.1 and see what they say... */
  static void
  apm_driver_version(void)
  {
! 	u_long eax, ebx, ecx;
  
  	eax = (APM_BIOS << 8) | APM_DRVVERSION;
  	ebx  = 0x0;
  	/* XXX - The APM 1.1 specification is only supported for now */
  	ecx  = 0x0101;
! 	if(!apm_int(&eax, &ebx, &ecx))
  		apm_version = eax & 0xffff;
  }
  
--- 158,179 ----
  	else
  		ebx  = 0xffff;	/* APM version 1.0 only */
  	ecx  = enable;
! 	edx  = 0;
! 	return apm_int(&eax, &ebx, &ecx, &edx);
  }
  
  /* Tell APM-BIOS that WE will do 1.1 and see what they say... */
  static void
  apm_driver_version(void)
  {
! 	u_long eax, ebx, ecx, edx;
  
  	eax = (APM_BIOS << 8) | APM_DRVVERSION;
  	ebx  = 0x0;
  	/* XXX - The APM 1.1 specification is only supported for now */
  	ecx  = 0x0101;
! 	edx  = 0;
! 	if(!apm_int(&eax, &ebx, &ecx, &edx))
  		apm_version = eax & 0xffff;
  }
  
***************
*** 165,189 ****
  static int
  apm_engage_disengage_pm(int engage)
  {
! 	u_long eax, ebx, ecx;
  
  	eax = (APM_BIOS << 8) | APM_ENGAGEDISENGAGEPM;
  	ebx = PMDV_ALLDEV;
  	ecx = engage;
! 	return(apm_int(&eax, &ebx, &ecx));
  }
  
  /* get PM event */
  static u_int
  apm_getevent(void)
  {
! 	u_long eax, ebx, ecx;
  
  	eax = (APM_BIOS << 8) | APM_GETPMEVENT;
  
  	ebx = 0;
  	ecx = 0;
! 	if (apm_int(&eax, &ebx, &ecx))
  		return PMEV_NOEVENT;
  
  	return ebx & 0xffff;
--- 181,207 ----
  static int
  apm_engage_disengage_pm(int engage)
  {
! 	u_long eax, ebx, ecx, edx;
  
  	eax = (APM_BIOS << 8) | APM_ENGAGEDISENGAGEPM;
  	ebx = PMDV_ALLDEV;
  	ecx = engage;
! 	edx = 0;
! 	return(apm_int(&eax, &ebx, &ecx, &edx));
  }
  
  /* get PM event */
  static u_int
  apm_getevent(void)
  {
! 	u_long eax, ebx, ecx, edx;
  
  	eax = (APM_BIOS << 8) | APM_GETPMEVENT;
  
  	ebx = 0;
  	ecx = 0;
! 	edx = 0;
! 	if (apm_int(&eax, &ebx, &ecx, &edx))
  		return PMEV_NOEVENT;
  
  	return ebx & 0xffff;
***************
*** 193,205 ****
  static int
  apm_suspend_system(void)
  {
! 	u_long eax, ebx, ecx;
  
  	eax = (APM_BIOS << 8) | APM_SETPWSTATE;
  	ebx = PMDV_ALLDEV;
  	ecx = PMST_SUSPEND;
  
! 	if (apm_int(&eax, &ebx, &ecx)) {
  		printf("Entire system suspend failure: errcode = %ld\n",
  			0xff & (eax >> 8));
  		return 1;
--- 211,224 ----
  static int
  apm_suspend_system(void)
  {
! 	u_long eax, ebx, ecx, edx;
  
  	eax = (APM_BIOS << 8) | APM_SETPWSTATE;
  	ebx = PMDV_ALLDEV;
  	ecx = PMST_SUSPEND;
+ 	edx = 0;
  
! 	if (apm_int(&eax, &ebx, &ecx, &edx)) {
  		printf("Entire system suspend failure: errcode = %ld\n",
  			0xff & (eax >> 8));
  		return 1;
***************
*** 207,212 ****
--- 226,248 ----
  	return 0;
  }
  
+ static int
+ apm_standby_system(void)
+ {
+ 	u_long eax, ebx, ecx, edx;
+ 
+ 	eax = (APM_BIOS << 8) | APM_SETPWSTATE;
+ 	ebx = PMDV_ALLDEV;
+ 	ecx = PMST_STANDBY;
+ 	edx = 0;
+ 	if (apm_int(&eax, &ebx, &ecx, &edx)) {
+ 		printf("Entire system standby failure: errcode = %ld\n",
+ 			0xff & (eax >> 8));
+ 		return 1;
+ 	}
+ 	return 0;
+ }
+ 
  /* Display control */
  /*
   * Experimental implementation: My laptop machine can't handle this function
***************
*** 216,227 ****
  static int
  apm_display(int newstate)
  {
! 	u_long eax, ebx, ecx;
  
  	eax = (APM_BIOS << 8) | APM_SETPWSTATE;
  	ebx = PMDV_DISP0;
  	ecx = newstate ? PMST_APMENABLED:PMST_SUSPEND;
! 	if (apm_int(&eax, &ebx, &ecx)) {
  		printf("Display off failure: errcode = %ld\n",
  			0xff & (eax >> 8));
  		return 1;
--- 252,264 ----
  static int
  apm_display(int newstate)
  {
! 	u_long eax, ebx, ecx, edx;
  
  	eax = (APM_BIOS << 8) | APM_SETPWSTATE;
  	ebx = PMDV_DISP0;
  	ecx = newstate ? PMST_APMENABLED:PMST_SUSPEND;
! 	edx = 0;
! 	if (apm_int(&eax, &ebx, &ecx, &edx)) {
  		printf("Display off failure: errcode = %ld\n",
  			0xff & (eax >> 8));
  		return 1;
***************
*** 229,234 ****
--- 266,300 ----
  	return 0;
  }
  
+ /*
+  * Shutdown the system completely
+  *
+  * It does not work on some laptops.  I think it works on some desktops
+  * that has ATX power supply.
+  */
+ void
+ apm_power_off(int howto, void *dummy_arg)
+ {
+ 	u_long eax, ebx, ecx, edx;
+ 
+ 	if (howto & RB_POWEROFF) {
+ 		if (!apm_softc.active)
+ 			return;
+ 
+ 		/* wait 1sec before turning off the system power */
+ 		DELAY(1000000);
+ 
+ 		eax = (APM_BIOS << 8) | APM_SETPWSTATE;
+ 		ebx = PMDV_ALLDEV;
+ 		ecx = PMST_OFF;
+ 		edx = 0;
+ 		if (apm_int(&eax, &ebx, &ecx, &edx)) {
+ 			printf("Power off failure: errcode = %ld\n",
+ 				0xff & (eax >> 8));
+ 		}
+ 	}
+ }
+ 
  
  /* APM Battery low handler */
  static void
***************
*** 329,334 ****
--- 395,401 ----
  
  static struct timeval suspend_time;
  static struct timeval diff_time;
+ static int		apm_no_clock_adjust = 0;
  
  static int
  apm_default_resume(void *arg)
***************
*** 337,357 ****
  	u_int second, minute, hour;
  	struct timeval resume_time, tmp_time;
  
! 	/* modified for adjkerntz */
! 	pl = splsoftclock();
! 	inittodr(0);			/* adjust time to RTC */
! 	microtime(&resume_time);
! 	tmp_time = time;		/* because 'time' is volatile */
! 	timevaladd(&tmp_time, &diff_time);
! 	time = tmp_time;
! 	splx(pl);
! 	second = resume_time.tv_sec - suspend_time.tv_sec;
! 	hour = second / 3600;
! 	second %= 3600;
! 	minute = second / 60;
! 	second %= 60;
! 	log(LOG_NOTICE, "resumed from suspended mode (slept %02d:%02d:%02d)\n",
! 		hour, minute, second);
  	return 0;
  }
  
--- 404,430 ----
  	u_int second, minute, hour;
  	struct timeval resume_time, tmp_time;
  
! 	if (apm_no_clock_adjust) {
! 		log(LOG_NOTICE, "resumed from suspended mode\n");
! 	}
! 	else {
! 		/* modified for adjkerntz */
! 		pl = splsoftclock();
! 		inittodr(0);			/* adjust time to RTC */
! 		microtime(&resume_time);
! 		tmp_time = time;		/* because 'time' is volatile */
! 		timevaladd(&tmp_time, &diff_time);
! 		time = tmp_time;
! 		splx(pl);
! 		second = resume_time.tv_sec - suspend_time.tv_sec;
! 		hour = second / 3600;
! 		second %= 3600;
! 		minute = second / 60;
! 		second %= 60;
! 		log(LOG_NOTICE, 
! 			"resumed from suspended mode (slept %02d:%02d:%02d)\n",
! 			hour, minute, second);
! 	}
  	return 0;
  }
  
***************
*** 360,374 ****
  {
  	int	pl;
  
! 	pl = splsoftclock();
! 	microtime(&diff_time);
! 	inittodr(0);
! 	microtime(&suspend_time);
! 	timevalsub(&diff_time, &suspend_time);
! 	splx(pl);
  	return 0;
  }
  
  static void apm_processevent(void);
  
  /*
--- 433,454 ----
  {
  	int	pl;
  
! 	if (!apm_no_clock_adjust) {
! 		pl = splsoftclock();
! 		microtime(&diff_time);
! 		inittodr(0);
! 		microtime(&suspend_time);
! 		timevalsub(&diff_time, &suspend_time);
! 		splx(pl);
! 	}
  	return 0;
  }
  
+ /* 
+  * Do not suspend immediately after the system is resumed from 
+  * suspended mode 
+  */
+ 
  static void apm_processevent(void);
  
  /*
***************
*** 386,398 ****
  	if (!sc)
  		return;
  
  	if (sc->initialized) {
  		apm_execute_hook(hook[APM_HOOK_SUSPEND]);
  		if (apm_suspend_system() == 0)
  			apm_processevent();
! 		else
  			/* Failure, 'resume' the system again */
  			apm_execute_hook(hook[APM_HOOK_RESUME]);
  	}
  }
  
--- 466,518 ----
  	if (!sc)
  		return;
  
+ 	if (sc->suspending != 0) {	/* avoid reentry */
+ 		/* PCG-505: suspend -> save-to-disk */
+ 		if (sc->initialized) {
+ 			if (apm_suspend_system() == 0)
+ 				apm_processevent();
+ 		}
+ 		return;
+ 	}
+ 	sc->suspending = 1;
+ 
+ 
  	if (sc->initialized) {
+ #ifdef NECMG
+ 		int s = splhigh();
+ #endif
  		apm_execute_hook(hook[APM_HOOK_SUSPEND]);
  		if (apm_suspend_system() == 0)
+ #ifdef  PC98
+ 		{
+ #endif
  			apm_processevent();
! #ifdef  PC98
! 			/* fail to resume on 98NOTEs with old APM BIOS. */
! 			if (sc->intversion == INTVERSION(1, 0))
! 				timeout((void(*)(void*))apm_resume, 0, 3 * hz);
! 		}
! #endif
! 		else {
  			/* Failure, 'resume' the system again */
  			apm_execute_hook(hook[APM_HOOK_RESUME]);
+ 		}
+ #ifdef NECMG
+ 		splx(s);
+ #endif
+ 	}
+ }
+ 
+ void
+ apm_standby(void)
+ {
+ 	struct apm_softc *sc = &apm_softc;
+ 
+ 	if (!sc)
+ 		return;
+ 
+ 	if (sc->initialized) {
+ 		apm_standby_system();
  	}
  }
  
***************
*** 404,426 ****
  	if (!sc)
  		return;
  
  	if (sc->initialized)
  		apm_execute_hook(hook[APM_HOOK_RESUME]);
  }
  
  
  /* get APM information */
  static int
  apm_get_info(apm_info_t aip)
  {
  	struct apm_softc *sc = &apm_softc;
! 	u_long eax, ebx, ecx;
  
  	eax = (APM_BIOS << 8) | APM_GETPWSTATUS;
  	ebx = PMDV_ALLDEV;
  	ecx = 0;
  
! 	if (apm_int(&eax, &ebx, &ecx))
  		return 1;
  
  	aip->ai_acline    = (ebx >> 8) & 0xff;
--- 524,616 ----
  	if (!sc)
  		return;
  
+ 	sc->suspending = 0;
+ 
  	if (sc->initialized)
  		apm_execute_hook(hook[APM_HOOK_RESUME]);
  }
  
  
  /* get APM information */
+ #ifdef PC98
+ static inline int get_batt_life_pc98(u_char status)
+ {
+ 	int remain;
+ 
+ 	switch (status) {
+ 	case 0x11:
+ 		remain = 0; break;
+ 	case 0x00:
+ 	case 0x01:
+ 	case 0x02:
+ 	case 0x03:
+ 	case 0x04:
+ 	case 0x05:
+ 	case 0x06:
+ 	case 0x07:
+ 		remain = status & 0x7; break;
+ 	case 0x17:
+ 		remain = 8; break;
+ 	default:
+ 		return -1;
+ 	}
+ 	return ((100*remain)/8);
+ }
+ 
+ static int
+ apm_get_info_pc98(apm_info_t aip)
+ {
+ 	struct apm_softc *sc = &apm_softc;
+ 	u_long eax, ebx, ecx, edx;
+ 	int batt1, batt2;
+ 
+ 	eax = (APM_BIOS << 8) | APM_GETPWSTATUS_PC98;
+ 	ebx = PMDV_ALLDEV;
+ 	ecx = 0;
+ 	edx = 0xffff;                   /* default to unknown battery time */
+ 	if (apm_int(&eax, &ebx, &ecx, &edx))
+ 		return 1;
+ 		
+ 	aip->ai_acline    = ebx & 0x01;
+ 	aip->ai_batt_stat = 255;	/* unknown */
+ 
+ 	batt1 = get_batt_life_pc98(ecx & 0xff);
+ 	batt2 = get_batt_life_pc98((ecx >> 8) & 0xff);
+ 
+ 	if (batt1 > 0 && batt2 > 0){
+ 		aip->ai_batt_life = (batt1 + batt2)/2;
+ 	}else if (batt1 > 0){
+ 		aip->ai_batt_life = batt1;
+ 	}else if (batt2 > 0){
+ 		aip->ai_batt_life = batt2;
+ 	}else{
+ 		aip->ai_batt_life = 255;
+ 	}
+ 
+ 	aip->ai_major     = (u_int)sc->majorversion;
+ 	aip->ai_minor     = (u_int)sc->minorversion;
+ 	aip->ai_status    = (u_int)sc->active;
+ 	return 0;
+ }
+ #endif	/*PC98*/
+ 
  static int
  apm_get_info(apm_info_t aip)
  {
  	struct apm_softc *sc = &apm_softc;
! 	u_long eax, ebx, ecx, edx;
  
+ #ifdef	PC98
+ 	if (sc->intversion == INTVERSION(1, 0)){
+ 		return apm_get_info_pc98(aip);
+ 	}
+ #endif
  	eax = (APM_BIOS << 8) | APM_GETPWSTATUS;
  	ebx = PMDV_ALLDEV;
  	ecx = 0;
+ 	edx = 0xffff;                   /* default to unknown battery time */
  
! 	if (apm_int(&eax, &ebx, &ecx, &edx))
  		return 1;
  
  	aip->ai_acline    = (ebx >> 8) & 0xff;
***************
*** 441,451 ****
  	struct apm_softc *sc = &apm_softc;
  
  	if (sc->active) {
! 		u_long eax, ebx, ecx;
  
  		eax = (APM_BIOS <<8) | APM_CPUIDLE;
! 		ecx = ebx = 0;
! 		apm_int(&eax, &ebx, &ecx);
  	}
  	/*
  	 * Some APM implementation halts CPU in BIOS, whenever
--- 631,641 ----
  	struct apm_softc *sc = &apm_softc;
  
  	if (sc->active) {
! 		u_long eax, ebx, ecx, edx;
  
  		eax = (APM_BIOS <<8) | APM_CPUIDLE;
! 		edx = ecx = ebx = 0;
! 		apm_int(&eax, &ebx, &ecx, &edx);
  	}
  	/*
  	 * Some APM implementation halts CPU in BIOS, whenever
***************
*** 473,483 ****
  	 * necessary.
  	 */
  	if (sc->slow_idle_cpu && sc->active) {
! 		u_long eax, ebx, ecx;
  
  		eax = (APM_BIOS <<8) | APM_CPUBUSY;
! 		ecx = ebx = 0;
! 		apm_int(&eax, &ebx, &ecx);
  	}
  }
  
--- 663,673 ----
  	 * necessary.
  	 */
  	if (sc->slow_idle_cpu && sc->active) {
! 		u_long eax, ebx, ecx, edx;
  
  		eax = (APM_BIOS <<8) | APM_CPUBUSY;
! 		edx = ecx = ebx = 0;
! 		apm_int(&eax, &ebx, &ecx, &edx);
  	}
  }
  
***************
*** 606,612 ****
  		apm_event = apm_getevent();
  		switch (apm_event) {
  		    OPMEV_DEBUGMESSAGE(PMEV_STANDBYREQ);
! 			apm_suspend();
  			break;
  		    OPMEV_DEBUGMESSAGE(PMEV_SUSPENDREQ);
  			apm_suspend();
--- 796,802 ----
  		apm_event = apm_getevent();
  		switch (apm_event) {
  		    OPMEV_DEBUGMESSAGE(PMEV_STANDBYREQ);
! 			apm_standby();
  			break;
  		    OPMEV_DEBUGMESSAGE(PMEV_SUSPENDREQ);
  			apm_suspend();
***************
*** 624,634 ****
  			apm_resume();
  			break;
  		    OPMEV_DEBUGMESSAGE(PMEV_STANDBYRESUME);
! 			apm_resume();
  			break;
  		    OPMEV_DEBUGMESSAGE(PMEV_BATTERYLOW);
  			apm_battery_low();
  			apm_suspend();
  			break;
  		    OPMEV_DEBUGMESSAGE(PMEV_POWERSTATECHANGE);
  			break;
--- 814,830 ----
  			apm_resume();
  			break;
  		    OPMEV_DEBUGMESSAGE(PMEV_STANDBYRESUME);
! #if 0
! 			apm_resume();	/* should we call this or not? */
! #else
! 			inittodr(0);	/* adjust time to RTC */
! #endif
  			break;
  		    OPMEV_DEBUGMESSAGE(PMEV_BATTERYLOW);
  			apm_battery_low();
+ #ifdef APM_BATT_LOW_SUSPEND
  			apm_suspend();
+ #endif /* APM_BATT_LOW_SUSPEND */
  			break;
  		    OPMEV_DEBUGMESSAGE(PMEV_POWERSTATECHANGE);
  			break;
***************
*** 655,660 ****
--- 851,871 ----
  {
  #define APM_KERNBASE	KERNBASE
  	struct apm_softc	*sc = &apm_softc;
+ 	int			apm_force_apm10 = 0;
+ 	int     		rversion, rmajorversion, rminorversion;
+ 
+ #ifdef        FORCE_APM10
+ 	apm_force_apm10 = 1;
+ #else /* FORCE_APM10 */
+ 	apm_force_apm10 = (dvp->id_flags & APM_FORCE_APM10_FLAG);
+ #endif        /* FORCE_APM10 */
+ 
+ #ifdef	APM_NO_CLOCK_ADJUST
+ 	apm_no_clock_adjust = 1;
+ #else	/* APM_NO_CLOCK_ADJUST */
+ 	apm_no_clock_adjust = (dvp->id_flags & APM_NO_CLOCK_ADJUST_FLAG);
+ #endif	/* APM_NO_CLOCK_ADJUST */
+ 
  
  	sc->initialized = 0;
  
***************
*** 665,672 ****
  	sc->cs16_base = (apm_cs16_base << 4) + APM_KERNBASE;
  	sc->cs32_base = (apm_cs32_base << 4) + APM_KERNBASE;
  	sc->ds_base = (apm_ds_base << 4) + APM_KERNBASE;
! 	sc->cs_limit = apm_cs_limit;
! 	sc->ds_limit = apm_ds_limit;
  	sc->cs_entry = apm_cs_entry;
  
  	/* Always call HLT in idle loop */
--- 876,886 ----
  	sc->cs16_base = (apm_cs16_base << 4) + APM_KERNBASE;
  	sc->cs32_base = (apm_cs32_base << 4) + APM_KERNBASE;
  	sc->ds_base = (apm_ds_base << 4) + APM_KERNBASE;
! 	sc->cs32_limit = apm_cs32_limit - 1;
! 	if (apm_cs16_limit == 0)
! 	    apm_cs16_limit == apm_cs32_limit;
! 	sc->cs16_limit = apm_cs16_limit - 1;
! 	sc->ds_limit = apm_ds_limit - 1;
  	sc->cs_entry = apm_cs_entry;
  
  	/* Always call HLT in idle loop */
***************
*** 684,691 ****
  	printf("apm: Code entry 0x%08x, Idling CPU %s, Management %s\n",
  		sc->cs_entry, is_enabled(sc->slow_idle_cpu),
  		is_enabled(!sc->disabled));
! 	printf("apm: CS_limit=0x%x, DS_limit=0x%x\n",
! 		sc->cs_limit, sc->ds_limit);
  #endif /* APM_DEBUG */
  
  #if 0
--- 898,905 ----
  	printf("apm: Code entry 0x%08x, Idling CPU %s, Management %s\n",
  		sc->cs_entry, is_enabled(sc->slow_idle_cpu),
  		is_enabled(!sc->disabled));
! 	printf("apm: CS32_limit=0x%x, CS16_limit=0x%x, DS_limit=0x%x\n",
! 		(u_short)sc->cs32_limit, (u_short)sc->cs16_limit, (u_short)sc->ds_limit);
  #endif /* APM_DEBUG */
  
  #if 0
***************
*** 696,731 ****
  
  	/* setup GDT */
  	setup_apm_gdt(sc->cs32_base, sc->cs16_base, sc->ds_base,
! 			sc->cs_limit, sc->ds_limit);
  
  	/* setup entry point 48bit pointer */
  	apm_addr.segment = GSEL(GAPMCODE32_SEL, SEL_KPL);
  	apm_addr.offset  = sc->cs_entry;
  
! #ifdef FORCE_APM10
! 	apm_version = 0x100;
! 	sc->majorversion = 1;
! 	sc->minorversion = 0;
! 	sc->intversion = INTVERSION(sc->majorversion, sc->minorversion);
! 	printf("apm: running in APM 1.0 compatible mode\n");
! #else
! 	/* Try to kick bios into 1.1 or greater mode */
! 	apm_driver_version();
  	sc->minorversion = ((apm_version & 0x00f0) >>  4) * 10 +
  			((apm_version & 0x000f) >> 0);
  	sc->majorversion = ((apm_version & 0xf000) >> 12) * 10 +
  			((apm_version & 0x0f00) >> 8);
  
! 	sc->intversion = INTVERSION(sc->majorversion, sc->minorversion);
! 
  #ifdef APM_DEBUG
! 	if (sc->intversion >= INTVERSION(1, 1))
! 		printf("apm: Engaged control %s\n", is_enabled(!sc->disengaged));
  #endif
! 
! 	printf("apm: found APM BIOS version %d.%d\n",
! 		sc->majorversion, sc->minorversion);
! #endif /* FORCE_APM10 */
  
  #ifdef APM_DEBUG
  	printf("apm: Slow Idling CPU %s\n", is_enabled(sc->slow_idle_cpu));
--- 910,990 ----
  
  	/* setup GDT */
  	setup_apm_gdt(sc->cs32_base, sc->cs16_base, sc->ds_base,
! 			sc->cs32_limit, sc->cs16_limit, sc->ds_limit);
  
  	/* setup entry point 48bit pointer */
  	apm_addr.segment = GSEL(GAPMCODE32_SEL, SEL_KPL);
  	apm_addr.offset  = sc->cs_entry;
  
! 	rversion = apm_version;
! 
! #ifdef	PC98
! 	if (rversion & 0x00f0){
! 		rminorversion = rversion  & 0x000f;
! 	}else{
! 		rminorversion = 0;
! 	}
! 	rmajorversion = ((rversion & 0xf000) >> 12) * 10 +
! 			((rversion & 0x0f00) >> 8);
! 
  	sc->minorversion = ((apm_version & 0x00f0) >>  4) * 10 +
  			((apm_version & 0x000f) >> 0);
  	sc->majorversion = ((apm_version & 0xf000) >> 12) * 10 +
  			((apm_version & 0x0f00) >> 8);
  
! 	sc->intversion = INTVERSION(1, 0);
! 	if (rmajorversion >= 1 && rminorversion >= 1) {
! 		apm_driver_version();
! 		sc->intversion = INTVERSION(1, 1);
! 	}
! 	printf("apm: found APM BIOS version %d.%d\n",
! 	       sc->majorversion, sc->minorversion);
! #else
! 	rminorversion = ((rversion & 0x00f0) >>  4) * 10 +
! 			((rversion & 0x000f) >> 0);
! 	rmajorversion = ((rversion & 0xf000) >> 12) * 10 +
! 			((rversion & 0x0f00) >> 8);
! 
! 	if (apm_force_apm10) {
! 		apm_version = 0x100;
! 		sc->majorversion = 1;
! 		sc->minorversion = 0;
! 		sc->intversion = INTVERSION(1, 0);
! 		printf("apm: running in APM 1.0 compatible mode\n");
! 	}
! 	else {
! 		if (rmajorversion >= 1 && rminorversion >= 1) {
! 			apm_driver_version();
! 		}
! 		sc->minorversion = ((apm_version & 0x00f0) >>  4) * 10 +
! 				((apm_version & 0x000f) >> 0);
! 		sc->majorversion = ((apm_version & 0xf000) >> 12) * 10 +
! 				((apm_version & 0x0f00) >> 8);
! 
! 		if ((sc->majorversion == 1 && sc->minorversion == 0 
! 			&& rmajorversion >= 1 && rminorversion >= 1)
! 			|| sc->majorversion > 10 /* for broken APM 1.1 */
! 			) {
! 			apm_version = 0x100;
! 			sc->majorversion = 1;
! 			sc->minorversion = 0;
! 			sc->intversion = INTVERSION(1, 0);
! 			printf("apm: running in APM 1.0 compatible mode\n");
! 		}
! 		else {
! 			sc->intversion = 
! 				INTVERSION(sc->majorversion, sc->minorversion);
  #ifdef APM_DEBUG
! 			if (sc->intversion >= INTVERSION(1, 1)) {
! 				printf("apm: Engaged control %s\n", 
! 					is_enabled(!sc->disengaged));
! 			}
  #endif
! 			printf("apm: found APM BIOS version %d.%d\n",
! 				sc->majorversion, sc->minorversion);
! 		}
! 	}
! #endif	/* PC98 */
  
  #ifdef APM_DEBUG
  	printf("apm: Slow Idling CPU %s\n", is_enabled(sc->slow_idle_cpu));
***************
*** 752,772 ****
  		}
  	}
  
!         /* default suspend hook */
!         sc->sc_suspend.ah_fun = apm_default_suspend;
!         sc->sc_suspend.ah_arg = sc;
!         sc->sc_suspend.ah_name = "default suspend";
!         sc->sc_suspend.ah_order = APM_MAX_ORDER;
! 
!         /* default resume hook */
!         sc->sc_resume.ah_fun = apm_default_resume;
!         sc->sc_resume.ah_arg = sc;
!         sc->sc_resume.ah_name = "default resume";
!         sc->sc_resume.ah_order = APM_MIN_ORDER;
! 
!         apm_hook_establish(APM_HOOK_SUSPEND, &sc->sc_suspend);
!         apm_hook_establish(APM_HOOK_RESUME , &sc->sc_resume);
  
  	apm_event_enable();
  
  	sc->initialized = 1;
--- 1011,1043 ----
  		}
  	}
  
! 	/* default suspend hook */
! 	sc->sc_suspend.ah_fun = apm_default_suspend;
! 	sc->sc_suspend.ah_arg = sc;
! 	sc->sc_suspend.ah_name = "default suspend";
! 	sc->sc_suspend.ah_order = APM_MAX_ORDER;
! 
! 	/* default resume hook */
! 	sc->sc_resume.ah_fun = apm_default_resume;
! 	sc->sc_resume.ah_arg = sc;
! 	sc->sc_resume.ah_name = "default resume";
! 	sc->sc_resume.ah_order = APM_MIN_ORDER;
! 
! 	apm_hook_establish(APM_HOOK_SUSPEND, &sc->sc_suspend);
! 	apm_hook_establish(APM_HOOK_RESUME , &sc->sc_resume);
! 
! #ifndef NECMG
! 	at_shutdown(apm_power_off, NULL, SHUTDOWN_POWER_OFF);
! #else /* NECMG */
! 	at_shutdown(necmg_cpu_poweroff, NULL, SHUTDOWN_POWER_OFF);
! #endif /* NECMG */
  
+ #ifdef NECMG
+ 	/*
+ 	 * apm_event_enable() do nothing if sc->initialized = 0.
+ 	 */
+ 	sc->initialized = 1;
+ #endif /* NECMG */
  	apm_event_enable();
  
  	sc->initialized = 1;
***************
*** 816,822 ****
  		break;
  	case APMIO_GETINFO:
  		if (apm_get_info((apm_info_t)addr))
! 			error = ENXIO;
  		break;
  	case APMIO_ENABLE:
  		apm_event_enable();
--- 1087,1093 ----
  		break;
  	case APMIO_GETINFO:
  		if (apm_get_info((apm_info_t)addr))
! 			error = ENODEV;
  		break;
  	case APMIO_ENABLE:
  		apm_event_enable();
***************
*** 833,839 ****
  	case APMIO_DISPLAY:
  		newstate = *(int *)addr;
  		if (apm_display(newstate))
! 			error = ENXIO;
  		break;
  	default:
  		error = EINVAL;
--- 1104,1110 ----
  	case APMIO_DISPLAY:
  		newstate = *(int *)addr;
  		if (apm_display(newstate))
! 			error = ENODEV;
  		break;
  	default:
  		error = EINVAL;
***************
*** 854,860 ****
  		dev = makedev(CDEV_MAJOR,0);
  		cdevsw_add(&dev,&apm_cdevsw,NULL);
  		apm_devsw_installed = 1;
!     	}
  }
  
  SYSINIT(apmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,apm_drvinit,NULL)
--- 1125,1134 ----
  		dev = makedev(CDEV_MAJOR,0);
  		cdevsw_add(&dev,&apm_cdevsw,NULL);
  		apm_devsw_installed = 1;
! #ifdef NECMG
! 		necmg_apm_init();
! #endif /* !NECMG */
! 	}
  }
  
  SYSINIT(apmdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,apm_drvinit,NULL)
Index: PAO/sys/i386/apm/apm_setup.h
diff -c PAO/sys/i386/apm/apm_setup.h:1.1.1.2 PAO/sys/i386/apm/apm_setup.h:1.1.1.2.8.1
*** PAO/sys/i386/apm/apm_setup.h:1.1.1.2	Sun Apr  5 07:08:57 1998
--- PAO/sys/i386/apm/apm_setup.h	Tue Dec 22 17:19:54 1998
***************
*** 10,16 ****
   *
   * Sep., 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
   *
!  *	$Id: apm_setup.h,v 1.4.8.1 1997/11/04 19:02:15 nate Exp $
   */
  
  extern u_long	apm_version;
--- 10,16 ----
   *
   * Sep., 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
   *
!  *	$Id: apm_setup.h,v 1.9 1998/06/03 01:59:33 msmith Exp $
   */
  
  extern u_long	apm_version;
***************
*** 18,24 ****
  extern u_short	apm_cs32_base;
  extern u_short	apm_cs16_base;
  extern u_short	apm_ds_base;
! extern u_short	apm_cs_limit;
  extern u_short	apm_ds_limit;
  extern u_short	apm_flags;
  extern u_short	kernelbase;
--- 18,27 ----
  extern u_short	apm_cs32_base;
  extern u_short	apm_cs16_base;
  extern u_short	apm_ds_base;
! extern u_short	apm_cs32_limit;
! extern u_short	apm_cs16_limit;
  extern u_short	apm_ds_limit;
  extern u_short	apm_flags;
  extern u_short	kernelbase;
+ 
+ int apm_bios_call __P((struct apm_bios_arg *));
Index: PAO/sys/i386/apm/apm_setup.s
diff -c PAO/sys/i386/apm/apm_setup.s:1.1.1.2 PAO/sys/i386/apm/apm_setup.s:1.1.1.2.8.1
*** PAO/sys/i386/apm/apm_setup.s:1.1.1.2	Sun Apr  5 07:08:58 1998
--- PAO/sys/i386/apm/apm_setup.s	Tue Dec 22 17:19:55 1998
***************
*** 1,5 ****
--- 1,6 ----
  /*
   * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@jp.FreeBSD.org>
+  * Copyright (C) 1997 by Poul-Henning Kamp <phk@FreeBSD.org>
   *
   * This software may be used, modified, copied, distributed, and sold,
   * in both source and binary form provided that the above copyright and
***************
*** 10,16 ****
   *
   * Sep., 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
   *
!  *	$Id: apm_setup.s,v 1.7.2.1 1997/11/04 19:02:17 nate Exp $
   */
  
  #include "apm.h"
--- 11,17 ----
   *
   * Sep., 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
   *
!  *	$Id: apm_setup.s,v 1.13 1998/06/03 01:59:34 msmith Exp $
   */
  
  #include "apm.h"
***************
*** 58,65 ****
  	.globl	_apm_ds_base
  	.word	0
  
! _apm_cs_limit:
! 	.globl	_apm_cs_limit
  	.word	0
  
  _apm_ds_limit:
--- 59,70 ----
  	.globl	_apm_ds_base
  	.word	0
  
! _apm_cs32_limit:
! 	.globl	_apm_cs32_limit
! 	.word	0
! 
! _apm_cs16_limit:
! 	.globl	_apm_cs16_limit
  	.word	0
  
  _apm_ds_limit:
***************
*** 168,177 ****
  	shrl	$16, %ecx
  	movw	%cx, PADDR(_apm_cs32_base)
  	movw	%dx, PADDR(_apm_ds_base)
! 	movw	%si, PADDR(_apm_cs_limit)
  	shrl	$16, %esi
  	movw	%si, PADDR(_apm_ds_limit)
  	movw	%di, PADDR(_apm_flags)
  
  	ret
  #endif NAPM > 0
--- 173,216 ----
  	shrl	$16, %ecx
  	movw	%cx, PADDR(_apm_cs32_base)
  	movw	%dx, PADDR(_apm_ds_base)
! 	movw	%si, PADDR(_apm_cs32_limit)
  	shrl	$16, %esi
  	movw	%si, PADDR(_apm_ds_limit)
  	movw	%di, PADDR(_apm_flags)
  
+ 	ret
+ 
+ .text
+ 	.align 2
+ 	.globl	_apm_bios_call
+ _apm_bios_call:
+ 	pushl	%ebp
+ 	movl	8(%esp),%ebp
+ 	pushl	%esi
+ 	pushl	%edi
+ 	pushl	%ebx
+ 	movl	20(%ebp),%edi
+ 	movl	16(%ebp),%esi
+ 	movl	12(%ebp),%edx
+ 	movl	8(%ebp),%ecx
+ 	movl	4(%ebp),%ebx
+ 	movl	0(%ebp),%eax
+ 	pushl	%ebp
+ 	lcall	_apm_addr
+ 	popl	%ebp
+ 	movl	%eax,0(%ebp)
+ 	jc	1f
+ 	xorl	%eax,%eax
+ 	jz	2f
+ 1:	movl	$1, %eax
+ 2:	movl	%ebx,4(%ebp)
+ 	movl	%ecx,8(%ebp)
+ 	movl	%edx,12(%ebp)
+ 	movl	%esi,16(%ebp)
+ 	movl	%edi,20(%ebp)
+ 	popl	%ebx
+ 	popl	%edi
+ 	popl	%esi
+ 	popl	%ebp
  	ret
  #endif NAPM > 0
Index: PAO/sys/i386/include/apm_bios.h
diff -c PAO/sys/i386/include/apm_bios.h:1.1.1.2 PAO/sys/i386/include/apm_bios.h:1.1.1.2.6.3
*** PAO/sys/i386/include/apm_bios.h:1.1.1.2	Sun Apr  5 07:10:32 1998
--- PAO/sys/i386/include/apm_bios.h	Tue Dec 22 17:27:56 1998
***************
*** 62,67 ****
--- 62,68 ----
  #define APM_RESTOREDEFAULT	0x09
  #ifdef PC98
  #define	APM_GETPWSTATUS		0x3a
+ #define	APM_GETPWSTATUS_PC98	0x0a
  #else
  #define	APM_GETPWSTATUS		0x0a
  #endif
***************
*** 74,79 ****
--- 75,84 ----
  #define APM_DRVVERSION		0x0e
  #endif
  #define APM_ENGAGEDISENGAGEPM	0x0f
+ #define APM_GETCAPABILITY	0x10
+ #define APM_CTLRESUMETIMER	0x11
+ #define APM_ENABLEDISABLEROR	0x12
+ #define APM_ENABLEDISABLETBR	0x13
  #define APM_OEMFUNC		0x80
  
  /* error code */
***************
*** 88,93 ****
--- 93,100 ----
  #define APME_UNKNOWNDEVICEID	0x09
  #define APME_OUTOFRANGE		0x0a
  #define APME_NOTENGAGED		0x0b
+ #define	APME_UNSUPPORTFUNC	0x0c
+ #define	APME_RESMTIMERDISABLED	0x0d
  #define APME_CANTENTERSTATE	0x60
  #define APME_NOPMEVENT		0x80
  #define APME_NOAPMPRESENT	0x86
***************
*** 120,126 ****
  #define PMDV_PCMCIA1		0x0601
  #define PMDV_PCMCIA2		0x0602
  #define PMDV_PCMCIA3		0x0603
! /* 0x0700 - 0xdfff	Reserved			*/
  /* 0xe000 - 0xefff	OEM-defined power device IDs	*/
  /* 0xf000 - 0xffff	Reserved			*/
  
--- 127,136 ----
  #define PMDV_PCMCIA1		0x0601
  #define PMDV_PCMCIA2		0x0602
  #define PMDV_PCMCIA3		0x0603
! /* 0x0700 - 0x7fff	Reserved			*/
! #define PMDV_BATT0		0x8000
! #define PMDV_BATT1		0x8001
! /* 0x8100 - 0xdfff	Reserved			*/
  /* 0xe000 - 0xefff	OEM-defined power device IDs	*/
  /* 0xf000 - 0xffff	Reserved			*/
  
***************
*** 152,161 ****
--- 162,173 ----
  #define NAPM_HOOK               2
  
  void apm_suspend(void);
+ void apm_standby(void);
  struct apmhook *apm_hook_establish (int apmh, struct apmhook *);
  void apm_hook_disestablish (int apmh, struct apmhook *);
  void apm_cpu_idle(void);
  void apm_cpu_busy(void);
+ void apm_power_off(int, void*);
  
  #endif /* !ASSEMBLER && !INITIALIZER */
  
***************
*** 178,184 ****
  #define PMEV_USERSTANDBYREQ	0x0009
  #define PMEV_USERSUSPENDREQ	0x000a
  #define PMEV_STANDBYRESUME	0x000b
! /* 0x000c - 0x00ff	Reserved system events	*/
  /* 0x0100 - 0x01ff	Reserved device events	*/
  /* 0x0200 - 0x02ff	OEM-defined APM events	*/
  /* 0x0300 - 0xffff	Reserved		*/
--- 190,197 ----
  #define PMEV_USERSTANDBYREQ	0x0009
  #define PMEV_USERSUSPENDREQ	0x000a
  #define PMEV_STANDBYRESUME	0x000b
! #define PMEV_CAPABLITYCHANGE	0x000c
! /* 0x000d - 0x00ff	Reserved system events	*/
  /* 0x0100 - 0x01ff	Reserved device events	*/
  /* 0x0200 - 0x02ff	OEM-defined APM events	*/
  /* 0x0300 - 0xffff	Reserved		*/
***************
*** 194,199 ****
--- 207,221 ----
  	u_int	ai_batt_life;	/* Remaining battery life */
  	u_int	ai_status;	/* Status of APM support (enabled/disabled) */
  } *apm_info_t;
+ 
+ struct apm_bios_arg {
+ 	u_long eax;
+ 	u_long ebx;
+ 	u_long ecx;
+ 	u_long edx;
+ 	u_long esi;
+ 	u_long edi;
+ };
  
  #define APMIO_SUSPEND		_IO('P', 1)
  #define APMIO_GETINFO		_IOR('P', 2, struct apm_info)
Index: PAO/sys/kern/kern_shutdown.c
diff -c PAO/sys/kern/kern_shutdown.c:1.1.1.2 PAO/sys/kern/kern_shutdown.c:1.1.1.2.4.2
*** PAO/sys/kern/kern_shutdown.c:1.1.1.2	Fri Jul 24 19:21:04 1998
--- PAO/sys/kern/kern_shutdown.c	Tue Dec 22 17:27:59 1998
***************
*** 118,123 ****
--- 118,124 ----
   */
  static sle_p shutdown_list1;
  static sle_p shutdown_list2;
+ static sle_p shutdown_list3;
  
  
  static void dumpsys(void);
***************
*** 249,254 ****
--- 250,263 ----
  	}
  	splhigh();
  	if (howto & RB_HALT) {
+ 		if (howto & RB_POWEROFF) {
+ 			ep = shutdown_list3;
+ 			while (ep) {
+ 				shutdown_list3 = ep->next;
+ 				(*ep->function)(howto, ep->arg);
+ 				ep = ep->next;
+ 			}
+ 		}
  		printf("\n");
  		printf("The operating system has halted.\n");
  		printf("Please press any key to reboot.\n\n");
***************
*** 420,425 ****
--- 429,437 ----
  		break;
  	case SHUTDOWN_POST_SYNC:
  		epp = &shutdown_list2;
+ 		break;
+ 	case SHUTDOWN_POWER_OFF:
+ 		epp = &shutdown_list3;
  		break;
  	default:
  		printf("bad exit callout list specified\n");
Index: PAO/sys/sys/systm.h
diff -c PAO/sys/sys/systm.h:1.1.1.2 PAO/sys/sys/systm.h:1.1.1.2.4.2
*** PAO/sys/sys/systm.h:1.1.1.2	Fri Jul 24 19:28:30 1998
--- PAO/sys/sys/systm.h	Tue Dec 22 17:28:04 1998
***************
*** 173,178 ****
--- 173,179 ----
  int rm_at_shutdown(bootlist_fn function, void *arg);
  #define SHUTDOWN_PRE_SYNC 0
  #define SHUTDOWN_POST_SYNC 1
+ #define SHUTDOWN_POWER_OFF 2
  
  /* forking */ /* XXX not yet */
  typedef void (*forklist_fn)(struct proc *parent,struct proc *child,int flags);
