[PATCH] evdev and 3DConnexion SpaceTraveler

Barton C Massey bart at cs.pdx.edu
Tue Feb 6 00:30:19 PST 2007


You probably want to fix the Linux driver such that the
device features will be correctly recognized.  This is
usually doable if you're OK with touching the kernel.

I have no idea what kernel Ubuntu 6.10 uses, but kernels
2.6.18 and later have a bugfix I put in that might just fix
your problem already.

	Bart

In message <45C7DB87.8040403 at ccom.unh.edu> you wrote:
> Hello all,
> 
> This is my first list message, first patch submission, first time using 
> git and first time hacking Xserver code, so please be gentle with me! :)
> 
> Anyways, I have been trying to get my 3DConnexion SpaceTraveler to be 
> supported by glut like the old SpaceBalls used to be. Fortunately, the 
> device automatically showed up as an input device when plugged into my 
> Ubuntu 6.10 box. Here's the relevant section from /proc/bus/input/devices
> 
> I: Bus=0003 Vendor=046d Product=c623 Version=0311
> N: Name="3Dconnexion SpaceTraveler USB"
> P: Phys=usb-0000:00:02.0-5/input0
> S: Sysfs=/class/input/input7
> H: Handlers=event3
> B: EV=7
> B: KEY=ff 0 0 0 0
> B: REL=3f
> 
> A few problems surfaced as I tried to configure it as an XInput device 
> using the evdev driver. Here are the problems and how I dealt with them 
> in the attached patch.
> 
> * The axis are reported as relative, but they should be treated as absolute.
> 
> -  I simply allowed the "Mode" "Absolute" option to work with relative axes.
> 
> * Min and Max values are not made available to XInput, but glut expects 
> them to be valid.
> 
> - I just hard coded the values used in the magellan input driver. (I 
> probably should have added options for this as well...)
> 
> * Glut expects the device to be named "spaceball", not 
> "spaceball-some-other-stuff"
> 
> - I added a "ForceID" option that allows to override the generated name 
> for the device. I'm assuming the generated name is to prevent name 
> conflicts, so using this option should be considered risky, and should 
> only be used if really needed.
> 
> * An event was created for each individual axes.
> 
> - I added a "Type" option, and if it is set to "Spaceball", state->sync 
> is set to 1, fixing the problem. It also sets the type_name to 
> XI_SPACEBALL instead of the default XI_MOUSE.
> 
> 
> Here's my resulting xorg.conf entry to make it work:
> 
> Section "InputDevice"
>          Identifier      "spaceball"
>          Driver          "evdev"
>          Option          "Name" "3Dconnexion*"
>          Option          "Mode" "Absolute"
>          Option          "ZRelativeAxisButtons" "0 0"
>          Option          "Type" "Spaceball"
>          Option          "ForceID" "spaceball"
> EndSection
> 
> 
> This allowed me to move and rotate the dinosaur in the glut dinoball 
> demo! (Woohoo a working spaceball!!!)
> 
> Does this seem like a reasonable way of getting the SpaceTraveler to 
> work, or is it better to have a separate, specific driver? I suspect 
> that other devices might have some of the problems I encountered, and 
> could use the added options, making this patch belong here. On the other 
> hand, maybe evdev is not meant to get bloated with such special cases.
> 
> Either way, what's the best way to make this, or an alternative solution 
> to supporting 3DConnexion devices part of a future release?
> 
> Thanks
> 
> Roland
> 
> 
> 
> -- 
> Roland Arsenault
> 
> Center for Coastal and Ocean Mapping
> University of New Hampshire
> Durham, New Hampshire
> 03824-3525
> 
> roland at ccom.unh.edu
> 
> Work: (603)862-3702
> Fax:  (603)862-0839
> 
> --------------040904010700020508030208
> Content-Type: text/x-patch;
>  name="xf86-input-evdev-spaceball.patch"
> Content-Transfer-Encoding: 7bit
> Content-Disposition: inline;
>  filename="xf86-input-evdev-spaceball.patch"
> 
> #
> # Updated but not checked in:
> #   (will commit)
> #
> #	modified: src/evdev.c
> #	modified: src/evdev.h
> #	modified: src/evdev_axes.c
> #	modified: src/evdev_btn.c
> #
> #
> # Untracked files:
> #   (use "git add" to add to commit)
> #
> #	mkinstalldirs
> #	xf86-input-evdev-spaceball.patch
> diff --git a/src/evdev.c b/src/evdev.c
> index 1bcaef8..b0eef30 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -236,10 +236,7 @@ EvdevSwitchMode (ClientPtr client, Devic
>  	case Absolute:
>  	case Relative:
>  	    xf86Msg(X_INFO, "%s: Switching mode to %d.\n", pInfo->name, mode);
> -	    if (state->abs)
>  		state->mode = mode;
> -	    else
> -		return !Success;
>  	    break;
>  #if 0
>  	case SendCoreEvents:
> @@ -259,15 +256,13 @@ EvdevNew(evdevDriverPtr driver, evdevDev
>  {
>      InputInfoPtr pInfo;
>      char name[512] = {0};
> +    char *s, option[64];
>  
>      if (!(pInfo = xf86AllocateInput(driver->drv, 0)))
>  	return 0;
>  
>      /* Initialise the InputInfoRec. */
> -    strncat (name, driver->dev->identifier, sizeof(name));
> -    strncat (name, "-", sizeof(name));
> -    strncat (name, device->phys, sizeof(name));
> -    pInfo->name = xstrdup(name);
> +
>      pInfo->flags = 0;
>      pInfo->type_name = "UNKNOWN";
>      pInfo->device_control = EvdevProc;
> @@ -285,6 +280,10 @@ #endif
>  
>      xf86CollectInputOptions(pInfo, NULL, NULL);
>      xf86ProcessCommonOptions(pInfo, pInfo->options);
> +    strncat (name, driver->dev->identifier, sizeof(name));
> +    strncat (name, "-", sizeof(name));
> +    strncat (name, device->phys, sizeof(name));
> +    pInfo->name = xstrdup(xf86SetStrOption(pInfo->options, "ForceID", name));
>  
>      if ((pInfo->fd = evdevGetFDForDevice (device)) == -1) {
>  	xf86Msg(X_ERROR, "%s: cannot open input device\n", pInfo->name);
> diff --git a/src/evdev.h b/src/evdev.h
> index f682312..a46381f 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -183,12 +183,16 @@ typedef struct {
>      int		axes;
>      int		v[REL_MAX];
>      int		count;
> +    int     min[REL_MAX];
> +    int     max[REL_MAX];
>      int		map[REL_MAX];
>      int		btnMap[REL_MAX][2];
>  } evdevRelRec, *evdevRelPtr;
>  
>  typedef struct {
>      int		axes;
> +    int		min[ABS_MAX];
> +    int		max[ABS_MAX];
>      int		v[ABS_MAX];
>  } evdevAxesRec, *evdevAxesPtr;
>  
> diff --git a/src/evdev_axes.c b/src/evdev_axes.c
> index 9d2ef20..b10ecc5 100644
> --- a/src/evdev_axes.c
> +++ b/src/evdev_axes.c
> @@ -318,8 +318,12 @@ EvdevAxesRelSynRep (InputInfoPtr pInfo)
>  	rel->v[i] = 0;
>      }
>  
> -    EvdevAxesRealSyn (pInfo, 0, 0);
> -    rel->count = 0;
> +    if(state->mode == Relative)
> +        EvdevAxesRealSyn (pInfo, 0, 0);
> +    else
> +        EvdevAxesRealSyn (pInfo, 1, 0);
> +    state->rel->count = 0;
> +
>  }
>  
>  void
> @@ -369,11 +373,18 @@ EvdevAxesRelProcess (InputInfoPtr pInfo,
>      if (ev->code >= REL_MAX)
>  	return;
>  
> +
>      map = state->rel->map[ev->code];
>      if (map >= 0)
> +        if (state->mode == Relative)
>  	state->rel->v[map] += ev->value;
>      else
> +            state->rel->v[map] = ev->value;
> +    else
> +        if (state->mode == Relative)
>  	state->rel->v[-map] -= ev->value;
> +        else
> +            state->rel->v[-map] = ev->value;
>  
>      state->rel->count++;
>  
> @@ -539,7 +550,18 @@ EvdevAxisRelNew0(InputInfoPtr pInfo)
>      xf86Msg(X_INFO, "%s: Configuring as pointer.\n", pInfo->name);
>      pInfo->flags |= XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS |
>  	XI86_CONFIGURED;
> -    pInfo->type_name = XI_MOUSE;
> +
> +    s = xf86SetStrOption(pInfo->options, "Type", "Mouse");
> +    if (!strcasecmp(s, "Spaceball")) {
> +        pInfo->type_name = XI_SPACEBALL;
> +        state->sync = 1;
> +        xf86Msg(X_CONFIG, "%s: Configuring type as %s mode.\n", pInfo->name, s);
> +    } else {
> +        pInfo->type_name = XI_MOUSE;
> +    }
> +
> +
> +
>      pInfo->conversion_proc = EvdevConvert;
>  
>      for (i = 0, j = 0; i < REL_MAX; i++) {
> @@ -575,6 +597,9 @@ EvdevAxisRelNew0(InputInfoPtr pInfo)
>  	    xf86Msg(X_CONFIG, "%s: %s: %d %d.\n", pInfo->name, option,
>  		    state->rel->btnMap[k][0], state->rel->btnMap[k][1]);
>  
> +    state->rel->min[state->rel->map[i]]=-1800;
> +    state->rel->max[state->rel->map[i]]= 1800;
> +
>  	j++;
>      }
>  
> @@ -594,13 +619,25 @@ EvdevAxisRelNew1(InputInfoPtr pInfo)
>  {
>      evdevDevicePtr pEvdev = pInfo->private;
>      evdevStatePtr state = &pEvdev->state;
> +    char *s;
>  
>      if (!state->rel)
> -	return !Success;
> +    	return !Success;
>  
>      xf86Msg(X_CONFIG, "%s: Configuring %d relative axes.\n", pInfo->name,
>  	    state->rel->axes);
>  
> +    s = xf86SetStrOption(pInfo->options, "Mode", "Relative");
> +    if (!strcasecmp(s, "Absolute")) {
> +        state->mode = Absolute;
> +        xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
> +    } else if (!strcasecmp(s, "Relative")) {
> +        state->mode = Relative;
> +        xf86Msg(X_CONFIG, "%s: Configuring in %s mode.\n", pInfo->name, s);
> +    } else {
> +        state->mode = Relative;
> +        xf86Msg(X_CONFIG, "%s: Unknown Mode: %s.\n", pInfo->name, s);
> +    }
>      return Success;
>  }
>  
> @@ -633,12 +670,12 @@ EvdevAxesNew1 (InputInfoPtr pInfo)
>  
>      state->axes = Xcalloc (sizeof (evdevAxesRec));
>      if (EvdevAxisAbsNew1(pInfo) != Success)
> -	ret = !Success;
> +        ret = !Success;
>      if (EvdevAxisRelNew1(pInfo) != Success)
> -	ret = !Success;
> +        ret = !Success;
>      if (!state->abs && !state->rel) {
> -	Xfree (state->axes);
> -	state->axes = NULL;
> +        Xfree (state->axes);
> +        state->axes = NULL;
>      }
>  
>      return ret;
> @@ -660,9 +697,23 @@ EvdevAxesInit (DeviceIntPtr device)
>      int i, axes = 0;
>  
>      if (state->abs && state->abs->axes > axes)
> -	axes = state->abs->axes;
> +    {
> +        axes = state->abs->axes;
> +        for (i = 0; i < axes; i++)
> +        {
> +            state->axes->min[i] = state->abs->min[i];
> +            state->axes->max[i] = state->abs->max[i];
> +        }
> +    }
>      if (state->rel && state->rel->axes > axes)
> -	axes = state->rel->axes;
> +    {
> +        axes = state->rel->axes;
> +        for (i = 0; i < axes; i++)
> +        {
> +            state->axes->min[i] = state->rel->min[i];
> +            state->axes->max[i] = state->rel->max[i];
> +        }
> +    }
>  
>      state->axes->axes = axes;
>  
> @@ -683,7 +734,7 @@ #endif
>          return !Success;
>  
>      for (i = 0; i < axes; i++) {
> -	xf86InitValuatorAxisStruct(device, i, 0, -1, 0, 0, 1);
> +        xf86InitValuatorAxisStruct(device, i, state->axes->min[i], state->axes->max[i], 1, 1, 1);
>  	xf86InitValuatorDefaults(device, i);
>      }
>  
> diff --git a/src/evdev_btn.c b/src/evdev_btn.c
> index b9bfe07..a769434 100644
> --- a/src/evdev_btn.c
> +++ b/src/evdev_btn.c
> @@ -346,6 +346,7 @@ EvdevBtnNew1(InputInfoPtr pInfo)
>  {
>      evdevDevicePtr pEvdev = pInfo->private;
>      evdevStatePtr state = &pEvdev->state;
> +    char *s;
>  
>      if (!state->btn)
>  	return !Success;
> @@ -365,7 +366,14 @@ EvdevBtnNew1(InputInfoPtr pInfo)
>       * FIXME: Mouse may not be accurate.
>       * Check buttons to see if we're actually a joystick or something.
>       */
> -    pInfo->type_name = XI_MOUSE;
> +    s = xf86SetStrOption(pInfo->options, "Type", "Mouse");
> +    if (!strcasecmp(s, "Spaceball")) {
> +        pInfo->type_name = XI_SPACEBALL;
> +        state->sync = 1;
> +        xf86Msg(X_CONFIG, "%s: Configuring type as %s mode.\n", pInfo->name, s);
> +    } else {
> +        pInfo->type_name = XI_MOUSE;
> +    }
>  
>      return Success;
>  }
> 
> --------------040904010700020508030208
> Content-Type: text/plain; charset="us-ascii"
> MIME-Version: 1.0
> Content-Transfer-Encoding: 7bit
> Content-Disposition: inline
> 
> _______________________________________________
> xorg mailing list
> xorg at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/xorg
> --------------040904010700020508030208--



More information about the xorg mailing list