tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

apm(4) fixes



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 <bouyer%antioche.eu.org@localhost>
     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 */


Home | Main Index | Thread Index | Old Index