linux/include/sound/control.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2#ifndef __SOUND_CONTROL_H
   3#define __SOUND_CONTROL_H
   4
   5/*
   6 *  Header file for control interface
   7 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   8 */
   9
  10#include <linux/wait.h>
  11#include <linux/nospec.h>
  12#include <sound/asound.h>
  13
  14#define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data)
  15
  16struct snd_kcontrol;
  17typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
  18typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
  19typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
  20typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
  21                                    int op_flag, /* SNDRV_CTL_TLV_OP_XXX */
  22                                    unsigned int size,
  23                                    unsigned int __user *tlv);
  24
  25/* internal flag for skipping validations */
  26#ifdef CONFIG_SND_CTL_VALIDATION
  27#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK        (1 << 24)
  28#define snd_ctl_skip_validation(info) \
  29        ((info)->access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK)
  30#else
  31#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK        0
  32#define snd_ctl_skip_validation(info)           true
  33#endif
  34
  35/* kernel only - LED bits */
  36#define SNDRV_CTL_ELEM_ACCESS_LED_SHIFT         25
  37#define SNDRV_CTL_ELEM_ACCESS_LED_MASK          (7<<25) /* kernel three bits - LED group */
  38#define SNDRV_CTL_ELEM_ACCESS_SPK_LED           (1<<25) /* kernel speaker (output) LED flag */
  39#define SNDRV_CTL_ELEM_ACCESS_MIC_LED           (2<<25) /* kernel microphone (input) LED flag */
  40
  41enum {
  42        SNDRV_CTL_TLV_OP_READ = 0,
  43        SNDRV_CTL_TLV_OP_WRITE = 1,
  44        SNDRV_CTL_TLV_OP_CMD = -1,
  45};
  46
  47struct snd_kcontrol_new {
  48        snd_ctl_elem_iface_t iface;     /* interface identifier */
  49        unsigned int device;            /* device/client number */
  50        unsigned int subdevice;         /* subdevice (substream) number */
  51        const char *name;               /* ASCII name of item */
  52        unsigned int index;             /* index of item */
  53        unsigned int access;            /* access rights */
  54        unsigned int count;             /* count of same elements */
  55        snd_kcontrol_info_t *info;
  56        snd_kcontrol_get_t *get;
  57        snd_kcontrol_put_t *put;
  58        union {
  59                snd_kcontrol_tlv_rw_t *c;
  60                const unsigned int *p;
  61        } tlv;
  62        unsigned long private_value;
  63};
  64
  65struct snd_kcontrol_volatile {
  66        struct snd_ctl_file *owner;     /* locked */
  67        unsigned int access;    /* access rights */
  68};
  69
  70struct snd_kcontrol {
  71        struct list_head list;          /* list of controls */
  72        struct snd_ctl_elem_id id;
  73        unsigned int count;             /* count of same elements */
  74        snd_kcontrol_info_t *info;
  75        snd_kcontrol_get_t *get;
  76        snd_kcontrol_put_t *put;
  77        union {
  78                snd_kcontrol_tlv_rw_t *c;
  79                const unsigned int *p;
  80        } tlv;
  81        unsigned long private_value;
  82        void *private_data;
  83        void (*private_free)(struct snd_kcontrol *kcontrol);
  84        struct snd_kcontrol_volatile vd[];      /* volatile data */
  85};
  86
  87#define snd_kcontrol(n) list_entry(n, struct snd_kcontrol, list)
  88
  89struct snd_kctl_event {
  90        struct list_head list;  /* list of events */
  91        struct snd_ctl_elem_id id;
  92        unsigned int mask;
  93};
  94
  95#define snd_kctl_event(n) list_entry(n, struct snd_kctl_event, list)
  96
  97struct pid;
  98
  99enum {
 100        SND_CTL_SUBDEV_PCM,
 101        SND_CTL_SUBDEV_RAWMIDI,
 102        SND_CTL_SUBDEV_ITEMS,
 103};
 104
 105struct snd_ctl_file {
 106        struct list_head list;          /* list of all control files */
 107        struct snd_card *card;
 108        struct pid *pid;
 109        int preferred_subdevice[SND_CTL_SUBDEV_ITEMS];
 110        wait_queue_head_t change_sleep;
 111        spinlock_t read_lock;
 112        struct fasync_struct *fasync;
 113        int subscribed;                 /* read interface is activated */
 114        struct list_head events;        /* waiting events for read */
 115};
 116
 117struct snd_ctl_layer_ops {
 118        struct snd_ctl_layer_ops *next;
 119        const char *module_name;
 120        void (*lregister)(struct snd_card *card);
 121        void (*ldisconnect)(struct snd_card *card);
 122        void (*lnotify)(struct snd_card *card, unsigned int mask, struct snd_kcontrol *kctl, unsigned int ioff);
 123};
 124
 125#define snd_ctl_file(n) list_entry(n, struct snd_ctl_file, list)
 126
 127typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card,
 128                                      struct snd_ctl_file * control,
 129                                      unsigned int cmd, unsigned long arg);
 130
 131void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id);
 132void snd_ctl_notify_one(struct snd_card * card, unsigned int mask, struct snd_kcontrol * kctl, unsigned int ioff);
 133
 134struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);
 135void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
 136int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
 137int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
 138int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace);
 139int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
 140int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
 141int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active);
 142struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid);
 143struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id);
 144
 145int snd_ctl_create(struct snd_card *card);
 146
 147int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
 148int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
 149#ifdef CONFIG_COMPAT
 150int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn);
 151int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
 152#else
 153#define snd_ctl_register_ioctl_compat(fcn)
 154#define snd_ctl_unregister_ioctl_compat(fcn)
 155#endif
 156
 157int snd_ctl_request_layer(const char *module_name);
 158void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops);
 159void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops);
 160
 161int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type);
 162
 163static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
 164{
 165        unsigned int ioff = id->numid - kctl->id.numid;
 166        return array_index_nospec(ioff, kctl->count);
 167}
 168
 169static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
 170{
 171        unsigned int ioff = id->index - kctl->id.index;
 172        return array_index_nospec(ioff, kctl->count);
 173}
 174
 175static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
 176{
 177        if (id->numid) {
 178                return snd_ctl_get_ioffnum(kctl, id);
 179        } else {
 180                return snd_ctl_get_ioffidx(kctl, id);
 181        }
 182}
 183
 184static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id *dst_id,
 185                                                    struct snd_kcontrol *src_kctl,
 186                                                    unsigned int offset)
 187{
 188        *dst_id = src_kctl->id;
 189        dst_id->index += offset;
 190        dst_id->numid += offset;
 191        return dst_id;
 192}
 193
 194/*
 195 * Frequently used control callbacks/helpers
 196 */
 197int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
 198                              struct snd_ctl_elem_info *uinfo);
 199int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
 200                                struct snd_ctl_elem_info *uinfo);
 201int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
 202                      unsigned int items, const char *const names[]);
 203
 204/*
 205 * virtual master control
 206 */
 207struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
 208                                                 const unsigned int *tlv);
 209int _snd_ctl_add_follower(struct snd_kcontrol *master,
 210                          struct snd_kcontrol *follower,
 211                          unsigned int flags);
 212/* optional flags for follower */
 213#define SND_CTL_FOLLOWER_NEED_UPDATE    (1 << 0)
 214
 215/**
 216 * snd_ctl_add_follower - Add a virtual follower control
 217 * @master: vmaster element
 218 * @follower: follower element to add
 219 *
 220 * Add a virtual follower control to the given master element created via
 221 * snd_ctl_create_virtual_master() beforehand.
 222 *
 223 * All followers must be the same type (returning the same information
 224 * via info callback).  The function doesn't check it, so it's your
 225 * responsibility.
 226 *
 227 * Also, some additional limitations:
 228 * at most two channels,
 229 * logarithmic volume control (dB level) thus no linear volume,
 230 * master can only attenuate the volume without gain
 231 *
 232 * Return: Zero if successful or a negative error code.
 233 */
 234static inline int
 235snd_ctl_add_follower(struct snd_kcontrol *master, struct snd_kcontrol *follower)
 236{
 237        return _snd_ctl_add_follower(master, follower, 0);
 238}
 239
 240/**
 241 * snd_ctl_add_follower_uncached - Add a virtual follower control
 242 * @master: vmaster element
 243 * @follower: follower element to add
 244 *
 245 * Add a virtual follower control to the given master.
 246 * Unlike snd_ctl_add_follower(), the element added via this function
 247 * is supposed to have volatile values, and get callback is called
 248 * at each time queried from the master.
 249 *
 250 * When the control peeks the hardware values directly and the value
 251 * can be changed by other means than the put callback of the element,
 252 * this function should be used to keep the value always up-to-date.
 253 *
 254 * Return: Zero if successful or a negative error code.
 255 */
 256static inline int
 257snd_ctl_add_follower_uncached(struct snd_kcontrol *master,
 258                              struct snd_kcontrol *follower)
 259{
 260        return _snd_ctl_add_follower(master, follower, SND_CTL_FOLLOWER_NEED_UPDATE);
 261}
 262
 263int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl,
 264                             void (*hook)(void *private_data, int),
 265                             void *private_data);
 266void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only);
 267#define snd_ctl_sync_vmaster_hook(kctl) snd_ctl_sync_vmaster(kctl, true)
 268int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl,
 269                                    int (*func)(struct snd_kcontrol *vfollower,
 270                                                struct snd_kcontrol *follower,
 271                                                void *arg),
 272                                    void *arg);
 273
 274/*
 275 * Control LED trigger layer
 276 */
 277#define SND_CTL_LAYER_MODULE_LED        "snd-ctl-led"
 278
 279#if IS_MODULE(CONFIG_SND_CTL_LED)
 280static inline int snd_ctl_led_request(void) { return snd_ctl_request_layer(SND_CTL_LAYER_MODULE_LED); }
 281#else
 282static inline int snd_ctl_led_request(void) { return 0; }
 283#endif
 284
 285/*
 286 * Helper functions for jack-detection controls
 287 */
 288struct snd_kcontrol *
 289snd_kctl_jack_new(const char *name, struct snd_card *card);
 290void snd_kctl_jack_report(struct snd_card *card,
 291                          struct snd_kcontrol *kctl, bool status);
 292
 293#endif  /* __SOUND_CONTROL_H */
 294