I think that these sysctl should not be writable unless securelevel is <=0..
On 2009/05/08 17:59, Constantine A. Murenin wrote:
> Dear tech@,
>
> It is my great pleasure to announce a patch that allows interested users
> to monitor and control the speed of the fans connected to some popular
> Winbond Super I/O Hardware Monitors.
>
> The patch below supports the following chips, as shown by their dmesg name:
>
> * W83627HF (chip only provides the manual PWM mode, fully supported)
> * W83627THF / W83637HF (manual and thermal cruise modes are supported)
> * W83627EHF / W83627DHG (manual and thermal cruise, PWM/DC supported)
>
> The list above identifies 3 families, with the latter family having
> the most functionality.
>
> I will thus describe the functionality of the latter family, W83627EHF and
> W83627DHG, some parts of which will not be applicable to earlier families.
>
> The percent{0,1,2,3} sensors provide a summary of what the current
> settings of the chip are. The value shows the current duty cycle,
> whereas the description specifies whether the PWM or the DC mode is
> currently activated, and what kind of controlling is being done:
> Manual, Thermal Cruise, Fan Speed Cruise or Smart Fan III.
>
> If you change any of the percent{0,1,2,3} sensors (integer values only),
> the chip will automatically go from whatever mode on that specific fan
> output to the Manual mode, with the duty cycle set to the value that
> you specify.
>
> If you want to go into the Thermal Cruise mode, simply set the value of
> one of the temp sensors that have a "Target" in their description to the
> target temperature that you desire. In Thermal Cruise mode, you could
> also modify the Start-up and Stop duty cycle of the fan, and, of course,
> the target temperature tolerance.
>
> PWM/DC mode setting is done by switching the indicators between 0 and 1.
> The description of the indicator indicates which mode is currently active
> for which fan. If your fan doesn't seem to stop at all with one mode,
> try the other.
>
> I'd like to warn users that many motherboards are terribly miswired
> as far as fan-controlling is concerned, so please don't be surprised
> if the controlling doesn't seem to affect the speed of the fans, or
> if one control affects the speed of multiple fans etc.
>
>
> *** WARNING: ***
>
> The patch doesn't make any unconditional modifications to the behaviour
> of the chip, unless you specifically alter one of the modifiable sysctl
> values. Please, keep in mind, that altering these values is easy, and
> they affect a major safety harbour of your computer, so it is strongly
> advised that you ensure you have appropriate watch over the computer
> with which you are playing before leaving it unattended, if at all.
> Consider that fans need to run at higher speeds during higher workload,
> so be specifically careful if playing with the Manual mode.
>
> ** NOONE BUT YOU WILL BE RESPONSIBLE IF YOU ABUSE THE PATCH! **
>
> Of course, noone knows if the patch doesn't contain any bugs, or if
> it is not going to trigger some weird system/bios/acpi bugs and cause
> a malfunction or a fire, so use at your own risk. I do. :)
>
>
> Anyhow, to make the longer story short, here is the output from a
> W83627DHG chip on an Intel D201GLY2 box with one small system fan:
>
> % dmesg | fgrep W83627DHG
> wbsio0 at isa0 port 0x4e/2: W83627DHG rev 0x25
> lm1 at wbsio0 port 0x290/8: W83627DHG
>
> % sysctl hw.sensors
> hw.sensors.cpu0.temp0=58.00 degC
> hw.sensors.lm1.temp0=45.00 degC (Sys)
> hw.sensors.lm1.temp1=51.00 degC (CPU)
> hw.sensors.lm1.temp2=14.50 degC (Aux)
> hw.sensors.lm1.temp3=38.00 degC (Sys Target)
> hw.sensors.lm1.temp4=unknown (CPU Target)
> hw.sensors.lm1.temp5=unknown (Aux Target)
> hw.sensors.lm1.temp6=unknown (CPU Target)
> hw.sensors.lm1.temp7=2.00 degC (Sys Tolerance)
> hw.sensors.lm1.temp8=unknown (CPU Tolerance)
> hw.sensors.lm1.temp9=unknown (Aux Tolerance)
> hw.sensors.lm1.temp10=unknown (CPU Tolerance)
> hw.sensors.lm1.fan0=1854 RPM (Sys)
> hw.sensors.lm1.volt0=1.34 VDC (VCore)
> hw.sensors.lm1.volt1=12.20 VDC (+12V)
> hw.sensors.lm1.volt2=3.33 VDC (+3.3V)
> hw.sensors.lm1.volt3=3.33 VDC (+3.3V)
> hw.sensors.lm1.volt4=-3.95 VDC (-12V)
> hw.sensors.lm1.volt5=0.11 VDC
> hw.sensors.lm1.volt6=1.62 VDC
> hw.sensors.lm1.volt7=3.28 VDC (3.3VSB)
> hw.sensors.lm1.volt8=0.03 VDC (VBAT)
> hw.sensors.lm1.indicator0=Off (Sys Fan PWM/DC: PWM)
> hw.sensors.lm1.indicator1=Off (CPU Fan PWM/DC: PWM)
> hw.sensors.lm1.indicator2=Off (Aux Fan PWM/DC: PWM)
> hw.sensors.lm1.indicator3=On (CPU Fan PWM/DC: DC)
> hw.sensors.lm1.percent0=100.00% (Sys Fan PWM Thermal), OK
> hw.sensors.lm1.percent1=100.00% (CPU Fan PWM Manual), OK
> hw.sensors.lm1.percent2=100.00% (Aux Fan PWM Manual), OK
> hw.sensors.lm1.percent3=100.00% (CPU Fan DC SmartIII), OK
> hw.sensors.lm1.percent4=0.39% (Sys Fan Start-up Value), CRITICAL
> hw.sensors.lm1.percent5=unknown (CPU Fan Start-up Value)
> hw.sensors.lm1.percent6=unknown (Aux Fan Start-up Value)
> hw.sensors.lm1.percent7=unknown (CPU Fan Start-up Value)
> hw.sensors.lm1.percent8=29.41% (Sys Fan Stop Value), CRITICAL
> hw.sensors.lm1.percent9=unknown (CPU Fan Stop Value)
> hw.sensors.lm1.percent10=unknown (Aux Fan Stop Value)
> hw.sensors.lm1.percent11=unknown (CPU Fan Stop Value)
>
> (Values that are not applicable to the current operational mode
> are marked as 'unknown' in sysctl.)
>
>
> Here we alter the target temperature value for the Thermal Cruise mode:
>
> % sudo sysctl hw.sensors.lm1.temp3=50
> hw.sensors.lm1.temp3=38.00 degC {updating} (Sys Target)
>
>
> We now see that the percent0 value went down:
>
> % sysctl hw.sensors | fgrep Sys
> hw.sensors.lm1.temp0=45.00 degC (Sys)
> hw.sensors.lm1.temp3=50.00 degC (Sys Target)
> hw.sensors.lm1.temp7=2.00 degC (Sys Tolerance)
> hw.sensors.lm1.fan0=1739 RPM (Sys)
> hw.sensors.lm1.indicator0=Off (Sys Fan PWM/DC: PWM)
> hw.sensors.lm1.percent0=29.41% (Sys Fan PWM Thermal), CRITICAL
> hw.sensors.lm1.percent4=0.39% (Sys Fan Start-up Value), CRITICAL
> hw.sensors.lm1.percent8=29.41% (Sys Fan Stop Value), CRITICAL
>
>
> This D201GLY2 board is kinda weird, because the fan doesn't stop much
> until the duty cycle is almost zero. (Or, perhaps, the issue lies with
> the fan of the enclosure itself.) So don't try this on other boards;
> the status field indicates the likelihood that the fan is not going
> to run on a given voltage.
>
> % sudo sysctl hw.sensors.lm1.percent8=10
> hw.sensors.lm1.percent8=29.41% {updating} (Sys Fan Stop Value), CRITICAL
>
> % sysctl hw.sensors | fgrep Sys
> hw.sensors.lm1.temp0=45.00 degC (Sys)
> hw.sensors.lm1.temp3=50.00 degC (Sys Target)
> hw.sensors.lm1.temp7=2.00 degC (Sys Tolerance)
> hw.sensors.lm1.fan0=1240 RPM (Sys)
> hw.sensors.lm1.indicator0=Off (Sys Fan PWM/DC: PWM)
> hw.sensors.lm1.percent0=9.80% (Sys Fan PWM Thermal), CRITICAL
> hw.sensors.lm1.percent4=0.39% (Sys Fan Start-up Value), CRITICAL
> hw.sensors.lm1.percent8=9.80% (Sys Fan Stop Value), CRITICAL
>
>
> Now let's go into the Manual mode:
>
> % sudo sysctl hw.sensors.lm1.percent0=6
> hw.sensors.lm1.percent0=9.80% {updating} (Sys Fan PWM Thermal), CRITICAL
>
> % sysctl hw.sensors | fgrep Sys
> hw.sensors.lm1.temp0=45.00 degC (Sys)
> hw.sensors.lm1.temp3=unknown (Sys Target)
> hw.sensors.lm1.temp7=unknown (Sys Tolerance)
> hw.sensors.lm1.fan0=1240 RPM (Sys)
> hw.sensors.lm1.indicator0=Off (Sys Fan PWM/DC: PWM)
> hw.sensors.lm1.percent0=9.80% (Sys Fan PWM Manual), CRITICAL
> hw.sensors.lm1.percent4=unknown (Sys Fan Start-up Value)
> hw.sensors.lm1.percent8=unknown (Sys Fan Stop Value)
>
> % sysctl hw.sensors | fgrep Sys
> hw.sensors.lm1.temp0=45.00 degC (Sys)
> hw.sensors.lm1.temp3=unknown (Sys Target)
> hw.sensors.lm1.temp7=unknown (Sys Tolerance)
> hw.sensors.lm1.fan0=781 RPM (Sys)
> hw.sensors.lm1.indicator0=Off (Sys Fan PWM/DC: PWM)
> hw.sensors.lm1.percent0=5.88% (Sys Fan PWM Manual), CRITICAL
> hw.sensors.lm1.percent4=unknown (Sys Fan Start-up Value)
> hw.sensors.lm1.percent8=unknown (Sys Fan Stop Value)
>
> (Note that the description of the percent0 sensor changed to indicate
> that the Manual mode is now active, and that the value goes gradually
> towards the desired value over some period of time.)
>
>
> Note that the driver only implements reading and writing to the registers,
> e.g. the Thermal Cruise and other modes are still performed by the chip
> itself. Fan Cruise mode and the Smart Fan III modes are not supported,
> although you can still monitor their effects via the percent{0,1,2,3}
> sensors.
>
> Etc.
>
>
> Comments and test reports are welcome. If you like this stuff,
> make sure to come by tomorrow for my BSDCan 2009 talk on
> Quiet Computing with BSD. :) The talk will, of course, have
> a bit more details on the subject.
>
> Best regards,
> Constantine.SU.
>
> P.S. The patch applies cleanly to OpenBSD 4.3, 4.4, 4.5 and 4.5-current.
>
>
>
> Index: sys/sys/sensors.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/sensors.h,v
> retrieving revision 1.24
> diff -u -d -p -8 -r1.24 sensors.h
> --- sys/sys/sensors.h 24 Jun 2007 05:34:35 -0000 1.24
> +++ sys/sys/sensors.h 8 May 2009 18:47:07 -0000
> @@ -96,18 +96,28 @@ enum sensor_status {
> struct sensor {
> char desc[32]; /* sensor description, may be empty */
> struct timeval tv; /* sensor value last change time */
> int64_t value; /* current value */
> enum sensor_type type; /* sensor type */
> enum sensor_status status; /* sensor status */
> int numt; /* sensor number of .type type */
> int flags; /* sensor flags */
> + /*int64_t upvalue;*/ /* new value */
> + /*
> + * The upvalue is commented out from the userland structure
> + * to avoid increasing sizeof(struct sensor), such as to
> + * preserve the ABI of C/C++ sysctl(3) HW_SENSORS users,
> + * since otherwise recompilation of all sensor tools would
> + * have been required to avoid [ENOMEM] from sysctl(3).
> + */
> #define SENSOR_FINVALID 0x0001 /* sensor is invalid */
> #define SENSOR_FUNKNOWN 0x0002 /* sensor value is unknown */
> +#define SENSOR_FCONTROLLABLE 0x0004 /* sensor value could be altered */
> +#define SENSOR_FNEWVALUE 0x0008 /* upvalue contains update inf. */
> };
>
> /* Sensor device data:
> * New fields should be added at the end to encourage backwards compat
> */
> struct sensordev {
> int num; /* sensordev number */
> char xname[16]; /* unix device name */
> @@ -124,16 +134,17 @@ struct ksensor {
> SLIST_ENTRY(ksensor) list; /* device-scope list */
> char desc[32]; /* sensor description, may be empty */
> struct timeval tv; /* sensor value last change time */
> int64_t value; /* current value */
> enum sensor_type type; /* sensor type */
> enum sensor_status status; /* sensor status */
> int numt; /* sensor number of .type type */
> int flags; /* sensor flags, ie. SENSOR_FINVALID */
> + int64_t upvalue; /* new value */
> };
> SLIST_HEAD(ksensors_head, ksensor);
>
> /* Sensor device data */
> struct ksensordev {
> SLIST_ENTRY(ksensordev) list;
> int num; /* sensordev number */
> char xname[16]; /* unix device name */
> Index: sys/kern/kern_sysctl.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
> retrieving revision 1.168
> diff -u -d -p -8 -r1.168 kern_sysctl.c
> --- sys/kern/kern_sysctl.c 21 Jan 2009 21:02:40 -0000 1.168
> +++ sys/kern/kern_sysctl.c 8 May 2009 18:47:08 -0000
> @@ -1825,27 +1825,37 @@ sysctl_sensors(int *name, u_int namelen,
>
> type = name[1];
> numt = name[2];
>
> ks = sensor_find(dev, type, numt);
> if (ks == NULL)
> return (ENOENT);
>
> + if (newp && newlen != sizeof(int))
> + return (EINVAL);
> + if (newp && !(ks->flags & SENSOR_FCONTROLLABLE))
> + return (EPERM);
> + if (newp) {
> + ks->upvalue = *(int*)newp;
> + ks->flags |= SENSOR_FNEWVALUE;
> + }
> +
> /* Grab a copy, to clear the kernel pointers */
> us = malloc(sizeof(*us), M_TEMP, M_WAITOK|M_ZERO);
> memcpy(us->desc, ks->desc, sizeof(us->desc));
> us->tv = ks->tv;
> us->value = ks->value;
> us->type = ks->type;
> us->status = ks->status;
> us->numt = ks->numt;
> us->flags = ks->flags;
> + /*us->upvalue = ks->upvalue;*/
>
> - ret = sysctl_rdstruct(oldp, oldlenp, newp, us,
> + ret = sysctl_rdstruct(oldp, oldlenp, NULL, us,
> sizeof(struct sensor));
> free(us, M_TEMP);
> return (ret);
> }
>
> int
> sysctl_emul(int *name, u_int namelen, void *oldp, size_t *oldlenp,
> void *newp, size_t newlen)
> Index: sbin/sysctl/sysctl.c
> ===================================================================
> RCS file: /cvs/src/sbin/sysctl/sysctl.c,v
> retrieving revision 1.160
> diff -u -d -p -8 -r1.160 sysctl.c
> --- sbin/sysctl/sysctl.c 4 Aug 2008 04:26:42 -0000 1.160
> +++ sbin/sysctl/sysctl.c 8 May 2009 18:47:09 -0000
> @@ -465,16 +465,19 @@ parse(char *string, int flags)
> warnx("use vmstat to view %s information",
> string);
> return;
> case HW_SENSORS:
> special |= SENSORS;
> len = sysctl_sensors(string, &bufp, mib, flags, &type);
> if (len < 0)
> return;
> + if (newsize > 0)
> + /* XXX: make this more intelligent */
> + type = CTLTYPE_INT;
> break;
> case HW_PHYSMEM:
> case HW_USERMEM:
> /*
> * Don't print these; we'll print the 64-bit
> * variants instead.
> */
> return;
> @@ -2412,16 +2415,19 @@ print_sensor(struct sensor *s)
> break;
> case SENSOR_TIMEDELTA:
> printf("%.6f secs", s->value / 1000000000.0);
> break;
> default:
> printf("unknown");
> }
> }
> +
> + if (s->flags & SENSOR_FNEWVALUE)
> + printf(" {updating}");
>
> if (s->desc[0] != '\0')
> printf(" (%s)", s->desc);
>
> switch (s->status) {
> case SENSOR_S_UNSPEC:
> break;
> case SENSOR_S_OK:
> Index: sys/dev/ic/lm78var.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/lm78var.h,v
> retrieving revision 1.14
> diff -u -d -p -8 -r1.14 lm78var.h
> --- sys/dev/ic/lm78var.h 25 Jun 2007 22:50:18 -0000 1.14
> +++ sys/dev/ic/lm78var.h 8 May 2009 18:47:09 -0000
> @@ -118,17 +118,17 @@
>
> /* Config bits */
> #define WB_CONFIG_VMR9 0x01
>
> /* Reference voltage (mV) */
> #define WB_VREF 3600
> #define WB_W83627EHF_VREF 2048
>
> -#define WB_MAX_SENSORS 19
> +#define WB_MAX_SENSORS 96
>
> struct lm_softc;
>
> struct lm_sensor {
> char *desc;
> enum sensor_type type;
> u_int8_t bank;
> u_int8_t reg;
> Index: sys/dev/ic/lm78.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/ic/lm78.c,v
> retrieving revision 1.20
> diff -u -d -p -8 -r1.20 lm78.c
> --- sys/dev/ic/lm78.c 25 Jun 2007 22:50:18 -0000 1.20
> +++ sys/dev/ic/lm78.c 8 May 2009 18:47:10 -0000
> @@ -1,12 +1,13 @@
> /* $OpenBSD: lm78.c,v 1.20 2007/06/25 22:50:18 cnst Exp $ */
>
> /*
> * Copyright (c) 2005, 2006 Mark Kettenis
> + * Copyright (c) 2006, 2009 Constantine A. Murenin <cnst>
> *
> * Permission to use, copy, modify, and distribute this software for any
> * purpose with or without fee is hereby granted, provided that the above
> * copyright notice and this permission notice appear in all copies.
> *
> * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> @@ -21,16 +22,20 @@
> #include <sys/device.h>
> #include <sys/kernel.h>
> #include <sys/queue.h>
> #include <sys/sensors.h>
> #include <machine/bus.h>
>
> #include <dev/ic/lm78var.h>
>
> +//#define LMFANCTLRAW
> +#define LMFANDUTYHINTS
> +/* or use `rm lm78.o; env DEBUG="-DLMFANCTLRAW -DLMFANDUTYHINTS" make
> lm78.o` */
> +
> #if defined(LMDEBUG)
> #define DPRINTF(x) do { printf x; } while (0)
> #else
> #define DPRINTF(x)
> #endif
>
> /*
> * LM78-compatible chips can typically measure voltages up to 4.096 V.
> @@ -55,16 +60,24 @@ void lm_setup_sensors(struct lm_softc *,
> void lm_refresh(void *);
>
> void lm_refresh_sensor_data(struct lm_softc *);
> void lm_refresh_volt(struct lm_softc *, int);
> void lm_refresh_temp(struct lm_softc *, int);
> void lm_refresh_fanrpm(struct lm_softc *, int);
>
> void wb_refresh_sensor_data(struct lm_softc *);
> +void wb_refresh_raw_rw(struct lm_softc *, int);
> +void w83627hf_refresh_pwm_rw(struct lm_softc *, int);
> +void w83627ehf_refresh_fanvolt_rw(struct lm_softc *, int);
> +void w83627ehf_refresh_fanvolt_thermal_rw(struct lm_softc *, int);
> +void w83627ehf_refresh_indicator_rw(struct lm_softc *, int);
> +void w83627ehf_refresh_temptarget_rw(struct lm_softc *, int);
> +void w83627ehf_refresh_temptargettol_rw(struct lm_softc *, int);
> +void w83627thf_refresh_fanvolt_rw(struct lm_softc *, int);
> void wb_w83637hf_refresh_vcore(struct lm_softc *, int);
> void wb_refresh_nvolt(struct lm_softc *, int);
> void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int);
> void wb_refresh_temp(struct lm_softc *, int);
> void wb_refresh_fanrpm(struct lm_softc *, int);
> void wb_w83792d_refresh_fanrpm(struct lm_softc *, int);
>
> void as_refresh_temp(struct lm_softc *, int);
> @@ -95,17 +108,23 @@ struct lm_sensor lm78_sensors[] = {
> /* Fans */
> { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm },
> { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm },
> { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm },
>
> { NULL }
> };
>
> +
> struct lm_sensor w83627hf_sensors[] = {
> + /* The W83627HG only support the manual PWM fan speed control. */
> + { "PWM", SENSOR_PERCENT, 0, 0x5a, w83627hf_refresh_pwm_rw },
> + { "PWM", SENSOR_PERCENT, 0, 0x5b, w83627hf_refresh_pwm_rw },
> + { "PWM 0/1 Clock Freq", SENSOR_INTEGER, 0, 0x5c, wb_refresh_raw_rw },
> +
> /* Voltage */
> { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
> { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE },
> { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
> { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
> { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
> { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
> { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
> @@ -128,93 +147,342 @@ struct lm_sensor w83627hf_sensors[] = {
> /*
> * The W83627EHF can measure voltages up to 2.048 V instead of the
> * traditional 4.096 V. For measuring positive voltages, this can be
> * accounted for by halving the resistor factor. Negative voltages
> * need special treatment, also because the reference voltage is 2.048 V
> * instead of the traditional 3.6 V.
> */
> struct lm_sensor w83627ehf_sensors[] = {
> + /* Controlling parts: Duty Cycle */
> + { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01,
> w83627ehf_refresh_fanvolt_rw },
> + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03,
> w83627ehf_refresh_fanvolt_rw },
> + { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11,
> w83627ehf_refresh_fanvolt_rw },
> + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x61,
> w83627ehf_refresh_fanvolt_rw },
> + /* Start-up Values */
> + { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x65,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + /* Stop Values */
> + { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> + { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x64,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> +
> + /* Controlling parts: PWM/DC */
> + { "Sys Fan Volt Control", SENSOR_INDICATOR, 0, 0x01,
> w83627ehf_refresh_indicator_rw },
> + { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x03,
> w83627ehf_refresh_indicator_rw },
> + { "Aux Fan Volt Control", SENSOR_INDICATOR, 0, 0x11,
> w83627ehf_refresh_indicator_rw },
> + { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x61,
> w83627ehf_refresh_indicator_rw },
> +
> +#ifdef LMFANCTLRAW
> + /* Smart Fan Configuration Registers, 00h--1Fh */
> + { "0x00: SysFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x00,
> wb_refresh_raw_rw },
> + { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw },
> + { "0x02: CPUFanOut0 PWM Output Freq", SENSOR_INTEGER, 0, 0x02,
> wb_refresh_raw_rw },
> + { "0x03: CPUFanOut0", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw },
> + { "0x04: Fan Configuration Reg I", SENSOR_INTEGER, 0, 0x04,
> wb_refresh_raw_rw },
> + { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05,
> wb_refresh_raw_rw },
> + { "0x06: CPU Target Temp/RPM0", SENSOR_INTEGER, 0, 0x06,
> wb_refresh_raw_rw },
> + { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07,
> wb_refresh_raw_rw },
> + { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08,
> wb_refresh_raw_rw },
> + { "0x09: CPUFanOut0 Stop Value", SENSOR_INTEGER, 0, 0x09,
> wb_refresh_raw_rw },
> + { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a,
> wb_refresh_raw_rw },
> + { "0x0b: CPUFanOut0 Start-up Value", SENSOR_INTEGER, 0, 0x0b,
> wb_refresh_raw_rw },
> + { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c,
> wb_refresh_raw_rw },
> + { "0x0d: CPUFanOut0 Stop Time", SENSOR_INTEGER, 0, 0x0d,
> wb_refresh_raw_rw },
> + { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e,
> wb_refresh_raw_rw },
> + { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f,
> wb_refresh_raw_rw },
> + { "0x10: AuxFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x10,
> wb_refresh_raw_rw },
> + { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw },
> + { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12,
> wb_refresh_raw_rw },
> + { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13,
> wb_refresh_raw_rw },
> + { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14,
> wb_refresh_raw_rw },
> + { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15,
> wb_refresh_raw_rw },
> + { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16,
> wb_refresh_raw_rw },
> + { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17,
> wb_refresh_raw_rw },
> + { "0x18: OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw },
> + { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw },
> + { "0x1a: reserved", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw },
> + { "0x1b: reserved", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw },
> + { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw },
> + { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw },
> + { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw },
> + { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw },
> +
> + { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw
> },
> + { "0x4a: CPUFanOut1 Temp Source Select", SENSOR_INTEGER, 0, 0x4a,
> wb_refresh_raw_rw },
> + { "0x4b: Fan Divisor Reg II", SENSOR_INTEGER, 0, 0x4b,
> wb_refresh_raw_rw },
> + { "0x59: Diode Selection", SENSOR_INTEGER, 0, 0x59, wb_refresh_raw_rw },
> + { "0x5d: VBat Monitor Control", SENSOR_INTEGER, 0, 0x5d,
> wb_refresh_raw_rw },
> +
> + { "0x60: CPUFanOut1 PWM Output Freq", SENSOR_INTEGER, 0, 0x60,
> wb_refresh_raw_rw },
> + { "0x61: CPUFanOut1", SENSOR_INTEGER, 0, 0x61, wb_refresh_raw_rw },
> + { "0x62: Fan Configuration Reg III", SENSOR_INTEGER, 0, 0x62,
> wb_refresh_raw_rw },
> + { "0x63: CPU Target Temp/RPM1", SENSOR_INTEGER, 0, 0x63,
> wb_refresh_raw_rw },
> + { "0x64: CPUFanOut1 Stop Value", SENSOR_INTEGER, 0, 0x64,
> wb_refresh_raw_rw },
> + { "0x65: CPUFanOut1 Start-up Value", SENSOR_INTEGER, 0, 0x65,
> wb_refresh_raw_rw },
> + { "0x66: CPUFanOut1 Stop Time", SENSOR_INTEGER, 0, 0x66,
> wb_refresh_raw_rw },
> + { "0x67: CPUFanOut0 Max Output Value", SENSOR_INTEGER, 0, 0x67,
> wb_refresh_raw_rw },
> + { "0x68: CPUFanOut0 Output Step Value", SENSOR_INTEGER, 0, 0x68,
> wb_refresh_raw_rw },
> + { "0x69: CPUFanOut1 Max Output Value", SENSOR_INTEGER, 0, 0x69,
> wb_refresh_raw_rw },
> + { "0x6a: CPUFanOut1 Output Step Value", SENSOR_INTEGER, 0, 0x6a,
> wb_refresh_raw_rw },
> +#endif /* LMFANCTLRAW */
> +
> /* Voltage */
> { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
> { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2
> },
> { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2
> },
> { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2
> },
> { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
> { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
> { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
> { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) /
> 2 },
> { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
> { "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 },
>
> /* Temperature */
> - { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
> - { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
> - { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
> + { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
> + { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
> + { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
> +
> + /* search for Relative Registers in the datasheet for a nice table */
> + /* Controlling parts: Target Temperature */
> + { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw },
> + { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw },
> + { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw },
> + { "CPU Target", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptarget_rw },
> + /* Controlling parts: Target Temperature Tolerance */
> + { "Sys Tolerance", SENSOR_TEMP, 0, 0x05,
> w83627ehf_refresh_temptargettol_rw },
> + { "CPU Tolerance", SENSOR_TEMP, 0, 0x06,
> w83627ehf_refresh_temptargettol_rw },
> + { "Aux Tolerance", SENSOR_TEMP, 0, 0x13,
> w83627ehf_refresh_temptargettol_rw },
> + { "CPU Tolerance", SENSOR_TEMP, 0, 0x63,
> w83627ehf_refresh_temptargettol_rw },
>
> /* Fans */
> - { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
> - { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
> - { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
> + { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
> + { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
> + { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
> +/* { "CPU", SENSOR_FANRPM, 0, 0x3f, w83627ehf_refresh_fanrpm },
> + { "Aux", SENSOR_FANRPM, 0, 0x53, w83627ehf_refresh_fanrpm },*/
>
> { NULL }
> };
>
> /*
> * w83627dhg is almost identical to w83627ehf, except that
> * it has 9 instead of 10 voltage sensors
> */
> struct lm_sensor w83627dhg_sensors[] = {
> + /* Controlling parts: Duty Cycle */
> + { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01,
> w83627ehf_refresh_fanvolt_rw },
> + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03,
> w83627ehf_refresh_fanvolt_rw },
> + { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11,
> w83627ehf_refresh_fanvolt_rw },
> + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x61,
> w83627ehf_refresh_fanvolt_rw },
> + /* Start-up Values */
> + { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x65,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + /* Stop Values */
> + { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> + { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x64,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> +
> + /* Controlling parts: PWM/DC */
> + { "Sys Fan Volt Control", SENSOR_INDICATOR, 0, 0x01,
> w83627ehf_refresh_indicator_rw },
> + { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x03,
> w83627ehf_refresh_indicator_rw },
> + { "Aux Fan Volt Control", SENSOR_INDICATOR, 0, 0x11,
> w83627ehf_refresh_indicator_rw },
> + { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x61,
> w83627ehf_refresh_indicator_rw },
> +
> +#ifdef LMFANCTLRAW
> + /* Smart Fan Configuration Registers, 00h--1Fh */
> + { "0x00: SysFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x00,
> wb_refresh_raw_rw },
> + { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw },
> + { "0x02: CPUFanOut0 PWM Output Freq", SENSOR_INTEGER, 0, 0x02,
> wb_refresh_raw_rw },
> + { "0x03: CPUFanOut0", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw },
> + { "0x04: Fan Configuration Reg I", SENSOR_INTEGER, 0, 0x04,
> wb_refresh_raw_rw },
> + { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05,
> wb_refresh_raw_rw },
> + { "0x06: CPU Target Temp/RPM0", SENSOR_INTEGER, 0, 0x06,
> wb_refresh_raw_rw },
> + { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07,
> wb_refresh_raw_rw },
> + { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08,
> wb_refresh_raw_rw },
> + { "0x09: CPUFanOut0 Stop Value", SENSOR_INTEGER, 0, 0x09,
> wb_refresh_raw_rw },
> + { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a,
> wb_refresh_raw_rw },
> + { "0x0b: CPUFanOut0 Start-up Value", SENSOR_INTEGER, 0, 0x0b,
> wb_refresh_raw_rw },
> + { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c,
> wb_refresh_raw_rw },
> + { "0x0d: CPUFanOut0 Stop Time", SENSOR_INTEGER, 0, 0x0d,
> wb_refresh_raw_rw },
> + { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e,
> wb_refresh_raw_rw },
> + { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f,
> wb_refresh_raw_rw },
> + { "0x10: AuxFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x10,
> wb_refresh_raw_rw },
> + { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw },
> + { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12,
> wb_refresh_raw_rw },
> + { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13,
> wb_refresh_raw_rw },
> + { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14,
> wb_refresh_raw_rw },
> + { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15,
> wb_refresh_raw_rw },
> + { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16,
> wb_refresh_raw_rw },
> + { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17,
> wb_refresh_raw_rw },
> + { "0x18: OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw },
> + { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw },
> + { "0x1a: reserved", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw },
> + { "0x1b: reserved", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw },
> + { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw },
> + { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw },
> + { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw },
> + { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw },
> +
> + { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw
> },
> + { "0x49: CPUFanOut0/Aux Temp Source Select", SENSOR_INTEGER, 0, 0x49,
> wb_refresh_raw_rw }, /*dhg only, not on ehf*/
> + { "0x4a: CPUFanOut1 Temp Source Select", SENSOR_INTEGER, 0, 0x4a,
> wb_refresh_raw_rw },
> + { "0x4b: Fan Divisor Reg II", SENSOR_INTEGER, 0, 0x4b,
> wb_refresh_raw_rw },
> + { "0x59: Diode Selection", SENSOR_INTEGER, 0, 0x59, wb_refresh_raw_rw },
> + { "0x5d: VBat Monitor Control", SENSOR_INTEGER, 0, 0x5d,
> wb_refresh_raw_rw },
> +
> + { "0x60: CPUFanOut1 PWM Output Freq", SENSOR_INTEGER, 0, 0x60,
> wb_refresh_raw_rw },
> + { "0x61: CPUFanOut1", SENSOR_INTEGER, 0, 0x61, wb_refresh_raw_rw },
> + { "0x62: Fan Configuration Reg III", SENSOR_INTEGER, 0, 0x62,
> wb_refresh_raw_rw },
> + { "0x63: CPU Target Temp/RPM1", SENSOR_INTEGER, 0, 0x63,
> wb_refresh_raw_rw },
> + { "0x64: CPUFanOut1 Stop Value", SENSOR_INTEGER, 0, 0x64,
> wb_refresh_raw_rw },
> + { "0x65: CPUFanOut1 Start-up Value", SENSOR_INTEGER, 0, 0x65,
> wb_refresh_raw_rw },
> + { "0x66: CPUFanOut1 Stop Time", SENSOR_INTEGER, 0, 0x66,
> wb_refresh_raw_rw },
> + { "0x67: CPUFanOut0 Max Output Value", SENSOR_INTEGER, 0, 0x67,
> wb_refresh_raw_rw },
> + { "0x68: CPUFanOut0 Output Step Value", SENSOR_INTEGER, 0, 0x68,
> wb_refresh_raw_rw },
> + { "0x69: CPUFanOut1 Max Output Value", SENSOR_INTEGER, 0, 0x69,
> wb_refresh_raw_rw },
> + { "0x6a: CPUFanOut1 Output Step Value", SENSOR_INTEGER, 0, 0x6a,
> wb_refresh_raw_rw },
> +#endif /* LMFANCTLRAW */
> +
> /* Voltage */
> { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2},
> { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2
> },
> { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2
> },
> { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2
> },
> { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt },
> { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 },
> { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 },
> { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) /
> 2 },
> { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 },
>
> /* Temperature */
> - { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
> - { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
> - { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
> + { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
> + { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
> + { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
> +
> + /* search for Relative Registers in the datasheet for a nice table */
> + /* Controlling parts: Target Temperature */
> + { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw },
> + { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw },
> + { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw },
> + { "CPU Target", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptarget_rw },
> + /* Controlling parts: Target Temperature Tolerance */
> + { "Sys Tolerance", SENSOR_TEMP, 0, 0x05,
> w83627ehf_refresh_temptargettol_rw },
> + { "CPU Tolerance", SENSOR_TEMP, 0, 0x06,
> w83627ehf_refresh_temptargettol_rw },
> + { "Aux Tolerance", SENSOR_TEMP, 0, 0x13,
> w83627ehf_refresh_temptargettol_rw },
> + { "CPU Tolerance", SENSOR_TEMP, 0, 0x63,
> w83627ehf_refresh_temptargettol_rw },
>
> /* Fans */
> - { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
> - { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
> - { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
> + { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
> + { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
> + { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
> +/* { "CPU", SENSOR_FANRPM, 0, 0x3f, w83627ehf_refresh_fanrpm },*/
>
> { NULL }
> };
>
> -struct lm_sensor w83637hf_sensors[] = {
> +struct lm_sensor w83627thf_sensors[] = {
> + /* Controlling parts: Duty Cycle */
> + { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01,
> w83627thf_refresh_fanvolt_rw },
> + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03,
> w83627thf_refresh_fanvolt_rw },
> + { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11,
> w83627thf_refresh_fanvolt_rw },
> + /* Start-up Values */
> + { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16,
> w83627ehf_refresh_fanvolt_thermal_rw, 0 },
> + /* Stop Values */
> + { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> + { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15,
> w83627ehf_refresh_fanvolt_thermal_rw, 1 },
> +
> +#ifdef LMFANCTLRAW
> + /* Smart Fan Configuration Registers, 00h--1Fh */
> + { "0x00: reserved", SENSOR_INTEGER, 0, 0x00, wb_refresh_raw_rw },
> + { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw },
> + { "0x02: reserved", SENSOR_INTEGER, 0, 0x02, wb_refresh_raw_rw },
> + { "0x03: CPUFanOut", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw },
> + { "0x04: Fan Conguration Reg I", SENSOR_INTEGER, 0, 0x04,
> wb_refresh_raw_rw },
> + { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05,
> wb_refresh_raw_rw },
> + { "0x06: CPU Target Temp/RPM", SENSOR_INTEGER, 0, 0x06,
> wb_refresh_raw_rw },
> + { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07,
> wb_refresh_raw_rw },
> + { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08,
> wb_refresh_raw_rw },
> + { "0x09: CPUFanOut Stop Value", SENSOR_INTEGER, 0, 0x09,
> wb_refresh_raw_rw },
> + { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a,
> wb_refresh_raw_rw },
> + { "0x0b: CPUFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0b,
> wb_refresh_raw_rw },
> + { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c,
> wb_refresh_raw_rw },
> + { "0x0d: CPUFanOut Stop Time", SENSOR_INTEGER, 0, 0x0d,
> wb_refresh_raw_rw },
> + { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e,
> wb_refresh_raw_rw },
> + { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f,
> wb_refresh_raw_rw },
> + { "0x10: reserved", SENSOR_INTEGER, 0, 0x10, wb_refresh_raw_rw },
> + { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw },
> + { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12,
> wb_refresh_raw_rw },
> + { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13,
> wb_refresh_raw_rw },
> + { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14,
> wb_refresh_raw_rw },
> + { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15,
> wb_refresh_raw_rw },
> + { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16,
> wb_refresh_raw_rw },
> + { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17,
> wb_refresh_raw_rw },
> + { "0x18: VRM and OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw },
> + { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw },
> + { "0x1a: user-defined", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw },
> + { "0x1b: user-defined", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw },
> + { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw },
> + { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw },
> + { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw },
> + { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw },
> +
> + { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw
> },
> +#endif /* LMFANCTLRAW */
> +
> /* Voltage */
> { "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore },
> { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) },
> { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
> { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) },
> { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) },
> { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) },
> { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE },
>
> /* Temperature */
> - { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
> - { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
> - { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
> + { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp },
> + { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp },
> + { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp },
> +
> + /* Controlling parts: Target Temperature */
> + { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw },
> + { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw },
> + { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw },
> + /* Controlling parts: Target Temperature Tolerance */
> + { "Sys Tolerance", SENSOR_TEMP, 0, 0x05,
> w83627ehf_refresh_temptargettol_rw },
> + { "CPU Tolerance", SENSOR_TEMP, 0, 0x06,
> w83627ehf_refresh_temptargettol_rw },
> + { "Aux Tolerance", SENSOR_TEMP, 0, 0x13,
> w83627ehf_refresh_temptargettol_rw },
>
> /* Fans */
> - { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
> - { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
> - { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
> + { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm },
> + { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm },
> + { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm },
>
> { NULL }
> };
>
> +/*
> + * With regard to fan control, W83697HF documentation appears to be
> + * contradictory, as section 6.4.2 "Fan speed control" suggests
> + * using CR5A and CR5B, like in W83627HG, for PWM duty cycle,
> + * whereas other sections define these registers differently,
> + * and suggest registers similar to the other chips that implement
> + * the Smart Fan control system.
> + * Support for fan-controlling with this chip might be added later.
> + */
> struct lm_sensor w83697hf_sensors[] = {
> /* Voltage */
> { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE },
> { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE },
> { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) },
> { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) },
> { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) },
> { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) },
> @@ -394,17 +662,17 @@ lm_attach(struct lm_softc *sc)
> for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++)
> if (lm_chips[i].chip_match(sc))
> break;
>
> /* No point in doing anything if we don't have any sensors. */
> if (sc->numsensors == 0)
> return;
>
> - sc->sensortask = sensor_task_register(sc, lm_refresh, 5);
> + sc->sensortask = sensor_task_register(sc, lm_refresh, 3);
> if (sc->sensortask == NULL) {
> printf("%s: unable to register update task\n",
> sc->sc_dev.dv_xname);
> return;
> }
>
> /* Start the monitoring loop */
> config = sc->lm_readreg(sc, LM_CONFIG);
> @@ -498,17 +766,21 @@ wb_match(struct lm_softc *sc)
> DPRINTF((" winbond chip id 0x%x\n", sc->chipid));
> switch(sc->chipid) {
> case WB_CHIPID_W83627HF:
> printf(": W83627HF\n");
> lm_setup_sensors(sc, w83627hf_sensors);
> break;
> case WB_CHIPID_W83627THF:
> printf(": W83627THF\n");
> - lm_setup_sensors(sc, w83637hf_sensors);
> + sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
> + if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
> + sc->vrm9 = 1;
> + sc->lm_writereg(sc, WB_BANKSEL, banksel);
> + lm_setup_sensors(sc, w83627thf_sensors);
> break;
> case WB_CHIPID_W83627EHF_A:
> printf(": W83627EHF-A\n");
> lm_setup_sensors(sc, w83627ehf_sensors);
> break;
> case WB_CHIPID_W83627EHF:
> printf(": W83627EHF\n");
> lm_setup_sensors(sc, w83627ehf_sensors);
> @@ -518,17 +790,17 @@ wb_match(struct lm_softc *sc)
> lm_setup_sensors(sc, w83627dhg_sensors);
> break;
> case WB_CHIPID_W83637HF:
> printf(": W83637HF\n");
> sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
> if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9)
> sc->vrm9 = 1;
> sc->lm_writereg(sc, WB_BANKSEL, banksel);
> - lm_setup_sensors(sc, w83637hf_sensors);
> + lm_setup_sensors(sc, w83627thf_sensors);
> break;
> case WB_CHIPID_W83697HF:
> printf(": W83697HF\n");
> lm_setup_sensors(sc, w83697hf_sensors);
> break;
> case WB_CHIPID_W83781D:
> case WB_CHIPID_W83781D_2:
> printf(": W83781D\n");
> @@ -584,16 +856,22 @@ lm_setup_sensors(struct lm_softc *sc, st
>
> strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
> sizeof(sc->sensordev.xname));
>
> for (i = 0; sensors[i].desc; i++) {
> sc->sensors[i].type = sensors[i].type;
> strlcpy(sc->sensors[i].desc, sensors[i].desc,
> sizeof(sc->sensors[i].desc));
> + if (sc->sensors[i].type == SENSOR_PERCENT ||
> + sc->sensors[i].type == SENSOR_INDICATOR ||
> + sc->sensors[i].type == SENSOR_INTEGER ||
> + (sc->sensors[i].type == SENSOR_TEMP &&
> + sc->sensors[i].desc[4] != '\0'))
> + sc->sensors[i].flags = SENSOR_FCONTROLLABLE;
> sc->numsensors++;
> }
> sc->lm_sensors = sensors;
> }
>
> void
> lm_refresh(void *arg)
> {
> @@ -690,16 +968,434 @@ wb_refresh_sensor_data(struct lm_softc *
> for (i = 0; i < sc->numsensors; i++) {
> if (bank != sc->lm_sensors[i].bank) {
> bank = sc->lm_sensors[i].bank;
> sc->lm_writereg(sc, WB_BANKSEL, bank);
> }
> sc->lm_sensors[i].refresh(sc, i);
> }
> sc->lm_writereg(sc, WB_BANKSEL, banksel);
> +}
> +
> +void
> +wb_refresh_raw_rw(struct lm_softc *sc, int n)
> +{
> + struct ksensor *sensor = &sc->sensors[n];
> + int nv, data;
> +
> + if (sensor->flags & SENSOR_FNEWVALUE) {
> + sensor->flags &= ~SENSOR_FNEWVALUE;
> + nv = sensor->upvalue;
> + if (nv >= 0x00 && nv <= 0xff)
> + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
> + }
> + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
> + sensor->value = data;
> +}
> +
> +void
> +w83627hf_refresh_pwm_rw(struct lm_softc *sc, int n)
> +{
> + struct ksensor *sensor = &sc->sensors[n];
> + int nv, data;
> +
> + if (sensor->flags & SENSOR_FNEWVALUE) {
> + sensor->flags &= ~SENSOR_FNEWVALUE;
> + nv = sensor->upvalue;
> + if (nv < 0 || nv > 100)
> + nv = 100; /* ramp it up! */
> + nv = 255 * nv / 100;
> + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
> + }
> + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
> + /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */
> + sensor->value = 1000 * 100 * data / 255;
> +}
> +
> +void
> +w83627ehf_refresh_fanvolt_rw(struct lm_softc *sc, int n)
> +{
> + struct ksensor *sensor = &sc->sensors[n];
> + int nv, data;
> + int confreg, selshift, modeshift, conf, sel, mode;
> + const char* const sels[2] =
> + { "PWM", "DC" };
> + const char* const modes[4] =
> + { "Manual", "Thermal", "Speed", "SmartIII" };
> +
> + /* get the right Fan Configuration Register */
> + switch (sc->lm_sensors[n].reg) {
> + case 0x01: /* Sys */
> + confreg = 0x04; selshift = 0; modeshift = 2;
> + break;
> + case 0x03: /* CPU */
> + confreg = 0x04; selshift = 1; modeshift = 4;
> + break;
> + case 0x11: /* Aux */
> + confreg = 0x12; selshift = 0; modeshift = 1;
> + break;
> + case 0x61: /* CPU */
> + confreg = 0x5b; selshift = 6; modeshift = 4;
> + break;
> + }
> +
> + if (sensor->flags & SENSOR_FNEWVALUE) {
> + sensor->flags &= ~SENSOR_FNEWVALUE;
> + nv = sensor->upvalue;
> + if (nv < 0 || nv > 100)
> + nv = 100; /* ramp it up! */
> + nv = 255 * nv / 100;
> + /*
> + * Since we got an explicit request to affect the speed,
> + * we need to go into manual mode first.
> + */
> + conf = sc->lm_readreg(sc, confreg);
> + mode = (conf >> modeshift) & 0x3;
> + if (mode != 0) {
> + conf &= ~(0x3 << modeshift);
> + sc->lm_writereg(sc, confreg, conf);
> + }
> + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
> + }
> +
> + /* now populate our struct ksensor */
> +
> + conf = sc->lm_readreg(sc, confreg);
> + sel = (conf >> selshift) & 0x1;
> + mode = (conf >> modeshift) & 0x3;
> + snprintf(sensor->desc + 8, sizeof(sensor->desc) - 8,
> + "%s %s", sels[sel], modes[mode]);
> +
> + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
> + /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */
> + sensor->value = 1000 * 100 * data / 255;
> +#ifdef LMFANDUTYHINTS
> + if (data > 148)
> + sensor->status = SENSOR_S_OK; /* at least 7V */
> + else if (data > 106)
> + sensor->status = SENSOR_S_WARN; /* at least 5V */
> + else
> + sensor->status = SENSOR_S_CRIT; /* less than 5V */
> +#endif /* LMFANDUTYHINTS */
> +}
> +
> +/*
> + * Fan Start-up and Stop Values are only used in Thermal Cruise mode.
> + * The documentation is ambiguous of whether they are used in other
> + * modes, too.
> + */
> +void
> +w83627ehf_refresh_fanvolt_thermal_rw(struct lm_softc *sc, int n)
> +{
> + struct ksensor *sensor = &sc->sensors[n];
> + int nv, data;
> + int confreg, selshift, modeshift, conf, mode, minfanbit, minfan;
> +
> + /*
> + * Get the right Fan Configuration Register.
> + * Register 0x12 has the "Keep Min. Fan Output Value" bools indicating
> + * whether the output should or should not go below the stop value.
> + */
> + switch (sc->lm_sensors[n].reg) {
> + case 0x0a:
> + case 0x08:
> + /* Sys */
> + confreg = 0x04; selshift = 0; modeshift = 2;
> + minfanbit = 5;
> + break;
> + case 0x0b:
> + case 0x09:
> + /* CPU */
> + confreg = 0x04; selshift = 1; modeshift = 4;
> + minfanbit = 4;
> + break;
> + case 0x16:
> + case 0x15:
> + /* Aux */
> + confreg = 0x12; selshift = 0; modeshift = 1;
> + minfanbit = 3;
> + break;
> + case 0x65:
> + case 0x64:
> + /* CPU */
> + confreg = 0x5b; selshift = 6; modeshift = 4;
> + minfanbit = 6;
> + break;
> + }
> +
> + if (sensor->flags & SENSOR_FNEWVALUE) {
> + sensor->flags &= ~SENSOR_FNEWVALUE;
> + nv = sensor->upvalue;
> + if (!(nv < 0 || nv > 100)) {
> + if (sc->lm_sensors[n].rfact == 1) {
> + conf = sc->lm_readreg(sc, 0x12);
> + minfan = (conf >> minfanbit) & 0x1;
> + if (minfan != 1) {
> + conf |= (0x1 << minfanbit);
> + sc->lm_writereg(sc, 0x12, conf);
> + }
> + }
> + nv = 255 * nv / 100;
> + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
> + }
> + }
> +
> + /* now populate our struct ksensor */
> +
> + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
> + /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */
> + sensor->value = 1000 * 100 * data / 255;
> +
> + conf = sc->lm_readreg(sc, confreg);
> + mode = (conf >> modeshift) & 0x3;
> + if (sc->lm_sensors[n].rfact == 1) {
> + conf = sc->lm_readreg(sc, 0x12);
> + minfan = (conf >> minfanbit) & 0x1;
> + } else
> + minfan = 1;
> +
> + if (mode == 0x1 && minfan == 1)
> + sensor->flags &= ~SENSOR_FUNKNOWN;
> + else
> + sensor->flags |= SENSOR_FUNKNOWN;
> +
> +#ifdef LMFANDUTYHINTS
> + if (sensor->flags & SENSOR_FUNKNOWN)
> + sensor->status = SENSOR_S_UNSPEC;
> + else if (data > 148)
> + sensor->status = SENSOR_S_OK; /* at least 7V */
> + else if (data > 106)
> + sensor->status = SENSOR_S_WARN; /* at least 5V */
> + else
> + sensor->status = SENSOR_S_CRIT; /* less than 5V */
> +#endif /* LMFANDUTYHINTS */
> +}
> +
> +void
> +w83627ehf_refresh_indicator_rw(struct lm_softc *sc, int n)
> +{
> + struct ksensor *sensor = &sc->sensors[n];
> + int nv;
> + int confreg, selshift, modeshift, conf, sel;
> + const char* const sels[2] =
> + { "PWM", "DC" };
> +
> + /* get the right Fan Configuration Register */
> + switch (sc->lm_sensors[n].reg) {
> + case 0x01: /* Sys */
> + confreg = 0x04; selshift = 0; modeshift = 2;
> + break;
> + case 0x03: /* CPU */
> + confreg = 0x04; selshift = 1; modeshift = 4;
> + break;
> + case 0x11: /* Aux */
> + confreg = 0x12; selshift = 0; modeshift = 1;
> + break;
> + case 0x61: /* CPU */
> + confreg = 0x5b; selshift = 6; modeshift = 4;
> + break;
> + }
> +
> + if (sensor->flags & SENSOR_FNEWVALUE) {
> + sensor->flags &= ~SENSOR_FNEWVALUE;
> + nv = sensor->upvalue;
> + if (nv == 0 || nv == 1) {
> + conf = sc->lm_readreg(sc, confreg);
> + sel = (conf >> selshift) & 0x1;
> + if (sel != nv) {
> + if (nv == 0)
> + conf &= ~(0x1 << selshift);
> + else
> + conf |= (0x1 << selshift);
> + sc->lm_writereg(sc, confreg, conf);
> + }
> + }
> + }
> +
> + conf = sc->lm_readreg(sc, confreg);
> + sel = (conf >> selshift) & 0x1;
> + sensor->value = sel;
> + snprintf(sensor->desc + 8, sizeof(sensor->desc) - 8,
> + "%s/%s: %s", sels[0], sels[1], sels[sel]);
> +}
> +
> +void
> +w83627ehf_refresh_temptarget_rw(struct lm_softc *sc, int n)
> +{
> + struct ksensor *sensor = &sc->sensors[n];
> + int nv, data;
> + int confreg, modeshift, tolreg, tolsh, conf, mode;
> +
> + /* get the right Fan Configuration Register and Tolerance */
> + /* search for Relative Registers in the datasheet for a nice table */
> + /* .reg in this switch is the target cruise register */
> + switch (sc->lm_sensors[n].reg) {
> + case 0x05: /* Sys */
> + confreg = 0x04; modeshift = 2; tolreg = 0x07; tolsh = 0;
> + break;
> + case 0x06: /* CPU */
> + confreg = 0x04; modeshift = 4; tolreg = 0x07; tolsh = 4;
> + break;
> + case 0x13: /* Aux */
> + confreg = 0x12; modeshift = 1; tolreg = 0x14; tolsh = 0;
> + break;
> + case 0x63: /* CPU */
> + confreg = 0x5b; modeshift = 4; tolreg = 0x62; tolsh = 0;
> + break;
> + }
> +
> + if (sensor->flags & SENSOR_FNEWVALUE) {
> + sensor->flags &= ~SENSOR_FNEWVALUE;
> + nv = sensor->upvalue;
> + /*
> + * If the new value is invalid, assume 'panic',
> + * and make 36 degC the new target temp.
> + */
> + if (nv < 0 || nv > 127)
> + nv = 36;
> + /*
> + * Since we got an explicit request to affect the speed,
> + * we need to go into Temperature Cruise mode first.
> + */
> + conf = sc->lm_readreg(sc, confreg);
> + mode = (conf >> modeshift) & 0x3;
> + if (mode != 0x1) {
> + conf &= ~(0x3 << modeshift);
> + conf |= (0x1 << modeshift);
> + sc->lm_writereg(sc, confreg, conf);
> + }
> + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
> + }
> +
> + /* now populate our struct ksensor */
> +
> + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
> + sensor->value = data * 1000000 + 273150000;
> +
> + conf = sc->lm_readreg(sc, confreg);
> + mode = (conf >> modeshift) & 0x3;
> + if (mode != 0x1)
> + sensor->flags |= SENSOR_FUNKNOWN;
> + else
> + sensor->flags &= ~SENSOR_FUNKNOWN;
> +}
> +
> +void
> +w83627ehf_refresh_temptargettol_rw(struct lm_softc *sc, int n)
> +{
> + struct ksensor *sensor = &sc->sensors[n];
> + int nv, data;
> + int confreg, modeshift, tolreg, tolsh, conf, mode;
> +
> + /* get the right Fan Configuration Register and Tolerance */
> + /* search for Relative Registers in the datasheet for a nice table */
> + /* .reg in this switch is the target cruise register */
> + switch (sc->lm_sensors[n].reg) {
> + case 0x05: /* Sys */
> + confreg = 0x04; modeshift = 2; tolreg = 0x07; tolsh = 0;
> + break;
> + case 0x06: /* CPU */
> + confreg = 0x04; modeshift = 4; tolreg = 0x07; tolsh = 4;
> + break;
> + case 0x13: /* Aux */
> + confreg = 0x12; modeshift = 1; tolreg = 0x14; tolsh = 0;
> + break;
> + case 0x63: /* CPU */
> + confreg = 0x5b; modeshift = 4; tolreg = 0x62; tolsh = 0;
> + break;
> + }
> +
> + if (sensor->flags & SENSOR_FNEWVALUE) {
> + sensor->flags &= ~SENSOR_FNEWVALUE;
> + nv = sensor->upvalue;
> + if (!(nv < 0 || nv > 16)) {
> + data = sc->lm_readreg(sc, tolreg);
> + data &= ~(0xf << tolsh);
> + data |= (nv << tolsh);
> + sc->lm_writereg(sc, tolreg, data);
> + }
> + }
> +
> + /* now populate our struct ksensor */
> +
> + data = sc->lm_readreg(sc, tolreg);
> + data &= (0xf << tolsh);
> + data >>= tolsh;
> + sensor->value = data * 1000000 + 273150000;
> +
> + conf = sc->lm_readreg(sc, confreg);
> + mode = (conf >> modeshift) & 0x3;
> + if (mode != 0x1)
> + sensor->flags |= SENSOR_FUNKNOWN;
> + else
> + sensor->flags &= ~SENSOR_FUNKNOWN;
> +}
> +
> +void
> +w83627thf_refresh_fanvolt_rw(struct lm_softc *sc, int n)
> +{
> + struct ksensor *sensor = &sc->sensors[n];
> + int nv, data;
> + int confreg, modeshift, conf, mode;
> + const char* const modes[4] =
> + { "Manual", "Thermal", "Speed", "" };
> +
> + /* get the right Fan Configuration Register */
> + switch (sc->lm_sensors[n].reg) {
> + case 0x01: /* Sys */
> + confreg = 0x04; modeshift = 2;
> + break;
> + case 0x03: /* CPU */
> + confreg = 0x04; modeshift = 4;
> + break;
> + case 0x11: /* Aux */
> + confreg = 0x12; modeshift = 1;
> + break;
> + }
> +
> + if (sensor->flags & SENSOR_FNEWVALUE) {
> + sensor->flags &= ~SENSOR_FNEWVALUE;
> + nv = sensor->upvalue;
> + if (nv < 0 || nv > 100)
> + nv = 100; /* ramp it up! */
> + /* only 4 out of 8 bits are used to control voltage */
> + nv = 0xf * nv / 100;
> + nv <<= 4;
> + /*
> + * Since we got an explicit request to affect the speed,
> + * we need to go into manual mode first.
> + */
> + conf = sc->lm_readreg(sc, confreg);
> + mode = (conf >> modeshift) & 0x3;
> + if (mode != 0) {
> + conf &= ~(0x3 << modeshift);
> + sc->lm_writereg(sc, confreg, conf);
> + }
> + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv);
> + }
> +
> + /* now populate our struct ksensor */
> +
> + conf = sc->lm_readreg(sc, confreg);
> + mode = (conf >> modeshift) & 0x3;
> + snprintf(sensor->desc + 8, sizeof(sensor->desc) - 8,
> + "Ctl %s", modes[mode]);
> +
> + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg);
> + data >>= 4;
> + /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */
> + sensor->value = 1000 * 100 * data / 0xf;
> +#ifdef LMFANDUTYHINTS
> + if (data > 0x8)
> + sensor->status = SENSOR_S_OK; /* at least 7.2V */
> + else if (data > 0x5)
> + sensor->status = SENSOR_S_WARN; /* at least 4.8V */
> + else
> + sensor->status = SENSOR_S_CRIT; /* 4.0V and less */
> +#endif /* LMFANDUTYHINTS */
> }
>
> void
> wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n)
> {
> struct ksensor *sensor = &sc->sensors[n];
> int data;