/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Joystick driver for the Gravis GrIP. * (Xterminator, GamepadPro, Stinger, ?) * * By Robert J. Ragno, using the Gravis SDK and the other * Allegro drivers as references. * * TODO: * - Test on more devices * - Add support for restricting joystick to 4-directions * - Look into dropping the grip.gll support (with asm code) * - Look into providing direction names, not just axis names * - (analog detection) */ #include #include "allegro.h" #include "allegro/internal/aintern.h" #include "allegro/platform/aintdos.h" #include "grip.h" #ifndef ALLEGRO_DOS #error something is wrong with the makefile #endif /* If this is true, throttles will be 'packed' to fit in the * smallest number of pseudo-sticks possible. */ #define PACK_THROTTLES 1 /* enable support for each type of control */ #define ENABLE_AXIS 1 #define ENABLE_ANALOG 1 #define ENABLE_POV 1 #define ENABLE_THROTTLE 1 /* driver functions */ static int grip_init(void); static void grip_exit(void); static int grip_poll(void); static int grip_link(void); static int grip_unlink(void); static int read_grip(int joy_num); /* hack to simplify axis names... */ #define SIMPLIFY_AXIS(foo) \ if (((foo[0] == 'X') || (foo[0] == 'Y')) && (foo[1] == '_')) \ foo[1] = '\0'; /* internal variables for extra joystick data */ static GRIP_SLOT slot_index[MAX_JOYSTICKS]; static GRIP_VALUE max_value[MAX_JOYSTICKS][(int)GRIP_CLASS_MAX+1]; static int throttle_button_start[MAX_JOYSTICKS]; static GRIP_CLASS stick_class[MAX_JOYSTICKS][MAX_JOYSTICK_STICKS]; static int fourway[MAX_JOYSTICKS][MAX_JOYSTICK_STICKS]; /* the normal GrIP driver */ JOYSTICK_DRIVER joystick_grip = { JOY_TYPE_GRIP, empty_string, empty_string, "GrIP", grip_init, grip_exit, grip_poll, NULL, NULL, /* no saving/loading data */ NULL, NULL /* no calibrating */ }; /* only allows 4-way movement on digital pad */ JOYSTICK_DRIVER joystick_grip4 = { JOY_TYPE_GRIP4, empty_string, empty_string, "GrIP 4-way", grip_init, grip_exit, grip_poll, NULL, NULL, /* no saving/loading data */ NULL, NULL /* no calibrating */ }; /* read_grip; * Reads the GrIP controller pointed to by joy_num (0 or 1) and * sets its state; no useful return value currently. */ static int read_grip(int j) { GRIP_BITFIELD buttons_packed; GRIP_SLOT slot_num; GRIP_CLASS last_class; GRIP_INDEX axis; int a, b, s, state; slot_num = slot_index[j]; /* sticks must be grouped by type for axis grouping to work! */ axis = 0; last_class = stick_class[j][0]; for (s=0; s 64; axis++; } } /* handle 4-way restriction */ if (_joy_type == JOY_TYPE_GRIP4) { for (s=0; s= MAX_JOYSTICKS) break; } } if (num_joysticks == 0) { ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("No GrIP devices available")); grip_exit(); return -1; } /* loop over each joystick (active GrIP slot) */ for (i=0; i MAX_JOYSTICK_STICKS) { joy[i].num_sticks = MAX_JOYSTICK_STICKS; last_axis = MAX_JOYSTICK_STICKS*2; } max_value[i][GRIP_CLASS_AXIS] = _GrGetMaxValue(slot_index[i], GRIP_CLASS_AXIS); /* loop over each actual stick on the device (often just 1) * We arbitrarily split the axes up into pairs... GrIP gives no * info on how this can be identified */ for (stick=0; stick < joy[i].num_sticks; stick++) { stick_class[i][stick] = GRIP_CLASS_AXIS; /* name stick... :( */ _al_sane_strncpy(tmpstr, "Stick", sizeof(tmpstr)); if (joy[i].num_sticks > 1) { tmpstr[strlen(tmpstr)+2] = '\0'; tmpstr[strlen(tmpstr)+1] = '1'+stick; tmpstr[strlen(tmpstr)] = ' '; } joy[i].stick[stick].name = get_config_text(tmpstr); joy[i].stick[stick].flags = JOYFLAG_DIGITAL | JOYFLAG_SIGNED; /* name axes */ joy[i].stick[stick].num_axis = ((stick*2) == last_axis) ? 1 : 2; _GrGetControlName(slot_index[i], GRIP_CLASS_AXIS, stick*2, tmpstr); if (tmpstr[0] == '\0') _al_sane_strncpy(tmpstr, "X", sizeof(tmpstr)); SIMPLIFY_AXIS(tmpstr); joy[i].stick[stick].axis[0].name = get_config_text(tmpstr); joy[i].stick[stick].axis[0].pos = 0; joy[i].stick[stick].axis[0].d1 = 0; joy[i].stick[stick].axis[0].d2 = 0; if (joy[i].stick[stick].num_axis == 2) { _GrGetControlName(slot_index[i], GRIP_CLASS_AXIS, stick*2 + 1, tmpstr); if (tmpstr[0] == '\0') _al_sane_strncpy(tmpstr, "Y", sizeof(tmpstr)); SIMPLIFY_AXIS(tmpstr); joy[i].stick[stick].axis[1].name = get_config_text(tmpstr); joy[i].stick[stick].axis[1].pos = 0; joy[i].stick[stick].axis[1].d1 = 0; joy[i].stick[stick].axis[1].d2 = 0; } } } /* check for Analog pads (as in the Xterminator) */ if ((ENABLE_ANALOG) && (class_map & (1 << GRIP_CLASS_ANALOG)) && (_GrGetMaxIndex(slot_index[i], GRIP_CLASS_ANALOG) > 0)) { int num_pads = 0; int stick = 0; int analog_start; max_value[i][GRIP_CLASS_ANALOG] = _GrGetMaxValue(slot_index[i], GRIP_CLASS_ANALOG); num_pads = (_GrGetMaxIndex(slot_index[i], GRIP_CLASS_ANALOG) + 1) / 2; analog_start = joy[i].num_sticks; joy[i].num_sticks += num_pads; if (joy[i].num_sticks > MAX_JOYSTICK_STICKS) { num_pads -= joy[i].num_sticks - MAX_JOYSTICK_STICKS; joy[i].num_sticks = MAX_JOYSTICK_STICKS; } /* loop over each pair of analog pads on the device (often just 1) */ for (stick=analog_start; stick < analog_start+num_pads; stick++) { stick_class[i][stick] = GRIP_CLASS_ANALOG; /* name pad... :( */ _al_sane_strncpy(tmpstr, "Analog", sizeof(tmpstr)); if (num_pads > 1) { tmpstr[strlen(tmpstr)+2] = '\0'; tmpstr[strlen(tmpstr)+1] = '1'+stick-analog_start; tmpstr[strlen(tmpstr)] = ' '; } joy[i].stick[stick].name = get_config_text(tmpstr); joy[i].stick[stick].flags = JOYFLAG_ANALOG | JOYFLAG_SIGNED; /* name axes */ joy[i].stick[stick].num_axis = 2; _GrGetControlName(slot_index[i], GRIP_CLASS_ANALOG, (stick-analog_start)*2, tmpstr); if (tmpstr[0] == '\0') _al_sane_strncpy(tmpstr, "X", sizeof(tmpstr)); SIMPLIFY_AXIS(tmpstr); joy[i].stick[stick].axis[0].name = get_config_text(tmpstr); joy[i].stick[stick].axis[0].pos = 0; joy[i].stick[stick].axis[0].d1 = 0; joy[i].stick[stick].axis[0].d2 = 0; _GrGetControlName(slot_index[i], GRIP_CLASS_ANALOG, (stick-analog_start)*2 + 1, tmpstr); if (tmpstr[0] == '\0') _al_sane_strncpy(tmpstr, "Y", sizeof(tmpstr)); SIMPLIFY_AXIS(tmpstr); joy[i].stick[stick].axis[1].name = get_config_text(tmpstr); joy[i].stick[stick].axis[1].pos = 0; joy[i].stick[stick].axis[1].d1 = 0; joy[i].stick[stick].axis[1].d2 = 0; } } /* check for a Point-of-View Hat... */ if ((ENABLE_POV) && (class_map & (1 << GRIP_CLASS_POV_HAT)) && (_GrGetMaxIndex(slot_index[i], GRIP_CLASS_POV_HAT) > 0)) { int num_hats = 0; int stick = 0; int pov_start; max_value[i][GRIP_CLASS_POV_HAT] = _GrGetMaxValue(slot_index[i], GRIP_CLASS_POV_HAT); num_hats = (_GrGetMaxIndex(slot_index[i], GRIP_CLASS_POV_HAT) + 1) / 2; pov_start = joy[i].num_sticks; joy[i].num_sticks += num_hats; if (joy[i].num_sticks > MAX_JOYSTICK_STICKS) { num_hats -= joy[i].num_sticks - MAX_JOYSTICK_STICKS; joy[i].num_sticks = MAX_JOYSTICK_STICKS; } /* loop over each pov hat on the device (often just 1) */ for (stick=pov_start; stick < pov_start+num_hats; stick++) { stick_class[i][stick] = GRIP_CLASS_POV_HAT; /* name hat... :( */ _al_sane_strncpy(tmpstr, "Hat", sizeof(tmpstr)); if (num_hats > 1) { tmpstr[strlen(tmpstr)+2] = '\0'; tmpstr[strlen(tmpstr)+1] = '1'+stick-pov_start; tmpstr[strlen(tmpstr)] = ' '; } joy[i].stick[stick].name = get_config_text(tmpstr); joy[i].stick[stick].flags = JOYFLAG_DIGITAL | JOYFLAG_SIGNED; /* name axes */ joy[i].stick[stick].num_axis = 2; _GrGetControlName(slot_index[i], GRIP_CLASS_POV_HAT, (stick-pov_start)*2, tmpstr); if (tmpstr[0] == '\0') _al_sane_strncpy(tmpstr, "X", sizeof(tmpstr)); SIMPLIFY_AXIS(tmpstr); joy[i].stick[stick].axis[0].name = get_config_text(tmpstr); joy[i].stick[stick].axis[0].pos = 0; joy[i].stick[stick].axis[0].d1 = 0; joy[i].stick[stick].axis[0].d2 = 0; _GrGetControlName(slot_index[i], GRIP_CLASS_POV_HAT, (stick-pov_start)*2 + 1, tmpstr); if (tmpstr[0] == '\0') _al_sane_strncpy(tmpstr, "Y", sizeof(tmpstr)); SIMPLIFY_AXIS(tmpstr); joy[i].stick[stick].axis[1].name = get_config_text(tmpstr); joy[i].stick[stick].axis[1].pos = 0; joy[i].stick[stick].axis[1].d1 = 0; joy[i].stick[stick].axis[1].d2 = 0; } } /* check for throttles */ if ((ENABLE_THROTTLE) && (class_map & (1 << GRIP_CLASS_THROTTLE))) { int num_throt = 0; int num_throt_sticks = 0; int num_throt_extra_axes = 0; int stick = 0; int throttle_start; int throttle_count; max_value[i][GRIP_CLASS_THROTTLE] = _GrGetMaxValue(slot_index[i], GRIP_CLASS_THROTTLE); num_throt = _GrGetMaxIndex(slot_index[i], GRIP_CLASS_THROTTLE) + 1; if (PACK_THROTTLES) { num_throt_sticks = num_throt / MAX_JOYSTICK_AXIS; num_throt_extra_axes = num_throt % MAX_JOYSTICK_AXIS; } else { num_throt_sticks = num_throt; num_throt_extra_axes = 0; } throttle_start = joy[i].num_sticks; joy[i].num_sticks += num_throt_sticks; if (joy[i].num_sticks > MAX_JOYSTICK_STICKS) { num_throt_sticks -= joy[i].num_sticks - MAX_JOYSTICK_STICKS; joy[i].num_sticks = MAX_JOYSTICK_STICKS; } /* account for leftover axes, if packing: */ if ((num_throt_extra_axes) && (joy[i].num_sticks < MAX_JOYSTICK_STICKS)) { joy[i].num_sticks += 1; num_throt_sticks++; } else num_throt_extra_axes = 0; /* loop over each throttle on the device */ throttle_count = 0; for (stick=throttle_start; stick < throttle_start+num_throt_sticks; stick++) { int last_axis, a; if (PACK_THROTTLES) { if ((stick == throttle_start+num_throt_sticks-1) && (num_throt_extra_axes)) last_axis = num_throt_extra_axes; else last_axis = MAX_JOYSTICK_AXIS; } else last_axis = 1; stick_class[i][stick] = GRIP_CLASS_THROTTLE; joy[i].stick[stick].flags = JOYFLAG_ANALOG | JOYFLAG_SIGNED; joy[i].stick[stick].num_axis = last_axis; /* name throttle... */ _al_sane_strncpy(tmpstr, "Throttle", sizeof(tmpstr)); if (num_throt_sticks > 1) { tmpstr[strlen(tmpstr)+2] = '\0'; tmpstr[strlen(tmpstr)+1] = '1'+stick-throttle_start; tmpstr[strlen(tmpstr)] = ' '; } joy[i].stick[stick].name = get_config_text(tmpstr); for (a=0; a MAX_JOYSTICK_BUTTONS) joy[i].num_buttons = MAX_JOYSTICK_BUTTONS; for (b=0; b 32*1024)) return -1; /* open the loadable library file size */ if ((f = pack_fopen(name, F_READ)) == NULL) return -1; if ((image = malloc(size)) == NULL) { pack_fclose(f); return -1; } pack_fread(image, size, f); pack_fclose(f); /* link to the library (and free up the temporary memory) */ if (!_GrLink(image, size)) { free(image); return -1; } free(image); already_linked = 1; return 0; } static int grip_unlink(void) { already_linked = 0; if (!_GrUnlink()) return -1; return 0; }