示例#1
0
文件: apm.c 项目: bluhm/sys
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);
}
示例#2
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);
}
示例#3
0
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(&regs, sizeof(regs));
			if (!apmcall(APM_GET_POWER_STATE, actl->dev, &regs))
				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(&regs) == 0) {
			struct apm_power_info *powerp =
			    (struct apm_power_info *)data;

			bzero(powerp, sizeof(*powerp));
			if (BATT_LIFE(&regs) != APM_BATT_LIFE_UNKNOWN)
				powerp->battery_life = BATT_LIFE(&regs);
			powerp->ac_state = AC_STATE(&regs);
			switch (apm_minver) {
			case 0:
				if (!(BATT_FLAGS(&regs) & APM_BATT_FLAG_NOBATTERY))
					powerp->battery_state = BATT_STATE(&regs);
				break;
			case 1:
			default:
				if (BATT_FLAGS(&regs) & APM_BATT_FLAG_HIGH)
					powerp->battery_state = APM_BATT_HIGH;
				else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_LOW)
					powerp->battery_state = APM_BATT_LOW;
				else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_CRITICAL)
					powerp->battery_state = APM_BATT_CRITICAL;
				else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_CHARGING)
					powerp->battery_state = APM_BATT_CHARGING;
				else if (BATT_FLAGS(&regs) & APM_BATT_FLAG_NOBATTERY)
					powerp->battery_state = APM_BATTERY_ABSENT;
				else
					powerp->battery_state = APM_BATT_UNKNOWN;
				if (BATT_REM_VALID(&regs)) {
					powerp->minutes_left = BATT_REMAINING(&regs);
					if (sc->be_batt)
						powerp->minutes_left =
						    swap16(powerp->minutes_left);
				}
			}
		} else {
			apm_perror("ioctl get power status", &regs);
			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;
}