Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 1 | ======================== |
| 2 | Force feedback for Linux |
| 3 | ======================== |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 5 | :Author: Johann Deneux <johann.deneux@gmail.com> on 2001/04/22. |
| 6 | :Updated: Anssi Hannula <anssi.hannula@gmail.com> on 2006/04/09. |
| 7 | |
Mauro Carvalho Chehab | deeb1e9 | 2017-04-04 21:42:54 -0700 | [diff] [blame] | 8 | You may redistribute this file. Please remember to include shape.svg and |
| 9 | interactive.svg as well. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 11 | Introduction |
| 12 | ~~~~~~~~~~~~ |
| 13 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | This document describes how to use force feedback devices under Linux. The |
| 15 | goal is not to support these devices as if they were simple input-only devices |
| 16 | (as it is already the case), but to really enable the rendering of force |
| 17 | effects. |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 18 | This document only describes the force feedback part of the Linux input |
| 19 | interface. Please read joystick.txt and input.txt before reading further this |
| 20 | document. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 22 | Instructions to the user |
| 23 | ~~~~~~~~~~~~~~~~~~~~~~~~ |
| 24 | |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 25 | To enable force feedback, you have to: |
| 26 | |
| 27 | 1. have your kernel configured with evdev and a driver that supports your |
| 28 | device. |
| 29 | 2. make sure evdev module is loaded and /dev/input/event* device files are |
| 30 | created. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | |
| 32 | Before you start, let me WARN you that some devices shake violently during the |
| 33 | initialisation phase. This happens for example with my "AVB Top Shot Pegasus". |
| 34 | To stop this annoying behaviour, move you joystick to its limits. Anyway, you |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 35 | should keep a hand on your device, in order to avoid it to break down if |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 36 | something goes wrong. |
| 37 | |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 38 | If you have a serial iforce device, you need to start inputattach. See |
| 39 | joystick.txt for details. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 41 | Does it work ? |
| 42 | -------------- |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 44 | There is an utility called fftest that will allow you to test the driver:: |
| 45 | |
| 46 | % fftest /dev/input/eventXX |
| 47 | |
| 48 | Instructions to the developer |
| 49 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 50 | |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 51 | All interactions are done using the event API. That is, you can use ioctl() |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | and write() on /dev/input/eventXX. |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 53 | This information is subject to change. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 55 | Querying device capabilities |
| 56 | ---------------------------- |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 57 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 58 | :: |
| 59 | |
| 60 | #include <linux/input.h> |
| 61 | #include <sys/ioctl.h> |
| 62 | |
| 63 | #define BITS_TO_LONGS(x) \ |
| 64 | (((x) + 8 * sizeof (unsigned long) - 1) / (8 * sizeof (unsigned long))) |
| 65 | unsigned long features[BITS_TO_LONGS(FF_CNT)]; |
| 66 | int ioctl(int file_descriptor, int request, unsigned long *features); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 | |
| 68 | "request" must be EVIOCGBIT(EV_FF, size of features array in bytes ) |
| 69 | |
| 70 | Returns the features supported by the device. features is a bitfield with the |
| 71 | following bits: |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 72 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 | - FF_CONSTANT can render constant force effects |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 74 | - FF_PERIODIC can render periodic effects with the following waveforms: |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 75 | |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 76 | - FF_SQUARE square waveform |
| 77 | - FF_TRIANGLE triangle waveform |
| 78 | - FF_SINE sine waveform |
| 79 | - FF_SAW_UP sawtooth up waveform |
| 80 | - FF_SAW_DOWN sawtooth down waveform |
| 81 | - FF_CUSTOM custom waveform |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 82 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | - FF_RAMP can render ramp effects |
| 84 | - FF_SPRING can simulate the presence of a spring |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 85 | - FF_FRICTION can simulate friction |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | - FF_DAMPER can simulate damper effects |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 87 | - FF_RUMBLE rumble effects |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 | - FF_INERTIA can simulate inertia |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 89 | - FF_GAIN gain is adjustable |
| 90 | - FF_AUTOCENTER autocenter is adjustable |
| 91 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 92 | .. note:: |
| 93 | |
| 94 | - In most cases you should use FF_PERIODIC instead of FF_RUMBLE. All |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 95 | devices that support FF_RUMBLE support FF_PERIODIC (square, triangle, |
| 96 | sine) and the other way around. |
| 97 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 98 | - The exact syntax FF_CUSTOM is undefined for the time being as no driver |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 99 | supports it yet. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 101 | :: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 102 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 103 | int ioctl(int fd, EVIOCGEFFECTS, int *n); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 104 | |
| 105 | Returns the number of effects the device can keep in its memory. |
| 106 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 107 | Uploading effects to the device |
| 108 | ------------------------------- |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 109 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 110 | :: |
| 111 | |
| 112 | #include <linux/input.h> |
| 113 | #include <sys/ioctl.h> |
| 114 | |
| 115 | int ioctl(int file_descriptor, int request, struct ff_effect *effect); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | |
| 117 | "request" must be EVIOCSFF. |
| 118 | |
| 119 | "effect" points to a structure describing the effect to upload. The effect is |
| 120 | uploaded, but not played. |
| 121 | The content of effect may be modified. In particular, its field "id" is set |
| 122 | to the unique id assigned by the driver. This data is required for performing |
| 123 | some operations (removing an effect, controlling the playback). |
| 124 | This if field must be set to -1 by the user in order to tell the driver to |
| 125 | allocate a new effect. |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 126 | |
| 127 | Effects are file descriptor specific. |
| 128 | |
Linus Torvalds | 16a12fa | 2017-05-03 12:38:20 -0700 | [diff] [blame] | 129 | See <uapi/linux/input.h> for a description of the ff_effect struct. You |
| 130 | should also find help in a few sketches, contained in files shape.svg |
| 131 | and interactive.svg: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 | |
Mauro Carvalho Chehab | aeb899a | 2017-04-11 07:01:19 -0300 | [diff] [blame] | 133 | .. kernel-figure:: shape.svg |
Mauro Carvalho Chehab | deeb1e9 | 2017-04-04 21:42:54 -0700 | [diff] [blame] | 134 | |
| 135 | Shape |
| 136 | |
Mauro Carvalho Chehab | aeb899a | 2017-04-11 07:01:19 -0300 | [diff] [blame] | 137 | .. kernel-figure:: interactive.svg |
Mauro Carvalho Chehab | deeb1e9 | 2017-04-04 21:42:54 -0700 | [diff] [blame] | 138 | |
| 139 | Interactive |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 140 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 141 | |
| 142 | Removing an effect from the device |
| 143 | ---------------------------------- |
| 144 | |
| 145 | :: |
| 146 | |
| 147 | int ioctl(int fd, EVIOCRMFF, effect.id); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 148 | |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 149 | This makes room for new effects in the device's memory. Note that this also |
| 150 | stops the effect if it was playing. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 151 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 152 | Controlling the playback of effects |
| 153 | ----------------------------------- |
| 154 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 | Control of playing is done with write(). Below is an example: |
| 156 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 157 | :: |
| 158 | |
| 159 | #include <linux/input.h> |
| 160 | #include <unistd.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 161 | |
| 162 | struct input_event play; |
| 163 | struct input_event stop; |
| 164 | struct ff_effect effect; |
| 165 | int fd; |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 166 | ... |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | fd = open("/dev/input/eventXX", O_RDWR); |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 168 | ... |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 169 | /* Play three times */ |
| 170 | play.type = EV_FF; |
| 171 | play.code = effect.id; |
| 172 | play.value = 3; |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 173 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 174 | write(fd, (const void*) &play, sizeof(play)); |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 175 | ... |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 176 | /* Stop an effect */ |
| 177 | stop.type = EV_FF; |
| 178 | stop.code = effect.id; |
| 179 | stop.value = 0; |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 180 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 181 | write(fd, (const void*) &play, sizeof(stop)); |
| 182 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 183 | Setting the gain |
| 184 | ---------------- |
| 185 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 186 | Not all devices have the same strength. Therefore, users should set a gain |
| 187 | factor depending on how strong they want effects to be. This setting is |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 188 | persistent across access to the driver. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 189 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 190 | :: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 191 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 192 | /* Set the gain of the device |
| 193 | int gain; /* between 0 and 100 */ |
| 194 | struct input_event ie; /* structure used to communicate with the driver */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 195 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 196 | ie.type = EV_FF; |
| 197 | ie.code = FF_GAIN; |
| 198 | ie.value = 0xFFFFUL * gain / 100; |
| 199 | |
| 200 | if (write(fd, &ie, sizeof(ie)) == -1) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | perror("set gain"); |
| 202 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 203 | Enabling/Disabling autocenter |
| 204 | ----------------------------- |
| 205 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | The autocenter feature quite disturbs the rendering of effects in my opinion, |
| 207 | and I think it should be an effect, which computation depends on the game |
| 208 | type. But you can enable it if you want. |
| 209 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 210 | :: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 211 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 212 | int autocenter; /* between 0 and 100 */ |
| 213 | struct input_event ie; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 214 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 215 | ie.type = EV_FF; |
| 216 | ie.code = FF_AUTOCENTER; |
| 217 | ie.value = 0xFFFFUL * autocenter / 100; |
| 218 | |
| 219 | if (write(fd, &ie, sizeof(ie)) == -1) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 220 | perror("set auto-center"); |
| 221 | |
| 222 | A value of 0 means "no auto-center". |
| 223 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 224 | Dynamic update of an effect |
| 225 | --------------------------- |
| 226 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 227 | Proceed as if you wanted to upload a new effect, except that instead of |
| 228 | setting the id field to -1, you set it to the wanted effect id. |
| 229 | Normally, the effect is not stopped and restarted. However, depending on the |
| 230 | type of device, not all parameters can be dynamically updated. For example, |
| 231 | the direction of an effect cannot be updated with iforce devices. In this |
| 232 | case, the driver stops the effect, up-load it, and restart it. |
| 233 | |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 234 | Therefore it is recommended to dynamically change direction while the effect |
| 235 | is playing only when it is ok to restart the effect with a replay count of 1. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 236 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 237 | Information about the status of effects |
| 238 | --------------------------------------- |
| 239 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 240 | Every time the status of an effect is changed, an event is sent. The values |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 241 | and meanings of the fields of the event are as follows:: |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 242 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 243 | struct input_event { |
| 244 | /* When the status of the effect changed */ |
| 245 | struct timeval time; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 246 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 247 | /* Set to EV_FF_STATUS */ |
| 248 | unsigned short type; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 249 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 250 | /* Contains the id of the effect */ |
| 251 | unsigned short code; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 252 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 253 | /* Indicates the status */ |
| 254 | unsigned int value; |
| 255 | }; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 256 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 257 | FF_STATUS_STOPPED The effect stopped playing |
| 258 | FF_STATUS_PLAYING The effect started to play |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 259 | |
Mauro Carvalho Chehab | 3057d50 | 2017-04-04 17:40:14 -0700 | [diff] [blame] | 260 | .. note:: |
| 261 | |
| 262 | - Status feedback is only supported by iforce driver. If you have |
Anssi Hannula | 8b8277a | 2006-07-19 01:44:22 -0400 | [diff] [blame] | 263 | a really good reason to use this, please contact |
| 264 | linux-joystick@atrey.karlin.mff.cuni.cz or anssi.hannula@gmail.com |
| 265 | so that support for it can be added to the rest of the drivers. |