From dec8a86ff4b287019b4ce6989a738934c9eb95a1 Mon Sep 17 00:00:00 2001
From: Jari Vanhala <ext-jari.vanhala@nokia.com>
Date: Tue, 9 Feb 2010 11:03:54 +0200
Subject: [PATCH] Input: FF-memless custom sequence hack
This takes unused custom functionality and use it for
making sequences in ff-memless. This can be only counted
as a hack for testing purposes.
Signed-off-by: Jari Vanhala <ext-jari.vanhala@nokia.com>
---
drivers/input/ff-core.c | 9 +++
drivers/input/ff-memless.c | 115 ++++++++++++++++++++++++++++++++++++++++-
drivers/input/input-compat.c | 1 +
3 files changed, 122 insertions(+), 3 deletions(-)
@@ -193,6 +193,9 @@ static int erase_effect(struct input_dev *dev, int effect_id,
return error;
spin_lock_irq(&dev->event_lock);
+ if (ff->effects[effect_id].type == FF_PERIODIC &&
+ ff->effects[effect_id].u.periodic.waveform == FF_CUSTOM)
+ ff->effects[effect_id].u.periodic.custom_data = NULL;
ff->playback(dev, effect_id, 0);
ff->effect_owners[effect_id] = NULL;
spin_unlock_irq(&dev->event_lock);
@@ -250,6 +253,12 @@ static int flush_effects(struct input_dev *dev, struct file *file)
mutex_lock(&ff->mutex);
for (i = 0; i < ff->max_effects; i++)
+ if (!check_effect_access(ff, i, file) &&
+ ff->effects[i].type == FF_PERIODIC &&
+ ff->effects[i].u.periodic.waveform == FF_CUSTOM)
+ ff->effects[i].u.periodic.custom_data = NULL;
+
+ for (i = 0; i < ff->max_effects; i++)
erase_effect(dev, i, file);
mutex_unlock(&ff->mutex);
@@ -54,6 +54,7 @@ struct ml_effect_state {
unsigned long play_at; /* start time */
unsigned long stop_at; /* stop time */
unsigned long adj_at; /* last time the effect was sent */
+ int custom_index; /* current custom index */
};
struct ml_device {
@@ -317,6 +318,29 @@ static void ml_combine_effects(struct ff_effect *effect,
}
+#define IS_CUSTOM(effect) (effect->type == FF_PERIODIC && \
+ effect->u.periodic.waveform == FF_CUSTOM)
+static struct ff_effect *find_custom_effect(struct ml_effect_state *states,
+ struct ff_effect *effect,
+ int index)
+{
+ s16 id;
+ struct ff_effect *ret;
+
+ if (!effect || !effect->u.periodic.custom_data ||
+ effect->u.periodic.custom_len / sizeof(__s16) <= index)
+ return NULL;
+ /* XXX: check if effect->u.periodic.custom_data still points
+ * to valid memory */
+ id = effect->u.periodic.custom_data[index];
+ if (id < 0 || id == effect->id || id >= FF_MEMLESS_EFFECTS)
+ return NULL;
+ ret = states[id].effect;
+ if (IS_CUSTOM(ret))
+ return NULL;
+
+ return ret;
+}
/*
* Because memoryless devices have only one effect per effect type active
@@ -326,7 +350,7 @@ static int ml_get_combo_effect(struct ml_device *ml,
unsigned long *effect_handled,
struct ff_effect *combo_effect)
{
- struct ff_effect *effect;
+ struct ff_effect *effect, *effect2;
struct ml_effect_state *state;
int effect_type;
int i;
@@ -368,9 +392,56 @@ static int ml_get_combo_effect(struct ml_device *ml,
__clear_bit(FF_EFFECT_PLAYING, &state->flags);
+ if (IS_CUSTOM(effect)) {
+ state->custom_index++;
+ effect2 = find_custom_effect(ml->states,
+ effect, state->custom_index);
+ if (effect2) {
+ struct ff_envelope *envelope;
+ state->play_at = jiffies +
+ msecs_to_jiffies(effect2->
+ replay.delay);
+ state->stop_at = state->play_at +
+ msecs_to_jiffies(effect2->
+ replay.length);
+ state->adj_at = state->play_at;
+ effect->replay.length =
+ effect2->replay.length;
+ envelope = (struct ff_envelope *)
+ get_envelope(effect2);
+ effect->u.periodic.envelope =
+ *envelope;
+ __clear_bit(i, effect_handled);
+ i--;
+ continue;
+ }
+ }
+
if (--state->count <= 0) {
__clear_bit(FF_EFFECT_STARTED, &state->flags);
} else {
+ if (IS_CUSTOM(effect)) {
+ struct ff_envelope *envelope;
+ state->custom_index = 0;
+ effect2 =
+ find_custom_effect(ml->states,
+ effect, state->custom_index);
+ if (!effect2) {
+ __clear_bit(FF_EFFECT_PLAYING,
+ &state->flags);
+ __clear_bit(FF_EFFECT_STARTED,
+ &state->flags);
+ continue;
+ }
+ effect->replay.length =
+ effect2->replay.length;
+ envelope = (struct ff_envelope *)
+ get_envelope(effect2);
+ effect->u.periodic.envelope =
+ *envelope;
+ __clear_bit(i, effect_handled);
+ i--;
+ }
state->play_at = jiffies +
msecs_to_jiffies(effect->replay.delay);
state->stop_at = state->play_at +
@@ -378,8 +449,27 @@ static int ml_get_combo_effect(struct ml_device *ml,
}
} else {
__set_bit(FF_EFFECT_PLAYING, &state->flags);
- state->adj_at = jiffies;
- ml_combine_effects(combo_effect, state, ml->gain);
+ if (IS_CUSTOM(effect)) {
+ struct ml_effect_state state2;
+ effect2 = find_custom_effect(ml->states,
+ effect, state->custom_index);
+ if (!effect2) {
+ __clear_bit(FF_EFFECT_PLAYING,
+ &state->flags);
+ __clear_bit(FF_EFFECT_STARTED,
+ &state->flags);
+ continue;
+ }
+ state->adj_at = jiffies;
+ memcpy(&state2, state, sizeof(state2));
+ state2.effect = effect2;
+ ml_combine_effects(combo_effect,
+ &state2, ml->gain);
+ } else {
+ state->adj_at = jiffies;
+ ml_combine_effects(combo_effect, state,
+ ml->gain);
+ }
}
}
@@ -446,6 +536,24 @@ static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
state->stop_at = state->play_at +
msecs_to_jiffies(state->effect->replay.length);
state->adj_at = state->play_at;
+ if (IS_CUSTOM(state->effect)) {
+ struct ff_effect *effect;
+ struct ff_envelope *envelope;
+ state->custom_index = 0;
+ effect = find_custom_effect(ml->states, state->effect,
+ state->custom_index);
+ if (!effect) {
+ __clear_bit(FF_EFFECT_STARTED, &state->flags);
+ return -EINVAL;
+ }
+ state->play_at = jiffies +
+ msecs_to_jiffies(effect->replay.delay);
+ state->stop_at = state->play_at +
+ msecs_to_jiffies(effect->replay.length);
+ state->effect->replay.length = effect->replay.length;
+ envelope = (struct ff_envelope *)get_envelope(effect);
+ state->effect->u.periodic.envelope = *envelope;
+ }
} else {
debug("initiated stop");
@@ -536,6 +644,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
set_bit(FF_SINE, dev->ffbit);
set_bit(FF_TRIANGLE, dev->ffbit);
set_bit(FF_SQUARE, dev->ffbit);
+ set_bit(FF_CUSTOM, dev->ffbit);
}
for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
@@ -83,6 +83,7 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size,
if (compat_effect->type == FF_PERIODIC &&
compat_effect->u.periodic.waveform == FF_CUSTOM)
+ /* This propably should make a real copy ++Jam */
effect->u.periodic.custom_data =
compat_ptr(compat_effect->u.periodic.custom_data);
} else {
--
1.6.3.3