#include #include #include #include #include #include #include #include #include #include #include #include struct event { struct timeval time; unsigned short type; unsigned short code; unsigned int value; }; #define eventDevice "/dev/input/event1" #define apmDevice "/dev/apm_bios" sig_atomic_t quit = 0; /* write string to sysfs file */ static int writeStr (const char * const file, const char * const s, const size_t slen) { int fd; if ((fd = open (file, O_WRONLY)) == -1) { perror ("open"); return -1; } if (write (fd, s, slen) == -1) { perror ("write"); } close (fd); } /* write 1 or 0 to sysfs file */ static int writeToggleStr (const char * const file, const int enable) { const char *s = "0"; const size_t slen = 1; if (enable) { s = "1"; } writeStr (file, s, slen); } /* suspend to ram */ static void suspend (int apmfd) { static const char * const s = "mem"; const size_t slen = sizeof (s)-1; if (ioctl (apmfd, APM_IOC_SUSPEND, NULL) == -1) { perror ("ioctl suspend"); } } /* reboot system */ static void reboot () { system ("reboot"); } /* en/disable gps unit */ static void toggleGps (int enable) { writeToggleStr ("/sys/devices/platform/n35-gps/gps_power", enable); } /* en/disable blue led */ static void toggleBlueLed (int enable) { writeToggleStr ("/sys/devices/platform/s3c24xx_led.1/leds/blue_led/brightness", enable); } /* en/disable red warning led */ static void toggleWarningLed (int enable) { writeToggleStr ("/sys/devices/platform/s3c24xx_led.2/leds/warning_led/brightness", enable); } void handleSignal (int signum) { switch (signum) { case SIGTERM: case SIGINT: quit = 1; break; } } int main (int argc, char **argv) { int eventfd, watchdogfd, apmfd, maxfd; int blueBlink = 0, suspended = 0; enum {BLUE_OFF = 0, BLUE_ON = 1} blinkState = BLUE_OFF; struct sigaction sact; /* FIXME: check initial gps antenna state (how?) */ memset (&sact, 0, sizeof (sact)); sact.sa_handler = handleSignal; sigaction (SIGTERM, &sact, NULL); sigaction (SIGINT, &sact, NULL); if ((eventfd = open (eventDevice, O_RDONLY)) == -1) { perror ("open event"); return 1; } if ((apmfd = open (apmDevice, O_RDWR)) == -1) { perror ("open apm"); return 1; } maxfd = eventfd > apmfd ? eventfd : apmfd; ++maxfd; #if 0 if ((watchdogfd = open ("/dev/watchdog", O_WRONLY)) == -1) { perror ("open watchdog"); return -1; } int timeout; ioctl(watchdogfd, WDIOC_GETTIMEOUT, &timeout); printf("The timeout was is %d seconds\n", timeout); /* we’re not dead and purposefully closed the device */ write (watchdogfd, "V", 1); close (watchdogfd); #endif while (!quit) { fd_set rfds; struct timeval tv; int ret; FD_ZERO(&rfds); FD_SET(eventfd, &rfds); FD_SET(apmfd, &rfds); if (blueBlink) { if (blinkState == BLUE_ON) { tv.tv_sec = 0; tv.tv_usec = 100000; } else { tv.tv_sec = 1; tv.tv_usec = 0; } } ret = select (maxfd, &rfds, NULL, NULL, blueBlink ? &tv : NULL); if (ret == -1) { perror ("select"); break; } else if (ret > 0) { if (FD_ISSET (eventfd, &rfds)) { /* handle key press events */ struct event ev; if (read (eventfd, &ev, sizeof (ev)) == -1) { perror ("read"); } printf ("time: %u sec %u usec, type %x, code %x, value %x\n", ev.time.tv_sec, ev.time.tv_usec, ev.type, ev.code, ev.value); if (ev.type == EV_KEY) { switch (ev.code) { case KEY_POWER: /* suspend */ if (ev.value == 1) { if (suspended > 0) { /* prevent wakeup keypress from suspending * again */ --suspended; } else { /* make sure device does not wake ap again */ usleep (100000); suspended = 1; suspend (apmfd); } } break; case KEY_POWER2: /* reboot */ if (ev.value == 1) { reboot (); } break; case SW_RADIO: /* toggle gps power */ toggleGps ((ev.value == 1)); blueBlink = (ev.value == 1); toggleBlueLed (0); break; } } } else if (FD_ISSET (apmfd, &rfds)) { /* handle apm events */ apm_event_t ev; if (read (apmfd, &ev, sizeof (ev)) == -1) { perror ("read"); break; } printf ("got apm event %x\n", ev); switch (ev) { case APM_NORMAL_RESUME: /* device resumed from suspend */ break; #if 0 /* this is done by the hardware (8% left) */ case APM_LOW_BATTERY: toggleWarningLed (1); break; #endif /* the apm driver is unable to send these events atm */ case APM_POWER_STATUS_CHANGE: /* ? */ break; } } } if (blueBlink) { blinkState = !blinkState; toggleBlueLed (blinkState); } } /* make sure the windows are closed before leaving */ toggleGps (0); toggleBlueLed (0); toggleWarningLed (0); close (eventfd); close (apmfd); return 0; }