Hi,

I've finally found some time to work on the fan control support for my
thinkpad.
But I'm having problems calling to acpiec_write() from sysctl or
timeout_set(9) context. (Assertion failure in acpiec_gpehandler()).
According to dev/acpi/acpiec.c:229 this function is meant to be called
only from "acpi thread context".
Now how am I supposed to talk to the acpi controller?
One solution would be to use the aml_register_notify(..., ACPIDEV_POLL)
callback mechanism already in use by the acpithinkpad(4) driver to
somehow get into acpi thread context. The problem is that this callback
mechanism is hardcoded to 10s intervals. But I need intervals <1s to
implement a workaround described on
http://www.thinkwiki.org/wiki/How_to_control_fan_speed#Disengaged_.28full-speed.29_mode

any help is appreciated. I'm stuck here.

Christopher



this is what I've got so far:

Index: arch/i386/i386/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.485
diff -u -p -r1.485 machdep.c
--- arch/i386/i386/machdep.c    2 Oct 2010 23:31:34 -0000       1.485
+++ arch/i386/i386/machdep.c    19 Dec 2010 15:11:09 -0000
@@ -243,6 +243,7 @@ void        via_update_sensor(void *args);
 #endif
 int kbd_reset;
 int lid_suspend;
+int fan_control;

 /*
  * safepri is a safe priority for sleep to set for a spin-wait
@@ -3416,6 +3417,8 @@ cpu_sysctl(int *name, u_int namelen, voi
                return (sysctl_rdint(oldp, oldlenp, newp, i386_has_xcrypt));
        case CPU_LIDSUSPEND:
                return (sysctl_int(oldp, oldlenp, newp, newlen, &lid_suspend));
+       case CPU_FANCONTROL:
+               return (sysctl_int(oldp, oldlenp, newp, newlen, &fan_control));
        default:
                return (EOPNOTSUPP);
        }
Index: arch/i386/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/i386/include/cpu.h,v
retrieving revision 1.117
diff -u -p -r1.117 cpu.h
--- arch/i386/include/cpu.h     2 Oct 2010 23:13:28 -0000       1.117
+++ arch/i386/include/cpu.h     19 Dec 2010 15:11:09 -0000
@@ -461,7 +461,8 @@ void        vm86_gpfault(struct proc *, int);
 #define CPU_SSE2               15      /* supports SSE2 */
 #define CPU_XCRYPT             16      /* supports VIA xcrypt in userland */
 #define CPU_LIDSUSPEND         17      /* lid close causes a suspend */
-#define CPU_MAXID              18      /* number of valid machdep ids */
+#define CPU_FANCONTROL         18      /* lid close causes a suspend */
+#define CPU_MAXID              19      /* number of valid machdep ids */

 #define        CTL_MACHDEP_NAMES { \
        { 0, 0 }, \
@@ -482,6 +483,7 @@ void        vm86_gpfault(struct proc *, int);
        { "sse2", CTLTYPE_INT }, \
        { "xcrypt", CTLTYPE_INT }, \
        { "lidsuspend", CTLTYPE_INT }, \
+       { "fancontrol", CTLTYPE_INT }, \
 }

 /*
Index: dev/acpi/acpithinkpad.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpithinkpad.c,v
retrieving revision 1.24
diff -u -p -r1.24 acpithinkpad.c
--- dev/acpi/acpithinkpad.c     7 Aug 2010 16:21:20 -0000       1.24
+++ dev/acpi/acpithinkpad.c     19 Dec 2010 15:11:17 -0000
@@ -77,6 +77,16 @@
 #define THINKPAD_ECOFFSET_FANLO                0x84
 #define THINKPAD_ECOFFSET_FANHI                0x85

+#define THINKPAD_ECOFFSET_FANCTL       0x2f
+#define THINKPAD_FAN_REGVAL            0xff
+/* Most thinkpads only support only speed steps 1-7 */
+#define THINKPAD_FAN_MANUAL            0x3f
+#define THINKPAD_FAN_DISENGAGE         0x40
+#define THINKPAD_FAN_AUTO              0x80
+/* AntiPulse */
+#define THINKPAD_FAN_AP                        0x100
+#define THINKPAD_FAN_AP_DISENGAGE      0x200
+
 struct acpithinkpad_softc {
        struct device            sc_dev;

@@ -86,8 +96,13 @@ struct acpithinkpad_softc {

        struct ksensor           sc_sens[THINKPAD_NSENSORS];
        struct ksensordev        sc_sensdev;
+
+       /* Fan control */
+       struct timeout          sc_fan_timeout;
 };

+extern int fan_control;
+
 extern void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);

 int    thinkpad_match(struct device *, void *, void *);
@@ -103,8 +118,9 @@ int thinkpad_volume_mute(struct acpithin
 int    thinkpad_brightness_up(struct acpithinkpad_softc *);
 int    thinkpad_brightness_down(struct acpithinkpad_softc *);

-void    thinkpad_sensor_attach(struct acpithinkpad_softc *sc);
+void    thinkpad_sensor_attach(struct acpithinkpad_softc *);
 void    thinkpad_sensor_refresh(void *);
+void    thinkpad_fancontrol(void *);

 struct cfattach acpithinkpad_ca = {
        sizeof(struct acpithinkpad_softc), thinkpad_match, thinkpad_attach
@@ -185,6 +201,46 @@ thinkpad_sensor_refresh(void *arg)
 }

 void
+thinkpad_fancontrol(void *arg)
+{
+       u_int8_t fanctl;
+
+       struct acpithinkpad_softc *sc = arg;
+
+       if (fan_control & THINKPAD_FAN_AP)
+       {
+               if (fan_control & THINKPAD_FAN_AP_DISENGAGE)
+               {
+                       fanctl = fan_control & 0xff;
+                       fan_control &= ~THINKPAD_FAN_AP_DISENGAGE;
+                       timeout_add_sec(&sc->sc_fan_timeout, 1);
+               }
+               else
+               {
+                       fanctl = 0x40;
+                       fan_control |= THINKPAD_FAN_AP_DISENGAGE;
+                       timeout_add_sec(&sc->sc_fan_timeout, 4);
+               }
+
+       }
+       else if ((fan_control & 0xff) != fanctl)
+       {
+               fanctl = fan_control & 0xff;
+               timeout_add_sec(&sc->sc_fan_timeout, 5);
+       }
+       else
+               return;
+
+       printf("thinkpad_fancontrol: setting to 0x%.2hhx",
+                       fanctl);
+       acpiec_write(sc->sc_acpi->sc_ec,
+                       THINKPAD_ECOFFSET_FANCTL,
+                       1,
+                       &fanctl);
+       printf(".\n");
+}
+
+void
 thinkpad_attach(struct device *parent, struct device *self, void *aux)
 {
        struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
@@ -202,6 +258,13 @@ thinkpad_attach(struct device *parent, s
        /* Run thinkpad_hotkey on button presses */
        aml_register_notify(sc->sc_devnode, aa->aaa_dev,
            thinkpad_hotkey, sc, ACPIDEV_POLL);
+
+       /* automatic fan control, AntiPulse disable by default*/
+       fan_control = THINKPAD_FAN_AUTO;
+
+       /* Initialize and start fan timer */
+       timeout_set(&sc->sc_fan_timeout, thinkpad_fancontrol, sc);
+       timeout_add_sec(&sc->sc_fan_timeout, 1);
 }

 int

Reply via email to