]> git.karo-electronics.de Git - linux-beck.git/blobdiff - sound/core/pcm_native.c
Merge branch 'fix/misc' into topic/misc
[linux-beck.git] / sound / core / pcm_native.c
index 27284f6283619e67271a0cb7772b24917dbd7a34..87288762403055a3f6f842c70b9e99794956a1cd 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pm_qos_params.h>
 #include <linux/uio.h>
 #include <linux/dma-mapping.h>
+#include <linux/math64.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -315,10 +316,10 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
        if (!params->info)
                params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
        if (!params->fifo_size) {
-               if (snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) ==
-                   snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT]) &&
-                    snd_mask_min(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS]) ==
-                    snd_mask_max(&params->masks[SNDRV_PCM_HW_PARAM_CHANNELS])) {
+               m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+               i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+               if (snd_mask_min(m) == snd_mask_max(m) &&
+                    snd_interval_min(i) == snd_interval_max(i)) {
                        changed = substream->ops->ioctl(substream,
                                        SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
                        if (changed < 0)
@@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
        return usecs;
 }
 
+static int calc_boundary(struct snd_pcm_runtime *runtime)
+{
+       u_int64_t boundary;
+
+       boundary = (u_int64_t)runtime->buffer_size *
+                  (u_int64_t)runtime->period_size;
+#if BITS_PER_LONG < 64
+       /* try to find lowest common multiple for buffer and period */
+       if (boundary > LONG_MAX - runtime->buffer_size) {
+               u_int32_t remainder = -1;
+               u_int32_t divident = runtime->buffer_size;
+               u_int32_t divisor = runtime->period_size;
+               while (remainder) {
+                       remainder = divident % divisor;
+                       if (remainder) {
+                               divident = divisor;
+                               divisor = remainder;
+                       }
+               }
+               boundary = div_u64(boundary, divisor);
+               if (boundary > LONG_MAX - runtime->buffer_size)
+                       return -ERANGE;
+       }
+#endif
+       if (boundary == 0)
+               return -ERANGE;
+       runtime->boundary = boundary;
+       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
+               runtime->boundary *= 2;
+       return 0;
+}
+
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        runtime->stop_threshold = runtime->buffer_size;
        runtime->silence_threshold = 0;
        runtime->silence_size = 0;
-       runtime->boundary = runtime->buffer_size;
-       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
-               runtime->boundary *= 2;
+       err = calc_boundary(runtime);
+       if (err < 0)
+               goto _error;
 
        snd_pcm_timer_resolution_change(substream);
        runtime->status->state = SNDRV_PCM_STATE_SETUP;
@@ -919,6 +952,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
                runtime->status->state = state;
        }
        wake_up(&runtime->sleep);
+       wake_up(&runtime->tsleep);
 }
 
 static struct action_ops snd_pcm_action_stop = {
@@ -1004,6 +1038,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
                                         SNDRV_TIMER_EVENT_MPAUSE,
                                         &runtime->trigger_tstamp);
                wake_up(&runtime->sleep);
+               wake_up(&runtime->tsleep);
        } else {
                runtime->status->state = SNDRV_PCM_STATE_RUNNING;
                if (substream->timer)
@@ -1061,6 +1096,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
        runtime->status->suspended_state = runtime->status->state;
        runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
        wake_up(&runtime->sleep);
+       wake_up(&runtime->tsleep);
 }
 
 static struct action_ops snd_pcm_action_suspend = {
@@ -1249,6 +1285,8 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state)
        if (err < 0)
                return err;
        runtime->hw_ptr_base = 0;
+       runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
+               runtime->status->hw_ptr % runtime->period_size;
        runtime->silence_start = runtime->status->hw_ptr;
        runtime->silence_filled = 0;
        return 0;
@@ -1918,13 +1956,13 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
 
        err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
                                           hw->rate_min, hw->rate_max);
-        if (err < 0)
-                return err;
+       if (err < 0)
+               return err;
 
        err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
                                           hw->period_bytes_min, hw->period_bytes_max);
-        if (err < 0)
-                return err;
+       if (err < 0)
+               return err;
 
        err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,
                                           hw->periods_min, hw->periods_max);
@@ -3162,9 +3200,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
        long size;
        unsigned long offset;
 
-#ifdef pgprot_noncached
        area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
-#endif
        area->vm_flags |= VM_IO;
        size = area->vm_end - area->vm_start;
        offset = area->vm_pgoff << PAGE_SHIFT;
@@ -3178,6 +3214,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
 EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
 #endif /* SNDRV_PCM_INFO_MMAP */
 
+/* mmap callback with pgprot_noncached */
+int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream,
+                              struct vm_area_struct *area)
+{
+       area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
+       return snd_pcm_default_mmap(substream, area);
+}
+EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached);
+
 /*
  * mmap DMA buffer
  */