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 }
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 }