4 * Joystick handling code
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Steve Baker, <sjbaker1@airmail.net>
8 * Copied for Platform code by Evan Felix <karcaw at gmail.com>
9 * Creation date: Thur Feb 2 2012
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
32 * Redone by John Fay 2/4/04 with another look from the PLIB "js" library.
33 * Many thanks for Steve Baker for permission to pull from that library.
36 #include <GL/freeglut.h>
37 #include "../fg_internal.h"
38 #ifdef HAVE_SYS_PARAM_H
39 # include <sys/param.h>
45 /* BSD defines from "jsBSD.cxx" around lines 42-270 */
47 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
50 # if defined(__NetBSD__)
56 # include <dev/usb/usb.h>
57 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
61 # include <libusbhid.h>
63 # include <legacy/dev/usb/usb.h>
65 # include <dev/usb/usbhid.h>
67 /* Compatibility with older usb.h revisions */
68 # if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
69 # define USB_MAX_DEVNAMES MAXDEVNAMES
73 struct os_specific_s {
77 /* The following structure members are specific to analog joysticks */
80 /* The following structure members are specific to USB joysticks */
81 struct hid_item *hids;
85 int axes_usage [ _JS_MAX_AXES ];
87 /* We keep button and axes state ourselves, as they might not be updated
88 * on every read of a USB device
91 float cache_axes [ _JS_MAX_AXES ];
94 /* Idents lower than USB_IDENT_OFFSET are for analog joysticks. */
95 # define USB_IDENT_OFFSET 2
97 # define USBDEV "/dev/usb"
98 # define UHIDDEV "/dev/uhid"
99 # define AJSDEV "/dev/joy"
104 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
106 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
107 static int hatmap_x[9] = {0, 0, 1, 1, 1, 0, -1, -1, -1};
108 static int hatmap_y[9] = {0, 1, 1, 0, -1, -1, -1, 0, 1};
112 * fghJoystickFindUSBdev (and its helper, fghJoystickWalkUSBdev) try to locate
113 * the full name of a USB device. If /dev/usbN isn't readable, we punt and
114 * return the uhidN device name. We warn the user of this situation once.
116 static char *fghJoystickWalkUSBdev(int f, char *dev, char *out, int outlen)
118 struct usb_device_info di;
122 for (a = 1; a < USB_MAX_DEVICES; a++) {
124 if (ioctl(f, USB_DEVICEINFO, &di) != 0)
126 for (i = 0; i < USB_MAX_DEVNAMES; i++)
127 if (di.udi_devnames[i][0] &&
128 strcmp(di.udi_devnames[i], dev) == 0) {
129 cp = calloc(1, strlen(di.udi_vendor) + strlen(di.udi_product) + 2);
130 strcpy(cp, di.udi_vendor);
132 strcat(cp, di.udi_product);
133 strncpy(out, cp, outlen - 1);
142 static int fghJoystickFindUSBdev(char *name, char *out, int outlen)
147 static int protection_warned = 0;
149 for (i = 0; i < 16; i++) {
150 snprintf(buf, sizeof(buf), "%s%d", USBDEV, i);
151 f = open(buf, O_RDONLY);
153 cp = fghJoystickWalkUSBdev(f, name, out, outlen);
158 else if (errno == EACCES) {
159 if (!protection_warned) {
160 fgWarning("Can't open %s for read!", buf);
161 protection_warned = 1;
169 static int fghJoystickInitializeHID(struct os_specific_s *os,
170 int *num_axes, int *num_buttons)
172 int size, is_joystick;
173 # ifdef HAVE_USBHID_H
180 if ((rd = hid_get_report_desc(os->fd)) == 0)
182 fgWarning("error: %s: %s", os->fname, strerror(errno));
188 # ifdef HAVE_USBHID_H
189 if (ioctl(os->fd, USB_GET_REPORT_ID, &report_id) < 0)
191 /*** XXX {report_id} may not be the right variable? ***/
192 fgWarning("error: %s%d: %s", UHIDDEV, report_id, strerror(errno));
196 size = hid_report_size(rd, hid_input, report_id);
198 size = hid_report_size(rd, 0, hid_input);
200 os->hid_data_buf = calloc(1, size);
204 # ifdef HAVE_USBHID_H
205 d = hid_start_parse(rd, 1 << hid_input, report_id);
207 d = hid_start_parse(rd, 1 << hid_input);
209 while (hid_get_item(d, &h))
211 int usage, page, interesting_hid;
213 page = HID_PAGE(h.usage);
214 usage = HID_USAGE(h.usage);
216 /* This test is somewhat too simplistic, but this is how MicroSoft
217 * does, so I guess it works for all joysticks/game pads. */
218 is_joystick = is_joystick ||
219 (h.kind == hid_collection &&
220 page == HUP_GENERIC_DESKTOP &&
221 (usage == HUG_JOYSTICK || usage == HUG_GAME_PAD));
223 if (h.kind != hid_input)
229 interesting_hid = TRUE;
230 if (page == HUP_GENERIC_DESKTOP)
241 if (*num_axes < _JS_MAX_AXES)
243 os->axes_usage[*num_axes] = usage;
248 /* Allocate two axes for a hat */
249 if (*num_axes + 1 < _JS_MAX_AXES)
251 os->axes_usage[*num_axes] = usage;
253 os->axes_usage[*num_axes] = usage;
258 interesting_hid = FALSE;
262 else if (page == HUP_BUTTON)
264 interesting_hid = (usage > 0) &&
265 (usage <= _JS_MAX_BUTTONS);
267 if (interesting_hid && usage - 1 > *num_buttons)
268 *num_buttons = usage - 1;
274 os->hids = calloc(1, sizeof(struct hid_item));
280 return os->hids != NULL;
286 /*this should be defined in a header file */
287 #define MAX_NUM_JOYSTICKS 2
288 extern SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
290 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
294 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
297 if ( joy->pJoystick.os->is_analog )
299 int status = read ( joy->pJoystick.os->fd, &joy->pJoystick.os->ajs, sizeof(joy->pJoystick.os->ajs) );
300 if ( status != sizeof(joy->pJoystick.os->ajs) ) {
301 perror ( joy->pJoystick.os->fname );
302 joy->error = GL_TRUE;
305 if ( buttons != NULL )
306 *buttons = ( joy->pJoystick.os->ajs.b1 ? 1 : 0 ) | ( joy->pJoystick.os->ajs.b2 ? 2 : 0 );
310 axes[0] = (float) joy->pJoystick.os->ajs.x;
311 axes[1] = (float) joy->pJoystick.os->ajs.y;
318 while ( ( len = read ( joy->pJoystick.os->fd, joy->pJoystick.os->hid_data_buf, joy->pJoystick.os->hid_dlen ) ) == joy->pJoystick.os->hid_dlen )
322 for ( h = joy->pJoystick.os->hids; h; h = h->next )
324 int d = hid_get_data ( joy->pJoystick.os->hid_data_buf, h );
326 int page = HID_PAGE ( h->usage );
327 int usage = HID_USAGE ( h->usage );
329 if ( page == HUP_GENERIC_DESKTOP )
332 for ( i = 0; i < joy->num_axes; i++ )
333 if (joy->pJoystick.os->axes_usage[i] == usage)
335 if (usage == HUG_HAT_SWITCH)
339 joy->pJoystick.os->cache_axes[i] = (float)hatmap_x[d];
340 joy->pJoystick.os->cache_axes[i + 1] = (float)hatmap_y[d];
344 joy->pJoystick.os->cache_axes[i] = (float)d;
349 else if (page == HUP_BUTTON)
351 if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
354 joy->pJoystick.os->cache_buttons |= (1 << ( usage - 1 ));
356 joy->pJoystick.os->cache_buttons &= ~(1 << ( usage - 1 ));
361 if ( len < 0 && errno != EAGAIN )
363 perror( joy->pJoystick.os->fname );
366 if ( buttons != NULL ) *buttons = joy->pJoystick.os->cache_buttons;
368 memcpy ( axes, joy->pJoystick.os->cache_axes, sizeof(float) * joy->num_axes );
376 status = read ( joy->pJoystick.fd, &joy->pJoystick.js, sizeof(struct js_event) );
378 if ( status != sizeof( struct js_event ) )
380 if ( errno == EAGAIN )
382 /* Use the old values */
384 *buttons = joy->pJoystick.tmp_buttons;
386 memcpy( axes, joy->pJoystick.tmp_axes,
387 sizeof( float ) * joy->num_axes );
391 fgWarning ( "%s", joy->pJoystick.fname );
392 joy->error = GL_TRUE;
396 switch ( joy->pJoystick.js.type & ~JS_EVENT_INIT )
398 case JS_EVENT_BUTTON:
399 if( joy->pJoystick.js.value == 0 ) /* clear the flag */
400 joy->pJoystick.tmp_buttons &= ~( 1 << joy->pJoystick.js.number );
402 joy->pJoystick.tmp_buttons |= ( 1 << joy->pJoystick.js.number );
406 if ( joy->pJoystick.js.number < joy->num_axes )
408 joy->pJoystick.tmp_axes[ joy->pJoystick.js.number ] = ( float )joy->pJoystick.js.value;
411 memcpy( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );
416 fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
418 /* use the old values */
420 if ( buttons != NULL ) *buttons = joy->pJoystick.tmp_buttons;
422 memcpy ( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );
428 *buttons = joy->pJoystick.tmp_buttons;
432 status = read( joy->pJoystick.fd, &joy->pJoystick.js, JS_RETURN );
434 if ( status != JS_RETURN )
436 fgWarning( "%s", joy->pJoystick.fname );
437 joy->error = GL_TRUE;
442 # if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
443 *buttons = ( joy->pJoystick.js.b1 ? 1 : 0 ) | ( joy->pJoystick.js.b2 ? 2 : 0 ); /* XXX Should not be here -- BSD is handled earlier */
445 *buttons = joy->pJoystick.js.buttons;
450 axes[ 0 ] = (float) joy->pJoystick.js.x;
451 axes[ 1 ] = (float) joy->pJoystick.js.y;
457 void fgPlatformJoystickOpen( SFG_Joystick* joy )
459 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__)
467 # if defined( __linux__ ) || TARGET_HOST_SOLARIS
473 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__)
474 for( i = 0; i < _JS_MAX_AXES; i++ )
475 joy->pJoystick.os->cache_axes[ i ] = 0.0f;
477 joy->pJoystick.os->cache_buttons = 0;
479 joy->pJoystick.os->fd = open( joy->pJoystick.os->fname, O_RDONLY | O_NONBLOCK);
481 if( joy->pJoystick.os->fd < 0 && errno == EACCES )
482 fgWarning ( "%s exists but is not readable by you", joy->pJoystick.os->fname );
484 joy->error =( joy->pJoystick.os->fd < 0 );
490 joy->num_buttons = 0;
491 if( joy->pJoystick.os->is_analog )
494 char joyfname[ 1024 ];
495 int noargs, in_no_axes;
497 float axes [ _JS_MAX_AXES ];
498 int buttons[ _JS_MAX_AXES ];
501 joy->num_buttons = 32;
503 fghJoystickRawRead( joy, buttons, axes );
504 joy->error = axes[ 0 ] < -1000000000.0f;
508 snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
510 joyfile = fopen( joyfname, "r" );
511 joy->error =( joyfile == NULL );
515 noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
516 &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
517 &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
518 joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
523 for( i = 0; i < _JS_MAX_AXES; i++ )
525 joy->dead_band[ i ] = 0.0f;
526 joy->saturate [ i ] = 1.0f;
529 return; /* End of analog code */
533 if( ! fghJoystickInitializeHID( joy->pJoystick.os, &joy->num_axes,
534 &joy->num_buttons ) )
536 close( joy->pJoystick.os->fd );
537 joy->error = GL_TRUE;
541 cp = strrchr( joy->pJoystick.os->fname, '/' );
544 if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
546 strcpy( joy->name, &cp[1] );
549 if( joy->num_axes > _JS_MAX_AXES )
550 joy->num_axes = _JS_MAX_AXES;
552 for( i = 0; i < _JS_MAX_AXES; i++ )
554 /* We really should get this from the HID, but that data seems
555 * to be quite unreliable for analog-to-USB converters. Punt for
558 if( joy->pJoystick.os->axes_usage[ i ] == HUG_HAT_SWITCH )
560 joy->max [ i ] = 1.0f;
561 joy->center[ i ] = 0.0f;
562 joy->min [ i ] = -1.0f;
566 joy->max [ i ] = 255.0f;
567 joy->center[ i ] = 127.0f;
568 joy->min [ i ] = 0.0f;
571 joy->dead_band[ i ] = 0.0f;
572 joy->saturate[ i ] = 1.0f;
577 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
578 /* Default for older Linux systems. */
580 joy->num_buttons = 32;
583 for( i = 0; i < _JS_MAX_AXES; i++ )
584 joy->pJoystick.tmp_axes[ i ] = 0.0f;
586 joy->pJoystick.tmp_buttons = 0;
589 joy->pJoystick.fd = open( joy->pJoystick.fname, O_RDONLY );
591 joy->error =( joy->pJoystick.fd < 0 );
596 /* Set the correct number of axes for the linux driver */
598 /* Melchior Franz's fixes for big-endian Linuxes since writing
599 * to the upper byte of an uninitialized word doesn't work.
602 ioctl( joy->pJoystick.fd, JSIOCGAXES, &u );
604 ioctl( joy->pJoystick.fd, JSIOCGBUTTONS, &u );
605 joy->num_buttons = u;
606 ioctl( joy->pJoystick.fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
607 fcntl( joy->pJoystick.fd, F_SETFL, O_NONBLOCK );
611 * The Linux driver seems to return 512 for all axes
612 * when no stick is present - but there is a chance
613 * that could happen by accident - so it's gotta happen
614 * on both axes for at least 100 attempts.
616 * PWO: shouldn't be that done somehow wiser on the kernel level?
623 fghJoystickRawRead( joy, NULL, joy->center );
625 } while( !joy->error &&
627 joy->center[ 0 ] == 512.0f &&
628 joy->center[ 1 ] == 512.0f );
630 if ( counter >= 100 )
631 joy->error = GL_TRUE;
634 for( i = 0; i < _JS_MAX_AXES; i++ )
637 joy->max [ i ] = 32767.0f;
638 joy->center[ i ] = 0.0f;
639 joy->min [ i ] = -32767.0f;
641 joy->max[ i ] = joy->center[ i ] * 2.0f;
642 joy->min[ i ] = 0.0f;
644 joy->dead_band[ i ] = 0.0f;
645 joy->saturate [ i ] = 1.0f;
651 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
653 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__)
654 fgJoystick[ ident ]->id = ident;
655 fgJoystick[ ident ]->error = GL_FALSE;
657 fgJoystick[ ident ]->pJoystick.os = calloc( 1, sizeof( struct os_specific_s ) );
658 memset( fgJoystick[ ident ]->pJoystick.os, 0, sizeof( struct os_specific_s ) );
659 if( ident < USB_IDENT_OFFSET )
660 fgJoystick[ ident ]->pJoystick.os->is_analog = 1;
661 if( fgJoystick[ ident ]->pJoystick.os->is_analog )
662 snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", AJSDEV, ident );
664 snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", UHIDDEV,
665 ident - USB_IDENT_OFFSET );
666 #elif defined( __linux__ )
667 fgJoystick[ ident ]->id = ident;
668 fgJoystick[ ident ]->error = GL_FALSE;
670 snprintf( fgJoystick[ident]->pJoystick.fname, sizeof(fgJoystick[ident]->pJoystick.fname), "/dev/input/js%d", ident );
672 if( access( fgJoystick[ ident ]->pJoystick.fname, F_OK ) != 0 )
673 snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident );
678 void fgPlatformJoystickClose ( int ident )
680 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__)
681 if( fgJoystick[ident]->pJoystick.os )
683 if( ! fgJoystick[ ident ]->error )
684 close( fgJoystick[ ident ]->pJoystick.os->fd );
686 if( fgJoystick[ ident ]->pJoystick.os->hids )
687 free (fgJoystick[ ident ]->pJoystick.os->hids);
688 if( fgJoystick[ ident ]->pJoystick.os->hid_data_buf )
689 free( fgJoystick[ ident ]->pJoystick.os->hid_data_buf );
691 free( fgJoystick[ident]->pJoystick.os );
695 if( ! fgJoystick[ident]->error )
696 close( fgJoystick[ ident ]->pJoystick.fd );