void apm_suspend(int state) { extern int perflevel; int s; #if NWSDISPLAY > 0 wsdisplay_suspend(); #endif /* NWSDISPLAY > 0 */ stop_periodic_resettodr(); config_suspend_all(DVACT_QUIESCE); bufq_quiesce(); s = splhigh(); intr_disable(); cold = 2; config_suspend_all(DVACT_SUSPEND); suspend_randomness(); /* XXX * Flag to disk drivers that they should "power down" the disk * when we get to DVACT_POWERDOWN. */ boothowto |= RB_POWERDOWN; config_suspend_all(DVACT_POWERDOWN); boothowto &= ~RB_POWERDOWN; /* Send machine to sleep */ apm_set_powstate(APM_DEV_ALLDEVS, state); /* Wake up */ /* They say that some machines may require reinitializing the clocks */ i8254_startclock(); if (initclock_func == i8254_initclocks) rtcstart(); /* in i8254 mode, rtc is profclock */ inittodr(time_second); config_suspend_all(DVACT_RESUME); cold = 0; intr_enable(); splx(s); resume_randomness(NULL, 0); /* force RNG upper level reseed */ bufq_restart(); config_suspend_all(DVACT_WAKEUP); start_periodic_resettodr(); #if NWSDISPLAY > 0 wsdisplay_resume(); #endif /* NWSDISPLAY > 0 */ /* restore hw.setperf */ if (cpu_setperf != NULL) cpu_setperf(perflevel); }
int apm_periodic_check(struct apm_softc *sc) { struct apmregs regs; int ret = 0; if (apm_op_inprog) apm_set_powstate(APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); while (1) { if (apm_get_event(®s) != 0) { /* i think some bioses combine the error codes */ if (!(APM_ERR_CODE(®s) & APM_ERR_NOEVENTS)) apm_perror("get event", ®s); break; } /* If the APM BIOS tells us to suspend, don't do it twice */ if (regs.bx == APM_SUSPEND_REQ) apm_lidclose = 0; if (apm_handle_event(sc, ®s)) break; } if (apm_error || APM_ERR_CODE(®s) == APM_ERR_NOTCONN) ret = -1; if (apm_lidclose) { apm_lidclose = 0; /* Fake a suspend request */ regs.bx = APM_SUSPEND_REQ; apm_handle_event(sc, ®s); } if (apm_suspends /*|| (apm_battlow && apm_userstandbys)*/) { apm_op_inprog = 0; apm_suspend(APM_SYS_SUSPEND); } else if (apm_standbys || apm_userstandbys) { apm_op_inprog = 0; apm_suspend(APM_SYS_STANDBY); } apm_suspends = apm_standbys = apm_battlow = apm_userstandbys = 0; apm_error = 0; if (apm_resumes) apm_resumes--; return (ret); }
int apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { struct apm_softc *sc; struct apmregs regs; int error = 0; /* apm0 only */ if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || !(sc = apm_cd.cd_devs[APMUNIT(dev)])) return ENXIO; rw_enter_write(&sc->sc_lock); switch (cmd) { /* some ioctl names from linux */ case APM_IOC_STANDBY: if ((flag & FWRITE) == 0) error = EBADF; else apm_userstandbys++; break; case APM_IOC_SUSPEND: if ((flag & FWRITE) == 0) error = EBADF; else apm_suspends++; break; case APM_IOC_PRN_CTL: if ((flag & FWRITE) == 0) error = EBADF; else { int flag = *(int *)data; DPRINTF(( "APM_IOC_PRN_CTL: %d\n", flag )); switch (flag) { case APM_PRINT_ON: /* enable printing */ sc->sc_flags &= ~SCFLAG_PRINT; break; case APM_PRINT_OFF: /* disable printing */ sc->sc_flags &= ~SCFLAG_PRINT; sc->sc_flags |= SCFLAG_NOPRINT; break; case APM_PRINT_PCT: /* disable some printing */ sc->sc_flags &= ~SCFLAG_PRINT; sc->sc_flags |= SCFLAG_PCTPRINT; break; default: error = EINVAL; break; } } break; case APM_IOC_DEV_CTL: if ((flag & FWRITE) == 0) error = EBADF; else { struct apm_ctl *actl = (struct apm_ctl *)data; bzero(®s, sizeof(regs)); if (!apmcall(APM_GET_POWER_STATE, actl->dev, ®s)) printf("%s: dev %04x state %04x\n", sc->sc_dev.dv_xname, dev, regs.cx); error = apm_set_powstate(actl->dev, actl->mode); } break; case APM_IOC_GETPOWER: if (apm_get_powstat(®s) == 0) { struct apm_power_info *powerp = (struct apm_power_info *)data; bzero(powerp, sizeof(*powerp)); if (BATT_LIFE(®s) != APM_BATT_LIFE_UNKNOWN) powerp->battery_life = BATT_LIFE(®s); powerp->ac_state = AC_STATE(®s); switch (apm_minver) { case 0: if (!(BATT_FLAGS(®s) & APM_BATT_FLAG_NOBATTERY)) powerp->battery_state = BATT_STATE(®s); break; case 1: default: if (BATT_FLAGS(®s) & APM_BATT_FLAG_HIGH) powerp->battery_state = APM_BATT_HIGH; else if (BATT_FLAGS(®s) & APM_BATT_FLAG_LOW) powerp->battery_state = APM_BATT_LOW; else if (BATT_FLAGS(®s) & APM_BATT_FLAG_CRITICAL) powerp->battery_state = APM_BATT_CRITICAL; else if (BATT_FLAGS(®s) & APM_BATT_FLAG_CHARGING) powerp->battery_state = APM_BATT_CHARGING; else if (BATT_FLAGS(®s) & APM_BATT_FLAG_NOBATTERY) powerp->battery_state = APM_BATTERY_ABSENT; else powerp->battery_state = APM_BATT_UNKNOWN; if (BATT_REM_VALID(®s)) { powerp->minutes_left = BATT_REMAINING(®s); if (sc->be_batt) powerp->minutes_left = swap16(powerp->minutes_left); } } } else { apm_perror("ioctl get power status", ®s); error = EIO; } break; case APM_IOC_STANDBY_REQ: if ((flag & FWRITE) == 0) error = EBADF; /* only fails if no one cares. apmd at least should */ else if (apm_record_event(sc, APM_USER_STANDBY_REQ)) error = EINVAL; /* ? */ break; case APM_IOC_SUSPEND_REQ: if ((flag & FWRITE) == 0) error = EBADF; /* only fails if no one cares. apmd at least should */ else if (apm_record_event(sc, APM_USER_SUSPEND_REQ)) error = EINVAL; /* ? */ break; default: error = ENOTTY; } rw_exit_write(&sc->sc_lock); return error; }