From af7a36e1e2b5eb5dd924d2380c67d887843cbbac Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Mal=C3=BD?= Date: Sun, 20 Sep 2015 21:41:44 +0200 Subject: [PATCH] Initial implementation of rumble effects combining --- klgd_ff_plugin.c | 146 +++++++++++++++++++++++++++++++++++---------- klgd_ff_plugin.h | 5 +- klgd_ff_plugin_p.h | 6 +- klgdff.c | 3 +- 4 files changed, 126 insertions(+), 34 deletions(-) diff --git a/klgd_ff_plugin.c b/klgd_ff_plugin.c index 830257f..313a712 100644 --- a/klgd_ff_plugin.c +++ b/klgd_ff_plugin.c @@ -11,6 +11,47 @@ MODULE_DESCRIPTION("KLGD-FF Module"); #define DIR_TO_DEGREES(dir) (360 - ((((dir > 0xc000) ? (u32)dir + 0x4000 - 0xffff : (u32)dir + 0x4000) * 360) / 0xffff)) #define FRAC_16 15 #define RECALC_DELTA_T_MSEC 20 +#define NEEDS_UPDATE_SET(etype, ffbit) \ + do { \ + switch (etype) { \ + case FF_CONSTANT: \ + case FF_RAMP: \ + needs_update_cf = true; \ + break; \ + case FF_RUMBLE: \ + needs_update_rumble = true; \ + break; \ + case FF_PERIODIC: \ + if (test_bit(FF_CONSTANT, ffbit)) \ + needs_update_cf = true; \ + else \ + needs_update_rumble = true; \ + break; \ + default: \ + break; \ + } \ + } while (0); + +#define ACTIVE_EFFECTS_INC(etype, ffbit) \ + do { \ + switch (etype) { \ + case FF_CONSTANT: \ + case FF_RAMP: \ + active_effects_cf++; \ + break; \ + case FF_RUMBLE: \ + active_effects_rumble++; \ + break; \ + case FF_PERIODIC: \ + if (test_bit(FF_CONSTANT, ffbit)) \ + active_effects_cf++; \ + else \ + active_effects_rumble++; \ + break; \ + default: \ + break; \ + } \ + } while (0); static int ffpl_handle_state_change(struct klgd_plugin_private *priv, struct klgd_command_stream *s, struct ffpl_effect *eff, const unsigned long now); @@ -35,6 +76,8 @@ inline static bool ffpl_process_memless(const struct klgd_plugin_private *priv, return priv->memless_periodic; case FF_RAMP: return priv->memless_ramp; + case FF_RUMBLE: + return priv->memless_rumble; default: return false; } @@ -328,10 +371,10 @@ static void ffpl_ramp_to_x_y(struct ffpl_effect *eff, s32 *x, s32 *y, const unsi ffpl_lvl_dir_to_x_y(new, ueff->direction, x, y); } -static void ffpl_recalc_combined(struct klgd_plugin_private *priv, const unsigned long now) +static void ffpl_recalc_combined_cf(struct klgd_plugin_private *priv, const unsigned long now, const bool handle_periodic) { size_t idx; - struct ff_effect *cb_latest = &priv->combined_effect.latest; + struct ff_effect *cb_latest = &priv->combined_effect_cf.latest; s32 x = 0; s32 y = 0; @@ -349,6 +392,8 @@ static void ffpl_recalc_combined(struct klgd_plugin_private *priv, const unsigne ffpl_constant_to_x_y(eff, &_x, &_y, now); break; case FF_PERIODIC: + if (!handle_periodic) + break; ffpl_periodic_to_x_y(eff, &_x, &_y, now); break; case FF_RAMP: @@ -370,6 +415,26 @@ static void ffpl_recalc_combined(struct klgd_plugin_private *priv, const unsigne cb_latest->direction); } +static void ffpl_recalc_combined_rumble(struct klgd_plugin_private *priv, const unsigned long now, const bool handle_periodic) +{ + size_t idx; + struct ff_effect *cb_latest = &priv->combined_effect_rumble.latest; + + for (idx = 0; idx < priv->effect_count; idx++) { + struct ffpl_effect *eff = &priv->effects[idx]; + struct ff_effect *ueff = &eff->active; + + switch (ueff->type) { + case FF_RUMBLE: + break; + case FF_PERIODIC: + if (!handle_periodic) + break; + break; + } + } +} + static int ffpl_erase_effect(struct klgd_plugin_private *priv, struct klgd_command_stream *s, struct ffpl_effect *eff) { if (eff->uploaded_to_device) { @@ -698,8 +763,10 @@ static int ffpl_handle_combinable_effects(struct klgd_plugin_private *priv, stru const unsigned long now) { size_t idx; - bool needs_update = false; - size_t active_effects = 0; + bool needs_update_cf = false; + bool needs_update_rumble = false; + size_t active_effects_cf = 0; + size_t active_effects_rumble = 0; for (idx = 0; idx < priv->effect_count; idx++) { int ret; @@ -730,7 +797,7 @@ static int ffpl_handle_combinable_effects(struct klgd_plugin_private *priv, stru /* Combinable effect is being replaced by an uncombinable one */ printk(KERN_NOTICE "KLGDFF: Replacing combinable with uncombinable\n"); if (eff->state == FFPL_STARTED) - needs_update = true; + NEEDS_UPDATE_SET(eff->active.type, priv->dev->ffbit); eff->state = FFPL_EMPTY; eff->replace = false; continue; @@ -743,14 +810,14 @@ static int ffpl_handle_combinable_effects(struct klgd_plugin_private *priv, stru switch (eff->change) { case FFPL_DONT_TOUCH: if (eff->state == FFPL_STARTED) { - active_effects++; + ACTIVE_EFFECTS_INC(eff->active.type, priv->dev->ffbit); if (eff->recalculate) { - needs_update = true; + NEEDS_UPDATE_SET(eff->active.type, priv->dev->ffbit); eff->recalculate = false; - printk(KERN_NOTICE "KLGDFF: Recalculable combinable effect, total active effects %lu\n", active_effects); + printk(KERN_NOTICE "KLGDFF: Recalculable combinable effect, total active effects (CF/Rumble) %lu/%lu\n", active_effects_cf, active_effects_rumble); } } else - printk(KERN_NOTICE "KLGDFF: Unchanged combinable effect, total active effects %lu\n", active_effects); + printk(KERN_NOTICE "KLGDFF: Unchanged combinable effect, total active effects (CF/Rumble) %lu/%lu\n", active_effects_cf, active_effects_rumble); break; case FFPL_TO_START: eff->state = FFPL_STARTED; @@ -760,13 +827,14 @@ static int ffpl_handle_combinable_effects(struct klgd_plugin_private *priv, stru printk(KERN_NOTICE "KLGDFF: Updating a stopped combinable effect\n"); break; } - active_effects++; - needs_update = true; - printk(KERN_NOTICE "KLGDFF: %s combinable effect, total active effects %lu\n", eff->change == FFPL_TO_START ? "Started" : "Altered", active_effects); + ACTIVE_EFFECTS_INC(eff->active.type, priv->dev->ffbit); + NEEDS_UPDATE_SET(eff->active.type, priv->dev->ffbit); + printk(KERN_NOTICE "KLGDFF: %s combinable effect, total active effects (CF/Rumble) %lu/%lu\n", eff->change == FFPL_TO_START ? "Started" : "Altered", + active_effects_cf, active_effects_rumble); break; case FFPL_TO_STOP: if (eff->state == FFPL_STARTED) - needs_update = true; + NEEDS_UPDATE_SET(eff->active.type, priv->dev->ffbit); case FFPL_TO_UPLOAD: eff->active = eff->latest; eff->state = FFPL_UPLOADED; @@ -774,9 +842,9 @@ static int ffpl_handle_combinable_effects(struct klgd_plugin_private *priv, stru break; case FFPL_TO_ERASE: if (eff->state == FFPL_STARTED) - needs_update = true; + NEEDS_UPDATE_SET(eff->active.type, priv->dev->ffbit); eff->state = FFPL_EMPTY; - printk(KERN_NOTICE "KLGDFF: Stopped combinable effect, total active effects %lu\n", active_effects); + printk(KERN_NOTICE "KLGDFF: Stopped combinable effect, total active effects (CF/Rumble) %lu/%lu\n", active_effects_cf, active_effects_rumble); break; default: printk(KERN_WARNING "KLGDFF: Unknown effect change!\n"); @@ -787,21 +855,37 @@ static int ffpl_handle_combinable_effects(struct klgd_plugin_private *priv, stru } /* Combined effect needs recalculation */ - if (needs_update) { - if (active_effects) { - printk(KERN_NOTICE "KLGDFF: Combined effect needs an update, total effects active: %lu\n", active_effects); - ffpl_recalc_combined(priv, now); - if (priv->combined_effect.state == FFPL_STARTED) - priv->combined_effect.change = FFPL_TO_UPDATE; + if (needs_update_cf) { + if (active_effects_cf) { + printk(KERN_NOTICE "KLGDFF: Combined constant force effect needs an update, total effects active: %lu\n", active_effects_cf); + ffpl_recalc_combined_cf(priv, now, test_bit(FF_CONSTANT, priv->dev->ffbit)); + if (priv->combined_effect_cf.state == FFPL_STARTED) + priv->combined_effect_cf.change = FFPL_TO_UPDATE; else - priv->combined_effect.change = FFPL_TO_START; - - return 0; + priv->combined_effect_cf.change = FFPL_TO_START; + } else { + /* No combinable effects are active, remove the effect from device */ + if (priv->combined_effect_cf.state != FFPL_EMPTY) { + printk(KERN_NOTICE "KLGDFF: No combinable constant force effects are active, erase the combined constant force effect from device\n"); + priv->combined_effect_cf.change = FFPL_TO_ERASE; + } } - /* No combinable effects are active, remove the effect from device */ - if (priv->combined_effect.state != FFPL_EMPTY) { - printk(KERN_NOTICE "KLGDFF: No combinable effects are active, erase the combined effect from device\n"); - priv->combined_effect.change = FFPL_TO_ERASE; + } + + if (needs_update_rumble) { + if (active_effects_rumble) { + printk(KERN_NOTICE "KLGDFF: Combined rumble effect needs an update, total effects active: %lu\n", active_effects_rumble); + ffpl_recalc_combined_rumble(priv, now, test_bit(FF_CONSTANT, priv->dev->ffbit)); + if (priv->combined_effect_rumble.state == FFPL_STARTED) + priv->combined_effect_rumble.change = FFPL_TO_UPDATE; + else + priv->combined_effect_rumble.change = FFPL_TO_START; + } else { + /* No combinable effects are active, remove the effect from device */ + if (priv->combined_effect_rumble.state != FFPL_EMPTY) { + printk(KERN_NOTICE "KLGDFF: No combinable rumble effects are active, erase the combined effect from device\n"); + priv->combined_effect_rumble.change = FFPL_TO_ERASE; + } } } @@ -1002,9 +1086,9 @@ static int ffpl_get_commands(struct klgd_plugin *self, struct klgd_command_strea } /* Handle combined effect here */ - ret = ffpl_handle_state_change(priv, *s, &priv->combined_effect, now); + ret = ffpl_handle_state_change(priv, *s, &priv->combined_effect_cf, now); if (ret) { - printk(KERN_WARNING "KLGDFF: Cannot get command stream for combined effect\n"); + printk(KERN_WARNING "KLGDFF: Cannot get command stream for combined constant force effect\n"); goto out; } @@ -1383,6 +1467,8 @@ int ffpl_init_plugin(struct klgd_plugin **plugin, struct input_dev *dev, const s priv->memless_periodic = true; if (FFPL_MEMLESS_RAMP & flags) priv->memless_ramp = true; + if (FFPL_MEMLESS_RUMBLE & flags) + priv->memless_rumble = true; if (FFPL_TIMING_CONDITION & flags) priv->timing_condition = true; diff --git a/klgd_ff_plugin.h b/klgd_ff_plugin.h index e7c7e4c..f110e8b 100644 --- a/klgd_ff_plugin.h +++ b/klgd_ff_plugin.h @@ -17,7 +17,10 @@ Device must support FF_CONSTANT for this to work. */ #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. */ -#define FFPL_TIMING_CONDITION BIT(9) /* Let the plugin take care of starting and stopping of condition effects */ +#define FFPL_MEMLESS_RUMBLE BIT(9) /* Device cannot process FF_RUMBLE by itself and requires KLGD-FF to calculate the overall force. + Device must support FF_RUMBLE for this to work. */ + +#define FFPL_TIMING_CONDITION BIT(10) /* Let the plugin take care of starting and stopping of condition effects */ #define FFPL_HAS_NATIVE_GAIN BIT(15) /* Device can adjust the gain by itself */ #define FFPL_HAS_AUTOCENTER BIT(16) /* Device supports autocentering */ diff --git a/klgd_ff_plugin_p.h b/klgd_ff_plugin_p.h index 60dac45..a064497 100644 --- a/klgd_ff_plugin_p.h +++ b/klgd_ff_plugin_p.h @@ -48,7 +48,8 @@ struct ffpl_effect { struct klgd_plugin_private { struct ffpl_effect *effects; - struct ffpl_effect combined_effect; + struct ffpl_effect combined_effect_cf; + struct ffpl_effect combined_effect_rumble; unsigned long supported_effects; size_t effect_count; struct input_dev *dev; @@ -68,8 +69,9 @@ struct klgd_plugin_private { bool memless_constant; bool memless_periodic; bool memless_ramp; + bool memless_rumble; bool timing_condition; - u32 padding_caps:20; + u32 padding_caps:19; /* Device-wide state changes */ bool change_gain; bool change_autocenter; diff --git a/klgdff.c b/klgdff.c index 83fe160..f282dcd 100644 --- a/klgdff.c +++ b/klgdff.c @@ -356,7 +356,8 @@ 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_MEMLESS_RAMP | FFPL_TIMING_CONDITION, + FFPL_HAS_EMP_TO_SRT | FFPL_REPLACE_STARTED | FFPL_HAS_AUTOCENTER | + FFPL_MEMLESS_CONSTANT | FFPL_MEMLESS_RUMBLE | FFPL_TIMING_CONDITION, klgdff_control, &test_user); if (ret) { printk(KERN_ERR "KLGDFF-TD: Cannot init plugin\n"); -- 2.43.5