/* $NetBSD$ */ /*- * Copyright (c) 2026 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Julian Coleman. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #define ENVMON_MACHINE_U25 0x19 #define ENVMON_MACHINE_U45 0x2d #define ENVMON_MACHINE_V215 0xd7 #define ENVMON_MACHINE_V245 0xf5 #define ENVMON_PIC_MAX_TEMPS 1 #define ENVMON_PIC_WMIN_TEMP 273150000 /* 0C from Solaris */ #define ENVMON_PIC_WMAX_TEMP 318150000 /* 45C from Solaris */ #define ENVMON_PIC_CRIT_TEMP 338150000 /* 65C from Solaris */ struct envmon_epic_fans { const uint8_t reg; const char *desc; }; static struct envmon_epic_fans envmon_epic_fans_table[] = { { ENVMON_EPC_FAN_FT0_F0, "FT0.F0" }, { ENVMON_EPC_FAN_FT1_F0, "FT1.F0" }, { ENVMON_EPC_FAN_FT2_F0, "FT2.F0" }, { ENVMON_EPC_FAN_FT3_F0, "FT3.F0" }, { ENVMON_EPC_FAN_FT4_F0, "FT4.F0" }, { ENVMON_EPC_FAN_FT5_F0, "FT5.F0" }, { ENVMON_EPC_FAN_FT0_F1, "FT0.F1" }, { ENVMON_EPC_FAN_FT1_F1, "FT1.F1" }, { ENVMON_EPC_FAN_FT2_F1, "FT2.F1" }, { ENVMON_EPC_FAN_FT3_F1, "FT3.F1" }, { ENVMON_EPC_FAN_FT4_F1, "FT4.F1" }, { ENVMON_EPC_FAN_FT5_F1, "FT5.F1" }, }; #define ENVMON_EPC_MAX_FANS (sizeof(envmon_epic_fans_table) / \ sizeof(envmon_epic_fans_table[0])) #define ENVMON_EPC_DIV_V245 5625 #define ENVMON_EPC_DIV_V215 11250 #define ENVMON_EPC_CRIT_SPEED_V245 2022 /* From ALOM */ #define ENVMON_EPC_CRIT_SPEED_V215 5012 /* From ALOM */ #define ENVMON_EPC_WMIN_TEMP 273150000 /* 0C from ALOM */ #define ENVMON_EPC_WMAX_TEMP 318150000 /* 45C from ALOM */ #define ENVMON_EPC_CRIT_TEMP 323150000 /* 50C from ALOM */ #define ENVMON_EPC_VAL_TO_SPEED(div, val) ((div * 60) / val) #define ENVMON_EPC_MAX_TEMPS 1 struct envmon_epic_ind { uint8_t reg, set; const char *desc; }; static struct envmon_epic_ind envmon_epic_inds_table[] = { { ENVMON_EPC_KEYSW, ENVMON_EPC_KEYSW_NORM, "keyswitch normal/diag" }, { ENVMON_EPC_KEYSW, ENVMON_EPC_KEYSW_LOCK, "keyswitch locked" }, }; #define ENVMON_EPC_MAX_INDS (sizeof(envmon_epic_inds_table) / \ sizeof(envmon_epic_inds_table[0])) struct envmon_epic_led { uint8_t reg, v_on; const char *desc; }; static struct envmon_epic_led envmon_epic_led_table[] = { { ENVMON_EPC_LED6, ENVMON_EPC_LED6_LOC, "locator" }, { ENVMON_EPC_LED6, ENVMON_EPC_LED6_SRV, "service" }, { ENVMON_EPC_LED6, ENVMON_EPC_LED6_SRV_FSH, "service_flash" }, { ENVMON_EPC_LED6, ENVMON_EPC_LED6_PWR, "power" }, { ENVMON_EPC_LED6, ENVMON_EPC_LED6_TF_FLT, "top_fan_fault" }, { ENVMON_EPC_LED6, ENVMON_EPC_LED6_TF_FLT_FSH, "top_fan_fault_flash" }, { ENVMON_EPC_LED7, ENVMON_EPC_LED7_PSU, "psu_fault" }, { ENVMON_EPC_LED7, ENVMON_EPC_LED7_PSU_FSH, "psu_fault_flash" }, { ENVMON_EPC_LED7, ENVMON_EPC_LED7_CTEMP, "cpu_overtemp" }, { ENVMON_EPC_LED7, ENVMON_EPC_LED7_CTEMP_FSH, "cpu_overtemp_flash" }, }; #define ENVMON_EPC_MAX_LEDS (sizeof(envmon_epic_led_table) / \ sizeof(envmon_epic_led_table[0])) #define ENVMON_EPC_MAX_SENSORS \ (ENVMON_EPC_MAX_FANS + ENVMON_EPC_MAX_TEMPS + ENVMON_EPC_MAX_INDS) #define ENVMON_MAX_TEMPS \ MAX(ENVMON_PIC_MAX_TEMPS, ENVMON_EPC_MAX_TEMPS) #define ENVMON_MAX_SENSORS \ MAX(ENVMON_PIC_MAX_TEMPS, ENVMON_EPC_MAX_SENSORS) struct envmon_sc_fan { uint8_t reg; int crit; }; struct envmon_sc_temp { uint8_t reg; int wmin, wmax, crit; }; struct envmon_sc_ind { uint8_t reg, set; }; struct envmon_sc_led { void *cookie; struct led_device *led; uint8_t reg, v_on; }; struct envmon_softc { device_t sc_dev; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; int sc_machine_type, sc_nfans; struct envmon_sc_fan sc_fan[ENVMON_EPC_MAX_FANS]; struct envmon_sc_temp sc_temp[ENVMON_MAX_TEMPS]; struct envmon_sc_ind sc_ind[ENVMON_EPC_MAX_INDS]; struct envmon_sc_led sc_led[ENVMON_EPC_MAX_LEDS]; struct sysmon_envsys *sc_sme; envsys_data_t sc_sensor[ENVMON_MAX_SENSORS]; #ifdef ENVMON_DEBUG #define ENVMON_MAX_REG 0x3d uint8_t sc_reg[ENVMON_MAX_REG]; #define ENVMON_TIMER 60 callout_t sc_timer; #endif }; static int envmon_ebus_match(device_t, cfdata_t, void *); static void envmon_ebus_attach(device_t, device_t, void *); static void envmon_pic_attach(struct envmon_softc *, int); static void envmon_epic_attach(struct envmon_softc *, int); void envmon_pic_refresh(struct sysmon_envsys *, envsys_data_t *); void envmon_epic_refresh(struct sysmon_envsys *, envsys_data_t *); void envmon_epic_refresh_fan(struct envmon_softc *, envsys_data_t *); void envmon_refresh_temp(struct envmon_softc *, envsys_data_t *); void envmon_epic_refresh_ind(struct envmon_softc *, envsys_data_t *); void envmon_pic_get_limits(struct sysmon_envsys *, envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); void envmon_pic_set_limits(struct sysmon_envsys *, envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); void envmon_epic_get_limits(struct sysmon_envsys *, envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); void envmon_epic_set_limits(struct sysmon_envsys *, envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); static void envmon_epic_get_fan_limits(struct envmon_softc *, envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); static void envmon_get_temp_limits(struct envmon_softc *, envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); static void envmon_epic_set_fan_limits(struct envmon_softc *, envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); static void envmon_set_temp_limits(struct envmon_softc *, envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *); int envmon_epic_get_led(void *); void envmon_epic_set_led(void *, int); #ifdef ENVMON_DEBUG static void envmon_timeout(void *); #endif CFATTACH_DECL_NEW(envmon_ebus, sizeof(struct envmon_softc), envmon_ebus_match, envmon_ebus_attach, NULL, NULL); #define envmon_read(sc, reg) \ bus_space_read_1(sc->sc_bst, sc->sc_bsh, reg) #define envmon_write(sc, reg, val) \ bus_space_write_1(sc->sc_bst, sc->sc_bsh, reg, val) static int envmon_ebus_match(device_t parent, cfdata_t cf, void *aux) { struct ebus_attach_args *ea = aux; char *compat; if (strcmp("env-monitor", ea->ea_name) != 0) return 0; compat = prom_getpropstring(ea->ea_node, "compatible"); if (compat != NULL && (!strcmp(compat, "SUNW,ebus-pic16f747-env") || !strcmp(compat, "epic"))) return 1; return 0; } static void envmon_ebus_attach(device_t parent, device_t self, void *aux) { struct envmon_softc *sc = device_private(self); struct ebus_attach_args *ea = aux; char compat[32]; int sz; #ifdef ENVMON_DEBUG uint8_t reg; #endif sc->sc_dev = self; sc->sc_bst = ea->ea_bustag; sz = ea->ea_reg[0].size; if (bus_space_map(sc->sc_bst, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]), sz, 0, &sc->sc_bsh) != 0) { aprint_error(": can't map register\n"); return; } sc->sc_sme = sysmon_envsys_create(); sc->sc_sme->sme_name = device_xname(self); sc->sc_sme->sme_cookie = sc; OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)); if (!strcmp(compat, "SUNW,ebus-pic16f747-env")) { envmon_pic_attach(sc, ea->ea_node); } if (!strcmp(compat, "epic")) { envmon_epic_attach(sc, ea->ea_node); } #ifdef ENVMON_DEBUG for (reg = 0; reg < ENVMON_MAX_REG; reg++) { envmon_write(sc, ENVMON_ADDR, reg); sc->sc_reg[reg] = envmon_read(sc, ENVMON_DATA); } callout_init(&sc->sc_timer, CALLOUT_MPSAFE); callout_reset(&sc->sc_timer, hz * ENVMON_TIMER, envmon_timeout, sc); #endif } /* * We only add the front panel temperature here. * Other U45 sensors are handled by the ADT7462 driver. */ static void envmon_pic_attach(struct envmon_softc *sc, int node) { int32_t vers; vers = prom_getpropint(node, "version", 0); aprint_normal(": pic16f747 (ver. %d)\n", vers); if (!strcmp(machine_model, "SUNW,A70")) { sc->sc_machine_type = ENVMON_MACHINE_U45; } else if (!strcmp(machine_model, "SUNW,Ultra-25")) { sc->sc_machine_type = ENVMON_MACHINE_U25; } else { aprint_error_dev(sc->sc_dev, "unsupported machine model\n"); return; } sc->sc_sme->sme_refresh = envmon_pic_refresh; sc->sc_sme->sme_get_limits = envmon_pic_get_limits; sc->sc_sme->sme_set_limits = envmon_pic_set_limits; strlcpy(sc->sc_sensor[0].desc, "Front_panel", sizeof(sc->sc_sensor[0].desc)); sc->sc_sensor[0].units = ENVSYS_STEMP; sc->sc_sensor[0].state = ENVSYS_SINVALID; sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY | ENVSYS_FMONCRITICAL; sc->sc_temp[0].reg = ENVMON_PIC_TEMP_FP; sc->sc_temp[0].wmin = ENVMON_PIC_WMIN_TEMP; sc->sc_temp[0].wmax = ENVMON_PIC_WMAX_TEMP; sc->sc_temp[0].crit = ENVMON_PIC_CRIT_TEMP; if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[0])) { sysmon_envsys_destroy(sc->sc_sme); sc->sc_sme = NULL; aprint_error_dev(sc->sc_dev, "unable to attach sensor to sysmon\n"); return; } if (sysmon_envsys_register(sc->sc_sme)) { aprint_error_dev(sc->sc_dev, "unable to register with sysmon\n"); sysmon_envsys_destroy(sc->sc_sme); sc->sc_sme = NULL; return; } return; } static void envmon_epic_attach(struct envmon_softc *sc, int node) { const char *vers; uint16_t fan_mask; int crit, i, j; vers = prom_getpropstring(node, "version"); aprint_normal(": epic (ver. %s)\n", vers); /* Fans */ if (!strcmp(machine_model, "SUNW,Sun-Fire-V245")) { sc->sc_machine_type = ENVMON_MACHINE_V245; sc->sc_nfans = 6; fan_mask = 0x003f; /* 6 fans */ crit = ENVMON_EPC_CRIT_SPEED_V245; } else if (!strcmp(machine_model, "SUNW,Sun-Fire-V215")) { sc->sc_machine_type = ENVMON_MACHINE_V215; sc->sc_nfans = 12; fan_mask = 0x0fff; /* 12 fans */ crit = ENVMON_EPC_CRIT_SPEED_V215; } else { aprint_error_dev(sc->sc_dev, "unsupported machine model\n"); return; } sc->sc_sme->sme_refresh = envmon_epic_refresh; sc->sc_sme->sme_get_limits = envmon_epic_get_limits; sc->sc_sme->sme_set_limits = envmon_epic_set_limits; for (i = 0; i < ENVMON_EPC_MAX_FANS; i++) { if (!(fan_mask & (1 << i))) continue; strlcpy(sc->sc_sensor[i].desc, envmon_epic_fans_table[i].desc, sizeof(sc->sc_sensor[i].desc)); sc->sc_sensor[i].units = ENVSYS_SFANRPM; sc->sc_sensor[i].state = ENVSYS_SINVALID; sc->sc_sensor[i].flags = ENVSYS_FMONCRITICAL; sc->sc_fan[i].reg = envmon_epic_fans_table[i].reg; sc->sc_fan[i].crit = crit; if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) { sysmon_envsys_destroy(sc->sc_sme); sc->sc_sme = NULL; aprint_error_dev(sc->sc_dev, "unable to attach sensor to sysmon\n"); goto leds; } } /* Temperature */ i = sc->sc_nfans; strlcpy(sc->sc_sensor[i].desc, "FIOB.T_AMB", sizeof(sc->sc_sensor[i].desc)); sc->sc_sensor[i].units = ENVSYS_STEMP; sc->sc_sensor[i].state = ENVSYS_SINVALID; sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY | ENVSYS_FMONCRITICAL; sc->sc_temp[0].reg = ENVMON_EPC_TEMP_FP; sc->sc_temp[0].wmin = ENVMON_PIC_WMIN_TEMP; sc->sc_temp[0].wmax = ENVMON_PIC_WMAX_TEMP; sc->sc_temp[0].crit = ENVMON_EPC_CRIT_TEMP; if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) { sysmon_envsys_destroy(sc->sc_sme); sc->sc_sme = NULL; aprint_error_dev(sc->sc_dev, "unable to attach sensor to sysmon\n"); goto leds; } i++; /* Indicators */ for (j = 0; j < ENVMON_EPC_MAX_INDS; j++, i++) { strlcpy(sc->sc_sensor[i].desc, envmon_epic_inds_table[j].desc, sizeof(sc->sc_sensor[i].desc)); sc->sc_sensor[i].units = ENVSYS_INDICATOR; sc->sc_sensor[i].state = ENVSYS_SINVALID; sc->sc_ind[j].reg = envmon_epic_inds_table[j].reg; sc->sc_ind[j].set = envmon_epic_inds_table[j].set; if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) { sysmon_envsys_destroy(sc->sc_sme); sc->sc_sme = NULL; aprint_error_dev(sc->sc_dev, "unable to attach sensor to sysmon\n"); goto leds; } } if (sysmon_envsys_register(sc->sc_sme)) { aprint_error_dev(sc->sc_dev, "unable to register with sysmon\n"); sysmon_envsys_destroy(sc->sc_sme); sc->sc_sme = NULL; } leds: /* LED's */ for (i = 0; i < ENVMON_EPC_MAX_LEDS; i++) { sc->sc_led[i].cookie = sc; sc->sc_led[i].reg = envmon_epic_led_table[i].reg; sc->sc_led[i].v_on = envmon_epic_led_table[i].v_on; led_attach(envmon_epic_led_table[i].desc, &sc->sc_led[i], envmon_epic_get_led, envmon_epic_set_led); } return; } void envmon_pic_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) { struct envmon_softc *sc = sme->sme_cookie; envmon_refresh_temp(sc, edata); } void envmon_epic_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) { struct envmon_softc *sc = sme->sme_cookie; if (edata->sensor < sc->sc_nfans) envmon_epic_refresh_fan(sc, edata); else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS) envmon_refresh_temp(sc, edata); else envmon_epic_refresh_ind(sc, edata); return; } void envmon_epic_refresh_fan(struct envmon_softc *sc, envsys_data_t *edata) { uint8_t val; int div; if (sc->sc_machine_type == ENVMON_MACHINE_V245) div = ENVMON_EPC_DIV_V245; else div = ENVMON_EPC_DIV_V215; /* switch (sc->sc_machine_type) { case ENVMON_MACHINE_V215: div = ENVMON_EPC_DIV_V215; crit = ENVMON_EPC_CRIT_SPEED_V215; break; case ENVMON_MACHINE_V245: default: div = ENVMON_EPC_DIV_V245; crit = ENVMON_EPC_CRIT_SPEED_V245; break; } */ envmon_write(sc, ENVMON_ADDR, sc->sc_fan[edata->sensor].reg); val = envmon_read(sc, ENVMON_DATA); if (val == 0xff || val == 0x0) edata->value_cur = 0; else { edata->value_cur = ENVMON_EPC_VAL_TO_SPEED(div, val); } if (edata->value_cur < sc->sc_fan[edata->sensor].crit) edata->state = ENVSYS_SCRITICAL; else edata->state = ENVSYS_SVALID; } void envmon_refresh_temp(struct envmon_softc *sc, envsys_data_t *edata) { uint8_t val; /* We currently only have 1 temperature sensor */ envmon_write(sc, ENVMON_ADDR, sc->sc_temp[0].reg); val = envmon_read(sc, ENVMON_DATA); edata->value_cur = ENVMON_TEMP_BASE + val * 1000000; if (edata->value_cur > sc->sc_temp[0].crit) edata->state = ENVSYS_SCRITICAL; else edata->state = ENVSYS_SVALID; } void envmon_epic_refresh_ind(struct envmon_softc *sc, envsys_data_t *edata) { int ind = edata->sensor - sc->sc_nfans - ENVMON_EPC_MAX_TEMPS; uint8_t val; envmon_write(sc, ENVMON_ADDR, sc->sc_ind[ind].reg); val = envmon_read(sc, ENVMON_DATA); if (val == sc->sc_ind[ind].set) edata->value_cur = TRUE; else edata->value_cur = FALSE; edata->state = ENVSYS_SVALID; } void envmon_pic_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) { struct envmon_softc *sc = sme->sme_cookie; envmon_get_temp_limits(sc, edata, limits, props); } void envmon_pic_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) { struct envmon_softc *sc = sme->sme_cookie; envmon_set_temp_limits(sc, edata, limits, props); } void envmon_epic_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) { struct envmon_softc *sc = sme->sme_cookie; if (edata->sensor < sc->sc_nfans) envmon_epic_get_fan_limits(sc, edata, limits, props); else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS) envmon_get_temp_limits(sc, edata, limits, props); } void envmon_epic_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) { struct envmon_softc *sc = sme->sme_cookie; if (edata->sensor < sc->sc_nfans) envmon_epic_set_fan_limits(sc, edata, limits, props); else if (edata->sensor < sc->sc_nfans + ENVMON_EPC_MAX_TEMPS) envmon_set_temp_limits(sc, edata, limits, props); } static void envmon_epic_get_fan_limits(struct envmon_softc *sc, envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) { *props = PROP_CRITMAX; limits->sel_critmax = sc->sc_fan[edata->sensor].crit; } static void envmon_get_temp_limits(struct envmon_softc *sc, envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) { *props = PROP_WARNMIN | PROP_WARNMAX | PROP_CRITMAX; limits->sel_warnmin = sc->sc_temp[0].wmin; limits->sel_warnmax = sc->sc_temp[0].wmax; limits->sel_critmax = sc->sc_temp[0].crit; } static void envmon_epic_set_fan_limits(struct envmon_softc *sc, envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) { if (limits == NULL || *props & PROP_CRITMAX) { if (limits == NULL) /* Restore defaults */ switch (sc->sc_machine_type) { case ENVMON_MACHINE_V215: sc->sc_fan[edata->sensor].crit = ENVMON_EPC_CRIT_SPEED_V215; break; case ENVMON_MACHINE_V245: sc->sc_fan[edata->sensor].crit = ENVMON_EPC_CRIT_SPEED_V245; break; } else sc->sc_fan[edata->sensor].crit = limits->sel_critmax; } } static void envmon_set_temp_limits(struct envmon_softc *sc, envsys_data_t *edata, sysmon_envsys_lim_t *limits, uint32_t *props) { if (limits == NULL || *props & PROP_CRITMAX) { if (limits == NULL) /* Restore defaults */ switch (sc->sc_machine_type) { case ENVMON_MACHINE_U25: case ENVMON_MACHINE_U45: sc->sc_temp[0].crit = ENVMON_PIC_CRIT_TEMP; break; case ENVMON_MACHINE_V215: case ENVMON_MACHINE_V245: sc->sc_temp[0].crit = ENVMON_EPC_CRIT_TEMP; break; } else sc->sc_temp[edata->sensor].crit = limits->sel_critmax; } if (limits == NULL || *props & PROP_WARNMAX) { if (limits == NULL) /* Restore defaults */ switch (sc->sc_machine_type) { case ENVMON_MACHINE_U25: case ENVMON_MACHINE_U45: sc->sc_temp[0].wmax = ENVMON_PIC_WMAX_TEMP; break; case ENVMON_MACHINE_V215: case ENVMON_MACHINE_V245: sc->sc_temp[0].wmax = ENVMON_EPC_WMAX_TEMP; break; } else sc->sc_temp[edata->sensor].wmax = limits->sel_warnmax; } if (limits == NULL || *props & PROP_WARNMIN) { if (limits == NULL) /* Restore defaults */ switch (sc->sc_machine_type) { case ENVMON_MACHINE_U25: case ENVMON_MACHINE_U45: sc->sc_temp[0].wmin = ENVMON_PIC_WMIN_TEMP; break; case ENVMON_MACHINE_V215: case ENVMON_MACHINE_V245: sc->sc_temp[0].wmin = ENVMON_EPC_WMIN_TEMP; break; } else sc->sc_temp[edata->sensor].wmin = limits->sel_warnmin; } } int envmon_epic_get_led(void *cookie) { struct envmon_sc_led *l = cookie; struct envmon_softc *sc = l->cookie; uint8_t val; envmon_write(sc, ENVMON_ADDR, l->reg); val = envmon_read(sc, ENVMON_DATA); return ((val & l->v_on) == l->v_on); } void envmon_epic_set_led(void *cookie, int val) { struct envmon_sc_led *l = cookie; struct envmon_softc *sc = l->cookie; uint8_t oldval, newval; envmon_write(sc, ENVMON_ADDR, l->reg); oldval = envmon_read(sc, ENVMON_DATA); newval = oldval & ~(l->v_on); newval |= val ? l->v_on : 0x0; if (newval != oldval) { envmon_write(sc, ENVMON_EPC_LED_MASK, l->v_on); envmon_write(sc, ENVMON_ADDR, l->reg); delay(10000); envmon_write(sc, ENVMON_DATA, newval); } } #ifdef ENVMON_DEBUG static void envmon_timeout(void *v) { struct envmon_softc *sc = v; uint8_t reg, val; for (reg = 0; reg < ENVMON_MAX_REG; reg++) { envmon_write(sc, ENVMON_ADDR, reg); val = envmon_read(sc, ENVMON_DATA); if (val != sc->sc_reg[reg]) { printf("%s: reg 0x%02x: 0x%02x > 0x%02x\n", device_xname(sc->sc_dev), reg, sc->sc_reg[reg], val); sc->sc_reg[reg] = val; } } callout_reset(&sc->sc_timer, hz * ENVMON_TIMER, envmon_timeout, sc); } #endif