123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- ========================
- Force feedback for Linux
- ========================
- :Author: Johann Deneux <[email protected]> on 2001/04/22.
- :Updated: Anssi Hannula <[email protected]> on 2006/04/09.
- You may redistribute this file. Please remember to include shape.svg and
- interactive.svg as well.
- Introduction
- ~~~~~~~~~~~~
- This document describes how to use force feedback devices under Linux. The
- goal is not to support these devices as if they were simple input-only devices
- (as it is already the case), but to really enable the rendering of force
- effects.
- This document only describes the force feedback part of the Linux input
- interface. Please read joydev/joystick.rst and input.rst before reading further
- this document.
- Instructions to the user
- ~~~~~~~~~~~~~~~~~~~~~~~~
- To enable force feedback, you have to:
- 1. have your kernel configured with evdev and a driver that supports your
- device.
- 2. make sure evdev module is loaded and /dev/input/event* device files are
- created.
- Before you start, let me WARN you that some devices shake violently during the
- initialisation phase. This happens for example with my "AVB Top Shot Pegasus".
- To stop this annoying behaviour, move your joystick to its limits. Anyway, you
- should keep a hand on your device, in order to avoid it to break down if
- something goes wrong.
- If you have a serial iforce device, you need to start inputattach. See
- joydev/joystick.rst for details.
- Does it work ?
- --------------
- There is an utility called fftest that will allow you to test the driver::
- % fftest /dev/input/eventXX
- Instructions to the developer
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- All interactions are done using the event API. That is, you can use ioctl()
- and write() on /dev/input/eventXX.
- This information is subject to change.
- Querying device capabilities
- ----------------------------
- ::
- #include <linux/input.h>
- #include <sys/ioctl.h>
- #define BITS_TO_LONGS(x) \
- (((x) + 8 * sizeof (unsigned long) - 1) / (8 * sizeof (unsigned long)))
- unsigned long features[BITS_TO_LONGS(FF_CNT)];
- int ioctl(int file_descriptor, int request, unsigned long *features);
- "request" must be EVIOCGBIT(EV_FF, size of features array in bytes )
- Returns the features supported by the device. features is a bitfield with the
- following bits:
- - FF_CONSTANT can render constant force effects
- - FF_PERIODIC can render periodic effects with the following waveforms:
- - FF_SQUARE square waveform
- - FF_TRIANGLE triangle waveform
- - FF_SINE sine waveform
- - FF_SAW_UP sawtooth up waveform
- - FF_SAW_DOWN sawtooth down waveform
- - FF_CUSTOM custom waveform
- - FF_RAMP can render ramp effects
- - FF_SPRING can simulate the presence of a spring
- - FF_FRICTION can simulate friction
- - FF_DAMPER can simulate damper effects
- - FF_RUMBLE rumble effects
- - FF_INERTIA can simulate inertia
- - FF_GAIN gain is adjustable
- - FF_AUTOCENTER autocenter is adjustable
- .. note::
- - In most cases you should use FF_PERIODIC instead of FF_RUMBLE. All
- devices that support FF_RUMBLE support FF_PERIODIC (square, triangle,
- sine) and the other way around.
- - The exact syntax FF_CUSTOM is undefined for the time being as no driver
- supports it yet.
- ::
- int ioctl(int fd, EVIOCGEFFECTS, int *n);
- Returns the number of effects the device can keep in its memory.
- Uploading effects to the device
- -------------------------------
- ::
- #include <linux/input.h>
- #include <sys/ioctl.h>
- int ioctl(int file_descriptor, int request, struct ff_effect *effect);
- "request" must be EVIOCSFF.
- "effect" points to a structure describing the effect to upload. The effect is
- uploaded, but not played.
- The content of effect may be modified. In particular, its field "id" is set
- to the unique id assigned by the driver. This data is required for performing
- some operations (removing an effect, controlling the playback).
- The "id" field must be set to -1 by the user in order to tell the driver to
- allocate a new effect.
- Effects are file descriptor specific.
- See <uapi/linux/input.h> for a description of the ff_effect struct. You
- should also find help in a few sketches, contained in files shape.svg
- and interactive.svg:
- .. kernel-figure:: shape.svg
- Shape
- .. kernel-figure:: interactive.svg
- Interactive
- Removing an effect from the device
- ----------------------------------
- ::
- int ioctl(int fd, EVIOCRMFF, effect.id);
- This makes room for new effects in the device's memory. Note that this also
- stops the effect if it was playing.
- Controlling the playback of effects
- -----------------------------------
- Control of playing is done with write(). Below is an example:
- ::
- #include <linux/input.h>
- #include <unistd.h>
- struct input_event play;
- struct input_event stop;
- struct ff_effect effect;
- int fd;
- ...
- fd = open("/dev/input/eventXX", O_RDWR);
- ...
- /* Play three times */
- play.type = EV_FF;
- play.code = effect.id;
- play.value = 3;
- write(fd, (const void*) &play, sizeof(play));
- ...
- /* Stop an effect */
- stop.type = EV_FF;
- stop.code = effect.id;
- stop.value = 0;
- write(fd, (const void*) &stop, sizeof(stop));
- Setting the gain
- ----------------
- Not all devices have the same strength. Therefore, users should set a gain
- factor depending on how strong they want effects to be. This setting is
- persistent across access to the driver.
- ::
- /* Set the gain of the device
- int gain; /* between 0 and 100 */
- struct input_event ie; /* structure used to communicate with the driver */
- ie.type = EV_FF;
- ie.code = FF_GAIN;
- ie.value = 0xFFFFUL * gain / 100;
- if (write(fd, &ie, sizeof(ie)) == -1)
- perror("set gain");
- Enabling/Disabling autocenter
- -----------------------------
- The autocenter feature quite disturbs the rendering of effects in my opinion,
- and I think it should be an effect, which computation depends on the game
- type. But you can enable it if you want.
- ::
- int autocenter; /* between 0 and 100 */
- struct input_event ie;
- ie.type = EV_FF;
- ie.code = FF_AUTOCENTER;
- ie.value = 0xFFFFUL * autocenter / 100;
- if (write(fd, &ie, sizeof(ie)) == -1)
- perror("set auto-center");
- A value of 0 means "no auto-center".
- Dynamic update of an effect
- ---------------------------
- Proceed as if you wanted to upload a new effect, except that instead of
- setting the id field to -1, you set it to the wanted effect id.
- Normally, the effect is not stopped and restarted. However, depending on the
- type of device, not all parameters can be dynamically updated. For example,
- the direction of an effect cannot be updated with iforce devices. In this
- case, the driver stops the effect, up-load it, and restart it.
- Therefore it is recommended to dynamically change direction while the effect
- is playing only when it is ok to restart the effect with a replay count of 1.
- Information about the status of effects
- ---------------------------------------
- Every time the status of an effect is changed, an event is sent. The values
- and meanings of the fields of the event are as follows::
- struct input_event {
- /* When the status of the effect changed */
- struct timeval time;
- /* Set to EV_FF_STATUS */
- unsigned short type;
- /* Contains the id of the effect */
- unsigned short code;
- /* Indicates the status */
- unsigned int value;
- };
- FF_STATUS_STOPPED The effect stopped playing
- FF_STATUS_PLAYING The effect started to play
- .. note::
- - Status feedback is only supported by iforce driver. If you have
- a really good reason to use this, please contact
- [email protected] or [email protected]
- so that support for it can be added to the rest of the drivers.
|