Index: j720kbd.c =================================================================== RCS file: /cvsroot/src/sys/arch/hpcarm/dev/j720kbd.c,v retrieving revision 1.3 diff -u -r1.3 j720kbd.c --- j720kbd.c 27 Jun 2006 14:36:50 -0000 1.3 +++ j720kbd.c 25 Sep 2006 04:50:01 -0000 @@ -59,7 +59,6 @@ #include #include -#include #ifdef DEBUG #define DPRINTF(arg) printf arg @@ -93,7 +92,6 @@ static int j720kbd_intr(void *); static int j720kbd_poll(void *); static void j720kbd_read(struct j720kbd_chip *, char *); -static int j720kbd_button_event(void *, int, long, void *); CFATTACH_DECL(j720kbd, sizeof(struct j720kbd_softc), j720kbd_match, j720kbd_attach, NULL, NULL); @@ -132,11 +130,6 @@ /* Install interrupt handler. */ sa11x0_intr_establish(0, 0, 1, IPL_TTY, j720kbd_intr, sc); - /* Add config hook for light button event. */ - config_hook(CONFIG_HOOK_BUTTONEVENT, - CONFIG_HOOK_BUTTONEVENT_LIGHT, - CONFIG_HOOK_SHARE, j720kbd_button_event, sc); - /* Attach hpckbd. */ haa.haa_ic = &sc->sc_chip->scc_if; config_found(self, &haa, hpckbd_print); @@ -253,16 +246,3 @@ DPRINTF(("j720kbd_read: error %x\n", data)); } - -static int -j720kbd_button_event(void *ctx, int type, long id, void *msg) -{ - - if (type != CONFIG_HOOK_BUTTONEVENT || - id != CONFIG_HOOK_BUTTONEVENT_LIGHT) - return 0; - - sed1356_toggle_lcdlight(); - - return 1; -} Index: j720pwr.c =================================================================== RCS file: /cvsroot/src/sys/arch/hpcarm/dev/j720pwr.c,v retrieving revision 1.2 diff -u -r1.2 j720pwr.c --- j720pwr.c 27 Jun 2006 14:36:50 -0000 1.2 +++ j720pwr.c 25 Sep 2006 04:50:02 -0000 @@ -72,11 +72,18 @@ struct device sc_dev; struct j720ssp_softc *sc_ssp; + + volatile int sc_state; +#define J720PWR_POWEROFF 0x01 +#define J720PWR_SLEEPING 0x02 }; static int j720pwr_match(struct device *, struct cfdata *, void *); static void j720pwr_attach(struct device *, struct device *, void *); +static void j720pwr_sleep(void *); +static int j720pwr_suspend_hook(void *, int, long, void *); +static int j720pwr_event_hook(void *, int, long, void *); static int j720pwr_apm_getpower_hook(void *, int, long, void *); static int j720pwr_get_battery(struct j720pwr_softc *); static int j720pwr_get_ac_status(struct j720pwr_softc *); @@ -120,10 +127,17 @@ j720pwr_attach(struct device *parent, struct device *self, void *aux) { struct j720pwr_softc *sc = (struct j720pwr_softc *)self; + extern void (*__sleep_func)(void *); + extern void *__sleep_ctx; printf("\n"); sc->sc_ssp = (struct j720ssp_softc *)parent; + sc->sc_state = 0; + + /* Register apm sleep function. */ + __sleep_func = j720pwr_sleep; + __sleep_ctx = sc; /* Battery status query hook. */ config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BATTERYVAL, @@ -137,10 +151,94 @@ config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_ACADAPTER, CONFIG_HOOK_EXCLUSIVE, j720pwr_apm_getpower_hook, sc); + /* Suspend/resume button hook. */ + config_hook(CONFIG_HOOK_BUTTONEVENT, + CONFIG_HOOK_BUTTONEVENT_POWER, + CONFIG_HOOK_SHARE, j720pwr_suspend_hook, sc); + + /* Receive suspend/resume events. */ + config_hook(CONFIG_HOOK_PMEVENT, + CONFIG_HOOK_PMEVENT_HARDPOWER, + CONFIG_HOOK_SHARE, j720pwr_event_hook, sc); + /* Attach hpcapm. */ config_found_ia(self, "hpcapmif", NULL, NULL); } +static void +j720pwr_sleep(void *ctx) +{ + struct j720pwr_softc *sc = ctx; + struct j720ssp_softc *ssp = sc->sc_ssp; + uint32_t oldfer; + + /* Disable falling-edge detect on all GPIO ports, except keyboard. */ + oldfer = bus_space_read_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_FER); + bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_FER, 1 << 0); + + while (sc->sc_state & J720PWR_POWEROFF) { + /* + * Just sleep here until the poweroff bit gets unset. + * We need to wait here because when machine_sleep() returns + * hpcapm(4) assumes that we are "resuming". + */ + (void)tsleep(&sc->sc_state, PWAIT, "j720slp", 0); + } + + /* Restore previous FER value. */ + bus_space_write_4(ssp->sc_iot, ssp->sc_gpioh, SAGPIO_FER, oldfer); +} + +static int +j720pwr_suspend_hook(void *ctx, int type, long id, void *msg) +{ + struct j720pwr_softc *sc = ctx; + + if (type != CONFIG_HOOK_BUTTONEVENT || + id != CONFIG_HOOK_BUTTONEVENT_POWER) + return EINVAL; + + if ((sc->sc_state & (J720PWR_POWEROFF | J720PWR_SLEEPING)) == 0) { + sc->sc_state |= J720PWR_POWEROFF; + } else if ((sc->sc_state & (J720PWR_POWEROFF | J720PWR_SLEEPING)) == + (J720PWR_POWEROFF | J720PWR_SLEEPING)) { + sc->sc_state &= ~J720PWR_POWEROFF; + wakeup(&sc->sc_state); + } else { + DPRINTF(("j720pwr_suspend_hook: busy\n")); + return EBUSY; + } + + config_hook_call(CONFIG_HOOK_PMEVENT, + CONFIG_HOOK_PMEVENT_SUSPENDREQ, NULL); + + return 0; +} + +static int +j720pwr_event_hook(void *ctx, int type, long id, void *msg) +{ + struct j720pwr_softc *sc = ctx; + int event = (int)msg; + + if (type != CONFIG_HOOK_PMEVENT || + id != CONFIG_HOOK_PMEVENT_HARDPOWER) + return EINVAL; + + switch (event) { + case PWR_SUSPEND: + sc->sc_state |= (J720PWR_SLEEPING | J720PWR_POWEROFF); + break; + case PWR_RESUME: + sc->sc_state &= ~(J720PWR_SLEEPING | J720PWR_POWEROFF); + break; + default: + return EINVAL; + } + + return 0; +} + static int j720pwr_apm_getpower_hook(void *ctx, int type, long id, void *msg) {