aboutsummaryrefslogtreecommitdiff
path: root/n35d/n35d.c
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2012-03-24 14:56:48 +0100
committerLars-Dominik Braun <lars@6xq.net>2012-03-24 14:56:48 +0100
commit35c78055e4386f5d02aaf299c4a2f21480b07741 (patch)
tree1ddab0ae0d74d8a08331a44d817d3590fda7ce18 /n35d/n35d.c
parent6e8bfd4629ef901541b34f26207abfd7f2236bf4 (diff)
downloadbuildroot-n35-master.tar.gz
buildroot-n35-master.tar.bz2
buildroot-n35-master.zip
Spring cleanupHEADmaster
Updated to buildroot 2012.02 and Linux 3.1.10, added n35d, updated install instructions.
Diffstat (limited to 'n35d/n35d.c')
-rw-r--r--n35d/n35d.c250
1 files changed, 250 insertions, 0 deletions
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;
+}
+