Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/ff-core.c
15109 views
1
/*
2
* Force feedback support for Linux input subsystem
3
*
4
* Copyright (c) 2006 Anssi Hannula <[email protected]>
5
* Copyright (c) 2006 Dmitry Torokhov <[email protected]>
6
*/
7
8
/*
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or
12
* (at your option) any later version.
13
*
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
18
*
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
*/
23
24
/* #define DEBUG */
25
26
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
27
28
#include <linux/input.h>
29
#include <linux/module.h>
30
#include <linux/mutex.h>
31
#include <linux/sched.h>
32
#include <linux/slab.h>
33
34
/*
35
* Check that the effect_id is a valid effect and whether the user
36
* is the owner
37
*/
38
static int check_effect_access(struct ff_device *ff, int effect_id,
39
struct file *file)
40
{
41
if (effect_id < 0 || effect_id >= ff->max_effects ||
42
!ff->effect_owners[effect_id])
43
return -EINVAL;
44
45
if (file && ff->effect_owners[effect_id] != file)
46
return -EACCES;
47
48
return 0;
49
}
50
51
/*
52
* Checks whether 2 effects can be combined together
53
*/
54
static inline int check_effects_compatible(struct ff_effect *e1,
55
struct ff_effect *e2)
56
{
57
return e1->type == e2->type &&
58
(e1->type != FF_PERIODIC ||
59
e1->u.periodic.waveform == e2->u.periodic.waveform);
60
}
61
62
/*
63
* Convert an effect into compatible one
64
*/
65
static int compat_effect(struct ff_device *ff, struct ff_effect *effect)
66
{
67
int magnitude;
68
69
switch (effect->type) {
70
case FF_RUMBLE:
71
if (!test_bit(FF_PERIODIC, ff->ffbit))
72
return -EINVAL;
73
74
/*
75
* calculate manginude of sine wave as average of rumble's
76
* 2/3 of strong magnitude and 1/3 of weak magnitude
77
*/
78
magnitude = effect->u.rumble.strong_magnitude / 3 +
79
effect->u.rumble.weak_magnitude / 6;
80
81
effect->type = FF_PERIODIC;
82
effect->u.periodic.waveform = FF_SINE;
83
effect->u.periodic.period = 50;
84
effect->u.periodic.magnitude = max(magnitude, 0x7fff);
85
effect->u.periodic.offset = 0;
86
effect->u.periodic.phase = 0;
87
effect->u.periodic.envelope.attack_length = 0;
88
effect->u.periodic.envelope.attack_level = 0;
89
effect->u.periodic.envelope.fade_length = 0;
90
effect->u.periodic.envelope.fade_level = 0;
91
92
return 0;
93
94
default:
95
/* Let driver handle conversion */
96
return 0;
97
}
98
}
99
100
/**
101
* input_ff_upload() - upload effect into force-feedback device
102
* @dev: input device
103
* @effect: effect to be uploaded
104
* @file: owner of the effect
105
*/
106
int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
107
struct file *file)
108
{
109
struct ff_device *ff = dev->ff;
110
struct ff_effect *old;
111
int ret = 0;
112
int id;
113
114
if (!test_bit(EV_FF, dev->evbit))
115
return -ENOSYS;
116
117
if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX ||
118
!test_bit(effect->type, dev->ffbit)) {
119
pr_debug("invalid or not supported effect type in upload\n");
120
return -EINVAL;
121
}
122
123
if (effect->type == FF_PERIODIC &&
124
(effect->u.periodic.waveform < FF_WAVEFORM_MIN ||
125
effect->u.periodic.waveform > FF_WAVEFORM_MAX ||
126
!test_bit(effect->u.periodic.waveform, dev->ffbit))) {
127
pr_debug("invalid or not supported wave form in upload\n");
128
return -EINVAL;
129
}
130
131
if (!test_bit(effect->type, ff->ffbit)) {
132
ret = compat_effect(ff, effect);
133
if (ret)
134
return ret;
135
}
136
137
mutex_lock(&ff->mutex);
138
139
if (effect->id == -1) {
140
for (id = 0; id < ff->max_effects; id++)
141
if (!ff->effect_owners[id])
142
break;
143
144
if (id >= ff->max_effects) {
145
ret = -ENOSPC;
146
goto out;
147
}
148
149
effect->id = id;
150
old = NULL;
151
152
} else {
153
id = effect->id;
154
155
ret = check_effect_access(ff, id, file);
156
if (ret)
157
goto out;
158
159
old = &ff->effects[id];
160
161
if (!check_effects_compatible(effect, old)) {
162
ret = -EINVAL;
163
goto out;
164
}
165
}
166
167
ret = ff->upload(dev, effect, old);
168
if (ret)
169
goto out;
170
171
spin_lock_irq(&dev->event_lock);
172
ff->effects[id] = *effect;
173
ff->effect_owners[id] = file;
174
spin_unlock_irq(&dev->event_lock);
175
176
out:
177
mutex_unlock(&ff->mutex);
178
return ret;
179
}
180
EXPORT_SYMBOL_GPL(input_ff_upload);
181
182
/*
183
* Erases the effect if the requester is also the effect owner. The mutex
184
* should already be locked before calling this function.
185
*/
186
static int erase_effect(struct input_dev *dev, int effect_id,
187
struct file *file)
188
{
189
struct ff_device *ff = dev->ff;
190
int error;
191
192
error = check_effect_access(ff, effect_id, file);
193
if (error)
194
return error;
195
196
spin_lock_irq(&dev->event_lock);
197
ff->playback(dev, effect_id, 0);
198
ff->effect_owners[effect_id] = NULL;
199
spin_unlock_irq(&dev->event_lock);
200
201
if (ff->erase) {
202
error = ff->erase(dev, effect_id);
203
if (error) {
204
spin_lock_irq(&dev->event_lock);
205
ff->effect_owners[effect_id] = file;
206
spin_unlock_irq(&dev->event_lock);
207
208
return error;
209
}
210
}
211
212
return 0;
213
}
214
215
/**
216
* input_ff_erase - erase a force-feedback effect from device
217
* @dev: input device to erase effect from
218
* @effect_id: id of the ffect to be erased
219
* @file: purported owner of the request
220
*
221
* This function erases a force-feedback effect from specified device.
222
* The effect will only be erased if it was uploaded through the same
223
* file handle that is requesting erase.
224
*/
225
int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file)
226
{
227
struct ff_device *ff = dev->ff;
228
int ret;
229
230
if (!test_bit(EV_FF, dev->evbit))
231
return -ENOSYS;
232
233
mutex_lock(&ff->mutex);
234
ret = erase_effect(dev, effect_id, file);
235
mutex_unlock(&ff->mutex);
236
237
return ret;
238
}
239
EXPORT_SYMBOL_GPL(input_ff_erase);
240
241
/*
242
* flush_effects - erase all effects owned by a file handle
243
*/
244
static int flush_effects(struct input_dev *dev, struct file *file)
245
{
246
struct ff_device *ff = dev->ff;
247
int i;
248
249
pr_debug("flushing now\n");
250
251
mutex_lock(&ff->mutex);
252
253
for (i = 0; i < ff->max_effects; i++)
254
erase_effect(dev, i, file);
255
256
mutex_unlock(&ff->mutex);
257
258
return 0;
259
}
260
261
/**
262
* input_ff_event() - generic handler for force-feedback events
263
* @dev: input device to send the effect to
264
* @type: event type (anything but EV_FF is ignored)
265
* @code: event code
266
* @value: event value
267
*/
268
int input_ff_event(struct input_dev *dev, unsigned int type,
269
unsigned int code, int value)
270
{
271
struct ff_device *ff = dev->ff;
272
273
if (type != EV_FF)
274
return 0;
275
276
switch (code) {
277
case FF_GAIN:
278
if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff)
279
break;
280
281
ff->set_gain(dev, value);
282
break;
283
284
case FF_AUTOCENTER:
285
if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff)
286
break;
287
288
ff->set_autocenter(dev, value);
289
break;
290
291
default:
292
if (check_effect_access(ff, code, NULL) == 0)
293
ff->playback(dev, code, value);
294
break;
295
}
296
297
return 0;
298
}
299
EXPORT_SYMBOL_GPL(input_ff_event);
300
301
/**
302
* input_ff_create() - create force-feedback device
303
* @dev: input device supporting force-feedback
304
* @max_effects: maximum number of effects supported by the device
305
*
306
* This function allocates all necessary memory for a force feedback
307
* portion of an input device and installs all default handlers.
308
* @dev->ffbit should be already set up before calling this function.
309
* Once ff device is created you need to setup its upload, erase,
310
* playback and other handlers before registering input device
311
*/
312
int input_ff_create(struct input_dev *dev, int max_effects)
313
{
314
struct ff_device *ff;
315
int i;
316
317
if (!max_effects) {
318
pr_err("cannot allocate device without any effects\n");
319
return -EINVAL;
320
}
321
322
ff = kzalloc(sizeof(struct ff_device) +
323
max_effects * sizeof(struct file *), GFP_KERNEL);
324
if (!ff)
325
return -ENOMEM;
326
327
ff->effects = kcalloc(max_effects, sizeof(struct ff_effect),
328
GFP_KERNEL);
329
if (!ff->effects) {
330
kfree(ff);
331
return -ENOMEM;
332
}
333
334
ff->max_effects = max_effects;
335
mutex_init(&ff->mutex);
336
337
dev->ff = ff;
338
dev->flush = flush_effects;
339
dev->event = input_ff_event;
340
__set_bit(EV_FF, dev->evbit);
341
342
/* Copy "true" bits into ff device bitmap */
343
for (i = 0; i <= FF_MAX; i++)
344
if (test_bit(i, dev->ffbit))
345
__set_bit(i, ff->ffbit);
346
347
/* we can emulate RUMBLE with periodic effects */
348
if (test_bit(FF_PERIODIC, ff->ffbit))
349
__set_bit(FF_RUMBLE, dev->ffbit);
350
351
return 0;
352
}
353
EXPORT_SYMBOL_GPL(input_ff_create);
354
355
/**
356
* input_ff_destroy() - frees force feedback portion of input device
357
* @dev: input device supporting force feedback
358
*
359
* This function is only needed in error path as input core will
360
* automatically free force feedback structures when device is
361
* destroyed.
362
*/
363
void input_ff_destroy(struct input_dev *dev)
364
{
365
struct ff_device *ff = dev->ff;
366
367
__clear_bit(EV_FF, dev->evbit);
368
if (ff) {
369
if (ff->destroy)
370
ff->destroy(ff);
371
kfree(ff->private);
372
kfree(ff->effects);
373
kfree(ff);
374
dev->ff = NULL;
375
}
376
}
377
EXPORT_SYMBOL_GPL(input_ff_destroy);
378
379