Merge branch 'topic/pcm-delay' into for-linus
[safe/jmp/linux-2.6] / sound / core / pcm_native.c
index aef1868..45dc53f 100644 (file)
@@ -186,7 +186,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                if (!(params->rmask & (1 << k)))
                        continue;
 #ifdef RULES_DEBUG
-               printk("%s = ", snd_pcm_hw_param_names[k]);
+               printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
                printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
 #endif
                changed = snd_mask_refine(m, constrs_mask(constrs, k));
@@ -206,7 +206,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                if (!(params->rmask & (1 << k)))
                        continue;
 #ifdef RULES_DEBUG
-               printk("%s = ", snd_pcm_hw_param_names[k]);
+               printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
                if (i->empty)
                        printk("empty");
                else
@@ -251,7 +251,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
                        if (!doit)
                                continue;
 #ifdef RULES_DEBUG
-                       printk("Rule %d [%p]: ", k, r->func);
+                       printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func);
                        if (r->var >= 0) {
                                printk("%s = ", snd_pcm_hw_param_names[r->var]);
                                if (hw_is_mask(r->var)) {
@@ -327,21 +327,16 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params;
        int err;
 
-       params = kmalloc(sizeof(*params), GFP_KERNEL);
-       if (!params) {
-               err = -ENOMEM;
-               goto out;
-       }
-       if (copy_from_user(params, _params, sizeof(*params))) {
-               err = -EFAULT;
-               goto out;
-       }
+       params = memdup_user(_params, sizeof(*params));
+       if (IS_ERR(params))
+               return PTR_ERR(params);
+
        err = snd_pcm_hw_refine(substream, params);
        if (copy_to_user(_params, params, sizeof(*params))) {
                if (!err)
                        err = -EFAULT;
        }
-out:
+
        kfree(params);
        return err;
 }
@@ -465,21 +460,16 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params;
        int err;
 
-       params = kmalloc(sizeof(*params), GFP_KERNEL);
-       if (!params) {
-               err = -ENOMEM;
-               goto out;
-       }
-       if (copy_from_user(params, _params, sizeof(*params))) {
-               err = -EFAULT;
-               goto out;
-       }
+       params = memdup_user(_params, sizeof(*params));
+       if (IS_ERR(params))
+               return PTR_ERR(params);
+
        err = snd_pcm_hw_params(substream, params);
        if (copy_to_user(_params, params, sizeof(*params))) {
                if (!err)
                        err = -EFAULT;
        }
-out:
+
        kfree(params);
        return err;
 }
@@ -597,14 +587,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                status->avail = snd_pcm_playback_avail(runtime);
                if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
-                   runtime->status->state == SNDRV_PCM_STATE_DRAINING)
+                   runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
                        status->delay = runtime->buffer_size - status->avail;
-               else
+                       status->delay += runtime->delay;
+               } else
                        status->delay = 0;
        } else {
                status->avail = snd_pcm_capture_avail(runtime);
                if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-                       status->delay = status->avail;
+                       status->delay = status->avail + runtime->delay;
                else
                        status->delay = 0;
        }
@@ -858,6 +849,7 @@ 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->status->state = state;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
@@ -971,6 +963,11 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push)
 {
        if (substream->runtime->trigger_master != substream)
                return 0;
+       /* The jiffies check in snd_pcm_update_hw_ptr*() is done by
+        * a delta betwen the current jiffies, this gives a large enough
+        * delta, effectively to skip the check once.
+        */
+       substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000;
        return substream->ops->trigger(substream,
                                       push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH :
                                              SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
@@ -2169,7 +2166,6 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
        if (snd_BUG_ON(!substream))
                return -ENXIO;
        pcm = substream->pcm;
-       fasync_helper(-1, file, 0, &substream->runtime->fasync);
        mutex_lock(&pcm->open_mutex);
        snd_pcm_release_substream(substream);
        kfree(pcm_file);
@@ -2415,6 +2411,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
                        n = snd_pcm_playback_hw_avail(runtime);
                else
                        n = snd_pcm_capture_avail(runtime);
+               n += runtime->delay;
                break;
        case SNDRV_PCM_STATE_XRUN:
                err = -EPIPE;
@@ -2594,13 +2591,11 @@ static int snd_pcm_playback_ioctl1(struct file *file,
                        return -EFAULT;
                if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
                        return -EFAULT;
-               bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL);
-               if (bufs == NULL)
-                       return -ENOMEM;
-               if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) {
-                       kfree(bufs);
-                       return -EFAULT;
-               }
+
+               bufs = memdup_user(xfern.bufs,
+                                  sizeof(void *) * runtime->channels);
+               if (IS_ERR(bufs))
+                       return PTR_ERR(bufs);
                result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
                kfree(bufs);
                __put_user(result, &_xfern->result);
@@ -2676,13 +2671,11 @@ static int snd_pcm_capture_ioctl1(struct file *file,
                        return -EFAULT;
                if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
                        return -EFAULT;
-               bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL);
-               if (bufs == NULL)
-                       return -ENOMEM;
-               if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) {
-                       kfree(bufs);
-                       return -EFAULT;
-               }
+
+               bufs = memdup_user(xfern.bufs,
+                                  sizeof(void *) * runtime->channels);
+               if (IS_ERR(bufs))
+                       return PTR_ERR(bufs);
                result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
                kfree(bufs);
                __put_user(result, &_xfern->result);
@@ -3247,9 +3240,7 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
        err = fasync_helper(fd, file, on, &runtime->fasync);
 out:
        unlock_kernel();
-       if (err < 0)
-               return err;
-       return 0;
+       return err;
 }
 
 /*
@@ -3315,18 +3306,12 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
        int err;
 
        params = kmalloc(sizeof(*params), GFP_KERNEL);
-       if (!params) {
-               err = -ENOMEM;
-               goto out;
-       }
-       oparams = kmalloc(sizeof(*oparams), GFP_KERNEL);
-       if (!oparams) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!params)
+               return -ENOMEM;
 
-       if (copy_from_user(oparams, _oparams, sizeof(*oparams))) {
-               err = -EFAULT;
+       oparams = memdup_user(_oparams, sizeof(*oparams));
+       if (IS_ERR(oparams)) {
+               err = PTR_ERR(oparams);
                goto out;
        }
        snd_pcm_hw_convert_from_old_params(params, oparams);
@@ -3336,9 +3321,10 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
                if (!err)
                        err = -EFAULT;
        }
+
+       kfree(oparams);
 out:
        kfree(params);
-       kfree(oparams);
        return err;
 }
 
@@ -3350,17 +3336,12 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
        int err;
 
        params = kmalloc(sizeof(*params), GFP_KERNEL);
-       if (!params) {
-               err = -ENOMEM;
-               goto out;
-       }
-       oparams = kmalloc(sizeof(*oparams), GFP_KERNEL);
-       if (!oparams) {
-               err = -ENOMEM;
-               goto out;
-       }
-       if (copy_from_user(oparams, _oparams, sizeof(*oparams))) {
-               err = -EFAULT;
+       if (!params)
+               return -ENOMEM;
+
+       oparams = memdup_user(_oparams, sizeof(*oparams));
+       if (IS_ERR(oparams)) {
+               err = PTR_ERR(oparams);
                goto out;
        }
        snd_pcm_hw_convert_from_old_params(params, oparams);
@@ -3370,9 +3351,10 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
                if (!err)
                        err = -EFAULT;
        }
+
+       kfree(oparams);
 out:
        kfree(params);
-       kfree(oparams);
        return err;
 }
 #endif /* CONFIG_SND_SUPPORT_OLD_API */