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