/* * 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 #include #include #include #include #include #include #include #include #include #include #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]; const 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]; const 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; } }