#include <linux/compat.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/pm_qos.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/timer.h>
#include <sound/minors.h>
#include <linux/uio.h>
#include <linux/delay.h>
#include "pcm_local.h"
#ifdef CONFIG_SND_DEBUG
#define CREATE_TRACE_POINTS
#include "pcm_param_trace.h"
#else
#define trace_hw_mask_param_enabled …
#define trace_hw_interval_param_enabled …
#define trace_hw_mask_param …
#define trace_hw_interval_param …
#endif
struct snd_pcm_hw_params_old { … };
#ifdef CONFIG_SND_SUPPORT_OLD_API
#define SNDRV_PCM_IOCTL_HW_REFINE_OLD …
#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD …
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params_old __user * _oparams);
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params_old __user * _oparams);
#endif
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
static DECLARE_RWSEM(snd_pcm_link_rwsem);
void snd_pcm_group_init(struct snd_pcm_group *group)
{ … }
#define DEFINE_PCM_GROUP_LOCK(action, mutex_action) …
DEFINE_PCM_GROUP_LOCK(lock, lock);
DEFINE_PCM_GROUP_LOCK(unlock, unlock);
DEFINE_PCM_GROUP_LOCK(lock_irq, lock);
DEFINE_PCM_GROUP_LOCK(unlock_irq, unlock);
void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
{ … }
EXPORT_SYMBOL_GPL(…);
void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
{ … }
EXPORT_SYMBOL_GPL(…);
void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
{ … }
EXPORT_SYMBOL_GPL(…);
static void snd_pcm_stream_lock_nested(struct snd_pcm_substream *substream)
{ … }
void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
{ … }
EXPORT_SYMBOL_GPL(…);
unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
{ … }
EXPORT_SYMBOL_GPL(…);
unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream)
{ … }
EXPORT_SYMBOL_GPL(…);
void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
unsigned long flags)
{ … }
EXPORT_SYMBOL_GPL(…);
static int snd_pcm_ops_ioctl(struct snd_pcm_substream *substream,
unsigned cmd, void *arg)
{ … }
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)
{ … }
#define PARAM_MASK_BIT(b) …
static bool hw_support_mmap(struct snd_pcm_substream *substream)
{ … }
static int constrain_mask_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{ … }
static int constrain_interval_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{ … }
static int constrain_params_by_rules(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{ … }
static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{ … }
int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{ … }
EXPORT_SYMBOL(…);
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params __user * _params)
{ … }
static int period_to_usecs(struct snd_pcm_runtime *runtime)
{ … }
static void snd_pcm_set_state(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
int event)
{ … }
void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq)
{ … }
static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
struct snd_pcm_hw_params *params)
{ … }
static int snd_pcm_buffer_access_lock(struct snd_pcm_runtime *runtime)
{ … }
static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime)
{ … }
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
#define is_oss_stream(substream) …
#else
#define is_oss_stream …
#endif
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{ … }
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params __user * _params)
{ … }
static int do_hw_free(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
struct snd_pcm_sw_params *params)
{ … }
static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
struct snd_pcm_sw_params __user * _params)
{ … }
static inline snd_pcm_uframes_t
snd_pcm_calc_delay(struct snd_pcm_substream *substream)
{ … }
int snd_pcm_status64(struct snd_pcm_substream *substream,
struct snd_pcm_status64 *status)
{ … }
static int snd_pcm_status_user64(struct snd_pcm_substream *substream,
struct snd_pcm_status64 __user * _status,
bool ext)
{ … }
static int snd_pcm_status_user32(struct snd_pcm_substream *substream,
struct snd_pcm_status32 __user * _status,
bool ext)
{ … }
static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
struct snd_pcm_channel_info * info)
{ … }
static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_channel_info __user * _info)
{ … }
static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
{ … }
#define ACTION_ARG_IGNORE …
struct action_ops { … };
static int snd_pcm_action_group(const struct action_ops *ops,
struct snd_pcm_substream *substream,
snd_pcm_state_t state,
bool stream_lock)
{ … }
static int snd_pcm_action_single(const struct action_ops *ops,
struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_group_assign(struct snd_pcm_substream *substream,
struct snd_pcm_group *new_group)
{ … }
static void snd_pcm_group_unref(struct snd_pcm_group *group,
struct snd_pcm_substream *substream)
{ … }
static struct snd_pcm_group *
snd_pcm_stream_group_ref(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_action(const struct action_ops *ops,
struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_action_lock_irq(const struct action_ops *ops,
struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_action_nonatomic(const struct action_ops *ops,
struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_pre_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_do_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_undo_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_post_start(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static const struct action_ops snd_pcm_action_start = …;
int snd_pcm_start(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_pre_stop(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_do_stop(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_post_stop(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static const struct action_ops snd_pcm_action_stop = …;
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{ … }
EXPORT_SYMBOL(…);
int snd_pcm_drain_done(struct snd_pcm_substream *substream)
{ … }
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
{ … }
EXPORT_SYMBOL_GPL(…);
#define pause_pushed(state) …
static int snd_pcm_pre_pause(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_do_pause(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_undo_pause(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_post_pause(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static const struct action_ops snd_pcm_action_pause = …;
static int snd_pcm_pause(struct snd_pcm_substream *substream, bool push)
{ … }
static int snd_pcm_pause_lock_irq(struct snd_pcm_substream *substream,
bool push)
{ … }
#ifdef CONFIG_PM
static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_do_suspend(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_post_suspend(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static const struct action_ops snd_pcm_action_suspend = …;
static int snd_pcm_suspend(struct snd_pcm_substream *substream)
{ … }
int snd_pcm_suspend_all(struct snd_pcm *pcm)
{ … }
EXPORT_SYMBOL(…);
static int snd_pcm_pre_resume(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_do_resume(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_undo_resume(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_post_resume(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static const struct action_ops snd_pcm_action_resume = …;
static int snd_pcm_resume(struct snd_pcm_substream *substream)
{ … }
#else
static int snd_pcm_resume(struct snd_pcm_substream *substream)
{
return -ENOSYS;
}
#endif
static int snd_pcm_xrun(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_pre_reset(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_do_reset(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_post_reset(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static const struct action_ops snd_pcm_action_reset = …;
static int snd_pcm_reset(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_do_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_post_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static const struct action_ops snd_pcm_action_prepare = …;
static int snd_pcm_prepare(struct snd_pcm_substream *substream,
struct file *file)
{ … }
static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{ … }
static const struct action_ops snd_pcm_action_drain_init = …;
static int snd_pcm_drain(struct snd_pcm_substream *substream,
struct file *file)
{ … }
static int snd_pcm_drop(struct snd_pcm_substream *substream)
{ … }
static bool is_pcm_file(struct file *file)
{ … }
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
{ … }
static void relink_to_local(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_unlink(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
static int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
static int snd_pcm_hw_rule_muldivk(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
static int snd_pcm_hw_rule_mulkdiv(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 ||\
SNDRV_PCM_RATE_128000 != 1 << 19
#error "Change this table"
#endif
static const unsigned int rates[] = …;
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = …;
static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
static int snd_pcm_hw_rule_subformats(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{ … }
static int snd_pcm_hw_constraint_subformats(struct snd_pcm_runtime *runtime,
unsigned int cond, u32 *subformats)
{ … }
static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
{ … }
static void pcm_release_private(struct snd_pcm_substream *substream)
{ … }
void snd_pcm_release_substream(struct snd_pcm_substream *substream)
{ … }
EXPORT_SYMBOL(…);
int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
struct file *file,
struct snd_pcm_substream **rsubstream)
{ … }
EXPORT_SYMBOL(…);
static int snd_pcm_open_file(struct file *file,
struct snd_pcm *pcm,
int stream)
{ … }
static int snd_pcm_playback_open(struct inode *inode, struct file *file)
{ … }
static int snd_pcm_capture_open(struct inode *inode, struct file *file)
{ … }
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
{ … }
static int snd_pcm_release(struct inode *inode, struct file *file)
{ … }
static int do_pcm_hwsync(struct snd_pcm_substream *substream)
{ … }
static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,
snd_pcm_uframes_t frames,
snd_pcm_sframes_t avail)
{ … }
static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,
snd_pcm_uframes_t frames,
snd_pcm_sframes_t avail)
{ … }
static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
snd_pcm_uframes_t frames)
{ … }
static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
snd_pcm_uframes_t frames)
{ … }
static int snd_pcm_delay(struct snd_pcm_substream *substream,
snd_pcm_sframes_t *delay)
{ … }
static inline int snd_pcm_hwsync(struct snd_pcm_substream *substream)
{ … }
static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
struct snd_pcm_sync_ptr __user *_sync_ptr)
{ … }
struct snd_pcm_mmap_status32 { … } __packed;
struct snd_pcm_mmap_control32 { … };
struct snd_pcm_sync_ptr32 { … } __packed;
static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime)
{ … }
static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
struct snd_pcm_sync_ptr32 __user *src)
{ … }
#define __SNDRV_PCM_IOCTL_SYNC_PTR32 …
static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
{ … }
static int snd_pcm_xferi_frames_ioctl(struct snd_pcm_substream *substream,
struct snd_xferi __user *_xferi)
{ … }
static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
struct snd_xfern __user *_xfern)
{ … }
static int snd_pcm_rewind_ioctl(struct snd_pcm_substream *substream,
snd_pcm_uframes_t __user *_frames)
{ … }
static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream,
snd_pcm_uframes_t __user *_frames)
{ … }
static int snd_pcm_common_ioctl(struct file *file,
struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg)
{ … }
static long snd_pcm_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{ … }
int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{ … }
EXPORT_SYMBOL(…);
static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
loff_t * offset)
{ … }
static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
size_t count, loff_t * offset)
{ … }
static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
{ … }
static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
{ … }
static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
{ … }
#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA)
static vm_fault_t snd_pcm_mmap_status_fault(struct vm_fault *vmf)
{ … }
static const struct vm_operations_struct snd_pcm_vm_ops_status = …;
static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{ … }
static vm_fault_t snd_pcm_mmap_control_fault(struct vm_fault *vmf)
{ … }
static const struct vm_operations_struct snd_pcm_vm_ops_control = …;
static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{ … }
static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file)
{ … }
static bool pcm_control_mmap_allowed(struct snd_pcm_file *pcm_file)
{ … }
#else
#define pcm_status_mmap_allowed …
#define pcm_control_mmap_allowed …
static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
return -ENXIO;
}
static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
return -ENXIO;
}
#endif
static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
{ … }
static const struct vm_operations_struct snd_pcm_vm_ops_data = …;
static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = …;
int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{ … }
EXPORT_SYMBOL_GPL(…);
#if SNDRV_PCM_INFO_MMAP_IOMEM
int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{ … }
EXPORT_SYMBOL(…);
#endif
int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{ … }
EXPORT_SYMBOL(…);
static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
{ … }
static int snd_pcm_fasync(int fd, struct file * file, int on)
{ … }
#ifdef CONFIG_COMPAT
#include "pcm_compat.c"
#else
#define snd_pcm_ioctl_compat …
#endif
#ifdef CONFIG_SND_SUPPORT_OLD_API
#define __OLD_TO_NEW_MASK(x) …
#define __NEW_TO_OLD_MASK(x) …
static void snd_pcm_hw_convert_from_old_params(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_params_old *oparams)
{ … }
static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *oparams,
struct snd_pcm_hw_params *params)
{ … }
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params_old __user * _oparams)
{ … }
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params_old __user * _oparams)
{ … }
#endif
#ifndef CONFIG_MMU
static unsigned long snd_pcm_get_unmapped_area(struct file *file,
unsigned long addr,
unsigned long len,
unsigned long pgoff,
unsigned long flags)
{
struct snd_pcm_file *pcm_file = file->private_data;
struct snd_pcm_substream *substream = pcm_file->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long offset = pgoff << PAGE_SHIFT;
switch (offset) {
case SNDRV_PCM_MMAP_OFFSET_STATUS_NEW:
return (unsigned long)runtime->status;
case SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW:
return (unsigned long)runtime->control;
default:
return (unsigned long)runtime->dma_area + offset;
}
}
#else
#define snd_pcm_get_unmapped_area …
#endif
const struct file_operations snd_pcm_f_ops[2] = …;