Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d807500a authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/pcm-cleanup' into for-linus

parents c7ccfd06 8b22d943
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -364,7 +364,6 @@ struct snd_pcm_substream {
        /* -- timer section -- */
	struct snd_timer *timer;		/* timer */
	unsigned timer_running: 1;	/* time is running */
	spinlock_t timer_lock;
	/* -- next substream -- */
	struct snd_pcm_substream *next;
	/* -- linked substreams -- */
+0 −1
Original line number Diff line number Diff line
@@ -667,7 +667,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
		spin_lock_init(&substream->self_group.lock);
		INIT_LIST_HEAD(&substream->self_group.substreams);
		list_add_tail(&substream->link_list, &substream->self_group.substreams);
		spin_lock_init(&substream->timer_lock);
		atomic_set(&substream->mmap_count, 0);
		prev = substream;
	}
+102 −53
Original line number Diff line number Diff line
@@ -125,22 +125,31 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
	}
}

#ifdef CONFIG_SND_PCM_XRUN_DEBUG
#define xrun_debug(substream)	((substream)->pstr->xrun_debug)
#else
#define xrun_debug(substream)	0
#endif

#define dump_stack_on_xrun(substream) do {	\
		if (xrun_debug(substream) > 1)	\
			dump_stack();		\
	} while (0)

static void xrun(struct snd_pcm_substream *substream)
{
	snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
	if (substream->pstr->xrun_debug) {
	if (xrun_debug(substream)) {
		snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
			   substream->pcm->card->number,
			   substream->pcm->device,
			   substream->stream ? 'c' : 'p');
		if (substream->pstr->xrun_debug > 1)
			dump_stack();
		dump_stack_on_xrun(substream);
	}
#endif
}

static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
static snd_pcm_uframes_t
snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
			  struct snd_pcm_runtime *runtime)
{
	snd_pcm_uframes_t pos;
@@ -150,16 +159,20 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substre
	pos = substream->ops->pointer(substream);
	if (pos == SNDRV_PCM_POS_XRUN)
		return pos; /* XRUN */
#ifdef CONFIG_SND_DEBUG
	if (pos >= runtime->buffer_size) {
		snd_printk(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
		if (printk_ratelimit()) {
			snd_printd(KERN_ERR  "BUG: stream = %i, pos = 0x%lx, "
				   "buffer size = 0x%lx, period size = 0x%lx\n",
				   substream->stream, pos, runtime->buffer_size,
				   runtime->period_size);
		}
		pos = 0;
	}
#endif
	pos -= pos % runtime->min_align;
	return pos;
}

static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
				      struct snd_pcm_runtime *runtime)
{
	snd_pcm_uframes_t avail;
@@ -182,11 +195,21 @@ static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream
	return 0;
}

static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
#define hw_ptr_error(substream, fmt, args...)				\
	do {								\
		if (xrun_debug(substream)) {				\
			if (printk_ratelimit()) {			\
				snd_printd("PCM: " fmt, ##args);	\
			}						\
			dump_stack_on_xrun(substream);			\
		}							\
	} while (0)

static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_pcm_uframes_t pos;
	snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt;
	snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base;
	snd_pcm_sframes_t delta;

	pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
@@ -194,36 +217,53 @@ static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *subs
		xrun(substream);
		return -EPIPE;
	}
	if (runtime->period_size == runtime->buffer_size)
		goto __next_buf;
	new_hw_ptr = runtime->hw_ptr_base + pos;
	hw_base = runtime->hw_ptr_base;
	new_hw_ptr = hw_base + pos;
	hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;

	delta = hw_ptr_interrupt - new_hw_ptr;
	if (delta > 0) {
		if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
			if (runtime->periods > 1 && substream->pstr->xrun_debug) {
				snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
				if (substream->pstr->xrun_debug > 1)
					dump_stack();
			}
#endif
			return 0;
		}
	      __next_buf:
		runtime->hw_ptr_base += runtime->buffer_size;
		if (runtime->hw_ptr_base == runtime->boundary)
			runtime->hw_ptr_base = 0;
		new_hw_ptr = runtime->hw_ptr_base + pos;
	delta = new_hw_ptr - hw_ptr_interrupt;
	if (hw_ptr_interrupt >= runtime->boundary) {
		hw_ptr_interrupt -= runtime->boundary;
		if (hw_base < runtime->boundary / 2)
			/* hw_base was already lapped; recalc delta */
			delta = new_hw_ptr - hw_ptr_interrupt;
	}
	if (delta < 0) {
		delta += runtime->buffer_size;
		if (delta < 0) {
			hw_ptr_error(substream, 
				     "Unexpected hw_pointer value "
				     "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
				     substream->stream, (long)pos,
				     (long)hw_ptr_interrupt);
			/* rebase to interrupt position */
			hw_base = new_hw_ptr = hw_ptr_interrupt;
			/* align hw_base to buffer_size */
			hw_base -= hw_base % runtime->buffer_size;
			delta = 0;
		} else {
			hw_base += runtime->buffer_size;
			if (hw_base >= runtime->boundary)
				hw_base = 0;
			new_hw_ptr = hw_base + pos;
		}
	}
	if (delta > runtime->period_size) {
		hw_ptr_error(substream,
			     "Lost interrupts? "
			     "(stream=%i, delta=%ld, intr_ptr=%ld)\n",
			     substream->stream, (long)delta,
			     (long)hw_ptr_interrupt);
		/* rebase hw_ptr_interrupt */
		hw_ptr_interrupt =
			new_hw_ptr - new_hw_ptr % runtime->period_size;
	}

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    runtime->silence_size > 0)
		snd_pcm_playback_silence(substream, new_hw_ptr);

	runtime->hw_ptr_base = hw_base;
	runtime->status->hw_ptr = new_hw_ptr;
	runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size;
	runtime->hw_ptr_interrupt = hw_ptr_interrupt;

	return snd_pcm_update_hw_ptr_post(substream, runtime);
}
@@ -233,7 +273,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	snd_pcm_uframes_t pos;
	snd_pcm_uframes_t old_hw_ptr, new_hw_ptr;
	snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
	snd_pcm_sframes_t delta;

	old_hw_ptr = runtime->status->hw_ptr;
@@ -242,29 +282,38 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
		xrun(substream);
		return -EPIPE;
	}
	new_hw_ptr = runtime->hw_ptr_base + pos;

	delta = old_hw_ptr - new_hw_ptr;
	if (delta > 0) {
		if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
			if (runtime->periods > 2 && substream->pstr->xrun_debug) {
				snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
				if (substream->pstr->xrun_debug > 1)
					dump_stack();
			}
#endif
	hw_base = runtime->hw_ptr_base;
	new_hw_ptr = hw_base + pos;

	delta = new_hw_ptr - old_hw_ptr;
	if (delta < 0) {
		delta += runtime->buffer_size;
		if (delta < 0) {
			hw_ptr_error(substream, 
				     "Unexpected hw_pointer value [2] "
				     "(stream=%i, pos=%ld, old_ptr=%ld)\n",
				     substream->stream, (long)pos,
				     (long)old_hw_ptr);
			return 0;
		}
		runtime->hw_ptr_base += runtime->buffer_size;
		if (runtime->hw_ptr_base == runtime->boundary)
			runtime->hw_ptr_base = 0;
		new_hw_ptr = runtime->hw_ptr_base + pos;
		hw_base += runtime->buffer_size;
		if (hw_base >= runtime->boundary)
			hw_base = 0;
		new_hw_ptr = hw_base + pos;
	}
	if (delta > runtime->period_size && runtime->periods > 1) {
		hw_ptr_error(substream,
			     "hw_ptr skipping! "
			     "(pos=%ld, delta=%ld, period=%ld)\n",
			     (long)pos, (long)delta,
			     (long)runtime->period_size);
		return 0;
	}
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    runtime->silence_size > 0)
		snd_pcm_playback_silence(substream, new_hw_ptr);

	runtime->hw_ptr_base = hw_base;
	runtime->status->hw_ptr = new_hw_ptr;

	return snd_pcm_update_hw_ptr_post(substream, runtime);
+0 −6
Original line number Diff line number Diff line
@@ -85,25 +85,19 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)

static int snd_pcm_timer_start(struct snd_timer * timer)
{
	unsigned long flags;
	struct snd_pcm_substream *substream;
	
	substream = snd_timer_chip(timer);
	spin_lock_irqsave(&substream->timer_lock, flags);
	substream->timer_running = 1;
	spin_unlock_irqrestore(&substream->timer_lock, flags);
	return 0;
}

static int snd_pcm_timer_stop(struct snd_timer * timer)
{
	unsigned long flags;
	struct snd_pcm_substream *substream;
	
	substream = snd_timer_chip(timer);
	spin_lock_irqsave(&substream->timer_lock, flags);
	substream->timer_running = 0;
	spin_unlock_irqrestore(&substream->timer_lock, flags);
	return 0;
}