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