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