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