From f9a3fba2ce8622977c5373d2449eb71705613721 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 31 Dec 2008 10:08:37 +0200 Subject: ASoC: TWL4030: Make the enum filter generic for twl4030 Modify the enum filter to more generic that it will filter out the enums with text "Invalid". The enum filter also required for the capture path. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 5184888..2c279cd 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -298,25 +298,23 @@ static const struct soc_enum twl4030_handsfreer_enum = static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); -static int outmixer_event(struct snd_soc_dapm_widget *w, +/* + * This function filters out the non valid mux settings, named as "Invalid" + * in the enum texts. + * Just refuse to set an invalid mux mode. + */ +static int twl4030_enum_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; int ret = 0; int val; - switch (e->reg) { - case TWL4030_REG_PREDL_CTL: - case TWL4030_REG_PREDR_CTL: - case TWL4030_REG_EAR_CTL: - val = w->value >> e->shift_l; - if (val == 3) { - printk(KERN_WARNING - "Invalid MUX setting for register 0x%02x (%d)\n", - e->reg, val); - ret = -1; - } - break; + val = w->value >> e->shift_l; + if (!strcmp("Invalid", e->texts[val])) { + printk(KERN_WARNING "Invalid MUX setting on 0x%02x (%d)\n", + e->reg, val); + ret = -1; } return ret; @@ -810,14 +808,14 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { /* Output MUX controls */ /* Earpiece */ SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_earpiece_control, outmixer_event, + &twl4030_dapm_earpiece_control, twl4030_enum_event, SND_SOC_DAPM_PRE_REG), /* PreDrivL/R */ SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predrivel_control, outmixer_event, + &twl4030_dapm_predrivel_control, twl4030_enum_event, SND_SOC_DAPM_PRE_REG), SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predriver_control, outmixer_event, + &twl4030_dapm_predriver_control, twl4030_enum_event, SND_SOC_DAPM_PRE_REG), /* HeadsetL/R */ SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, -- cgit v1.1 From 276c62225a7c98737510483dcaec6af7e7965389 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 31 Dec 2008 10:08:38 +0200 Subject: ASoC: TWL4030: DAPM based capture implementation This patch adds DAPM implementaion for the capture path on twlx030. TWL has two physical ADC and two digital microphone (stereo) connections. The CPU interface has four microphone channels. For simplicity the microphone channel paths are named as: TX1 (Left/Right) - when using i2s mode, only the TX1 data is valid TX2 (Left/Right) Input routing (simplified version): There is two levels of mux settings for TWL in input path: Analog input mux: ADCL <- {Off, Main mic, Headset mic, AUXL, Carkit mic} ADCR <- {Off, Sub mic, AUXR} Analog/Digital mux: TX1 Analog mode: TX1L <- ADCL TX1R <- ADCR TX1 Digital mode: TX1L <- Digimic0 (Left) TX1R <- Digimic0 (Right) TX2 Analog mode: TX2L <- ADCL TX2R <- ADCR TX2 Digital mode: TX2L <- Digimic1 (Left) TX2R <- Digimic1 (Right) The patch provides the following user controls for the capture path: Mux settings: "TX1 Capture Route": {Analog, Digimic0} "TX2 Capture Route": {Analog, Digimic1} "Analog Left Capture Route": {Off, Main Mic, Headset Mic, AUXL, Carkit Mic} "Analog Right Capture Route": {Off, Sub Mic, AUXR} Volume/Gain controls: "TX1 Digital Capture Volume": Stereo gain control for TX1 path "TX2 Digital Capture Volume": Stereo gain control for TX2 path "Analog Capture Volume": Stereo gain control for the analog path only Important things for the board files: Microphone bias: "Mic Bias 1": Bias for Main mic or for digimic0 (analog or digital path) "Mic Bias 2": Bias for Sub mic or for digimic1 (analog or digital path) "Headset Mic Bias": Bias for Headset mic When the routing configured correctly only the needed components will be powered/enabled. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 347 +++++++++++++++++++++++---------------------- sound/soc/codecs/twl4030.h | 7 + 2 files changed, 182 insertions(+), 172 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 2c279cd..31e44e3 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -298,6 +298,55 @@ static const struct soc_enum twl4030_handsfreer_enum = static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); +/* Left analog microphone selection */ +static const char *twl4030_analoglmic_texts[] = + {"Off", "Main mic", "Headset mic", "Invalid", "AUXL", + "Invalid", "Invalid", "Invalid", "Carkit mic"}; + +static const struct soc_enum twl4030_analoglmic_enum = + SOC_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, + ARRAY_SIZE(twl4030_analoglmic_texts), + twl4030_analoglmic_texts); + +static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control = +SOC_DAPM_ENUM("Route", twl4030_analoglmic_enum); + +/* Right analog microphone selection */ +static const char *twl4030_analogrmic_texts[] = + {"Off", "Sub mic", "Invalid", "Invalid", "AUXR"}; + +static const struct soc_enum twl4030_analogrmic_enum = + SOC_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, + ARRAY_SIZE(twl4030_analogrmic_texts), + twl4030_analogrmic_texts); + +static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control = +SOC_DAPM_ENUM("Route", twl4030_analogrmic_enum); + +/* TX1 L/R Analog/Digital microphone selection */ +static const char *twl4030_micpathtx1_texts[] = + {"Analog", "Digimic0"}; + +static const struct soc_enum twl4030_micpathtx1_enum = + SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 0, + ARRAY_SIZE(twl4030_micpathtx1_texts), + twl4030_micpathtx1_texts); + +static const struct snd_kcontrol_new twl4030_dapm_micpathtx1_control = +SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum); + +/* TX2 L/R Analog/Digital microphone selection */ +static const char *twl4030_micpathtx2_texts[] = + {"Analog", "Digimic1"}; + +static const struct soc_enum twl4030_micpathtx2_enum = + SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 2, + ARRAY_SIZE(twl4030_micpathtx2_texts), + twl4030_micpathtx2_texts); + +static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = +SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); + /* * This function filters out the non valid mux settings, named as "Invalid" * in the enum texts. @@ -320,6 +369,36 @@ static int twl4030_enum_event(struct snd_soc_dapm_widget *w, return ret; } +static int micpath_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value; + unsigned char adcmicsel, micbias_ctl; + + adcmicsel = twl4030_read_reg_cache(w->codec, TWL4030_REG_ADCMICSEL); + micbias_ctl = twl4030_read_reg_cache(w->codec, TWL4030_REG_MICBIAS_CTL); + /* Prepare the bits for the given TX path: + * shift_l == 0: TX1 microphone path + * shift_l == 2: TX2 microphone path */ + if (e->shift_l) { + /* TX2 microphone path */ + if (adcmicsel & TWL4030_TX2IN_SEL) + micbias_ctl |= TWL4030_MICBIAS2_CTL; /* digimic */ + else + micbias_ctl &= ~TWL4030_MICBIAS2_CTL; + } else { + /* TX1 microphone path */ + if (adcmicsel & TWL4030_TX1IN_SEL) + micbias_ctl |= TWL4030_MICBIAS1_CTL; /* digimic */ + else + micbias_ctl &= ~TWL4030_MICBIAS1_CTL; + } + + twl4030_write(w->codec, TWL4030_REG_MICBIAS_CTL, micbias_ctl); + + return 0; +} + static int handsfree_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -501,162 +580,6 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, return err; } -static int twl4030_get_left_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); - int result = 0; - - /* one bit must be set a time */ - reg &= TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN - | TWL4030_MAINMIC_EN; - if (reg != 0) { - result++; - while ((reg & 1) == 0) { - result++; - reg >>= 1; - } - } - - ucontrol->value.integer.value[0] = result; - return 0; -} - -static int twl4030_put_left_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - int value = ucontrol->value.integer.value[0]; - u8 anamicl, micbias, avadc_ctl; - - anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); - anamicl &= ~(TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN - | TWL4030_MAINMIC_EN); - micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); - micbias &= ~(TWL4030_HSMICBIAS_EN | TWL4030_MICBIAS1_EN); - avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); - - switch (value) { - case 1: - anamicl |= TWL4030_MAINMIC_EN; - micbias |= TWL4030_MICBIAS1_EN; - break; - case 2: - anamicl |= TWL4030_HSMIC_EN; - micbias |= TWL4030_HSMICBIAS_EN; - break; - case 3: - anamicl |= TWL4030_AUXL_EN; - break; - case 4: - anamicl |= TWL4030_CKMIC_EN; - break; - default: - break; - } - - /* If some input is selected, enable amp and ADC */ - if (value != 0) { - anamicl |= TWL4030_MICAMPL_EN; - avadc_ctl |= TWL4030_ADCL_EN; - } else { - anamicl &= ~TWL4030_MICAMPL_EN; - avadc_ctl &= ~TWL4030_ADCL_EN; - } - - twl4030_write(codec, TWL4030_REG_ANAMICL, anamicl); - twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); - twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); - - return 1; -} - -static int twl4030_get_right_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); - int value = 0; - - reg &= TWL4030_SUBMIC_EN|TWL4030_AUXR_EN; - switch (reg) { - case TWL4030_SUBMIC_EN: - value = 1; - break; - case TWL4030_AUXR_EN: - value = 2; - break; - default: - break; - } - - ucontrol->value.integer.value[0] = value; - return 0; -} - -static int twl4030_put_right_input(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = kcontrol->private_data; - int value = ucontrol->value.integer.value[0]; - u8 anamicr, micbias, avadc_ctl; - - anamicr = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); - anamicr &= ~(TWL4030_SUBMIC_EN|TWL4030_AUXR_EN); - micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); - micbias &= ~TWL4030_MICBIAS2_EN; - avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); - - switch (value) { - case 1: - anamicr |= TWL4030_SUBMIC_EN; - micbias |= TWL4030_MICBIAS2_EN; - break; - case 2: - anamicr |= TWL4030_AUXR_EN; - break; - default: - break; - } - - if (value != 0) { - anamicr |= TWL4030_MICAMPR_EN; - avadc_ctl |= TWL4030_ADCR_EN; - } else { - anamicr &= ~TWL4030_MICAMPR_EN; - avadc_ctl &= ~TWL4030_ADCR_EN; - } - - twl4030_write(codec, TWL4030_REG_ANAMICR, anamicr); - twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); - twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); - - return 1; -} - -static const char *twl4030_left_in_sel[] = { - "None", - "Main Mic", - "Headset Mic", - "Line In", - "Carkit Mic", -}; - -static const char *twl4030_right_in_sel[] = { - "None", - "Sub Mic", - "Line In", -}; - -static const struct soc_enum twl4030_left_input_mux = - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_left_in_sel), - twl4030_left_in_sel); - -static const struct soc_enum twl4030_right_input_mux = - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_right_in_sel), - twl4030_right_in_sel); - /* * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) @@ -739,18 +662,15 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { TWL4030_REG_EAR_CTL, 4, 3, 0, output_tvl), /* Common capture gain controls */ - SOC_DOUBLE_R_TLV("Capture Volume", + SOC_DOUBLE_R_TLV("TX1 Digital Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, 0, 0x1f, 0, digital_capture_tlv), + SOC_DOUBLE_R_TLV("TX2 Digital Capture Volume", + TWL4030_REG_AVTXL2PGA, TWL4030_REG_AVTXR2PGA, + 0, 0x1f, 0, digital_capture_tlv), - SOC_DOUBLE_TLV("Input Boost Volume", TWL4030_REG_ANAMIC_GAIN, + SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, 0, 3, 5, 0, input_gain_tlv), - - /* Input source controls */ - SOC_ENUM_EXT("Left Input Source", twl4030_left_input_mux, - twl4030_get_left_input, twl4030_put_left_input), - SOC_ENUM_EXT("Right Input Source", twl4030_right_input_mux, - twl4030_get_right_input, twl4030_put_right_input), }; /* add non dapm controls */ @@ -770,9 +690,19 @@ static int twl4030_add_controls(struct snd_soc_codec *codec) } static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { - SND_SOC_DAPM_INPUT("INL"), - SND_SOC_DAPM_INPUT("INR"), - + /* Left channel inputs */ + SND_SOC_DAPM_INPUT("MAINMIC"), + SND_SOC_DAPM_INPUT("HSMIC"), + SND_SOC_DAPM_INPUT("AUXL"), + SND_SOC_DAPM_INPUT("CARKITMIC"), + /* Right channel inputs */ + SND_SOC_DAPM_INPUT("SUBMIC"), + SND_SOC_DAPM_INPUT("AUXR"), + /* Digital microphones (Stereo) */ + SND_SOC_DAPM_INPUT("DIGIMIC0"), + SND_SOC_DAPM_INPUT("DIGIMIC1"), + + /* Outputs */ SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), SND_SOC_DAPM_OUTPUT("EARPIECE"), @@ -835,8 +765,50 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { &twl4030_dapm_handsfreer_control, handsfree_event, SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), + /* Introducing four virtual ADC, since TWL4030 have four channel for + capture */ + SND_SOC_DAPM_ADC("ADC Virtual Left1", "Left Front Capture", + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC Virtual Right1", "Right Front Capture", + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC Virtual Left2", "Left Rear Capture", + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC Virtual Right2", "Right Rear Capture", + SND_SOC_NOPM, 0, 0), + + /* Analog/Digital mic path selection. + TX1 Left/Right: either analog Left/Right or Digimic0 + TX2 Left/Right: either analog Left/Right or Digimic1 */ + SND_SOC_DAPM_MUX_E("TX1 Capture Route", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_micpathtx1_control, micpath_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| + SND_SOC_DAPM_POST_REG), + SND_SOC_DAPM_MUX_E("TX2 Capture Route", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_micpathtx2_control, micpath_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| + SND_SOC_DAPM_POST_REG), + + /* Analog input muxes with power switch for the physical ADCL/R */ + SND_SOC_DAPM_MUX_E("Analog Left Capture Route", + TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control, + twl4030_enum_event, SND_SOC_DAPM_PRE_REG), + SND_SOC_DAPM_MUX_E("Analog Right Capture Route", + TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control, + twl4030_enum_event, SND_SOC_DAPM_PRE_REG), + + SND_SOC_DAPM_PGA("Analog Left Amplifier", + TWL4030_REG_ANAMICL, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Analog Right Amplifier", + TWL4030_REG_ANAMICR, 4, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Digimic0 Enable", + TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA("Digimic1 Enable", + TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0), + + SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), + SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), + SND_SOC_DAPM_MICBIAS("Headset Mic Bias", TWL4030_REG_MICBIAS_CTL, 2, 0), }; static const struct snd_soc_dapm_route intercon[] = { @@ -892,9 +864,39 @@ static const struct snd_soc_dapm_route intercon[] = { {"HFL", NULL, "HandsfreeL Mux"}, {"HFR", NULL, "HandsfreeR Mux"}, - /* inputs */ - {"ADCL", NULL, "INL"}, - {"ADCR", NULL, "INR"}, + /* Capture path */ + {"Analog Left Capture Route", "Main mic", "MAINMIC"}, + {"Analog Left Capture Route", "Headset mic", "HSMIC"}, + {"Analog Left Capture Route", "AUXL", "AUXL"}, + {"Analog Left Capture Route", "Carkit mic", "CARKITMIC"}, + + {"Analog Right Capture Route", "Sub mic", "SUBMIC"}, + {"Analog Right Capture Route", "AUXR", "AUXR"}, + + {"Analog Left Amplifier", NULL, "Analog Left Capture Route"}, + {"Analog Right Amplifier", NULL, "Analog Right Capture Route"}, + + {"Digimic0 Enable", NULL, "DIGIMIC0"}, + {"Digimic1 Enable", NULL, "DIGIMIC1"}, + + /* TX1 Left capture path */ + {"TX1 Capture Route", "Analog", "Analog Left Amplifier"}, + {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, + /* TX1 Right capture path */ + {"TX1 Capture Route", "Analog", "Analog Right Amplifier"}, + {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, + /* TX2 Left capture path */ + {"TX2 Capture Route", "Analog", "Analog Left Amplifier"}, + {"TX2 Capture Route", "Digimic1", "Digimic1 Enable"}, + /* TX2 Right capture path */ + {"TX2 Capture Route", "Analog", "Analog Right Amplifier"}, + {"TX2 Capture Route", "Digimic1", "Digimic1 Enable"}, + + {"ADC Virtual Left1", NULL, "TX1 Capture Route"}, + {"ADC Virtual Right1", NULL, "TX1 Capture Route"}, + {"ADC Virtual Left2", NULL, "TX2 Capture Route"}, + {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, + }; static int twl4030_add_widgets(struct snd_soc_codec *codec) @@ -921,6 +923,7 @@ static void twl4030_power_up(struct snd_soc_codec *codec) twl4030_write(codec, TWL4030_REG_ANAMICL, anamicl | TWL4030_CNCL_OFFSET_START); + /* wait for offset cancellation to complete */ do { /* this takes a little while, so don't slam i2c */ diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index 54615c7..442e5a8 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -147,6 +147,13 @@ #define TWL4030_AVADC_CLK_PRIORITY 0x04 #define TWL4030_ADCR_EN 0x02 +/* TWL4030_REG_ADCMICSEL (0x08) Fields */ + +#define TWL4030_DIGMIC1_EN 0x08 +#define TWL4030_TX2IN_SEL 0x04 +#define TWL4030_DIGMIC0_EN 0x02 +#define TWL4030_TX1IN_SEL 0x01 + /* AUDIO_IF (0x0E) Fields */ #define TWL4030_AIF_SLAVE_EN 0x80 -- cgit v1.1 From 3fea2cb0451b9009af32d1418ea77cc674fe7e02 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 26 Dec 2008 12:20:43 +0800 Subject: ALSA: hda - fix name for ALC1200 Move the more specific preset for ALC1200 above the general one for ALC888, so that it will have the chance to get matched and selected. Reported-by: Thomas Schneider Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0bd4e6b..69a251b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16638,9 +16638,9 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { .patch = patch_alc882 }, /* should be patch_alc883() in future */ { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 }, - { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", .patch = patch_alc883 }, + { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, {} /* terminator */ }; -- cgit v1.1 From 06bf3e15f64aacfb068fed5002b6544f870cc638 Mon Sep 17 00:00:00 2001 From: Chris Bagwell Date: Thu, 1 Jan 2009 10:32:08 +0100 Subject: LSA: hda - Add HP Acacia detection Add automatic mapping of HP Acacia motherboards to 3stack-hp. Allows for greater then 2 channel audio by enabling Channel Mode option in mixer. Motherboard specs: http://h10025.www1.hp.com/ewfrf/wc/document?docname=c01321559&lc=en&dlc=en&cc=us&product=3829353&os=2093&lang=en# Signed-off-by: Chris Bagwell Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 69a251b..9065ebf 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8467,6 +8467,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), -- cgit v1.1 From 9bef6489d72abd8f598aede92be3854a69324c50 Mon Sep 17 00:00:00 2001 From: Stephen Ware Date: Wed, 31 Dec 2008 14:39:23 -0800 Subject: ASoC: Fix pxa2xx-pcm checks for invalid DMA channels Set the invalid dma channel to -1 (and check properly for it) in pxa2xx_pcm_hw_free(). Was assuming 0 is an invalid channel number but 0 is a valid pxa dma channel num. Signed-off-by: stephen Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index c670d08..53b9fb1 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -61,9 +61,9 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) __pxa2xx_pcm_hw_free(substream); - if (prtd->dma_ch) { + if (prtd->dma_ch >= 0) { pxa_free_dma(prtd->dma_ch); - prtd->dma_ch = 0; + prtd->dma_ch = -1; } return 0; -- cgit v1.1 From ac11a2b35cc25c77d28218aaf60e7f7c6c7ee5d3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 1 Jan 2009 12:18:17 +0000 Subject: ASoC: Clean up kerneldoc warnings Almost all parameters that have been misnamed in the comments. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 46 ++++++++++++++++++++++++---------------------- sound/soc/soc-dapm.c | 10 +++++----- 2 files changed, 29 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b098c0b..f73c134 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1300,6 +1300,8 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits); /** * snd_soc_new_pcms - create new sound card and pcms * @socdev: the SoC audio device + * @idx: ALSA card index + * @xid: card identification * * Create a new sound card based upon the codec and interface pcms. * @@ -1472,7 +1474,7 @@ EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); * snd_soc_cnew - create new control * @_template: control template * @data: control private data - * @lnng_name: control long name + * @long_name: control long name * * Create a new mixer control from a template control. * @@ -1522,7 +1524,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); /** * snd_soc_get_enum_double - enumerated double mixer get callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to get the value of a double enumerated mixer. * @@ -1551,7 +1553,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); /** * snd_soc_put_enum_double - enumerated double mixer put callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to set the value of a double enumerated mixer. * @@ -1668,7 +1670,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw); /** * snd_soc_get_volsw - single mixer get callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to get the value of a single mixer control. * @@ -1707,7 +1709,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw); /** * snd_soc_put_volsw - single mixer put callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to set the value of a single mixer control. * @@ -1775,7 +1777,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r); /** * snd_soc_get_volsw_2r - double mixer get callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to get the value of a double mixer control that spans 2 registers. * @@ -1812,7 +1814,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r); /** * snd_soc_put_volsw_2r - double mixer set callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to set the value of a double mixer control that spans 2 registers. * @@ -1882,7 +1884,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); /** * snd_soc_get_volsw_s8 - signed mixer get callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to get the value of a signed mixer control. * @@ -1909,7 +1911,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); /** * snd_soc_put_volsw_sgn - signed mixer put callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to set the value of a signed mixer control. * @@ -1954,7 +1956,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); /** * snd_soc_dai_set_clkdiv - configure DAI clock dividers. * @dai: DAI - * @clk_id: DAI specific clock divider ID + * @div_id: DAI specific clock divider ID * @div: new clock divisor. * * Configures the clock dividers. This is used to derive the best DAI bit and @@ -2060,7 +2062,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); /** * snd_soc_register_card - Register a card with the ASoC core * - * @param card Card to register + * @card: Card to register * * Note that currently this is an internal only function: it will be * exposed to machine drivers after further backporting of ASoC v2 @@ -2087,7 +2089,7 @@ static int snd_soc_register_card(struct snd_soc_card *card) /** * snd_soc_unregister_card - Unregister a card with the ASoC core * - * @param card Card to unregister + * @card: Card to unregister * * Note that currently this is an internal only function: it will be * exposed to machine drivers after further backporting of ASoC v2 @@ -2107,7 +2109,7 @@ static int snd_soc_unregister_card(struct snd_soc_card *card) /** * snd_soc_register_dai - Register a DAI with the ASoC core * - * @param dai DAI to register + * @dai: DAI to register */ int snd_soc_register_dai(struct snd_soc_dai *dai) { @@ -2134,7 +2136,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dai); /** * snd_soc_unregister_dai - Unregister a DAI from the ASoC core * - * @param dai DAI to unregister + * @dai: DAI to unregister */ void snd_soc_unregister_dai(struct snd_soc_dai *dai) { @@ -2149,8 +2151,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); /** * snd_soc_register_dais - Register multiple DAIs with the ASoC core * - * @param dai Array of DAIs to register - * @param count Number of DAIs + * @dai: Array of DAIs to register + * @count: Number of DAIs */ int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count) { @@ -2175,8 +2177,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais); /** * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core * - * @param dai Array of DAIs to unregister - * @param count Number of DAIs + * @dai: Array of DAIs to unregister + * @count: Number of DAIs */ void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count) { @@ -2190,7 +2192,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); /** * snd_soc_register_platform - Register a platform with the ASoC core * - * @param platform platform to register + * @platform: platform to register */ int snd_soc_register_platform(struct snd_soc_platform *platform) { @@ -2213,7 +2215,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform); /** * snd_soc_unregister_platform - Unregister a platform from the ASoC core * - * @param platform platform to unregister + * @platform: platform to unregister */ void snd_soc_unregister_platform(struct snd_soc_platform *platform) { @@ -2228,7 +2230,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); /** * snd_soc_register_codec - Register a codec with the ASoC core * - * @param codec codec to register + * @codec: codec to register */ int snd_soc_register_codec(struct snd_soc_codec *codec) { @@ -2255,7 +2257,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec); /** * snd_soc_unregister_codec - Unregister a codec from the ASoC core * - * @param codec codec to unregister + * @codec: codec to unregister */ void snd_soc_unregister_codec(struct snd_soc_codec *codec) { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8863edd..6c79ca6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1077,7 +1077,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); /** * snd_soc_dapm_get_volsw - dapm mixer get callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to get the value of a dapm mixer control. * @@ -1122,7 +1122,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); /** * snd_soc_dapm_put_volsw - dapm mixer set callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to set the value of a dapm mixer control. * @@ -1193,7 +1193,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); /** * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to get the value of a dapm enumerated double mixer control. * @@ -1221,7 +1221,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); /** * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback * @kcontrol: mixer control - * @uinfo: control element information + * @ucontrol: control element information * * Callback to set the value of a dapm enumerated double mixer control. * @@ -1419,7 +1419,7 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, /** * snd_soc_dapm_enable_pin - enable pin. - * @snd_soc_codec: SoC codec + * @codec: SoC codec * @pin: pin name * * Enables input/output pin and it's parents or children widgets iff there is -- cgit v1.1 From bec43661b1dc0075b7445223ba775674133b164d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Dec 2008 06:58:20 -0300 Subject: V4L/DVB (10135): v4l2: introduce v4l2_file_operations. Introduce a struct v4l2_file_operations for v4l2 drivers. Remove the unnecessary inode argument. Move compat32 handling (and llseek) into the v4l2-dev core: this is now handled in the v4l2 core and no longer in the drivers themselves. Note that this changeset reverts an earlier patch that changed the return type of__video_ioctl2 from int to long. This change will be reinstated later in a much improved version. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- sound/i2c/other/tea575x-tuner.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 549b4eb..90f416c 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -84,7 +84,7 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea) * Linux Video interface */ -static int snd_tea575x_ioctl(struct inode *inode, struct file *file, +static int snd_tea575x_ioctl(struct file *file, unsigned int cmd, unsigned long data) { struct snd_tea575x *tea = video_drvdata(file); @@ -174,14 +174,14 @@ static void snd_tea575x_release(struct video_device *vfd) { } -static int snd_tea575x_exclusive_open(struct inode *inode, struct file *file) +static int snd_tea575x_exclusive_open(struct file *file) { struct snd_tea575x *tea = video_drvdata(file); return test_and_set_bit(0, &tea->in_use) ? -EBUSY : 0; } -static int snd_tea575x_exclusive_release(struct inode *inode, struct file *file) +static int snd_tea575x_exclusive_release(struct file *file) { struct snd_tea575x *tea = video_drvdata(file); -- cgit v1.1 From 069b747931f13eda289c1d59a09ecc8162281a76 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Dec 2008 07:04:34 -0300 Subject: V4L/DVB (10138): v4l2-ioctl: change to long return type to match unlocked_ioctl. Since internal to v4l2 the ioctl prototype is the same regardless of it being called through .ioctl or .unlocked_ioctl, we need to convert it all to the long return type of unlocked_ioctl. Thanks to Jean-Francois Moine for posting an initial patch for this and thus bringing it to our attention. Cc: Jean-Francois Moine Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- sound/i2c/other/tea575x-tuner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 90f416c..9d98a66 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -84,7 +84,7 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea) * Linux Video interface */ -static int snd_tea575x_ioctl(struct file *file, +static long snd_tea575x_ioctl(struct file *file, unsigned int cmd, unsigned long data) { struct snd_tea575x *tea = video_drvdata(file); -- cgit v1.1 From bc7a166dd1530965aa80966f267235f067c5fddf Mon Sep 17 00:00:00 2001 From: Ulrich Dangel Date: Fri, 2 Jan 2009 19:30:13 +0100 Subject: ALSA: hda - add basic jack reporting functions to patch_conexant.c Added functions to report jack sense. As CXT5051_PORTB_EVENT has the same value as CONEXANT_MIC_EVENT two input devices for the microphone will be created if using CXT5051. Signed-off-by: Ulrich Dangel Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 111 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index b20e1ce..e0eebfb 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -25,6 +25,8 @@ #include #include #include +#include + #include "hda_codec.h" #include "hda_local.h" @@ -37,8 +39,21 @@ #define CONEXANT_HP_EVENT 0x37 #define CONEXANT_MIC_EVENT 0x38 +/* Conexant 5051 specific */ + +#define CXT5051_SPDIF_OUT 0x1C +#define CXT5051_PORTB_EVENT 0x38 +#define CXT5051_PORTC_EVENT 0x39 +struct conexant_jack { + + hda_nid_t nid; + int type; + struct snd_jack *jack; + +}; + struct conexant_spec { struct snd_kcontrol_new *mixers[5]; @@ -83,6 +98,9 @@ struct conexant_spec { unsigned int spdif_route; + /* jack detection */ + struct snd_array jacks; + /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; struct hda_input_mux private_imux; @@ -329,6 +347,86 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, &spec->cur_mux[adc_idx]); } +static int conexant_add_jack(struct hda_codec *codec, + hda_nid_t nid, int type) +{ + struct conexant_spec *spec; + struct conexant_jack *jack; + const char *name; + + spec = codec->spec; + snd_array_init(&spec->jacks, sizeof(*jack), 32); + jack = snd_array_new(&spec->jacks); + name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; + + if (!jack) + return -ENOMEM; + + jack->nid = nid; + jack->type = type; + + return snd_jack_new(codec->bus->card, name, type, &jack->jack); +} + +static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) +{ + struct conexant_spec *spec = codec->spec; + struct conexant_jack *jacks = spec->jacks.list; + + if (jacks) { + int i; + for (i = 0; i < spec->jacks.used; i++) { + if (jacks->nid == nid) { + unsigned int present; + present = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0) & + AC_PINSENSE_PRESENCE; + + present = (present) ? jacks->type : 0 ; + + snd_jack_report(jacks->jack, + present); + } + jacks++; + } + } +} + +static int conexant_init_jacks(struct hda_codec *codec) +{ +#ifdef CONFIG_SND_JACK + struct conexant_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_init_verbs; i++) { + const struct hda_verb *hv; + + hv = spec->init_verbs[i]; + while (hv->nid) { + int err = 0; + switch (hv->param ^ AC_USRSP_EN) { + case CONEXANT_HP_EVENT: + err = conexant_add_jack(codec, hv->nid, + SND_JACK_HEADPHONE); + conexant_report_jack(codec, hv->nid); + break; + case CXT5051_PORTC_EVENT: + case CONEXANT_MIC_EVENT: + err = conexant_add_jack(codec, hv->nid, + SND_JACK_MICROPHONE); + conexant_report_jack(codec, hv->nid); + break; + } + if (err < 0) + return err; + ++hv; + } + } +#endif + return 0; + +} + static int conexant_init(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -341,6 +439,16 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { +#ifdef CONFIG_SND_JACK + struct conexant_spec *spec = codec->spec; + if (spec->jacks.list) { + struct conexant_jack *jacks = spec->jacks.list; + int i; + for (i = 0; i < spec->jacks.used; i++) + snd_device_free(codec->bus->card, &jacks[i].jack); + snd_array_free(&spec->jacks); + } +#endif kfree(codec->spec); } @@ -1526,9 +1634,6 @@ static int patch_cxt5047(struct hda_codec *codec) /* Conexant 5051 specific */ static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; -#define CXT5051_SPDIF_OUT 0x1C -#define CXT5051_PORTB_EVENT 0x38 -#define CXT5051_PORTC_EVENT 0x39 static struct hda_channel_mode cxt5051_modes[1] = { { 2, NULL }, -- cgit v1.1 From acf26c0cad5ba00dcafa633805e4660e90c1eac0 Mon Sep 17 00:00:00 2001 From: Ulrich Dangel Date: Fri, 2 Jan 2009 19:30:14 +0100 Subject: ALSA: hda - cxt5051 report jack state Signed-off-by: Ulrich Dangel Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e0eebfb..75de40a 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1713,6 +1713,7 @@ static void cxt5051_hp_automute(struct hda_codec *codec) static void cxt5051_hp_unsol_event(struct hda_codec *codec, unsigned int res) { + int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20; switch (res >> 26) { case CONEXANT_HP_EVENT: cxt5051_hp_automute(codec); @@ -1724,6 +1725,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec, cxt5051_portc_automic(codec); break; } + conexant_report_jack(codec, nid); } static struct snd_kcontrol_new cxt5051_mixers[] = { @@ -1798,6 +1800,7 @@ static struct hda_verb cxt5051_init_verbs[] = { static int cxt5051_init(struct hda_codec *codec) { conexant_init(codec); + conexant_init_jacks(codec); if (codec->patch_ops.unsol_event) { cxt5051_hp_automute(codec); cxt5051_portb_automic(codec); -- cgit v1.1 From 5cf1c00b0ef3ba964b2ad268a55c278cf43f798f Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 5 Jan 2009 02:08:30 -0800 Subject: ASoC: fix davinci-sffsdr buglet Minor bugfix: now that DaVinci kernels can support multiple boards, board-specific ASoC components need to verify they're running on the right board before initializing. Signed-off-by: David Brownell Signed-off-by: Kevin Hilman Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-sffsdr.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index f67579d..4935d1b 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -115,6 +116,9 @@ static int __init sffsdr_init(void) { int ret; + if (!machine_is_sffsdr()) + return -EINVAL; + sffsdr_snd_device = platform_device_alloc("soc-audio", 0); if (!sffsdr_snd_device) { printk(KERN_ERR "platform device allocation failed\n"); -- cgit v1.1 From 8eca75382e012b74b98526a1679ada2a1849024b Mon Sep 17 00:00:00 2001 From: Alan Horstmann Date: Mon, 5 Jan 2009 18:30:04 +0100 Subject: ALSA: ice1724 - Fix a typo in IEC958 PCM name Fix trivial name string typo as reported in bug 2552. Signed-off-by: Alan Horstmann Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 0dfa054..bb8d8c7 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -1239,7 +1239,7 @@ static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device) if (ice->force_pdma4 || ice->force_rdma1) name = "ICE1724 Secondary"; else - name = "IEC1724 IEC958"; + name = "ICE1724 IEC958"; err = snd_pcm_new(ice->card, name, device, play, capt, &pcm); if (err < 0) return err; -- cgit v1.1 From d304c6ef6e9888addde075acb5bdd87e3fb48c1a Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 23 Dec 2008 10:09:35 +0200 Subject: ASoC: OMAP: Select OMAP pin multiplexing when using Nokia N810 ASoC drivers N810 bootloader muxes I2S pins for OMAP2420 EAC block while N810 ASoC drivers are using McBSP block so the kernel have to change configuration runtime. Author has not seen problems using kernel pin multiplexing on N810 but very many times unworking audio after forgotten to enable it and spending 15 minutes each time to figure it out again... This change makes it easier for other users as well. If problems arise, then they are better to find and fix in OMAP pin multiplexing framework. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a7b1d77..4f7f040 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -10,6 +10,7 @@ config SND_OMAP_SOC_N810 tristate "SoC Audio support for Nokia N810" depends on SND_OMAP_SOC && MACH_NOKIA_N810 select SND_OMAP_SOC_MCBSP + select OMAP_MUX select SND_SOC_TLV320AIC3X help Say Y if you want to add support for SoC audio on Nokia N810. -- cgit v1.1 From 7f185340da2594d65520b26f41e706a3ad0a368c Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Tue, 23 Dec 2008 12:04:48 +0200 Subject: ASoC: Mark non-connected TWL4030 pins for pandora Pandora has all TWL4030 output pins floating, it uses external DAC for playback. Mark those outputs as not connected using DAPM calls. Signed-off-by: Grazvydas Ignotas Signed-off-by: Mark Brown --- sound/soc/omap/omap3pandora.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sound') diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index bd91594..fcc2f5d 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -180,6 +180,19 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec) { int ret; + /* All TWL4030 output pins are floating */ + snd_soc_dapm_nc_pin(codec, "OUTL"), + snd_soc_dapm_nc_pin(codec, "OUTR"), + snd_soc_dapm_nc_pin(codec, "EARPIECE"), + snd_soc_dapm_nc_pin(codec, "PREDRIVEL"), + snd_soc_dapm_nc_pin(codec, "PREDRIVER"), + snd_soc_dapm_nc_pin(codec, "HSOL"), + snd_soc_dapm_nc_pin(codec, "HSOR"), + snd_soc_dapm_nc_pin(codec, "CARKITL"), + snd_soc_dapm_nc_pin(codec, "CARKITR"), + snd_soc_dapm_nc_pin(codec, "HFL"), + snd_soc_dapm_nc_pin(codec, "HFR"), + ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, ARRAY_SIZE(omap3pandora_in_dapm_widgets)); if (ret < 0) -- cgit v1.1 From 05d5e991a7290807e7d62a7d272bb4f37c27c6ae Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 4 Jan 2009 02:50:10 -0800 Subject: ASoC: Clocking fixes for davinci-evm.c Let's have audio playback not sound like chipmunks, 'k? :) ASP1 on the DM355 EVM uses a 27 MHz external audio clock, not the slower clock used with ASP0 on the DM6446 EVM. Also, that slower ASP0 clock on the DM6446 is 12.288 MHz, not 22.5792 MHz ... 48 KHz sample rate (x256), not a double speed 44.1 KHz sample rate (which could be done, but isn't what the board init code now sets up). Signed-off-by: David Brownell Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-evm.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 01b948b..54851f3 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -26,7 +26,6 @@ #include "davinci-pcm.h" #include "davinci-i2s.h" -#define EVM_CODEC_CLOCK 22579200 #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) @@ -37,6 +36,21 @@ static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; int ret = 0; + unsigned sysclk; + + /* ASP1 on DM355 EVM is clocked by an external oscillator */ + if (machine_is_davinci_dm355_evm()) + sysclk = 27000000; + + /* ASP0 in DM6446 EVM is clocked by U55, as configured by + * board-dm644x-evm.c using GPIOs from U18. There are six + * options; here we "know" we use a 48 KHz sample rate. + */ + else if (machine_is_davinci_evm()) + sysclk = 12288000; + + else + return -EINVAL; /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); @@ -49,8 +63,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream, return ret; /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, - SND_SOC_CLOCK_OUT); + ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); if (ret < 0) return ret; -- cgit v1.1 From 796123368871e4a838dc0dfd5dbc3cd8981ef429 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 5 Jan 2009 12:58:06 +0300 Subject: pxa2xx-ac97: switch AC unit to correct state before probing If AC97 unit is in partially enabled state, early request_irq can trigger IRQ storm or even full hang up. Workaround this by forcibly switching ACLINK off at the start of the probe. Signed-off-by: Dmitry Baryshkov Signed-off-by: Mark Brown --- sound/arm/pxa2xx-ac97-lib.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index ef6539e..35afd0c 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -321,10 +321,6 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) { int ret; - ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); - if (ret < 0) - goto err; - if (cpu_is_pxa25x() || cpu_is_pxa27x()) { pxa_gpio_mode(GPIO31_SYNC_AC97_MD); pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); @@ -339,7 +335,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) if (IS_ERR(ac97conf_clk)) { ret = PTR_ERR(ac97conf_clk); ac97conf_clk = NULL; - goto err_irq; + goto err_conf; } } @@ -347,19 +343,30 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) if (IS_ERR(ac97_clk)) { ret = PTR_ERR(ac97_clk); ac97_clk = NULL; - goto err_irq; + goto err_clk; } - return clk_enable(ac97_clk); + ret = clk_enable(ac97_clk); + if (ret) + goto err_clk2; + + ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL); + if (ret < 0) + goto err_irq; + + return 0; err_irq: GCR |= GCR_ACLINK_OFF; +err_clk2: + clk_put(ac97_clk); + ac97_clk = NULL; +err_clk: if (ac97conf_clk) { clk_put(ac97conf_clk); ac97conf_clk = NULL; } - free_irq(IRQ_AC97, NULL); -err: +err_conf: return ret; } EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); -- cgit v1.1 From 2e72f8e3716bc3bbf4c9b5b987fb5ab3223f60bf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 5 Jan 2009 09:54:57 +0200 Subject: ASoC: New enum type: value_enum This patch introduces a new enum type. In this enum type each enumerated items referred with a value. This new enum type can handle enums encoded in bitfield, or any other weird ways. twl4030 codec has several mux selection register, where the input/output mux is coded in a bitfield. With the normal enum type this type of mux can not be handled in a clean way. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 107 ++++++++++++++++++++++++++++ sound/soc/soc-dapm.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 301 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f73c134..6cbe7e8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1585,6 +1585,113 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); /** + * snd_soc_info_value_enum_double - semi enumerated double mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to provide information about a double semi enumerated + * mixer control. + * + * Semi enumerated mixer: the enumerated items are referred as values. Can be + * used for handling bitfield coded enumeration for example. + * + * Returns 0 for success. + */ +int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_value_enum *e = (struct soc_value_enum *) + kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = e->shift_l == e->shift_r ? 1 : 2; + uinfo->value.enumerated.items = e->max; + + if (uinfo->value.enumerated.item > e->max - 1) + uinfo->value.enumerated.item = e->max - 1; + strcpy(uinfo->value.enumerated.name, + e->texts[uinfo->value.enumerated.item]); + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_value_enum_double); + +/** + * snd_soc_get_value_enum_double - semi enumerated double mixer get callback + * @kcontrol: mixer control + * @ucontrol: control element information + * + * Callback to get the value of a double semi enumerated mixer. + * + * Semi enumerated mixer: the enumerated items are referred as values. Can be + * used for handling bitfield coded enumeration for example. + * + * Returns 0 for success. + */ +int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_value_enum *e = (struct soc_value_enum *) + kcontrol->private_value; + unsigned short reg_val, val, mux; + + reg_val = snd_soc_read(codec, e->reg); + val = (reg_val >> e->shift_l) & e->mask; + for (mux = 0; mux < e->max; mux++) { + if (val == e->values[mux]) + break; + } + ucontrol->value.enumerated.item[0] = mux; + if (e->shift_l != e->shift_r) { + val = (reg_val >> e->shift_r) & e->mask; + for (mux = 0; mux < e->max; mux++) { + if (val == e->values[mux]) + break; + } + ucontrol->value.enumerated.item[1] = mux; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); + +/** + * snd_soc_put_value_enum_double - semi enumerated double mixer put callback + * @kcontrol: mixer control + * @ucontrol: control element information + * + * Callback to set the value of a double semi enumerated mixer. + * + * Semi enumerated mixer: the enumerated items are referred as values. Can be + * used for handling bitfield coded enumeration for example. + * + * Returns 0 for success. + */ +int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_value_enum *e = (struct soc_value_enum *) + kcontrol->private_value; + unsigned short val; + unsigned short mask; + + if (ucontrol->value.enumerated.item[0] > e->max - 1) + return -EINVAL; + val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; + mask = e->mask << e->shift_l; + if (e->shift_l != e->shift_r) { + if (ucontrol->value.enumerated.item[1] > e->max - 1) + return -EINVAL; + val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; + mask |= e->mask << e->shift_r; + } + + return snd_soc_update_bits(codec, e->reg, mask, val); +} +EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); + +/** * snd_soc_info_enum_ext - external enumerated single mixer info callback * @kcontrol: mixer control * @uinfo: control element information diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 6c79ca6..ad0d801 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -53,13 +53,15 @@ /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, - snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga, - snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post + snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, + snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, + snd_soc_dapm_spk, snd_soc_dapm_post }; static int dapm_down_seq[] = { snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, - snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post + snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux, + snd_soc_dapm_post }; static int dapm_status = 1; @@ -134,6 +136,25 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, } } break; + case snd_soc_dapm_value_mux: { + struct soc_value_enum *e = (struct soc_value_enum *) + w->kcontrols[i].private_value; + int val, item; + + val = snd_soc_read(w->codec, e->reg); + val = (val >> e->shift_l) & e->mask; + for (item = 0; item < e->max; item++) { + if (val == e->values[item]) + break; + } + + p->connect = 0; + for (i = 0; i < e->max; i++) { + if (!(strcmp(p->name, e->texts[i])) && item == i) + p->connect = 1; + } + } + break; /* does not effect routing - always connected */ case snd_soc_dapm_pga: case snd_soc_dapm_output: @@ -179,6 +200,30 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, return -ENODEV; } +/* connect value_mux widget to it's interconnecting audio paths */ +static int dapm_connect_value_mux(struct snd_soc_codec *codec, + struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, + struct snd_soc_dapm_path *path, const char *control_name, + const struct snd_kcontrol_new *kcontrol) +{ + struct soc_value_enum *e = (struct soc_value_enum *) + kcontrol->private_value; + int i; + + for (i = 0; i < e->max; i++) { + if (!(strcmp(control_name, e->texts[i]))) { + list_add(&path->list, &codec->dapm_paths); + list_add(&path->list_sink, &dest->sources); + list_add(&path->list_source, &src->sinks); + path->name = (char *)e->texts[i]; + dapm_set_path_status(dest, path, 0); + return 0; + } + } + + return -ENODEV; +} + /* connect mixer widget to it's interconnecting audio paths */ static int dapm_connect_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, @@ -653,6 +698,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) case snd_soc_dapm_vmid: continue; case snd_soc_dapm_mux: + case snd_soc_dapm_value_mux: case snd_soc_dapm_output: case snd_soc_dapm_input: case snd_soc_dapm_switch: @@ -728,6 +774,45 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, return 0; } +/* test and update the power status of a value_mux widget */ +static int dapm_value_mux_update_power(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int mask, + int mux, int val, struct soc_value_enum *e) +{ + struct snd_soc_dapm_path *path; + int found = 0; + + if (widget->id != snd_soc_dapm_value_mux) + return -ENODEV; + + if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) + return 0; + + /* find dapm widget path assoc with kcontrol */ + list_for_each_entry(path, &widget->codec->dapm_paths, list) { + if (path->kcontrol != kcontrol) + continue; + + if (!path->name || !e->texts[mux]) + continue; + + found = 1; + /* we now need to match the string in the enum to the path */ + if (!(strcmp(path->name, e->texts[mux]))) + path->connect = 1; /* new connection */ + else + path->connect = 0; /* old connection must be + powered down */ + } + + if (found) { + dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); + dump_dapm(widget->codec, "mux power update"); + } + + return 0; +} + /* test and update the power status of a mixer or switch widget */ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int reg, @@ -965,6 +1050,12 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, if (ret != 0) goto err; break; + case snd_soc_dapm_value_mux: + ret = dapm_connect_value_mux(codec, wsource, wsink, path, + control, &wsink->kcontrols[0]); + if (ret != 0) + goto err; + break; case snd_soc_dapm_switch: case snd_soc_dapm_mixer: ret = dapm_connect_mixer(codec, wsource, wsink, path, control); @@ -1047,6 +1138,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) dapm_new_mixer(codec, w); break; case snd_soc_dapm_mux: + case snd_soc_dapm_value_mux: dapm_new_mux(codec, w); break; case snd_soc_dapm_adc: @@ -1274,6 +1366,105 @@ out: EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); /** + * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get + * callback + * @kcontrol: mixer control + * @ucontrol: control element information + * + * Callback to get the value of a dapm semi enumerated double mixer control. + * + * Semi enumerated mixer: the enumerated items are referred as values. Can be + * used for handling bitfield coded enumeration for example. + * + * Returns 0 for success. + */ +int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct soc_value_enum *e = (struct soc_value_enum *) + kcontrol->private_value; + unsigned short reg_val, val, mux; + + reg_val = snd_soc_read(widget->codec, e->reg); + val = (reg_val >> e->shift_l) & e->mask; + for (mux = 0; mux < e->max; mux++) { + if (val == e->values[mux]) + break; + } + ucontrol->value.enumerated.item[0] = mux; + if (e->shift_l != e->shift_r) { + val = (reg_val >> e->shift_r) & e->mask; + for (mux = 0; mux < e->max; mux++) { + if (val == e->values[mux]) + break; + } + ucontrol->value.enumerated.item[1] = mux; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); + +/** + * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set + * callback + * @kcontrol: mixer control + * @ucontrol: control element information + * + * Callback to set the value of a dapm semi enumerated double mixer control. + * + * Semi enumerated mixer: the enumerated items are referred as values. Can be + * used for handling bitfield coded enumeration for example. + * + * Returns 0 for success. + */ +int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); + struct soc_value_enum *e = (struct soc_value_enum *) + kcontrol->private_value; + unsigned short val, mux; + unsigned short mask; + int ret = 0; + + if (ucontrol->value.enumerated.item[0] > e->max - 1) + return -EINVAL; + mux = ucontrol->value.enumerated.item[0]; + val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; + mask = e->mask << e->shift_l; + if (e->shift_l != e->shift_r) { + if (ucontrol->value.enumerated.item[1] > e->max - 1) + return -EINVAL; + val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; + mask |= e->mask << e->shift_r; + } + + mutex_lock(&widget->codec->mutex); + widget->value = val; + dapm_value_mux_update_power(widget, kcontrol, mask, mux, val, e); + if (widget->event) { + if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { + ret = widget->event(widget, + kcontrol, SND_SOC_DAPM_PRE_REG); + if (ret < 0) + goto out; + } + ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); + if (widget->event_flags & SND_SOC_DAPM_POST_REG) + ret = widget->event(widget, + kcontrol, SND_SOC_DAPM_POST_REG); + } else + ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); + +out: + mutex_unlock(&widget->codec->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); + +/** * snd_soc_dapm_new_control - create new dapm control * @codec: audio codec * @widget: widget template -- cgit v1.1 From 2f42357722f7ddc1ec0236fa55ad49ea8a7ce4b0 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 5 Jan 2009 09:54:58 +0200 Subject: ASoC: TWL4030: Convert the bitfield enums to VALUE_ENUM type Convert the bitfield coded enums to the new VALUE_ENUM type. Remove the enum check, since the VALUE_ENUM type can handle the bitfield coding and also handles the 'holes' in the bitfield. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 118 +++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 63 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 31e44e3..fd0f338 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -192,39 +192,51 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* Earpiece */ static const char *twl4030_earpiece_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", "DACR1"}; + {"Off", "DACL1", "DACL2", "DACR1"}; -static const struct soc_enum twl4030_earpiece_enum = - SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, +static const unsigned int twl4030_earpiece_values[] = + {0x0, 0x1, 0x2, 0x4}; + +static const struct soc_value_enum twl4030_earpiece_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7, ARRAY_SIZE(twl4030_earpiece_texts), - twl4030_earpiece_texts); + twl4030_earpiece_texts, + twl4030_earpiece_values); static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = -SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); +SOC_DAPM_VALUE_ENUM("Route", twl4030_earpiece_enum); /* PreDrive Left */ static const char *twl4030_predrivel_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", "DACR2"}; + {"Off", "DACL1", "DACL2", "DACR2"}; + +static const unsigned int twl4030_predrivel_values[] = + {0x0, 0x1, 0x2, 0x4}; -static const struct soc_enum twl4030_predrivel_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, +static const struct soc_value_enum twl4030_predrivel_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7, ARRAY_SIZE(twl4030_predrivel_texts), - twl4030_predrivel_texts); + twl4030_predrivel_texts, + twl4030_predrivel_values); static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = -SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); +SOC_DAPM_VALUE_ENUM("Route", twl4030_predrivel_enum); /* PreDrive Right */ static const char *twl4030_predriver_texts[] = - {"Off", "DACR1", "DACR2", "Invalid", "DACL2"}; + {"Off", "DACR1", "DACR2", "DACL2"}; -static const struct soc_enum twl4030_predriver_enum = - SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, +static const unsigned int twl4030_predriver_values[] = + {0x0, 0x1, 0x2, 0x4}; + +static const struct soc_value_enum twl4030_predriver_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7, ARRAY_SIZE(twl4030_predriver_texts), - twl4030_predriver_texts); + twl4030_predriver_texts, + twl4030_predriver_values); static const struct snd_kcontrol_new twl4030_dapm_predriver_control = -SOC_DAPM_ENUM("Route", twl4030_predriver_enum); +SOC_DAPM_VALUE_ENUM("Route", twl4030_predriver_enum); /* Headset Left */ static const char *twl4030_hsol_texts[] = @@ -300,28 +312,35 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); /* Left analog microphone selection */ static const char *twl4030_analoglmic_texts[] = - {"Off", "Main mic", "Headset mic", "Invalid", "AUXL", - "Invalid", "Invalid", "Invalid", "Carkit mic"}; + {"Off", "Main mic", "Headset mic", "AUXL", "Carkit mic"}; + +static const unsigned int twl4030_analoglmic_values[] = + {0x0, 0x1, 0x2, 0x4, 0x8}; -static const struct soc_enum twl4030_analoglmic_enum = - SOC_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, +static const struct soc_value_enum twl4030_analoglmic_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf, ARRAY_SIZE(twl4030_analoglmic_texts), - twl4030_analoglmic_texts); + twl4030_analoglmic_texts, + twl4030_analoglmic_values); static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control = -SOC_DAPM_ENUM("Route", twl4030_analoglmic_enum); +SOC_DAPM_VALUE_ENUM("Route", twl4030_analoglmic_enum); /* Right analog microphone selection */ static const char *twl4030_analogrmic_texts[] = - {"Off", "Sub mic", "Invalid", "Invalid", "AUXR"}; + {"Off", "Sub mic", "AUXR"}; -static const struct soc_enum twl4030_analogrmic_enum = - SOC_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, +static const unsigned int twl4030_analogrmic_values[] = + {0x0, 0x1, 0x4}; + +static const struct soc_value_enum twl4030_analogrmic_enum = + SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5, ARRAY_SIZE(twl4030_analogrmic_texts), - twl4030_analogrmic_texts); + twl4030_analogrmic_texts, + twl4030_analogrmic_values); static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control = -SOC_DAPM_ENUM("Route", twl4030_analogrmic_enum); +SOC_DAPM_VALUE_ENUM("Route", twl4030_analogrmic_enum); /* TX1 L/R Analog/Digital microphone selection */ static const char *twl4030_micpathtx1_texts[] = @@ -347,28 +366,6 @@ static const struct soc_enum twl4030_micpathtx2_enum = static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); -/* - * This function filters out the non valid mux settings, named as "Invalid" - * in the enum texts. - * Just refuse to set an invalid mux mode. - */ -static int twl4030_enum_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int ret = 0; - int val; - - val = w->value >> e->shift_l; - if (!strcmp("Invalid", e->texts[val])) { - printk(KERN_WARNING "Invalid MUX setting on 0x%02x (%d)\n", - e->reg, val); - ret = -1; - } - - return ret; -} - static int micpath_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -737,16 +734,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { /* Output MUX controls */ /* Earpiece */ - SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_earpiece_control, twl4030_enum_event, - SND_SOC_DAPM_PRE_REG), + SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_earpiece_control), /* PreDrivL/R */ - SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predrivel_control, twl4030_enum_event, - SND_SOC_DAPM_PRE_REG), - SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, - &twl4030_dapm_predriver_control, twl4030_enum_event, - SND_SOC_DAPM_PRE_REG), + SND_SOC_DAPM_VALUE_MUX("PredriveL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predrivel_control), + SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predriver_control), /* HeadsetL/R */ SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_hsol_control), @@ -789,12 +783,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_POST_REG), /* Analog input muxes with power switch for the physical ADCL/R */ - SND_SOC_DAPM_MUX_E("Analog Left Capture Route", - TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control, - twl4030_enum_event, SND_SOC_DAPM_PRE_REG), - SND_SOC_DAPM_MUX_E("Analog Right Capture Route", - TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control, - twl4030_enum_event, SND_SOC_DAPM_PRE_REG), + SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route", + TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control), + SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route", + TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control), SND_SOC_DAPM_PGA("Analog Left Amplifier", TWL4030_REG_ANAMICL, 4, 0, NULL, 0), -- cgit v1.1 From 8c0bad7fa5be47aa8a3d03ff6ee1917fa68b72e3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 6 Jan 2009 09:52:18 +0000 Subject: ASoC: Use snd_soc_dapm_nc_pin() in at91sam9g20ek Signed-off-by: Mark Brown --- sound/soc/atmel/sam9g20_wm8731.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 1fb59a9..6ea04be 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -221,8 +221,8 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); /* not connected */ - snd_soc_dapm_disable_pin(codec, "RLINEIN"); - snd_soc_dapm_disable_pin(codec, "LLINEIN"); + snd_soc_dapm_nc_pin(codec, "RLINEIN"); + snd_soc_dapm_nc_pin(codec, "LLINEIN"); /* always connected */ snd_soc_dapm_enable_pin(codec, "Int Mic"); -- cgit v1.1 From 025dfdafe77f20b3890981a394774baab7b9c827 Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Thu, 16 Oct 2008 19:02:37 +0200 Subject: trivial: fix then -> than typos in comments and documentation - (better, more, bigger ...) then -> (...) than Signed-off-by: Frederik Schwarzer Signed-off-by: Jiri Kosina --- sound/usb/usx2y/usbusx2y.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index ca26c53..11639bd 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -238,7 +238,7 @@ static void i_usX2Y_In04Int(struct urb *urb) send = 0; for (j = 0; j < URBS_AsyncSeq && !err; ++j) if (0 == usX2Y->AS04.urb[j]->status) { - struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more then 1 p4out is new, 1 gets lost. + struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost. usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol, p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5, -- cgit v1.1 From 0211a9c8508b2183e0e539509aad60414f1c3813 Mon Sep 17 00:00:00 2001 From: Frederik Schwarzer Date: Mon, 29 Dec 2008 22:14:56 +0100 Subject: trivial: fix an -> a typos in documentation and comments It is always "an" if there is a vowel _spoken_ (not written). So it is: "an hour" (spoken vowel) but "a uniform" (spoken 'j') Signed-off-by: Frederik Schwarzer Signed-off-by: Jiri Kosina --- sound/oss/aedsp16.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c index a0274f3..3ee9900 100644 --- a/sound/oss/aedsp16.c +++ b/sound/oss/aedsp16.c @@ -157,7 +157,7 @@ Started Fri Mar 17 16:13:18 MET 1995 - v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c) + v0.1 (ALPHA, was a user-level program called AudioExcelDSP16.c) - Initial code. v0.2 (ALPHA) - Cleanups. -- cgit v1.1 From 227b4dc6432d271eecd0ff0aefe6f0897ec47397 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 3 Jan 2009 11:24:41 +0100 Subject: ASoC: Fix SND_SOC_ALL_CODECS handling of dual SPI and I2C control buses For codecs that have both SPI and I2C support we need to ensure that we don't try to make the codec driver built in when I2C is modular since that won't link. Do this by creating a helper variable which uses conditional defaults to pick up the correct value for all combinations. We don't need to do anything special for I2C-only codecs since a conditional select passes on the full value for a tristate. Reported-by: Ingo Molnar Tested-by: Ingo Molnar Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c41289b..d0e0d69 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1,3 +1,13 @@ +# Helper to resolve issues with configs that have SPI enabled but I2C +# modular, meaning we can't build the codec driver in with I2C support. +# We use an ordered list of conditional defaults to pick the appropriate +# setting - SPI can't be modular so that case doesn't need to be covered. +config SND_SOC_I2C_AND_SPI + tristate + default m if I2C=m + default y if I2C=y + default y if SPI_MASTER=y + config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS @@ -14,12 +24,12 @@ config SND_SOC_ALL_CODECS select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C select SND_SOC_WM8350 if MFD_WM8350 - select SND_SOC_WM8510 if (I2C || SPI_MASTER) + select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8580 if I2C - select SND_SOC_WM8728 if (I2C || SPI_MASTER) - select SND_SOC_WM8731 if (I2C || SPI_MASTER) - select SND_SOC_WM8750 if (I2C || SPI_MASTER) - select SND_SOC_WM8753 if (I2C || SPI_MASTER) + select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8900 if I2C select SND_SOC_WM8903 if I2C select SND_SOC_WM8971 if I2C -- cgit v1.1 From 3f4528d6e91cffde49894f5252e6657d420d3d74 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Tue, 6 Jan 2009 13:20:38 -0800 Subject: sparc64: Fix unsigned long long warnings in drivers. Fix warnings caused by the unsigned long long usage in sparc specific drivers. The drivers were considered sparc specific more or less from the filename alone. Signed-off-by: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- sound/sparc/cs4231.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index d44bf98..41c3875 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -2057,7 +2057,7 @@ static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_dev if (err) return err; - sprintf(card->longname, "%s at 0x%lx, irq %d", + sprintf(card->longname, "%s at 0x%llx, irq %d", card->shortname, op->resource[0].start, op->irqs[0]); -- cgit v1.1 From f41ced8f108cc80f16509b907cd7ac93944459bc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 6 Jan 2009 14:40:40 -0800 Subject: Check fops_get() return value Several subsystem open handlers dereference the fops_get() return value without checking it for nullness. This opens a race condition between the open handler and module unloading. A module can be marked as being unloaded (MODULE_STATE_GOING) before its exit function is called and gets the chance to unregister the driver. During that window open handlers can still be called, and fops_get() will fail in try_module_get() and return a NULL pointer. This change checks the fops_get() return value and returns -ENODEV if NULL. Reported-by: Alan Jenkins Signed-off-by: Laurent Pinchart Acked-by: Takashi Iwai Cc: Al Viro Cc: Dave Airlie Acked-by: Mauro Carvalho Chehab Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/core/sound.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/core/sound.c b/sound/core/sound.c index 44a69bb..7872a02 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -152,6 +152,10 @@ static int __snd_open(struct inode *inode, struct file *file) } old_fops = file->f_op; file->f_op = fops_get(mptr->f_ops); + if (file->f_op == NULL) { + file->f_op = old_fops; + return -ENODEV; + } if (file->f_op->open) err = file->f_op->open(inode, file); if (err) { -- cgit v1.1 From d5337debacc00591b3f81fc3c982b40af7de1ab6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Jan 2009 11:41:57 +0100 Subject: ALSA: hda - Add quirk for HP 2230s Added a quirk for HP 2230s, model=laptop, with AD1984A codec. Reference: Novell bnc#461660 https://bugzilla.novell.com/show_bug.cgi?id=461660 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 26247cf..13e4d91 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3900,6 +3900,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = { static struct snd_pci_quirk ad1884a_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), -- cgit v1.1 From c247ed6f5205f9feebd276c4cbe45018b10f19fa Mon Sep 17 00:00:00 2001 From: Clemens Fruhwirth Date: Wed, 7 Jan 2009 11:43:48 +0100 Subject: ALSA: hda - Fix typos for AD1882 codecs Fixed typos of codec-id checks for AD1882/AD1882A. Cc: stable@kernel.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 13e4d91..2e7371e 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -4263,13 +4263,13 @@ static int patch_ad1882(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids); spec->adc_nids = ad1882_adc_nids; spec->capsrc_nids = ad1882_capsrc_nids; - if (codec->vendor_id == 0x11d1882) + if (codec->vendor_id == 0x11d41882) spec->input_mux = &ad1882_capture_source; else spec->input_mux = &ad1882a_capture_source; spec->num_mixers = 2; spec->mixers[0] = ad1882_base_mixers; - if (codec->vendor_id == 0x11d1882) + if (codec->vendor_id == 0x11d41882) spec->mixers[1] = ad1882_loopback_mixers; else spec->mixers[1] = ad1882a_loopback_mixers; -- cgit v1.1 From e3d6ce6ff6e22ba35de77e306520779b384f0c38 Mon Sep 17 00:00:00 2001 From: Brian Hinz Date: Wed, 7 Jan 2009 11:49:56 +0100 Subject: ALSA: hda - Add codec ID for MCP73 HDMI Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 0270fda..96952a3 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -162,12 +162,14 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; MODULE_ALIAS("snd-hda-codec-id:10de0002"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); +MODULE_ALIAS("snd-hda-codec-id:10de8001"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); -- cgit v1.1 From a8e4f9ddea4a23705d4eea6afe4a01e1a57a0621 Mon Sep 17 00:00:00 2001 From: Lukasz Wojnilowicz Date: Thu, 8 Jan 2009 12:00:49 +0100 Subject: ALSA: hda - Add quirks for Acer Aspire 5930G and 6930G This is a patch which adds correct auto detection of model for snd-hda-intel for Acer Aspire 5930G and 6930G. Tested on my 5930G. It finally adds hp jack sense and 5.1 speaker system sliders. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9065ebf..ad23dc3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8461,6 +8461,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", + ALC888_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", + ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), -- cgit v1.1 From 741555568f8ba307c626019787c412f4386cafdc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 8 Jan 2009 13:34:29 +0200 Subject: ASoC: Merge the soc_value_enum to soc_enum struct Merge the recently introduced soc_value_enum structure to the soc_enum. The value based enums are still handled separately from the normal enum types, but with the merge some of the newly introduced functions can be removed. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 37 ++---------------------- sound/soc/soc-dapm.c | 80 ++++------------------------------------------------ 2 files changed, 7 insertions(+), 110 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6cbe7e8..55fdb4a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1585,37 +1585,6 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); /** - * snd_soc_info_value_enum_double - semi enumerated double mixer info callback - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to provide information about a double semi enumerated - * mixer control. - * - * Semi enumerated mixer: the enumerated items are referred as values. Can be - * used for handling bitfield coded enumeration for example. - * - * Returns 0 for success. - */ -int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = e->shift_l == e->shift_r ? 1 : 2; - uinfo->value.enumerated.items = e->max; - - if (uinfo->value.enumerated.item > e->max - 1) - uinfo->value.enumerated.item = e->max - 1; - strcpy(uinfo->value.enumerated.name, - e->texts[uinfo->value.enumerated.item]); - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_info_value_enum_double); - -/** * snd_soc_get_value_enum_double - semi enumerated double mixer get callback * @kcontrol: mixer control * @ucontrol: control element information @@ -1631,8 +1600,7 @@ int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short reg_val, val, mux; reg_val = snd_soc_read(codec, e->reg); @@ -1671,8 +1639,7 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short val; unsigned short mask; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ad0d801..493a4e8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -137,7 +137,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, } break; case snd_soc_dapm_value_mux: { - struct soc_value_enum *e = (struct soc_value_enum *) + struct soc_enum *e = (struct soc_enum *) w->kcontrols[i].private_value; int val, item; @@ -200,30 +200,6 @@ static int dapm_connect_mux(struct snd_soc_codec *codec, return -ENODEV; } -/* connect value_mux widget to it's interconnecting audio paths */ -static int dapm_connect_value_mux(struct snd_soc_codec *codec, - struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, - struct snd_soc_dapm_path *path, const char *control_name, - const struct snd_kcontrol_new *kcontrol) -{ - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; - int i; - - for (i = 0; i < e->max; i++) { - if (!(strcmp(control_name, e->texts[i]))) { - list_add(&path->list, &codec->dapm_paths); - list_add(&path->list_sink, &dest->sources); - list_add(&path->list_source, &src->sinks); - path->name = (char *)e->texts[i]; - dapm_set_path_status(dest, path, 0); - return 0; - } - } - - return -ENODEV; -} - /* connect mixer widget to it's interconnecting audio paths */ static int dapm_connect_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, @@ -774,45 +750,6 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, return 0; } -/* test and update the power status of a value_mux widget */ -static int dapm_value_mux_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int mask, - int mux, int val, struct soc_value_enum *e) -{ - struct snd_soc_dapm_path *path; - int found = 0; - - if (widget->id != snd_soc_dapm_value_mux) - return -ENODEV; - - if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) - return 0; - - /* find dapm widget path assoc with kcontrol */ - list_for_each_entry(path, &widget->codec->dapm_paths, list) { - if (path->kcontrol != kcontrol) - continue; - - if (!path->name || !e->texts[mux]) - continue; - - found = 1; - /* we now need to match the string in the enum to the path */ - if (!(strcmp(path->name, e->texts[mux]))) - path->connect = 1; /* new connection */ - else - path->connect = 0; /* old connection must be - powered down */ - } - - if (found) { - dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); - dump_dapm(widget->codec, "mux power update"); - } - - return 0; -} - /* test and update the power status of a mixer or switch widget */ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int reg, @@ -1045,17 +982,12 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, path->connect = 1; return 0; case snd_soc_dapm_mux: + case snd_soc_dapm_value_mux: ret = dapm_connect_mux(codec, wsource, wsink, path, control, &wsink->kcontrols[0]); if (ret != 0) goto err; break; - case snd_soc_dapm_value_mux: - ret = dapm_connect_value_mux(codec, wsource, wsink, path, - control, &wsink->kcontrols[0]); - if (ret != 0) - goto err; - break; case snd_soc_dapm_switch: case snd_soc_dapm_mixer: ret = dapm_connect_mixer(codec, wsource, wsink, path, control); @@ -1382,8 +1314,7 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short reg_val, val, mux; reg_val = snd_soc_read(widget->codec, e->reg); @@ -1423,8 +1354,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); - struct soc_value_enum *e = (struct soc_value_enum *) - kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned short val, mux; unsigned short mask; int ret = 0; @@ -1443,7 +1373,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, mutex_lock(&widget->codec->mutex); widget->value = val; - dapm_value_mux_update_power(widget, kcontrol, mask, mux, val, e); + dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); if (widget->event) { if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { ret = widget->event(widget, -- cgit v1.1 From cb1ace04d7797db21cb5a746ac0e0fc81d526060 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 8 Jan 2009 13:34:30 +0200 Subject: ASoC: TWL4030: Change the soc_value_enum back to soc_enum The soc_value_enum has been merged to soc_enum. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index fd0f338..db24f83 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -197,7 +197,7 @@ static const char *twl4030_earpiece_texts[] = static const unsigned int twl4030_earpiece_values[] = {0x0, 0x1, 0x2, 0x4}; -static const struct soc_value_enum twl4030_earpiece_enum = +static const struct soc_enum twl4030_earpiece_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7, ARRAY_SIZE(twl4030_earpiece_texts), twl4030_earpiece_texts, @@ -213,7 +213,7 @@ static const char *twl4030_predrivel_texts[] = static const unsigned int twl4030_predrivel_values[] = {0x0, 0x1, 0x2, 0x4}; -static const struct soc_value_enum twl4030_predrivel_enum = +static const struct soc_enum twl4030_predrivel_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7, ARRAY_SIZE(twl4030_predrivel_texts), twl4030_predrivel_texts, @@ -229,7 +229,7 @@ static const char *twl4030_predriver_texts[] = static const unsigned int twl4030_predriver_values[] = {0x0, 0x1, 0x2, 0x4}; -static const struct soc_value_enum twl4030_predriver_enum = +static const struct soc_enum twl4030_predriver_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7, ARRAY_SIZE(twl4030_predriver_texts), twl4030_predriver_texts, @@ -317,7 +317,7 @@ static const char *twl4030_analoglmic_texts[] = static const unsigned int twl4030_analoglmic_values[] = {0x0, 0x1, 0x2, 0x4, 0x8}; -static const struct soc_value_enum twl4030_analoglmic_enum = +static const struct soc_enum twl4030_analoglmic_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf, ARRAY_SIZE(twl4030_analoglmic_texts), twl4030_analoglmic_texts, @@ -333,7 +333,7 @@ static const char *twl4030_analogrmic_texts[] = static const unsigned int twl4030_analogrmic_values[] = {0x0, 0x1, 0x4}; -static const struct soc_value_enum twl4030_analogrmic_enum = +static const struct soc_enum twl4030_analogrmic_enum = SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5, ARRAY_SIZE(twl4030_analogrmic_texts), twl4030_analogrmic_texts, -- cgit v1.1 From f3f80a9205da74fa56d613f4c14b88b6e4e6caa8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2009 15:32:56 +0100 Subject: ALSA: caiaq - Fix Oops with MIDI The snd-usb-caiaq driver causes Oops occasionally when accessing MIDI devices. This patch fixes the Oops and invalid URB submission errors as well. Cc: stable@kernel.org Signed-off-by: Takashi Iwai --- sound/usb/caiaq/caiaq-device.h | 1 + sound/usb/caiaq/caiaq-midi.c | 32 ++++++++++++++++++-------------- 2 files changed, 19 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index f9fbdba..ab56e73 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h @@ -75,6 +75,7 @@ struct snd_usb_caiaqdev { wait_queue_head_t ep1_wait_queue; wait_queue_head_t prepare_wait_queue; int spec_received, audio_parm_answer; + int midi_out_active; char vendor_name[CAIAQ_USB_STR_LEN]; char product_name[CAIAQ_USB_STR_LEN]; diff --git a/sound/usb/caiaq/caiaq-midi.c b/sound/usb/caiaq/caiaq-midi.c index 30b57f9..f19fd36 100644 --- a/sound/usb/caiaq/caiaq-midi.c +++ b/sound/usb/caiaq/caiaq-midi.c @@ -59,6 +59,11 @@ static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substrea static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream) { + struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; + if (dev->midi_out_active) { + usb_kill_urb(&dev->midi_out_urb); + dev->midi_out_active = 0; + } return 0; } @@ -69,7 +74,8 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; dev->midi_out_buf[1] = 0; /* port */ - len = snd_rawmidi_transmit_peek(substream, dev->midi_out_buf+3, EP1_BUFSIZE-3); + len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3, + EP1_BUFSIZE - 3); if (len <= 0) return; @@ -79,24 +85,24 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC); if (ret < 0) - log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed, %d\n", - substream, ret); + log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," + "ret=%d, len=%d\n", + substream, ret, len); + else + dev->midi_out_active = 1; } static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; - if (dev->midi_out_substream != NULL) - return; - - if (!up) { + if (up) { + dev->midi_out_substream = substream; + if (!dev->midi_out_active) + snd_usb_caiaq_midi_send(dev, substream); + } else { dev->midi_out_substream = NULL; - return; } - - dev->midi_out_substream = substream; - snd_usb_caiaq_midi_send(dev, substream); } @@ -161,16 +167,14 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) void snd_usb_caiaq_midi_output_done(struct urb* urb) { struct snd_usb_caiaqdev *dev = urb->context; - char *buf = urb->transfer_buffer; + dev->midi_out_active = 0; if (urb->status != 0) return; if (!dev->midi_out_substream) return; - snd_rawmidi_transmit_ack(dev->midi_out_substream, buf[2]); - dev->midi_out_substream = NULL; snd_usb_caiaq_midi_send(dev, dev->midi_out_substream); } -- cgit v1.1 From 57d139278e6c246d78f71e4bf0e0d15bb0390646 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Jan 2009 15:52:09 +0100 Subject: ALSA: hda - Add quirk for Dell Inspiron Mini9 Added a quirk, model=dell, for Dell Inspiron Mini9 with ALC268 codec. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ad23dc3..e8ec741 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11693,6 +11693,7 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One", ALC268_ACER_ASPIRE_ONE), SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), + SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL), SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), -- cgit v1.1 From c19a28e1193a6c854738d609ae9b2fe2f6e6bea4 Mon Sep 17 00:00:00 2001 From: Fernando Carrijo Date: Wed, 7 Jan 2009 18:09:08 -0800 Subject: remove lots of double-semicolons Cc: Ingo Molnar Cc: Thomas Gleixner Acked-by: Theodore Ts'o Acked-by: Mark Fasheh Acked-by: David S. Miller Cc: James Morris Acked-by: Casey Schaufler Acked-by: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/soc/au1x/dbdma2.c | 2 +- sound/soc/davinci/davinci-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 74c823d..bc8d654 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -187,7 +187,7 @@ static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd, au1x_pcm_dmatx_cb, (void *)pcd); if (!pcd->ddma_chan) - return -ENOMEM;; + return -ENOMEM; au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits); au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2); diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 74abc9b..366049d 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -212,7 +212,7 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) count = src - runtime->dma_addr; else - count = dst - runtime->dma_addr;; + count = dst - runtime->dma_addr; spin_unlock(&prtd->lock); -- cgit v1.1 From 16b2857589b77c486f6261fbd0a28107bb9c9953 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Jan 2009 07:51:10 +0100 Subject: ALSA: caiaq - Version 1.3.10 Increase the version number in module info to indicate the fixes. Signed-off-by: Takashi Iwai --- sound/usb/caiaq/caiaq-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index a62500e..41c36b0 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c @@ -42,7 +42,7 @@ #endif MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.9"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.10"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," -- cgit v1.1 From 5a9e02e94989323c2a7102e2fc80ee9102b19fa0 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 9 Jan 2009 16:45:24 +0800 Subject: ALSA: hda - create hda_codec.control_mutex for kcontrol->private_value Fix the following lockdep warning by not reusing the hda_codec.spdif_mutex. ALSA sound/pci/hda/hda_codec.c:882: hda_codec_cleanup_stream: NID=0x2 ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.28-next-20090102 #33 ------------------------------------------------------- mplayer/3151 is trying to acquire lock: (&pcm->open_mutex){--..}, at: [] snd_pcm_release+0x43/0xd0 [snd_pcm] but task is already holding lock: (&mm->mmap_sem){----}, at: [] sys_munmap+0x42/0x80 which lock already depends on the new lock. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 25 +++++++++++++------------ sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/patch_realtek.c | 12 ++++++------ 3 files changed, 20 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e16cf63..f80e5f3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -735,6 +735,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr codec->bus = bus; codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); + mutex_init(&codec->control_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); @@ -1418,12 +1419,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, unsigned long pval; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); pval = kcontrol->private_value; kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); kcontrol->private_value = pval; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); @@ -1435,7 +1436,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, unsigned long pval; int i, indices, err = 0, change = 0; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); pval = kcontrol->private_value; indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; for (i = 0; i < indices; i++) { @@ -1447,7 +1448,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, change |= err; } kcontrol->private_value = pval; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err < 0 ? err : change; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); @@ -1462,12 +1463,12 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, struct hda_bind_ctls *c; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); c = (struct hda_bind_ctls *)kcontrol->private_value; kcontrol->private_value = *c->values; err = c->ops->info(kcontrol, uinfo); kcontrol->private_value = (long)c; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); @@ -1479,12 +1480,12 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct hda_bind_ctls *c; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); c = (struct hda_bind_ctls *)kcontrol->private_value; kcontrol->private_value = *c->values; err = c->ops->get(kcontrol, ucontrol); kcontrol->private_value = (long)c; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); @@ -1497,7 +1498,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, unsigned long *vals; int err = 0, change = 0; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); c = (struct hda_bind_ctls *)kcontrol->private_value; for (vals = c->values; *vals; vals++) { kcontrol->private_value = *vals; @@ -1507,7 +1508,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, change |= err; } kcontrol->private_value = (long)c; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err < 0 ? err : change; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); @@ -1519,12 +1520,12 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, struct hda_bind_ctls *c; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); c = (struct hda_bind_ctls *)kcontrol->private_value; kcontrol->private_value = *c->values; err = c->ops->tlv(kcontrol, op_flag, size, tlv); kcontrol->private_value = (long)c; - mutex_unlock(&codec->spdif_mutex); + mutex_unlock(&codec->control_mutex); return err; } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 729fc76..e9c723e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -771,6 +771,7 @@ struct hda_codec { struct hda_cache_rec cmd_cache; /* cache for other commands */ struct mutex spdif_mutex; + struct mutex control_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e8ec741..aa86a15 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1502,11 +1502,11 @@ static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_unlock(&codec->control_mutex); return err; } @@ -1517,11 +1517,11 @@ static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, struct alc_spec *spec = codec->spec; int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_unlock(&codec->control_mutex); return err; } @@ -1537,11 +1537,11 @@ static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); int err; - mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_lock(&codec->control_mutex); kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx], 3, 0, HDA_INPUT); err = func(kcontrol, ucontrol); - mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + mutex_unlock(&codec->control_mutex); return err; } -- cgit v1.1 From c6d1662b229410e64092fe3a9caed6535fb3dc65 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 8 Jan 2009 15:52:43 +0200 Subject: ASoC: TWL4030: Module unloading fix Call the snd_soc_free_pcm and snd_soc_dapm_free when the codec driver is unloaded. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index db24f83..ea370a4 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1280,6 +1280,8 @@ static int twl4030_remove(struct platform_device *pdev) struct snd_soc_codec *codec = socdev->codec; printk(KERN_INFO "TWL4030 Audio Codec remove\n"); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); kfree(codec); return 0; -- cgit v1.1 From 4b558991049c12689e5fd645222864b8a80730f1 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 12 Jan 2009 09:18:58 +0800 Subject: ALSA: hda - add support for Intel DX58SO board The Intel DX58SO board works fine with model ALC883_3ST_6ch_INTEL. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index aa86a15..ea4c88f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8526,6 +8526,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), + SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), {} }; -- cgit v1.1 From 6acaed38a32e8571e92cfc832b971f9e4450c207 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 12 Jan 2009 10:09:24 +0100 Subject: ALSA: hda - Use own workqueue snd-hda-intel driver used schedule_work() fot the delayed DMA pointer updates, but this has several potential problems: - it may block other eventsd works longer - it may deadlock when probing fails and flush_scheduled_work() is called during probe callback (as probe callback itself could be invoked from eventd) This patch adds an own workq for each driver instance to solve these problems. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 1 - sound/pci/hda/hda_codec.c | 23 +++++++++++++++++------ sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_intel.c | 6 +++--- 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e00421c..960fd79 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -135,7 +135,6 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) struct hda_beep *beep = codec->beep; if (beep) { cancel_work_sync(&beep->beep_work); - flush_scheduled_work(); input_unregister_device(beep->dev); kfree(beep); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f80e5f3..3c596da 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -373,7 +373,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) unsol->queue[wp] = res; unsol->queue[wp + 1] = res_ex; - schedule_work(&unsol->work); + queue_work(bus->workq, &unsol->work); return 0; } @@ -437,15 +437,17 @@ static int snd_hda_bus_free(struct hda_bus *bus) if (!bus) return 0; - if (bus->unsol) { - flush_scheduled_work(); + if (bus->workq) + flush_workqueue(bus->workq); + if (bus->unsol) kfree(bus->unsol); - } list_for_each_entry_safe(codec, n, &bus->codec_list, list) { snd_hda_codec_free(codec); } if (bus->ops.private_free) bus->ops.private_free(bus); + if (bus->workq) + destroy_workqueue(bus->workq); kfree(bus); return 0; } @@ -485,6 +487,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, { struct hda_bus *bus; int err; + char qname[8]; static struct snd_device_ops dev_ops = { .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, @@ -514,6 +517,14 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, mutex_init(&bus->cmd_mutex); INIT_LIST_HEAD(&bus->codec_list); + snprintf(qname, sizeof(qname), "hda%d", card->number); + bus->workq = create_workqueue(qname); + if (!bus->workq) { + snd_printk(KERN_ERR "cannot create workqueue %s\n", qname); + kfree(bus); + return -ENOMEM; + } + err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops); if (err < 0) { snd_hda_bus_free(bus); @@ -684,7 +695,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) return; #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); - flush_scheduled_work(); + flush_workqueue(codec->bus->workq); #endif list_del(&codec->list); snd_array_free(&codec->mixers); @@ -1273,7 +1284,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE cancel_delayed_work(&codec->power_work); - flush_scheduled_work(); + flush_workqueue(codec->bus->workq); #endif snd_hda_ctls_clear(codec); /* relase PCMs */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index e9c723e..5810ef5 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -614,6 +614,7 @@ struct hda_bus { /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; + struct workqueue_struct *workq; /* common workqueue for codecs */ /* assigned PCMs */ DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f04de11..11e791b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -996,10 +996,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(azx_dev->substream); spin_lock(&chip->reg_lock); - } else { + } else if (chip->bus && chip->bus->workq) { /* bogus IRQ, process it later */ azx_dev->irq_pending = 1; - schedule_work(&chip->irq_pending_work); + queue_work(chip->bus->workq, + &chip->irq_pending_work); } } } @@ -1741,7 +1742,6 @@ static void azx_clear_irq_pending(struct azx *chip) for (i = 0; i < chip->num_streams; i++) chip->azx_dev[i].irq_pending = 0; spin_unlock_irq(&chip->reg_lock); - flush_scheduled_work(); } static struct snd_pcm_ops azx_pcm_ops = { -- cgit v1.1 From 89bde7b86e21291ef091dc6ad3e63412f7c6ddd9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 30 Dec 2008 14:25:31 +0100 Subject: m68k: dmasound - Kill warn_unused_result warnings warning: ignoring return value of 'request_irq', declared with attribute warn_unused_result Signed-off-by: Geert Uytterhoeven --- sound/oss/dmasound/dmasound_atari.c | 5 +++-- sound/oss/dmasound/dmasound_q40.c | 16 ++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c index 4d45bd6..57d9f15 100644 --- a/sound/oss/dmasound/dmasound_atari.c +++ b/sound/oss/dmasound/dmasound_atari.c @@ -851,8 +851,9 @@ static int __init AtaIrqInit(void) mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ mfp.tim_ct_a = 8; /* Turn on event counting. */ /* Register interrupt handler. */ - request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound", - AtaInterrupt); + if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound", + AtaInterrupt)) + return 0; mfp.int_en_a |= 0x20; /* Turn interrupt on. */ mfp.int_mk_a |= 0x20; return 1; diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c index 1855b14..99bcb21 100644 --- a/sound/oss/dmasound/dmasound_q40.c +++ b/sound/oss/dmasound/dmasound_q40.c @@ -371,8 +371,9 @@ static void Q40Free(void *ptr, unsigned int size) static int __init Q40IrqInit(void) { /* Register interrupt handler. */ - request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, - "DMA sound", Q40Interrupt); + if (request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, + "DMA sound", Q40Interrupt)) + return 0; return(1); } @@ -401,6 +402,7 @@ static void Q40PlayNextFrame(int index) u_char *start; u_long size; u_char speed; + int error; /* used by Q40Play() if all doubts whether there really is something * to be played are already wiped out. @@ -419,11 +421,13 @@ static void Q40PlayNextFrame(int index) master_outb( 0,SAMPLE_ENABLE_REG); free_irq(Q40_IRQ_SAMPLE, Q40Interrupt); if (dmasound.soft.stereo) - request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, - "Q40 sound", Q40Interrupt); + error = request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0, + "Q40 sound", Q40Interrupt); else - request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0, - "Q40 sound", Q40Interrupt); + error = request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0, + "Q40 sound", Q40Interrupt); + if (error && printk_ratelimit()) + pr_err("Couldn't register sound interrupt\n"); master_outb( speed, SAMPLE_RATE_REG); master_outb( 1,SAMPLE_CLEAR_REG); -- cgit v1.1 From 641b4879444c0edb276fedca5c2fcbd2e5c70044 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Jan 2009 17:05:24 +0100 Subject: ALSA: usb-audio - Cache mixer values Cache mixer values in usb-audio driver to reduce too excessive accesses to the hardware. Signed-off-by: Takashi Iwai --- sound/usb/usbmixer.c | 122 +++++++++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 52 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 00397c8..c07b3f8 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -110,6 +110,8 @@ struct mixer_build { const struct usbmix_selector_map *selector_map; }; +#define MAX_CHANNELS 10 /* max logical channels */ + struct usb_mixer_elem_info { struct usb_mixer_interface *mixer; struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */ @@ -120,6 +122,8 @@ struct usb_mixer_elem_info { int channels; int val_type; int min, max, res; + int cached; + int cache_val[MAX_CHANNELS]; u8 initialized; }; @@ -181,8 +185,6 @@ enum { USB_PROC_DCR_RELEASE = 6, }; -#define MAX_CHANNELS 10 /* max logical channels */ - /* * manual mapping of mixer names @@ -376,11 +378,35 @@ static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int * } /* channel = 0: master, 1 = first channel */ -static inline int get_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int *value) +static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval, + int channel, int *value) { return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value); } +static int get_cur_mix_value(struct usb_mixer_elem_info *cval, + int channel, int index, int *value) +{ + int err; + + if (cval->cached & (1 << channel)) { + *value = cval->cache_val[index]; + return 0; + } + err = get_cur_mix_raw(cval, channel, value); + if (err < 0) { + if (!cval->mixer->ignore_ctl_error) + snd_printd(KERN_ERR "cannot get current value for " + "control %d ch %d: err = %d\n", + cval->control, channel, err); + return err; + } + cval->cached |= 1 << channel; + cval->cache_val[index] = *value; + return 0; +} + + /* * set a mixer value */ @@ -412,9 +438,17 @@ static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int v return set_ctl_value(cval, SET_CUR, validx, value); } -static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, int value) +static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, + int index, int value) { - return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value); + int err; + err = set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, + value); + if (err < 0) + return err; + cval->cached |= 1 << channel; + cval->cache_val[index] = value; + return 0; } /* @@ -718,7 +752,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) if (cval->min + cval->res < cval->max) { int last_valid_res = cval->res; int saved, test, check; - get_cur_mix_value(cval, minchn, &saved); + get_cur_mix_raw(cval, minchn, &saved); for (;;) { test = saved; if (test < cval->max) @@ -726,8 +760,8 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) else test -= cval->res; if (test < cval->min || test > cval->max || - set_cur_mix_value(cval, minchn, test) || - get_cur_mix_value(cval, minchn, &check)) { + set_cur_mix_value(cval, minchn, 0, test) || + get_cur_mix_raw(cval, minchn, &check)) { cval->res = last_valid_res; break; } @@ -735,7 +769,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) break; cval->res *= 2; } - set_cur_mix_value(cval, minchn, saved); + set_cur_mix_value(cval, minchn, 0, saved); } cval->initialized = 1; @@ -775,35 +809,25 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e struct usb_mixer_elem_info *cval = kcontrol->private_data; int c, cnt, val, err; + ucontrol->value.integer.value[0] = cval->min; if (cval->cmask) { cnt = 0; for (c = 0; c < MAX_CHANNELS; c++) { - if (cval->cmask & (1 << c)) { - err = get_cur_mix_value(cval, c + 1, &val); - if (err < 0) { - if (cval->mixer->ignore_ctl_error) { - ucontrol->value.integer.value[0] = cval->min; - return 0; - } - snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err); - return err; - } - val = get_relative_value(cval, val); - ucontrol->value.integer.value[cnt] = val; - cnt++; - } + if (!(cval->cmask & (1 << c))) + continue; + err = get_cur_mix_value(cval, c + 1, cnt, &val); + if (err < 0) + return cval->mixer->ignore_ctl_error ? 0 : err; + val = get_relative_value(cval, val); + ucontrol->value.integer.value[cnt] = val; + cnt++; } + return 0; } else { /* master channel */ - err = get_cur_mix_value(cval, 0, &val); - if (err < 0) { - if (cval->mixer->ignore_ctl_error) { - ucontrol->value.integer.value[0] = cval->min; - return 0; - } - snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err); - return err; - } + err = get_cur_mix_value(cval, 0, 0, &val); + if (err < 0) + return cval->mixer->ignore_ctl_error ? 0 : err; val = get_relative_value(cval, val); ucontrol->value.integer.value[0] = val; } @@ -820,34 +844,28 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e if (cval->cmask) { cnt = 0; for (c = 0; c < MAX_CHANNELS; c++) { - if (cval->cmask & (1 << c)) { - err = get_cur_mix_value(cval, c + 1, &oval); - if (err < 0) { - if (cval->mixer->ignore_ctl_error) - return 0; - return err; - } - val = ucontrol->value.integer.value[cnt]; - val = get_abs_value(cval, val); - if (oval != val) { - set_cur_mix_value(cval, c + 1, val); - changed = 1; - } - get_cur_mix_value(cval, c + 1, &val); - cnt++; + if (!(cval->cmask & (1 << c))) + continue; + err = get_cur_mix_value(cval, c + 1, cnt, &oval); + if (err < 0) + return cval->mixer->ignore_ctl_error ? 0 : err; + val = ucontrol->value.integer.value[cnt]; + val = get_abs_value(cval, val); + if (oval != val) { + set_cur_mix_value(cval, c + 1, cnt, val); + changed = 1; } + cnt++; } } else { /* master channel */ - err = get_cur_mix_value(cval, 0, &oval); - if (err < 0 && cval->mixer->ignore_ctl_error) - return 0; + err = get_cur_mix_value(cval, 0, 0, &oval); if (err < 0) - return err; + return cval->mixer->ignore_ctl_error ? 0 : err; val = ucontrol->value.integer.value[0]; val = get_abs_value(cval, val); if (val != oval) { - set_cur_mix_value(cval, 0, val); + set_cur_mix_value(cval, 0, 0, val); changed = 1; } } -- cgit v1.1