Exemplo n.º 1
0
void
stsec_sensors_update(void *vsc)
{
	struct stsec_softc *sc = (struct stsec_softc *)vsc;
	int status, control, batl, bath;
	ulong batuv;
	struct ksensor *ks;
	uint i;
#if NAPM > 0
	struct apm_power_info old;
	uint cap_pct;
#endif

	for (i = 0; i < nitems(sc->sc_sensors); i++)
		sc->sc_sensors[i].flags |= SENSOR_FINVALID;

	if (stsec_read(sc, ST7_STATUS, &status) != 0 ||
	    stsec_read(sc, ST7_CONTROL, &control) != 0 ||
	    stsec_read(sc, ST7_BATTERY_L, &batl) != 0 ||
	    stsec_read(sc, ST7_BATTERY_H, &bath) != 0)
		return;

	/*
	 * Battery voltage is in 10/1024V units, in the 0-1023 range.
	 */
	batuv = ((ulong)STB_VALUE(bath, batl) * 10 * 1000000) / 1024;
	
	ks = &sc->sc_sensors[STSEC_SENSOR_AC_PRESENCE];
	ks->value = !!ISSET(status, STS_AC_AVAILABLE);
	ks->flags &= ~SENSOR_FINVALID;

	/*
	 * Old mobo design does not have a battery presence bit; the Linux
	 * code decides there is no battery if the reported battery voltage
	 * is too low, we'll do the same.
	 */
	ks = &sc->sc_sensors[STSEC_SENSOR_BATTERY_PRESENCE];
	switch (gdium_revision) {
	case 0:
		if (ISSET(status, STS_AC_AVAILABLE))
			ks->value = batuv > 500000;
		else
			ks->value = 1;
		break;
	default:
		ks->value = !!ISSET(status, STS_BATTERY_PRESENT);
		break;
	}
	ks->flags &= ~SENSOR_FINVALID;
	
	ks = &sc->sc_sensors[STSEC_SENSOR_BATTERY_STATE];
	ks->value = !!ISSET(control, STC_CHARGE_ENABLE);
	ks->flags &= ~SENSOR_FINVALID;
	
	ks = &sc->sc_sensors[STSEC_SENSOR_BATTERY_VOLTAGE];
	ks->value = (int64_t)batuv;
	ks->flags &= ~SENSOR_FINVALID;

#if NAPM > 0
	bcopy(&stsec_apmdata, &old, sizeof(old));

	if (batuv < STSEC_BAT_MIN_VOLT)
		batuv = STSEC_BAT_MIN_VOLT;
	else if (batuv > STSEC_BAT_MAX_VOLT)
		batuv = STSEC_BAT_MAX_VOLT;
	cap_pct = (batuv - STSEC_BAT_MIN_VOLT) * 100 / (STSEC_BAT_MAX_VOLT -
	    STSEC_BAT_MIN_VOLT);
	stsec_apmdata.battery_life = cap_pct;

	stsec_apmdata.ac_state = ISSET(status, STS_AC_AVAILABLE) ? APM_AC_ON :
	    APM_AC_OFF;
	if (!sc->sc_sensors[STSEC_SENSOR_BATTERY_PRESENCE].value) {
		stsec_apmdata.battery_state = APM_BATTERY_ABSENT;
		stsec_apmdata.minutes_left = 0;
		stsec_apmdata.battery_life = 0;
	} else {
		if (ISSET(control, STC_CHARGE_ENABLE))
			stsec_apmdata.battery_state = APM_BATT_CHARGING;
		/* XXX arbitrary */
		else if (cap_pct < 10)
			stsec_apmdata.battery_state = APM_BATT_CRITICAL;
		else if (cap_pct > 60)
			stsec_apmdata.battery_state = APM_BATT_HIGH;
		else
			stsec_apmdata.battery_state = APM_BATT_LOW;

		stsec_apmdata.minutes_left = -1; /* unknown */
	}
	if (old.ac_state != stsec_apmdata.ac_state) 
		apm_record_event(APM_POWER_CHANGE, "AC power",
			stsec_apmdata.ac_state ? "restored" : "lost");
	if (old.battery_state != stsec_apmdata.battery_state) 
		apm_record_event(APM_POWER_CHANGE, "battery",
		    BATTERY_STRING(stsec_apmdata.battery_state));
#endif
}
Exemplo n.º 2
0
void
ykbec_refresh(void *arg)
{
	struct ykbec_softc *sc = (struct ykbec_softc *)arg;
	u_int val, bat_charge, bat_status, charge_status, bat_state, power_flag;
	u_int cap_pct, fullcap;
	int current;
#if NAPM > 0
	struct apm_power_info old;
#endif

	val = ykbec_read16(sc, REG_FAN_SPEED_HIGH) & 0xfffff;
	if (val != 0) {
		val = KB3310_FAN_SPEED_DIVIDER / val;
		sc->sc_sensor[YKBEC_FAN].value = val;
		CLR(sc->sc_sensor[YKBEC_FAN].flags, SENSOR_FINVALID);
	} else
		SET(sc->sc_sensor[YKBEC_FAN].flags, SENSOR_FINVALID);

	val = ykbec_read(sc, ECTEMP_CURRENT_REG);
	sc->sc_sensor[YKBEC_ITEMP].value = val * 1000000 + 273150000;

	fullcap = ykbec_read16(sc, REG_FULLCHG_CAP_HIGH);
	sc->sc_sensor[YKBEC_FCAP].value = fullcap * 1000;

	current = ykbec_read16(sc, REG_CURRENT_HIGH);
	/* sign extend short -> int, int -> int64 will be done next statement */
	current |= -(current & 0x8000);
	sc->sc_sensor[YKBEC_BCURRENT].value = -1000 * current;

	sc->sc_sensor[YKBEC_BVOLT].value = ykbec_read16(sc, REG_VOLTAGE_HIGH) *
	    1000;

	val = ykbec_read16(sc, REG_TEMPERATURE_HIGH);
	sc->sc_sensor[YKBEC_BTEMP].value = val * 1000000 + 273150000;

	cap_pct = ykbec_read16(sc, REG_RELATIVE_CAT_HIGH);
	sc->sc_sensor[YKBEC_CAP].value = cap_pct * 1000;

	bat_charge = ykbec_read(sc, REG_BAT_CHARGE);
	bat_status = ykbec_read(sc, REG_BAT_STATUS);
	charge_status = ykbec_read(sc, REG_CHARGE_STATUS);
	bat_state = ykbec_read(sc, REG_BAT_STATE);
	power_flag = ykbec_read(sc, REG_POWER_FLAG);

	sc->sc_sensor[YKBEC_CHARGING].value = !!ISSET(bat_state,
	    BAT_STATE_CHARGING);
	sc->sc_sensor[YKBEC_AC].value = !!ISSET(power_flag,
	    POWER_FLAG_ADAPTER_IN);

	sc->sc_sensor[YKBEC_CAP].status = ISSET(bat_status, BAT_STATUS_BAT_LOW) ?
		SENSOR_S_CRIT : SENSOR_S_OK;

#if NAPM > 0
	bcopy(&ykbec_apmdata, &old, sizeof(old));
	ykbec_apmdata.battery_life = cap_pct;
	ykbec_apmdata.ac_state = ISSET(power_flag, POWER_FLAG_ADAPTER_IN) ?
	    APM_AC_ON : APM_AC_OFF;
	if (!ISSET(bat_status, BAT_STATUS_BAT_EXISTS)) {
		ykbec_apmdata.battery_state = APM_BATTERY_ABSENT;
		ykbec_apmdata.minutes_left = 0;
		ykbec_apmdata.battery_life = 0;
	} else {
		if (ISSET(bat_state, BAT_STATE_CHARGING))
			ykbec_apmdata.battery_state = APM_BATT_CHARGING;
		else if (ISSET(bat_status, BAT_STATUS_BAT_LOW))
			ykbec_apmdata.battery_state = APM_BATT_CRITICAL;
		/* XXX arbitrary */
		else if (cap_pct > 60)
			ykbec_apmdata.battery_state = APM_BATT_HIGH;
		else
			ykbec_apmdata.battery_state = APM_BATT_LOW;

		/* if charging, current is positive */
		if (ISSET(bat_state, BAT_STATE_CHARGING))
			current = 0;
		else
			current = -current;
		/* XXX Yeeloong draw is about 1A */
		if (current <= 0)
			current = 1000;
		/* XXX at 5?%, the Yeeloong shuts down */
		if (cap_pct <= 5)
			cap_pct = 0;
		else
			cap_pct -= 5;
		fullcap = cap_pct * 60 * fullcap / 100;
		ykbec_apmdata.minutes_left = fullcap / current;

	}
	if (old.ac_state != ykbec_apmdata.ac_state) 
		apm_record_event(APM_POWER_CHANGE, "AC power",
			ykbec_apmdata.ac_state ? "restored" : "lost");
	if (old.battery_state != ykbec_apmdata.battery_state) 
		apm_record_event(APM_POWER_CHANGE, "battery",
		    BATTERY_STRING(ykbec_apmdata.battery_state));
#endif
}