void apm_thread(void *v) { struct pxa2x0_apm_softc *sc = v; u_int type; for (;;) { APM_LOCK(sc); while (1) { if (apm_get_event(sc, &type) != 0) break; if (apm_handle_event(sc, type) != 0) break; } if (apm_suspends || apm_userstandbys /* || apm_battlow*/) { apm_suspend(sc); apm_resume(sc); } apm_battlow = apm_suspends = apm_userstandbys = 0; APM_UNLOCK(sc); tsleep(&lbolt, PWAIT, "apmev", 0); } }
static void apm_periodic_check(struct apm_softc *sc) { int error; u_int event_code, event_info; /* * tell the BIOS we're working on it, if asked to do a * suspend/standby */ if (apm_op_inprog) (*sc->sc_ops->aa_set_powstate)(sc->sc_cookie, APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); while ((error = (*sc->sc_ops->aa_get_event)(sc->sc_cookie, &event_code, &event_info)) == 0 && !apm_damn_fool_bios) apm_event_handle(sc, event_code, event_info); if (error != APM_ERR_NOEVENTS) apm_perror("get event", error); if (apm_suspends) { apm_op_inprog = 0; apm_suspend(sc); } else if (apm_standbys || apm_userstandbys) { apm_op_inprog = 0; apm_standby(sc); } apm_suspends = apm_standbys = apm_battlow = apm_userstandbys = 0; apm_damn_fool_bios = 0; }
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 main(int argc, char *argv[]) { int c, fd; int dosleep = 0, all_info = 1, apm_status = 0, batt_status = 0; int display = -1, batt_life = 0, ac_status = 0, standby = 0; int batt_time = 0, delta = 0, enable = -1, haltcpu = -1; int bioscall_available = 0; size_t cmos_wall_len = sizeof(cmos_wall); if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len, NULL, 0) == -1) err(1, "sysctlbyname(machdep.wall_cmos_clock)"); while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) { switch (c) { case 'a': ac_status = 1; all_info = 0; break; case 'b': batt_status = 1; all_info = 0; break; case 'd': display = is_true(optarg); all_info = 0; break; case 'l': batt_life = 1; all_info = 0; break; case 'R': delta = -1; break; case 'r': delta = atoi(optarg); break; case 's': apm_status = 1; all_info = 0; break; case 'e': enable = is_true(optarg); all_info = 0; break; case 'h': haltcpu = is_true(optarg); all_info = 0; break; case 't': batt_time = 1; all_info = 0; break; case 'z': dosleep = 1; all_info = 0; break; case 'Z': standby = 1; all_info = 0; break; case '?': default: usage(); } argc -= optind; argv += optind; } if (haltcpu != -1 || enable != -1 || display != -1 || delta || dosleep || standby) { fd = open(APMDEV, O_RDWR); bioscall_available = 1; } else if ((fd = open(APMDEV, O_RDWR)) >= 0) bioscall_available = 1; else fd = open(APMDEV, O_RDONLY); if (fd == -1) err(1, "can't open %s", APMDEV); if (enable != -1) apm_enable(fd, enable); if (haltcpu != -1) apm_haltcpu(fd, haltcpu); if (delta) apm_set_timer(fd, delta); if (dosleep) apm_suspend(fd); else if (standby) apm_standby(fd); else if (delta == 0) { struct apm_info info; apm_getinfo(fd, &info); if (all_info) print_all_info(fd, &info, bioscall_available); if (ac_status) printf("%d\n", info.ai_acline); if (batt_status) printf("%d\n", info.ai_batt_stat); if (batt_life) printf("%d\n", info.ai_batt_life); if (apm_status) printf("%d\n", info.ai_status); if (batt_time) printf("%d\n", info.ai_batt_time); if (display != -1) apm_display(fd, display); } close(fd); exit(0); }
int main(int argc, char **argv) { int i, rtcfd, retval; struct rtc_time rtc_tm; struct tm kernel_tm; time_t kernel_time, new_time, old_time; char *p; int c; int apmfd=-1; /* APM device file descriptor */ int isoffset; /* setting time offset */ int hour, minute; /* alarm time requested */ int hour1, minute1; /* backup for precise_mode */ int flag; static int suspend_mode=0, wait_mode=0, debug_mode=0, precise_mode=0, noapm_mode=0; while (1) { /* int this_option_optind = optind ? optind : 1; */ int option_index = 0; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"debug", 0, 0, 'd'}, {"version", 0, 0, 'V'}, {"suspend", 0, 0, 's'}, {"standby", 0, 0, 'S'}, {"wait", 0, 0, 'w'}, {"noapm", 0, 0, 'n'}, {"precise", 0, 0, 'p'}, {0,0,0,0} }; c = getopt_long(argc, argv, "hdVsSwnp", long_options, &option_index); if (c == -1) break; switch(c) { case 'h': usage(); exit(0); case 'V': version(); exit(0); case 'd': debug_mode=1; break; case 's': /*suspend*/ suspend_mode=0; break; case 'S': /*standby*/ suspend_mode=1; break; case 'n': /*noapm*/ noapm_mode=1; wait_mode=1; break; case 'w': wait_mode=!precise_mode; break; case 'p':/*precise*/ precise_mode=1; break; case '?': /*unknown option*/ exit(1); default: fprintf(stderr,"unknown option return %d\n", c); exit(1); } } /* end while (1) */ if (optind < argc) { if (optind+1 != argc) { fprintf(stderr,"To many arguments.\n"); usage(); exit(1); } p=argv[optind]; isoffset=0; if (p[0]=='+') { p++; isoffset=1;} if (2!=sscanf(p, "%d:%d", &hour, &minute)) { fprintf(stderr,"apmsleep: Bad argument(s)\n"); exit(1); } hour1=hour; minute1=minute; /* backup */ } else { fprintf(stderr,"apmsleep: missing argument.\n"); usage(); exit(1); } if (noapm_mode) suspend_mode=2; /* argument processing finished */ if (geteuid()!=0) { fprintf(stderr, "apmsleep: warning: This program must be run as root " "or have the SUID attribute set\n"); } /* check if APM is supported */ if (apm_exists()) { fprintf(stderr, "apmsleep: Your kernel does not support APM.\n"); fprintf(stderr, "apmsleep: Recompile kernel with APM and " "/dev/rtc support\n"); exit(1); } if (!noapm_mode) { apmfd=open(APM_DEVICE, O_WRONLY); if (apmfd < 0) { fprintf(stderr, "apmsleep: Cannot open APM device.\n"); exit(1); } } rtcfd = open ("/dev/rtc", O_RDONLY); if (errno == EACCES) { fprintf(stderr, "apmsleep: You don't have permission to " "access /dev/rtc\n"); fprintf(stderr, "apmsleep: The program must be run as root " "or have the SUID attribute set\n"); exit(errno); } if (rtcfd == -1) { perror("/dev/rtc"); fprintf(stderr, "apmsleep: Your kernel does not support " "the real time clock device\n"); fprintf(stderr, "apmsleep: Recompile kernel with APM and " "/dev/rtc support\n"); exit(errno); } /* Read the RTC time/date */ retval = ioctl(rtcfd, RTC_RD_TIME, &rtc_tm); if (retval == -1) { perror("ioctl"); exit(errno); } /* Read Kernel time/date */ time(&kernel_time); kernel_tm=*localtime(&kernel_time); if (debug_mode) { printf("Current RTC time is %02d:%02d:%02d.\n", rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); printf("Current local time is %02d:%02d:%02d.\n", kernel_tm.tm_hour, kernel_tm.tm_min, kernel_tm.tm_sec); } /* set alarm time in RTC */ if (isoffset) { if (hour == 0 && minute == 0) exit(0); hour+=(int)rtc_tm.tm_hour; minute+=(int)rtc_tm.tm_min; hour1+=(int)kernel_tm.tm_hour; minute1+=(int)kernel_tm.tm_min; } else { /* Special case - wake-up time equal current time this may cause to systems to crash according to a user report. Therefore, we do not suspend in this case. */ if (hour == kernel_tm.tm_hour && minute == kernel_tm.tm_min) { printf("Wake-up time equal to current time. Suspend not required\n"); exit(0); } rtc_tm.tm_sec=0; /* here we take difference between RTC and localtime into account */ minute+=(int)rtc_tm.tm_min - (int)kernel_tm.tm_min; hour+=(int)rtc_tm.tm_hour - (int)kernel_tm.tm_hour; } while (minute<0) {minute +=60; hour--; } while (minute>=60) {minute -=60; hour++; } while (hour < 0) hour += 24; hour %= 24; rtc_tm.tm_min = minute; rtc_tm.tm_hour = hour; if (debug_mode) printf("Setting RTC alarm time to %02d:%02d:%02d.\n", hour, minute, rtc_tm.tm_sec); retval = ioctl(rtcfd, RTC_ALM_SET, &rtc_tm); if (retval == -1) { perror("ioctl"); exit(errno); } /* Read back the current alarm settings */ retval = ioctl(rtcfd, RTC_ALM_READ, &rtc_tm); if (retval == -1) { perror("ioctl"); exit(errno); } if (debug_mode) printf("RTC alarm time now set to %02d:%02d:%02d.\n", rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); /* Enable alarm interrupts */ retval = ioctl(rtcfd, RTC_AIE_ON, 0); if (retval == -1) { perror("ioctl"); exit(errno); } /* Save time before suspending */ time(&new_time); kernel_time=new_time; if (fork()==0) { /* suspend system -- called from within a child, to make * sure we don't miss the time leap */ switch(suspend_mode) { case 0: apm_suspend(apmfd); break; case 1: apm_standby(apmfd); break; } exit(0); } if (debug_mode) { printf("Waiting until clock jumps\n"); fflush(stdout); } flag=1; /* Note: flag is used as exit value */ if (precise_mode) { /* wait for clock match alarm time */ if (debug_mode) printf("Wait for wakeup time\n"); do { int diff; /* Read Kernel time/date */ time(&kernel_time); kernel_tm=*localtime(&kernel_time); if (debug_mode) printf("Time: %02d:%02d:%02d, wakeup time: %02d:%02d:%02d\n", kernel_tm.tm_hour, kernel_tm.tm_min, kernel_tm.tm_sec, hour1, minute1, 0); diff= hour1*60 + minute1 - kernel_tm.tm_hour*60 - kernel_tm.tm_min; diff %= (24*60); flag=(diff!=0 && diff!=-1); if (flag) sleep(10); } while (flag); } else { /* wait for the actual sleep event */ do { old_time=new_time; sleep(2); time(&new_time); flag=difftime(new_time,old_time)<10.0; /* check for time out */ if (flag && wait_mode==0 && difftime(new_time,kernel_time)>120.0) break; /* timeout, flag is 1 */ } while (flag); if (flag) fprintf(stderr,"Time out -- no time leap happened\n"); else if (debug_mode) printf("Time leap detected\n"); } /* Waiting for child to finish */ wait(&i); /* Disable alarm interrupts */ retval = ioctl(rtcfd, RTC_AIE_OFF, 0); if (retval == -1) { perror("ioctl"); exit(errno); } close(rtcfd); if (!noapm_mode) close(apmfd); return flag; }
int apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { struct apm_softc *sc; struct apm_power_info *power; int error = 0; /* apm0 only */ if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 || !(sc = apm_cd.cd_devs[APMUNIT(dev)])) return ENXIO; switch (cmd) { /* some ioctl names from linux */ case APM_IOC_STANDBY: case APM_IOC_STANDBY_REQ: case APM_IOC_SUSPEND: case APM_IOC_SUSPEND_REQ: if ((flag & FWRITE) == 0) error = EBADF; else if (sys_platform->suspend == NULL || sys_platform->resume == NULL) error = EOPNOTSUPP; else error = apm_suspend(APM_IOC_SUSPEND); break; #ifdef HIBERNATE case APM_IOC_HIBERNATE: if ((flag & FWRITE) == 0) error = EBADF; else if (sys_platform->suspend == NULL || sys_platform->resume == NULL) error = EOPNOTSUPP; else error = apm_suspend(APM_IOC_HIBERNATE); break; #endif 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 error = EOPNOTSUPP; /* XXX */ break; case APM_IOC_GETPOWER: power = (struct apm_power_info *)data; error = (*get_apminfo)(power); break; default: error = ENOTTY; } return error; }
static void apm_event_handle(struct apm_softc *sc, u_int event_code, u_int event_info) { int error; const char *code; struct apm_power_info pi; switch (event_code) { case APM_USER_STANDBY_REQ: DPRINTF(APMDEBUG_EVENTS, ("apmev: user standby request\n")); if (apm_do_standby) { if (apm_op_inprog == 0 && apm_record_event(sc, event_code)) apm_userstandbys++; apm_op_inprog++; (void)(*sc->sc_ops->aa_set_powstate)(sc->sc_cookie, APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); } else { (void)(*sc->sc_ops->aa_set_powstate)(sc->sc_cookie, APM_DEV_ALLDEVS, APM_LASTREQ_REJECTED); /* in case BIOS hates being spurned */ (*sc->sc_ops->aa_enable)(sc->sc_cookie, 1); } break; case APM_STANDBY_REQ: DPRINTF(APMDEBUG_EVENTS, ("apmev: system standby request\n")); if (apm_op_inprog) { DPRINTF(APMDEBUG_EVENTS | APMDEBUG_ANOM, ("damn fool BIOS did not wait for answer\n")); /* just give up the fight */ apm_damn_fool_bios = 1; } if (apm_do_standby) { if (apm_op_inprog == 0 && apm_record_event(sc, event_code)) apm_standbys++; apm_op_inprog++; (void)(*sc->sc_ops->aa_set_powstate)(sc->sc_cookie, APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); } else { (void)(*sc->sc_ops->aa_set_powstate)(sc->sc_cookie, APM_DEV_ALLDEVS, APM_LASTREQ_REJECTED); /* in case BIOS hates being spurned */ (*sc->sc_ops->aa_enable)(sc->sc_cookie, 1); } break; case APM_USER_SUSPEND_REQ: DPRINTF(APMDEBUG_EVENTS, ("apmev: user suspend request\n")); if (apm_op_inprog == 0 && apm_record_event(sc, event_code)) apm_suspends++; apm_op_inprog++; (void)(*sc->sc_ops->aa_set_powstate)(sc->sc_cookie, APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); break; case APM_SUSPEND_REQ: DPRINTF(APMDEBUG_EVENTS, ("apmev: system suspend request\n")); if (apm_op_inprog) { DPRINTF(APMDEBUG_EVENTS | APMDEBUG_ANOM, ("damn fool BIOS did not wait for answer\n")); /* just give up the fight */ apm_damn_fool_bios = 1; } if (apm_op_inprog == 0 && apm_record_event(sc, event_code)) apm_suspends++; apm_op_inprog++; (void)(*sc->sc_ops->aa_set_powstate)(sc->sc_cookie, APM_DEV_ALLDEVS, APM_LASTREQ_INPROG); break; case APM_POWER_CHANGE: DPRINTF(APMDEBUG_EVENTS, ("apmev: power status change\n")); error = (*sc->sc_ops->aa_get_powstat)(sc->sc_cookie, 0, &pi); #ifdef APM_POWER_PRINT /* only print if nobody is catching events. */ if (error == 0 && (sc->sc_flags & (SCFLAG_OREAD|SCFLAG_OWRITE)) == 0) apm_power_print(sc, &pi); #else __USE(error); #endif apm_record_event(sc, event_code); break; case APM_NORMAL_RESUME: DPRINTF(APMDEBUG_EVENTS, ("apmev: resume system\n")); apm_resume(sc, event_code, event_info); break; case APM_CRIT_RESUME: DPRINTF(APMDEBUG_EVENTS, ("apmev: critical resume system")); apm_resume(sc, event_code, event_info); break; case APM_SYS_STANDBY_RESUME: DPRINTF(APMDEBUG_EVENTS, ("apmev: system standby resume\n")); apm_resume(sc, event_code, event_info); break; case APM_UPDATE_TIME: DPRINTF(APMDEBUG_EVENTS, ("apmev: update time\n")); apm_resume(sc, event_code, event_info); break; case APM_CRIT_SUSPEND_REQ: DPRINTF(APMDEBUG_EVENTS, ("apmev: critical system suspend\n")); apm_record_event(sc, event_code); apm_suspend(sc); break; case APM_BATTERY_LOW: DPRINTF(APMDEBUG_EVENTS, ("apmev: battery low\n")); apm_battlow++; apm_record_event(sc, event_code); break; case APM_CAP_CHANGE: DPRINTF(APMDEBUG_EVENTS, ("apmev: capability change\n")); if (apm_minver < 2) { DPRINTF(APMDEBUG_EVENTS, ("apm: unexpected event\n")); } else { u_int numbatts, capflags; (*sc->sc_ops->aa_get_capabilities)(sc->sc_cookie, &numbatts, &capflags); (*sc->sc_ops->aa_get_powstat)(sc->sc_cookie, 0, &pi); } break; default: switch (event_code >> 8) { case 0: code = "reserved system"; break; case 1: code = "reserved device"; break; case 2: code = "OEM defined"; break; default: code = "reserved"; break; } printf("APM: %s event code %x\n", code, event_code); } }
int apm_handle_event(struct apm_softc *sc, struct apmregs *regs) { struct apmregs nregs; int ret = 0; switch (regs->bx) { case APM_NOEVENT: ret++; break; case APM_USER_STANDBY_REQ: if (apm_resumes || apm_op_inprog) break; DPRINTF(("user wants STANDBY--fat chance\n")); apm_op_inprog++; if (apm_record_event(sc, regs->bx)) { DPRINTF(("standby ourselves\n")); apm_userstandbys++; } break; case APM_STANDBY_REQ: if (apm_resumes || apm_op_inprog) break; DPRINTF(("standby requested\n")); if (apm_standbys || apm_suspends) { DPRINTF(("premature standby\n")); apm_error++; ret++; } apm_op_inprog++; if (apm_record_event(sc, regs->bx)) { DPRINTF(("standby ourselves\n")); apm_standbys++; } break; case APM_USER_SUSPEND_REQ: if (apm_resumes || apm_op_inprog) break; DPRINTF(("user wants suspend--fat chance!\n")); apm_op_inprog++; if (apm_record_event(sc, regs->bx)) { DPRINTF(("suspend ourselves\n")); apm_suspends++; } break; case APM_SUSPEND_REQ: if (apm_resumes || apm_op_inprog) break; DPRINTF(("suspend requested\n")); if (apm_standbys || apm_suspends) { DPRINTF(("premature suspend\n")); apm_error++; ret++; } apm_op_inprog++; if (apm_record_event(sc, regs->bx)) { DPRINTF(("suspend ourselves\n")); apm_suspends++; } break; case APM_POWER_CHANGE: DPRINTF(("power status change\n")); apm_get_powstat(&nregs); apm_record_event(sc, regs->bx); break; case APM_NORMAL_RESUME: DPRINTF(("system resumed\n")); apm_resume(sc, regs); break; case APM_CRIT_RESUME: DPRINTF(("system resumed without us!\n")); apm_resume(sc, regs); break; case APM_SYS_STANDBY_RESUME: DPRINTF(("system standby resume\n")); apm_resume(sc, regs); break; case APM_UPDATE_TIME: DPRINTF(("update time, please\n")); inittodr(time_second); apm_record_event(sc, regs->bx); break; case APM_CRIT_SUSPEND_REQ: DPRINTF(("suspend required immediately\n")); apm_record_event(sc, regs->bx); apm_suspend(APM_SYS_SUSPEND); break; case APM_BATTERY_LOW: DPRINTF(("Battery low!\n")); apm_battlow++; apm_record_event(sc, regs->bx); break; case APM_CAPABILITY_CHANGE: DPRINTF(("capability change\n")); if (apm_minver < 2) { DPRINTF(("adult event\n")); } else { if (apmcall(APM_GET_CAPABILITIES, APM_DEV_APM_BIOS, &nregs) != 0) { apm_perror("get capabilities", &nregs); } else { apm_get_powstat(&nregs); } } break; default: { #ifdef APMDEBUG char *p; switch (regs->bx >> 8) { case 0: p = "reserved system"; break; case 1: p = "reserved device"; break; case 2: p = "OEM defined"; break; default:p = "reserved"; break; } #endif DPRINTF(("apm_handle_event: %s event, code %d\n", p, regs->bx)); } } return ret; }