From ab69a4904b5dd4d7cd6996587ba066bca8d13838 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 15 Nov 2010 10:46:23 +0100 Subject: ALSA: pcm: support for period wakeup disabling This patch allows to disable period interrupts which are not needed when the application relies on a system timer to wake-up and refill the ring buffer. The behavior of the driver is left unchanged, and interrupts are only disabled if the application requests this configuration. The behavior in case of underruns is slightly different, instead of being detected during the period interrupts the underruns are detected when the application calls snd_pcm_update_avail, which in turns forces a refresh of the hw pointer and shows the buffer is empty. More specifically this patch makes a lot of sense when PulseAudio relies on timer-based scheduling to access audio devices such as HDAudio or Intel SST. Disabling interrupts removes two unwanted wake-ups due to period elapsed events in low-power playback modes. It also simplifies PulseAudio voice modules used for speech calls. To quote Lennart "This patch looks very interesting and desirable. This is something have long been waiting for." Support for this in hardware drivers is optional. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 6 ++++++ sound/core/pcm_native.c | 3 +++ 2 files changed, 9 insertions(+) (limited to 'sound/core') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b75db8e9cc0f..bc57501c584a 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -373,6 +373,11 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (unsigned long)new_hw_ptr, (unsigned long)runtime->hw_ptr_base); } + + /* without period interrupts, there are no regular pointer updates */ + if (runtime->no_period_wakeup) + goto no_delta_check; + /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { hw_ptr_error(substream, @@ -442,6 +447,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (long)old_hw_ptr); } + no_delta_check: if (runtime->status->hw_ptr == new_hw_ptr) return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8bc7cb3db330..f91a439f675c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -423,6 +423,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, runtime->info = params->info; runtime->rate_num = params->rate_num; runtime->rate_den = params->rate_den; + runtime->no_period_wakeup = + (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && + (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); bits = snd_pcm_format_physical_width(runtime->format); runtime->sample_bits = bits; -- cgit v1.2.3-58-ga151 From 59ff878ffb26bc0be812ca8295799164f413ae88 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 18 Nov 2010 09:43:52 +0100 Subject: ALSA: pcm: detect xruns in no-period-wakeup mode When period wakeups are disabled, successive calls to the pointer update function do not have a maximum allowed distance, so xruns cannot be detected with the pointer value only. To detect xruns, compare the actually elapsed time with the time that should have theoretically elapsed since the last update. When the hardware pointer has wrapped around due to an xrun, the actually elapsed time will be too big by about hw_ptr_buffer_jiffies. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sound/core') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index bc57501c584a..e9debaabf376 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -374,9 +374,23 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (unsigned long)runtime->hw_ptr_base); } - /* without period interrupts, there are no regular pointer updates */ - if (runtime->no_period_wakeup) + if (runtime->no_period_wakeup) { + /* + * Without regular period interrupts, we have to check + * the elapsed time to detect xruns. + */ + jdelta = jiffies - runtime->hw_ptr_jiffies; + hdelta = jdelta - delta * HZ / runtime->rate; + while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) { + delta += runtime->buffer_size; + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + hdelta -= runtime->hw_ptr_buffer_jiffies; + } goto no_delta_check; + } /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { -- cgit v1.2.3-58-ga151 From 47228e48aecdbec423a1275a5e27697d47f1f912 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 18 Nov 2010 09:53:07 +0100 Subject: ALSA: pcm: optimize xrun detection in no-period-wakeup mode Add a lightweight condition on top of the xrun checking so that we can avoid the division when the application is calling the update function often enough. Suggested-by: Jaroslav Kysela Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/core') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e9debaabf376..fd18c3c6484f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -380,6 +380,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, * the elapsed time to detect xruns. */ jdelta = jiffies - runtime->hw_ptr_jiffies; + if (jdelta < runtime->hw_ptr_buffer_jiffies / 2) + goto no_delta_check; hdelta = jdelta - delta * HZ / runtime->rate; while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) { delta += runtime->buffer_size; -- cgit v1.2.3-58-ga151 From 109fef9edcc100952eec980acbc2e1295627fbab Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 18 Nov 2010 09:53:54 +0100 Subject: ALSA: timer: automatically load the high-resolution timer Increase the default timer limit so that snd-hrtimer.ko can be automatically loaded when needed, e.g., when used as the default sequencer timer. This replaces the check for the obsolete CONFIG_SND_HPET. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/timer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/core') diff --git a/sound/core/timer.c b/sound/core/timer.c index 13afb60999b9..b3aaa600dcc2 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -34,8 +34,8 @@ #include #include -#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE) -#define DEFAULT_TIMER_LIMIT 3 +#if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE) +#define DEFAULT_TIMER_LIMIT 4 #elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE) #define DEFAULT_TIMER_LIMIT 2 #else -- cgit v1.2.3-58-ga151 From 03cfe6f57dc5c13ccdd235c23c80e3fa170f03d1 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 23 Nov 2010 17:43:19 +0100 Subject: ALSA: support module on-demand loading for seq and timer If CONFIG_SND_DYNAMIC_MINORS is used, assign /dev/snd/seq and /dev/snd/timer the usual static minors, and export specific module aliases to generate udev module on-demand loading instructions: $ cat /lib/modules/2.6.33.4-smp/modules.devname # Device nodes to trigger on-demand module loading. microcode cpu/microcode c10:184 fuse fuse c10:229 ppp_generic ppp c108:0 tun net/tun c10:200 uinput uinput c10:223 dm_mod mapper/control c10:236 snd_timer snd/timer c116:33 snd_seq snd/seq c116:1 The last two lines instruct udev to create device nodes, even when the modules are not loaded at that time. As soon as userspace accesses any of these nodes, the in-kernel module-loader will load the module, and the device can be used. The header file minor calculation needed to be simplified to make __stringify() (supports only two indirections) in the MODULE_ALIAS macro work. This is part of systemd's effort to get rid of unconditional module load instructions and needless init scripts. Cc: Lennart Poettering Signed-off-by: Kay Sievers Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- include/sound/minors.h | 4 ++-- sound/core/seq/seq.c | 4 ++++ sound/core/sound.c | 18 +++++++++++++----- sound/core/timer.c | 3 +++ 4 files changed, 22 insertions(+), 7 deletions(-) (limited to 'sound/core') diff --git a/include/sound/minors.h b/include/sound/minors.h index a81798ab73ed..8f764204a856 100644 --- a/include/sound/minors.h +++ b/include/sound/minors.h @@ -31,8 +31,8 @@ /* these minors can still be used for autoloading devices (/dev/aload*) */ #define SNDRV_MINOR_CONTROL 0 /* 0 */ #define SNDRV_MINOR_GLOBAL 1 /* 1 */ -#define SNDRV_MINOR_SEQUENCER (SNDRV_MINOR_GLOBAL + 0 * 32) -#define SNDRV_MINOR_TIMER (SNDRV_MINOR_GLOBAL + 1 * 32) +#define SNDRV_MINOR_SEQUENCER 1 /* SNDRV_MINOR_GLOBAL + 0 * 32 */ +#define SNDRV_MINOR_TIMER 33 /* SNDRV_MINOR_GLOBAL + 1 * 32 */ #ifndef CONFIG_SND_DYNAMIC_MINORS /* 2 - 3 (reserved) */ diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index bf09a5ad1865..119fddb6fc99 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -32,6 +32,7 @@ #include "seq_timer.h" #include "seq_system.h" #include "seq_info.h" +#include #include #if defined(CONFIG_SND_SEQ_DUMMY_MODULE) @@ -73,6 +74,9 @@ MODULE_PARM_DESC(seq_default_timer_subdevice, "The default timer subdevice numbe module_param(seq_default_timer_resolution, int, 0644); MODULE_PARM_DESC(seq_default_timer_resolution, "The default timer resolution in Hz."); +MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_SEQUENCER); +MODULE_ALIAS("devname:snd/seq"); + /* * INIT PART */ diff --git a/sound/core/sound.c b/sound/core/sound.c index 62a093efb453..345caea2d749 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -189,14 +189,22 @@ static const struct file_operations snd_fops = }; #ifdef CONFIG_SND_DYNAMIC_MINORS -static int snd_find_free_minor(void) +static int snd_find_free_minor(int type) { int minor; + /* static minors for module auto loading */ + if (type == SNDRV_DEVICE_TYPE_SEQUENCER) + return SNDRV_MINOR_SEQUENCER; + if (type == SNDRV_DEVICE_TYPE_TIMER) + return SNDRV_MINOR_TIMER; + for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { - /* skip minors still used statically for autoloading devices */ - if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL || - minor == SNDRV_MINOR_SEQUENCER) + /* skip static minors still used for module auto loading */ + if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL) + continue; + if (minor == SNDRV_MINOR_SEQUENCER || + minor == SNDRV_MINOR_TIMER) continue; if (!snd_minors[minor]) return minor; @@ -270,7 +278,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, preg->private_data = private_data; mutex_lock(&sound_mutex); #ifdef CONFIG_SND_DYNAMIC_MINORS - minor = snd_find_free_minor(); + minor = snd_find_free_minor(type); #else minor = snd_kernel_minor(type, card, dev); if (minor >= 0 && snd_minors[minor]) diff --git a/sound/core/timer.c b/sound/core/timer.c index b3aaa600dcc2..ed016329e911 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -52,6 +52,9 @@ MODULE_PARM_DESC(timer_limit, "Maximum global timers in system."); module_param(timer_tstamp_monotonic, int, 0444); MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default)."); +MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER); +MODULE_ALIAS("devname:snd/timer"); + struct snd_timer_user { struct snd_timer_instance *timeri; int tread; /* enhanced read with timestamps and events */ -- cgit v1.2.3-58-ga151 From 3daa7ea650d59ae86926f0ced4c4ccd99ab33fda Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 6 Jan 2011 22:19:47 +0100 Subject: ALSA: Don't leak in sound/core/oss/pcm_oss.c::snd_pcm_hw_param_near() snd_pcm_hw_param_near() will leak the memory allocated to 'save' if the call to snd_pcm_hw_param_max() returns less than zero. This patch makes sure we never leak. Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/core') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index b753ec661fcf..a2e4eb324699 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -453,8 +453,10 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, } else { *params = *save; max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); - if (max < 0) + if (max < 0) { + kfree(save); return max; + } last = 1; } _end: -- cgit v1.2.3-58-ga151 From 9600732b6caba595f34acf2abd930098ec9a0b2b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 16:25:44 +0100 Subject: ALSA: core, oxygen, virtuoso: add an enum control info helper Introduce the helper function snd_ctl_enum_info() to fill out the elem_info fields for an enumerated control. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- include/sound/control.h | 4 +++- sound/core/control.c | 28 +++++++++++++++++++++++++++- sound/pci/oxygen/oxygen.c | 16 ++-------------- sound/pci/oxygen/oxygen_mixer.c | 15 ++------------- sound/pci/oxygen/xonar_cs43xx.c | 8 +------- sound/pci/oxygen/xonar_dg.c | 30 ++++-------------------------- sound/pci/oxygen/xonar_pcm179x.c | 24 +++--------------------- sound/pci/oxygen/xonar_wm87x6.c | 25 ++++--------------------- 8 files changed, 46 insertions(+), 104 deletions(-) (limited to 'sound/core') diff --git a/include/sound/control.h b/include/sound/control.h index 112374dc0c58..7715e6f00d38 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -160,12 +160,14 @@ static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id } /* - * Frequently used control callbacks + * Frequently used control callbacks/helpers */ 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); +int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, + unsigned int items, const char *const names[]); /* * virtual master control diff --git a/sound/core/control.c b/sound/core/control.c index 45a818002d99..9ce00ed20fba 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1488,7 +1488,7 @@ int snd_ctl_create(struct snd_card *card) } /* - * Frequently used control callbacks + * Frequently used control callbacks/helpers */ int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1513,3 +1513,29 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); + +/** + * snd_ctl_enum_info - fills the info structure for an enumerated control + * @info: the structure to be filled + * @channels: the number of the control's channels; often one + * @items: the number of control values; also the size of @names + * @names: an array containing the names of all control values + * + * Sets all required fields in @info to their appropriate values. + * If the control's accessibility is not the default (readable and writable), + * the caller has to fill @info->access. + */ +int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels, + unsigned int items, const char *const names[]) +{ + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = channels; + info->value.enumerated.items = items; + if (info->value.enumerated.item >= items) + info->value.enumerated.item = items - 1; + strlcpy(info->value.enumerated.name, + names[info->value.enumerated.item], + sizeof(info->value.enumerated.name)); + return 0; +} +EXPORT_SYMBOL(snd_ctl_enum_info); diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index b59aeefd14db..45427d85045e 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -415,13 +415,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, "Sharp Roll-off", "Slow Roll-off" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int rolloff_get(struct snd_kcontrol *ctl, @@ -473,13 +467,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) "None", "High-pass Filter" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index d327c36fbddf..821df1c9d1d0 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -119,13 +119,7 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) struct oxygen *chip = ctl->private_data; unsigned int count = upmix_item_count(chip); - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = count; - if (info->value.enumerated.item >= count) - info->value.enumerated.item = count - 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, count, names); } static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) @@ -659,12 +653,7 @@ static int mic_fmic_source_info(struct snd_kcontrol *ctl, { static const char *const names[] = { "Mic Jack", "Front Panel" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - info->value.enumerated.item &= 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int mic_fmic_source_get(struct snd_kcontrol *ctl, diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 55c52c7e19b2..9f72d424969c 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -298,13 +298,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, "Fast Roll-off", "Slow Roll-off" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int rolloff_get(struct snd_kcontrol *ctl, diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c index 7ed3284d7d5b..cc610ac1fc19 100644 --- a/sound/pci/oxygen/xonar_dg.c +++ b/sound/pci/oxygen/xonar_dg.c @@ -213,13 +213,7 @@ static int output_switch_info(struct snd_kcontrol *ctl, "Speakers", "Headphones", "FP Headphones" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 3, names); } static int output_switch_get(struct snd_kcontrol *ctl, @@ -276,13 +270,7 @@ static int hp_volume_offset_info(struct snd_kcontrol *ctl, "< 64 ohms", "64-150 ohms", "150-300 ohms" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 3, names); } static int hp_volume_offset_get(struct snd_kcontrol *ctl, @@ -390,12 +378,7 @@ static int input_sel_info(struct snd_kcontrol *ctl, "Mic", "Aux", "Front Mic", "Line" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 4; - info->value.enumerated.item &= 3; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 4, names); } static int input_sel_get(struct snd_kcontrol *ctl, @@ -453,12 +436,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { static const char *const names[2] = { "Active", "Frozen" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - info->value.enumerated.item &= 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index bf4fd4bb1359..54cad38ec30a 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -678,13 +678,7 @@ static int rolloff_info(struct snd_kcontrol *ctl, "Sharp Roll-off", "Slow Roll-off" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int rolloff_get(struct snd_kcontrol *ctl, @@ -748,13 +742,7 @@ static int st_output_switch_info(struct snd_kcontrol *ctl, "Speakers", "Headphones", "FP Headphones" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 3, names); } static int st_output_switch_get(struct snd_kcontrol *ctl, @@ -809,13 +797,7 @@ static int st_hp_volume_offset_info(struct snd_kcontrol *ctl, "< 64 ohms", "64-300 ohms", "300-600 ohms" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item > 2) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 3, names); } static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index ad48356c54e4..42d1ab136217 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -577,11 +577,6 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, const char *const *names; max = (ctl->private_value >> 12) & 0xf; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = max + 1; - if (info->value.enumerated.item > max) - info->value.enumerated.item = max; switch ((ctl->private_value >> 24) & 0x1f) { case WM8776_ALCCTRL2: names = hld; @@ -605,8 +600,7 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl, default: return -ENXIO; } - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, max + 1, names); } static int wm8776_field_volume_info(struct snd_kcontrol *ctl, @@ -863,13 +857,8 @@ static int wm8776_level_control_info(struct snd_kcontrol *ctl, static const char *const names[3] = { "None", "Peak Limiter", "Automatic Level Control" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + + return snd_ctl_enum_info(info, 1, 3, names); } static int wm8776_level_control_get(struct snd_kcontrol *ctl, @@ -955,13 +944,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) "None", "High-pass Filter" }; - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 2; - if (info->value.enumerated.item >= 2) - info->value.enumerated.item = 1; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; + return snd_ctl_enum_info(info, 1, 2, names); } static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) -- cgit v1.2.3-58-ga151