diff options
Diffstat (limited to 'n35d')
-rw-r--r-- | n35d/Makefile | 8 | ||||
-rw-r--r-- | n35d/README | 9 | ||||
-rwxr-xr-x | n35d/n35d | bin | 0 -> 12983 bytes | |||
-rw-r--r-- | n35d/n35d.c | 250 |
4 files changed, 267 insertions, 0 deletions
diff --git a/n35d/Makefile b/n35d/Makefile new file mode 100644 index 0000000..387789b --- /dev/null +++ b/n35d/Makefile @@ -0,0 +1,8 @@ +CC=arm-unknown-linux-uclibcgnueabi-cc + +n35d: n35d.c + $(CC) -Os -march=armv4t -mtune=arm920t -g -o $@ $< + +clean: + $(RM) n35d + diff --git a/n35d/README b/n35d/README new file mode 100644 index 0000000..7717058 --- /dev/null +++ b/n35d/README @@ -0,0 +1,9 @@ +n35d +==== + +This daemon listens to the following events: + +- Antenna magnet: Activate/deactivate GPS receiver, blue LED +- Power butten: Enter suspend to ram/wake up +- APM events: Disabled/unusable at the moment + diff --git a/n35d/n35d b/n35d/n35d Binary files differnew file mode 100755 index 0000000..97cc54c --- /dev/null +++ b/n35d/n35d diff --git a/n35d/n35d.c b/n35d/n35d.c new file mode 100644 index 0000000..e9e4255 --- /dev/null +++ b/n35d/n35d.c @@ -0,0 +1,250 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/select.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <sys/ioctl.h> + +#include <linux/input.h> +#include <linux/watchdog.h> +#include <linux/apm_bios.h> + +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; +} + |