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;

Reply via email to