Пример #1
0
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);
	}
}
Пример #2
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;
}
Пример #3
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(&regs) != 0) {
			/* i think some bioses combine the error codes */
			if (!(APM_ERR_CODE(&regs) & APM_ERR_NOEVENTS))
				apm_perror("get event", &regs);
			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, &regs))
			break;
	}

	if (apm_error || APM_ERR_CODE(&regs) == APM_ERR_NOTCONN)
		ret = -1;

	if (apm_lidclose) {
		apm_lidclose = 0;
		/* Fake a suspend request */
		regs.bx = APM_SUSPEND_REQ;
		apm_handle_event(sc, &regs);
	}
	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);
}
Пример #4
0
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);
}
Пример #5
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;
}
Пример #6
0
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;
}
Пример #7
0
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);
	}
}
Пример #8
0
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;
}