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 * Copyright (c) 1996 Nate Williams + * Copyright (c) 1998 NAKAGAWA, Yoshihisa * * 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 #include + #include #include #include #include *************** *** 34,52 **** #include #include #include 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 #include #include + #ifdef NECMG + #include + #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 + * Copyright (C) 1997 by Poul-Henning Kamp * * 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);