control.h 8.6 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0-or-later */
L
Linus Torvalds 已提交
2 3 4 5 6
#ifndef __SOUND_CONTROL_H
#define __SOUND_CONTROL_H

/*
 *  Header file for control interface
7
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
L
Linus Torvalds 已提交
8 9
 */

10
#include <linux/wait.h>
11
#include <linux/nospec.h>
L
Linus Torvalds 已提交
12 13 14 15
#include <sound/asound.h>

#define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data)

16 17 18 19
struct snd_kcontrol;
typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
20
typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
21
				    int op_flag, /* SNDRV_CTL_TLV_OP_XXX */
22 23 24
				    unsigned int size,
				    unsigned int __user *tlv);

25 26 27 28 29 30 31 32 33 34
/* internal flag for skipping validations */
#ifdef CONFIG_SND_CTL_VALIDATION
#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK	(1 << 27)
#define snd_ctl_skip_validation(info) \
	((info)->access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK)
#else
#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK	0
#define snd_ctl_skip_validation(info)		true
#endif

35 36 37 38 39
enum {
	SNDRV_CTL_TLV_OP_READ = 0,
	SNDRV_CTL_TLV_OP_WRITE = 1,
	SNDRV_CTL_TLV_OP_CMD = -1,
};
L
Linus Torvalds 已提交
40

41
struct snd_kcontrol_new {
L
Linus Torvalds 已提交
42 43 44
	snd_ctl_elem_iface_t iface;	/* interface identifier */
	unsigned int device;		/* device/client number */
	unsigned int subdevice;		/* subdevice (substream) number */
45
	const unsigned char *name;	/* ASCII name of item */
L
Linus Torvalds 已提交
46 47 48 49 50 51
	unsigned int index;		/* index of item */
	unsigned int access;		/* access rights */
	unsigned int count;		/* count of same elements */
	snd_kcontrol_info_t *info;
	snd_kcontrol_get_t *get;
	snd_kcontrol_put_t *put;
52 53
	union {
		snd_kcontrol_tlv_rw_t *c;
54
		const unsigned int *p;
55
	} tlv;
L
Linus Torvalds 已提交
56
	unsigned long private_value;
57
};
L
Linus Torvalds 已提交
58

59 60
struct snd_kcontrol_volatile {
	struct snd_ctl_file *owner;	/* locked */
L
Linus Torvalds 已提交
61
	unsigned int access;	/* access rights */
62
};
L
Linus Torvalds 已提交
63

64
struct snd_kcontrol {
L
Linus Torvalds 已提交
65
	struct list_head list;		/* list of controls */
66
	struct snd_ctl_elem_id id;
L
Linus Torvalds 已提交
67 68 69 70
	unsigned int count;		/* count of same elements */
	snd_kcontrol_info_t *info;
	snd_kcontrol_get_t *get;
	snd_kcontrol_put_t *put;
71 72
	union {
		snd_kcontrol_tlv_rw_t *c;
73
		const unsigned int *p;
74
	} tlv;
L
Linus Torvalds 已提交
75 76
	unsigned long private_value;
	void *private_data;
77
	void (*private_free)(struct snd_kcontrol *kcontrol);
78
	struct snd_kcontrol_volatile vd[];	/* volatile data */
L
Linus Torvalds 已提交
79 80
};

81
#define snd_kcontrol(n) list_entry(n, struct snd_kcontrol, list)
L
Linus Torvalds 已提交
82

83
struct snd_kctl_event {
L
Linus Torvalds 已提交
84
	struct list_head list;	/* list of events */
85
	struct snd_ctl_elem_id id;
L
Linus Torvalds 已提交
86
	unsigned int mask;
87
};
L
Linus Torvalds 已提交
88

89
#define snd_kctl_event(n) list_entry(n, struct snd_kctl_event, list)
L
Linus Torvalds 已提交
90

91 92
struct pid;

93 94 95 96 97 98
enum {
	SND_CTL_SUBDEV_PCM,
	SND_CTL_SUBDEV_RAWMIDI,
	SND_CTL_SUBDEV_ITEMS,
};

99
struct snd_ctl_file {
L
Linus Torvalds 已提交
100
	struct list_head list;		/* list of all control files */
101
	struct snd_card *card;
102
	struct pid *pid;
103
	int preferred_subdevice[SND_CTL_SUBDEV_ITEMS];
L
Linus Torvalds 已提交
104 105 106 107 108 109 110
	wait_queue_head_t change_sleep;
	spinlock_t read_lock;
	struct fasync_struct *fasync;
	int subscribed;			/* read interface is activated */
	struct list_head events;	/* waiting events for read */
};

111
#define snd_ctl_file(n) list_entry(n, struct snd_ctl_file, list)
L
Linus Torvalds 已提交
112

113 114 115
typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card,
				      struct snd_ctl_file * control,
				      unsigned int cmd, unsigned long arg);
L
Linus Torvalds 已提交
116

117
void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id);
L
Linus Torvalds 已提交
118

119 120 121 122
struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);
void snd_ctl_free_one(struct snd_kcontrol * kcontrol);
int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol);
int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol);
123
int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace);
124 125
int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
T
Takashi Iwai 已提交
126 127
int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
			int active);
128 129
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid);
struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id);
L
Linus Torvalds 已提交
130

131
int snd_ctl_create(struct snd_card *card);
L
Linus Torvalds 已提交
132 133 134 135 136 137 138 139 140 141 142

int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
#ifdef CONFIG_COMPAT
int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn);
int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
#else
#define snd_ctl_register_ioctl_compat(fcn)
#define snd_ctl_unregister_ioctl_compat(fcn)
#endif

143 144
int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type);

145
static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
L
Linus Torvalds 已提交
146
{
147 148
	unsigned int ioff = id->numid - kctl->id.numid;
	return array_index_nospec(ioff, kctl->count);
L
Linus Torvalds 已提交
149 150
}

151
static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
L
Linus Torvalds 已提交
152
{
153 154
	unsigned int ioff = id->index - kctl->id.index;
	return array_index_nospec(ioff, kctl->count);
L
Linus Torvalds 已提交
155 156
}

157
static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
L
Linus Torvalds 已提交
158 159 160 161 162 163 164 165
{
	if (id->numid) {
		return snd_ctl_get_ioffnum(kctl, id);
	} else {
		return snd_ctl_get_ioffidx(kctl, id);
	}
}

166 167
static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id *dst_id,
						    struct snd_kcontrol *src_kctl,
L
Linus Torvalds 已提交
168 169 170 171 172 173 174 175
						    unsigned int offset)
{
	*dst_id = src_kctl->id;
	dst_id->index += offset;
	dst_id->numid += offset;
	return dst_id;
}

176
/*
177
 * Frequently used control callbacks/helpers
178 179 180 181 182
 */
int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
			      struct snd_ctl_elem_info *uinfo);
int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_info *uinfo);
183 184
int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
		      unsigned int items, const char *const names[]);
185

186 187 188 189 190
/*
 * virtual master control
 */
struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
						 const unsigned int *tlv);
191 192 193 194 195
int _snd_ctl_add_follower(struct snd_kcontrol *master,
			  struct snd_kcontrol *follower,
			  unsigned int flags);
/* optional flags for follower */
#define SND_CTL_FOLLOWER_NEED_UPDATE	(1 << 0)
196

197
/**
198
 * snd_ctl_add_follower - Add a virtual follower control
199
 * @master: vmaster element
200
 * @follower: follower element to add
201
 *
202
 * Add a virtual follower control to the given master element created via
203 204
 * snd_ctl_create_virtual_master() beforehand.
 *
205
 * All followers must be the same type (returning the same information
L
Lucas De Marchi 已提交
206
 * via info callback).  The function doesn't check it, so it's your
207 208 209 210 211 212
 * responsibility.
 *
 * Also, some additional limitations:
 * at most two channels,
 * logarithmic volume control (dB level) thus no linear volume,
 * master can only attenuate the volume without gain
213 214
 *
 * Return: Zero if successful or a negative error code.
215
 */
216
static inline int
217
snd_ctl_add_follower(struct snd_kcontrol *master, struct snd_kcontrol *follower)
218
{
219
	return _snd_ctl_add_follower(master, follower, 0);
220 221
}

222
/**
223
 * snd_ctl_add_follower_uncached - Add a virtual follower control
224
 * @master: vmaster element
225
 * @follower: follower element to add
226
 *
227 228
 * Add a virtual follower control to the given master.
 * Unlike snd_ctl_add_follower(), the element added via this function
229
 * is supposed to have volatile values, and get callback is called
230
 * at each time queried from the master.
231 232 233 234
 *
 * When the control peeks the hardware values directly and the value
 * can be changed by other means than the put callback of the element,
 * this function should be used to keep the value always up-to-date.
235 236
 *
 * Return: Zero if successful or a negative error code.
237
 */
238
static inline int
239 240
snd_ctl_add_follower_uncached(struct snd_kcontrol *master,
			      struct snd_kcontrol *follower)
241
{
242
	return _snd_ctl_add_follower(master, follower, SND_CTL_FOLLOWER_NEED_UPDATE);
243 244
}

245 246 247
int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl,
			     void (*hook)(void *private_data, int),
			     void *private_data);
248 249
void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only);
#define snd_ctl_sync_vmaster_hook(kctl)	snd_ctl_sync_vmaster(kctl, true)
250 251 252 253 254
int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl,
				    int (*func)(struct snd_kcontrol *vfollower,
						struct snd_kcontrol *follower,
						void *arg),
				    void *arg);
255

256 257 258 259
/*
 * Helper functions for jack-detection controls
 */
struct snd_kcontrol *
260
snd_kctl_jack_new(const char *name, struct snd_card *card);
261 262 263
void snd_kctl_jack_report(struct snd_card *card,
			  struct snd_kcontrol *kctl, bool status);

L
Linus Torvalds 已提交
264
#endif	/* __SOUND_CONTROL_H */