X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fx11%2Ffg_joystick_x11.c;h=bb21d7e538587664c5a21a59435f95a1707ebde9;hb=85fe5ac7b6efe580eab22820aa740a4b2dcafb0c;hp=1815577f3cc8cc372b40e8ddf5cc5141d16e4c5b;hpb=0e653a9d94fec583f7a4172b721c1c599e06cbc8;p=freeglut diff --git a/src/x11/fg_joystick_x11.c b/src/x11/fg_joystick_x11.c index 1815577..bb21d7e 100644 --- a/src/x11/fg_joystick_x11.c +++ b/src/x11/fg_joystick_x11.c @@ -1,5 +1,5 @@ /* - * freeglut_joystick_x11.c + * fg_joystick_x11.c * * Joystick handling code * @@ -39,16 +39,259 @@ # include #endif +#include + + +/* BSD defines from "jsBSD.cxx" around lines 42-270 */ + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + +# ifdef HAVE_USB_JS +# if defined(__NetBSD__) +# ifdef HAVE_USBHID_H +# include +# else +# include +# endif +# include +# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +# ifdef HAVE_USBHID_H +# include +# else +# include +# endif +# include +# endif +# include + +/* Compatibility with older usb.h revisions */ +# if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES) +# define USB_MAX_DEVNAMES MAXDEVNAMES +# endif +# endif + +struct os_specific_s { + char fname [128 ]; + int fd; + int is_analog; + /* The following structure members are specific to analog joysticks */ + struct joystick ajs; +# ifdef HAVE_USB_JS + /* The following structure members are specific to USB joysticks */ + struct hid_item *hids; + int hid_dlen; + int hid_offset; + char *hid_data_buf; + int axes_usage [ _JS_MAX_AXES ]; +# endif + /* We keep button and axes state ourselves, as they might not be updated + * on every read of a USB device + */ + int cache_buttons; + float cache_axes [ _JS_MAX_AXES ]; +}; + +/* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */ +# define USB_IDENT_OFFSET 2 + +# define USBDEV "/dev/usb" +# define UHIDDEV "/dev/uhid" +# define AJSDEV "/dev/joy" + + +#endif + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +static int hatmap_x[9] = {0, 0, 1, 1, 1, 0, -1, -1, -1}; +static int hatmap_y[9] = {0, 1, 1, 0, -1, -1, -1, 0, 1}; + +# ifdef HAVE_USB_JS +/* +* fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate +* the full name of a USB device. If /dev/usbN isn't readable, we punt and +* return the uhidN device name. We warn the user of this situation once. +*/ +static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen) +{ + struct usb_device_info di; + int i, a; + char *cp; + + for (a = 1; a < USB_MAX_DEVICES; a++) { + di.udi_addr = a; + if (ioctl(f, USB_DEVICEINFO, &di) != 0) + return NULL; + for (i = 0; i < USB_MAX_DEVNAMES; i++) + if (di.udi_devnames[i][0] && + strcmp(di.udi_devnames[i], dev) == 0) { + cp = calloc(1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2); + strcpy(cp, di.udi_vendor); + strcat(cp, " "); + strcat(cp, di.udi_product); + strncpy(out, cp, outlen - 1); + out[outlen - 1] = 0; + free(cp); + return out; + } + } + return NULL; +} + +static int fghJoystickFindUSBdev(char *name, char *out, int outlen) +{ + int i, f; + char buf[50]; + char *cp; + static int protection_warned = 0; + + for (i = 0; i < 16; i++) { + snprintf(buf, sizeof(buf), "%s%d", USBDEV, i); + f = open(buf, O_RDONLY); + if (f >= 0) { + cp = fghJoystickWalkUSBdev(f, name, out, outlen); + close(f); + if (cp) + return 1; + } + else if (errno == EACCES) { + if (!protection_warned) { + fgWarning("Can't open %s for read!", buf); + protection_warned = 1; + } + } + } + return 0; +} +#endif + +static int fghJoystickInitializeHID(struct os_specific_s *os, + int *num_axes, int *num_buttons) +{ + int size, is_joystick; +# ifdef HAVE_USBHID_H + int report_id = 0; +# endif + struct hid_data *d; + struct hid_item h; + report_desc_t rd; + + if ((rd = hid_get_report_desc(os->fd)) == 0) + { + fgWarning("error: %s: %s", os->fname, strerror(errno)); + return FALSE; + } + + os->hids = NULL; + +# ifdef HAVE_USBHID_H + if (ioctl(os->fd, USB_GET_REPORT_ID, &report_id) < 0) + { + /*** XXX {report_id} may not be the right variable? ***/ + fgWarning("error: %s%d: %s", UHIDDEV, report_id, strerror(errno)); + return FALSE; + } + + size = hid_report_size(rd, hid_input, report_id); +# else + size = hid_report_size(rd, 0, hid_input); +# endif + os->hid_data_buf = calloc(1, size); + os->hid_dlen = size; + + is_joystick = 0; +# ifdef HAVE_USBHID_H + d = hid_start_parse(rd, 1 << hid_input, report_id); +# else + d = hid_start_parse(rd, 1 << hid_input); +# endif + while (hid_get_item(d, &h)) + { + int usage, page, interesting_hid; + + page = HID_PAGE(h.usage); + usage = HID_USAGE(h.usage); + + /* This test is somewhat too simplistic, but this is how MicroSoft + * does, so I guess it works for all joysticks/game pads. */ + is_joystick = is_joystick || + (h.kind == hid_collection && + page == HUP_GENERIC_DESKTOP && + (usage == HUG_JOYSTICK || usage == HUG_GAME_PAD)); + + if (h.kind != hid_input) + continue; + + if (!is_joystick) + continue; + + interesting_hid = TRUE; + if (page == HUP_GENERIC_DESKTOP) + { + switch (usage) + { + case HUG_X: + case HUG_RX: + case HUG_Y: + case HUG_RY: + case HUG_Z: + case HUG_RZ: + case HUG_SLIDER: + if (*num_axes < _JS_MAX_AXES) + { + os->axes_usage[*num_axes] = usage; + (*num_axes)++; + } + break; + case HUG_HAT_SWITCH: + /* Allocate two axes for a hat */ + if (*num_axes + 1 < _JS_MAX_AXES) + { + os->axes_usage[*num_axes] = usage; + (*num_axes)++; + os->axes_usage[*num_axes] = usage; + (*num_axes)++; + } + break; + default: + interesting_hid = FALSE; + break; + } + } + else if (page == HUP_BUTTON) + { + interesting_hid = (usage > 0) && + (usage <= _JS_MAX_BUTTONS); + + if (interesting_hid && usage - 1 > *num_buttons) + *num_buttons = usage - 1; + } + + if (interesting_hid) + { + h.next = os->hids; + os->hids = calloc(1, sizeof(struct hid_item)); + *os->hids = h; + } + } + hid_end_parse(d); + + return os->hids != NULL; +} +# endif +#endif + /*this should be defined in a header file */ -#define MAX_NUM_JOYSTICKS 2 +#define MAX_NUM_JOYSTICKS 2 extern SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ]; void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes ) { int status; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) int len; if ( joy->pJoystick.os->is_analog ) @@ -115,11 +358,7 @@ void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes ) } } } -# ifdef HAVE_ERRNO_H if ( len < 0 && errno != EAGAIN ) -# else - if ( len < 0 ) -# endif { perror( joy->pJoystick.os->fname ); joy->error = 1; @@ -138,7 +377,6 @@ void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes ) if ( status != sizeof( struct js_event ) ) { -# ifdef HAVE_ERRNO_H if ( errno == EAGAIN ) { /* Use the old values */ @@ -149,7 +387,6 @@ void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes ) sizeof( float ) * joy->num_axes ); return; } -# endif fgWarning ( "%s", joy->pJoystick.fname ); joy->error = GL_TRUE; @@ -219,21 +456,21 @@ void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes ) void fgPlatformJoystickOpen( SFG_Joystick* joy ) { -#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ ) - int i = 0; +#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) + int i = 0; char *cp; #endif #ifdef JS_NEW unsigned char u; - int i=0; + int i=0; #else # if defined( __linux__ ) || TARGET_HOST_SOLARIS - int i = 0; + int i = 0; int counter = 0; # endif #endif -#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ ) +#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) for( i = 0; i < _JS_MAX_AXES; i++ ) joy->pJoystick.os->cache_axes[ i ] = 0.0f; @@ -241,10 +478,8 @@ void fgPlatformJoystickOpen( SFG_Joystick* joy ) joy->pJoystick.os->fd = open( joy->pJoystick.os->fname, O_RDONLY | O_NONBLOCK); -#ifdef HAVE_ERRNO_H if( joy->pJoystick.os->fd < 0 && errno == EACCES ) fgWarning ( "%s exists but is not readable by you", joy->pJoystick.os->fname ); -#endif joy->error =( joy->pJoystick.os->fd < 0 ); @@ -364,12 +599,12 @@ void fgPlatformJoystickOpen( SFG_Joystick* joy ) * to the upper byte of an uninitialized word doesn't work. * 9 April 2003 */ - ioctl( joy->pJoystick.fd, JSIOCGAXES, &u ); - joy->num_axes = u; - ioctl( joy->pJoystick.fd, JSIOCGBUTTONS, &u ); - joy->num_buttons = u; + if(ioctl(joy->pJoystick.fd, JSIOCGAXES, &u) != -1) + joy->num_axes = u; + if(ioctl(joy->pJoystick.fd, JSIOCGBUTTONS, &u) != -1) + joy->num_buttons = u; ioctl( joy->pJoystick.fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name ); - fcntl( joy->pJoystick.fd, F_SETFL, O_NONBLOCK ); + fcntl(joy->pJoystick.fd, F_SETFL, fcntl(joy->pJoystick.fd, F_GETFL) | O_NONBLOCK); # endif /* @@ -415,7 +650,7 @@ void fgPlatformJoystickOpen( SFG_Joystick* joy ) void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident ) { -#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ ) +#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) fgJoystick[ ident ]->id = ident; fgJoystick[ ident ]->error = GL_FALSE; @@ -442,7 +677,7 @@ void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident ) void fgPlatformJoystickClose ( int ident ) { -#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ ) +#if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) if( fgJoystick[ident]->pJoystick.os ) { if( ! fgJoystick[ ident ]->error ) @@ -454,7 +689,7 @@ void fgPlatformJoystickClose ( int ident ) free( fgJoystick[ ident ]->pJoystick.os->hid_data_buf ); #endif free( fgJoystick[ident]->pJoystick.os ); - } + } #endif if( ! fgJoystick[ident]->error )