LCOV - code coverage report
Current view: top level - drivers/input - ff-core.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 132 0.0 %
Date: 2023-03-27 20:00:47 Functions: 0 8 0.0 %

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

Generated by: LCOV version 1.14