From 7f82e543a92ac09ac41b476b2e022fc912771461 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Mal=C3=BD?= Date: Sun, 2 Aug 2015 01:10:25 +0200 Subject: [PATCH] - Adapt to KLGD's updated API - Add actual support for adjustable gain --- klgd_ff_plugin.c | 85 +++++++++++++++++++++++++++++----------------- klgd_ff_plugin.h | 6 ++-- klgd_ff_plugin_p.h | 9 +++-- klgdff.c | 36 ++++++++++++++++---- 4 files changed, 95 insertions(+), 41 deletions(-) diff --git a/klgd_ff_plugin.c b/klgd_ff_plugin.c index e741d42..9e01c91 100644 --- a/klgd_ff_plugin.c +++ b/klgd_ff_plugin.c @@ -9,7 +9,6 @@ static int ffpl_handle_state_change(struct klgd_plugin_private *priv, struct klgd_command_stream *s, struct ffpl_effect *eff, const unsigned long now); -static bool ffpl_has_gain(const struct ff_effect *eff); static bool ffpl_needs_replacing(const struct ff_effect *ac_eff, const struct ff_effect *la_eff); void ffpl_lvl_dir_to_x_y(const s32 level, const u16 direction, s32 *x, s32 *y) @@ -496,6 +495,14 @@ static int ffpl_upload_effect(struct klgd_plugin_private *priv, struct klgd_comm return 0; } +static int ffpl_set_gain(struct klgd_plugin_private *priv, struct klgd_command_stream *s) +{ + union ffpl_control_data data; + + data.gain = priv->gain; + return priv->control(priv->dev, s, FFPL_SET_GAIN, data); +} + static void ffpl_calculate_trip_times(struct ffpl_effect *eff, const unsigned long now) { const struct ff_effect *ueff = &eff->latest; @@ -603,7 +610,6 @@ static int ffpl_upload_rq(struct input_dev *dev, struct ff_effect *effect, struc return 0; } -/*FIXME: Rewrite this! */ static void ffpl_set_gain_rq(struct input_dev *dev, u16 gain) { struct klgd_plugin *self = dev->ff->private; @@ -612,15 +618,22 @@ static void ffpl_set_gain_rq(struct input_dev *dev, u16 gain) klgd_lock_plugins(self->plugins_lock); - printk(KERN_DEBUG "KLGDFF: Gain set, %u\n", gain); + priv->gain = gain; + priv->change_gain = true; + if (priv->has_native_gain) + goto out; + for (idx = 0; idx < priv->effect_count; idx++) { struct ffpl_effect *eff = &priv->effects[idx]; - if (ffpl_has_gain(&eff->active)) - eff->change = FFPL_TO_UPDATE; + if (eff->state != FFPL_STARTED) + continue; + + eff->change = FFPL_TO_UPDATE; + eff->trigger = FFPL_TRIG_NOW; } - /* priv->gain = gain;*/ +out: klgd_unlock_plugins_sched(self->plugins_lock); } @@ -896,40 +909,52 @@ static void ffpl_advance_trigger(struct ffpl_effect *eff, const unsigned long no } } -static struct klgd_command_stream * ffpl_get_commands(struct klgd_plugin *self, const unsigned long now) +static int ffpl_get_commands(struct klgd_plugin *self, struct klgd_command_stream **s, const unsigned long now) { struct klgd_plugin_private *priv = self->private; - struct klgd_command_stream *s; size_t idx; int ret; - s = klgd_alloc_stream(); + *s = klgd_alloc_stream(); if (!s) - return NULL; /* TODO: Error handling */ + return -EAGAIN; - ret = ffpl_handle_combinable_effects(priv, s, now); - if (ret) + if (priv->change_gain) { + ret = ffpl_set_gain(priv, *s); + if (ret) + goto out; + priv->change_gain = false; + } + + ret = ffpl_handle_combinable_effects(priv, *s, now); + if (ret) { printk(KERN_WARNING "KLGDFF: Cannot process combinable effects, ret %d\n", ret); + goto out; + } /* Handle combined effect here */ - ret = ffpl_handle_state_change(priv, s, &priv->combined_effect, now); - if (ret) + ret = ffpl_handle_state_change(priv, *s, &priv->combined_effect, now); + if (ret) { printk(KERN_WARNING "KLGDFF: Cannot get command stream for combined effect\n"); + goto out; + } for (idx = 0; idx < priv->effect_count; idx++) { struct ffpl_effect *eff = &priv->effects[idx]; printk(KERN_NOTICE "KLGDFF: Processing effect %lu\n", idx); - ret = ffpl_handle_state_change(priv, s, eff, now); + ret = ffpl_handle_state_change(priv, *s, eff, now); /* TODO: Do something useful with the return code */ - if (ret) + if (ret) { printk(KERN_WARNING "KLGDFF: Cannot get command stream for effect %lu\n", idx); + goto out; + } ffpl_advance_trigger(eff, now); } - - return s; +out: + return ret; } static bool ffpl_get_update_time(struct klgd_plugin *self, const unsigned long now, unsigned long *t) @@ -938,6 +963,12 @@ static bool ffpl_get_update_time(struct klgd_plugin *self, const unsigned long n size_t idx; unsigned long events = 0; + /* Handle device-wide changes first */ + if (priv->change_gain) { + *t = now; + return true; + } + for (idx = 0; idx < priv->effect_count; idx++) { unsigned long current_t; struct ffpl_effect *eff = &priv->effects[idx]; @@ -1165,19 +1196,6 @@ static int ffpl_handle_state_change(struct klgd_plugin_private *priv, struct klg return ret; } -static bool ffpl_has_gain(const struct ff_effect *eff) -{ - switch (eff->type) { - case FF_CONSTANT: - case FF_PERIODIC: - case FF_RAMP: - case FF_RUMBLE: - return true; - default: - return false; - } -} - static int ffpl_init(struct klgd_plugin *self) { struct klgd_plugin_private *priv = self->private; @@ -1239,6 +1257,7 @@ int ffpl_init_plugin(struct klgd_plugin **plugin, struct input_dev *dev, const s priv->effect_count = effect_count; priv->dev = dev; priv->control = control; + priv->gain = 0xFFFF; self->private = priv; *plugin = self; @@ -1269,6 +1288,10 @@ 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_HAS_NATIVE_GAIN & flags) { + priv->has_native_gain = true; + printk(KERN_NOTICE "KLGDFF: Using HAS_NATIVE_GAIN\n"); + } set_bit(FF_GAIN, dev->ffbit); for (idx = 0; idx <= (FF_WAVEFORM_MAX - FF_EFFECT_MIN); idx++) { diff --git a/klgd_ff_plugin.h b/klgd_ff_plugin.h index e77f855..aee7378 100644 --- a/klgd_ff_plugin.h +++ b/klgd_ff_plugin.h @@ -10,6 +10,7 @@ #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_HAS_NATIVE_GAIN BIT(15) /* Device can adjust the gain by itself */ enum ffpl_control_command { /* Force feedback state transitions */ @@ -22,7 +23,9 @@ enum ffpl_control_command { FFPL_EMP_TO_SRT, /* Upload and start effect */ FFPL_SRT_TO_EMP, /* Stop and erase started effect */ FFPL_OWR_TO_UPL, /* Overwrite an effect with a new one and set its state to UPLOADED */ - FFPL_OWR_TO_SRT /* Overwrite an effect with a new one and set its state to STARTED */ + FFPL_OWR_TO_SRT, /* Overwrite an effect with a new one and set its state to STARTED */ + + FFPL_SET_GAIN /* Set gain */ }; struct ffpl_effects { @@ -37,7 +40,6 @@ union ffpl_control_data { u16 gain; }; - void ffpl_lvl_dir_to_x_y(const s32 level, const u16 direction, s32 *x, s32 *y); int ffpl_init_plugin(struct klgd_plugin **plugin, struct input_dev *dev, const size_t effect_count, const unsigned long supported_effects, diff --git a/klgd_ff_plugin_p.h b/klgd_ff_plugin_p.h index a125b7b..5a0c9a9 100644 --- a/klgd_ff_plugin_p.h +++ b/klgd_ff_plugin_p.h @@ -14,7 +14,7 @@ enum ffpl_st_change { enum ffpl_state { FFPL_EMPTY, /* There is no effect in the slot */ FFPL_UPLOADED, /* Effect in the slot is uploaded to device */ - FFPL_STARTED, /* Effect in the slot is started on device */ + FFPL_STARTED /* Effect in the slot is started on device */ }; /* What to do at the next timing trip point */ @@ -52,6 +52,7 @@ struct klgd_plugin_private { size_t effect_count; struct input_dev *dev; int (*control)(struct input_dev *dev, struct klgd_command_stream *s, const enum ffpl_control_command cmd, const union ffpl_control_data data); + u16 gain; /* Optional device capabilities */ bool has_emp_to_srt; bool has_srt_to_emp; @@ -59,5 +60,9 @@ struct klgd_plugin_private { bool erase_when_stopped; bool has_owr_to_upl; bool has_owr_to_srt; - u32 padding:26; + bool has_native_gain; + u32 padding_caps:25; + /* Device-wide state changes */ + bool change_gain; + u32 padding_dw:31; }; diff --git a/klgdff.c b/klgdff.c index fc1c6c7..1b9012e 100644 --- a/klgdff.c +++ b/klgdff.c @@ -12,6 +12,7 @@ static struct kobject *klgdff_obj; static struct input_dev *dev; static struct klgd_main klgd; static struct klgd_plugin *ff_plugin; +static u16 gain; static int klgdff_erase(struct klgd_command_stream *s, const struct ff_effect *effect) { @@ -69,6 +70,22 @@ static int klgdff_er_stop(struct klgd_command_stream *s, const struct ff_effect return klgd_append_cmd(s, c); } +static int klgdff_set_gain(struct klgd_command_stream *s, const u16 _gain) +{ + char *text = kasprintf(GFP_KERNEL, "Setting gain to: %u", _gain); + size_t len = strlen(text); + struct klgd_command *c = klgd_alloc_cmd(len + 1); + + if (!c) + return -ENOMEM; + + gain = _gain; + + memcpy(c->bytes, text, len); + kfree(text); + return klgd_append_cmd(s, c); +} + static int klgdff_start(struct klgd_command_stream *s, const struct ff_effect *effect, const int repeat) { char *text; @@ -80,9 +97,10 @@ static int klgdff_start(struct klgd_command_stream *s, const struct ff_effect *e { s32 x; s32 y; + s16 level = effect->u.constant.level * gain / 0xFFFF; - ffpl_lvl_dir_to_x_y(effect->u.constant.level, effect->direction, &x, &y); - text = kasprintf(GFP_KERNEL, "Playing FF_CONSTANT, level: %d, dir: %u, X: %d, Y: %d", effect->u.constant.level, effect->direction, x, y); + ffpl_lvl_dir_to_x_y(level, effect->direction, &x, &y); + text = kasprintf(GFP_KERNEL, "Playing FF_CONSTANT, level: %d, dir: %u, X: %d, Y: %d", level, effect->direction, x, y); break; } default: @@ -126,9 +144,10 @@ static int klgdff_update(struct klgd_command_stream *s, const struct ff_effect * { s32 x; s32 y; + s16 level = effect->u.constant.level * gain / 0xFFFF; - ffpl_lvl_dir_to_x_y(effect->u.constant.level, effect->direction, &x, &y); - text = kasprintf(GFP_KERNEL, "Updating FF_CONSTANT, level: %d, dir: %u, X: %d, Y: %d", effect->u.constant.level, effect->direction, x, y); + ffpl_lvl_dir_to_x_y(level, effect->direction, &x, &y); + text = kasprintf(GFP_KERNEL, "Updating FF_CONSTANT, level: %d, dir: %u, X: %d, Y: %d", level, effect->direction, x, y); break; } default: @@ -172,9 +191,10 @@ static int klgdff_up_start(struct klgd_command_stream *s, const struct ff_effect { s32 x; s32 y; + s16 level = effect->u.constant.level * gain / 0xFFFF; - ffpl_lvl_dir_to_x_y(effect->u.constant.level, effect->direction, &x, &y); - text = kasprintf(GFP_KERNEL, "Uploading and starting FF_CONSTANT, level: %d, dir: %u, X: %d, Y: %d", effect->u.constant.level, effect->direction, x, y); + ffpl_lvl_dir_to_x_y(level, effect->direction, &x, &y); + text = kasprintf(GFP_KERNEL, "Uploading and starting FF_CONSTANT, level: %d, dir: %u, X: %d, Y: %d", level, effect->direction, x, y); break; } default: @@ -249,6 +269,8 @@ int klgdff_control(struct input_dev *dev, struct klgd_command_stream *s, const e case FFPL_OWR_TO_UPL: return klgdff_owr_upload(s, data.effects.cur, data.effects.old); break; + case FFPL_SET_GAIN: + return klgdff_set_gain(s, data.gain); default: printk(KERN_NOTICE "KLGDFF-TD - Unhandled command\n"); break; @@ -281,6 +303,7 @@ static int __init klgdff_init(void) if (!klgdff_obj) return -ENOMEM; + ret = klgd_init(&klgd, NULL, klgdff_callback, 1); if (ret) { printk(KERN_ERR "KLGDFF-TD: Cannot initialize KLGD\n"); @@ -300,6 +323,7 @@ static int __init klgdff_init(void) dev->name = kasprintf(GFP_KERNEL, "KLGD-FF TestModule"); dev->uniq = kasprintf(GFP_KERNEL, "KLGD-FF TestModule-X"); dev->dev.parent = NULL; + gain = 0xFFFF; input_set_capability(dev, EV_ABS, ABS_X); input_set_capability(dev, EV_ABS, ABS_Y); -- 2.43.5