sound/pci/ctxfi/cttimer.c

Source file repositories/reference/linux-study-clean/sound/pci/ctxfi/cttimer.c

File Facts

System
Linux kernel
Corpus path
sound/pci/ctxfi/cttimer.c
Extension
.c
Size
10546 bytes
Lines
423
Domain
Driver Families
Bucket
sound/pci
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

struct ct_timer_ops {
	void (*init)(struct ct_timer_instance *);
	void (*prepare)(struct ct_timer_instance *);
	void (*start)(struct ct_timer_instance *);
	void (*stop)(struct ct_timer_instance *);
	void (*free_instance)(struct ct_timer_instance *);
	void (*interrupt)(struct ct_timer *);
	void (*free_global)(struct ct_timer *);
};

/* timer instance -- assigned to each PCM stream */
struct ct_timer_instance {
	spinlock_t lock;
	struct ct_timer *timer_base;
	struct ct_atc_pcm *apcm;
	struct snd_pcm_substream *substream;
	struct timer_list timer;
	struct list_head instance_list;
	struct list_head running_list;
	unsigned int position;
	unsigned int frag_count;
	unsigned int running:1;
	unsigned int need_update:1;
};

/* timer instance manager */
struct ct_timer {
	spinlock_t lock;		/* global timer lock (for xfitimer) */
	spinlock_t list_lock;		/* lock for instance list */
	struct ct_atc *atc;
	const struct ct_timer_ops *ops;
	struct list_head instance_head;
	struct list_head running_head;
	unsigned int wc;		/* current wallclock */
	unsigned int irq_handling:1;	/* in IRQ handling */
	unsigned int reprogram:1;	/* need to reprogram the internval */
	unsigned int running:1;		/* global timer running */
};


/*
 * system-timer-based updates
 */

static void ct_systimer_callback(struct timer_list *t)
{
	struct ct_timer_instance *ti = timer_container_of(ti, t, timer);
	struct snd_pcm_substream *substream = ti->substream;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct ct_atc_pcm *apcm = ti->apcm;
	unsigned int period_size = runtime->period_size;
	unsigned int buffer_size = runtime->buffer_size;
	unsigned int position, dist, interval;

	position = substream->ops->pointer(substream);
	dist = (position + buffer_size - ti->position) % buffer_size;
	if (dist >= period_size ||
	    position / period_size != ti->position / period_size) {
		apcm->interrupt(apcm);
		ti->position = position;
	}
	/* Add extra HZ*5/1000 to avoid overrun issue when recording
	 * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
	interval = ((period_size - (position % period_size))
		   * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
	guard(spinlock_irqsave)(&ti->lock);
	if (ti->running)
		mod_timer(&ti->timer, jiffies + interval);
}

static void ct_systimer_init(struct ct_timer_instance *ti)
{
	timer_setup(&ti->timer, ct_systimer_callback, 0);
}

static void ct_systimer_start(struct ct_timer_instance *ti)
{
	struct snd_pcm_runtime *runtime = ti->substream->runtime;

	guard(spinlock_irqsave)(&ti->lock);
	ti->running = 1;
	mod_timer(&ti->timer,
		  jiffies + (runtime->period_size * HZ +
			     (runtime->rate - 1)) / runtime->rate);
}

static void ct_systimer_stop(struct ct_timer_instance *ti)
{
	guard(spinlock_irqsave)(&ti->lock);
	ti->running = 0;

Annotation

Implementation Notes