/*
 * pivot.c - read from the HDAPS (HardDrive Active Protection System).
 *
 * Copyright (C) 2005 Robert Love <rml@novell.com>
 *
 * "Why does that kid keep dropping his laptop?"
 */

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>

#define SYSFS_POSITION_FILE	"/sys/devices/platform/hdaps/position"
#define SYSFS_KEYBOARD_FILE	"/sys/devices/platform/hdaps/keyboard_activity"
#define SYSFS_MOUSE_FILE	"/sys/devices/platform/hdaps/mouse_activity"

#define BUF_LEN			32

/*
 * read_position - read the (x,y) position pair from hdaps.
 *
 * We open and close the file on every invocation, which is lame but due to
 * several features of sysfs files:
 *
 *	(a) Sysfs files are seekable.
 *	(b) Seeking to zero and then rereading does not seem to work.
 *
 * If I were king--and I will be one day--I would have made sysfs files
 * nonseekable and only able to return full-size reads.
 */
static int read_position (int *x, int *y)
{
	char buf[BUF_LEN];
	int fd, ret;

	fd = open (SYSFS_POSITION_FILE, O_RDONLY);
	if (fd < 0) {
		perror ("open");
		return fd;
	}	

	ret = read (fd, buf, BUF_LEN);
	if (ret < 0) {
		perror ("read");
		goto out;
	} else if (ret == 0) {
		fprintf (stderr, "error: unexpectedly read zero!\n");
		ret = 1;
		goto out;
	}
	ret = 0;

	if (sscanf (buf, "(%d,%d)\n", x, y) != 2)
		ret = 1;

out:
	if (close (fd))
		perror ("close");

	return ret;
}

static int read_one (const char *path, unsigned char *val)
{
	char buf[BUF_LEN];
	int fd, ret;

	fd = open (path, O_RDONLY);
	if (fd < 0) {
		perror ("open");
		return fd;
	}	

	ret = read (fd, buf, BUF_LEN);
	if (ret < 0) {
		perror ("read");
		goto out;
	} else if (ret == 0) {
		fprintf (stderr, "error: unexpectedly read zero!\n");
		ret = 1;
		goto out;
	}
	ret = 0;

	if (sscanf (buf, "%c\n", val) != 1)
		ret = 1;

out:
	if (close (fd))
		perror ("close");

	return ret;
}

int main (void)
{
	int rest_x, rest_y, i, ret, verbose = 1;

	/* get some base data for calibration */
	ret = read_position (&rest_x, &rest_y);
	if (ret)
		return 1;
	printf ("(x,y) base: (%u,%u)\n", rest_x, rest_y);

	for (i = 0; i < 1000; i++) {
		struct timespec ts = { 0, 250000000 };
		int x, y;

		ret = read_position (&x, &y);
		if (ret)
			break;

		printf ("(x,y) position: (%d,%d)\n", x - rest_x, y - rest_y);

		if (verbose) {
			unsigned char keyboard, mouse;

			if (read_one (SYSFS_KEYBOARD_FILE, &keyboard) ||
					read_one (SYSFS_MOUSE_FILE, &mouse))
				break;
			printf ("keyboard=%c mouse=%c\n", keyboard, mouse);
		}

		ret = nanosleep (&ts, NULL);
		if (ret) {
			perror ("nanosleep");
			break;
		}
	}

	return ret;
}
