renamed all references to freeglut_xxx files (their old names) to fg_xxx
[freeglut] / src / x11 / fg_joystick_x11.c
1 /*
2  * fg_joystick_x11.c
3  *
4  * Joystick handling code
5  *
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
10  *
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:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
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.
27  */
28
29 /*
30  * FreeBSD port by Stephen Montgomery-Smith <stephen@math.missouri.edu>
31  *
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.
34  */
35
36 #include <GL/freeglut.h>
37 #include "../fg_internal.h"
38 #ifdef HAVE_SYS_PARAM_H
39 #    include <sys/param.h>
40 #endif
41
42
43 /*this should be defined in a header file */
44 #define MAX_NUM_JOYSTICKS  2   
45 extern SFG_Joystick *fgJoystick [ MAX_NUM_JOYSTICKS ];
46
47 void fgPlatformJoystickRawRead( SFG_Joystick* joy, int* buttons, float* axes )
48 {
49     int status;
50
51 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
52     int len;
53
54     if ( joy->pJoystick.os->is_analog )
55     {
56         int status = read ( joy->pJoystick.os->fd, &joy->pJoystick.os->ajs, sizeof(joy->pJoystick.os->ajs) );
57         if ( status != sizeof(joy->pJoystick.os->ajs) ) {
58             perror ( joy->pJoystick.os->fname );
59             joy->error = GL_TRUE;
60             return;
61         }
62         if ( buttons != NULL )
63             *buttons = ( joy->pJoystick.os->ajs.b1 ? 1 : 0 ) | ( joy->pJoystick.os->ajs.b2 ? 2 : 0 );
64
65         if ( axes != NULL )
66         {
67             axes[0] = (float) joy->pJoystick.os->ajs.x;
68             axes[1] = (float) joy->pJoystick.os->ajs.y;
69         }
70
71         return;
72     }
73
74 #  ifdef HAVE_USB_JS
75     while ( ( len = read ( joy->pJoystick.os->fd, joy->pJoystick.os->hid_data_buf, joy->pJoystick.os->hid_dlen ) ) == joy->pJoystick.os->hid_dlen )
76     {
77         struct hid_item *h;
78
79         for  ( h = joy->pJoystick.os->hids; h; h = h->next )
80         {
81             int d = hid_get_data ( joy->pJoystick.os->hid_data_buf, h );
82
83             int page = HID_PAGE ( h->usage );
84             int usage = HID_USAGE ( h->usage );
85
86             if ( page == HUP_GENERIC_DESKTOP )
87             {
88                 int i;
89                 for ( i = 0; i < joy->num_axes; i++ )
90                     if (joy->pJoystick.os->axes_usage[i] == usage)
91                     {
92                         if (usage == HUG_HAT_SWITCH)
93                         {
94                             if (d < 0 || d > 8)
95                                 d = 0;  /* safety */
96                             joy->pJoystick.os->cache_axes[i] = (float)hatmap_x[d];
97                             joy->pJoystick.os->cache_axes[i + 1] = (float)hatmap_y[d];
98                         }
99                         else
100                         {
101                             joy->pJoystick.os->cache_axes[i] = (float)d;
102                         }
103                         break;
104                     }
105             }
106             else if (page == HUP_BUTTON)
107             {
108                if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
109                {
110                    if (d)
111                        joy->pJoystick.os->cache_buttons |=  (1 << ( usage - 1 ));
112                    else
113                        joy->pJoystick.os->cache_buttons &= ~(1 << ( usage - 1 ));
114                }
115             }
116         }
117     }
118 #    ifdef HAVE_ERRNO_H
119     if ( len < 0 && errno != EAGAIN )
120 #    else
121     if ( len < 0 )
122 #    endif
123     {
124         perror( joy->pJoystick.os->fname );
125         joy->error = 1;
126     }
127     if ( buttons != NULL ) *buttons = joy->pJoystick.os->cache_buttons;
128     if ( axes    != NULL )
129         memcpy ( axes, joy->pJoystick.os->cache_axes, sizeof(float) * joy->num_axes );
130 #  endif
131 #endif
132
133 #ifdef JS_NEW
134
135     while ( 1 )
136     {
137         status = read ( joy->pJoystick.fd, &joy->pJoystick.js, sizeof(struct js_event) );
138
139         if ( status != sizeof( struct js_event ) )
140         {
141 #  ifdef HAVE_ERRNO_H
142             if ( errno == EAGAIN )
143             {
144                 /* Use the old values */
145                 if ( buttons )
146                     *buttons = joy->pJoystick.tmp_buttons;
147                 if ( axes )
148                     memcpy( axes, joy->pJoystick.tmp_axes,
149                             sizeof( float ) * joy->num_axes );
150                 return;
151             }
152 #  endif
153
154             fgWarning ( "%s", joy->pJoystick.fname );
155             joy->error = GL_TRUE;
156             return;
157         }
158
159         switch ( joy->pJoystick.js.type & ~JS_EVENT_INIT )
160         {
161         case JS_EVENT_BUTTON:
162             if( joy->pJoystick.js.value == 0 ) /* clear the flag */
163                 joy->pJoystick.tmp_buttons &= ~( 1 << joy->pJoystick.js.number );
164             else
165                 joy->pJoystick.tmp_buttons |= ( 1 << joy->pJoystick.js.number );
166             break;
167
168         case JS_EVENT_AXIS:
169             if ( joy->pJoystick.js.number < joy->num_axes )
170             {
171                 joy->pJoystick.tmp_axes[ joy->pJoystick.js.number ] = ( float )joy->pJoystick.js.value;
172
173                 if( axes )
174                     memcpy( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );
175             }
176             break;
177
178         default:
179             fgWarning ( "PLIB_JS: Unrecognised /dev/js return!?!" );
180
181             /* use the old values */
182
183             if ( buttons != NULL ) *buttons = joy->pJoystick.tmp_buttons;
184             if ( axes    != NULL )
185                 memcpy ( axes, joy->pJoystick.tmp_axes, sizeof(float) * joy->num_axes );
186
187             return;
188         }
189
190         if( buttons )
191             *buttons = joy->pJoystick.tmp_buttons;
192     }
193 #else
194
195     status = read( joy->pJoystick.fd, &joy->pJoystick.js, JS_RETURN );
196
197     if ( status != JS_RETURN )
198     {
199         fgWarning( "%s", joy->pJoystick.fname );
200         joy->error = GL_TRUE;
201         return;
202     }
203
204     if ( buttons )
205 #    if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
206         *buttons = ( joy->pJoystick.js.b1 ? 1 : 0 ) | ( joy->pJoystick.js.b2 ? 2 : 0 );  /* XXX Should not be here -- BSD is handled earlier */
207 #    else
208         *buttons = joy->pJoystick.js.buttons;
209 #    endif
210
211     if ( axes )
212     {
213         axes[ 0 ] = (float) joy->pJoystick.js.x;
214         axes[ 1 ] = (float) joy->pJoystick.js.y;
215     }
216 #endif
217 }
218
219
220 void fgPlatformJoystickOpen( SFG_Joystick* joy )
221 {
222 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
223         int i = 0;
224        char *cp;
225 #endif
226 #ifdef JS_NEW
227        unsigned char u;
228         int i=0;
229 #else
230 #  if defined( __linux__ ) || TARGET_HOST_SOLARIS
231         int i = 0;
232     int counter = 0;
233 #  endif
234 #endif
235
236 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
237     for( i = 0; i < _JS_MAX_AXES; i++ )
238         joy->pJoystick.os->cache_axes[ i ] = 0.0f;
239
240     joy->pJoystick.os->cache_buttons = 0;
241
242     joy->pJoystick.os->fd = open( joy->pJoystick.os->fname, O_RDONLY | O_NONBLOCK);
243
244 #ifdef HAVE_ERRNO_H
245     if( joy->pJoystick.os->fd < 0 && errno == EACCES )
246         fgWarning ( "%s exists but is not readable by you", joy->pJoystick.os->fname );
247 #endif
248
249     joy->error =( joy->pJoystick.os->fd < 0 );
250
251     if( joy->error )
252         return;
253
254     joy->num_axes = 0;
255     joy->num_buttons = 0;
256     if( joy->pJoystick.os->is_analog )
257     {
258         FILE *joyfile;
259         char joyfname[ 1024 ];
260         int noargs, in_no_axes;
261
262         float axes [ _JS_MAX_AXES ];
263         int buttons[ _JS_MAX_AXES ];
264
265         joy->num_axes    =  2;
266         joy->num_buttons = 32;
267
268         fghJoystickRawRead( joy, buttons, axes );
269         joy->error = axes[ 0 ] < -1000000000.0f;
270         if( joy->error )
271             return;
272
273         snprintf( joyfname, sizeof(joyfname), "%s/.joy%drc", getenv( "HOME" ), joy->id );
274
275         joyfile = fopen( joyfname, "r" );
276         joy->error =( joyfile == NULL );
277         if( joy->error )
278             return;
279
280         noargs = fscanf( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
281                          &joy->min[ 0 ], &joy->center[ 0 ], &joy->max[ 0 ],
282                          &joy->min[ 1 ], &joy->center[ 1 ], &joy->max[ 1 ] );
283         joy->error = noargs != 7 || in_no_axes != _JS_MAX_AXES;
284         fclose( joyfile );
285         if( joy->error )
286             return;
287
288         for( i = 0; i < _JS_MAX_AXES; i++ )
289         {
290             joy->dead_band[ i ] = 0.0f;
291             joy->saturate [ i ] = 1.0f;
292         }
293
294         return;    /* End of analog code */
295     }
296
297 #    ifdef HAVE_USB_JS
298     if( ! fghJoystickInitializeHID( joy->pJoystick.os, &joy->num_axes,
299                                     &joy->num_buttons ) )
300     {
301         close( joy->pJoystick.os->fd );
302         joy->error = GL_TRUE;
303         return;
304     }
305
306     cp = strrchr( joy->pJoystick.os->fname, '/' );
307     if( cp )
308     {
309         if( fghJoystickFindUSBdev( &cp[1], joy->name, sizeof( joy->name ) ) ==
310             0 )
311             strcpy( joy->name, &cp[1] );
312     }
313
314     if( joy->num_axes > _JS_MAX_AXES )
315         joy->num_axes = _JS_MAX_AXES;
316
317     for( i = 0; i < _JS_MAX_AXES; i++ )
318     {
319         /* We really should get this from the HID, but that data seems
320          * to be quite unreliable for analog-to-USB converters. Punt for
321          * now.
322          */
323         if( joy->pJoystick.os->axes_usage[ i ] == HUG_HAT_SWITCH )
324         {
325             joy->max   [ i ] = 1.0f;
326             joy->center[ i ] = 0.0f;
327             joy->min   [ i ] = -1.0f;
328         }
329         else
330         {
331             joy->max   [ i ] = 255.0f;
332             joy->center[ i ] = 127.0f;
333             joy->min   [ i ] = 0.0f;
334         }
335
336         joy->dead_band[ i ] = 0.0f;
337         joy->saturate[ i ] = 1.0f;
338     }
339 #    endif
340 #endif
341
342 #if defined( __linux__ ) || TARGET_HOST_SOLARIS
343     /* Default for older Linux systems. */
344     joy->num_axes    =  2;
345     joy->num_buttons = 32;
346
347 #    ifdef JS_NEW
348     for( i = 0; i < _JS_MAX_AXES; i++ )
349         joy->pJoystick.tmp_axes[ i ] = 0.0f;
350
351     joy->pJoystick.tmp_buttons = 0;
352 #    endif
353
354     joy->pJoystick.fd = open( joy->pJoystick.fname, O_RDONLY );
355
356     joy->error =( joy->pJoystick.fd < 0 );
357
358     if( joy->error )
359         return;
360
361     /* Set the correct number of axes for the linux driver */
362 #    ifdef JS_NEW
363     /* Melchior Franz's fixes for big-endian Linuxes since writing
364      *  to the upper byte of an uninitialized word doesn't work.
365      *  9 April 2003
366      */
367     ioctl( joy->pJoystick.fd, JSIOCGAXES, &u );
368     joy->num_axes = u;
369     ioctl( joy->pJoystick.fd, JSIOCGBUTTONS, &u );
370     joy->num_buttons = u;
371     ioctl( joy->pJoystick.fd, JSIOCGNAME( sizeof( joy->name ) ), joy->name );
372     fcntl( joy->pJoystick.fd, F_SETFL, O_NONBLOCK );
373 #    endif
374
375     /*
376      * The Linux driver seems to return 512 for all axes
377      * when no stick is present - but there is a chance
378      * that could happen by accident - so it's gotta happen
379      * on both axes for at least 100 attempts.
380      *
381      * PWO: shouldn't be that done somehow wiser on the kernel level?
382      */
383 #    ifndef JS_NEW
384     counter = 0;
385
386     do
387     {
388         fghJoystickRawRead( joy, NULL, joy->center );
389         counter++;
390     } while( !joy->error &&
391              counter < 100 &&
392              joy->center[ 0 ] == 512.0f &&
393              joy->center[ 1 ] == 512.0f );
394
395     if ( counter >= 100 )
396         joy->error = GL_TRUE;
397 #    endif
398
399     for( i = 0; i < _JS_MAX_AXES; i++ )
400     {
401 #    ifdef JS_NEW
402         joy->max   [ i ] =  32767.0f;
403         joy->center[ i ] =      0.0f;
404         joy->min   [ i ] = -32767.0f;
405 #    else
406         joy->max[ i ] = joy->center[ i ] * 2.0f;
407         joy->min[ i ] = 0.0f;
408 #    endif
409         joy->dead_band[ i ] = 0.0f;
410         joy->saturate [ i ] = 1.0f;
411     }
412 #endif
413 }
414
415
416 void fgPlatformJoystickInit( SFG_Joystick *fgJoystick[], int ident )
417 {
418 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
419     fgJoystick[ ident ]->id = ident;
420     fgJoystick[ ident ]->error = GL_FALSE;
421
422     fgJoystick[ ident ]->pJoystick.os = calloc( 1, sizeof( struct os_specific_s ) );
423     memset( fgJoystick[ ident ]->pJoystick.os, 0, sizeof( struct os_specific_s ) );
424     if( ident < USB_IDENT_OFFSET )
425         fgJoystick[ ident ]->pJoystick.os->is_analog = 1;
426     if( fgJoystick[ ident ]->pJoystick.os->is_analog )
427         snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", AJSDEV, ident );
428     else
429         snprintf( fgJoystick[ ident ]->pJoystick.os->fname, sizeof(fgJoystick[ ident ]->pJoystick.os->fname), "%s%d", UHIDDEV,
430                  ident - USB_IDENT_OFFSET );
431 #elif defined( __linux__ )
432     fgJoystick[ ident ]->id = ident;
433     fgJoystick[ ident ]->error = GL_FALSE;
434
435     snprintf( fgJoystick[ident]->pJoystick.fname, sizeof(fgJoystick[ident]->pJoystick.fname), "/dev/input/js%d", ident );
436
437     if( access( fgJoystick[ ident ]->pJoystick.fname, F_OK ) != 0 )
438         snprintf( fgJoystick[ ident ]->pJoystick.fname, sizeof(fgJoystick[ ident ]->pJoystick.fname), "/dev/js%d", ident );
439 #endif
440 }
441
442
443 void fgPlatformJoystickClose ( int ident )
444 {
445 #if defined( __FreeBSD__ ) || defined(__FreeBSD_kernel__) || defined( __NetBSD__ )
446     if( fgJoystick[ident]->pJoystick.os )
447     {
448         if( ! fgJoystick[ ident ]->error )
449             close( fgJoystick[ ident ]->pJoystick.os->fd );
450 #ifdef HAVE_USB_JS
451         if( fgJoystick[ ident ]->pJoystick.os->hids )
452             free (fgJoystick[ ident ]->pJoystick.os->hids);
453         if( fgJoystick[ ident ]->pJoystick.os->hid_data_buf )
454             free( fgJoystick[ ident ]->pJoystick.os->hid_data_buf );
455 #endif
456         free( fgJoystick[ident]->pJoystick.os );
457         }
458 #endif
459
460     if( ! fgJoystick[ident]->error )
461          close( fgJoystick[ ident ]->pJoystick.fd );
462 }
463