dmaengine/dma_slave: introduce inline wrappers
[linux-2.6.git] / sound / core / pcm_native.c
index 1793574..1c6be91 100644 (file)
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/time.h>
 #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>
@@ -36,6 +34,9 @@
 #include <sound/timer.h>
 #include <sound/minors.h>
 #include <asm/io.h>
+#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+#include <dma-coherence.h>
+#endif
 
 /*
  *  Compatibility
@@ -140,7 +141,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
 
 #ifdef RULES_DEBUG
 #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
-char *snd_pcm_hw_param_names[] = {
+static const char * const snd_pcm_hw_param_names[] = {
        HW_PARAM(ACCESS),
        HW_PARAM(FORMAT),
        HW_PARAM(SUBFORMAT),
@@ -316,10 +317,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)
@@ -367,38 +368,6 @@ 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)
 {
@@ -453,6 +422,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        runtime->info = params->info;
        runtime->rate_num = params->rate_num;
        runtime->rate_den = params->rate_den;
+       runtime->no_period_wakeup =
+                       (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+                       (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
 
        bits = snd_pcm_format_physical_width(runtime->format);
        runtime->sample_bits = bits;
@@ -474,21 +446,21 @@ 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;
-       err = calc_boundary(runtime);
-       if (err < 0)
-               goto _error;
+       runtime->boundary = runtime->buffer_size;
+       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
+               runtime->boundary *= 2;
 
        snd_pcm_timer_resolution_change(substream);
        runtime->status->state = SNDRV_PCM_STATE_SETUP;
 
-       pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
-                               substream->latency_id);
+       if (pm_qos_request_active(&substream->latency_pm_qos_req))
+               pm_qos_remove_request(&substream->latency_pm_qos_req);
        if ((usecs = period_to_usecs(runtime)) >= 0)
-               pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY,
-                                       substream->latency_id, usecs);
+               pm_qos_add_request(&substream->latency_pm_qos_req,
+                                  PM_QOS_CPU_DMA_LATENCY, usecs);
        return 0;
  _error:
-       /* hardware might be unuseable from this time,
+       /* hardware might be unusable from this time,
           so we force application to retry to set
           the correct hardware parameter settings */
        runtime->status->state = SNDRV_PCM_STATE_OPEN;
@@ -540,8 +512,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
        if (substream->ops->hw_free)
                result = substream->ops->hw_free(substream);
        runtime->status->state = SNDRV_PCM_STATE_OPEN;
-       pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
-               substream->latency_id);
+       pm_qos_remove_request(&substream->latency_pm_qos_req);
        return result;
 }
 
@@ -895,6 +866,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        runtime->hw_ptr_jiffies = jiffies;
+       runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / 
+                                                           runtime->rate;
        runtime->status->state = state;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
@@ -968,7 +941,7 @@ static struct action_ops snd_pcm_action_stop = {
  *
  * The state of each stream is then changed to the given state unconditionally.
  */
-int snd_pcm_stop(struct snd_pcm_substream *substream, int state)
+int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
 {
        return snd_pcm_action(&snd_pcm_action_stop, substream, state);
 }
@@ -1009,8 +982,12 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push)
 {
        if (substream->runtime->trigger_master != substream)
                return 0;
+       /* some drivers might use hw_ptr to recover from the pause -
+          update the hw_ptr now */
+       if (push)
+               snd_pcm_update_hw_ptr(substream);
        /* The jiffies check in snd_pcm_update_hw_ptr*() is done by
-        * a delta betwen the current jiffies, this gives a large enough
+        * a delta between the current jiffies, this gives a large enough
         * delta, effectively to skip the check once.
         */
        substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000;
@@ -1504,11 +1481,20 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
                        break; /* all drained */
                init_waitqueue_entry(&wait, current);
                add_wait_queue(&to_check->sleep, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
                snd_pcm_stream_unlock_irq(substream);
                up_read(&snd_pcm_link_rwsem);
                snd_power_unlock(card);
-               tout = schedule_timeout(10 * HZ);
+               if (runtime->no_period_wakeup)
+                       tout = MAX_SCHEDULE_TIMEOUT;
+               else {
+                       tout = 10;
+                       if (runtime->rate) {
+                               long t = runtime->period_size * 2 / runtime->rate;
+                               tout = max(t, tout);
+                       }
+                       tout = msecs_to_jiffies(tout * 1000);
+               }
+               tout = schedule_timeout_interruptible(tout);
                snd_power_lock(card);
                down_read(&snd_pcm_link_rwsem);
                snd_pcm_stream_lock_irq(substream);
@@ -1541,13 +1527,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
 static int snd_pcm_drop(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime;
-       struct snd_card *card;
        int result = 0;
        
        if (PCM_RUNTIME_CHECK(substream))
                return -ENXIO;
        runtime = substream->runtime;
-       card = substream->pcm->card;
 
        if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
            runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
@@ -2019,6 +2003,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
                substream->ops->close(substream);
                substream->hw_opened = 0;
        }
+       if (pm_qos_request_active(&substream->latency_pm_qos_req))
+               pm_qos_remove_request(&substream->latency_pm_qos_req);
        if (substream->pcm_release) {
                substream->pcm_release(substream);
                substream->pcm_release = NULL;
@@ -2077,7 +2063,6 @@ static int snd_pcm_open_file(struct file *file,
 {
        struct snd_pcm_file *pcm_file;
        struct snd_pcm_substream *substream;
-       struct snd_pcm_str *str;
        int err;
 
        if (rpcm_file)
@@ -2094,7 +2079,6 @@ static int snd_pcm_open_file(struct file *file,
        }
        pcm_file->substream = substream;
        if (substream->ref_count == 1) {
-               str = substream->pstr;
                substream->file = pcm_file;
                substream->pcm_release = pcm_release_private;
        }
@@ -2107,7 +2091,9 @@ static int snd_pcm_open_file(struct file *file,
 static int snd_pcm_playback_open(struct inode *inode, struct file *file)
 {
        struct snd_pcm *pcm;
-
+       int err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
        pcm = snd_lookup_minor_data(iminor(inode),
                                    SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
        return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
@@ -2116,7 +2102,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
 static int snd_pcm_capture_open(struct inode *inode, struct file *file)
 {
        struct snd_pcm *pcm;
-
+       int err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
        pcm = snd_lookup_minor_data(iminor(inode),
                                    SNDRV_DEVICE_TYPE_PCM_CAPTURE);
        return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
@@ -3032,11 +3020,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_status =
 static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
                               struct vm_area_struct *area)
 {
-       struct snd_pcm_runtime *runtime;
        long size;
        if (!(area->vm_flags & VM_READ))
                return -EINVAL;
-       runtime = substream->runtime;
        size = area->vm_end - area->vm_start;
        if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)))
                return -EINVAL;
@@ -3071,11 +3057,9 @@ static const struct vm_operations_struct snd_pcm_vm_ops_control =
 static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
                                struct vm_area_struct *area)
 {
-       struct snd_pcm_runtime *runtime;
        long size;
        if (!(area->vm_flags & VM_READ))
                return -EINVAL;
-       runtime = substream->runtime;
        size = area->vm_end - area->vm_start;
        if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)))
                return -EINVAL;
@@ -3184,6 +3168,10 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
                                         substream->runtime->dma_area,
                                         substream->runtime->dma_addr,
                                         area->vm_end - area->vm_start);
+#elif defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
+       if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV &&
+           !plat_device_is_coherent(substream->dma_buffer.dev.dev))
+               area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
 #endif /* ARCH_HAS_DMA_MMAP_COHERENT */
        /* mmap with fault handler */
        area->vm_ops = &snd_pcm_vm_ops_data_fault;
@@ -3214,15 +3202,6 @@ 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
  */
@@ -3303,18 +3282,13 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
        struct snd_pcm_file * pcm_file;
        struct snd_pcm_substream *substream;
        struct snd_pcm_runtime *runtime;
-       int err = -ENXIO;
 
-       lock_kernel();
        pcm_file = file->private_data;
        substream = pcm_file->substream;
        if (PCM_RUNTIME_CHECK(substream))
-               goto out;
+               return -ENXIO;
        runtime = substream->runtime;
-       err = fasync_helper(fd, file, on, &runtime->fasync);
-out:
-       unlock_kernel();
-       return err;
+       return fasync_helper(fd, file, on, &runtime->fasync);
 }
 
 /*
@@ -3434,14 +3408,28 @@ out:
 #endif /* CONFIG_SND_SUPPORT_OLD_API */
 
 #ifndef CONFIG_MMU
-unsigned long dummy_get_unmapped_area(struct file *file, unsigned long addr,
-                                     unsigned long len, unsigned long pgoff,
-                                     unsigned long flags)
-{
-       return 0;
+static unsigned long snd_pcm_get_unmapped_area(struct file *file,
+                                              unsigned long addr,
+                                              unsigned long len,
+                                              unsigned long pgoff,
+                                              unsigned long flags)
+{
+       struct snd_pcm_file *pcm_file = file->private_data;
+       struct snd_pcm_substream *substream = pcm_file->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned long offset = pgoff << PAGE_SHIFT;
+
+       switch (offset) {
+       case SNDRV_PCM_MMAP_OFFSET_STATUS:
+               return (unsigned long)runtime->status;
+       case SNDRV_PCM_MMAP_OFFSET_CONTROL:
+               return (unsigned long)runtime->control;
+       default:
+               return (unsigned long)runtime->dma_area + offset;
+       }
 }
 #else
-# define dummy_get_unmapped_area NULL
+# define snd_pcm_get_unmapped_area NULL
 #endif
 
 /*
@@ -3455,12 +3443,13 @@ const struct file_operations snd_pcm_f_ops[2] = {
                .aio_write =            snd_pcm_aio_write,
                .open =                 snd_pcm_playback_open,
                .release =              snd_pcm_release,
+               .llseek =               no_llseek,
                .poll =                 snd_pcm_playback_poll,
                .unlocked_ioctl =       snd_pcm_playback_ioctl,
                .compat_ioctl =         snd_pcm_ioctl_compat,
                .mmap =                 snd_pcm_mmap,
                .fasync =               snd_pcm_fasync,
-               .get_unmapped_area =    dummy_get_unmapped_area,
+               .get_unmapped_area =    snd_pcm_get_unmapped_area,
        },
        {
                .owner =                THIS_MODULE,
@@ -3468,11 +3457,12 @@ const struct file_operations snd_pcm_f_ops[2] = {
                .aio_read =             snd_pcm_aio_read,
                .open =                 snd_pcm_capture_open,
                .release =              snd_pcm_release,
+               .llseek =               no_llseek,
                .poll =                 snd_pcm_capture_poll,
                .unlocked_ioctl =       snd_pcm_capture_ioctl,
                .compat_ioctl =         snd_pcm_ioctl_compat,
                .mmap =                 snd_pcm_mmap,
                .fasync =               snd_pcm_fasync,
-               .get_unmapped_area =    dummy_get_unmapped_area,
+               .get_unmapped_area =    snd_pcm_get_unmapped_area,
        }
 };