Hi, after updating my old laptop to netbsd-5, I did need to have a working APM again. I came up with the following patch, which makes standby, suspend to ram and suspend to disk work again for me.
There are 2 problems: - apm_suspend() and apm_standby() will call splhhigh() before entering standby or suspend. After resume, the system go back tsleep()ing in the apm thread without restoring the ipl (this is done in apm_resume()), and calling tlseep() at IPL_HIGH cause a DIAGOSCTIC panic (and other bad things, I guess). My fix is to call apm_resume() from within apm_suspend() or apm_standby(), after aa_set_powstate() has returned. Another option would be to set another global variable apm_in_sleep and not call tsleep in the apm thread when this variable is not 0. Not sure which one is better. - In apm_event_handle(), we test (apm_standbys || apm_suspends) to set apm_damn_fool_bios to 1 and break the while() loop in apm_periodic_check(). But we set apm_standbys or apm_suspends to non-0 only if apm_op_inprog is 0 and we failed to record the apm event. With apmd listening we usually succeed recording the event, so apm_standbys/apm_suspends remains 0 and we never go out of the while() loop. My fix is to check apm_op_inprog instead of (apm_standbys || apm_suspends) to break the loop. This one is always set when an event is being handled. Comments ? PS: on this laptop the pfm handler are harmfull and I had to disable them: on reboot, the laptop gets stuck in BIOS, and on wakeup after a suspend/standby, the kernel is completely dead. But that's a different problem. -- Manuel Bouyer <bou...@antioche.eu.org> NetBSD: 26 ans d'experience feront toujours la difference --
Index: apm.c =================================================================== RCS file: /cvsroot/src/sys/dev/apm/apm.c,v retrieving revision 1.22 diff -u -p -u -r1.22 apm.c --- apm.c 12 Jun 2008 21:47:46 -0000 1.22 +++ apm.c 26 Feb 2010 10:47:16 -0000 @@ -318,6 +318,8 @@ apm_suspend(struct apm_softc *sc) if (error) apm_resume(sc, 0, 0); + else + apm_resume(sc, APM_SYS_STANDBY_RESUME, 0); } static void @@ -342,12 +344,13 @@ apm_standby(struct apm_softc *sc) APM_SYS_STANDBY); if (error) apm_resume(sc, 0, 0); + else + apm_resume(sc, APM_SYS_STANDBY_RESUME, 0); } static void apm_resume(struct apm_softc *sc, u_int event_type, u_int event_info) { - if (sc->sc_power_state == PWR_RESUME) { #ifdef APMDEBUG aprint_debug_dev(sc->sc_dev, "apm_resume: already running?\n"); @@ -421,7 +424,7 @@ apm_event_handle(struct apm_softc *sc, u case APM_STANDBY_REQ: DPRINTF(APMDEBUG_EVENTS, ("apmev: system standby request\n")); - if (apm_standbys || apm_suspends) { + if (apm_op_inprog) { DPRINTF(APMDEBUG_EVENTS | APMDEBUG_ANOM, ("damn fool BIOS did not wait for answer\n")); /* just give up the fight */ @@ -453,7 +456,7 @@ apm_event_handle(struct apm_softc *sc, u case APM_SUSPEND_REQ: DPRINTF(APMDEBUG_EVENTS, ("apmev: system suspend request\n")); - if (apm_standbys || apm_suspends) { + if (apm_op_inprog) { DPRINTF(APMDEBUG_EVENTS | APMDEBUG_ANOM, ("damn fool BIOS did not wait for answer\n")); /* just give up the fight */