diff options
author | Takashi Iwai <tiwai@suse.de> | 2006-04-28 09:13:41 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-06-22 15:33:13 -0400 |
commit | 0df63e44c3e315ec0fe427ae62558231864108bd (patch) | |
tree | 3cff6f5d5fdb7ad047a61c591d891e3ca1bc669e /sound/core/pcm_native.c | |
parent | f001c3acf64b8ca18fe40af592629abb261b321e (diff) |
[ALSA] Add O_APPEND flag support to PCM
Added O_APPEND flag support to PCM to enable shared substreams
among multiple processes. This mechanism is used by dmix and
dsnoop plugins.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r-- | sound/core/pcm_native.c | 81 |
1 files changed, 55 insertions, 26 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 7b5729c4b21..36d6765618a 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -1284,13 +1284,16 @@ static int snd_pcm_reset(struct snd_pcm_substream *substream) | |||
1284 | /* | 1284 | /* |
1285 | * prepare ioctl | 1285 | * prepare ioctl |
1286 | */ | 1286 | */ |
1287 | static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, int state) | 1287 | /* we use the second argument for updating f_flags */ |
1288 | static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, | ||
1289 | int f_flags) | ||
1288 | { | 1290 | { |
1289 | struct snd_pcm_runtime *runtime = substream->runtime; | 1291 | struct snd_pcm_runtime *runtime = substream->runtime; |
1290 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 1292 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
1291 | return -EBADFD; | 1293 | return -EBADFD; |
1292 | if (snd_pcm_running(substream)) | 1294 | if (snd_pcm_running(substream)) |
1293 | return -EBUSY; | 1295 | return -EBUSY; |
1296 | substream->f_flags = f_flags; | ||
1294 | return 0; | 1297 | return 0; |
1295 | } | 1298 | } |
1296 | 1299 | ||
@@ -1319,17 +1322,26 @@ static struct action_ops snd_pcm_action_prepare = { | |||
1319 | /** | 1322 | /** |
1320 | * snd_pcm_prepare | 1323 | * snd_pcm_prepare |
1321 | * @substream: the PCM substream instance | 1324 | * @substream: the PCM substream instance |
1325 | * @file: file to refer f_flags | ||
1322 | * | 1326 | * |
1323 | * Prepare the PCM substream to be triggerable. | 1327 | * Prepare the PCM substream to be triggerable. |
1324 | */ | 1328 | */ |
1325 | static int snd_pcm_prepare(struct snd_pcm_substream *substream) | 1329 | static int snd_pcm_prepare(struct snd_pcm_substream *substream, |
1330 | struct file *file) | ||
1326 | { | 1331 | { |
1327 | int res; | 1332 | int res; |
1328 | struct snd_card *card = substream->pcm->card; | 1333 | struct snd_card *card = substream->pcm->card; |
1334 | int f_flags; | ||
1335 | |||
1336 | if (file) | ||
1337 | f_flags = file->f_flags; | ||
1338 | else | ||
1339 | f_flags = substream->f_flags; | ||
1329 | 1340 | ||
1330 | snd_power_lock(card); | 1341 | snd_power_lock(card); |
1331 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) | 1342 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) |
1332 | res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0); | 1343 | res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, |
1344 | substream, f_flags); | ||
1333 | snd_power_unlock(card); | 1345 | snd_power_unlock(card); |
1334 | return res; | 1346 | return res; |
1335 | } | 1347 | } |
@@ -1340,7 +1352,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream) | |||
1340 | 1352 | ||
1341 | static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) | 1353 | static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) |
1342 | { | 1354 | { |
1343 | if (substream->ffile->f_flags & O_NONBLOCK) | 1355 | if (substream->f_flags & O_NONBLOCK) |
1344 | return -EAGAIN; | 1356 | return -EAGAIN; |
1345 | substream->runtime->trigger_master = substream; | 1357 | substream->runtime->trigger_master = substream; |
1346 | return 0; | 1358 | return 0; |
@@ -2015,6 +2027,10 @@ static void pcm_release_private(struct snd_pcm_substream *substream) | |||
2015 | 2027 | ||
2016 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) | 2028 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) |
2017 | { | 2029 | { |
2030 | substream->ref_count--; | ||
2031 | if (substream->ref_count > 0) | ||
2032 | return; | ||
2033 | |||
2018 | snd_pcm_drop(substream); | 2034 | snd_pcm_drop(substream); |
2019 | if (substream->hw_opened) { | 2035 | if (substream->hw_opened) { |
2020 | if (substream->ops->hw_free != NULL) | 2036 | if (substream->ops->hw_free != NULL) |
@@ -2041,6 +2057,11 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | |||
2041 | err = snd_pcm_attach_substream(pcm, stream, file, &substream); | 2057 | err = snd_pcm_attach_substream(pcm, stream, file, &substream); |
2042 | if (err < 0) | 2058 | if (err < 0) |
2043 | return err; | 2059 | return err; |
2060 | if (substream->ref_count > 1) { | ||
2061 | *rsubstream = substream; | ||
2062 | return 0; | ||
2063 | } | ||
2064 | |||
2044 | substream->no_mmap_ctrl = 0; | 2065 | substream->no_mmap_ctrl = 0; |
2045 | err = snd_pcm_hw_constraints_init(substream); | 2066 | err = snd_pcm_hw_constraints_init(substream); |
2046 | if (err < 0) { | 2067 | if (err < 0) { |
@@ -2086,17 +2107,20 @@ static int snd_pcm_open_file(struct file *file, | |||
2086 | if (err < 0) | 2107 | if (err < 0) |
2087 | return err; | 2108 | return err; |
2088 | 2109 | ||
2089 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); | 2110 | if (substream->ref_count > 1) |
2090 | if (pcm_file == NULL) { | 2111 | pcm_file = substream->file; |
2091 | snd_pcm_release_substream(substream); | 2112 | else { |
2092 | return -ENOMEM; | 2113 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); |
2114 | if (pcm_file == NULL) { | ||
2115 | snd_pcm_release_substream(substream); | ||
2116 | return -ENOMEM; | ||
2117 | } | ||
2118 | str = substream->pstr; | ||
2119 | substream->file = pcm_file; | ||
2120 | substream->pcm_release = pcm_release_private; | ||
2121 | pcm_file->substream = substream; | ||
2122 | snd_pcm_add_file(str, pcm_file); | ||
2093 | } | 2123 | } |
2094 | str = substream->pstr; | ||
2095 | substream->file = pcm_file; | ||
2096 | substream->pcm_release = pcm_release_private; | ||
2097 | pcm_file->substream = substream; | ||
2098 | snd_pcm_add_file(str, pcm_file); | ||
2099 | |||
2100 | file->private_data = pcm_file; | 2124 | file->private_data = pcm_file; |
2101 | *rpcm_file = pcm_file; | 2125 | *rpcm_file = pcm_file; |
2102 | return 0; | 2126 | return 0; |
@@ -2506,7 +2530,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, | |||
2506 | return 0; | 2530 | return 0; |
2507 | } | 2531 | } |
2508 | 2532 | ||
2509 | static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, | 2533 | static int snd_pcm_common_ioctl1(struct file *file, |
2534 | struct snd_pcm_substream *substream, | ||
2510 | unsigned int cmd, void __user *arg) | 2535 | unsigned int cmd, void __user *arg) |
2511 | { | 2536 | { |
2512 | snd_assert(substream != NULL, return -ENXIO); | 2537 | snd_assert(substream != NULL, return -ENXIO); |
@@ -2531,7 +2556,7 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, | |||
2531 | case SNDRV_PCM_IOCTL_CHANNEL_INFO: | 2556 | case SNDRV_PCM_IOCTL_CHANNEL_INFO: |
2532 | return snd_pcm_channel_info_user(substream, arg); | 2557 | return snd_pcm_channel_info_user(substream, arg); |
2533 | case SNDRV_PCM_IOCTL_PREPARE: | 2558 | case SNDRV_PCM_IOCTL_PREPARE: |
2534 | return snd_pcm_prepare(substream); | 2559 | return snd_pcm_prepare(substream, file); |
2535 | case SNDRV_PCM_IOCTL_RESET: | 2560 | case SNDRV_PCM_IOCTL_RESET: |
2536 | return snd_pcm_reset(substream); | 2561 | return snd_pcm_reset(substream); |
2537 | case SNDRV_PCM_IOCTL_START: | 2562 | case SNDRV_PCM_IOCTL_START: |
@@ -2573,7 +2598,8 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, | |||
2573 | return -ENOTTY; | 2598 | return -ENOTTY; |
2574 | } | 2599 | } |
2575 | 2600 | ||
2576 | static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream, | 2601 | static int snd_pcm_playback_ioctl1(struct file *file, |
2602 | struct snd_pcm_substream *substream, | ||
2577 | unsigned int cmd, void __user *arg) | 2603 | unsigned int cmd, void __user *arg) |
2578 | { | 2604 | { |
2579 | snd_assert(substream != NULL, return -ENXIO); | 2605 | snd_assert(substream != NULL, return -ENXIO); |
@@ -2649,10 +2675,11 @@ static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream, | |||
2649 | return result < 0 ? result : 0; | 2675 | return result < 0 ? result : 0; |
2650 | } | 2676 | } |
2651 | } | 2677 | } |
2652 | return snd_pcm_common_ioctl1(substream, cmd, arg); | 2678 | return snd_pcm_common_ioctl1(file, substream, cmd, arg); |
2653 | } | 2679 | } |
2654 | 2680 | ||
2655 | static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream, | 2681 | static int snd_pcm_capture_ioctl1(struct file *file, |
2682 | struct snd_pcm_substream *substream, | ||
2656 | unsigned int cmd, void __user *arg) | 2683 | unsigned int cmd, void __user *arg) |
2657 | { | 2684 | { |
2658 | snd_assert(substream != NULL, return -ENXIO); | 2685 | snd_assert(substream != NULL, return -ENXIO); |
@@ -2728,7 +2755,7 @@ static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream, | |||
2728 | return result < 0 ? result : 0; | 2755 | return result < 0 ? result : 0; |
2729 | } | 2756 | } |
2730 | } | 2757 | } |
2731 | return snd_pcm_common_ioctl1(substream, cmd, arg); | 2758 | return snd_pcm_common_ioctl1(file, substream, cmd, arg); |
2732 | } | 2759 | } |
2733 | 2760 | ||
2734 | static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, | 2761 | static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, |
@@ -2741,7 +2768,8 @@ static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, | |||
2741 | if (((cmd >> 8) & 0xff) != 'A') | 2768 | if (((cmd >> 8) & 0xff) != 'A') |
2742 | return -ENOTTY; | 2769 | return -ENOTTY; |
2743 | 2770 | ||
2744 | return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg); | 2771 | return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, |
2772 | (void __user *)arg); | ||
2745 | } | 2773 | } |
2746 | 2774 | ||
2747 | static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, | 2775 | static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, |
@@ -2754,7 +2782,8 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, | |||
2754 | if (((cmd >> 8) & 0xff) != 'A') | 2782 | if (((cmd >> 8) & 0xff) != 'A') |
2755 | return -ENOTTY; | 2783 | return -ENOTTY; |
2756 | 2784 | ||
2757 | return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg); | 2785 | return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd, |
2786 | (void __user *)arg); | ||
2758 | } | 2787 | } |
2759 | 2788 | ||
2760 | int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, | 2789 | int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, |
@@ -2766,12 +2795,12 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, | |||
2766 | fs = snd_enter_user(); | 2795 | fs = snd_enter_user(); |
2767 | switch (substream->stream) { | 2796 | switch (substream->stream) { |
2768 | case SNDRV_PCM_STREAM_PLAYBACK: | 2797 | case SNDRV_PCM_STREAM_PLAYBACK: |
2769 | result = snd_pcm_playback_ioctl1(substream, | 2798 | result = snd_pcm_playback_ioctl1(NULL, substream, cmd, |
2770 | cmd, (void __user *)arg); | 2799 | (void __user *)arg); |
2771 | break; | 2800 | break; |
2772 | case SNDRV_PCM_STREAM_CAPTURE: | 2801 | case SNDRV_PCM_STREAM_CAPTURE: |
2773 | result = snd_pcm_capture_ioctl1(substream, | 2802 | result = snd_pcm_capture_ioctl1(NULL, substream, cmd, |
2774 | cmd, (void __user *)arg); | 2803 | (void __user *)arg); |
2775 | break; | 2804 | break; |
2776 | default: | 2805 | default: |
2777 | result = -EINVAL; | 2806 | result = -EINVAL; |