Commit 0df63e44c3e315ec0fe427ae62558231864108bd

Authored by Takashi Iwai
Committed by Jaroslav Kysela
1 parent f001c3acf6

[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>

Showing 8 changed files with 99 additions and 45 deletions Side-by-side Diff

include/sound/asound.h
... ... @@ -137,7 +137,7 @@
137 137 * *
138 138 *****************************************************************************/
139 139  
140   -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7)
  140 +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8)
141 141  
142 142 typedef unsigned long snd_pcm_uframes_t;
143 143 typedef signed long snd_pcm_sframes_t;
... ... @@ -368,7 +368,8 @@
368 368 struct snd_pcm_group *group; /* pointer to current group */
369 369 /* -- assigned files -- */
370 370 void *file;
371   - struct file *ffile;
  371 + int ref_count;
  372 + unsigned int f_flags;
372 373 void (*pcm_release)(struct snd_pcm_substream *);
373 374 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
374 375 /* -- OSS things -- */
... ... @@ -387,7 +388,7 @@
387 388 unsigned int hw_opened: 1;
388 389 };
389 390  
390   -#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL)
  391 +#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)
391 392  
392 393  
393 394 struct snd_pcm_str {
sound/core/oss/pcm_oss.c
... ... @@ -1331,7 +1331,7 @@
1331 1331 if (runtime->oss.period_ptr == 0 ||
1332 1332 runtime->oss.period_ptr == runtime->oss.buffer_used)
1333 1333 runtime->oss.buffer_used = 0;
1334   - else if ((substream->ffile->f_flags & O_NONBLOCK) != 0)
  1334 + else if ((substream->f_flags & O_NONBLOCK) != 0)
1335 1335 return xfer > 0 ? xfer : -EAGAIN;
1336 1336 }
1337 1337 } else {
... ... @@ -1344,7 +1344,7 @@
1344 1344 buf += tmp;
1345 1345 bytes -= tmp;
1346 1346 xfer += tmp;
1347   - if ((substream->ffile->f_flags & O_NONBLOCK) != 0 &&
  1347 + if ((substream->f_flags & O_NONBLOCK) != 0 &&
1348 1348 tmp != runtime->oss.period_bytes)
1349 1349 break;
1350 1350 }
1351 1351  
... ... @@ -1582,10 +1582,10 @@
1582 1582 * finish sync: drain the buffer
1583 1583 */
1584 1584 __direct:
1585   - saved_f_flags = substream->ffile->f_flags;
1586   - substream->ffile->f_flags &= ~O_NONBLOCK;
  1585 + saved_f_flags = substream->f_flags;
  1586 + substream->f_flags &= ~O_NONBLOCK;
1587 1587 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1588   - substream->ffile->f_flags = saved_f_flags;
  1588 + substream->f_flags = saved_f_flags;
1589 1589 if (err < 0)
1590 1590 return err;
1591 1591 runtime->oss.prepare = 1;
1592 1592  
... ... @@ -2164,9 +2164,9 @@
2164 2164 substream->oss.oss = 1;
2165 2165 substream->oss.setup = *setup;
2166 2166 if (setup->nonblock)
2167   - substream->ffile->f_flags |= O_NONBLOCK;
  2167 + substream->f_flags |= O_NONBLOCK;
2168 2168 else if (setup->block)
2169   - substream->ffile->f_flags &= ~O_NONBLOCK;
  2169 + substream->f_flags &= ~O_NONBLOCK;
2170 2170 runtime = substream->runtime;
2171 2171 runtime->oss.params = 1;
2172 2172 runtime->oss.trigger = 1;
... ... @@ -2223,6 +2223,7 @@
2223 2223 (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
2224 2224 f_mode = FMODE_WRITE;
2225 2225  
  2226 + file->f_flags &= ~O_APPEND;
2226 2227 for (idx = 0; idx < 2; idx++) {
2227 2228 if (setup[idx].disable)
2228 2229 continue;
... ... @@ -2540,6 +2541,7 @@
2540 2541 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2541 2542 if (substream == NULL)
2542 2543 return -ENXIO;
  2544 + substream->f_flags = file->f_flags & O_NONBLOCK;
2543 2545 #ifndef OSS_DEBUG
2544 2546 return snd_pcm_oss_read1(substream, buf, count);
2545 2547 #else
... ... @@ -2561,6 +2563,7 @@
2561 2563 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2562 2564 if (substream == NULL)
2563 2565 return -ENXIO;
  2566 + substream->f_flags = file->f_flags & O_NONBLOCK;
2564 2567 result = snd_pcm_oss_write1(substream, buf, count);
2565 2568 #ifdef OSS_DEBUG
2566 2569 printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
... ... @@ -829,6 +829,26 @@
829 829 return -EINVAL;
830 830 }
831 831  
  832 + if (file->f_flags & O_APPEND) {
  833 + if (prefer_subdevice < 0) {
  834 + if (pstr->substream_count > 1)
  835 + return -EINVAL; /* must be unique */
  836 + substream = pstr->substream;
  837 + } else {
  838 + for (substream = pstr->substream; substream;
  839 + substream = substream->next)
  840 + if (substream->number == prefer_subdevice)
  841 + break;
  842 + }
  843 + if (! substream)
  844 + return -ENODEV;
  845 + if (! SUBSTREAM_BUSY(substream))
  846 + return -EBADFD;
  847 + substream->ref_count++;
  848 + *rsubstream = substream;
  849 + return 0;
  850 + }
  851 +
832 852 if (prefer_subdevice >= 0) {
833 853 for (substream = pstr->substream; substream; substream = substream->next)
834 854 if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
... ... @@ -873,7 +893,8 @@
873 893  
874 894 substream->runtime = runtime;
875 895 substream->private_data = pcm->private_data;
876   - substream->ffile = file;
  896 + substream->ref_count = 1;
  897 + substream->f_flags = file->f_flags;
877 898 pstr->substream_opened++;
878 899 *rsubstream = substream;
879 900 return 0;
... ... @@ -882,7 +903,7 @@
882 903 void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
883 904 {
884 905 struct snd_pcm_runtime *runtime;
885   - substream->file = NULL;
  906 +
886 907 runtime = substream->runtime;
887 908 snd_assert(runtime != NULL, return);
888 909 if (runtime->private_free != NULL)
sound/core/pcm_compat.c
... ... @@ -497,9 +497,9 @@
497 497 case SNDRV_PCM_IOCTL_LINK:
498 498 case SNDRV_PCM_IOCTL_UNLINK:
499 499 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
500   - return snd_pcm_playback_ioctl1(substream, cmd, argp);
  500 + return snd_pcm_playback_ioctl1(file, substream, cmd, argp);
501 501 else
502   - return snd_pcm_capture_ioctl1(substream, cmd, argp);
  502 + return snd_pcm_capture_ioctl1(file, substream, cmd, argp);
503 503 case SNDRV_PCM_IOCTL_HW_REFINE32:
504 504 return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
505 505 case SNDRV_PCM_IOCTL_HW_PARAMS32:
sound/core/pcm_lib.c
... ... @@ -1782,7 +1782,7 @@
1782 1782 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
1783 1783 return -EBADFD;
1784 1784  
1785   - nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
  1785 + nonblock = !!(substream->f_flags & O_NONBLOCK);
1786 1786  
1787 1787 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
1788 1788 runtime->channels > 1)
... ... @@ -1847,7 +1847,7 @@
1847 1847 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
1848 1848 return -EBADFD;
1849 1849  
1850   - nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
  1850 + nonblock = !!(substream->f_flags & O_NONBLOCK);
1851 1851  
1852 1852 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
1853 1853 return -EINVAL;
... ... @@ -2059,7 +2059,7 @@
2059 2059 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2060 2060 return -EBADFD;
2061 2061  
2062   - nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
  2062 + nonblock = !!(substream->f_flags & O_NONBLOCK);
2063 2063 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
2064 2064 return -EINVAL;
2065 2065 return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
... ... @@ -2118,7 +2118,7 @@
2118 2118 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2119 2119 return -EBADFD;
2120 2120  
2121   - nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
  2121 + nonblock = !!(substream->f_flags & O_NONBLOCK);
2122 2122 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
2123 2123 return -EINVAL;
2124 2124 return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
sound/core/pcm_native.c
... ... @@ -1284,13 +1284,16 @@
1284 1284 /*
1285 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 1291 struct snd_pcm_runtime *runtime = substream->runtime;
1290 1292 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
1291 1293 return -EBADFD;
1292 1294 if (snd_pcm_running(substream))
1293 1295 return -EBUSY;
  1296 + substream->f_flags = f_flags;
1294 1297 return 0;
1295 1298 }
1296 1299  
1297 1300  
1298 1301  
1299 1302  
1300 1303  
... ... @@ -1319,17 +1322,26 @@
1319 1322 /**
1320 1323 * snd_pcm_prepare
1321 1324 * @substream: the PCM substream instance
  1325 + * @file: file to refer f_flags
1322 1326 *
1323 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 1332 int res;
1328 1333 struct snd_card *card = substream->pcm->card;
  1334 + int f_flags;
1329 1335  
  1336 + if (file)
  1337 + f_flags = file->f_flags;
  1338 + else
  1339 + f_flags = substream->f_flags;
  1340 +
1330 1341 snd_power_lock(card);
1331 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 1345 snd_power_unlock(card);
1334 1346 return res;
1335 1347 }
... ... @@ -1340,7 +1352,7 @@
1340 1352  
1341 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 1356 return -EAGAIN;
1345 1357 substream->runtime->trigger_master = substream;
1346 1358 return 0;
... ... @@ -2015,6 +2027,10 @@
2015 2027  
2016 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 2034 snd_pcm_drop(substream);
2019 2035 if (substream->hw_opened) {
2020 2036 if (substream->ops->hw_free != NULL)
... ... @@ -2041,6 +2057,11 @@
2041 2057 err = snd_pcm_attach_substream(pcm, stream, file, &substream);
2042 2058 if (err < 0)
2043 2059 return err;
  2060 + if (substream->ref_count > 1) {
  2061 + *rsubstream = substream;
  2062 + return 0;
  2063 + }
  2064 +
2044 2065 substream->no_mmap_ctrl = 0;
2045 2066 err = snd_pcm_hw_constraints_init(substream);
2046 2067 if (err < 0) {
2047 2068  
... ... @@ -2086,17 +2107,20 @@
2086 2107 if (err < 0)
2087 2108 return err;
2088 2109  
2089   - pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
2090   - if (pcm_file == NULL) {
2091   - snd_pcm_release_substream(substream);
2092   - return -ENOMEM;
  2110 + if (substream->ref_count > 1)
  2111 + pcm_file = substream->file;
  2112 + else {
  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 2124 file->private_data = pcm_file;
2101 2125 *rpcm_file = pcm_file;
2102 2126 return 0;
... ... @@ -2506,7 +2530,8 @@
2506 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 2535 unsigned int cmd, void __user *arg)
2511 2536 {
2512 2537 snd_assert(substream != NULL, return -ENXIO);
... ... @@ -2531,7 +2556,7 @@
2531 2556 case SNDRV_PCM_IOCTL_CHANNEL_INFO:
2532 2557 return snd_pcm_channel_info_user(substream, arg);
2533 2558 case SNDRV_PCM_IOCTL_PREPARE:
2534   - return snd_pcm_prepare(substream);
  2559 + return snd_pcm_prepare(substream, file);
2535 2560 case SNDRV_PCM_IOCTL_RESET:
2536 2561 return snd_pcm_reset(substream);
2537 2562 case SNDRV_PCM_IOCTL_START:
... ... @@ -2573,7 +2598,8 @@
2573 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 2603 unsigned int cmd, void __user *arg)
2578 2604 {
2579 2605 snd_assert(substream != NULL, return -ENXIO);
2580 2606  
... ... @@ -2649,10 +2675,11 @@
2649 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 2683 unsigned int cmd, void __user *arg)
2657 2684 {
2658 2685 snd_assert(substream != NULL, return -ENXIO);
... ... @@ -2728,7 +2755,7 @@
2728 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 2761 static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
... ... @@ -2741,7 +2768,8 @@
2741 2768 if (((cmd >> 8) & 0xff) != 'A')
2742 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 2775 static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
... ... @@ -2754,7 +2782,8 @@
2754 2782 if (((cmd >> 8) & 0xff) != 'A')
2755 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 2789 int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
2761 2790  
... ... @@ -2766,12 +2795,12 @@
2766 2795 fs = snd_enter_user();
2767 2796 switch (substream->stream) {
2768 2797 case SNDRV_PCM_STREAM_PLAYBACK:
2769   - result = snd_pcm_playback_ioctl1(substream,
2770   - cmd, (void __user *)arg);
  2798 + result = snd_pcm_playback_ioctl1(NULL, substream, cmd,
  2799 + (void __user *)arg);
2771 2800 break;
2772 2801 case SNDRV_PCM_STREAM_CAPTURE:
2773   - result = snd_pcm_capture_ioctl1(substream,
2774   - cmd, (void __user *)arg);
  2802 + result = snd_pcm_capture_ioctl1(NULL, substream, cmd,
  2803 + (void __user *)arg);
2775 2804 break;
2776 2805 default:
2777 2806 result = -EINVAL;
sound/usb/usx2y/usx2yhwdeppcm.c
... ... @@ -632,7 +632,7 @@
632 632 for (s = 0; s < 2; ++s) {
633 633 struct snd_pcm_substream *substream;
634 634 substream = pcm->streams[s].substream;
635   - if (substream && substream->ffile != NULL)
  635 + if (SUBSTREAM_BUSY(substream))
636 636 err = -EBUSY;
637 637 }
638 638 }