Date: Sun, 1 Jun 2003 15:38:45 -0700 (PDT)
authorSam Lantinga <slouken@libsdl.org>
Mon, 02 Jun 2003 14:50:22 +0000
changeset 63285e104fe14c2
parent 631 52864d66d168
child 633 873c2598f969
Date: Sun, 1 Jun 2003 15:38:45 -0700 (PDT)
From: Jeff Brown <jabrown@caida.org>
Subject: [patch] SDL-1.2.5 + FreeBSD joystick axes, hat fixes

Hello again! When I sent in some SDL fixes last December, I found out
they'd already been fixed in the CVS version. This time, I checked the
repository before bugging you. =)

I'm using SDL-1.2.5 on a FreeBSD 4.6.2-RELEASE system, and in the course
of getting my multi-analog-axis USB controller (with a hat switch!)
working with d2x-sdl -- the SDL port of the Descent 2 engine -- I came
across a few problems:

1) The second analog stick is reported as a slider in one direction, and
"Rz" in the other. SDL was ignoring the Rz axis, so I added Rx/Ry/Rz to
the set of things SDL considers to be axes.

2) After the above change, the set of JOYAXE_* axes for my gamepad was
{0,1,3,7}; however, d2x-sdl expects the axes to be contiguously numbered
from 0, which seems like a pretty reasonable expectation, rather than
having to scan the entire space of axes that SDL may or may not have.
So, I added a table lookup which maps the JOYAXE_* axis numbers to 0,1,...
in the order they're detected by SDL_SYS_JoystickOpen(), when reporting
them to the application. I also added a function "usage_to_joyaxe()"
which maps the USB HUG_* usage values to JOYAXE_values, since the repeated
case statements testing for HUG_* were getting out of hand.

3) The BSD joystick driver had no hat support, so I added it. It looks
like our USB library can only support one hat switch per device, which
makes life easy.

The patch against SDL-1.2.5 which implements these changes is at:

http://www.caida.org/~jabrown/patches/sdl-1.2.5-bsdhat.diff

After applying, SDL's "testjoystick" reports all activity from my gamepad
correctly, and d2x works too (though it needed some other fixes).

Moving on...

There is also a problem with slightly different USBHID library interfaces
on different versions of FreeBSD. I wasn't going to mention this since the
FreeBSD port for SDL-1.2.5 (and not SDL itself) was doing the FreeBSD
version-specific patching, so I e-mailed the port maintainer with this
change. However, I see that you've incorporated the FreeBSD
version-checking stuff into the CVS version of SDL, so now it's relevant
for you too.

The problem is, the FreeBSD #if tests don't work right for FreeBSD
4.6.2-RELEASE. There may be other versions with this problem, but I've
only tested 4.6.2-R. The following patch against your latest CVS version
fixes this:

--- SDL_sysjoystick.c-1.16 Tue Apr 15 09:02:08 2003
+++ SDL_sysjoystick.c Sun Jun 1 15:10:28 2003
@@ -420,6 +420,8 @@
# else
len = hid_report_size(rd, repinfo[repind].kind, r->rid);
# endif
+# elif (__FreeBSD_version == 460002)
+ len = hid_report_size(rd, r->rid, repinfo[repind].kind);
# else
len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
#endif


I hope this is all useful to you. I've been getting myself dizzy playing
Descent 2 with it, all morning!

-Jeff Brown


P.S. My USB controller is a Thrustmaster Firestorm Dual Analog 2. That's
probably irrelevant, but I threw it in for completeness.
src/joystick/bsd/SDL_sysjoystick.c
     1.1 --- a/src/joystick/bsd/SDL_sysjoystick.c	Thu May 29 04:52:36 2003 +0000
     1.2 +++ b/src/joystick/bsd/SDL_sysjoystick.c	Mon Jun 02 14:50:22 2003 +0000
     1.3 @@ -100,7 +100,11 @@
     1.4  	JOYAXE_Y,
     1.5  	JOYAXE_Z,
     1.6  	JOYAXE_SLIDER,
     1.7 -	JOYAXE_WHEEL
     1.8 +	JOYAXE_WHEEL,
     1.9 +	JOYAXE_RX,
    1.10 +	JOYAXE_RY,
    1.11 +	JOYAXE_RZ,
    1.12 +	JOYAXE_count
    1.13  };
    1.14  
    1.15  struct joystick_hwdata {
    1.16 @@ -112,10 +116,7 @@
    1.17  	} type;
    1.18  	struct	report_desc *repdesc;
    1.19  	struct	report inreport;
    1.20 -#if 0
    1.21 -	int	axismin[];
    1.22 -	int	axismax[];
    1.23 -#endif
    1.24 +	int	axis_map[JOYAXE_count];	/* map present JOYAXE_* to 0,1,..*/
    1.25  };
    1.26  
    1.27  static char *joynames[MAX_JOYS];
    1.28 @@ -180,6 +181,49 @@
    1.29  	return (joynames[index]);
    1.30  }
    1.31  
    1.32 +static int
    1.33 +usage_to_joyaxe(unsigned usage)
    1.34 +{
    1.35 +    int joyaxe;
    1.36 +    switch (usage) {
    1.37 +    case HUG_X:
    1.38 +	joyaxe = JOYAXE_X; break;
    1.39 +    case HUG_Y:
    1.40 +	joyaxe = JOYAXE_Y; break;
    1.41 +    case HUG_Z:
    1.42 +	joyaxe = JOYAXE_Z; break;
    1.43 +    case HUG_SLIDER:
    1.44 +	joyaxe = JOYAXE_SLIDER; break;
    1.45 +    case HUG_WHEEL:
    1.46 +	joyaxe = JOYAXE_WHEEL; break;
    1.47 +    case HUG_RX:
    1.48 +	joyaxe = JOYAXE_RX; break;
    1.49 +    case HUG_RY:
    1.50 +	joyaxe = JOYAXE_RY; break;
    1.51 +    case HUG_RZ:
    1.52 +	joyaxe = JOYAXE_RZ; break;
    1.53 +    default:
    1.54 +	joyaxe = -1;
    1.55 +    }
    1.56 +    return joyaxe;    
    1.57 +}
    1.58 +
    1.59 +static unsigned
    1.60 +hatval_to_sdl(Sint32 hatval)
    1.61 +{
    1.62 +    static const unsigned hat_dir_map[8] = {
    1.63 +	SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN, 
    1.64 +	SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
    1.65 +    };
    1.66 +    unsigned result;
    1.67 +    if ((hatval & 7) == hatval) 
    1.68 +	result = hat_dir_map[hatval];
    1.69 +    else 
    1.70 +	result = SDL_HAT_CENTERED;
    1.71 +    return result;
    1.72 +}
    1.73 +
    1.74 +
    1.75  int
    1.76  SDL_SYS_JoystickOpen(SDL_Joystick *joy)
    1.77  {
    1.78 @@ -206,6 +250,11 @@
    1.79  	hw->fd = fd;
    1.80  	hw->path = strdup(path);
    1.81  	hw->type = BSDJOY_UHID;
    1.82 +	{
    1.83 +	    int ax;
    1.84 +	    for (ax = 0; ax < JOYAXE_count; ax++)
    1.85 +		hw->axis_map[ax] = -1;
    1.86 +	}
    1.87  	hw->repdesc = hid_get_report_desc(fd);
    1.88  	if (hw->repdesc == NULL) {
    1.89  		SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
    1.90 @@ -259,23 +308,17 @@
    1.91  			break;
    1.92  		case hid_input:
    1.93  			switch (HID_PAGE(hitem.usage)) {
    1.94 -			case HUP_GENERIC_DESKTOP:
    1.95 -				switch (HID_USAGE(hitem.usage)) {
    1.96 -				case HUG_X:
    1.97 -				case HUG_Y:
    1.98 -				case HUG_Z:
    1.99 -				case HUG_SLIDER:
   1.100 -				case HUG_WHEEL:
   1.101 -#if 0
   1.102 -					hw->axismin[joy->naxes] =
   1.103 -					    hitem.logical_minimum;
   1.104 -					hw->axismax[joy->naxes] =
   1.105 -					    hitem.logical_maximum;
   1.106 -#endif
   1.107 -					joy->naxes++;
   1.108 -					break;
   1.109 -				}
   1.110 -				break;
   1.111 +			case HUP_GENERIC_DESKTOP: {
   1.112 +			    unsigned usage = HID_USAGE(hitem.usage);
   1.113 +			    int joyaxe = usage_to_joyaxe(usage);
   1.114 +			    if (joyaxe >= 0) {
   1.115 +				hw->axis_map[joyaxe] = joy->naxes;
   1.116 +				joy->naxes++;
   1.117 +			    } else if (usage == HUG_HAT_SWITCH) {
   1.118 +				joy->nhats++;
   1.119 +			    }
   1.120 +			    break;
   1.121 +			}
   1.122  			case HUP_BUTTON:
   1.123  				joy->nbuttons++;
   1.124  				break;
   1.125 @@ -329,35 +372,26 @@
   1.126  		switch (hitem.kind) {
   1.127  		case hid_input:
   1.128  			switch (HID_PAGE(hitem.usage)) {
   1.129 -			case HUP_GENERIC_DESKTOP:
   1.130 -				switch (HID_USAGE(hitem.usage)) {
   1.131 -				case HUG_X:
   1.132 -					naxe = JOYAXE_X;
   1.133 -					goto scaleaxe;
   1.134 -				case HUG_Y:
   1.135 -					naxe = JOYAXE_Y;
   1.136 -					goto scaleaxe;
   1.137 -				case HUG_Z:
   1.138 -					naxe = JOYAXE_Z;
   1.139 -					goto scaleaxe;
   1.140 -				case HUG_SLIDER:
   1.141 -					naxe = JOYAXE_SLIDER;
   1.142 -					goto scaleaxe;
   1.143 -				case HUG_WHEEL:
   1.144 -					naxe = JOYAXE_WHEEL;
   1.145 -					goto scaleaxe;
   1.146 -				default:
   1.147 -					continue;
   1.148 -				}
   1.149 -scaleaxe:
   1.150 +			case HUP_GENERIC_DESKTOP: {
   1.151 +			    unsigned usage = HID_USAGE(hitem.usage);
   1.152 +			    int joyaxe = usage_to_joyaxe(usage);
   1.153 +			    if (joyaxe >= 0) {
   1.154 +				naxe = joy->hwdata->axis_map[joyaxe];
   1.155 +				/* scaleaxe */
   1.156  				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
   1.157 -				    &hitem);
   1.158 +							 &hitem);
   1.159  				v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2;
   1.160  				v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2);
   1.161  				if (v != joy->axes[naxe]) {
   1.162 -					SDL_PrivateJoystickAxis(joy, naxe, v);
   1.163 +				    SDL_PrivateJoystickAxis(joy, naxe, v);
   1.164  				}
   1.165 -				break;
   1.166 +			    } else if (usage == HUG_HAT_SWITCH) {
   1.167 +				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
   1.168 +							 &hitem);
   1.169 +				SDL_PrivateJoystickHat(joy, 0, hatval_to_sdl(v));
   1.170 +			    }
   1.171 +			    break;
   1.172 +			}
   1.173  			case HUP_BUTTON:
   1.174  				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
   1.175  				    &hitem);
   1.176 @@ -420,6 +454,8 @@
   1.177  #  else
   1.178  	len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   1.179  #  endif
   1.180 +# elif (__FreeBSD_version == 460002)
   1.181 +	len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   1.182  # else
   1.183  	len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   1.184  #endif