drivers/input/ff-memless.c

Source file repositories/reference/linux-study-clean/drivers/input/ff-memless.c

File Facts

System
Linux kernel
Corpus path
drivers/input/ff-memless.c
Extension
.c
Size
14245 bytes
Lines
549
Domain
Driver Families
Bucket
drivers/input
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ml_effect_state {
	struct ff_effect *effect;
	unsigned long flags;	/* effect state (STARTED, PLAYING, etc) */
	int count;		/* loop count of the effect */
	unsigned long play_at;	/* start time */
	unsigned long stop_at;	/* stop time */
	unsigned long adj_at;	/* last time the effect was sent */
};

struct ml_device {
	void *private;
	struct ml_effect_state states[FF_MEMLESS_EFFECTS];
	int gain;
	struct timer_list timer;
	struct input_dev *dev;

	int (*play_effect)(struct input_dev *dev, void *data,
			   struct ff_effect *effect);
};

static const struct ff_envelope *get_envelope(const struct ff_effect *effect)
{
	static const struct ff_envelope empty_envelope;

	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
 */
static unsigned long calculate_next_time(struct ml_effect_state *state)
{
	const struct ff_envelope *envelope = get_envelope(state->effect);
	unsigned long 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;
}

static void ml_schedule_timer(struct ml_device *ml)
{
	struct ml_effect_state *state;
	unsigned long now = jiffies;
	unsigned long earliest = 0;
	unsigned long 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))

Annotation

Implementation Notes