diff options
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r-- | sound/core/pcm_native.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5e12e5bacbba..6e8872de5ba0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) | |||
369 | return usecs; | 369 | return usecs; |
370 | } | 370 | } |
371 | 371 | ||
372 | static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state) | ||
373 | { | ||
374 | snd_pcm_stream_lock_irq(substream); | ||
375 | if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED) | ||
376 | substream->runtime->status->state = state; | ||
377 | snd_pcm_stream_unlock_irq(substream); | ||
378 | } | ||
379 | |||
372 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | 380 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, |
373 | struct snd_pcm_hw_params *params) | 381 | struct snd_pcm_hw_params *params) |
374 | { | 382 | { |
@@ -452,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
452 | runtime->boundary *= 2; | 460 | runtime->boundary *= 2; |
453 | 461 | ||
454 | snd_pcm_timer_resolution_change(substream); | 462 | snd_pcm_timer_resolution_change(substream); |
455 | runtime->status->state = SNDRV_PCM_STATE_SETUP; | 463 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP); |
456 | 464 | ||
457 | if (pm_qos_request_active(&substream->latency_pm_qos_req)) | 465 | if (pm_qos_request_active(&substream->latency_pm_qos_req)) |
458 | pm_qos_remove_request(&substream->latency_pm_qos_req); | 466 | pm_qos_remove_request(&substream->latency_pm_qos_req); |
@@ -464,7 +472,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
464 | /* hardware might be unusable from this time, | 472 | /* hardware might be unusable from this time, |
465 | so we force application to retry to set | 473 | so we force application to retry to set |
466 | the correct hardware parameter settings */ | 474 | the correct hardware parameter settings */ |
467 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | 475 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); |
468 | if (substream->ops->hw_free != NULL) | 476 | if (substream->ops->hw_free != NULL) |
469 | substream->ops->hw_free(substream); | 477 | substream->ops->hw_free(substream); |
470 | return err; | 478 | return err; |
@@ -512,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) | |||
512 | return -EBADFD; | 520 | return -EBADFD; |
513 | if (substream->ops->hw_free) | 521 | if (substream->ops->hw_free) |
514 | result = substream->ops->hw_free(substream); | 522 | result = substream->ops->hw_free(substream); |
515 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | 523 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); |
516 | pm_qos_remove_request(&substream->latency_pm_qos_req); | 524 | pm_qos_remove_request(&substream->latency_pm_qos_req); |
517 | return result; | 525 | return result; |
518 | } | 526 | } |
@@ -1320,7 +1328,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) | |||
1320 | { | 1328 | { |
1321 | struct snd_pcm_runtime *runtime = substream->runtime; | 1329 | struct snd_pcm_runtime *runtime = substream->runtime; |
1322 | runtime->control->appl_ptr = runtime->status->hw_ptr; | 1330 | runtime->control->appl_ptr = runtime->status->hw_ptr; |
1323 | runtime->status->state = SNDRV_PCM_STATE_PREPARED; | 1331 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); |
1324 | } | 1332 | } |
1325 | 1333 | ||
1326 | static struct action_ops snd_pcm_action_prepare = { | 1334 | static struct action_ops snd_pcm_action_prepare = { |
@@ -1510,6 +1518,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, | |||
1510 | down_read(&snd_pcm_link_rwsem); | 1518 | down_read(&snd_pcm_link_rwsem); |
1511 | snd_pcm_stream_lock_irq(substream); | 1519 | snd_pcm_stream_lock_irq(substream); |
1512 | remove_wait_queue(&to_check->sleep, &wait); | 1520 | remove_wait_queue(&to_check->sleep, &wait); |
1521 | if (card->shutdown) { | ||
1522 | result = -ENODEV; | ||
1523 | break; | ||
1524 | } | ||
1513 | if (tout == 0) { | 1525 | if (tout == 0) { |
1514 | if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) | 1526 | if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) |
1515 | result = -ESTRPIPE; | 1527 | result = -ESTRPIPE; |
@@ -1634,6 +1646,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) | |||
1634 | write_unlock_irq(&snd_pcm_link_rwlock); | 1646 | write_unlock_irq(&snd_pcm_link_rwlock); |
1635 | up_write(&snd_pcm_link_rwsem); | 1647 | up_write(&snd_pcm_link_rwsem); |
1636 | _nolock: | 1648 | _nolock: |
1649 | snd_card_unref(substream1->pcm->card); | ||
1637 | fput_light(file, fput_needed); | 1650 | fput_light(file, fput_needed); |
1638 | if (res < 0) | 1651 | if (res < 0) |
1639 | kfree(group); | 1652 | kfree(group); |
@@ -2108,7 +2121,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file) | |||
2108 | return err; | 2121 | return err; |
2109 | pcm = snd_lookup_minor_data(iminor(inode), | 2122 | pcm = snd_lookup_minor_data(iminor(inode), |
2110 | SNDRV_DEVICE_TYPE_PCM_PLAYBACK); | 2123 | SNDRV_DEVICE_TYPE_PCM_PLAYBACK); |
2111 | return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); | 2124 | err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); |
2125 | snd_card_unref(pcm->card); | ||
2126 | return err; | ||
2112 | } | 2127 | } |
2113 | 2128 | ||
2114 | static int snd_pcm_capture_open(struct inode *inode, struct file *file) | 2129 | static int snd_pcm_capture_open(struct inode *inode, struct file *file) |
@@ -2119,7 +2134,9 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file) | |||
2119 | return err; | 2134 | return err; |
2120 | pcm = snd_lookup_minor_data(iminor(inode), | 2135 | pcm = snd_lookup_minor_data(iminor(inode), |
2121 | SNDRV_DEVICE_TYPE_PCM_CAPTURE); | 2136 | SNDRV_DEVICE_TYPE_PCM_CAPTURE); |
2122 | return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); | 2137 | err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); |
2138 | snd_card_unref(pcm->card); | ||
2139 | return err; | ||
2123 | } | 2140 | } |
2124 | 2141 | ||
2125 | static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) | 2142 | static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) |
@@ -2156,6 +2173,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream) | |||
2156 | mutex_unlock(&pcm->open_mutex); | 2173 | mutex_unlock(&pcm->open_mutex); |
2157 | schedule(); | 2174 | schedule(); |
2158 | mutex_lock(&pcm->open_mutex); | 2175 | mutex_lock(&pcm->open_mutex); |
2176 | if (pcm->card->shutdown) { | ||
2177 | err = -ENODEV; | ||
2178 | break; | ||
2179 | } | ||
2159 | if (signal_pending(current)) { | 2180 | if (signal_pending(current)) { |
2160 | err = -ERESTARTSYS; | 2181 | err = -ERESTARTSYS; |
2161 | break; | 2182 | break; |