11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2509ca1a9SAnssi Hannula /* 3509ca1a9SAnssi Hannula * Force feedback support for Linux input subsystem 4509ca1a9SAnssi Hannula * 5509ca1a9SAnssi Hannula * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com> 6509ca1a9SAnssi Hannula * Copyright (c) 2006 Dmitry Torokhov <dtor@mail.ru> 7509ca1a9SAnssi Hannula */ 8509ca1a9SAnssi Hannula 9509ca1a9SAnssi Hannula /* 10509ca1a9SAnssi Hannula */ 11509ca1a9SAnssi Hannula 12509ca1a9SAnssi Hannula /* #define DEBUG */ 13509ca1a9SAnssi Hannula 14509ca1a9SAnssi Hannula #include <linux/input.h> 15509ca1a9SAnssi Hannula #include <linux/module.h> 16509ca1a9SAnssi Hannula #include <linux/mutex.h> 1783680cdbSGeert Uytterhoeven #include <linux/sched.h> 185a0e3ad6STejun Heo #include <linux/slab.h> 19509ca1a9SAnssi Hannula 20509ca1a9SAnssi Hannula /* 21509ca1a9SAnssi Hannula * Check that the effect_id is a valid effect and whether the user 22509ca1a9SAnssi Hannula * is the owner 23509ca1a9SAnssi Hannula */ 24509ca1a9SAnssi Hannula static int check_effect_access(struct ff_device *ff, int effect_id, 25509ca1a9SAnssi Hannula struct file *file) 26509ca1a9SAnssi Hannula { 27509ca1a9SAnssi Hannula if (effect_id < 0 || effect_id >= ff->max_effects || 28509ca1a9SAnssi Hannula !ff->effect_owners[effect_id]) 29509ca1a9SAnssi Hannula return -EINVAL; 30509ca1a9SAnssi Hannula 31509ca1a9SAnssi Hannula if (file && ff->effect_owners[effect_id] != file) 32509ca1a9SAnssi Hannula return -EACCES; 33509ca1a9SAnssi Hannula 34509ca1a9SAnssi Hannula return 0; 35509ca1a9SAnssi Hannula } 36509ca1a9SAnssi Hannula 37509ca1a9SAnssi Hannula /* 38509ca1a9SAnssi Hannula * Checks whether 2 effects can be combined together 39509ca1a9SAnssi Hannula */ 40509ca1a9SAnssi Hannula static inline int check_effects_compatible(struct ff_effect *e1, 41509ca1a9SAnssi Hannula struct ff_effect *e2) 42509ca1a9SAnssi Hannula { 43509ca1a9SAnssi Hannula return e1->type == e2->type && 44509ca1a9SAnssi Hannula (e1->type != FF_PERIODIC || 45509ca1a9SAnssi Hannula e1->u.periodic.waveform == e2->u.periodic.waveform); 46509ca1a9SAnssi Hannula } 47509ca1a9SAnssi Hannula 48509ca1a9SAnssi Hannula /* 49509ca1a9SAnssi Hannula * Convert an effect into compatible one 50509ca1a9SAnssi Hannula */ 51509ca1a9SAnssi Hannula static int compat_effect(struct ff_device *ff, struct ff_effect *effect) 52509ca1a9SAnssi Hannula { 53509ca1a9SAnssi Hannula int magnitude; 54509ca1a9SAnssi Hannula 55509ca1a9SAnssi Hannula switch (effect->type) { 56509ca1a9SAnssi Hannula case FF_RUMBLE: 57509ca1a9SAnssi Hannula if (!test_bit(FF_PERIODIC, ff->ffbit)) 58509ca1a9SAnssi Hannula return -EINVAL; 59509ca1a9SAnssi Hannula 60509ca1a9SAnssi Hannula /* 618a4dda79SDan Murphy * calculate magnitude of sine wave as average of rumble's 62509ca1a9SAnssi Hannula * 2/3 of strong magnitude and 1/3 of weak magnitude 63509ca1a9SAnssi Hannula */ 64509ca1a9SAnssi Hannula magnitude = effect->u.rumble.strong_magnitude / 3 + 65509ca1a9SAnssi Hannula effect->u.rumble.weak_magnitude / 6; 66509ca1a9SAnssi Hannula 67509ca1a9SAnssi Hannula effect->type = FF_PERIODIC; 68509ca1a9SAnssi Hannula effect->u.periodic.waveform = FF_SINE; 69509ca1a9SAnssi Hannula effect->u.periodic.period = 50; 70*8c374ef4SCharles Keepax effect->u.periodic.magnitude = magnitude; 71509ca1a9SAnssi Hannula effect->u.periodic.offset = 0; 72509ca1a9SAnssi Hannula effect->u.periodic.phase = 0; 73509ca1a9SAnssi Hannula effect->u.periodic.envelope.attack_length = 0; 74509ca1a9SAnssi Hannula effect->u.periodic.envelope.attack_level = 0; 75509ca1a9SAnssi Hannula effect->u.periodic.envelope.fade_length = 0; 76509ca1a9SAnssi Hannula effect->u.periodic.envelope.fade_level = 0; 77509ca1a9SAnssi Hannula 78509ca1a9SAnssi Hannula return 0; 79509ca1a9SAnssi Hannula 80509ca1a9SAnssi Hannula default: 81509ca1a9SAnssi Hannula /* Let driver handle conversion */ 82509ca1a9SAnssi Hannula return 0; 83509ca1a9SAnssi Hannula } 84509ca1a9SAnssi Hannula } 85509ca1a9SAnssi Hannula 86509ca1a9SAnssi Hannula /** 87509ca1a9SAnssi Hannula * input_ff_upload() - upload effect into force-feedback device 88509ca1a9SAnssi Hannula * @dev: input device 89509ca1a9SAnssi Hannula * @effect: effect to be uploaded 90509ca1a9SAnssi Hannula * @file: owner of the effect 91509ca1a9SAnssi Hannula */ 92509ca1a9SAnssi Hannula int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, 93509ca1a9SAnssi Hannula struct file *file) 94509ca1a9SAnssi Hannula { 95509ca1a9SAnssi Hannula struct ff_device *ff = dev->ff; 96509ca1a9SAnssi Hannula struct ff_effect *old; 97509ca1a9SAnssi Hannula int ret = 0; 98509ca1a9SAnssi Hannula int id; 99509ca1a9SAnssi Hannula 100509ca1a9SAnssi Hannula if (!test_bit(EV_FF, dev->evbit)) 101509ca1a9SAnssi Hannula return -ENOSYS; 102509ca1a9SAnssi Hannula 103509ca1a9SAnssi Hannula if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || 104509ca1a9SAnssi Hannula !test_bit(effect->type, dev->ffbit)) { 1052afebafdSOliver Neukum dev_dbg(&dev->dev, "invalid or not supported effect type in upload\n"); 106509ca1a9SAnssi Hannula return -EINVAL; 107509ca1a9SAnssi Hannula } 108509ca1a9SAnssi Hannula 109509ca1a9SAnssi Hannula if (effect->type == FF_PERIODIC && 110509ca1a9SAnssi Hannula (effect->u.periodic.waveform < FF_WAVEFORM_MIN || 111509ca1a9SAnssi Hannula effect->u.periodic.waveform > FF_WAVEFORM_MAX || 112509ca1a9SAnssi Hannula !test_bit(effect->u.periodic.waveform, dev->ffbit))) { 1132afebafdSOliver Neukum dev_dbg(&dev->dev, "invalid or not supported wave form in upload\n"); 114509ca1a9SAnssi Hannula return -EINVAL; 115509ca1a9SAnssi Hannula } 116509ca1a9SAnssi Hannula 117509ca1a9SAnssi Hannula if (!test_bit(effect->type, ff->ffbit)) { 118509ca1a9SAnssi Hannula ret = compat_effect(ff, effect); 119509ca1a9SAnssi Hannula if (ret) 120509ca1a9SAnssi Hannula return ret; 121509ca1a9SAnssi Hannula } 122509ca1a9SAnssi Hannula 123509ca1a9SAnssi Hannula mutex_lock(&ff->mutex); 124509ca1a9SAnssi Hannula 125509ca1a9SAnssi Hannula if (effect->id == -1) { 126509ca1a9SAnssi Hannula for (id = 0; id < ff->max_effects; id++) 127509ca1a9SAnssi Hannula if (!ff->effect_owners[id]) 128509ca1a9SAnssi Hannula break; 129509ca1a9SAnssi Hannula 130509ca1a9SAnssi Hannula if (id >= ff->max_effects) { 131509ca1a9SAnssi Hannula ret = -ENOSPC; 132509ca1a9SAnssi Hannula goto out; 133509ca1a9SAnssi Hannula } 134509ca1a9SAnssi Hannula 135509ca1a9SAnssi Hannula effect->id = id; 136509ca1a9SAnssi Hannula old = NULL; 137509ca1a9SAnssi Hannula 138509ca1a9SAnssi Hannula } else { 139509ca1a9SAnssi Hannula id = effect->id; 140509ca1a9SAnssi Hannula 141509ca1a9SAnssi Hannula ret = check_effect_access(ff, id, file); 142509ca1a9SAnssi Hannula if (ret) 143509ca1a9SAnssi Hannula goto out; 144509ca1a9SAnssi Hannula 145509ca1a9SAnssi Hannula old = &ff->effects[id]; 146509ca1a9SAnssi Hannula 147509ca1a9SAnssi Hannula if (!check_effects_compatible(effect, old)) { 148509ca1a9SAnssi Hannula ret = -EINVAL; 149509ca1a9SAnssi Hannula goto out; 150509ca1a9SAnssi Hannula } 151509ca1a9SAnssi Hannula } 152509ca1a9SAnssi Hannula 153509ca1a9SAnssi Hannula ret = ff->upload(dev, effect, old); 154509ca1a9SAnssi Hannula if (ret) 155509ca1a9SAnssi Hannula goto out; 156509ca1a9SAnssi Hannula 157656acd2bSDmitry Torokhov spin_lock_irq(&dev->event_lock); 158509ca1a9SAnssi Hannula ff->effects[id] = *effect; 159509ca1a9SAnssi Hannula ff->effect_owners[id] = file; 160656acd2bSDmitry Torokhov spin_unlock_irq(&dev->event_lock); 161509ca1a9SAnssi Hannula 162509ca1a9SAnssi Hannula out: 163509ca1a9SAnssi Hannula mutex_unlock(&ff->mutex); 164509ca1a9SAnssi Hannula return ret; 165509ca1a9SAnssi Hannula } 166509ca1a9SAnssi Hannula EXPORT_SYMBOL_GPL(input_ff_upload); 167509ca1a9SAnssi Hannula 168509ca1a9SAnssi Hannula /* 169509ca1a9SAnssi Hannula * Erases the effect if the requester is also the effect owner. The mutex 170509ca1a9SAnssi Hannula * should already be locked before calling this function. 171509ca1a9SAnssi Hannula */ 172509ca1a9SAnssi Hannula static int erase_effect(struct input_dev *dev, int effect_id, 173509ca1a9SAnssi Hannula struct file *file) 174509ca1a9SAnssi Hannula { 175509ca1a9SAnssi Hannula struct ff_device *ff = dev->ff; 176509ca1a9SAnssi Hannula int error; 177509ca1a9SAnssi Hannula 178509ca1a9SAnssi Hannula error = check_effect_access(ff, effect_id, file); 179509ca1a9SAnssi Hannula if (error) 180509ca1a9SAnssi Hannula return error; 181509ca1a9SAnssi Hannula 182656acd2bSDmitry Torokhov spin_lock_irq(&dev->event_lock); 183509ca1a9SAnssi Hannula ff->playback(dev, effect_id, 0); 184656acd2bSDmitry Torokhov ff->effect_owners[effect_id] = NULL; 185656acd2bSDmitry Torokhov spin_unlock_irq(&dev->event_lock); 186509ca1a9SAnssi Hannula 187509ca1a9SAnssi Hannula if (ff->erase) { 188509ca1a9SAnssi Hannula error = ff->erase(dev, effect_id); 189656acd2bSDmitry Torokhov if (error) { 190656acd2bSDmitry Torokhov spin_lock_irq(&dev->event_lock); 191656acd2bSDmitry Torokhov ff->effect_owners[effect_id] = file; 192656acd2bSDmitry Torokhov spin_unlock_irq(&dev->event_lock); 193656acd2bSDmitry Torokhov 194509ca1a9SAnssi Hannula return error; 195509ca1a9SAnssi Hannula } 196656acd2bSDmitry Torokhov } 197509ca1a9SAnssi Hannula 198509ca1a9SAnssi Hannula return 0; 199509ca1a9SAnssi Hannula } 200509ca1a9SAnssi Hannula 201509ca1a9SAnssi Hannula /** 202e4477d2dSRandy Dunlap * input_ff_erase - erase a force-feedback effect from device 203509ca1a9SAnssi Hannula * @dev: input device to erase effect from 2044e3e4629SShailendra Verma * @effect_id: id of the effect to be erased 205509ca1a9SAnssi Hannula * @file: purported owner of the request 206509ca1a9SAnssi Hannula * 207509ca1a9SAnssi Hannula * This function erases a force-feedback effect from specified device. 208509ca1a9SAnssi Hannula * The effect will only be erased if it was uploaded through the same 209509ca1a9SAnssi Hannula * file handle that is requesting erase. 210509ca1a9SAnssi Hannula */ 211509ca1a9SAnssi Hannula int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file) 212509ca1a9SAnssi Hannula { 213509ca1a9SAnssi Hannula struct ff_device *ff = dev->ff; 214509ca1a9SAnssi Hannula int ret; 215509ca1a9SAnssi Hannula 216509ca1a9SAnssi Hannula if (!test_bit(EV_FF, dev->evbit)) 217509ca1a9SAnssi Hannula return -ENOSYS; 218509ca1a9SAnssi Hannula 219509ca1a9SAnssi Hannula mutex_lock(&ff->mutex); 220509ca1a9SAnssi Hannula ret = erase_effect(dev, effect_id, file); 221509ca1a9SAnssi Hannula mutex_unlock(&ff->mutex); 222509ca1a9SAnssi Hannula 223509ca1a9SAnssi Hannula return ret; 224509ca1a9SAnssi Hannula } 225509ca1a9SAnssi Hannula EXPORT_SYMBOL_GPL(input_ff_erase); 226509ca1a9SAnssi Hannula 227509ca1a9SAnssi Hannula /* 228e8b95728SDmitry Torokhov * input_ff_flush - erase all effects owned by a file handle 229e8b95728SDmitry Torokhov * @dev: input device to erase effect from 230e8b95728SDmitry Torokhov * @file: purported owner of the effects 231e8b95728SDmitry Torokhov * 232e8b95728SDmitry Torokhov * This function erases all force-feedback effects associated with 233e8b95728SDmitry Torokhov * the given owner from specified device. Note that @file may be %NULL, 234e8b95728SDmitry Torokhov * in which case all effects will be erased. 235509ca1a9SAnssi Hannula */ 236e8b95728SDmitry Torokhov int input_ff_flush(struct input_dev *dev, struct file *file) 237509ca1a9SAnssi Hannula { 238509ca1a9SAnssi Hannula struct ff_device *ff = dev->ff; 239509ca1a9SAnssi Hannula int i; 240509ca1a9SAnssi Hannula 2412afebafdSOliver Neukum dev_dbg(&dev->dev, "flushing now\n"); 242509ca1a9SAnssi Hannula 243509ca1a9SAnssi Hannula mutex_lock(&ff->mutex); 244509ca1a9SAnssi Hannula 245509ca1a9SAnssi Hannula for (i = 0; i < ff->max_effects; i++) 246509ca1a9SAnssi Hannula erase_effect(dev, i, file); 247509ca1a9SAnssi Hannula 248509ca1a9SAnssi Hannula mutex_unlock(&ff->mutex); 249509ca1a9SAnssi Hannula 250509ca1a9SAnssi Hannula return 0; 251509ca1a9SAnssi Hannula } 252e8b95728SDmitry Torokhov EXPORT_SYMBOL_GPL(input_ff_flush); 253509ca1a9SAnssi Hannula 254509ca1a9SAnssi Hannula /** 255509ca1a9SAnssi Hannula * input_ff_event() - generic handler for force-feedback events 256509ca1a9SAnssi Hannula * @dev: input device to send the effect to 257509ca1a9SAnssi Hannula * @type: event type (anything but EV_FF is ignored) 258509ca1a9SAnssi Hannula * @code: event code 259509ca1a9SAnssi Hannula * @value: event value 260509ca1a9SAnssi Hannula */ 261509ca1a9SAnssi Hannula int input_ff_event(struct input_dev *dev, unsigned int type, 262509ca1a9SAnssi Hannula unsigned int code, int value) 263509ca1a9SAnssi Hannula { 264509ca1a9SAnssi Hannula struct ff_device *ff = dev->ff; 265509ca1a9SAnssi Hannula 266509ca1a9SAnssi Hannula if (type != EV_FF) 267509ca1a9SAnssi Hannula return 0; 268509ca1a9SAnssi Hannula 269509ca1a9SAnssi Hannula switch (code) { 270509ca1a9SAnssi Hannula case FF_GAIN: 271379d7cfaSDan Carpenter if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffffU) 272509ca1a9SAnssi Hannula break; 273509ca1a9SAnssi Hannula 274509ca1a9SAnssi Hannula ff->set_gain(dev, value); 275509ca1a9SAnssi Hannula break; 276509ca1a9SAnssi Hannula 277509ca1a9SAnssi Hannula case FF_AUTOCENTER: 278379d7cfaSDan Carpenter if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffffU) 279509ca1a9SAnssi Hannula break; 280509ca1a9SAnssi Hannula 281509ca1a9SAnssi Hannula ff->set_autocenter(dev, value); 282509ca1a9SAnssi Hannula break; 283509ca1a9SAnssi Hannula 284509ca1a9SAnssi Hannula default: 285dec3eb01SDmitry Torokhov if (check_effect_access(ff, code, NULL) == 0) 286509ca1a9SAnssi Hannula ff->playback(dev, code, value); 287509ca1a9SAnssi Hannula break; 288509ca1a9SAnssi Hannula } 289509ca1a9SAnssi Hannula 290509ca1a9SAnssi Hannula return 0; 291509ca1a9SAnssi Hannula } 292509ca1a9SAnssi Hannula EXPORT_SYMBOL_GPL(input_ff_event); 293509ca1a9SAnssi Hannula 294509ca1a9SAnssi Hannula /** 295509ca1a9SAnssi Hannula * input_ff_create() - create force-feedback device 296509ca1a9SAnssi Hannula * @dev: input device supporting force-feedback 297509ca1a9SAnssi Hannula * @max_effects: maximum number of effects supported by the device 298509ca1a9SAnssi Hannula * 299509ca1a9SAnssi Hannula * This function allocates all necessary memory for a force feedback 300509ca1a9SAnssi Hannula * portion of an input device and installs all default handlers. 301509ca1a9SAnssi Hannula * @dev->ffbit should be already set up before calling this function. 302509ca1a9SAnssi Hannula * Once ff device is created you need to setup its upload, erase, 303509ca1a9SAnssi Hannula * playback and other handlers before registering input device 304509ca1a9SAnssi Hannula */ 30505be8b81SDan Carpenter int input_ff_create(struct input_dev *dev, unsigned int max_effects) 306509ca1a9SAnssi Hannula { 307509ca1a9SAnssi Hannula struct ff_device *ff; 30805be8b81SDan Carpenter size_t ff_dev_size; 309509ca1a9SAnssi Hannula int i; 310509ca1a9SAnssi Hannula 311509ca1a9SAnssi Hannula if (!max_effects) { 3122afebafdSOliver Neukum dev_err(&dev->dev, "cannot allocate device without any effects\n"); 313509ca1a9SAnssi Hannula return -EINVAL; 314509ca1a9SAnssi Hannula } 315509ca1a9SAnssi Hannula 31633b96d93SElias Vanderstuyft if (max_effects > FF_MAX_EFFECTS) { 31733b96d93SElias Vanderstuyft dev_err(&dev->dev, "cannot allocate more than FF_MAX_EFFECTS effects\n"); 31833b96d93SElias Vanderstuyft return -EINVAL; 31933b96d93SElias Vanderstuyft } 32033b96d93SElias Vanderstuyft 32105be8b81SDan Carpenter ff_dev_size = sizeof(struct ff_device) + 32205be8b81SDan Carpenter max_effects * sizeof(struct file *); 32305be8b81SDan Carpenter if (ff_dev_size < max_effects) /* overflow */ 32405be8b81SDan Carpenter return -EINVAL; 32505be8b81SDan Carpenter 32605be8b81SDan Carpenter ff = kzalloc(ff_dev_size, GFP_KERNEL); 327509ca1a9SAnssi Hannula if (!ff) 328509ca1a9SAnssi Hannula return -ENOMEM; 329509ca1a9SAnssi Hannula 330509ca1a9SAnssi Hannula ff->effects = kcalloc(max_effects, sizeof(struct ff_effect), 331509ca1a9SAnssi Hannula GFP_KERNEL); 332509ca1a9SAnssi Hannula if (!ff->effects) { 333509ca1a9SAnssi Hannula kfree(ff); 334509ca1a9SAnssi Hannula return -ENOMEM; 335509ca1a9SAnssi Hannula } 336509ca1a9SAnssi Hannula 337509ca1a9SAnssi Hannula ff->max_effects = max_effects; 338509ca1a9SAnssi Hannula mutex_init(&ff->mutex); 339509ca1a9SAnssi Hannula 340509ca1a9SAnssi Hannula dev->ff = ff; 341e8b95728SDmitry Torokhov dev->flush = input_ff_flush; 342509ca1a9SAnssi Hannula dev->event = input_ff_event; 343bf3204cbSDmitry Torokhov __set_bit(EV_FF, dev->evbit); 344509ca1a9SAnssi Hannula 345509ca1a9SAnssi Hannula /* Copy "true" bits into ff device bitmap */ 346948cea14SAnshul Garg for_each_set_bit(i, dev->ffbit, FF_CNT) 347bf3204cbSDmitry Torokhov __set_bit(i, ff->ffbit); 348509ca1a9SAnssi Hannula 349509ca1a9SAnssi Hannula /* we can emulate RUMBLE with periodic effects */ 350509ca1a9SAnssi Hannula if (test_bit(FF_PERIODIC, ff->ffbit)) 351bf3204cbSDmitry Torokhov __set_bit(FF_RUMBLE, dev->ffbit); 352509ca1a9SAnssi Hannula 353509ca1a9SAnssi Hannula return 0; 354509ca1a9SAnssi Hannula } 355509ca1a9SAnssi Hannula EXPORT_SYMBOL_GPL(input_ff_create); 356509ca1a9SAnssi Hannula 357509ca1a9SAnssi Hannula /** 358721a730eSRoger Quadros * input_ff_destroy() - frees force feedback portion of input device 359e4477d2dSRandy Dunlap * @dev: input device supporting force feedback 360509ca1a9SAnssi Hannula * 361509ca1a9SAnssi Hannula * This function is only needed in error path as input core will 362509ca1a9SAnssi Hannula * automatically free force feedback structures when device is 363509ca1a9SAnssi Hannula * destroyed. 364509ca1a9SAnssi Hannula */ 365509ca1a9SAnssi Hannula void input_ff_destroy(struct input_dev *dev) 366509ca1a9SAnssi Hannula { 367bf3204cbSDmitry Torokhov struct ff_device *ff = dev->ff; 368bf3204cbSDmitry Torokhov 369bf3204cbSDmitry Torokhov __clear_bit(EV_FF, dev->evbit); 370bf3204cbSDmitry Torokhov if (ff) { 371bf3204cbSDmitry Torokhov if (ff->destroy) 372bf3204cbSDmitry Torokhov ff->destroy(ff); 373bf3204cbSDmitry Torokhov kfree(ff->private); 3746a47081cSJari Vanhala kfree(ff->effects); 375bf3204cbSDmitry Torokhov kfree(ff); 376509ca1a9SAnssi Hannula dev->ff = NULL; 377509ca1a9SAnssi Hannula } 378509ca1a9SAnssi Hannula } 379509ca1a9SAnssi Hannula EXPORT_SYMBOL_GPL(input_ff_destroy); 380