Date: Sun, 1 Jun 2003 15:38:45 -0700 (PDT)
authorSam Lantinga <slouken@libsdl.org>
Mon, 02 Jun 2003 14:50:22 +0000
changeset 632 85e104fe14c2
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
--- a/src/joystick/bsd/SDL_sysjoystick.c	Thu May 29 04:52:36 2003 +0000
+++ b/src/joystick/bsd/SDL_sysjoystick.c	Mon Jun 02 14:50:22 2003 +0000
@@ -100,7 +100,11 @@
 	JOYAXE_Y,
 	JOYAXE_Z,
 	JOYAXE_SLIDER,
-	JOYAXE_WHEEL
+	JOYAXE_WHEEL,
+	JOYAXE_RX,
+	JOYAXE_RY,
+	JOYAXE_RZ,
+	JOYAXE_count
 };
 
 struct joystick_hwdata {
@@ -112,10 +116,7 @@
 	} type;
 	struct	report_desc *repdesc;
 	struct	report inreport;
-#if 0
-	int	axismin[];
-	int	axismax[];
-#endif
+	int	axis_map[JOYAXE_count];	/* map present JOYAXE_* to 0,1,..*/
 };
 
 static char *joynames[MAX_JOYS];
@@ -180,6 +181,49 @@
 	return (joynames[index]);
 }
 
+static int
+usage_to_joyaxe(unsigned usage)
+{
+    int joyaxe;
+    switch (usage) {
+    case HUG_X:
+	joyaxe = JOYAXE_X; break;
+    case HUG_Y:
+	joyaxe = JOYAXE_Y; break;
+    case HUG_Z:
+	joyaxe = JOYAXE_Z; break;
+    case HUG_SLIDER:
+	joyaxe = JOYAXE_SLIDER; break;
+    case HUG_WHEEL:
+	joyaxe = JOYAXE_WHEEL; break;
+    case HUG_RX:
+	joyaxe = JOYAXE_RX; break;
+    case HUG_RY:
+	joyaxe = JOYAXE_RY; break;
+    case HUG_RZ:
+	joyaxe = JOYAXE_RZ; break;
+    default:
+	joyaxe = -1;
+    }
+    return joyaxe;    
+}
+
+static unsigned
+hatval_to_sdl(Sint32 hatval)
+{
+    static const unsigned hat_dir_map[8] = {
+	SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN, 
+	SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
+    };
+    unsigned result;
+    if ((hatval & 7) == hatval) 
+	result = hat_dir_map[hatval];
+    else 
+	result = SDL_HAT_CENTERED;
+    return result;
+}
+
+
 int
 SDL_SYS_JoystickOpen(SDL_Joystick *joy)
 {
@@ -206,6 +250,11 @@
 	hw->fd = fd;
 	hw->path = strdup(path);
 	hw->type = BSDJOY_UHID;
+	{
+	    int ax;
+	    for (ax = 0; ax < JOYAXE_count; ax++)
+		hw->axis_map[ax] = -1;
+	}
 	hw->repdesc = hid_get_report_desc(fd);
 	if (hw->repdesc == NULL) {
 		SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
@@ -259,23 +308,17 @@
 			break;
 		case hid_input:
 			switch (HID_PAGE(hitem.usage)) {
-			case HUP_GENERIC_DESKTOP:
-				switch (HID_USAGE(hitem.usage)) {
-				case HUG_X:
-				case HUG_Y:
-				case HUG_Z:
-				case HUG_SLIDER:
-				case HUG_WHEEL:
-#if 0
-					hw->axismin[joy->naxes] =
-					    hitem.logical_minimum;
-					hw->axismax[joy->naxes] =
-					    hitem.logical_maximum;
-#endif
-					joy->naxes++;
-					break;
-				}
-				break;
+			case HUP_GENERIC_DESKTOP: {
+			    unsigned usage = HID_USAGE(hitem.usage);
+			    int joyaxe = usage_to_joyaxe(usage);
+			    if (joyaxe >= 0) {
+				hw->axis_map[joyaxe] = joy->naxes;
+				joy->naxes++;
+			    } else if (usage == HUG_HAT_SWITCH) {
+				joy->nhats++;
+			    }
+			    break;
+			}
 			case HUP_BUTTON:
 				joy->nbuttons++;
 				break;
@@ -329,35 +372,26 @@
 		switch (hitem.kind) {
 		case hid_input:
 			switch (HID_PAGE(hitem.usage)) {
-			case HUP_GENERIC_DESKTOP:
-				switch (HID_USAGE(hitem.usage)) {
-				case HUG_X:
-					naxe = JOYAXE_X;
-					goto scaleaxe;
-				case HUG_Y:
-					naxe = JOYAXE_Y;
-					goto scaleaxe;
-				case HUG_Z:
-					naxe = JOYAXE_Z;
-					goto scaleaxe;
-				case HUG_SLIDER:
-					naxe = JOYAXE_SLIDER;
-					goto scaleaxe;
-				case HUG_WHEEL:
-					naxe = JOYAXE_WHEEL;
-					goto scaleaxe;
-				default:
-					continue;
-				}
-scaleaxe:
+			case HUP_GENERIC_DESKTOP: {
+			    unsigned usage = HID_USAGE(hitem.usage);
+			    int joyaxe = usage_to_joyaxe(usage);
+			    if (joyaxe >= 0) {
+				naxe = joy->hwdata->axis_map[joyaxe];
+				/* scaleaxe */
 				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
-				    &hitem);
+							 &hitem);
 				v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2;
 				v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2);
 				if (v != joy->axes[naxe]) {
-					SDL_PrivateJoystickAxis(joy, naxe, v);
+				    SDL_PrivateJoystickAxis(joy, naxe, v);
 				}
-				break;
+			    } else if (usage == HUG_HAT_SWITCH) {
+				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
+							 &hitem);
+				SDL_PrivateJoystickHat(joy, 0, hatval_to_sdl(v));
+			    }
+			    break;
+			}
 			case HUP_BUTTON:
 				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
 				    &hitem);
@@ -420,6 +454,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