]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - sound/core/pcm_native.c
kbuild: Fix gcc -x syntax
[karo-tx-linux.git] / sound / core / pcm_native.c
index 1a07750f3836ae93826fa20d5c5f7a56511bb3c3..7393551a8c47e1cf3aec2b4fcf44752f4066d3da 100644 (file)
@@ -368,6 +368,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
        return usecs;
 }
 
+static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
+{
+       snd_pcm_stream_lock_irq(substream);
+       if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
+               substream->runtime->status->state = state;
+       snd_pcm_stream_unlock_irq(substream);
+}
+
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -451,7 +459,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                runtime->boundary *= 2;
 
        snd_pcm_timer_resolution_change(substream);
-       runtime->status->state = SNDRV_PCM_STATE_SETUP;
+       snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
 
        if (pm_qos_request_active(&substream->latency_pm_qos_req))
                pm_qos_remove_request(&substream->latency_pm_qos_req);
@@ -463,7 +471,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        /* 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;
+       snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
        if (substream->ops->hw_free != NULL)
                substream->ops->hw_free(substream);
        return err;
@@ -511,7 +519,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
                return -EBADFD;
        if (substream->ops->hw_free)
                result = substream->ops->hw_free(substream);
-       runtime->status->state = SNDRV_PCM_STATE_OPEN;
+       snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
        pm_qos_remove_request(&substream->latency_pm_qos_req);
        return result;
 }
@@ -1319,7 +1327,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        runtime->control->appl_ptr = runtime->status->hw_ptr;
-       runtime->status->state = SNDRV_PCM_STATE_PREPARED;
+       snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
 }
 
 static struct action_ops snd_pcm_action_prepare = {
@@ -1481,15 +1489,28 @@ 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);
                remove_wait_queue(&to_check->sleep, &wait);
+               if (card->shutdown) {
+                       result = -ENODEV;
+                       break;
+               }
                if (tout == 0) {
                        if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
                                result = -ESTRPIPE;
@@ -1518,13 +1539,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 ||
@@ -1612,6 +1631,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
  _end:
        write_unlock_irq(&snd_pcm_link_rwlock);
        up_write(&snd_pcm_link_rwsem);
+       snd_card_unref(substream1->pcm->card);
        fput(file);
        return res;
 }
@@ -2056,7 +2076,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)
@@ -2073,7 +2092,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;
        }
@@ -2091,7 +2109,10 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
                return err;
        pcm = snd_lookup_minor_data(iminor(inode),
                                    SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
-       return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+       err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+       if (pcm)
+               snd_card_unref(pcm->card);
+       return err;
 }
 
 static int snd_pcm_capture_open(struct inode *inode, struct file *file)
@@ -2102,7 +2123,10 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)
                return err;
        pcm = snd_lookup_minor_data(iminor(inode),
                                    SNDRV_DEVICE_TYPE_PCM_CAPTURE);
-       return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+       err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+       if (pcm)
+               snd_card_unref(pcm->card);
+       return err;
 }
 
 static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
@@ -2140,6 +2164,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
                mutex_unlock(&pcm->open_mutex);
                schedule();
                mutex_lock(&pcm->open_mutex);
+               if (pcm->card->shutdown) {
+                       err = -ENODEV;
+                       break;
+               }
                if (signal_pending(current)) {
                        err = -ERESTARTSYS;
                        break;
@@ -3015,11 +3043,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;
@@ -3054,11 +3080,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;