diff options
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r-- | sound/core/pcm_native.c | 157 |
1 files changed, 75 insertions, 82 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 01f150f0990e..964e4c47a7f1 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -1170,7 +1170,7 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream) | |||
1170 | int res; | 1170 | int res; |
1171 | 1171 | ||
1172 | snd_power_lock(card); | 1172 | snd_power_lock(card); |
1173 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) | 1173 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) |
1174 | res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); | 1174 | res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); |
1175 | snd_power_unlock(card); | 1175 | snd_power_unlock(card); |
1176 | return res; | 1176 | return res; |
@@ -1198,7 +1198,7 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream) | |||
1198 | 1198 | ||
1199 | snd_power_lock(card); | 1199 | snd_power_lock(card); |
1200 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | 1200 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { |
1201 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); | 1201 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0); |
1202 | if (result < 0) | 1202 | if (result < 0) |
1203 | goto _unlock; | 1203 | goto _unlock; |
1204 | } | 1204 | } |
@@ -1313,13 +1313,13 @@ static struct action_ops snd_pcm_action_prepare = { | |||
1313 | * | 1313 | * |
1314 | * Prepare the PCM substream to be triggerable. | 1314 | * Prepare the PCM substream to be triggerable. |
1315 | */ | 1315 | */ |
1316 | int snd_pcm_prepare(struct snd_pcm_substream *substream) | 1316 | static int snd_pcm_prepare(struct snd_pcm_substream *substream) |
1317 | { | 1317 | { |
1318 | int res; | 1318 | int res; |
1319 | struct snd_card *card = substream->pcm->card; | 1319 | struct snd_card *card = substream->pcm->card; |
1320 | 1320 | ||
1321 | snd_power_lock(card); | 1321 | snd_power_lock(card); |
1322 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) | 1322 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) |
1323 | res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0); | 1323 | res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0); |
1324 | snd_power_unlock(card); | 1324 | snd_power_unlock(card); |
1325 | return res; | 1325 | return res; |
@@ -1410,7 +1410,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) | |||
1410 | 1410 | ||
1411 | snd_power_lock(card); | 1411 | snd_power_lock(card); |
1412 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | 1412 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { |
1413 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); | 1413 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0); |
1414 | if (result < 0) { | 1414 | if (result < 0) { |
1415 | snd_power_unlock(card); | 1415 | snd_power_unlock(card); |
1416 | return result; | 1416 | return result; |
@@ -1533,7 +1533,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) | |||
1533 | 1533 | ||
1534 | snd_power_lock(card); | 1534 | snd_power_lock(card); |
1535 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | 1535 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { |
1536 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); | 1536 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0); |
1537 | if (result < 0) | 1537 | if (result < 0) |
1538 | goto _unlock; | 1538 | goto _unlock; |
1539 | } | 1539 | } |
@@ -1995,28 +1995,63 @@ static void snd_pcm_remove_file(struct snd_pcm_str *str, | |||
1995 | } | 1995 | } |
1996 | } | 1996 | } |
1997 | 1997 | ||
1998 | static int snd_pcm_release_file(struct snd_pcm_file * pcm_file) | 1998 | static void pcm_release_private(struct snd_pcm_substream *substream) |
1999 | { | 1999 | { |
2000 | struct snd_pcm_substream *substream; | 2000 | struct snd_pcm_file *pcm_file = substream->file; |
2001 | struct snd_pcm_runtime *runtime; | ||
2002 | struct snd_pcm_str * str; | ||
2003 | 2001 | ||
2004 | snd_assert(pcm_file != NULL, return -ENXIO); | ||
2005 | substream = pcm_file->substream; | ||
2006 | snd_assert(substream != NULL, return -ENXIO); | ||
2007 | runtime = substream->runtime; | ||
2008 | str = substream->pstr; | ||
2009 | snd_pcm_unlink(substream); | 2002 | snd_pcm_unlink(substream); |
2010 | if (substream->ffile != NULL) { | 2003 | snd_pcm_remove_file(substream->pstr, pcm_file); |
2004 | kfree(pcm_file); | ||
2005 | } | ||
2006 | |||
2007 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) | ||
2008 | { | ||
2009 | snd_pcm_drop(substream); | ||
2010 | if (substream->pcm_release) | ||
2011 | substream->pcm_release(substream); | ||
2012 | if (substream->hw_opened) { | ||
2011 | if (substream->ops->hw_free != NULL) | 2013 | if (substream->ops->hw_free != NULL) |
2012 | substream->ops->hw_free(substream); | 2014 | substream->ops->hw_free(substream); |
2013 | substream->ops->close(substream); | 2015 | substream->ops->close(substream); |
2014 | substream->ffile = NULL; | 2016 | substream->hw_opened = 0; |
2015 | } | 2017 | } |
2016 | snd_pcm_remove_file(str, pcm_file); | 2018 | snd_pcm_detach_substream(substream); |
2017 | snd_pcm_release_substream(substream); | 2019 | } |
2018 | kfree(pcm_file); | 2020 | |
2021 | int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | ||
2022 | struct file *file, | ||
2023 | struct snd_pcm_substream **rsubstream) | ||
2024 | { | ||
2025 | struct snd_pcm_substream *substream; | ||
2026 | int err; | ||
2027 | |||
2028 | err = snd_pcm_attach_substream(pcm, stream, file, &substream); | ||
2029 | if (err < 0) | ||
2030 | return err; | ||
2031 | substream->no_mmap_ctrl = 0; | ||
2032 | err = snd_pcm_hw_constraints_init(substream); | ||
2033 | if (err < 0) { | ||
2034 | snd_printd("snd_pcm_hw_constraints_init failed\n"); | ||
2035 | goto error; | ||
2036 | } | ||
2037 | |||
2038 | if ((err = substream->ops->open(substream)) < 0) | ||
2039 | goto error; | ||
2040 | |||
2041 | substream->hw_opened = 1; | ||
2042 | |||
2043 | err = snd_pcm_hw_constraints_complete(substream); | ||
2044 | if (err < 0) { | ||
2045 | snd_printd("snd_pcm_hw_constraints_complete failed\n"); | ||
2046 | goto error; | ||
2047 | } | ||
2048 | |||
2049 | *rsubstream = substream; | ||
2019 | return 0; | 2050 | return 0; |
2051 | |||
2052 | error: | ||
2053 | snd_pcm_release_substream(substream); | ||
2054 | return err; | ||
2020 | } | 2055 | } |
2021 | 2056 | ||
2022 | static int snd_pcm_open_file(struct file *file, | 2057 | static int snd_pcm_open_file(struct file *file, |
@@ -2024,52 +2059,29 @@ static int snd_pcm_open_file(struct file *file, | |||
2024 | int stream, | 2059 | int stream, |
2025 | struct snd_pcm_file **rpcm_file) | 2060 | struct snd_pcm_file **rpcm_file) |
2026 | { | 2061 | { |
2027 | int err = 0; | ||
2028 | struct snd_pcm_file *pcm_file; | 2062 | struct snd_pcm_file *pcm_file; |
2029 | struct snd_pcm_substream *substream; | 2063 | struct snd_pcm_substream *substream; |
2030 | struct snd_pcm_str *str; | 2064 | struct snd_pcm_str *str; |
2065 | int err; | ||
2031 | 2066 | ||
2032 | snd_assert(rpcm_file != NULL, return -EINVAL); | 2067 | snd_assert(rpcm_file != NULL, return -EINVAL); |
2033 | *rpcm_file = NULL; | 2068 | *rpcm_file = NULL; |
2034 | 2069 | ||
2070 | err = snd_pcm_open_substream(pcm, stream, file, &substream); | ||
2071 | if (err < 0) | ||
2072 | return err; | ||
2073 | |||
2035 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); | 2074 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); |
2036 | if (pcm_file == NULL) { | 2075 | if (pcm_file == NULL) { |
2076 | snd_pcm_release_substream(substream); | ||
2037 | return -ENOMEM; | 2077 | return -ENOMEM; |
2038 | } | 2078 | } |
2039 | |||
2040 | if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) { | ||
2041 | kfree(pcm_file); | ||
2042 | return err; | ||
2043 | } | ||
2044 | |||
2045 | str = substream->pstr; | 2079 | str = substream->pstr; |
2046 | substream->file = pcm_file; | 2080 | substream->file = pcm_file; |
2047 | substream->no_mmap_ctrl = 0; | 2081 | substream->pcm_release = pcm_release_private; |
2048 | |||
2049 | pcm_file->substream = substream; | 2082 | pcm_file->substream = substream; |
2050 | |||
2051 | snd_pcm_add_file(str, pcm_file); | 2083 | snd_pcm_add_file(str, pcm_file); |
2052 | 2084 | ||
2053 | err = snd_pcm_hw_constraints_init(substream); | ||
2054 | if (err < 0) { | ||
2055 | snd_printd("snd_pcm_hw_constraints_init failed\n"); | ||
2056 | snd_pcm_release_file(pcm_file); | ||
2057 | return err; | ||
2058 | } | ||
2059 | |||
2060 | if ((err = substream->ops->open(substream)) < 0) { | ||
2061 | snd_pcm_release_file(pcm_file); | ||
2062 | return err; | ||
2063 | } | ||
2064 | substream->ffile = file; | ||
2065 | |||
2066 | err = snd_pcm_hw_constraints_complete(substream); | ||
2067 | if (err < 0) { | ||
2068 | snd_printd("snd_pcm_hw_constraints_complete failed\n"); | ||
2069 | snd_pcm_release_file(pcm_file); | ||
2070 | return err; | ||
2071 | } | ||
2072 | |||
2073 | file->private_data = pcm_file; | 2085 | file->private_data = pcm_file; |
2074 | *rpcm_file = pcm_file; | 2086 | *rpcm_file = pcm_file; |
2075 | return 0; | 2087 | return 0; |
@@ -2158,10 +2170,9 @@ static int snd_pcm_release(struct inode *inode, struct file *file) | |||
2158 | snd_assert(substream != NULL, return -ENXIO); | 2170 | snd_assert(substream != NULL, return -ENXIO); |
2159 | snd_assert(!atomic_read(&substream->runtime->mmap_count), ); | 2171 | snd_assert(!atomic_read(&substream->runtime->mmap_count), ); |
2160 | pcm = substream->pcm; | 2172 | pcm = substream->pcm; |
2161 | snd_pcm_drop(substream); | ||
2162 | fasync_helper(-1, file, 0, &substream->runtime->fasync); | 2173 | fasync_helper(-1, file, 0, &substream->runtime->fasync); |
2163 | mutex_lock(&pcm->open_mutex); | 2174 | mutex_lock(&pcm->open_mutex); |
2164 | snd_pcm_release_file(pcm_file); | 2175 | snd_pcm_release_substream(substream); |
2165 | mutex_unlock(&pcm->open_mutex); | 2176 | mutex_unlock(&pcm->open_mutex); |
2166 | wake_up(&pcm->open_wait); | 2177 | wake_up(&pcm->open_wait); |
2167 | module_put(pcm->card->module); | 2178 | module_put(pcm->card->module); |
@@ -2480,11 +2491,6 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, | |||
2480 | return 0; | 2491 | return 0; |
2481 | } | 2492 | } |
2482 | 2493 | ||
2483 | static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream, | ||
2484 | unsigned int cmd, void __user *arg); | ||
2485 | static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream, | ||
2486 | unsigned int cmd, void __user *arg); | ||
2487 | |||
2488 | static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, | 2494 | static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, |
2489 | unsigned int cmd, void __user *arg) | 2495 | unsigned int cmd, void __user *arg) |
2490 | { | 2496 | { |
@@ -2736,41 +2742,28 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, | |||
2736 | return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg); | 2742 | return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg); |
2737 | } | 2743 | } |
2738 | 2744 | ||
2739 | int snd_pcm_kernel_playback_ioctl(struct snd_pcm_substream *substream, | 2745 | int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, |
2740 | unsigned int cmd, void *arg) | 2746 | unsigned int cmd, void *arg) |
2741 | { | ||
2742 | mm_segment_t fs; | ||
2743 | int result; | ||
2744 | |||
2745 | fs = snd_enter_user(); | ||
2746 | result = snd_pcm_playback_ioctl1(substream, cmd, (void __user *)arg); | ||
2747 | snd_leave_user(fs); | ||
2748 | return result; | ||
2749 | } | ||
2750 | |||
2751 | int snd_pcm_kernel_capture_ioctl(struct snd_pcm_substream *substream, | ||
2752 | unsigned int cmd, void *arg) | ||
2753 | { | 2747 | { |
2754 | mm_segment_t fs; | 2748 | mm_segment_t fs; |
2755 | int result; | 2749 | int result; |
2756 | 2750 | ||
2757 | fs = snd_enter_user(); | 2751 | fs = snd_enter_user(); |
2758 | result = snd_pcm_capture_ioctl1(substream, cmd, (void __user *)arg); | ||
2759 | snd_leave_user(fs); | ||
2760 | return result; | ||
2761 | } | ||
2762 | |||
2763 | int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, | ||
2764 | unsigned int cmd, void *arg) | ||
2765 | { | ||
2766 | switch (substream->stream) { | 2752 | switch (substream->stream) { |
2767 | case SNDRV_PCM_STREAM_PLAYBACK: | 2753 | case SNDRV_PCM_STREAM_PLAYBACK: |
2768 | return snd_pcm_kernel_playback_ioctl(substream, cmd, arg); | 2754 | result = snd_pcm_playback_ioctl1(substream, |
2755 | cmd, (void __user *)arg); | ||
2756 | break; | ||
2769 | case SNDRV_PCM_STREAM_CAPTURE: | 2757 | case SNDRV_PCM_STREAM_CAPTURE: |
2770 | return snd_pcm_kernel_capture_ioctl(substream, cmd, arg); | 2758 | result = snd_pcm_capture_ioctl1(substream, |
2759 | cmd, (void __user *)arg); | ||
2760 | break; | ||
2771 | default: | 2761 | default: |
2772 | return -EINVAL; | 2762 | result = -EINVAL; |
2763 | break; | ||
2773 | } | 2764 | } |
2765 | snd_leave_user(fs); | ||
2766 | return result; | ||
2774 | } | 2767 | } |
2775 | 2768 | ||
2776 | static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, | 2769 | static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, |