#include <linux/threads.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/math64.h>
#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
#include <sound/control.h>
static int max_user_ctl_alloc_size = …;
module_param_named(max_user_ctl_alloc_size, max_user_ctl_alloc_size, int, 0444);
MODULE_PARM_DESC(…) …;
#define MAX_CONTROL_COUNT …
struct snd_kctl_ioctl { … };
static DECLARE_RWSEM(snd_ioctl_rwsem);
static DECLARE_RWSEM(snd_ctl_layer_rwsem);
static LIST_HEAD(snd_control_ioctls);
#ifdef CONFIG_COMPAT
static LIST_HEAD(snd_control_compat_ioctls);
#endif
static struct snd_ctl_layer_ops *snd_ctl_layer;
static int snd_ctl_remove_locked(struct snd_card *card,
struct snd_kcontrol *kcontrol);
static int snd_ctl_open(struct inode *inode, struct file *file)
{ … }
static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
{ … }
static int snd_ctl_release(struct inode *inode, struct file *file)
{ … }
void snd_ctl_notify(struct snd_card *card, unsigned int mask,
struct snd_ctl_elem_id *id)
{ … }
EXPORT_SYMBOL(…);
void snd_ctl_notify_one(struct snd_card *card, unsigned int mask,
struct snd_kcontrol *kctl, unsigned int ioff)
{ … }
EXPORT_SYMBOL(…);
static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
unsigned int access, struct snd_ctl_file *file)
{ … }
struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
void *private_data)
{ … }
EXPORT_SYMBOL(…);
void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
{ … }
EXPORT_SYMBOL(…);
static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
unsigned int count)
{ … }
static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
{ … }
static bool elem_id_matches(const struct snd_kcontrol *kctl,
const struct snd_ctl_elem_id *id)
{ … }
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
#define MULTIPLIER …
static unsigned long get_ctl_id_hash(const struct snd_ctl_elem_id *id)
{ … }
static void add_hash_entries(struct snd_card *card,
struct snd_kcontrol *kcontrol)
{ … }
static void remove_hash_entries(struct snd_card *card,
struct snd_kcontrol *kcontrol)
{ … }
#else
static inline void add_hash_entries(struct snd_card *card,
struct snd_kcontrol *kcontrol)
{
}
static inline void remove_hash_entries(struct snd_card *card,
struct snd_kcontrol *kcontrol)
{
}
#endif
enum snd_ctl_add_mode { … };
static int __snd_ctl_add_replace(struct snd_card *card,
struct snd_kcontrol *kcontrol,
enum snd_ctl_add_mode mode)
{ … }
static int snd_ctl_add_replace(struct snd_card *card,
struct snd_kcontrol *kcontrol,
enum snd_ctl_add_mode mode)
{ … }
int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
{ … }
EXPORT_SYMBOL(…);
int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
bool add_on_replace)
{ … }
EXPORT_SYMBOL(…);
static int __snd_ctl_remove(struct snd_card *card,
struct snd_kcontrol *kcontrol,
bool remove_hash)
{ … }
static inline int snd_ctl_remove_locked(struct snd_card *card,
struct snd_kcontrol *kcontrol)
{ … }
int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
{ … }
EXPORT_SYMBOL(…);
int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
{ … }
EXPORT_SYMBOL(…);
static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
struct snd_ctl_elem_id *id)
{ … }
int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
int active)
{ … }
EXPORT_SYMBOL_GPL(…);
int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
struct snd_ctl_elem_id *dst_id)
{ … }
EXPORT_SYMBOL(…);
void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
const char *name)
{ … }
EXPORT_SYMBOL(…);
#ifndef CONFIG_SND_CTL_FAST_LOOKUP
static struct snd_kcontrol *
snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid)
{
struct snd_kcontrol *kctl;
guard(read_lock_irqsave)(&card->controls_rwlock);
list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
return kctl;
}
return NULL;
}
#endif
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card,
unsigned int numid)
{ … }
EXPORT_SYMBOL(…);
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
const struct snd_ctl_elem_id *id)
{ … }
EXPORT_SYMBOL(…);
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
unsigned int cmd, void __user *arg)
{ … }
static int snd_ctl_elem_list(struct snd_card *card,
struct snd_ctl_elem_list *list)
{ … }
static int snd_ctl_elem_list_user(struct snd_card *card,
struct snd_ctl_elem_list __user *_list)
{ … }
static int snd_ctl_check_elem_info(struct snd_card *card,
const struct snd_ctl_elem_info *info)
{ … }
static const unsigned int value_sizes[] = …;
static void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
struct snd_ctl_elem_info *info,
u32 pattern)
{ … }
static int sanity_check_int_value(struct snd_card *card,
const struct snd_ctl_elem_value *control,
const struct snd_ctl_elem_info *info,
int i, bool print_error)
{ … }
static int sanity_check_input_values(struct snd_card *card,
const struct snd_ctl_elem_value *control,
const struct snd_ctl_elem_info *info,
bool print_error)
{ … }
static int sanity_check_elem_value(struct snd_card *card,
const struct snd_ctl_elem_value *control,
const struct snd_ctl_elem_info *info,
u32 pattern)
{ … }
static int __snd_ctl_elem_info(struct snd_card *card,
struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *info,
struct snd_ctl_file *ctl)
{ … }
static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info *info)
{ … }
static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info __user *_info)
{ … }
static int snd_ctl_elem_read(struct snd_card *card,
struct snd_ctl_elem_value *control)
{ … }
static int snd_ctl_elem_read_user(struct snd_card *card,
struct snd_ctl_elem_value __user *_control)
{ … }
static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
struct snd_ctl_elem_value *control)
{ … }
static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
struct snd_ctl_elem_value __user *_control)
{ … }
static int snd_ctl_elem_lock(struct snd_ctl_file *file,
struct snd_ctl_elem_id __user *_id)
{ … }
static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
struct snd_ctl_elem_id __user *_id)
{ … }
struct user_element { … };
static bool check_user_elem_overflow(struct snd_card *card, ssize_t add)
{ … }
static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{ … }
static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{ … }
static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{ … }
static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
unsigned int size)
{ … }
static int read_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
unsigned int size)
{ … }
static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kctl, int op_flag,
unsigned int size, unsigned int __user *buf)
{ … }
static int snd_ctl_elem_init_enum_names(struct user_element *ue)
{ … }
static size_t compute_user_elem_size(size_t size, unsigned int count)
{ … }
static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
{ … }
static int snd_ctl_elem_add(struct snd_ctl_file *file,
struct snd_ctl_elem_info *info, int replace)
{ … }
static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
struct snd_ctl_elem_info __user *_info, int replace)
{ … }
static int snd_ctl_elem_remove(struct snd_ctl_file *file,
struct snd_ctl_elem_id __user *_id)
{ … }
static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
{ … }
static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
struct snd_kcontrol *kctl,
struct snd_ctl_elem_id *id,
unsigned int __user *buf, unsigned int size)
{ … }
static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
unsigned int __user *buf, unsigned int size)
{ … }
static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
struct snd_ctl_tlv __user *buf,
int op_flag)
{ … }
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ … }
static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
size_t count, loff_t * offset)
{ … }
static __poll_t snd_ctl_poll(struct file *file, poll_table * wait)
{ … }
static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
{ … }
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
{ … }
EXPORT_SYMBOL(…);
#ifdef CONFIG_COMPAT
int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{ … }
EXPORT_SYMBOL(…);
#endif
static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
struct list_head *lists)
{ … }
int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
{ … }
EXPORT_SYMBOL(…);
#ifdef CONFIG_COMPAT
int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{ … }
EXPORT_SYMBOL(…);
#endif
static int snd_ctl_fasync(int fd, struct file * file, int on)
{ … }
int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
{ … }
EXPORT_SYMBOL_GPL(…);
#ifdef CONFIG_COMPAT
#include "control_compat.c"
#else
#define snd_ctl_ioctl_compat …
#endif
int snd_ctl_request_layer(const char *module_name)
{ … }
EXPORT_SYMBOL_GPL(…);
void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops)
{ … }
EXPORT_SYMBOL_GPL(…);
void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops)
{ … }
EXPORT_SYMBOL_GPL(…);
static const struct file_operations snd_ctl_f_ops = …;
#define call_snd_ctl_lops(_card, _op) …
static int snd_ctl_dev_register(struct snd_device *device)
{ … }
static int snd_ctl_dev_disconnect(struct snd_device *device)
{ … }
static int snd_ctl_dev_free(struct snd_device *device)
{ … }
int snd_ctl_create(struct snd_card *card)
{ … }
int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{ … }
EXPORT_SYMBOL(…);
int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{ … }
EXPORT_SYMBOL(…);
int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
unsigned int items, const char *const names[])
{ … }
EXPORT_SYMBOL(…);