/*
 * Copyright (c) Des Herriott 1993, 1994
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the copyright holder not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  The copyright holder makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: Des Herriott
 */

/*
 * Source file joystick.c - emulate a Kempston joystick.
 * Only works on Linux with joystick kernel patches, tested
 * with versions 0.5, 0.6 & 0.7.
 */

#ifdef JOY
#include <fcntl.h>
#include <stdio.h>
#include <linux/joystick.h>
#endif

/* Kempston joystick bits */
#define KEMPST_RIGHT 0x01
#define KEMPST_LEFT 0x02
#define KEMPST_DOWN 0x04
#define KEMPST_UP 0x08
#define KEMPST_FIRE 0x10

static int jsfd;	/* joystick file descriptor */
static int joystick_ok = 0;
static int js_tol;

static int centre_x, centre_y;

int
joystick_init(char *devname, int tolerance)
{
#ifdef JOY
	struct JS_DATA_TYPE js_data;
	long tmpl;
	int tmp;

	if ((jsfd = open(devname, O_RDONLY)) < 1)
		return -1;

	tmpl=10;

	if (ioctl(jsfd, JS_SET_TIMELIMIT, &tmpl) == -1) {
		perror("ioctl JS_SET_TIMELIMIT");
		return -1;
	}

	fprintf(stderr, "xzx: Linux joystick option selected:\n");
	fprintf(stderr, "  Move joystick to lower right and press either button\n");

	while ((read(jsfd, &js_data, JS_RETURN) > 0) && js_data.buttons == 0x00)
		;

	for(tmp=0; js_data.x > 0xff; tmp++, js_data.x >>= 1)
		;
	js_data.x=tmp;
	for(tmp=0; js_data.y > 0xff; tmp++, js_data.y >>= 1)
		;
	js_data.y=tmp;

	if (ioctl(jsfd, JS_SET_CAL, &js_data) == -1) {
		perror("ioctl JS_SET_CAL");
		return -1;
	}

	while ((read(jsfd, &js_data, JS_RETURN) > 0) && js_data.buttons != 0x00)
		;
	fprintf(stderr, "  Now centralise the joystick and press either button\n");
	while ((read(jsfd, &js_data, JS_RETURN) > 0) && js_data.buttons == 0x00)
		;
	centre_x = js_data.x; centre_y = js_data.y;

	fprintf(stderr, "xzx: joystick initialisation successful\n");

	joystick_ok = 1;
	js_tol = tolerance;
	return 0;
#else
	return -1;
#endif
}


/* Read the current joystick position.  If it's displaced by more
 * than <js_tol> from centre, then OR in the appropriate 
 * direction bit.
 */
int 
joystick_read(void)
{
#ifdef JOY
	struct JS_DATA_TYPE js_data;
	int res = 0;

	if (!joystick_ok)
		return -1;

	if (read(jsfd, &js_data, JS_RETURN) != JS_RETURN) {
		fprintf(stderr, "xzx: Lost joystick connection!\n");
		joystick_ok = 0;
		return -1;
	}

	/* decode the joystick return values */
	if (js_data.x < centre_x - js_tol) res |= KEMPST_LEFT;
	else if (js_data.x > centre_x + js_tol) res |= KEMPST_RIGHT;

	if (js_data.y < centre_y - js_tol) res |= KEMPST_UP;
	else if (js_data.y > centre_y + js_tol) res |= KEMPST_DOWN;

	if (js_data.buttons) res |= KEMPST_FIRE;

	return res;
#else
	return -1;
#endif
}
