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__) || defined(__NetBSD__) |
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__) || defined( __NetBSD__ ) |
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__) || defined( __NetBSD__ ) |
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__) || defined( __NetBSD__ ) |
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__) || defined( __NetBSD__ ) |
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 | |
458 | |