summaryrefslogtreecommitdiff
path: root/include/sound/pcm.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/sound/pcm.h')
-rw-r--r--include/sound/pcm.h505
1 files changed, 323 insertions, 182 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index d6bd3caf6878..58fd6e84f961 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __SOUND_PCM_H
#define __SOUND_PCM_H
@@ -5,22 +6,6 @@
* Digital Audio (PCM) abstract layer
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Abramo Bagnara <abramo@alsa-project.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <sound/asound.h>
@@ -30,6 +15,8 @@
#include <linux/mm.h>
#include <linux/bitops.h>
#include <linux/pm_qos.h>
+#include <linux/refcount.h>
+#include <linux/uio.h>
#define snd_pcm_substream_chip(substream) ((substream)->private_data)
#define snd_pcm_chip(pcm) ((pcm)->private_data)
@@ -45,6 +32,7 @@
struct snd_pcm_hardware {
unsigned int info; /* SNDRV_PCM_INFO_* */
u64 formats; /* SNDRV_PCM_FMTBIT_* */
+ u32 subformats; /* for S32_LE, SNDRV_PCM_SUBFMTBIT_* */
unsigned int rates; /* SNDRV_PCM_RATE_* */
unsigned int rate_min; /* min rate */
unsigned int rate_max; /* max rate */
@@ -58,6 +46,7 @@ struct snd_pcm_hardware {
size_t fifo_size; /* fifo size in bytes */
};
+struct snd_pcm_status64;
struct snd_pcm_substream;
struct snd_pcm_audio_tstamp_config; /* definitions further down */
@@ -73,18 +62,16 @@ struct snd_pcm_ops {
int (*hw_free)(struct snd_pcm_substream *substream);
int (*prepare)(struct snd_pcm_substream *substream);
int (*trigger)(struct snd_pcm_substream *substream, int cmd);
+ int (*sync_stop)(struct snd_pcm_substream *substream);
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
int (*get_time_info)(struct snd_pcm_substream *substream,
- struct timespec *system_ts, struct timespec *audio_ts,
+ struct timespec64 *system_ts, struct timespec64 *audio_ts,
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
int (*fill_silence)(struct snd_pcm_substream *substream, int channel,
unsigned long pos, unsigned long bytes);
- int (*copy_user)(struct snd_pcm_substream *substream, int channel,
- unsigned long pos, void __user *buf,
- unsigned long bytes);
- int (*copy_kernel)(struct snd_pcm_substream *substream, int channel,
- unsigned long pos, void *buf, unsigned long bytes);
+ int (*copy)(struct snd_pcm_substream *substream, int channel,
+ unsigned long pos, struct iov_iter *iter, unsigned long bytes);
struct page *(*page)(struct snd_pcm_substream *substream,
unsigned long offset);
int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
@@ -106,34 +93,43 @@ struct snd_pcm_ops {
#define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2
/* 3 is absent slot. */
#define SNDRV_PCM_IOCTL1_FIFO_SIZE 4
+#define SNDRV_PCM_IOCTL1_SYNC_ID 5
#define SNDRV_PCM_TRIGGER_STOP 0
#define SNDRV_PCM_TRIGGER_START 1
-#define SNDRV_PCM_TRIGGER_PAUSE_PUSH 3
-#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 4
-#define SNDRV_PCM_TRIGGER_SUSPEND 5
-#define SNDRV_PCM_TRIGGER_RESUME 6
-#define SNDRV_PCM_TRIGGER_DRAIN 7
+#define SNDRV_PCM_TRIGGER_PAUSE_PUSH 2
+#define SNDRV_PCM_TRIGGER_PAUSE_RELEASE 3
+#define SNDRV_PCM_TRIGGER_SUSPEND 4
+#define SNDRV_PCM_TRIGGER_RESUME 5
+#define SNDRV_PCM_TRIGGER_DRAIN 6
#define SNDRV_PCM_POS_XRUN ((snd_pcm_uframes_t)-1)
/* If you change this don't forget to change rates[] table in pcm_native.c */
-#define SNDRV_PCM_RATE_5512 (1<<0) /* 5512Hz */
-#define SNDRV_PCM_RATE_8000 (1<<1) /* 8000Hz */
-#define SNDRV_PCM_RATE_11025 (1<<2) /* 11025Hz */
-#define SNDRV_PCM_RATE_16000 (1<<3) /* 16000Hz */
-#define SNDRV_PCM_RATE_22050 (1<<4) /* 22050Hz */
-#define SNDRV_PCM_RATE_32000 (1<<5) /* 32000Hz */
-#define SNDRV_PCM_RATE_44100 (1<<6) /* 44100Hz */
-#define SNDRV_PCM_RATE_48000 (1<<7) /* 48000Hz */
-#define SNDRV_PCM_RATE_64000 (1<<8) /* 64000Hz */
-#define SNDRV_PCM_RATE_88200 (1<<9) /* 88200Hz */
-#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
-#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
-#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
-
-#define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */
-#define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */
+#define SNDRV_PCM_RATE_5512 (1U<<0) /* 5512Hz */
+#define SNDRV_PCM_RATE_8000 (1U<<1) /* 8000Hz */
+#define SNDRV_PCM_RATE_11025 (1U<<2) /* 11025Hz */
+#define SNDRV_PCM_RATE_16000 (1U<<3) /* 16000Hz */
+#define SNDRV_PCM_RATE_22050 (1U<<4) /* 22050Hz */
+#define SNDRV_PCM_RATE_32000 (1U<<5) /* 32000Hz */
+#define SNDRV_PCM_RATE_44100 (1U<<6) /* 44100Hz */
+#define SNDRV_PCM_RATE_48000 (1U<<7) /* 48000Hz */
+#define SNDRV_PCM_RATE_64000 (1U<<8) /* 64000Hz */
+#define SNDRV_PCM_RATE_88200 (1U<<9) /* 88200Hz */
+#define SNDRV_PCM_RATE_96000 (1U<<10) /* 96000Hz */
+#define SNDRV_PCM_RATE_176400 (1U<<11) /* 176400Hz */
+#define SNDRV_PCM_RATE_192000 (1U<<12) /* 192000Hz */
+#define SNDRV_PCM_RATE_352800 (1U<<13) /* 352800Hz */
+#define SNDRV_PCM_RATE_384000 (1U<<14) /* 384000Hz */
+#define SNDRV_PCM_RATE_705600 (1U<<15) /* 705600Hz */
+#define SNDRV_PCM_RATE_768000 (1U<<16) /* 768000Hz */
+/* extended rates since 6.12 */
+#define SNDRV_PCM_RATE_12000 (1U<<17) /* 12000Hz */
+#define SNDRV_PCM_RATE_24000 (1U<<18) /* 24000Hz */
+#define SNDRV_PCM_RATE_128000 (1U<<19) /* 128000Hz */
+
+#define SNDRV_PCM_RATE_CONTINUOUS (1U<<30) /* continuous range */
+#define SNDRV_PCM_RATE_KNOT (1U<<31) /* supports more non-continuous rates */
#define SNDRV_PCM_RATE_8000_44100 (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\
SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|\
@@ -143,6 +139,12 @@ struct snd_pcm_ops {
SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
#define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\
SNDRV_PCM_RATE_192000)
+#define SNDRV_PCM_RATE_8000_384000 (SNDRV_PCM_RATE_8000_192000|\
+ SNDRV_PCM_RATE_352800|\
+ SNDRV_PCM_RATE_384000)
+#define SNDRV_PCM_RATE_8000_768000 (SNDRV_PCM_RATE_8000_384000|\
+ SNDRV_PCM_RATE_705600|\
+ SNDRV_PCM_RATE_768000)
#define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt)
#define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8)
#define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8)
@@ -154,6 +156,9 @@ struct snd_pcm_ops {
#define SNDRV_PCM_FMTBIT_S24_BE _SNDRV_PCM_FMTBIT(S24_BE)
#define SNDRV_PCM_FMTBIT_U24_LE _SNDRV_PCM_FMTBIT(U24_LE)
#define SNDRV_PCM_FMTBIT_U24_BE _SNDRV_PCM_FMTBIT(U24_BE)
+// For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
+// available bit count in most significant bit. It's for the case of so-called 'left-justified' or
+// `right-padding` sample which has less width than 32 bit.
#define SNDRV_PCM_FMTBIT_S32_LE _SNDRV_PCM_FMTBIT(S32_LE)
#define SNDRV_PCM_FMTBIT_S32_BE _SNDRV_PCM_FMTBIT(S32_BE)
#define SNDRV_PCM_FMTBIT_U32_LE _SNDRV_PCM_FMTBIT(U32_LE)
@@ -223,6 +228,12 @@ struct snd_pcm_ops {
#define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_BE
#endif
+#define _SNDRV_PCM_SUBFMTBIT(fmt) BIT((__force int)SNDRV_PCM_SUBFORMAT_##fmt)
+#define SNDRV_PCM_SUBFMTBIT_STD _SNDRV_PCM_SUBFMTBIT(STD)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX _SNDRV_PCM_SUBFMTBIT(MSBITS_MAX)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_20 _SNDRV_PCM_SUBFMTBIT(MSBITS_20)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_24 _SNDRV_PCM_SUBFMTBIT(MSBITS_24)
+
struct snd_pcm_file {
struct snd_pcm_substream *substream;
int no_compat_mmap;
@@ -236,7 +247,7 @@ typedef int (*snd_pcm_hw_rule_func_t)(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule {
unsigned int cond;
int var;
- int deps[4];
+ int deps[5];
snd_pcm_hw_rule_func_t func;
void *private;
@@ -350,8 +361,10 @@ static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy
struct snd_pcm_runtime {
/* -- Status -- */
+ snd_pcm_state_t state; /* stream state */
+ snd_pcm_state_t suspended_state; /* suspended stream state */
struct snd_pcm_substream *trigger_master;
- struct timespec trigger_tstamp; /* trigger timestamp */
+ struct timespec64 trigger_tstamp; /* trigger timestamp */
bool trigger_tstamp_latched; /* trigger timestamp latched in low-level driver/hardware */
int overrange;
snd_pcm_uframes_t avail_max;
@@ -380,20 +393,20 @@ struct snd_pcm_runtime {
unsigned int rate_den;
unsigned int no_period_wakeup: 1;
- /* -- SW params -- */
- int tstamp_mode; /* mmap timestamp is updated */
+ /* -- SW params; see struct snd_pcm_sw_params for comments -- */
+ int tstamp_mode;
unsigned int period_step;
snd_pcm_uframes_t start_threshold;
snd_pcm_uframes_t stop_threshold;
- snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
- noise is nearest than this */
- snd_pcm_uframes_t silence_size; /* Silence filling size */
- snd_pcm_uframes_t boundary; /* pointers wrap point */
+ snd_pcm_uframes_t silence_threshold;
+ snd_pcm_uframes_t silence_size;
+ snd_pcm_uframes_t boundary;
+ /* internal data of auto-silencer */
snd_pcm_uframes_t silence_start; /* starting pointer to silence area */
- snd_pcm_uframes_t silence_filled; /* size filled with silence */
+ snd_pcm_uframes_t silence_filled; /* already filled part of silence area */
- union snd_pcm_sync_id sync; /* hardware synchronization ID */
+ bool std_sync_id; /* hardware synchronization - standard per card ID */
/* -- mmap -- */
struct snd_pcm_mmap_status *status;
@@ -403,7 +416,10 @@ struct snd_pcm_runtime {
snd_pcm_uframes_t twake; /* do transfer (!poll) wakeup if non-zero */
wait_queue_head_t sleep; /* poll sleep */
wait_queue_head_t tsleep; /* transfer sleep */
- struct fasync_struct *fasync;
+ struct snd_fasync *fasync;
+ bool stop_operating; /* sync_stop will be called */
+ struct mutex buffer_mutex; /* protect for buffer changes */
+ atomic_t buffer_accessing; /* >0: in r/w operation, <0: blocked */
/* -- private section -- */
void *private_data;
@@ -423,11 +439,12 @@ struct snd_pcm_runtime {
size_t dma_bytes; /* size of DMA area */
struct snd_dma_buffer *dma_buffer_p; /* allocated buffer */
+ unsigned int buffer_changed:1; /* buffer allocation changed; set only in managed mode */
/* -- audio timestamp config -- */
struct snd_pcm_audio_tstamp_config audio_tstamp_config;
struct snd_pcm_audio_tstamp_report audio_tstamp_report;
- struct timespec driver_tstamp;
+ struct timespec64 driver_tstamp;
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
/* -- OSS things -- */
@@ -439,7 +456,7 @@ struct snd_pcm_group { /* keep linked substreams */
spinlock_t lock;
struct mutex mutex;
struct list_head substreams;
- int count;
+ refcount_t refs;
};
struct pid;
@@ -470,7 +487,6 @@ struct snd_pcm_substream {
struct snd_pcm_group self_group; /* fake group for non linked substream (with substream lock inside) */
struct snd_pcm_group *group; /* pointer to current group */
/* -- assigned files -- */
- void *file;
int ref_count;
atomic_t mmap_count;
unsigned int f_flags;
@@ -482,18 +498,13 @@ struct snd_pcm_substream {
#endif
#ifdef CONFIG_SND_VERBOSE_PROCFS
struct snd_info_entry *proc_root;
- struct snd_info_entry *proc_info_entry;
- struct snd_info_entry *proc_hw_params_entry;
- struct snd_info_entry *proc_sw_params_entry;
- struct snd_info_entry *proc_status_entry;
- struct snd_info_entry *proc_prealloc_entry;
- struct snd_info_entry *proc_prealloc_max_entry;
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
- struct snd_info_entry *proc_xrun_injection_entry;
-#endif
#endif /* CONFIG_SND_VERBOSE_PROCFS */
/* misc flags */
unsigned int hw_opened: 1;
+ unsigned int managed_buffer_alloc:1;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ unsigned int xrun_counter; /* number of times xrun happens */
+#endif /* CONFIG_SND_PCM_XRUN_DEBUG */
};
#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)
@@ -512,14 +523,12 @@ struct snd_pcm_str {
#endif
#ifdef CONFIG_SND_VERBOSE_PROCFS
struct snd_info_entry *proc_root;
- struct snd_info_entry *proc_info_entry;
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
unsigned int xrun_debug; /* 0 = disabled, 1 = verbose, 2 = stacktrace */
- struct snd_info_entry *proc_xrun_debug_entry;
#endif
#endif
struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
- struct device dev;
+ struct device *dev;
};
struct snd_pcm {
@@ -538,6 +547,7 @@ struct snd_pcm {
void (*private_free) (struct snd_pcm *pcm);
bool internal; /* pcm is for internal use only */
bool nonatomic; /* whole PCM operations are in non-atomic context */
+ bool no_device_suspend; /* don't invoke device PM suspend */
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
struct snd_pcm_oss oss;
#endif
@@ -574,20 +584,15 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree);
int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info);
int snd_pcm_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_info __user *info);
-int snd_pcm_status(struct snd_pcm_substream *substream,
- struct snd_pcm_status *status);
+int snd_pcm_status64(struct snd_pcm_substream *substream,
+ struct snd_pcm_status64 *status);
int snd_pcm_start(struct snd_pcm_substream *substream);
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
int snd_pcm_drain_done(struct snd_pcm_substream *substream);
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream);
#ifdef CONFIG_PM
-int snd_pcm_suspend(struct snd_pcm_substream *substream);
int snd_pcm_suspend_all(struct snd_pcm *pcm);
#else
-static inline int snd_pcm_suspend(struct snd_pcm_substream *substream)
-{
- return 0;
-}
static inline int snd_pcm_suspend_all(struct snd_pcm *pcm)
{
return 0;
@@ -622,7 +627,7 @@ snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
* snd_pcm_stream_linked - Check whether the substream is linked with others
* @substream: substream to check
*
- * Returns true if the given substream is being linked with others.
+ * Return: true if the given substream is being linked with others
*/
static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream)
{
@@ -634,6 +639,7 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream);
void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream);
void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream);
unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
+unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream);
/**
* snd_pcm_stream_lock_irqsave - Lock the PCM stream
@@ -653,6 +659,32 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
unsigned long flags);
/**
+ * snd_pcm_stream_lock_irqsave_nested - Single-nested PCM stream locking
+ * @substream: PCM substream
+ * @flags: irq flags
+ *
+ * This locks the PCM stream like snd_pcm_stream_lock_irqsave() but with
+ * the single-depth lockdep subclass.
+ */
+#define snd_pcm_stream_lock_irqsave_nested(substream, flags) \
+ do { \
+ typecheck(unsigned long, flags); \
+ flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
+ } while (0)
+
+/* definitions for guard(); use like guard(pcm_stream_lock) */
+DEFINE_LOCK_GUARD_1(pcm_stream_lock, struct snd_pcm_substream,
+ snd_pcm_stream_lock(_T->lock),
+ snd_pcm_stream_unlock(_T->lock))
+DEFINE_LOCK_GUARD_1(pcm_stream_lock_irq, struct snd_pcm_substream,
+ snd_pcm_stream_lock_irq(_T->lock),
+ snd_pcm_stream_unlock_irq(_T->lock))
+DEFINE_LOCK_GUARD_1(pcm_stream_lock_irqsave, struct snd_pcm_substream,
+ snd_pcm_stream_lock_irqsave(_T->lock, _T->flags),
+ snd_pcm_stream_unlock_irqrestore(_T->lock, _T->flags),
+ unsigned long flags)
+
+/**
* snd_pcm_group_for_each_entry - iterate over the linked substreams
* @s: the iterator
* @substream: the substream
@@ -664,24 +696,45 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
#define snd_pcm_group_for_each_entry(s, substream) \
list_for_each_entry(s, &substream->group->substreams, link_list)
+#define for_each_pcm_streams(stream) \
+ for (stream = SNDRV_PCM_STREAM_PLAYBACK; \
+ stream <= SNDRV_PCM_STREAM_LAST; \
+ stream++)
+
/**
* snd_pcm_running - Check whether the substream is in a running state
* @substream: substream to check
*
- * Returns true if the given substream is in the state RUNNING, or in the
+ * Return: true if the given substream is in the state RUNNING, or in the
* state DRAINING for playback.
*/
static inline int snd_pcm_running(struct snd_pcm_substream *substream)
{
- return (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
- (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+ return (substream->runtime->state == SNDRV_PCM_STATE_RUNNING ||
+ (substream->runtime->state == SNDRV_PCM_STATE_DRAINING &&
substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
}
/**
+ * __snd_pcm_set_state - Change the current PCM state
+ * @runtime: PCM runtime to set
+ * @state: the current state to set
+ *
+ * Call within the stream lock
+ */
+static inline void __snd_pcm_set_state(struct snd_pcm_runtime *runtime,
+ snd_pcm_state_t state)
+{
+ runtime->state = state;
+ runtime->status->state = state; /* copy for mmap */
+}
+
+/**
* bytes_to_samples - Unit conversion of the size from bytes to samples
* @runtime: PCM runtime instance
* @size: size in bytes
+ *
+ * Return: the size in samples
*/
static inline ssize_t bytes_to_samples(struct snd_pcm_runtime *runtime, ssize_t size)
{
@@ -692,6 +745,8 @@ static inline ssize_t bytes_to_samples(struct snd_pcm_runtime *runtime, ssize_t
* bytes_to_frames - Unit conversion of the size from bytes to frames
* @runtime: PCM runtime instance
* @size: size in bytes
+ *
+ * Return: the size in frames
*/
static inline snd_pcm_sframes_t bytes_to_frames(struct snd_pcm_runtime *runtime, ssize_t size)
{
@@ -702,6 +757,8 @@ static inline snd_pcm_sframes_t bytes_to_frames(struct snd_pcm_runtime *runtime,
* samples_to_bytes - Unit conversion of the size from samples to bytes
* @runtime: PCM runtime instance
* @size: size in samples
+ *
+ * Return: the byte size
*/
static inline ssize_t samples_to_bytes(struct snd_pcm_runtime *runtime, ssize_t size)
{
@@ -712,6 +769,8 @@ static inline ssize_t samples_to_bytes(struct snd_pcm_runtime *runtime, ssize_t
* frames_to_bytes - Unit conversion of the size from frames to bytes
* @runtime: PCM runtime instance
* @size: size in frames
+ *
+ * Return: the byte size
*/
static inline ssize_t frames_to_bytes(struct snd_pcm_runtime *runtime, snd_pcm_sframes_t size)
{
@@ -722,6 +781,8 @@ static inline ssize_t frames_to_bytes(struct snd_pcm_runtime *runtime, snd_pcm_s
* frame_aligned - Check whether the byte size is aligned to frames
* @runtime: PCM runtime instance
* @bytes: size in bytes
+ *
+ * Return: true if aligned, or false if not
*/
static inline int frame_aligned(struct snd_pcm_runtime *runtime, ssize_t bytes)
{
@@ -731,6 +792,8 @@ static inline int frame_aligned(struct snd_pcm_runtime *runtime, ssize_t bytes)
/**
* snd_pcm_lib_buffer_bytes - Get the buffer size of the current PCM in bytes
* @substream: PCM substream
+ *
+ * Return: buffer byte size
*/
static inline size_t snd_pcm_lib_buffer_bytes(struct snd_pcm_substream *substream)
{
@@ -741,6 +804,8 @@ static inline size_t snd_pcm_lib_buffer_bytes(struct snd_pcm_substream *substrea
/**
* snd_pcm_lib_period_bytes - Get the period size of the current PCM in bytes
* @substream: PCM substream
+ *
+ * Return: period byte size
*/
static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substream)
{
@@ -753,6 +818,8 @@ static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substrea
* @runtime: PCM runtime instance
*
* Result is between 0 ... (boundary - 1)
+ *
+ * Return: available frame size
*/
static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *runtime)
{
@@ -765,10 +832,12 @@ static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *r
}
/**
- * snd_pcm_playback_avail - Get the available (readable) space for capture
+ * snd_pcm_capture_avail - Get the available (readable) space for capture
* @runtime: PCM runtime instance
*
* Result is between 0 ... (boundary - 1)
+ *
+ * Return: available frame size
*/
static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *runtime)
{
@@ -781,6 +850,8 @@ static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *ru
/**
* snd_pcm_playback_hw_avail - Get the queued space for playback
* @runtime: PCM runtime instance
+ *
+ * Return: available frame size
*/
static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime *runtime)
{
@@ -790,6 +861,8 @@ static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime
/**
* snd_pcm_capture_hw_avail - Get the free space for capture
* @runtime: PCM runtime instance
+ *
+ * Return: available frame size
*/
static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime *runtime)
{
@@ -929,6 +1002,8 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc
/**
* params_channels - Get the number of channels from the hw params
* @p: hw params
+ *
+ * Return: the number of channels
*/
static inline unsigned int params_channels(const struct snd_pcm_hw_params *p)
{
@@ -938,6 +1013,8 @@ static inline unsigned int params_channels(const struct snd_pcm_hw_params *p)
/**
* params_rate - Get the sample rate from the hw params
* @p: hw params
+ *
+ * Return: the sample rate
*/
static inline unsigned int params_rate(const struct snd_pcm_hw_params *p)
{
@@ -947,6 +1024,8 @@ static inline unsigned int params_rate(const struct snd_pcm_hw_params *p)
/**
* params_period_size - Get the period size (in frames) from the hw params
* @p: hw params
+ *
+ * Return: the period size in frames
*/
static inline unsigned int params_period_size(const struct snd_pcm_hw_params *p)
{
@@ -956,6 +1035,8 @@ static inline unsigned int params_period_size(const struct snd_pcm_hw_params *p)
/**
* params_periods - Get the number of periods from the hw params
* @p: hw params
+ *
+ * Return: the number of periods
*/
static inline unsigned int params_periods(const struct snd_pcm_hw_params *p)
{
@@ -965,6 +1046,8 @@ static inline unsigned int params_periods(const struct snd_pcm_hw_params *p)
/**
* params_buffer_size - Get the buffer size (in frames) from the hw params
* @p: hw params
+ *
+ * Return: the buffer size in frames
*/
static inline unsigned int params_buffer_size(const struct snd_pcm_hw_params *p)
{
@@ -974,6 +1057,8 @@ static inline unsigned int params_buffer_size(const struct snd_pcm_hw_params *p)
/**
* params_buffer_bytes - Get the buffer size (in bytes) from the hw params
* @p: hw params
+ *
+ * Return: the buffer size in bytes
*/
static inline unsigned int params_buffer_bytes(const struct snd_pcm_hw_params *p)
{
@@ -1078,9 +1163,21 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int
void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
const struct snd_pcm_ops *ops);
-void snd_pcm_set_sync(struct snd_pcm_substream *substream);
+void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
+ const unsigned char *id, unsigned int len);
+/**
+ * snd_pcm_set_sync - set the PCM sync id
+ * @substream: the pcm substream
+ *
+ * Use the default PCM sync identifier for the specific card.
+ */
+static inline void snd_pcm_set_sync(struct snd_pcm_substream *substream)
+{
+ substream->runtime->std_sync_id = true;
+}
int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg);
+void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream);
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
void *buf, bool interleaved,
@@ -1142,13 +1239,18 @@ snd_pcm_kernel_readv(struct snd_pcm_substream *substream,
return __snd_pcm_lib_xfer(substream, bufs, false, frames, true);
}
-int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime);
+int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw);
+
+static inline int
+snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
+{
+ return snd_pcm_hw_limit_rates(&runtime->hw);
+}
+
unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate);
unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit);
unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
unsigned int rates_b);
-unsigned int snd_pcm_rate_range_to_bits(unsigned int rate_min,
- unsigned int rate_max);
/**
* snd_pcm_set_runtime_buffer - Set the PCM runtime buffer
@@ -1176,22 +1278,22 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea
}
/**
- * snd_pcm_gettime - Fill the timespec depending on the timestamp mode
+ * snd_pcm_gettime - Fill the timespec64 depending on the timestamp mode
* @runtime: PCM runtime instance
- * @tv: timespec to fill
+ * @tv: timespec64 to fill
*/
static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime,
- struct timespec *tv)
+ struct timespec64 *tv)
{
switch (runtime->tstamp_type) {
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC:
- ktime_get_ts(tv);
+ ktime_get_ts64(tv);
break;
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
- getrawmonotonic(tv);
+ ktime_get_raw_ts64(tv);
break;
default:
- getnstimeofday(tv);
+ ktime_get_real_ts64(tv);
break;
}
}
@@ -1200,81 +1302,72 @@ static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime,
* Memory
*/
-int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream);
-int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm);
-int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
+void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream);
+void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm);
+void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
int type, struct device *data,
size_t size, size_t max);
-int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
+void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
int type, void *data,
size_t size, size_t max);
int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size);
int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream);
-int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
- size_t size, gfp_t gfp_flags);
-int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream);
-struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
- unsigned long offset);
+int snd_pcm_set_managed_buffer(struct snd_pcm_substream *substream, int type,
+ struct device *data, size_t size, size_t max);
+int snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type,
+ struct device *data,
+ size_t size, size_t max);
+
/**
- * snd_pcm_lib_alloc_vmalloc_buffer - allocate virtual DMA buffer
- * @substream: the substream to allocate the buffer to
- * @size: the requested buffer size, in bytes
+ * snd_pcm_set_fixed_buffer - Preallocate and set up the fixed size PCM buffer
+ * @substream: the pcm substream instance
+ * @type: DMA type (SNDRV_DMA_TYPE_*)
+ * @data: DMA type dependent data
+ * @size: the requested pre-allocation size in bytes
*
- * Allocates the PCM substream buffer using vmalloc(), i.e., the memory is
- * contiguous in kernel virtual space, but not in physical memory. Use this
- * if the buffer is accessed by kernel code but not by device DMA.
+ * This is a variant of snd_pcm_set_managed_buffer(), but this pre-allocates
+ * only the given sized buffer and doesn't allow re-allocation nor dynamic
+ * allocation of a larger buffer unlike the standard one.
+ * The function may return -ENOMEM error, hence the caller must check it.
*
- * Return: 1 if the buffer was changed, 0 if not changed, or a negative error
- * code.
+ * Return: zero if successful, or a negative error code
*/
-static inline int snd_pcm_lib_alloc_vmalloc_buffer
- (struct snd_pcm_substream *substream, size_t size)
+static inline int __must_check
+snd_pcm_set_fixed_buffer(struct snd_pcm_substream *substream, int type,
+ struct device *data, size_t size)
{
- return _snd_pcm_lib_alloc_vmalloc_buffer(substream, size,
- GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+ return snd_pcm_set_managed_buffer(substream, type, data, size, 0);
}
/**
- * snd_pcm_lib_alloc_vmalloc_32_buffer - allocate 32-bit-addressable buffer
- * @substream: the substream to allocate the buffer to
- * @size: the requested buffer size, in bytes
+ * snd_pcm_set_fixed_buffer_all - Preallocate and set up the fixed size PCM buffer
+ * @pcm: the pcm instance
+ * @type: DMA type (SNDRV_DMA_TYPE_*)
+ * @data: DMA type dependent data
+ * @size: the requested pre-allocation size in bytes
*
- * This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses
- * vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory.
+ * Apply the set up of the fixed buffer via snd_pcm_set_fixed_buffer() for
+ * all substream. If any of allocation fails, it returns -ENOMEM, hence the
+ * caller must check the return value.
*
- * Return: 1 if the buffer was changed, 0 if not changed, or a negative error
- * code.
+ * Return: zero if successful, or a negative error code
*/
-static inline int snd_pcm_lib_alloc_vmalloc_32_buffer
- (struct snd_pcm_substream *substream, size_t size)
+static inline int __must_check
+snd_pcm_set_fixed_buffer_all(struct snd_pcm *pcm, int type,
+ struct device *data, size_t size)
{
- return _snd_pcm_lib_alloc_vmalloc_buffer(substream, size,
- GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+ return snd_pcm_set_managed_buffer_all(pcm, type, data, size, 0);
}
#define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p)
-#ifdef CONFIG_SND_DMA_SGBUF
-/*
- * SG-buffer handling
- */
-#define snd_pcm_substream_sgbuf(substream) \
- snd_pcm_get_dma_buf(substream)->private_data
-
-struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
- unsigned long offset);
-#else /* !SND_DMA_SGBUF */
-/*
- * fake using a continuous buffer
- */
-#define snd_pcm_sgbuf_ops_page NULL
-#endif /* SND_DMA_SGBUF */
-
/**
* snd_pcm_sgbuf_get_addr - Get the DMA address at the corresponding offset
* @substream: PCM substream
* @ofs: byte offset
+ *
+ * Return: DMA address
*/
static inline dma_addr_t
snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
@@ -1283,22 +1376,13 @@ snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
}
/**
- * snd_pcm_sgbuf_get_ptr - Get the virtual address at the corresponding offset
- * @substream: PCM substream
- * @ofs: byte offset
- */
-static inline void *
-snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
-{
- return snd_sgbuf_get_ptr(snd_pcm_get_dma_buf(substream), ofs);
-}
-
-/**
- * snd_pcm_sgbuf_chunk_size - Compute the max size that fits within the contig.
- * page from the given size
+ * snd_pcm_sgbuf_get_chunk_size - Compute the max size that fits within the
+ * contig. page from the given size
* @substream: PCM substream
* @ofs: byte offset
* @size: byte size to examine
+ *
+ * Return: chunk size
*/
static inline unsigned int
snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
@@ -1307,30 +1391,6 @@ snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
return snd_sgbuf_get_chunk_size(snd_pcm_get_dma_buf(substream), ofs, size);
}
-/**
- * snd_pcm_mmap_data_open - increase the mmap counter
- * @area: VMA
- *
- * PCM mmap callback should handle this counter properly
- */
-static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
-{
- struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
- atomic_inc(&substream->mmap_count);
-}
-
-/**
- * snd_pcm_mmap_data_close - decrease the mmap counter
- * @area: VMA
- *
- * PCM mmap callback should handle this counter properly
- */
-static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
-{
- struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
- atomic_dec(&substream->mmap_count);
-}
-
int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area);
/* mmap for io-memory area */
@@ -1342,6 +1402,8 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s
#define snd_pcm_lib_mmap_iomem NULL
#endif
+void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime);
+
/**
* snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer
* @dma: DMA number
@@ -1361,11 +1423,23 @@ static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
(IEC958_AES1_CON_PCM_CODER<<8)|\
(IEC958_AES3_CON_FS_48000<<24))
-#define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime)
-
const char *snd_pcm_format_name(snd_pcm_format_t format);
/**
+ * snd_pcm_direction_name - Get a string naming the direction of a stream
+ * @direction: Stream's direction, one of SNDRV_PCM_STREAM_XXX
+ *
+ * Returns a string naming the direction of the stream.
+ */
+static inline const char *snd_pcm_direction_name(int direction)
+{
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ return "Playback";
+ else
+ return "Capture";
+}
+
+/**
* snd_pcm_stream_str - Get a string naming the direction of a stream
* @substream: the pcm substream instance
*
@@ -1373,10 +1447,7 @@ const char *snd_pcm_format_name(snd_pcm_format_t format);
*/
static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream)
{
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return "Playback";
- else
- return "Capture";
+ return snd_pcm_direction_name(substream->stream);
}
/*
@@ -1403,6 +1474,8 @@ struct snd_pcm_chmap {
* snd_pcm_chmap_substream - get the PCM substream assigned to the given chmap info
* @info: chmap information
* @idx: the substream number index
+ *
+ * Return: the matched PCM substream, or NULL if not found
*/
static inline struct snd_pcm_substream *
snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx)
@@ -1433,12 +1506,23 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
/**
* pcm_format_to_bits - Strong-typed conversion of pcm_format to bitwise
* @pcm_format: PCM format
+ *
+ * Return: 64bit mask corresponding to the given PCM format
*/
static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
{
return 1ULL << (__force int) pcm_format;
}
+/**
+ * pcm_for_each_format - helper to iterate for each format type
+ * @f: the iterator variable in snd_pcm_format_t type
+ */
+#define pcm_for_each_format(f) \
+ for ((f) = SNDRV_PCM_FORMAT_FIRST; \
+ (__force int)(f) <= (__force int)SNDRV_PCM_FORMAT_LAST; \
+ (f) = (__force snd_pcm_format_t)((__force int)(f) + 1))
+
/* printk helpers */
#define pcm_err(pcm, fmt, args...) \
dev_err((pcm)->card->dev, fmt, ##args)
@@ -1447,4 +1531,61 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
#define pcm_dbg(pcm, fmt, args...) \
dev_dbg((pcm)->card->dev, fmt, ##args)
+/* helpers for copying between iov_iter and iomem */
+size_t copy_to_iter_fromio(const void __iomem *src, size_t bytes,
+ struct iov_iter *iter) __must_check;
+size_t copy_from_iter_toio(void __iomem *dst, size_t bytes,
+ struct iov_iter *iter) __must_check;
+
+struct snd_pcm_status64 {
+ snd_pcm_state_t state; /* stream state */
+ u8 rsvd[4];
+ s64 trigger_tstamp_sec; /* time when stream was started/stopped/paused */
+ s64 trigger_tstamp_nsec;
+ s64 tstamp_sec; /* reference timestamp */
+ s64 tstamp_nsec;
+ snd_pcm_uframes_t appl_ptr; /* appl ptr */
+ snd_pcm_uframes_t hw_ptr; /* hw ptr */
+ snd_pcm_sframes_t delay; /* current delay in frames */
+ snd_pcm_uframes_t avail; /* number of frames available */
+ snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */
+ snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */
+ snd_pcm_state_t suspended_state; /* suspended stream state */
+ __u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */
+ s64 audio_tstamp_sec; /* sample counter, wall clock, PHC or on-demand sync'ed */
+ s64 audio_tstamp_nsec;
+ s64 driver_tstamp_sec; /* useful in case reference system tstamp is reported with delay */
+ s64 driver_tstamp_nsec;
+ __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */
+ unsigned char reserved[52-4*sizeof(s64)]; /* must be filled with zero */
+};
+
+#define SNDRV_PCM_IOCTL_STATUS64 _IOR('A', 0x20, struct snd_pcm_status64)
+#define SNDRV_PCM_IOCTL_STATUS_EXT64 _IOWR('A', 0x24, struct snd_pcm_status64)
+
+struct snd_pcm_status32 {
+ snd_pcm_state_t state; /* stream state */
+ s32 trigger_tstamp_sec; /* time when stream was started/stopped/paused */
+ s32 trigger_tstamp_nsec;
+ s32 tstamp_sec; /* reference timestamp */
+ s32 tstamp_nsec;
+ u32 appl_ptr; /* appl ptr */
+ u32 hw_ptr; /* hw ptr */
+ s32 delay; /* current delay in frames */
+ u32 avail; /* number of frames available */
+ u32 avail_max; /* max frames available on hw since last status */
+ u32 overrange; /* count of ADC (capture) overrange detections from last status */
+ snd_pcm_state_t suspended_state; /* suspended stream state */
+ u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */
+ s32 audio_tstamp_sec; /* sample counter, wall clock, PHC or on-demand sync'ed */
+ s32 audio_tstamp_nsec;
+ s32 driver_tstamp_sec; /* useful in case reference system tstamp is reported with delay */
+ s32 driver_tstamp_nsec;
+ u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */
+ unsigned char reserved[52-4*sizeof(s32)]; /* must be filled with zero */
+};
+
+#define SNDRV_PCM_IOCTL_STATUS32 _IOR('A', 0x20, struct snd_pcm_status32)
+#define SNDRV_PCM_IOCTL_STATUS_EXT32 _IOWR('A', 0x24, struct snd_pcm_status32)
+
#endif /* __SOUND_PCM_H */