/*
- * freeglut_joystick_x11.c
+ * fg_joystick_x11.c
*
* Joystick handling code
*
# include <sys/param.h>
#endif
+#include <fcntl.h>
+
+
+#if defined(__NetBSD__) || 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;
+}
+
+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 )
}
}
}
-# ifdef HAVE_ERRNO_H
if ( len < 0 && errno != EAGAIN )
-# else
- if ( len < 0 )
-# endif
{
perror( joy->pJoystick.os->fname );
joy->error = 1;
if ( status != sizeof( struct js_event ) )
{
-# ifdef HAVE_ERRNO_H
if ( errno == EAGAIN )
{
/* Use the old values */
sizeof( float ) * joy->num_axes );
return;
}
-# endif
fgWarning ( "%s", joy->pJoystick.fname );
joy->error = GL_TRUE;
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;
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 );
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;
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 )
free( fgJoystick[ ident ]->pJoystick.os->hid_data_buf );
#endif
free( fgJoystick[ident]->pJoystick.os );
- }
+ }
#endif
if( ! fgJoystick[ident]->error )