#include "klgd_ff_plugin_p.h"
#include <linux/slab.h>
#include <linux/fixp-arith.h>
+#include <linux/jiffies.h>
#define DIR_TO_DEGREES(dir) (360 - ((((dir > 0xc000) ? (u32)dir + 0x4000 - 0xffff : (u32)dir + 0x4000) * 360) / 0xffff))
struct klgd_plugin *self = dev->ff->private;
struct klgd_plugin_private *priv = self->private;
struct ffpl_effect *eff = &priv->effects[effect_id];
+ struct ff_effect *uff = &eff->latest;
+ const unsigned long now = jiffies;
klgd_lock_plugins(self->plugins_lock);
if (value) {
- eff->change = FFPL_TO_START;
eff->repeat = value;
- } else
- eff->change = FFPL_TO_STOP;
+ eff->start_at = now + msecs_to_jiffies(uff->replay.delay);
+ eff->trigger = FFPL_TRIG_START;
+ printk(KERN_NOTICE "KLGDFF: Delayed effect will be started at %lu, now: %lu\n", eff->start_at, now);
+
+ if (uff->replay.length) {
+ eff->finite = true;
+ eff->stop_at = eff->start_at + msecs_to_jiffies(uff->replay.length);
+ printk(KERN_NOTICE "KLGDFF: Finite effect will be stopped at %lu, now: %lu\n", eff->stop_at, now);
+ } else
+ eff->finite = false;
+ } else {
+ eff->trigger = FFPL_TRIG_STOP;
+ }
klgd_unlock_plugins_sched(self->plugins_lock);
return s;
}
+static void ffpl_advance_trigger(struct ffpl_effect *eff)
+{
+ switch (eff->trigger) {
+ case FFPL_TRIG_START:
+ if (eff->finite)
+ eff->trigger = FFPL_TRIG_STOP;
+ else
+ eff->trigger = FFPL_TRIG_NONE;
+ break;
+ case FFPL_TRIG_STOP:
+ eff->trigger = FFPL_TRIG_NONE;
+ break;
+ default:
+ break;
+ }
+}
+
static bool ffpl_get_update_time(struct klgd_plugin *self, const unsigned long now, unsigned long *t)
{
struct klgd_plugin_private *priv = self->private;
- size_t idx, events = 0;
+ size_t idx;
+ unsigned long events = 0;
for (idx = 0; idx < priv->effect_count; idx++) {
+ unsigned long current_t;
struct ffpl_effect *eff = &priv->effects[idx];
- /* Tell KLGD to attend to us as soon as possible if an effect has to change state */
- if (eff->change == FFPL_DONT_TOUCH)
+ switch (eff->trigger) {
+ default:
continue;
- *t = now;
- events++;
+ case FFPL_TRIG_START:
+ current_t = eff->start_at;
+ eff->change = FFPL_TO_START;
+ break;
+ case FFPL_TRIG_STOP:
+ current_t = eff->stop_at;
+ eff->change = FFPL_TO_STOP;
+ break;
+ }
+
+ ffpl_advance_trigger(eff);
+ if (!events++)
+ *t = current_t;
+ else if (time_before(current_t, *t))
+ *t = current_t;
}
return events ? true : false;
FFPL_TO_START, /* Effect shall be started */
FFPL_TO_STOP, /* Effect shall be stopped */
FFPL_TO_ERASE, /* Effect shall be removed from device */
- FFPL_TO_UPDATE /* Effect paramaters shall be updated */
+ FFPL_TO_UPDATE, /* Effect paramaters shall be updated */
};
/* Possible states of an effect */
FFPL_STARTED, /* Effect in the slot is started on device */
};
+/* What to do at the next timing trip point */
+enum ffpl_trigger {
+ FFPL_TRIG_NONE, /* No timing event scheduled for and effect */
+ FFPL_TRIG_START, /* Effect is to be started */
+ FFPL_TRIG_STOP /* Effect is to be stopped */
+};
+
struct ffpl_effect {
struct ff_effect active; /* Last effect submitted to device */
struct ff_effect latest; /* Last effect submitted to us by userspace */
- int repeat; /* How many times to repeat an effect - set in playback_rq */
enum ffpl_st_change change; /* State to which the effect shall be put */
enum ffpl_state state; /* State of the active effect */
bool replace; /* Active effect has to be replaced => active effect shall be erased and latest uploaded */
bool uploaded_to_device; /* Effect was physically uploaded to device */
+
+ enum ffpl_trigger trigger; /* What to do with the effect at its nearest timing trip point */
+ int repeat; /* How many times to repeat an effect - set in playback_rq */
+ unsigned long start_at; /* Time when to start the effect - in jiffies */
+ unsigned long stop_at; /* Time when to stop the effect - in jiffies */
+ bool finite; /* Effect has a finite duration */
};
struct klgd_plugin_private {