Exemple #1
0
void
apm_set_ver(struct apm_softc *self)
{
	struct apmregs regs;
	int rv = 0;

	bzero(&regs, sizeof(regs));
	regs.cx = APM_VERSION;

	if (APM_MAJOR(apm_flags) == 1 && APM_MINOR(apm_flags) == 2 &&
	    (rv = apmcall(APM_DRIVER_VERSION, APM_DEV_APM_BIOS, &regs)) == 0) {
		apm_majver = APM_CONN_MAJOR(&regs);
		apm_minver = APM_CONN_MINOR(&regs);
	} else {
#ifdef APMDEBUG
		if (rv)
			apm_perror("set version 1.2", &regs);
#endif
		/* try downgrading to 1.1 */
		bzero(&regs, sizeof(regs));
		regs.cx = 0x0101;

		if (apmcall(APM_DRIVER_VERSION, APM_DEV_APM_BIOS, &regs) == 0) {
			apm_majver = 1;
			apm_minver = 1;
		} else {
#ifdef APMDEBUG
			apm_perror("set version 1.1", &regs);
#endif
			/* stay w/ flags then */
			apm_majver = APM_MAJOR(apm_flags);
			apm_minver = APM_MINOR(apm_flags);

			/* fix version for some endianess-challenged compaqs */
			if (!apm_majver) {
				apm_majver = 1;
				apm_minver = 0;
			}
		}
	}
	printf(": Power Management spec V%d.%d", apm_majver, apm_minver);
#ifdef DIAGNOSTIC
	if (apm_flags & APM_IDLE_SLOWS)
		printf(" (slowidle)");
	if (apm_flags & APM_BIOS_PM_DISABLED)
		printf(" (BIOS management disabled)");
	if (apm_flags & APM_BIOS_PM_DISENGAGED)
		printf(" (BIOS managing devices)");
#endif
	printf("\n");
}
Exemple #2
0
void
apm_disconnect(struct apm_softc *sc)
{
	struct apmregs regs;

	bzero(&regs, sizeof(regs));
	if (apmcall(APM_SYSTEM_DEFAULTS,
	    (apm_minver == 1 ? APM_DEV_ALLDEVS : APM_DEFAULTS_ALL), &regs))
		apm_perror("system defaults failed", &regs);

	if (apmcall(APM_DISCONNECT, APM_DEV_APM_BIOS, &regs))
		apm_perror("disconnect failed", &regs);
	else
		printf("%s: disconnected\n", sc->sc_dev.dv_xname);
	apm_flags |= APM_BIOS_PM_DISABLED;
}
Exemple #3
0
void
apm_cpu_idle(void)
{
	struct apmregs regs;
	static u_int64_t call_apm_idle = 0;

	/*
	 * We call the bios APM_IDLE routine here only when we
	 * have been idle for some time - otherwise we just hlt.
	 */

	if  (call_apm_idle != curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]) {
		/* Always call BIOS halt/idle stuff */
		bzero(&regs, sizeof(regs));
		if (apmcall(APM_CPU_IDLE, 0, &regs) != 0) {
#ifdef DIAGNOSTIC
			apm_perror("set CPU idle", &regs);
#endif
		}

		/* If BIOS did not halt, halt now! */
		if (apm_flags & APM_IDLE_SLOWS) {
			__asm __volatile("sti;hlt");
		}
		call_apm_idle = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE];
	} else {
		__asm __volatile("sti;hlt");
	}
}
Exemple #4
0
static int __inline
apm_get_event(struct apmregs *r)
{
	int rv;
	bzero(r, sizeof(*r));
	rv = apmcall(APM_GET_PM_EVENT, 0, r);
	return rv;
}
Exemple #5
0
void
apm_powmgt_enable(int onoff)
{
	struct apmregs regs;

	bzero(&regs, sizeof(regs));
	regs.cx = onoff ? APM_MGT_ENABLE : APM_MGT_DISABLE;
	if (apmcall(APM_PWR_MGT_ENABLE,
	    (apm_minver? APM_DEV_APM_BIOS : APM_MGT_ALL), &regs) != 0)
		apm_perror("power management enable", &regs);
}
Exemple #6
0
void
apm_powmgt_engage(int onoff, u_int dev)
{
	struct apmregs regs;

	if (apm_minver == 0)
		return;
	bzero(&regs, sizeof(regs));
	regs.cx = onoff ? APM_MGT_ENGAGE : APM_MGT_DISENGAGE;
	if (apmcall(APM_PWR_MGT_ENGAGE, dev, &regs) != 0)
		printf("apm0: APM engage (device %x): %s (%d)\n",
		    dev, apm_err_translate(APM_ERR_CODE(&regs)),
		    APM_ERR_CODE(&regs));
}
Exemple #7
0
void
apm_devpowmgt_enable(int onoff, u_int dev)
{
	struct apmregs regs;

	if (apm_minver == 0)
		return;
	/* enable is auto BIOS management.
	 * disable is program control.
	 */
	bzero(&regs, sizeof(regs));
	regs.cx = onoff ? APM_MGT_ENABLE : APM_MGT_DISABLE;
	if (apmcall(APM_DEVICE_MGMT_ENABLE, dev, &regs) != 0)
		printf("APM device engage (device %x): %s (%d)\n",
		    dev, apm_err_translate(APM_ERR_CODE(&regs)),
		    APM_ERR_CODE(&regs));
}
Exemple #8
0
void
apm_cpu_busy(void)
{
	struct apmregs regs;

	if (!apm_slow_called)
		return;

	if (apm_flags & APM_IDLE_SLOWS) {
		bzero(&regs, sizeof(regs));
		if (apmcall(APM_CPU_BUSY, 0, &regs) != 0) {
#ifdef DIAGNOSTIC
			apm_perror("set CPU busy", &regs);
#endif
		}
		apm_slow_called = 0;
	}
}
Exemple #9
0
void
apm_cpu_slow(void)
{
	struct apmregs regs;
	static u_int64_t call_apm_slow = 0;

	if  (call_apm_slow != curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]) {
		/* Always call BIOS halt/idle stuff */
		bzero(&regs, sizeof(regs));
		if (apmcall(APM_CPU_IDLE, 0, &regs) != 0) {
#ifdef DIAGNOSTIC
			apm_perror("set CPU slow", &regs);
#endif
		}
		apm_slow_called = 1;
		call_apm_slow = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE];
	}
}
Exemple #10
0
int
apm_set_powstate(u_int dev, u_int state)
{
	struct apmregs regs;

	if (!apm_cd.cd_ndevs || (apm_minver == 0 && state > APM_SYS_OFF))
		return EINVAL;
	bzero(&regs, sizeof(regs));
	regs.cx = state;
	if (apmcall(APM_SET_PWR_STATE, dev, &regs) != 0) {
		apm_perror("set power state", &regs);
		if (APM_ERR_CODE(&regs) == APM_ERR_UNRECOG_DEV)
			return ENXIO;
		else
			return EIO;
	}
	return 0;
}
Exemple #11
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;
}
Exemple #12
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;
}