]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - sound/core/pcm_lib.c
ALSA: pcm: Check PCM state by a common helper function
[karo-tx-linux.git] / sound / core / pcm_lib.c
index 5088d4b8db2222e28a71baaa4db7c70a30997e48..5fcd798672b49207bea1332a15c42067103889a9 100644 (file)
@@ -33,6 +33,8 @@
 #include <sound/pcm_params.h>
 #include <sound/timer.h>
 
+#include "pcm_local.h"
+
 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
 #define CREATE_TRACE_POINTS
 #include "pcm_trace.h"
@@ -55,6 +57,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t frames, ofs, transfer;
+       char *hwbuf;
+       int err;
 
        if (runtime->silence_size < runtime->boundary) {
                snd_pcm_sframes_t noise_dist, n;
@@ -109,27 +113,29 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
                transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
                if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
                    runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
-                       if (substream->ops->silence) {
-                               int err;
-                               err = substream->ops->silence(substream, -1, ofs, transfer);
+                       if (substream->ops->fill_silence) {
+                               err = substream->ops->fill_silence(substream, 0,
+                                                                  frames_to_bytes(runtime, ofs),
+                                                                  frames_to_bytes(runtime, transfer));
                                snd_BUG_ON(err < 0);
                        } else {
-                               char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
+                               hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
                                snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
                        }
                } else {
                        unsigned int c;
                        unsigned int channels = runtime->channels;
-                       if (substream->ops->silence) {
+                       if (substream->ops->fill_silence) {
                                for (c = 0; c < channels; ++c) {
-                                       int err;
-                                       err = substream->ops->silence(substream, c, ofs, transfer);
+                                       err = substream->ops->fill_silence(substream, c,
+                                                                          samples_to_bytes(runtime, ofs),
+                                                                          samples_to_bytes(runtime, transfer));
                                        snd_BUG_ON(err < 0);
                                }
                        } else {
                                size_t dma_csize = runtime->dma_bytes / channels;
                                for (c = 0; c < channels; ++c) {
-                                       char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs);
+                                       hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs);
                                        snd_pcm_format_set_silence(runtime->format, hwbuf, transfer);
                                }
                        }
@@ -1415,7 +1421,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
        unsigned int l = (unsigned long) rule->private;
        int width = l & 0xffff;
        unsigned int msbits = l >> 16;
-       struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+       const struct snd_interval *i =
+               hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
 
        if (!snd_interval_single(i))
                return 0;
@@ -1733,7 +1740,7 @@ EXPORT_SYMBOL(snd_pcm_hw_param_last);
 int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
                             struct snd_pcm_hw_params *params)
 {
-       static int vars[] = {
+       static const int vars[] = {
                SNDRV_PCM_HW_PARAM_ACCESS,
                SNDRV_PCM_HW_PARAM_FORMAT,
                SNDRV_PCM_HW_PARAM_SUBFORMAT,
@@ -1744,7 +1751,8 @@ int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
                SNDRV_PCM_HW_PARAM_TICK_TIME,
                -1
        };
-       int err, *v;
+       const int *v;
+       int err;
 
        for (v = vars; *v != -1; v++) {
                if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
@@ -1993,8 +2001,11 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
        char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
-       if (substream->ops->copy) {
-               if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
+       if (substream->ops->copy_user) {
+               hwoff = frames_to_bytes(runtime, hwoff);
+               frames = frames_to_bytes(runtime, frames);
+               err = substream->ops->copy_user(substream, 0, hwoff, buf, frames);
+               if (err < 0)
                        return err;
        } else {
                char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
@@ -2008,6 +2019,22 @@ typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwof
                          unsigned long data, unsigned int off,
                          snd_pcm_uframes_t size);
 
+static int pcm_accessible_state(struct snd_pcm_runtime *runtime)
+{
+       switch (runtime->status->state) {
+       case SNDRV_PCM_STATE_PREPARED:
+       case SNDRV_PCM_STATE_RUNNING:
+       case SNDRV_PCM_STATE_PAUSED:
+               return 0;
+       case SNDRV_PCM_STATE_XRUN:
+               return -EPIPE;
+       case SNDRV_PCM_STATE_SUSPENDED:
+               return -ESTRPIPE;
+       default:
+               return -EBADFD;
+       }
+}
+
 static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, 
                                            unsigned long data,
                                            snd_pcm_uframes_t size,
@@ -2024,21 +2051,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                return 0;
 
        snd_pcm_stream_lock_irq(substream);
-       switch (runtime->status->state) {
-       case SNDRV_PCM_STATE_PREPARED:
-       case SNDRV_PCM_STATE_RUNNING:
-       case SNDRV_PCM_STATE_PAUSED:
-               break;
-       case SNDRV_PCM_STATE_XRUN:
-               err = -EPIPE;
-               goto _end_unlock;
-       case SNDRV_PCM_STATE_SUSPENDED:
-               err = -ESTRPIPE;
-               goto _end_unlock;
-       default:
-               err = -EBADFD;
+       err = pcm_accessible_state(runtime);
+       if (err < 0)
                goto _end_unlock;
-       }
 
        runtime->twake = runtime->control->avail_min ? : 1;
        if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
@@ -2074,16 +2089,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
                snd_pcm_stream_lock_irq(substream);
                if (err < 0)
                        goto _end_unlock;
-               switch (runtime->status->state) {
-               case SNDRV_PCM_STATE_XRUN:
-                       err = -EPIPE;
-                       goto _end_unlock;
-               case SNDRV_PCM_STATE_SUSPENDED:
-                       err = -ESTRPIPE;
+               err = pcm_accessible_state(runtime);
+               if (err < 0)
                        goto _end_unlock;
-               default:
-                       break;
-               }
                appl_ptr += frames;
                if (appl_ptr >= runtime->boundary)
                        appl_ptr -= runtime->boundary;
@@ -2117,7 +2125,7 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream)
        if (PCM_RUNTIME_CHECK(substream))
                return -ENXIO;
        runtime = substream->runtime;
-       if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
+       if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area))
                return -EINVAL;
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
                return -EBADFD;
@@ -2154,19 +2162,28 @@ static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
        int err;
        void __user **bufs = (void __user **)data;
        int channels = runtime->channels;
+       char __user *buf;
        int c;
-       if (substream->ops->copy) {
-               if (snd_BUG_ON(!substream->ops->silence))
-                       return -EINVAL;
+
+       if (substream->ops->copy_user) {
+               hwoff = samples_to_bytes(runtime, hwoff);
+               off = samples_to_bytes(runtime, off);
+               frames = samples_to_bytes(runtime, frames);
                for (c = 0; c < channels; ++c, ++bufs) {
-                       if (*bufs == NULL) {
-                               if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
-                                       return err;
+                       buf = *bufs + off;
+                       if (!*bufs) {
+                               if (snd_BUG_ON(!substream->ops->fill_silence))
+                                       return -EINVAL;
+                               err = substream->ops->fill_silence(substream, c,
+                                                                  hwoff,
+                                                                  frames);
                        } else {
-                               char __user *buf = *bufs + samples_to_bytes(runtime, off);
-                               if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
-                                       return err;
+                               err = substream->ops->copy_user(substream, c,
+                                                               hwoff, buf,
+                                                               frames);
                        }
+                       if (err < 0)
+                               return err;
                }
        } else {
                /* default transfer behaviour */
@@ -2215,8 +2232,11 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        int err;
        char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
-       if (substream->ops->copy) {
-               if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
+       if (substream->ops->copy_user) {
+               hwoff = frames_to_bytes(runtime, hwoff);
+               frames = frames_to_bytes(runtime, frames);
+               err = substream->ops->copy_user(substream, 0, hwoff, buf, frames);
+               if (err < 0)
                        return err;
        } else {
                char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
@@ -2242,27 +2262,14 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                return 0;
 
        snd_pcm_stream_lock_irq(substream);
-       switch (runtime->status->state) {
-       case SNDRV_PCM_STATE_PREPARED:
-               if (size >= runtime->start_threshold) {
-                       err = snd_pcm_start(substream);
-                       if (err < 0)
-                               goto _end_unlock;
-               }
-               break;
-       case SNDRV_PCM_STATE_DRAINING:
-       case SNDRV_PCM_STATE_RUNNING:
-       case SNDRV_PCM_STATE_PAUSED:
-               break;
-       case SNDRV_PCM_STATE_XRUN:
-               err = -EPIPE;
-               goto _end_unlock;
-       case SNDRV_PCM_STATE_SUSPENDED:
-               err = -ESTRPIPE;
-               goto _end_unlock;
-       default:
-               err = -EBADFD;
+       err = pcm_accessible_state(runtime);
+       if (err < 0)
                goto _end_unlock;
+       if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
+           size >= runtime->start_threshold) {
+               err = snd_pcm_start(substream);
+               if (err < 0)
+                       goto _end_unlock;
        }
 
        runtime->twake = runtime->control->avail_min ? : 1;
@@ -2306,16 +2313,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
                snd_pcm_stream_lock_irq(substream);
                if (err < 0)
                        goto _end_unlock;
-               switch (runtime->status->state) {
-               case SNDRV_PCM_STATE_XRUN:
-                       err = -EPIPE;
-                       goto _end_unlock;
-               case SNDRV_PCM_STATE_SUSPENDED:
-                       err = -ESTRPIPE;
+               err = pcm_accessible_state(runtime);
+               if (err < 0)
                        goto _end_unlock;
-               default:
-                       break;
-               }
                appl_ptr += frames;
                if (appl_ptr >= runtime->boundary)
                        appl_ptr -= runtime->boundary;
@@ -2363,21 +2363,25 @@ static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
        int err;
        void __user **bufs = (void __user **)data;
        int channels = runtime->channels;
+       char __user *buf;
+       char *hwbuf;
        int c;
-       if (substream->ops->copy) {
+
+       if (substream->ops->copy_user) {
+               hwoff = samples_to_bytes(runtime, hwoff);
+               off = samples_to_bytes(runtime, off);
+               frames = samples_to_bytes(runtime, frames);
                for (c = 0; c < channels; ++c, ++bufs) {
-                       char __user *buf;
-                       if (*bufs == NULL)
+                       if (!*bufs)
                                continue;
-                       buf = *bufs + samples_to_bytes(runtime, off);
-                       if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
+                       err = substream->ops->copy_user(substream, c, hwoff,
+                                                       *bufs + off, frames);
+                       if (err < 0)
                                return err;
                }
        } else {
                snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
                for (c = 0; c < channels; ++c, ++bufs) {
-                       char *hwbuf;
-                       char __user *buf;
                        if (*bufs == NULL)
                                continue;