projects/linux·blob master · refs

322 lines · 10.6 KiB

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