1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * DOS joystick routines.
12 *
13 * By Shawn Hargreaves.
14 *
15 * Based on code provided by Jonathan Tarbox and Marcel de Kogel.
16 *
17 * CH Flightstick Pro and Logitech Wingman Extreme
18 * support by Fabian Nunez.
19 *
20 * Matthew Bowie added support for 4-button joysticks.
21 *
22 * Richard Mitton added support for 6-button joysticks.
23 *
24 * Stefan Eilert added support for dual joysticks.
25 *
26 * See readme.txt for copyright information.
27 */
28
29
30 #include "allegro.h"
31 #include "allegro/internal/aintern.h"
32 #include "allegro/platform/aintdos.h"
33
34 #ifndef ALLEGRO_DOS
35 #error something is wrong with the makefile
36 #endif
37
38
39
40 /* driver functions */
41 static int joy_init(void);
42 static void joy_exit(void);
43 static int joy_poll(void);
44 static int joy_save_data(void);
45 static int joy_load_data(void);
46 static AL_CONST char *joy_calibrate_name(int n);
47 static int joy_calibrate(int n);
48
49 static int poll(int *x, int *y, int *x2, int *y2, int poll_mask);
50
51
52
53 #define JOYSTICK_DRIVER_CONTENTS \
54 joy_init, \
55 joy_exit, \
56 joy_poll, \
57 joy_save_data, \
58 joy_load_data, \
59 joy_calibrate_name, \
60 joy_calibrate
61
62
63
64 JOYSTICK_DRIVER joystick_standard =
65 {
66 JOY_TYPE_STANDARD,
67 empty_string,
68 empty_string,
69 "Standard joystick",
70 JOYSTICK_DRIVER_CONTENTS
71 };
72
73
74
75 JOYSTICK_DRIVER joystick_2pads =
76 {
77 JOY_TYPE_2PADS,
78 empty_string,
79 empty_string,
80 "Dual joysticks",
81 JOYSTICK_DRIVER_CONTENTS
82 };
83
84
85
86 JOYSTICK_DRIVER joystick_4button =
87 {
88 JOY_TYPE_4BUTTON,
89 empty_string,
90 empty_string,
91 "4-button joystick",
92 JOYSTICK_DRIVER_CONTENTS
93 };
94
95
96
97 JOYSTICK_DRIVER joystick_6button =
98 {
99 JOY_TYPE_6BUTTON,
100 empty_string,
101 empty_string,
102 "6-button joystick",
103 JOYSTICK_DRIVER_CONTENTS
104 };
105
106
107
108 JOYSTICK_DRIVER joystick_8button =
109 {
110 JOY_TYPE_8BUTTON,
111 empty_string,
112 empty_string,
113 "8-button joystick",
114 JOYSTICK_DRIVER_CONTENTS
115 };
116
117
118
119 JOYSTICK_DRIVER joystick_fspro =
120 {
121 JOY_TYPE_FSPRO,
122 empty_string,
123 empty_string,
124 "Flightstick Pro",
125 JOYSTICK_DRIVER_CONTENTS
126 };
127
128
129
130 JOYSTICK_DRIVER joystick_wingex =
131 {
132 JOY_TYPE_WINGEX,
133 empty_string,
134 empty_string,
135 "Wingman Extreme",
136 JOYSTICK_DRIVER_CONTENTS
137 };
138
139
140
141 /* flags describing different variants of the basic joystick */
142 #define JDESC_STICK2 0x0001
143 #define JDESC_4BUTTON 0x0002
144 #define JDESC_6BUTTON 0x0004
145 #define JDESC_8BUTTON 0x0008
146 #define JDESC_Y2_THROTTLE 0x0010
147 #define JDESC_Y2_HAT 0x0020
148 #define JDESC_FSPRO_HAT 0x0040
149
150
151
152 /* calibration state information */
153 #define JOYSTICK_CALIB_TL1 0x00010000
154 #define JOYSTICK_CALIB_BR1 0x00020000
155 #define JOYSTICK_CALIB_TL2 0x00040000
156 #define JOYSTICK_CALIB_BR2 0x00080000
157 #define JOYSTICK_CALIB_THRTL_MIN 0x00100000
158 #define JOYSTICK_CALIB_THRTL_MAX 0x00200000
159 #define JOYSTICK_CALIB_HAT_CENTRE 0x00400000
160 #define JOYSTICK_CALIB_HAT_LEFT 0x00800000
161 #define JOYSTICK_CALIB_HAT_DOWN 0x01000000
162 #define JOYSTICK_CALIB_HAT_RIGHT 0x02000000
163 #define JOYSTICK_CALIB_HAT_UP 0x04000000
164
165 #define JOYSTICK_CALIB_HAT (JOYSTICK_CALIB_HAT_CENTRE | \
166 JOYSTICK_CALIB_HAT_LEFT | \
167 JOYSTICK_CALIB_HAT_DOWN | \
168 JOYSTICK_CALIB_HAT_RIGHT | \
169 JOYSTICK_CALIB_HAT_UP)
170
171
172
173 /* driver state information */
174 static int joystick_flags = 0;
175
176 static int joycentre_x, joycentre_y;
177 static int joyx_min, joyx_low_margin, joyx_high_margin, joyx_max;
178 static int joyy_min, joyy_low_margin, joyy_high_margin, joyy_max;
179
180 static int joycentre2_x, joycentre2_y;
181 static int joyx2_min, joyx2_low_margin, joyx2_high_margin, joyx2_max;
182 static int joyy2_min, joyy2_low_margin, joyy2_high_margin, joyy2_max;
183
184 static int joy_thr_min, joy_thr_max;
185
186 static int joy_hat_pos[5], joy_hat_threshold[4];
187
188 static int joy_old_x, joy_old_y;
189 static int joy2_old_x, joy2_old_y;
190
191
192
193 /* masks indicating which axis to read */
194 #define MASK_1X 1
195 #define MASK_1Y 2
196 #define MASK_2X 4
197 #define MASK_2Y 8
198
199
200
201 /* poll_mask:
202 * Returns a mask indicating which axes to poll.
203 */
poll_mask(void)204 static int poll_mask(void)
205 {
206 int mask = MASK_1X | MASK_1Y;
207
208 if (joystick_flags & (JDESC_STICK2 | JDESC_6BUTTON | JDESC_8BUTTON))
209 mask |= (MASK_2X | MASK_2Y);
210
211 if (joystick_flags & (JDESC_Y2_THROTTLE | JDESC_Y2_HAT))
212 mask |= MASK_2Y;
213
214 return mask;
215 }
216
217
218
219 /* averaged_poll:
220 * For calibration it is crucial that we get the right results, so we
221 * average out several attempts.
222 */
averaged_poll(int * x,int * y,int * x2,int * y2,int mask)223 static int averaged_poll(int *x, int *y, int *x2, int *y2, int mask)
224 {
225 int x_tmp, y_tmp, x2_tmp, y2_tmp;
226 int x_total, y_total, x2_total, y2_total;
227 int c;
228
229 #define AVERAGE_COUNT 4
230
231 x_total = y_total = x2_total = y2_total = 0;
232
233 for (c=0; c<AVERAGE_COUNT; c++) {
234 if (poll(&x_tmp, &y_tmp, &x2_tmp, &y2_tmp, mask) != 0)
235 return -1;
236
237 x_total += x_tmp;
238 y_total += y_tmp;
239 x2_total += x2_tmp;
240 y2_total += y2_tmp;
241 }
242
243 *x = x_total / AVERAGE_COUNT;
244 *y = y_total / AVERAGE_COUNT;
245 *x2 = x2_total / AVERAGE_COUNT;
246 *y2 = y2_total / AVERAGE_COUNT;
247
248 return 0;
249 }
250
251
252
253 /* recalc_calibration_flags:
254 * Called after each calibration operation, to calculate what else might
255 * need to be measured for the current hardware.
256 */
recalc_calibration_flags(void)257 static void recalc_calibration_flags(void)
258 {
259 #define FLAG_SET(n) ((joystick_flags & (n)) == (n))
260
261 /* stick 1 analogue input? */
262 if (FLAG_SET(JOYSTICK_CALIB_TL1 | JOYSTICK_CALIB_BR1)) {
263 joy[0].stick[0].flags |= JOYFLAG_ANALOGUE;
264 joy[0].stick[0].flags &= ~JOYFLAG_CALIB_ANALOGUE;
265 }
266 else {
267 joy[0].stick[0].flags &= ~JOYFLAG_ANALOGUE;
268 joy[0].stick[0].flags |= JOYFLAG_CALIB_ANALOGUE;
269 }
270
271 /* stick 2 analogue input? */
272 if (joystick_flags & JDESC_STICK2) {
273 if (FLAG_SET(JOYSTICK_CALIB_TL2 | JOYSTICK_CALIB_BR2)) {
274 joy[1].stick[0].flags |= JOYFLAG_ANALOGUE;
275 joy[1].stick[0].flags &= ~JOYFLAG_CALIB_ANALOGUE;
276 }
277 else {
278 joy[1].stick[0].flags &= ~JOYFLAG_ANALOGUE;
279 joy[1].stick[0].flags |= JOYFLAG_CALIB_ANALOGUE;
280 }
281 }
282
283 /* Wingman Extreme hat input? */
284 if (joystick_flags & JDESC_Y2_HAT) {
285 if (FLAG_SET(JOYSTICK_CALIB_HAT)) {
286 joy[0].stick[1].flags |= JOYFLAG_DIGITAL;
287 joy[0].stick[1].flags &= ~JOYFLAG_CALIB_DIGITAL;
288 }
289 else {
290 joy[0].stick[1].flags &= ~JOYFLAG_DIGITAL;
291 joy[0].stick[1].flags |= JOYFLAG_CALIB_DIGITAL;
292 }
293 }
294
295 /* FSPro throttle input? */
296 if (joystick_flags & JDESC_Y2_THROTTLE) {
297 if (FLAG_SET(JOYSTICK_CALIB_THRTL_MIN | JOYSTICK_CALIB_THRTL_MAX)) {
298 joy[0].stick[2].flags |= JOYFLAG_ANALOGUE;
299 joy[0].stick[2].flags &= ~JOYFLAG_CALIB_ANALOGUE;
300 }
301 else {
302 joy[0].stick[2].flags &= ~JOYFLAG_ANALOGUE;
303 joy[0].stick[2].flags |= JOYFLAG_CALIB_ANALOGUE;
304 }
305 }
306 }
307
308
309
310 /* joy_init:
311 * Initialises the driver.
312 */
joy_init(void)313 static int joy_init(void)
314 {
315 int i;
316
317 /* store info about the stick type */
318 switch (_joy_type) {
319
320 case JOY_TYPE_STANDARD:
321 joystick_flags = 0;
322 break;
323
324 case JOY_TYPE_2PADS:
325 joystick_flags = JDESC_STICK2;
326 break;
327
328 case JOY_TYPE_4BUTTON:
329 joystick_flags = JDESC_4BUTTON;
330 break;
331
332 case JOY_TYPE_6BUTTON:
333 joystick_flags = JDESC_4BUTTON | JDESC_6BUTTON;
334 break;
335
336 case JOY_TYPE_8BUTTON:
337 joystick_flags = JDESC_4BUTTON | JDESC_8BUTTON;
338 break;
339
340 case JOY_TYPE_FSPRO:
341 joystick_flags = JDESC_4BUTTON | JDESC_Y2_THROTTLE | JDESC_FSPRO_HAT;
342 break;
343
344 case JOY_TYPE_WINGEX:
345 joystick_flags = JDESC_4BUTTON | JDESC_Y2_HAT;
346 break;
347
348 default:
349 return -1;
350 }
351
352 joy_old_x = joy_old_y = 0;
353 joy2_old_x = joy2_old_y = 0;
354
355 /* make sure the hardware is really present */
356 if (averaged_poll(&joycentre_x, &joycentre_y, &joycentre2_x, &joycentre2_y, poll_mask()) != 0)
357 return -1;
358
359 /* fill in the joystick structure */
360 num_joysticks = (joystick_flags & JDESC_STICK2) ? 2 : 1;
361
362 joy[0].flags = JOYFLAG_DIGITAL;
363
364 /* how many buttons? */
365 if (joystick_flags & JDESC_8BUTTON)
366 joy[0].num_buttons = 8;
367 else if (joystick_flags & JDESC_6BUTTON)
368 joy[0].num_buttons = 6;
369 else if (joystick_flags & JDESC_4BUTTON)
370 joy[0].num_buttons = 4;
371 else
372 joy[0].num_buttons = 2;
373
374 /* main analogue stick */
375 joy[0].stick[0].flags = JOYFLAG_DIGITAL | JOYFLAG_SIGNED;
376 joy[0].stick[0].num_axis = 2;
377 joy[0].stick[0].axis[0].name = get_config_text("X");
378 joy[0].stick[0].axis[1].name = get_config_text("Y");
379 joy[0].stick[0].name = get_config_text("Stick");
380 joy[0].num_sticks = 1;
381
382 /* hat control? */
383 if (joystick_flags & (JDESC_FSPRO_HAT | JDESC_Y2_HAT)) {
384 joy[0].stick[joy[0].num_sticks].flags = JOYFLAG_DIGITAL | JOYFLAG_SIGNED;
385 joy[0].stick[joy[0].num_sticks].num_axis = 2;
386 joy[0].stick[joy[0].num_sticks].axis[0].name = get_config_text("X");
387 joy[0].stick[joy[0].num_sticks].axis[1].name = get_config_text("Y");
388 joy[0].stick[joy[0].num_sticks].name = get_config_text("Hat");
389 joy[0].num_sticks++;
390 }
391
392 /* throttle control? */
393 if (joystick_flags & JDESC_Y2_THROTTLE) {
394 joy[0].stick[joy[0].num_sticks].flags = JOYFLAG_UNSIGNED;
395 joy[0].stick[joy[0].num_sticks].num_axis = 1;
396 joy[0].stick[joy[0].num_sticks].axis[0].name = get_config_text("Throttle");
397 joy[0].stick[joy[0].num_sticks].name = get_config_text("Throttle");
398 joy[0].num_sticks++;
399 }
400
401 /* clone everything for a second joystick? */
402 if (joystick_flags & JDESC_STICK2)
403 joy[1] = joy[0];
404
405 /* fill in the button names */
406 for (i=0; i<2; i++) {
407 joy[i].button[0].name = get_config_text("B1");
408 joy[i].button[1].name = get_config_text("B2");
409
410 if (joy[i].num_buttons > 2) {
411 joy[i].button[2].name = get_config_text("B3");
412 joy[i].button[3].name = get_config_text("B4");
413 }
414
415 if (joy[i].num_buttons > 4) {
416 joy[i].button[4].name = get_config_text("B5");
417 joy[i].button[5].name = get_config_text("B6");
418 }
419
420 if (joy[i].num_buttons > 6) {
421 joy[i].button[6].name = get_config_text("B7");
422 joy[i].button[7].name = get_config_text("B8");
423 }
424 }
425
426 recalc_calibration_flags();
427
428 return 0;
429 }
430
431
432
433 /* joy_exit:
434 * Shuts down the driver.
435 */
joy_exit(void)436 static void joy_exit(void)
437 {
438 joystick_flags = 0;
439 }
440
441
442
443 /* sort_out_middle_values:
444 * Sets up the values used by sort_out_analogue() to create a 'dead'
445 * region in the centre of the joystick range.
446 */
sort_out_middle_values(int n)447 static void sort_out_middle_values(int n)
448 {
449 if (n == 0) {
450 joyx_low_margin = joycentre_x - (joycentre_x - joyx_min) / 8;
451 joyx_high_margin = joycentre_x + (joyx_max - joycentre_x) / 8;
452 joyy_low_margin = joycentre_y - (joycentre_y - joyy_min) / 8;
453 joyy_high_margin = joycentre_y + (joyy_max - joycentre_y) / 8;
454 }
455 else {
456 joyx2_low_margin = joycentre2_x - (joycentre2_x - joyx2_min) / 8;
457 joyx2_high_margin = joycentre2_x + (joyx2_max - joycentre2_x) / 8;
458 joyy2_low_margin = joycentre2_y - (joycentre2_y - joyy2_min) / 8;
459 joyy2_high_margin = joycentre2_y + (joyy2_max - joycentre2_y) / 8;
460 }
461 }
462
463
464
465 /* calibrate_corner:
466 * For analogue access to the joystick, this is used to measure the top
467 * left and bottom right corner positions.
468 */
calibrate_corner(int stick,int corner)469 static int calibrate_corner(int stick, int corner)
470 {
471 int flag, other, ret, nowhere;
472
473 if (stick == 0) {
474 /* stick 1 calibration */
475 flag = (corner) ? JOYSTICK_CALIB_BR1 : JOYSTICK_CALIB_TL1;
476 other = (corner) ? JOYSTICK_CALIB_TL1 : JOYSTICK_CALIB_BR1;
477
478 if (corner)
479 ret = averaged_poll(&joyx_max, &joyy_max, &nowhere, &nowhere, MASK_1X | MASK_1Y);
480 else
481 ret = averaged_poll(&joyx_min, &joyy_min, &nowhere, &nowhere, MASK_1X | MASK_1Y);
482 }
483 else {
484 /* stick 2 calibration */
485 flag = (corner) ? JOYSTICK_CALIB_BR2 : JOYSTICK_CALIB_TL2;
486 other = (corner) ? JOYSTICK_CALIB_TL2 : JOYSTICK_CALIB_BR2;
487
488 if (corner)
489 ret = averaged_poll(&nowhere, &nowhere, &joyx2_max, &joyy2_max, MASK_2X | MASK_2Y);
490 else
491 ret = averaged_poll(&nowhere, &nowhere, &joyx2_min, &joyy2_min, MASK_2X | MASK_2Y);
492 }
493
494 if (ret != 0) {
495 joystick_flags &= ~flag;
496 return -1;
497 }
498
499 joystick_flags |= flag;
500
501 /* once we've done both corners, we are ready for full analogue input */
502 if (joystick_flags & other) {
503 sort_out_middle_values(stick);
504 recalc_calibration_flags();
505 }
506
507 return 0;
508 }
509
510
511
512 /* calibrate_joystick_tl:
513 * For backward compatibility with the old API.
514 */
calibrate_joystick_tl(void)515 int calibrate_joystick_tl(void)
516 {
517 int ret;
518
519 if (!_joystick_installed)
520 return -1;
521
522 ret = calibrate_corner(0, 0);
523
524 if ((ret == 0) && (joystick_flags & JDESC_STICK2))
525 ret = calibrate_corner(1, 0);
526
527 return ret;
528 }
529
530
531
532 /* calibrate_joystick_br:
533 * For backward compatibility with the old API.
534 */
calibrate_joystick_br(void)535 int calibrate_joystick_br(void)
536 {
537 int ret;
538
539 if (!_joystick_installed)
540 return -1;
541
542 ret = calibrate_corner(0, 1);
543
544 if ((ret == 0) && (joystick_flags & JDESC_STICK2))
545 ret = calibrate_corner(1, 1);
546
547 return ret;
548 }
549
550
551
552 /* calibrate_joystick_throttle_min:
553 * For analogue access to the FSPro's throttle, call this after
554 * initialise_joystick(), with the throttle at the "minimum" extreme
555 * (the user decides whether this is all the way forwards or all the
556 * way back), and also call calibrate_joystick_throttle_max().
557 */
calibrate_joystick_throttle_min(void)558 int calibrate_joystick_throttle_min(void)
559 {
560 int dummy;
561
562 if (!_joystick_installed)
563 return -1;
564
565 if (averaged_poll(&dummy, &dummy, &dummy, &joy_thr_min, MASK_2Y) != 0)
566 return -1;
567
568 /* prevent division by zero errors if user miscalibrated */
569 if ((joystick_flags & JOYSTICK_CALIB_THRTL_MAX) && (joy_thr_min == joy_thr_max))
570 joy_thr_min = 255 - joy_thr_max;
571
572 joystick_flags |= JOYSTICK_CALIB_THRTL_MIN;
573 recalc_calibration_flags();
574
575 return 0;
576 }
577
578
579
580 /* calibrate_joystick_throttle_max:
581 * For analogue access to the FSPro's throttle, call this after
582 * initialise_joystick(), with the throttle at the "maximum" extreme
583 * (the user decides whether this is all the way forwards or all the
584 * way back), and also call calibrate_joystick_throttle_min().
585 */
calibrate_joystick_throttle_max(void)586 int calibrate_joystick_throttle_max(void)
587 {
588 int dummy;
589
590 if (!_joystick_installed)
591 return -1;
592
593 if (averaged_poll(&dummy, &dummy, &dummy, &joy_thr_max, MASK_2Y) != 0)
594 return -1;
595
596 /* prevent division by zero errors if user miscalibrated */
597 if ((joystick_flags & JOYSTICK_CALIB_THRTL_MIN) && (joy_thr_min == joy_thr_max))
598 joy_thr_max = 255 - joy_thr_min;
599
600 joystick_flags |= JOYSTICK_CALIB_THRTL_MAX;
601 recalc_calibration_flags();
602
603 return 0;
604 }
605
606
607
608 /* calibrate_joystick_hat:
609 * For access to the Wingman Extreme's hat (I think this will work on all
610 * Thrustmaster compatible joysticks), call this after initialise_joystick(),
611 * passing the JOY_HAT constant you wish to calibrate.
612 */
calibrate_joystick_hat(int direction)613 int calibrate_joystick_hat(int direction)
614 {
615 static int pos_const[] =
616 {
617 JOYSTICK_CALIB_HAT_CENTRE,
618 JOYSTICK_CALIB_HAT_LEFT,
619 JOYSTICK_CALIB_HAT_DOWN,
620 JOYSTICK_CALIB_HAT_RIGHT,
621 JOYSTICK_CALIB_HAT_UP
622 };
623
624 int dummy, value;
625
626 if ((direction > JOY_HAT_UP) || (!_joystick_installed))
627 return -1;
628
629 if (averaged_poll(&dummy, &dummy, &dummy, &value, MASK_2Y) != 0)
630 return -1;
631
632 joy_hat_pos[direction] = value;
633 joystick_flags |= pos_const[direction];
634
635 /* when all directions have been calibrated, calculate deltas */
636 if ((joystick_flags & JOYSTICK_CALIB_HAT) == JOYSTICK_CALIB_HAT) {
637 joy_hat_threshold[0] = (joy_hat_pos[0] + joy_hat_pos[1]) / 2;
638 joy_hat_threshold[1] = (joy_hat_pos[1] + joy_hat_pos[2]) / 2;
639 joy_hat_threshold[2] = (joy_hat_pos[2] + joy_hat_pos[3]) / 2;
640 joy_hat_threshold[3] = (joy_hat_pos[3] + joy_hat_pos[4]) / 2;
641
642 recalc_calibration_flags();
643 }
644
645 return 0;
646 }
647
648
649
650 /* sort_out_analogue:
651 * There are a couple of problems with reading analogue input from the PC
652 * joystick. For one thing, joysticks tend not to centre repeatably, so
653 * we need a small 'dead' zone in the middle. Also a lot of joysticks aren't
654 * linear, so the positions less than centre need to be handled differently
655 * to those above the centre.
656 */
sort_out_analogue(int x,int min,int low_margin,int high_margin,int max)657 static int sort_out_analogue(int x, int min, int low_margin, int high_margin, int max)
658 {
659 if (x < min) {
660 return -128;
661 }
662 else if (x < low_margin) {
663 return -128 + (x - min) * 128 / (low_margin - min);
664 }
665 else if (x <= high_margin) {
666 return 0;
667 }
668 else if (x <= max) {
669 return 128 - (max - x) * 128 / (max - high_margin);
670 }
671 else
672 return 128;
673 }
674
675
676
677 /* joy_poll:
678 * Updates the joystick status variables.
679 */
joy_poll(void)680 static int joy_poll(void)
681 {
682 int x, y, x2, y2, i;
683 unsigned char status;
684
685 /* read the hardware */
686 if (poll(&x, &y, &x2, &y2, poll_mask()) != 0)
687 return -1;
688
689 status = inportb(0x201);
690
691 /* stick 1 position */
692 if ((ABS(x-joy_old_x) <= x/4) && (ABS(y-joy_old_y) <= y/4)) {
693 if ((joystick_flags & JOYSTICK_CALIB_TL1) && (joystick_flags & JOYSTICK_CALIB_BR1)) {
694 joy[0].stick[0].axis[0].pos = sort_out_analogue(x, joyx_min, joyx_low_margin, joyx_high_margin, joyx_max);
695 joy[0].stick[0].axis[1].pos = sort_out_analogue(y, joyy_min, joyy_low_margin, joyy_high_margin, joyy_max);
696 }
697 else {
698 joy[0].stick[0].axis[0].pos = x - joycentre_x;
699 joy[0].stick[0].axis[1].pos = y - joycentre_y;
700 }
701
702 joy[0].stick[0].axis[0].d1 = (x < (joycentre_x/2));
703 joy[0].stick[0].axis[0].d2 = (x > (joycentre_x*4/3));
704 joy[0].stick[0].axis[1].d1 = (y < (joycentre_y/2));
705 joy[0].stick[0].axis[1].d2 = (y > (joycentre_y*4/3));
706 }
707
708 if (joystick_flags & JDESC_STICK2) {
709 /* stick 2 position */
710 if ((ABS(x2-joy2_old_x) <= x2/4) && (ABS(y2-joy2_old_y) <= y2/4)) {
711 if ((joystick_flags & JOYSTICK_CALIB_TL2) && (joystick_flags & JOYSTICK_CALIB_BR2)) {
712 joy[1].stick[0].axis[0].pos = sort_out_analogue(x2, joyx2_min, joyx2_low_margin, joyx2_high_margin, joyx2_max);
713 joy[1].stick[0].axis[1].pos = sort_out_analogue(y2, joyy2_min, joyy2_low_margin, joyy2_high_margin, joyy2_max);
714 }
715 else {
716 joy[1].stick[0].axis[0].pos = x2 - joycentre2_x;
717 joy[1].stick[0].axis[1].pos = y2 - joycentre2_y;
718 }
719
720 joy[1].stick[0].axis[0].d1 = (x2 < (joycentre2_x/2));
721 joy[1].stick[0].axis[0].d2 = (x2 > (joycentre2_x*3/2));
722 joy[1].stick[0].axis[1].d1 = (y2 < (joycentre2_y/2));
723 joy[1].stick[0].axis[1].d2 = (y2 > (joycentre2_y*3/2));
724 }
725
726 joy[1].button[0].b = ((status & 0x40) == 0);
727 joy[1].button[1].b = ((status & 0x80) == 0);
728 }
729
730 /* button state */
731 joy[0].button[0].b = ((status & 0x10) == 0);
732 joy[0].button[1].b = ((status & 0x20) == 0);
733
734 if (joystick_flags & JDESC_4BUTTON) {
735 /* four button state */
736 joy[0].button[2].b = ((status & 0x40) == 0);
737 joy[0].button[3].b = ((status & 0x80) == 0);
738 }
739
740 if (joystick_flags & JDESC_6BUTTON) {
741 /* six button state */
742 joy[0].button[4].b = (x2 < 128);
743 joy[0].button[5].b = (y2 < 128);
744 }
745 else if (joystick_flags & JDESC_8BUTTON) {
746 /* eight button state */
747 joy[0].button[4].b = (x2 < (joycentre2_x/2));
748 joy[0].button[5].b = (y2 < (joycentre2_y/2));
749 joy[0].button[6].b = (x2 > (joycentre2_x*3/2));
750 joy[0].button[7].b = (y2 > (joycentre2_y*3)/2);
751 }
752
753 if (joystick_flags & JDESC_Y2_THROTTLE) {
754 /* throttle */
755 if ((joystick_flags & JOYSTICK_CALIB_THRTL_MIN) && (joystick_flags & JOYSTICK_CALIB_THRTL_MAX)) {
756 i = (y2 - joy_thr_min) * 255 / (joy_thr_max - joy_thr_min);
757 joy[0].stick[2].axis[0].pos = CLAMP(0, i, 255);
758 if (joy[0].stick[2].axis[0].pos > 255*2/3)
759 joy[0].stick[2].axis[0].d2 = TRUE;
760 else
761 joy[0].stick[2].axis[0].d2 = FALSE;
762 }
763 }
764
765 if (joystick_flags & JDESC_FSPRO_HAT) {
766 /* FSPro hat control (accessed via special button values) */
767 joy[0].stick[1].axis[0].pos = 0;
768 joy[0].stick[1].axis[1].pos = 0;
769 joy[0].stick[1].axis[0].d1 = joy[0].stick[1].axis[0].d2 = 0;
770 joy[0].stick[1].axis[1].d1 = joy[0].stick[1].axis[1].d2 = 0;
771
772 if ((status & 0x30) == 0) {
773 joy[0].button[0].b = FALSE;
774 joy[0].button[1].b = FALSE;
775 joy[0].button[2].b = FALSE;
776 joy[0].button[3].b = FALSE;
777
778 switch (status & 0xC0) {
779
780 case 0x00:
781 /* up */
782 joy[0].stick[1].axis[1].pos = -128;
783 joy[0].stick[1].axis[1].d1 = TRUE;
784 break;
785
786 case 0x40:
787 /* right */
788 joy[0].stick[1].axis[0].pos = 128;
789 joy[0].stick[1].axis[0].d2 = TRUE;
790 break;
791
792 case 0x80:
793 /* down */
794 joy[0].stick[1].axis[1].pos = 128;
795 joy[0].stick[1].axis[1].d2 = TRUE;
796 break;
797
798 case 0xC0:
799 /* left */
800 joy[0].stick[1].axis[0].pos = -128;
801 joy[0].stick[1].axis[0].d1 = TRUE;
802 break;
803 }
804 }
805 }
806
807 if (joystick_flags & JDESC_Y2_HAT) {
808 /* Wingman Extreme hat control (accessed via the y2 pot) */
809 joy[0].stick[1].axis[0].pos = 0;
810 joy[0].stick[1].axis[1].pos = 0;
811 joy[0].stick[1].axis[0].d1 = joy[0].stick[1].axis[0].d2 = 0;
812 joy[0].stick[1].axis[1].d1 = joy[0].stick[1].axis[1].d2 = 0;
813
814 if ((joystick_flags & JOYSTICK_CALIB_HAT) == JOYSTICK_CALIB_HAT) {
815 if (y2 >= joy_hat_threshold[0]) {
816 /* centre */
817 }
818 else if (y2 >= joy_hat_threshold[1]) {
819 /* left */
820 joy[0].stick[1].axis[0].pos = -128;
821 joy[0].stick[1].axis[0].d1 = TRUE;
822 }
823 else if (y2 >= joy_hat_threshold[2]) {
824 /* down */
825 joy[0].stick[1].axis[1].pos = 128;
826 joy[0].stick[1].axis[1].d2 = TRUE;
827 }
828 else if (y2 >= joy_hat_threshold[3]) {
829 /* right */
830 joy[0].stick[1].axis[0].pos = 128;
831 joy[0].stick[1].axis[0].d2 = TRUE;
832 }
833 else {
834 /* up */
835 joy[0].stick[1].axis[1].pos = -128;
836 joy[0].stick[1].axis[1].d1 = TRUE;
837 }
838 }
839 }
840
841 joy_old_x = x;
842 joy_old_y = y;
843
844 joy2_old_x = x2;
845 joy2_old_y = y2;
846
847 return 0;
848 }
849
850
851
852 /* poll:
853 * Polls the joystick to read the axis position. Returns raw position
854 * values, zero for success, non-zero if no joystick found. This has
855 * to come after the routines that call it, to make sure it will never
856 * be inlined (that could shift alignment and upset the timing values).
857 */
poll(int * x,int * y,int * x2,int * y2,int poll_mask)858 static int poll(int *x, int *y, int *x2, int *y2, int poll_mask)
859 {
860 int c, d;
861
862 *x = *y = *x2 = *y2 = 0;
863
864 _enter_critical();
865
866 outportb(0x201, 0);
867
868 for (c=0; c<100000; c++) {
869 d = inportb(0x201);
870
871 if (d & MASK_1X)
872 (*x)++;
873
874 if (d & MASK_1Y)
875 (*y)++;
876
877 if (d & MASK_2X)
878 (*x2)++;
879
880 if (d & MASK_2Y)
881 (*y2)++;
882
883 if (!(d & poll_mask))
884 break;
885 }
886
887 _exit_critical();
888
889 if (((poll_mask & MASK_1X) && (*x >= 100000)) ||
890 ((poll_mask & MASK_1Y) && (*y >= 100000)) ||
891 ((poll_mask & MASK_2X) && (*x2 >= 100000)) ||
892 ((poll_mask & MASK_2Y) && (*y2 >= 100000)))
893 return -1;
894
895 return 0;
896 }
897
898
899
900 /* joy_save_data:
901 * Writes calibration data into the config file.
902 */
joy_save_data(void)903 static int joy_save_data(void)
904 {
905 char tmp1[128], tmp2[128];
906 char *j = uconvert_ascii("joystick", tmp1);
907
908 set_config_int(j, uconvert_ascii("joystick_flags", tmp2), joystick_flags);
909
910 set_config_int(j, uconvert_ascii("joycentre_x", tmp2), joycentre_x);
911 set_config_int(j, uconvert_ascii("joycentre_y", tmp2), joycentre_y);
912 set_config_int(j, uconvert_ascii("joyx_min", tmp2), joyx_min);
913 set_config_int(j, uconvert_ascii("joyx_low_margin", tmp2), joyx_low_margin);
914 set_config_int(j, uconvert_ascii("joyx_high_margin", tmp2), joyx_high_margin);
915 set_config_int(j, uconvert_ascii("joyx_max", tmp2), joyx_max);
916 set_config_int(j, uconvert_ascii("joyy_min", tmp2), joyy_min);
917 set_config_int(j, uconvert_ascii("joyy_low_margin", tmp2), joyy_low_margin);
918 set_config_int(j, uconvert_ascii("joyy_high_margin", tmp2), joyy_high_margin);
919 set_config_int(j, uconvert_ascii("joyy_max", tmp2), joyy_max);
920
921 set_config_int(j, uconvert_ascii("joycentre2_x", tmp2), joycentre2_x);
922 set_config_int(j, uconvert_ascii("joycentre2_y", tmp2), joycentre2_y);
923 set_config_int(j, uconvert_ascii("joyx2_min", tmp2), joyx2_min);
924 set_config_int(j, uconvert_ascii("joyx2_low_margin", tmp2), joyx2_low_margin);
925 set_config_int(j, uconvert_ascii("joyx2_high_margin", tmp2), joyx2_high_margin);
926 set_config_int(j, uconvert_ascii("joyx2_max", tmp2), joyx2_max);
927 set_config_int(j, uconvert_ascii("joyy2_min", tmp2), joyy2_min);
928 set_config_int(j, uconvert_ascii("joyy2_low_margin", tmp2), joyy2_low_margin);
929 set_config_int(j, uconvert_ascii("joyy2_high_margin", tmp2), joyy2_high_margin);
930 set_config_int(j, uconvert_ascii("joyy2_max", tmp2), joyy2_max);
931
932 set_config_int(j, uconvert_ascii("joythr_min", tmp2), joy_thr_min);
933 set_config_int(j, uconvert_ascii("joythr_max", tmp2), joy_thr_max);
934
935 set_config_int(j, uconvert_ascii("joyhat_0", tmp2), joy_hat_threshold[0]);
936 set_config_int(j, uconvert_ascii("joyhat_1", tmp2), joy_hat_threshold[1]);
937 set_config_int(j, uconvert_ascii("joyhat_2", tmp2), joy_hat_threshold[2]);
938 set_config_int(j, uconvert_ascii("joyhat_3", tmp2), joy_hat_threshold[3]);
939
940 return 0;
941 }
942
943
944
945 /* joy_load_data:
946 * Loads calibration data from the config file.
947 */
joy_load_data(void)948 static int joy_load_data(void)
949 {
950 char tmp1[128], tmp2[128];
951 char *j = uconvert_ascii("joystick", tmp1);
952
953 joystick_flags = get_config_int(j, uconvert_ascii("joystick_flags", tmp2), joystick_flags);
954
955 joycentre_x = get_config_int(j, uconvert_ascii("joycentre_x", tmp2), joycentre_x);
956 joycentre_y = get_config_int(j, uconvert_ascii("joycentre_y", tmp2), joycentre_y);
957 joyx_min = get_config_int(j, uconvert_ascii("joyx_min", tmp2), joyx_min);
958 joyx_low_margin = get_config_int(j, uconvert_ascii("joyx_low_margin", tmp2), joyx_low_margin);
959 joyx_high_margin = get_config_int(j, uconvert_ascii("joyx_high_margin", tmp2), joyx_high_margin);
960 joyx_max = get_config_int(j, uconvert_ascii("joyx_max", tmp2), joyx_max);
961 joyy_min = get_config_int(j, uconvert_ascii("joyy_min", tmp2), joyy_min);
962 joyy_low_margin = get_config_int(j, uconvert_ascii("joyy_low_margin", tmp2), joyy_low_margin);
963 joyy_high_margin = get_config_int(j, uconvert_ascii("joyy_high_margin", tmp2), joyy_high_margin);
964 joyy_max = get_config_int(j, uconvert_ascii("joyy_max", tmp2), joyy_max);
965
966 joycentre2_x = get_config_int(j, uconvert_ascii("joycentre2_x", tmp2), joycentre2_x);
967 joycentre2_y = get_config_int(j, uconvert_ascii("joycentre2_y", tmp2), joycentre2_y);
968 joyx2_min = get_config_int(j, uconvert_ascii("joyx2_min", tmp2), joyx2_min);
969 joyx2_low_margin = get_config_int(j, uconvert_ascii("joyx_low2_margin", tmp2), joyx2_low_margin);
970 joyx2_high_margin = get_config_int(j, uconvert_ascii("joyx_high2_margin", tmp2), joyx2_high_margin);
971 joyx2_max = get_config_int(j, uconvert_ascii("joyx2_max", tmp2), joyx2_max);
972 joyy2_min = get_config_int(j, uconvert_ascii("joyy2_min", tmp2), joyy2_min);
973 joyy2_low_margin = get_config_int(j, uconvert_ascii("joyy2_low_margin", tmp2), joyy2_low_margin);
974 joyy2_high_margin = get_config_int(j, uconvert_ascii("joyy2_high_margin", tmp2), joyy2_high_margin);
975 joyy2_max = get_config_int(j, uconvert_ascii("joyy2_max", tmp2), joyy2_max);
976
977 joy_thr_min = get_config_int(j, uconvert_ascii("joythr_min", tmp2), joy_thr_min);
978 joy_thr_max = get_config_int(j, uconvert_ascii("joythr_max", tmp2), joy_thr_max);
979
980 joy_hat_threshold[0] = get_config_int(j, uconvert_ascii("joyhat_0", tmp2), joy_hat_threshold[0]);
981 joy_hat_threshold[1] = get_config_int(j, uconvert_ascii("joyhat_1", tmp2), joy_hat_threshold[1]);
982 joy_hat_threshold[2] = get_config_int(j, uconvert_ascii("joyhat_2", tmp2), joy_hat_threshold[2]);
983 joy_hat_threshold[3] = get_config_int(j, uconvert_ascii("joyhat_3", tmp2), joy_hat_threshold[3]);
984
985 joy_old_x = joy_old_y = 0;
986
987 recalc_calibration_flags();
988
989 return 0;
990 }
991
992
993
994 /* next_calib_action:
995 * Returns a flag indicating the next thing that needs to be calibrated.
996 */
next_calib_action(int stick)997 static int next_calib_action(int stick)
998 {
999 if (stick == 0) {
1000 /* stick 1 analogue input? */
1001 if (!(joystick_flags & JOYSTICK_CALIB_TL1))
1002 return JOYSTICK_CALIB_TL1;
1003
1004 if (!(joystick_flags & JOYSTICK_CALIB_BR1))
1005 return JOYSTICK_CALIB_BR1;
1006
1007 /* FSPro throttle input? */
1008 if (joystick_flags & JDESC_Y2_THROTTLE) {
1009 if (!(joystick_flags & JOYSTICK_CALIB_THRTL_MIN))
1010 return JOYSTICK_CALIB_THRTL_MIN;
1011
1012 if (!(joystick_flags & JOYSTICK_CALIB_THRTL_MAX))
1013 return JOYSTICK_CALIB_THRTL_MAX;
1014 }
1015
1016 /* Wingman Extreme hat input? */
1017 if (joystick_flags & JDESC_Y2_HAT) {
1018 if (!(joystick_flags & JOYSTICK_CALIB_HAT_CENTRE))
1019 return JOYSTICK_CALIB_HAT_CENTRE;
1020
1021 if (!(joystick_flags & JOYSTICK_CALIB_HAT_LEFT))
1022 return JOYSTICK_CALIB_HAT_LEFT;
1023
1024 if (!(joystick_flags & JOYSTICK_CALIB_HAT_DOWN))
1025 return JOYSTICK_CALIB_HAT_DOWN;
1026
1027 if (!(joystick_flags & JOYSTICK_CALIB_HAT_RIGHT))
1028 return JOYSTICK_CALIB_HAT_RIGHT;
1029
1030 if (!(joystick_flags & JOYSTICK_CALIB_HAT_UP))
1031 return JOYSTICK_CALIB_HAT_UP;
1032 }
1033 }
1034 else if (stick == 1) {
1035 if (joystick_flags & JDESC_STICK2) {
1036 /* stick 2 analogue input? */
1037 if (!(joystick_flags & JOYSTICK_CALIB_TL2))
1038 return JOYSTICK_CALIB_TL2;
1039
1040 if (!(joystick_flags & JOYSTICK_CALIB_BR2))
1041 return JOYSTICK_CALIB_BR2;
1042 }
1043 }
1044
1045 return 0;
1046 }
1047
1048
1049
1050 /* joy_calibrate_name:
1051 * Returns the name of the next calibration operation.
1052 */
joy_calibrate_name(int n)1053 static AL_CONST char *joy_calibrate_name(int n)
1054 {
1055 switch (next_calib_action(n)) {
1056
1057 case JOYSTICK_CALIB_TL1: return get_config_text("Move stick to the top left"); break;
1058 case JOYSTICK_CALIB_BR1: return get_config_text("Move stick to the bottom right"); break;
1059 case JOYSTICK_CALIB_TL2: return get_config_text("Move stick 2 to the top left"); break;
1060 case JOYSTICK_CALIB_BR2: return get_config_text("Move stick 2 to the bottom right"); break;
1061 case JOYSTICK_CALIB_THRTL_MIN: return get_config_text("Set throttle to minimum"); break;
1062 case JOYSTICK_CALIB_THRTL_MAX: return get_config_text("Set throttle to maximum"); break;
1063 case JOYSTICK_CALIB_HAT_CENTRE: return get_config_text("Centre the hat"); break;
1064 case JOYSTICK_CALIB_HAT_LEFT: return get_config_text("Move the hat left"); break;
1065 case JOYSTICK_CALIB_HAT_DOWN: return get_config_text("Move the hat down"); break;
1066 case JOYSTICK_CALIB_HAT_RIGHT: return get_config_text("Move the hat right"); break;
1067 case JOYSTICK_CALIB_HAT_UP: return get_config_text("Move the hat up"); break;
1068 }
1069
1070 return NULL;
1071 }
1072
1073
1074
1075 /* joy_calibrate:
1076 * Performs the next calibration operation.
1077 */
joy_calibrate(int n)1078 static int joy_calibrate(int n)
1079 {
1080 switch (next_calib_action(n)) {
1081
1082 case JOYSTICK_CALIB_TL1:
1083 return calibrate_corner(0, 0);
1084 break;
1085
1086 case JOYSTICK_CALIB_BR1:
1087 return calibrate_corner(0, 1);
1088 break;
1089
1090 case JOYSTICK_CALIB_TL2:
1091 return calibrate_corner(1, 0);
1092 break;
1093
1094 case JOYSTICK_CALIB_BR2:
1095 return calibrate_corner(1, 1);
1096 break;
1097
1098 case JOYSTICK_CALIB_THRTL_MIN:
1099 return calibrate_joystick_throttle_min();
1100 break;
1101
1102 case JOYSTICK_CALIB_THRTL_MAX:
1103 return calibrate_joystick_throttle_max();
1104 break;
1105
1106 case JOYSTICK_CALIB_HAT_CENTRE:
1107 return calibrate_joystick_hat(JOY_HAT_CENTRE);
1108 break;
1109
1110 case JOYSTICK_CALIB_HAT_LEFT:
1111 return calibrate_joystick_hat(JOY_HAT_LEFT);
1112 break;
1113
1114 case JOYSTICK_CALIB_HAT_DOWN:
1115 return calibrate_joystick_hat(JOY_HAT_DOWN);
1116 break;
1117
1118 case JOYSTICK_CALIB_HAT_RIGHT:
1119 return calibrate_joystick_hat(JOY_HAT_RIGHT);
1120 break;
1121
1122 case JOYSTICK_CALIB_HAT_UP:
1123 return calibrate_joystick_hat(JOY_HAT_UP);
1124 break;
1125 }
1126
1127 return -1;
1128 }
1129
1130
1131