struct ml_effect_state { struct ff_effect *effect; unsignedlong flags; /* effect state (STARTED, PLAYING, etc) */ int count; /* loop count of the effect */ unsignedlong play_at; /* start time */ unsignedlong stop_at; /* stop time */ unsignedlong adj_at; /* last time the effect was sent */
};
switch (effect->type) { case FF_PERIODIC: return &effect->u.periodic.envelope;
case FF_CONSTANT: return &effect->u.constant.envelope;
default: return &empty_envelope;
}
}
/* * Check for the next time envelope requires an update on memoryless devices
*/ staticunsignedlong calculate_next_time(struct ml_effect_state *state)
{ conststruct ff_envelope *envelope = get_envelope(state->effect); unsignedlong attack_stop, fade_start, next_fade;
if (envelope->attack_length) {
attack_stop = state->play_at +
msecs_to_jiffies(envelope->attack_length); if (time_before(state->adj_at, attack_stop)) return state->adj_at +
msecs_to_jiffies(FF_ENVELOPE_INTERVAL);
}
if (state->effect->replay.length) { if (envelope->fade_length) { /* check when fading should start */
fade_start = state->stop_at -
msecs_to_jiffies(envelope->fade_length);
if (time_before(state->adj_at, fade_start)) return fade_start;
/* already fading, advance to next checkpoint */
next_fade = state->adj_at +
msecs_to_jiffies(FF_ENVELOPE_INTERVAL); if (time_before(next_fade, state->stop_at)) return next_fade;
}
return state->stop_at;
}
return state->play_at;
}
staticvoid ml_schedule_timer(struct ml_device *ml)
{ struct ml_effect_state *state; unsignedlong now = jiffies; unsignedlong earliest = 0; unsignedlong next_at; int events = 0; int i;
pr_debug("calculating next timer\n");
for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
state = &ml->states[i];
if (!test_bit(FF_EFFECT_STARTED, &state->flags)) continue;
if (test_bit(FF_EFFECT_PLAYING, &state->flags))
next_at = calculate_next_time(state); else
next_at = state->play_at;
/* * Apply an envelope to a value
*/ staticint apply_envelope(struct ml_effect_state *state, int value, struct ff_envelope *envelope)
{ struct ff_effect *effect = state->effect; unsignedlong now = jiffies; int time_from_level; int time_of_envelope; int envelope_level; int difference;
/* * Return the type the effect has to be converted into (memless devices)
*/ staticint get_compatible_type(struct ff_device *ff, int effect_type)
{
if (test_bit(effect_type, ff->ffbit)) return effect_type;
if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit)) return FF_RUMBLE;
pr_err("invalid type in get_compatible_type()\n");
return0;
}
/* * Only left/right direction should be used (under/over 0x8000) for * forward/reverse motor direction (to keep calculation fast & simple).
*/ static u16 ml_calculate_direction(u16 direction, u16 force,
u16 new_direction, u16 new_force)
{ if (!force) return new_direction; if (!new_force) return direction; return (((u32)(direction >> 1) * force +
(new_direction >> 1) * new_force) /
(force + new_force)) << 1;
}
staticinline s16 fixp_mult(s16 a, s16 b)
{
a = ((s32)a * 0x100) / 0x7fff; return ((s32)(a * b)) >> FRAC_N;
}
/* * Combine two effects and apply gain.
*/ staticvoid ml_combine_effects(struct ff_effect *effect, struct ml_effect_state *state, int gain)
{ struct ff_effect *new = state->effect; unsignedint strong, weak, i; int x, y;
s16 level;
switch (new->type) { case FF_CONSTANT:
i = new->direction * 360 / 0xffff;
level = fixp_new16(apply_envelope(state, new->u.constant.level,
&new->u.constant.envelope));
x = fixp_mult(fixp_sin16(i), level) * gain / 0xffff;
y = fixp_mult(-fixp_cos16(i), level) * gain / 0xffff; /* * here we abuse ff_ramp to hold x and y of constant force * If in future any driver wants something else than x and y * in s8, this should be changed to something more generic
*/
effect->u.ramp.start_level =
clamp_val(effect->u.ramp.start_level + x, -0x80, 0x7f);
effect->u.ramp.end_level =
clamp_val(effect->u.ramp.end_level + y, -0x80, 0x7f); break;
case FF_RUMBLE:
strong = (u32)new->u.rumble.strong_magnitude * gain / 0xffff;
weak = (u32)new->u.rumble.weak_magnitude * gain / 0xffff;
default:
pr_err("invalid type in ml_combine_effects()\n"); break;
}
}
/* * Because memoryless devices have only one effect per effect type active * at one time we have to combine multiple effects into one
*/ staticint ml_get_combo_effect(struct ml_device *ml, unsignedlong *effect_handled, struct ff_effect *combo_effect)
{ struct ff_effect *effect; struct ml_effect_state *state; int effect_type; int i;
for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { if (__test_and_set_bit(i, effect_handled)) continue;
state = &ml->states[i];
effect = state->effect;
if (!test_bit(FF_EFFECT_STARTED, &state->flags)) continue;
if (time_before(jiffies, state->play_at)) continue;
/* * here we have started effects that are either * currently playing (and may need be aborted) * or need to start playing.
*/
effect_type = get_compatible_type(ml->dev->ff, effect->type); if (combo_effect->type != effect_type) { if (combo_effect->type != 0) {
__clear_bit(i, effect_handled); continue;
}
combo_effect->type = effect_type;
}
/* * Even though we stop all playing effects when tearing down * an input device (via input_device_flush() that calls into * input_ff_flush() that stops and erases all effects), we * do not actually stop the timer, and therefore we should * do it here.
*/
timer_delete_sync(&ml->timer);
kfree(ml->private);
}
/** * input_ff_create_memless() - create memoryless force-feedback device * @dev: input device supporting force-feedback * @data: driver-specific data to be passed into @play_effect * @play_effect: driver-specific method for playing FF effect
*/ int input_ff_create_memless(struct input_dev *dev, void *data, int (*play_effect)(struct input_dev *, void *, struct ff_effect *))
{ struct ff_device *ff; int error; int i;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.