Skip to content

Commit

Permalink
ALSA: pcm_lib - cleanup & merge hw_ptr update functions
Browse files Browse the repository at this point in the history
Do general cleanup in snd_pcm_update_hw_ptr*() routines and merge them.
The main change is hw_ptr_interrupt variable removal to simplify code
logic. This variable can be computed directly from hw_ptr.

Ensure that updated hw_ptr is not lower than previous one (it was possible
with old code in some obscure situations when interrupt was delayed or
the lowlevel driver returns wrong ring buffer position value).

Signed-off-by: Jaroslav Kysela <[email protected]>
  • Loading branch information
perexg committed Jan 7, 2010
1 parent 4d96eb2 commit f240406
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 195 deletions.
1 change: 0 additions & 1 deletion include/sound/pcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ struct snd_pcm_runtime {
int overrange;
snd_pcm_uframes_t avail_max;
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */
snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */

Expand Down
2 changes: 1 addition & 1 deletion include/sound/pcm_oss.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ struct snd_pcm_oss_runtime {
struct snd_pcm_plugin *plugin_first;
struct snd_pcm_plugin *plugin_last;
#endif
unsigned int prev_hw_ptr_interrupt;
unsigned int prev_hw_ptr_period;
};

struct snd_pcm_oss_file {
Expand Down
32 changes: 23 additions & 9 deletions sound/core/oss/pcm_oss.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,13 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
}

static inline
snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t ptr = runtime->status->hw_ptr;
return ptr - (ptr % runtime->period_size);
}

/* define extended formats in the recent OSS versions (if any) */
/* linear formats */
#define AFMT_S32_LE 0x00001000
Expand Down Expand Up @@ -1102,7 +1109,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
return err;
}
runtime->oss.prepare = 0;
runtime->oss.prev_hw_ptr_interrupt = 0;
runtime->oss.prev_hw_ptr_period = 0;
runtime->oss.period_ptr = 0;
runtime->oss.buffer_used = 0;

Expand Down Expand Up @@ -1950,7 +1957,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
return result;
}

static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr)
static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream,
snd_pcm_uframes_t hw_ptr)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t appl_ptr;
Expand Down Expand Up @@ -1986,7 +1994,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
if (runtime->oss.trigger)
goto _skip1;
if (atomic_read(&psubstream->mmap_count))
snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
snd_pcm_oss_simulate_fill(psubstream,
get_hw_ptr_period(runtime));
runtime->oss.trigger = 1;
runtime->start_threshold = 1;
cmd = SNDRV_PCM_IOCTL_START;
Expand Down Expand Up @@ -2105,11 +2114,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
if (atomic_read(&substream->mmap_count)) {
snd_pcm_sframes_t n;
n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
delay = get_hw_ptr_period(runtime);
n = delay - runtime->oss.prev_hw_ptr_period;
if (n < 0)
n += runtime->boundary;
info.blocks = n / runtime->period_size;
runtime->oss.prev_hw_ptr_interrupt = delay;
runtime->oss.prev_hw_ptr_period = delay;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_pcm_oss_simulate_fill(substream, delay);
info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
Expand Down Expand Up @@ -2673,18 +2683,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
return runtime->oss.prev_hw_ptr_period !=
get_hw_ptr_period(runtime);
else
return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
return snd_pcm_playback_avail(runtime) >=
runtime->oss.period_frames;
}

static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
return runtime->oss.prev_hw_ptr_period !=
get_hw_ptr_period(runtime);
else
return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
return snd_pcm_capture_avail(runtime) >=
runtime->oss.period_frames;
}

static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
Expand Down
Loading

0 comments on commit f240406

Please sign in to comment.