233 lines
5.5 KiB
C
233 lines
5.5 KiB
C
/*
|
|
* Joystick input driver for LCDd
|
|
*
|
|
* Only two unique functions are defined:
|
|
*
|
|
* joy_get_key
|
|
* joy_close
|
|
*
|
|
* All others are at their defaults.
|
|
*
|
|
* The code here is configured for a Gravis Gamepad (2 axis, 4 button)
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <termios.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <linux/joystick.h>
|
|
#ifndef JSIOCGNAME
|
|
#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */
|
|
#endif
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "lcd.h"
|
|
#include "joy.h"
|
|
#include "report.h"
|
|
#include "shared/str.h"
|
|
|
|
#define JOY_NAMELENGTH 128
|
|
#define JOY_DEFAULT_DEVICE "/dev/js0"
|
|
#define JOY_MAPSIZE 16
|
|
#define JOY_DEFAULT_AXISMAP "EFGHIJKLMNOPQRST"
|
|
#define JOY_DEFAULT_BUTTONMAP "BDACEFGHIJKLMNOP"
|
|
|
|
|
|
|
|
typedef struct driver_private_data {
|
|
char device[256];
|
|
int fd;
|
|
|
|
char axes;
|
|
char buttons;
|
|
int jsversion;
|
|
char jsname[JOY_NAMELENGTH];
|
|
|
|
char **axismap;
|
|
char **buttonmap;
|
|
} PrivateData;
|
|
|
|
|
|
// Vars for the server core
|
|
MODULE_EXPORT char *api_version = API_VERSION;
|
|
MODULE_EXPORT int stay_in_foreground = 0;
|
|
MODULE_EXPORT int supports_multiple = 0;
|
|
MODULE_EXPORT char *symbol_prefix = "joy_";
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// init() should set up any device-specific stuff, and
|
|
// point all the function pointers.
|
|
MODULE_EXPORT int
|
|
joy_init (Driver *drvthis)
|
|
{
|
|
PrivateData *p;
|
|
int i;
|
|
|
|
/* Allocate and store private data */
|
|
p = (PrivateData *) calloc(1, sizeof(PrivateData));
|
|
if (p == NULL)
|
|
return -1;
|
|
if (drvthis->store_private_ptr(drvthis, p))
|
|
return -1;
|
|
|
|
/* initialize private data */
|
|
p->fd = -1;
|
|
p->axes = 2;
|
|
p->buttons = 2;
|
|
p->jsversion = 0;
|
|
strcpy(p->jsname, "Unknown");
|
|
p->axismap = NULL;
|
|
p->buttonmap = NULL;
|
|
|
|
|
|
/* Read config file (1st part) */
|
|
|
|
/* What device should be used */
|
|
strncpy(p->device, drvthis->config_get_string(drvthis->name, "Device", 0,
|
|
JOY_DEFAULT_DEVICE), sizeof(p->device));
|
|
p->device[sizeof(p->device)-1] = '\0';
|
|
report(RPT_INFO, "%s: using Device %s", drvthis->name, p->device);
|
|
|
|
/* End of config file parsing (1st part) */
|
|
|
|
if ((p->fd = open(p->device, O_RDONLY)) < 0) {
|
|
report(RPT_ERR, "%s: open(%s) failed (%s)",
|
|
drvthis->name, p->device, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
/* init joystick, get values for buttons, exes, name, ... */
|
|
fcntl(p->fd, F_SETFL, O_NONBLOCK);
|
|
ioctl(p->fd, JSIOCGVERSION, &p->jsversion);
|
|
ioctl(p->fd, JSIOCGAXES, &p->axes);
|
|
ioctl(p->fd, JSIOCGBUTTONS, &p->buttons);
|
|
ioctl(p->fd, JSIOCGNAME(JOY_NAMELENGTH), p->jsname);
|
|
|
|
report(RPT_NOTICE, "%s: Joystick (%s) has %d axes and %d buttons. Driver version is %d.%d.%d",
|
|
drvthis->name, p->jsname, p->axes, p->buttons,
|
|
p->jsversion >> 16, (p->jsversion >> 8) & 0xff, p->jsversion & 0xff);
|
|
|
|
if ((p->axismap = calloc(2 * p->axes, sizeof(char *))) == NULL) {
|
|
report(RPT_ERR, "%s: cannot allocate memory for axes", drvthis->name);
|
|
return -1;
|
|
}
|
|
|
|
if ((p->buttonmap = calloc(p->buttons, sizeof(char *))) == NULL) {
|
|
report(RPT_ERR, "%s: cannot allocate memory for buttons", drvthis->name);
|
|
return -1;
|
|
}
|
|
|
|
/* Read config file (2nd part) */
|
|
|
|
for (i = 0; i < p->axes; i++) {
|
|
char mapkey[50];
|
|
char *mapval;
|
|
|
|
snprintf(mapkey, sizeof(mapkey), "Map_Axis%dneg", i+1);
|
|
mapval = drvthis->config_get_string(drvthis->name, mapkey, 0, NULL);
|
|
if (mapval != NULL) {
|
|
p->axismap[2*i] = strdup(mapval);
|
|
report(RPT_DEBUG, "%s: map Axis%dneg to %s",
|
|
drvthis->name, i+1, p->axismap[2*i]);
|
|
}
|
|
|
|
snprintf(mapkey, sizeof(mapkey), "Map_Axis%dpos", i+1);
|
|
mapval = drvthis->config_get_string(drvthis->name, mapkey, 0, NULL);
|
|
if (mapval != NULL) {
|
|
p->axismap[2*i + 1] = strdup(mapval);
|
|
report(RPT_DEBUG, "%s: map Axis%dpos to %s",
|
|
drvthis->name, i+1, p->axismap[2*i + 1]);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < p->buttons; i++) {
|
|
char mapkey[50];
|
|
char *mapval;
|
|
|
|
snprintf(mapkey, sizeof(mapkey), "Map_Button%d", i+1);
|
|
mapval = drvthis->config_get_string(drvthis->name, mapkey, 0, NULL);
|
|
if (mapval != NULL) {
|
|
p->buttonmap[i] = strdup(mapval);
|
|
report(RPT_DEBUG, "%s: map Button%d to %s",
|
|
drvthis->name, i+1, p->buttonmap[i]);
|
|
}
|
|
}
|
|
|
|
/* End of config file parsing (2nd part) */
|
|
|
|
report(RPT_DEBUG, "%s: init() done", drvthis->name);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
MODULE_EXPORT void
|
|
joy_close (Driver *drvthis)
|
|
{
|
|
PrivateData *p = drvthis->private_data;
|
|
|
|
if (p != NULL) {
|
|
if (p->fd >= 0)
|
|
close(p->fd);
|
|
|
|
if (p->axismap != NULL)
|
|
free(p->axismap);
|
|
if (p->buttonmap != NULL)
|
|
free(p->buttonmap);
|
|
|
|
free(p);
|
|
}
|
|
drvthis->store_private_ptr(drvthis, NULL);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Tries to read a character from an input device...
|
|
//
|
|
// Return NULL0 for "nothing available".
|
|
//
|
|
MODULE_EXPORT const char *
|
|
joy_get_key (Driver *drvthis)
|
|
{
|
|
PrivateData *p = drvthis->private_data;
|
|
struct js_event js;
|
|
int err;
|
|
|
|
if ((err = read(p->fd, &js, sizeof(struct js_event))) <= 0) {
|
|
return NULL;
|
|
}
|
|
if (err != sizeof(struct js_event)) {
|
|
report(RPT_ERR, "%s: error reading joystick input", drvthis->name);
|
|
return NULL;
|
|
}
|
|
|
|
switch (js.type & ~JS_EVENT_INIT) {
|
|
case JS_EVENT_BUTTON:
|
|
/* ignore button release */
|
|
if ((js.value == 0) || (js.number >= p->buttons))
|
|
return NULL;
|
|
return p->buttonmap[js.number];
|
|
case JS_EVENT_AXIS:
|
|
/* ignore noise */
|
|
if (((js.value > -20000) && (js.value < 20000))
|
|
|| (js.number >= 2 * p->axes))
|
|
return NULL;
|
|
return p->axismap[js.number];
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|