brintos

brintos / linux-shallow public Read only

0
0
Text · 10.6 KiB · e07f6b9 Raw
320 lines · c
1/* SPDX-License-Identifier: GPL-2.0-or-later */2#ifndef __SOUND_CONTROL_H3#define __SOUND_CONTROL_H4 5/*6 *  Header file for control interface7 *  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_DEBUG27#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#else31#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK	032#define snd_ctl_skip_validation(info)		true33#endif34 35/* kernel only - LED bits */36#define SNDRV_CTL_ELEM_ACCESS_LED_SHIFT		2537#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[] __counted_by(count);	/* 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 snd_fasync *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);141void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name);142int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active);143struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid);144struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id);145 146/**147 * snd_ctl_find_id_mixer - find the control instance with the given name string148 * @card: the card instance149 * @name: the name string150 *151 * Finds the control instance with the given name and152 * @SNDRV_CTL_ELEM_IFACE_MIXER. Other fields are set to zero.153 *154 * This is merely a wrapper to snd_ctl_find_id().155 *156 * Return: The pointer of the instance if found, or %NULL if not.157 */158static inline struct snd_kcontrol *159snd_ctl_find_id_mixer(struct snd_card *card, const char *name)160{161	struct snd_ctl_elem_id id = {};162 163	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;164	strscpy(id.name, name, sizeof(id.name));165	return snd_ctl_find_id(card, &id);166}167 168int snd_ctl_create(struct snd_card *card);169 170int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);171int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);172#ifdef CONFIG_COMPAT173int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn);174int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);175#else176#define snd_ctl_register_ioctl_compat(fcn)177#define snd_ctl_unregister_ioctl_compat(fcn)178#endif179 180int snd_ctl_request_layer(const char *module_name);181void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops);182void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops);183 184int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type);185 186static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)187{188	unsigned int ioff = id->numid - kctl->id.numid;189	return array_index_nospec(ioff, kctl->count);190}191 192static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)193{194	unsigned int ioff = id->index - kctl->id.index;195	return array_index_nospec(ioff, kctl->count);196}197 198static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)199{200	if (id->numid) {201		return snd_ctl_get_ioffnum(kctl, id);202	} else {203		return snd_ctl_get_ioffidx(kctl, id);204	}205}206 207static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id *dst_id,208						    struct snd_kcontrol *src_kctl,209						    unsigned int offset)210{211	*dst_id = src_kctl->id;212	dst_id->index += offset;213	dst_id->numid += offset;214	return dst_id;215}216 217/*218 * Frequently used control callbacks/helpers219 */220int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,221			      struct snd_ctl_elem_info *uinfo);222int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,223				struct snd_ctl_elem_info *uinfo);224int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,225		      unsigned int items, const char *const names[]);226 227/*228 * virtual master control229 */230struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,231						 const unsigned int *tlv);232int _snd_ctl_add_follower(struct snd_kcontrol *master,233			  struct snd_kcontrol *follower,234			  unsigned int flags);235/* optional flags for follower */236#define SND_CTL_FOLLOWER_NEED_UPDATE	(1 << 0)237 238/**239 * snd_ctl_add_follower - Add a virtual follower control240 * @master: vmaster element241 * @follower: follower element to add242 *243 * Add a virtual follower control to the given master element created via244 * snd_ctl_create_virtual_master() beforehand.245 *246 * All followers must be the same type (returning the same information247 * via info callback).  The function doesn't check it, so it's your248 * responsibility.249 *250 * Also, some additional limitations:251 * at most two channels,252 * logarithmic volume control (dB level) thus no linear volume,253 * master can only attenuate the volume without gain254 *255 * Return: Zero if successful or a negative error code.256 */257static inline int258snd_ctl_add_follower(struct snd_kcontrol *master, struct snd_kcontrol *follower)259{260	return _snd_ctl_add_follower(master, follower, 0);261}262 263int snd_ctl_add_followers(struct snd_card *card, struct snd_kcontrol *master,264			  const char * const *list);265 266/**267 * snd_ctl_add_follower_uncached - Add a virtual follower control268 * @master: vmaster element269 * @follower: follower element to add270 *271 * Add a virtual follower control to the given master.272 * Unlike snd_ctl_add_follower(), the element added via this function273 * is supposed to have volatile values, and get callback is called274 * at each time queried from the master.275 *276 * When the control peeks the hardware values directly and the value277 * can be changed by other means than the put callback of the element,278 * this function should be used to keep the value always up-to-date.279 *280 * Return: Zero if successful or a negative error code.281 */282static inline int283snd_ctl_add_follower_uncached(struct snd_kcontrol *master,284			      struct snd_kcontrol *follower)285{286	return _snd_ctl_add_follower(master, follower, SND_CTL_FOLLOWER_NEED_UPDATE);287}288 289int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl,290			     void (*hook)(void *private_data, int),291			     void *private_data);292void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only);293#define snd_ctl_sync_vmaster_hook(kctl)	snd_ctl_sync_vmaster(kctl, true)294int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl,295				    int (*func)(struct snd_kcontrol *vfollower,296						struct snd_kcontrol *follower,297						void *arg),298				    void *arg);299 300/*301 * Control LED trigger layer302 */303#define SND_CTL_LAYER_MODULE_LED	"snd-ctl-led"304 305#if IS_MODULE(CONFIG_SND_CTL_LED)306static inline int snd_ctl_led_request(void) { return snd_ctl_request_layer(SND_CTL_LAYER_MODULE_LED); }307#else308static inline int snd_ctl_led_request(void) { return 0; }309#endif310 311/*312 * Helper functions for jack-detection controls313 */314struct snd_kcontrol *315snd_kctl_jack_new(const char *name, struct snd_card *card);316void snd_kctl_jack_report(struct snd_card *card,317			  struct snd_kcontrol *kctl, bool status);318 319#endif	/* __SOUND_CONTROL_H */320