ALSA: pcm: Refactoring snd_pcm_action()
[cascardo/linux.git] / sound / core / pcm_native.c
index 03e1e92..ca224fa 100644 (file)
@@ -74,6 +74,14 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
 static DEFINE_RWLOCK(snd_pcm_link_rwlock);
 static DECLARE_RWSEM(snd_pcm_link_rwsem);
 
+/**
+ * snd_pcm_stream_lock - Lock the PCM stream
+ * @substream: PCM substream
+ *
+ * This locks the PCM stream's spinlock or mutex depending on the nonatomic
+ * flag of the given substream.  This also takes the global link rw lock
+ * (or rw sem), too, for avoiding the race with linked streams.
+ */
 void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
 {
        if (substream->pcm->nonatomic) {
@@ -86,6 +94,12 @@ void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);
 
+/**
+ * snd_pcm_stream_lock - Unlock the PCM stream
+ * @substream: PCM substream
+ *
+ * This unlocks the PCM stream that has been locked via snd_pcm_stream_lock().
+ */
 void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
 {
        if (substream->pcm->nonatomic) {
@@ -98,6 +112,14 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
 
+/**
+ * snd_pcm_stream_lock_irq - Lock the PCM stream
+ * @substream: PCM substream
+ *
+ * This locks the PCM stream like snd_pcm_stream_lock() and disables the local
+ * IRQ (only when nonatomic is false).  In nonatomic case, this is identical
+ * as snd_pcm_stream_lock().
+ */
 void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
 {
        if (!substream->pcm->nonatomic)
@@ -106,6 +128,12 @@ void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
 
+/**
+ * snd_pcm_stream_unlock_irq - Unlock the PCM stream
+ * @substream: PCM substream
+ *
+ * This is a counter-part of snd_pcm_stream_lock_irq().
+ */
 void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
 {
        snd_pcm_stream_unlock(substream);
@@ -124,6 +152,13 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
 }
 EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
 
+/**
+ * snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream
+ * @substream: PCM substream
+ * @flags: irq flags
+ *
+ * This is a counter-part of snd_pcm_stream_lock_irqsave().
+ */
 void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
                                      unsigned long flags)
 {
@@ -797,16 +832,15 @@ static int snd_pcm_action_group(struct action_ops *ops,
 {
        struct snd_pcm_substream *s = NULL;
        struct snd_pcm_substream *s1;
-       int res = 0;
+       int res = 0, depth = 1;
 
        snd_pcm_group_for_each_entry(s, substream) {
                if (do_lock && s != substream) {
                        if (s->pcm->nonatomic)
-                               mutex_lock_nested(&s->self_group.mutex,
-                                                 SINGLE_DEPTH_NESTING);
+                               mutex_lock_nested(&s->self_group.mutex, depth);
                        else
-                               spin_lock_nested(&s->self_group.lock,
-                                                SINGLE_DEPTH_NESTING);
+                               spin_lock_nested(&s->self_group.lock, depth);
+                       depth++;
                }
                res = ops->pre_action(s, state);
                if (res < 0)
@@ -866,14 +900,19 @@ static int snd_pcm_action_single(struct action_ops *ops,
        return res;
 }
 
-/* call in mutex-protected context */
-static int snd_pcm_action_mutex(struct action_ops *ops,
-                               struct snd_pcm_substream *substream,
-                               int state)
+/*
+ *  Note: call with stream lock
+ */
+static int snd_pcm_action(struct action_ops *ops,
+                         struct snd_pcm_substream *substream,
+                         int state)
 {
        int res;
 
-       if (snd_pcm_stream_linked(substream)) {
+       if (!snd_pcm_stream_linked(substream))
+               return snd_pcm_action_single(ops, substream, state);
+
+       if (substream->pcm->nonatomic) {
                if (!mutex_trylock(&substream->group->mutex)) {
                        mutex_unlock(&substream->self_group.mutex);
                        mutex_lock(&substream->group->mutex);
@@ -882,24 +921,6 @@ static int snd_pcm_action_mutex(struct action_ops *ops,
                res = snd_pcm_action_group(ops, substream, state, 1);
                mutex_unlock(&substream->group->mutex);
        } else {
-               res = snd_pcm_action_single(ops, substream, state);
-       }
-       return res;
-}
-
-/*
- *  Note: call with stream lock
- */
-static int snd_pcm_action(struct action_ops *ops,
-                         struct snd_pcm_substream *substream,
-                         int state)
-{
-       int res;
-
-       if (substream->pcm->nonatomic)
-               return snd_pcm_action_mutex(ops, substream, state);
-
-       if (snd_pcm_stream_linked(substream)) {
                if (!spin_trylock(&substream->group->lock)) {
                        spin_unlock(&substream->self_group.lock);
                        spin_lock(&substream->group->lock);
@@ -907,35 +928,10 @@ static int snd_pcm_action(struct action_ops *ops,
                }
                res = snd_pcm_action_group(ops, substream, state, 1);
                spin_unlock(&substream->group->lock);
-       } else {
-               res = snd_pcm_action_single(ops, substream, state);
        }
        return res;
 }
 
-static int snd_pcm_action_lock_mutex(struct action_ops *ops,
-                                    struct snd_pcm_substream *substream,
-                                    int state)
-{
-       int res;
-
-       down_read(&snd_pcm_link_rwsem);
-       if (snd_pcm_stream_linked(substream)) {
-               mutex_lock(&substream->group->mutex);
-               mutex_lock_nested(&substream->self_group.mutex,
-                                 SINGLE_DEPTH_NESTING);
-               res = snd_pcm_action_group(ops, substream, state, 1);
-               mutex_unlock(&substream->self_group.mutex);
-               mutex_unlock(&substream->group->mutex);
-       } else {
-               mutex_lock(&substream->self_group.mutex);
-               res = snd_pcm_action_single(ops, substream, state);
-               mutex_unlock(&substream->self_group.mutex);
-       }
-       up_read(&snd_pcm_link_rwsem);
-       return res;
-}
-
 /*
  *  Note: don't use any locks before
  */
@@ -945,22 +941,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
 {
        int res;
 
-       if (substream->pcm->nonatomic)
-               return snd_pcm_action_lock_mutex(ops, substream, state);
-
-       read_lock_irq(&snd_pcm_link_rwlock);
-       if (snd_pcm_stream_linked(substream)) {
-               spin_lock(&substream->group->lock);
-               spin_lock(&substream->self_group.lock);
-               res = snd_pcm_action_group(ops, substream, state, 1);
-               spin_unlock(&substream->self_group.lock);
-               spin_unlock(&substream->group->lock);
-       } else {
-               spin_lock(&substream->self_group.lock);
-               res = snd_pcm_action_single(ops, substream, state);
-               spin_unlock(&substream->self_group.lock);
-       }
-       read_unlock_irq(&snd_pcm_link_rwlock);
+       snd_pcm_stream_lock_irq(substream);
+       res = snd_pcm_action(ops, substream, state);
+       snd_pcm_stream_unlock_irq(substream);
        return res;
 }
 
@@ -3314,6 +3297,15 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
 /*
  * mmap the DMA buffer on RAM
  */
+
+/**
+ * snd_pcm_lib_default_mmap - Default PCM data mmap function
+ * @substream: PCM substream
+ * @area: VMA
+ *
+ * This is the default mmap handler for PCM data.  When mmap pcm_ops is NULL,
+ * this function is invoked implicitly.
+ */
 int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
                             struct vm_area_struct *area)
 {
@@ -3345,6 +3337,15 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
  * mmap the DMA buffer on I/O memory area
  */
 #if SNDRV_PCM_INFO_MMAP_IOMEM
+/**
+ * snd_pcm_lib_mmap_iomem - Default PCM data mmap function for I/O mem
+ * @substream: PCM substream
+ * @area: VMA
+ *
+ * When your hardware uses the iomapped pages as the hardware buffer and
+ * wants to mmap it, pass this function as mmap pcm_ops.  Note that this
+ * is supposed to work only on limited architectures.
+ */
 int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
                           struct vm_area_struct *area)
 {