]> Devoid-pointer.net GitWeb - KLGD_FF_plugin.git/commitdiff
Allow KLGD-FF to operate in a dumbed down mode where it does not process
authorMichal Malý <madcatxster@devoid-pointer.net>
Sun, 9 Aug 2015 18:30:16 +0000 (20:30 +0200)
committerMichal Malý <madcatxster@devoid-pointer.net>
Sun, 9 Aug 2015 18:30:16 +0000 (20:30 +0200)
combinable effect and/or controls timing of those effects.

klgd_ff_plugin.c
klgd_ff_plugin.h
klgd_ff_plugin_p.h
klgdff.c

index 3a2b7c0eb00dd09fb8929bc0b32d1a24c43cc1f9..41240f9bb0f5696da6227d46f21c18802b3a3b17 100644 (file)
@@ -20,14 +20,15 @@ void ffpl_lvl_dir_to_x_y(const s32 level, const u16 direction, s32 *x, s32 *y)
        *y = (level * fixp_sin16(degrees)) >> FRAC_16;
 }
 
-static bool ffpl_is_combinable(const struct ff_effect *eff)
+static bool ffpl_process_memless(const struct klgd_plugin_private *priv, const struct ff_effect *eff)
 {
-       /* TODO: Proper decision of what is a combinable effect */
        switch (eff->type) {
        case FF_CONSTANT:
+               return priv->memless_mode;
        case FF_PERIODIC:
+               return priv->memless_periodic;
        case FF_RAMP:
-               return true;
+               return priv->memless_ramp;
        default:
                return false;
        }
@@ -50,6 +51,7 @@ static const struct ff_envelope * ffpl_get_envelope(const struct ff_effect *ueff
 static bool ffpl_is_effect_valid(const struct ff_effect *ueff)
 {
        const u16 length = ueff->replay.length;
+       const struct ff_envelope *env = ffpl_get_envelope(ueff);
 
        /* Periodic effects must have a non-zero period */
        if (ueff->type == FF_PERIODIC) {
@@ -60,14 +62,8 @@ static bool ffpl_is_effect_valid(const struct ff_effect *ueff)
        if (ueff->type == FF_RAMP && !length)
                return false;
 
-       if (ffpl_is_combinable(ueff)) {
+       if (env) {
                int fade_from;
-               const struct ff_envelope *env = ffpl_get_envelope(ueff);
-
-               if (!env) {
-                       printk(KERN_ERR "KLGDFF: NULL envelope in validity check. This cannot happen!\n");
-                       return false;
-               }
 
                /* Infinite effects cannot fade */
                if (!length && env->fade_length > 0)
@@ -454,6 +450,12 @@ static int ffpl_stop_effect(struct klgd_plugin_private *priv, struct klgd_comman
        if (cmd == FFPL_SRT_TO_EMP)
                eff->uploaded_to_device = false;
        eff->state = FFPL_UPLOADED;
+
+
+       /* Report back that the effect has stopped */
+       if (eff->trigger == FFPL_TRIG_STOP)
+               input_report_ff_status(dev, eff->active.id, FF_STATUS_STOPPED);
+
        return 0;
 }
 
@@ -568,7 +570,10 @@ static int ffpl_playback_rq(struct input_dev *dev, int effect_id, int value)
 
        eff->repeat = value;
        if (value > 0) {
-               ffpl_calculate_trip_times(eff, now);
+               if (priv->control_timing && ffpl_process_memless(priv, &eff->active))
+                       ffpl_calculate_trip_times(eff, now);
+               else
+                       eff->start_at = now; /* Start the effect right away and let the device deal with the timing */
                eff->trigger = FFPL_TRIG_START;
        } else {
                eff->change = FFPL_TO_STOP;
@@ -678,7 +683,7 @@ static int ffpl_handle_combinable_effects(struct klgd_plugin_private *priv, stru
 
                if (eff->replace) {
                        /* Uncombinable effect is about to be replaced by a combinable one */
-                       if (ffpl_is_combinable(&eff->latest)) {
+                       if (ffpl_process_memless(priv, &eff->latest)) {
                                printk(KERN_NOTICE "KLGDFF: Replacing uncombinable with combinable\n");
                                switch (eff->state) {
                                case FFPL_STARTED:
@@ -702,7 +707,7 @@ static int ffpl_handle_combinable_effects(struct klgd_plugin_private *priv, stru
                                continue;
                        }
                } else {
-                       if (!ffpl_is_combinable(&eff->latest))
+                       if (!ffpl_process_memless(priv, &eff->latest))
                                continue;
                }
 
@@ -851,13 +856,14 @@ static unsigned long ffpl_get_recalculation_time(const struct ffpl_effect *eff,
        return ffpl_get_env_recalculation_time(eff, now);
 }
 
-static bool ffpl_needs_recalculation(const struct ff_effect *ueff, const unsigned long start_at, const unsigned long stop_at, const unsigned long now)
+static bool ffpl_needs_recalculation(const struct klgd_plugin_private *priv, const struct ff_effect *ueff, const unsigned long start_at,
+                                    const unsigned long stop_at, const unsigned long now)
 {
        const struct ff_envelope *env = ffpl_get_envelope(ueff);
        bool ticks = ueff->type == FF_PERIODIC || ueff->type == FF_RAMP;
 
-       /* Only combinable effects can be periodically reprocessed */
-       if (!ffpl_is_combinable(ueff)) {
+       /* Only effects handled by memless mode can be periodically reprocessed */
+       if (!ffpl_process_memless(priv, ueff)) {
                printk(KERN_NOTICE "KLGDFF: Effect not combinable, won't recalculate\n");
                return false;
        }
@@ -888,15 +894,15 @@ static bool ffpl_needs_recalculation(const struct ff_effect *ueff, const unsigne
        return true;
 }
 
-static void ffpl_advance_trigger(struct ffpl_effect *eff, const unsigned long now)
+static void ffpl_advance_trigger(const struct klgd_plugin_private *priv, struct ffpl_effect *eff, const unsigned long now)
 {
        switch (eff->trigger) {
        case FFPL_TRIG_START:
-               if (ffpl_needs_recalculation(&eff->latest, eff->start_at, eff->stop_at, now)) {
+               if (ffpl_needs_recalculation(priv, &eff->latest, eff->start_at, eff->stop_at, now)) {
                        eff->trigger = FFPL_TRIG_RECALC;
                        break;
                }
-               if (eff->latest.replay.length)
+               if (eff->latest.replay.length && priv->control_timing && ffpl_process_memless(priv, &eff->latest))
                        eff->trigger = FFPL_TRIG_STOP;
                else
                        eff->trigger = FFPL_TRIG_NONE;
@@ -905,16 +911,16 @@ static void ffpl_advance_trigger(struct ffpl_effect *eff, const unsigned long no
                eff->trigger = FFPL_TRIG_STOP;
                break;
        case FFPL_TRIG_RECALC:
-               if (ffpl_needs_recalculation(&eff->active, eff->start_at, eff->stop_at, now))
+               if (ffpl_needs_recalculation(priv, &eff->active, eff->start_at, eff->stop_at, now))
                        break;
-               if (eff->active.replay.length) {
+               if (eff->active.replay.length && priv->control_timing && ffpl_process_memless(priv, &eff->active)) {
                        eff->trigger = FFPL_TRIG_STOP;
                        break;
                }
                eff->trigger = FFPL_TRIG_NONE;
                break;
        case FFPL_TRIG_STOP:
-               if (eff->repeat > 0) {
+               if (eff->repeat > 0 && priv->control_timing && ffpl_process_memless(priv, &eff->active)) {
                        eff->trigger = FFPL_TRIG_RESTART;
                        break;
                }
@@ -922,7 +928,7 @@ static void ffpl_advance_trigger(struct ffpl_effect *eff, const unsigned long no
                eff->trigger = FFPL_TRIG_NONE;
                break;
        case FFPL_TRIG_UPDATE:
-               if (ffpl_needs_recalculation(&eff->active, eff->start_at, eff->stop_at, now) && eff->state == FFPL_STARTED)
+               if (ffpl_needs_recalculation(priv, &eff->active, eff->start_at, eff->stop_at, now) && eff->state == FFPL_STARTED)
                        eff->trigger = FFPL_TRIG_RECALC;
                else
                        eff->trigger = FFPL_TRIG_NONE;
@@ -979,7 +985,7 @@ static int ffpl_get_commands(struct klgd_plugin *self, struct klgd_command_strea
                        goto out;
                }
 
-               ffpl_advance_trigger(eff, now);
+               ffpl_advance_trigger(priv, eff, now);
        }
 
 out:
@@ -1318,6 +1324,22 @@ int ffpl_init_plugin(struct klgd_plugin **plugin, struct input_dev *dev, const s
                priv->has_owr_to_srt = true;
                printk("KLGDFF: Using REPLACE STARTED\n");
        }
+       if (FFPL_MEMLESS_MODE & flags) {
+               priv->memless_mode = true;
+               priv->control_timing = true;
+       }
+       if (FFPL_MEMLESS_PERIODIC & flags) {
+               priv->memless_mode = true;
+               priv->memless_periodic = true;
+               priv->control_timing = true;
+       }
+       if (FFPL_MEMLESS_RAMP & flags) {
+               priv->memless_mode = true;
+               priv->memless_ramp = true;
+               priv->control_timing = true;
+       }
+       if (FFPL_CONTROL_TIMING & flags)
+             priv->control_timing = true;
        if (FFPL_HAS_NATIVE_GAIN & flags) {
                priv->has_native_gain = true;
                printk(KERN_NOTICE "KLGDFF: Using HAS_NATIVE_GAIN\n");
@@ -1327,7 +1349,6 @@ int ffpl_init_plugin(struct klgd_plugin **plugin, struct input_dev *dev, const s
                set_bit(FF_AUTOCENTER, dev->ffbit);
                printk(KERN_NOTICE "KLGDFF: Using HAS_AUTOCENTER\n");
        }
-
        set_bit(FF_GAIN, dev->ffbit);
        for (idx = 0; idx <= (FF_WAVEFORM_MAX - FF_EFFECT_MIN); idx++) {
                if (test_bit(idx, &priv->supported_effects)) {
index 748163be807165a74b00bbd6abe5bd70e169880b..90aa9b557356955230362e2f671e26a017fc8d20 100644 (file)
 #define FFPL_ERASE_WHEN_STOPPED BIT(3) /* Erases effect from device when it is stopped - this implies HAS_SRT_TO_EMP */
 #define FFPL_REPLACE_UPLOADED BIT(4) /* Device can accept a new effect to UPLOADED state without the need to explicitly stop and erase the previously uploaded effect beforehand */
 #define FFPL_REPLACE_STARTED BIT(5) /* Device can accept a new effect to STARTED state without the need to explicitly stop and erase the previously uploaded effect beforehand */
+
+#define FFPL_MEMLESS_MODE BIT(6)     /* Device cannot process effects by itself and required KLGD-FF to do all calculations for it. */
+#define FFPL_MEMLESS_PERIODIC BIT(7) /* Device cannot process FF_PERIODIC by itself and requires KLGD-FF to calculate the overall force.
+                                       Device must support FF_CONSTANT for this to work.
+                                       This flag implies FFPL_MEMLESS_MODE */
+#define FFPL_MEMLESS_RAMP BIT(8)     /* Device cannot process FF_RAMP by itself and requires KLGD-FF to calculate the overall force.
+                                       Device must support FF_CONSTANT for this to work.
+                                       This flag implies FFPL_MEMLESS_MODE */
+#define FFPL_CONTROL_TIMING BIT(9)   /* Device cannot handle effects with finite duration, delays and repeated effects. Let KLGD-FF take care
+                                       of starting, stopping and restarting effects at appropriate times.
+                                       FFPL_MEMLESS_MODE implies this flag. */
+
 #define FFPL_HAS_NATIVE_GAIN BIT(15)  /* Device can adjust the gain by itself */
 #define FFPL_HAS_AUTOCENTER BIT(16) /* Device supports autocentering */
 
index bd0f4f348340529220c9bc2417e31f7037d044c1..e23b6491b8e698efee0d36e83fb49925255b8681 100644 (file)
@@ -63,7 +63,11 @@ struct klgd_plugin_private {
        bool has_owr_to_srt;
        bool has_native_gain;
        bool has_autocenter;
-       u32 padding_caps:24;
+       bool memless_mode;
+       bool memless_periodic;
+       bool memless_ramp;
+       bool control_timing;
+       u32 padding_caps:20;
        /* Device-wide state changes */
        bool change_gain;
        bool change_autocenter;
index 747ad016bbb7e9278c4d7252a8e326ba057956b1..703993d2ca51e59d5dc7b707bfcdc0180274028a 100644 (file)
--- a/klgdff.c
+++ b/klgdff.c
@@ -83,6 +83,7 @@ static int klgdff_set_autocenter(struct klgd_command_stream *s, const u16 _autoc
        autocenter = _autocenter;
 
        memcpy(c->bytes, text, len);
+       c->user = (unsigned long)0xDEADBEEF;
        kfree(text);
        return klgd_append_cmd(s, c);
 }
@@ -235,8 +236,11 @@ int klgdff_callback(void *data, const struct klgd_command_stream *s)
        size_t idx;
 
        printk(KERN_NOTICE "KLGDTM - EFF...\n");
-       for (idx = 0; idx < s->count; idx++)
+       for (idx = 0; idx < s->count; idx++) {
                printk(KERN_NOTICE "KLGDFF-TD: EFF %s\n", s->commands[idx]->bytes);
+               if (s->commands[idx]->user)
+                       printk("KLGDFF-TD: User 0x%x\n", (unsigned int)s->commands[idx]->user);
+       }
 
        /* Simulate default USB polling rate of 125 Hz */
        /*usleep_range(7500, 8500);*/
@@ -315,7 +319,9 @@ static int __init klgdff_init(void)
                                                       | FFPL_EFBIT(FF_SAW_UP)
                                                       | FFPL_EFBIT(FF_SAW_DOWN)
                                                       | FFPL_EFBIT(FF_TRIANGLE) |
-                              FFPL_EFBIT(FF_RAMP);
+                              FFPL_EFBIT(FF_RAMP) |
+                              FFPL_EFBIT(FF_SPRING);
+
        int ret;
 
        klgdff_obj = kobject_create_and_add("klgdff_obj", kernel_kobj);
@@ -352,7 +358,7 @@ static int __init klgdff_init(void)
        input_set_abs_params(dev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
 
        ret = ffpl_init_plugin(&ff_plugin, dev, EFFECT_COUNT, ffbits,
-                              FFPL_HAS_EMP_TO_SRT | FFPL_REPLACE_STARTED | FFPL_HAS_AUTOCENTER,
+                              FFPL_HAS_EMP_TO_SRT | FFPL_REPLACE_STARTED | FFPL_HAS_AUTOCENTER | FFPL_MEMLESS_MODE,
                               klgdff_control);
        if (ret) {
                printk(KERN_ERR "KLGDFF-TD: Cannot init plugin\n");