sound/core/seq/seq_timer.c

Source file repositories/reference/linux-study-clean/sound/core/seq/seq_timer.c

File Facts

System
Linux kernel
Corpus path
sound/core/seq/seq_timer.c
Extension
.c
Size
11334 bytes
Lines
473
Domain
Driver Families
Bucket
sound/core
Inferred role
Driver Families: implementation source
Status
source 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

if (tmr->skew != tmr->skew_base) {
			/* FIXME: assuming skew_base = 0x10000 */
			resolution = (resolution >> 16) * tmr->skew +
				(((resolution & 0xffff) * tmr->skew) >> 16);
		}

		/* update timer */
		snd_seq_inc_time_nsec(&tmr->cur_time, resolution);

		/* calculate current tick */
		snd_seq_timer_update_tick(&tmr->tick, resolution);

		/* register actual time of this timer update */
		ktime_get_ts64(&tmr->last_update);
	}

	/* check queues and dispatch events */
	snd_seq_check_queue(q, 1, 0);
}

/* set current tempo */
int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
{
	if (snd_BUG_ON(!tmr))
		return -EINVAL;
	if (tempo <= 0)
		return -EINVAL;
	guard(spinlock_irqsave)(&tmr->lock);
	if ((unsigned int)tempo != tmr->tempo) {
		tmr->tempo = tempo;
		snd_seq_timer_set_tick_resolution(tmr);
	}
	return 0;
}

/* set current tempo, ppq and base in a shot */
int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq,
				unsigned int tempo_base)
{
	int changed;

	if (snd_BUG_ON(!tmr))
		return -EINVAL;
	if (tempo <= 0 || ppq <= 0)
		return -EINVAL;
	/* allow only 10ns or 1us tempo base for now */
	if (tempo_base && tempo_base != 10 && tempo_base != 1000)
		return -EINVAL;
	guard(spinlock_irqsave)(&tmr->lock);
	if (tmr->running && (ppq != tmr->ppq)) {
		/* refuse to change ppq on running timers */
		/* because it will upset the song position (ticks) */
		pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
		return -EBUSY;
	}
	changed = (tempo != tmr->tempo) || (ppq != tmr->ppq);
	tmr->tempo = tempo;
	tmr->ppq = ppq;
	tmr->tempo_base = tempo_base ? tempo_base : 1000;
	if (changed)
		snd_seq_timer_set_tick_resolution(tmr);
	return 0;
}

/* set current tick position */
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
				    snd_seq_tick_time_t position)
{
	if (snd_BUG_ON(!tmr))
		return -EINVAL;

	guard(spinlock_irqsave)(&tmr->lock);
	tmr->tick.cur_tick = position;
	tmr->tick.fraction = 0;
	return 0;
}

/* set current real-time position */
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
				    snd_seq_real_time_t position)
{
	if (snd_BUG_ON(!tmr))
		return -EINVAL;

	snd_seq_sanity_real_time(&position);
	guard(spinlock_irqsave)(&tmr->lock);
	tmr->cur_time = position;
	return 0;
}

Annotation

Implementation Notes