11a59d1b8SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-or-later */ 21da177e4SLinus Torvalds #ifndef __SOUND_CONTROL_H 31da177e4SLinus Torvalds #define __SOUND_CONTROL_H 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds /* 61da177e4SLinus Torvalds * Header file for control interface 7c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 10b69339baSIngo Molnar #include <linux/wait.h> 11088e861eSTakashi Iwai #include <linux/nospec.h> 121da177e4SLinus Torvalds #include <sound/asound.h> 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data) 151da177e4SLinus Torvalds 1682e9bae6STakashi Iwai struct snd_kcontrol; 1782e9bae6STakashi Iwai typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo); 1882e9bae6STakashi Iwai typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol); 1982e9bae6STakashi Iwai typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol); 208aa9b586SJaroslav Kysela typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol, 210cea76f3STakashi Iwai int op_flag, /* SNDRV_CTL_TLV_OP_XXX */ 228aa9b586SJaroslav Kysela unsigned int size, 238aa9b586SJaroslav Kysela unsigned int __user *tlv); 248aa9b586SJaroslav Kysela 25fbd3eb7fSTakashi Iwai /* internal flag for skipping validations */ 26fbd3eb7fSTakashi Iwai #ifdef CONFIG_SND_CTL_VALIDATION 27fbd3eb7fSTakashi Iwai #define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK (1 << 27) 28fbd3eb7fSTakashi Iwai #define snd_ctl_skip_validation(info) \ 29fbd3eb7fSTakashi Iwai ((info)->access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK) 30fbd3eb7fSTakashi Iwai #else 31fbd3eb7fSTakashi Iwai #define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK 0 32fbd3eb7fSTakashi Iwai #define snd_ctl_skip_validation(info) true 33fbd3eb7fSTakashi Iwai #endif 34fbd3eb7fSTakashi Iwai 350cea76f3STakashi Iwai enum { 360cea76f3STakashi Iwai SNDRV_CTL_TLV_OP_READ = 0, 370cea76f3STakashi Iwai SNDRV_CTL_TLV_OP_WRITE = 1, 380cea76f3STakashi Iwai SNDRV_CTL_TLV_OP_CMD = -1, 390cea76f3STakashi Iwai }; 401da177e4SLinus Torvalds 4182e9bae6STakashi Iwai struct snd_kcontrol_new { 421da177e4SLinus Torvalds snd_ctl_elem_iface_t iface; /* interface identifier */ 431da177e4SLinus Torvalds unsigned int device; /* device/client number */ 441da177e4SLinus Torvalds unsigned int subdevice; /* subdevice (substream) number */ 455ac2ba94SMark Brown const unsigned char *name; /* ASCII name of item */ 461da177e4SLinus Torvalds unsigned int index; /* index of item */ 471da177e4SLinus Torvalds unsigned int access; /* access rights */ 481da177e4SLinus Torvalds unsigned int count; /* count of same elements */ 491da177e4SLinus Torvalds snd_kcontrol_info_t *info; 501da177e4SLinus Torvalds snd_kcontrol_get_t *get; 511da177e4SLinus Torvalds snd_kcontrol_put_t *put; 528aa9b586SJaroslav Kysela union { 538aa9b586SJaroslav Kysela snd_kcontrol_tlv_rw_t *c; 540cb29ea0STakashi Iwai const unsigned int *p; 558aa9b586SJaroslav Kysela } tlv; 561da177e4SLinus Torvalds unsigned long private_value; 5782e9bae6STakashi Iwai }; 581da177e4SLinus Torvalds 5982e9bae6STakashi Iwai struct snd_kcontrol_volatile { 6082e9bae6STakashi Iwai struct snd_ctl_file *owner; /* locked */ 611da177e4SLinus Torvalds unsigned int access; /* access rights */ 6282e9bae6STakashi Iwai }; 631da177e4SLinus Torvalds 6482e9bae6STakashi Iwai struct snd_kcontrol { 651da177e4SLinus Torvalds struct list_head list; /* list of controls */ 6682e9bae6STakashi Iwai struct snd_ctl_elem_id id; 671da177e4SLinus Torvalds unsigned int count; /* count of same elements */ 681da177e4SLinus Torvalds snd_kcontrol_info_t *info; 691da177e4SLinus Torvalds snd_kcontrol_get_t *get; 701da177e4SLinus Torvalds snd_kcontrol_put_t *put; 718aa9b586SJaroslav Kysela union { 728aa9b586SJaroslav Kysela snd_kcontrol_tlv_rw_t *c; 730cb29ea0STakashi Iwai const unsigned int *p; 748aa9b586SJaroslav Kysela } tlv; 751da177e4SLinus Torvalds unsigned long private_value; 761da177e4SLinus Torvalds void *private_data; 7782e9bae6STakashi Iwai void (*private_free)(struct snd_kcontrol *kcontrol); 789ad06ebbSGustavo A. R. Silva struct snd_kcontrol_volatile vd[]; /* volatile data */ 791da177e4SLinus Torvalds }; 801da177e4SLinus Torvalds 8182e9bae6STakashi Iwai #define snd_kcontrol(n) list_entry(n, struct snd_kcontrol, list) 821da177e4SLinus Torvalds 8382e9bae6STakashi Iwai struct snd_kctl_event { 841da177e4SLinus Torvalds struct list_head list; /* list of events */ 8582e9bae6STakashi Iwai struct snd_ctl_elem_id id; 861da177e4SLinus Torvalds unsigned int mask; 8782e9bae6STakashi Iwai }; 881da177e4SLinus Torvalds 8982e9bae6STakashi Iwai #define snd_kctl_event(n) list_entry(n, struct snd_kctl_event, list) 901da177e4SLinus Torvalds 9125d27edeSClemens Ladisch struct pid; 9225d27edeSClemens Ladisch 9323c18d4bSTakashi Iwai enum { 9423c18d4bSTakashi Iwai SND_CTL_SUBDEV_PCM, 9523c18d4bSTakashi Iwai SND_CTL_SUBDEV_RAWMIDI, 9623c18d4bSTakashi Iwai SND_CTL_SUBDEV_ITEMS, 9723c18d4bSTakashi Iwai }; 9823c18d4bSTakashi Iwai 9982e9bae6STakashi Iwai struct snd_ctl_file { 1001da177e4SLinus Torvalds struct list_head list; /* list of all control files */ 10182e9bae6STakashi Iwai struct snd_card *card; 10225d27edeSClemens Ladisch struct pid *pid; 10323c18d4bSTakashi Iwai int preferred_subdevice[SND_CTL_SUBDEV_ITEMS]; 1041da177e4SLinus Torvalds wait_queue_head_t change_sleep; 1051da177e4SLinus Torvalds spinlock_t read_lock; 1061da177e4SLinus Torvalds struct fasync_struct *fasync; 1071da177e4SLinus Torvalds int subscribed; /* read interface is activated */ 1081da177e4SLinus Torvalds struct list_head events; /* waiting events for read */ 1091da177e4SLinus Torvalds }; 1101da177e4SLinus Torvalds 11182e9bae6STakashi Iwai #define snd_ctl_file(n) list_entry(n, struct snd_ctl_file, list) 1121da177e4SLinus Torvalds 11382e9bae6STakashi Iwai typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card, 11482e9bae6STakashi Iwai struct snd_ctl_file * control, 1151da177e4SLinus Torvalds unsigned int cmd, unsigned long arg); 1161da177e4SLinus Torvalds 11782e9bae6STakashi Iwai void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id); 1181da177e4SLinus Torvalds 11982e9bae6STakashi Iwai struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data); 12082e9bae6STakashi Iwai void snd_ctl_free_one(struct snd_kcontrol * kcontrol); 12182e9bae6STakashi Iwai int snd_ctl_add(struct snd_card * card, struct snd_kcontrol * kcontrol); 12282e9bae6STakashi Iwai int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol); 12366b5b972SDimitris Papastamos int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace); 12482e9bae6STakashi Iwai int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id); 12582e9bae6STakashi Iwai int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id); 1263cbdd753STakashi Iwai int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, 1273cbdd753STakashi Iwai int active); 12882e9bae6STakashi Iwai struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid); 12982e9bae6STakashi Iwai struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id); 1301da177e4SLinus Torvalds 13182e9bae6STakashi Iwai int snd_ctl_create(struct snd_card *card); 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn); 1341da177e4SLinus Torvalds int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn); 1351da177e4SLinus Torvalds #ifdef CONFIG_COMPAT 1361da177e4SLinus Torvalds int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn); 1371da177e4SLinus Torvalds int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn); 1381da177e4SLinus Torvalds #else 1391da177e4SLinus Torvalds #define snd_ctl_register_ioctl_compat(fcn) 1401da177e4SLinus Torvalds #define snd_ctl_unregister_ioctl_compat(fcn) 1411da177e4SLinus Torvalds #endif 1421da177e4SLinus Torvalds 14323c18d4bSTakashi Iwai int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type); 14423c18d4bSTakashi Iwai 14582e9bae6STakashi Iwai static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) 1461da177e4SLinus Torvalds { 147088e861eSTakashi Iwai unsigned int ioff = id->numid - kctl->id.numid; 148088e861eSTakashi Iwai return array_index_nospec(ioff, kctl->count); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 15182e9bae6STakashi Iwai static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) 1521da177e4SLinus Torvalds { 153088e861eSTakashi Iwai unsigned int ioff = id->index - kctl->id.index; 154088e861eSTakashi Iwai return array_index_nospec(ioff, kctl->count); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 15782e9bae6STakashi Iwai static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) 1581da177e4SLinus Torvalds { 1591da177e4SLinus Torvalds if (id->numid) { 1601da177e4SLinus Torvalds return snd_ctl_get_ioffnum(kctl, id); 1611da177e4SLinus Torvalds } else { 1621da177e4SLinus Torvalds return snd_ctl_get_ioffidx(kctl, id); 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 16682e9bae6STakashi Iwai static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id *dst_id, 16782e9bae6STakashi Iwai struct snd_kcontrol *src_kctl, 1681da177e4SLinus Torvalds unsigned int offset) 1691da177e4SLinus Torvalds { 1701da177e4SLinus Torvalds *dst_id = src_kctl->id; 1711da177e4SLinus Torvalds dst_id->index += offset; 1721da177e4SLinus Torvalds dst_id->numid += offset; 1731da177e4SLinus Torvalds return dst_id; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 176b9ed4f2bSTakashi Iwai /* 1779600732bSClemens Ladisch * Frequently used control callbacks/helpers 178b9ed4f2bSTakashi Iwai */ 179b9ed4f2bSTakashi Iwai int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, 180b9ed4f2bSTakashi Iwai struct snd_ctl_elem_info *uinfo); 181b9ed4f2bSTakashi Iwai int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, 182b9ed4f2bSTakashi Iwai struct snd_ctl_elem_info *uinfo); 1839600732bSClemens Ladisch int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, 1849600732bSClemens Ladisch unsigned int items, const char *const names[]); 185b9ed4f2bSTakashi Iwai 186e922b002STakashi Iwai /* 187e922b002STakashi Iwai * virtual master control 188e922b002STakashi Iwai */ 189e922b002STakashi Iwai struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, 190e922b002STakashi Iwai const unsigned int *tlv); 191f5b1db63STakashi Iwai int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave, 192f5b1db63STakashi Iwai unsigned int flags); 193f5b1db63STakashi Iwai /* optional flags for slave */ 194f5b1db63STakashi Iwai #define SND_CTL_SLAVE_NEED_UPDATE (1 << 0) 195f5b1db63STakashi Iwai 19679c7cdd5STakashi Iwai /** 19779c7cdd5STakashi Iwai * snd_ctl_add_slave - Add a virtual slave control 19879c7cdd5STakashi Iwai * @master: vmaster element 19979c7cdd5STakashi Iwai * @slave: slave element to add 20079c7cdd5STakashi Iwai * 20179c7cdd5STakashi Iwai * Add a virtual slave control to the given master element created via 20279c7cdd5STakashi Iwai * snd_ctl_create_virtual_master() beforehand. 20379c7cdd5STakashi Iwai * 20479c7cdd5STakashi Iwai * All slaves must be the same type (returning the same information 20525985edcSLucas De Marchi * via info callback). The function doesn't check it, so it's your 20679c7cdd5STakashi Iwai * responsibility. 20779c7cdd5STakashi Iwai * 20879c7cdd5STakashi Iwai * Also, some additional limitations: 20979c7cdd5STakashi Iwai * at most two channels, 21079c7cdd5STakashi Iwai * logarithmic volume control (dB level) thus no linear volume, 21179c7cdd5STakashi Iwai * master can only attenuate the volume without gain 212eb7c06e8SYacine Belkadi * 213eb7c06e8SYacine Belkadi * Return: Zero if successful or a negative error code. 21479c7cdd5STakashi Iwai */ 215f5b1db63STakashi Iwai static inline int 216f5b1db63STakashi Iwai snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) 217f5b1db63STakashi Iwai { 218f5b1db63STakashi Iwai return _snd_ctl_add_slave(master, slave, 0); 219f5b1db63STakashi Iwai } 220f5b1db63STakashi Iwai 22179c7cdd5STakashi Iwai /** 22279c7cdd5STakashi Iwai * snd_ctl_add_slave_uncached - Add a virtual slave control 22379c7cdd5STakashi Iwai * @master: vmaster element 22479c7cdd5STakashi Iwai * @slave: slave element to add 22579c7cdd5STakashi Iwai * 22679c7cdd5STakashi Iwai * Add a virtual slave control to the given master. 22779c7cdd5STakashi Iwai * Unlike snd_ctl_add_slave(), the element added via this function 22879c7cdd5STakashi Iwai * is supposed to have volatile values, and get callback is called 2291a6ab46fSMasanari Iida * at each time queried from the master. 23079c7cdd5STakashi Iwai * 23179c7cdd5STakashi Iwai * When the control peeks the hardware values directly and the value 23279c7cdd5STakashi Iwai * can be changed by other means than the put callback of the element, 23379c7cdd5STakashi Iwai * this function should be used to keep the value always up-to-date. 234eb7c06e8SYacine Belkadi * 235eb7c06e8SYacine Belkadi * Return: Zero if successful or a negative error code. 23679c7cdd5STakashi Iwai */ 237f5b1db63STakashi Iwai static inline int 238f5b1db63STakashi Iwai snd_ctl_add_slave_uncached(struct snd_kcontrol *master, 239f5b1db63STakashi Iwai struct snd_kcontrol *slave) 240f5b1db63STakashi Iwai { 241f5b1db63STakashi Iwai return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE); 242f5b1db63STakashi Iwai } 243e922b002STakashi Iwai 2442ad787e9STakashi Iwai int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl, 2452ad787e9STakashi Iwai void (*hook)(void *private_data, int), 2462ad787e9STakashi Iwai void *private_data); 2471ca2f2ecSTakashi Iwai void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only); 2481ca2f2ecSTakashi Iwai #define snd_ctl_sync_vmaster_hook(kctl) snd_ctl_sync_vmaster(kctl, true) 249a91d6612STakashi Iwai int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl, 250d6c0615fSTakashi Iwai int (*func)(struct snd_kcontrol *vslave, 251d6c0615fSTakashi Iwai struct snd_kcontrol *slave, 252d6c0615fSTakashi Iwai void *arg), 253a91d6612STakashi Iwai void *arg); 2542ad787e9STakashi Iwai 25535be544aSTakashi Iwai /* 25635be544aSTakashi Iwai * Helper functions for jack-detection controls 25735be544aSTakashi Iwai */ 25835be544aSTakashi Iwai struct snd_kcontrol * 2592ba2dfa1SJie Yang snd_kctl_jack_new(const char *name, struct snd_card *card); 26035be544aSTakashi Iwai void snd_kctl_jack_report(struct snd_card *card, 26135be544aSTakashi Iwai struct snd_kcontrol *kctl, bool status); 26235be544aSTakashi Iwai 2631da177e4SLinus Torvalds #endif /* __SOUND_CONTROL_H */ 264