return 0;
}
+static int ffpl_set_autocenter(struct klgd_plugin_private *priv, struct klgd_command_stream *s)
+{
+ union ffpl_control_data data;
+
+ data.autocenter = priv->autocenter;
+ return priv->control(priv->dev, s, FFPL_SET_AUTOCENTER, data);
+}
+
static int ffpl_set_gain(struct klgd_plugin_private *priv, struct klgd_command_stream *s)
{
union ffpl_control_data data;
return 0;
}
+static void ffpl_set_autocenter_rq(struct input_dev *dev, u16 autocenter)
+{
+ struct klgd_plugin *self = dev->ff->private;
+ struct klgd_plugin_private *priv = self->private;
+
+ klgd_lock_plugins(self->plugins_lock);
+
+ priv->autocenter = autocenter;
+ priv->change_autocenter = true;
+
+ klgd_unlock_plugins_sched(self->plugins_lock);
+}
+
static void ffpl_set_gain_rq(struct input_dev *dev, u16 gain)
{
struct klgd_plugin *self = dev->ff->private;
if (!s)
return -EAGAIN;
+ if (priv->change_autocenter) {
+ ret = ffpl_set_autocenter(priv, *s);
+ if (ret)
+ goto out;
+ priv->change_autocenter = false;
+ }
if (priv->change_gain) {
ret = ffpl_set_gain(priv, *s);
if (ret)
unsigned long events = 0;
/* Handle device-wide changes first */
- if (priv->change_gain) {
+ if (priv->change_gain || priv->change_autocenter) {
*t = now;
return true;
}
dev->ff->playback = ffpl_playback_rq;
dev->ff->upload = ffpl_upload_rq;
dev->ff->set_gain = ffpl_set_gain_rq;
+ dev->ff->set_autocenter = ffpl_set_autocenter_rq;
dev->ff->destroy = ffpl_destroy_rq;
printk(KERN_NOTICE "KLGDFF: Init complete\n");
priv->has_native_gain = true;
printk(KERN_NOTICE "KLGDFF: Using HAS_NATIVE_GAIN\n");
}
+ if (FFPL_HAS_AUTOCENTER & flags) {
+ priv->has_autocenter = true;
+ 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++) {
#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 */
+#define FFPL_HAS_AUTOCENTER BIT(16) /* Device supports autocentering */
enum ffpl_control_command {
/* Force feedback state transitions */
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_SET_GAIN /* Set gain */
+ FFPL_SET_GAIN, /* Set gain */
+ FFPL_SET_AUTOCENTER /*Set autocenter */
};
struct ffpl_effects {
union ffpl_control_data {
struct ffpl_effects effects;
- u16 ac_magnitude;
+ u16 autocenter;
u16 gain;
};
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;
+ u16 autocenter;
/* Optional device capabilities */
bool has_emp_to_srt;
bool has_srt_to_emp;
bool has_owr_to_upl;
bool has_owr_to_srt;
bool has_native_gain;
- u32 padding_caps:25;
+ bool has_autocenter;
+ u32 padding_caps:24;
/* Device-wide state changes */
bool change_gain;
- u32 padding_dw:31;
+ bool change_autocenter;
+ u32 padding_dw:30;
};
static struct klgd_main klgd;
static struct klgd_plugin *ff_plugin;
static u16 gain;
+static u16 autocenter;
static int klgdff_erase(struct klgd_command_stream *s, const struct ff_effect *effect)
{
return klgd_append_cmd(s, c);
}
+static int klgdff_set_autocenter(struct klgd_command_stream *s, const u16 _autocenter)
+{
+ char *text = kasprintf(GFP_KERNEL, "Setting autocenter to: %u", _autocenter);
+ size_t len = strlen(text);
+ struct klgd_command *c = klgd_alloc_cmd(len + 1);
+
+ if (!c)
+ return -ENOMEM;
+
+ autocenter = _autocenter;
+
+ memcpy(c->bytes, text, len);
+ kfree(text);
+ 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);
break;
case FFPL_SET_GAIN:
return klgdff_set_gain(s, data.gain);
+ case FFPL_SET_AUTOCENTER:
+ return klgdff_set_autocenter(s, data.autocenter);
default:
printk(KERN_NOTICE "KLGDFF-TD - Unhandled command\n");
break;
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_EMP_TO_SRT | FFPL_REPLACE_STARTED | FFPL_HAS_AUTOCENTER,
klgdff_control);
if (ret) {
printk(KERN_ERR "KLGDFF-TD: Cannot init plugin\n");