Hi. There are some problems with the controls on the cs4236+ chips. 1) The same control bit is given two different names: > CS4236_SINGLEC("S/PDIF Output 3D", 0, 3, 5, 1, 0), and > CS4236_SINGLEC("3D Control - S/PDIF", 0, 3, 5, 1, 0) 2) The following control is omitted: CS4236_SINGLEC("the name you think appropriate", 0, 4, 7, 1, 0) If you decide to make revisions to the the control section, I would ask that you consider the following: 3) The output is not, strictly speaking, S/PDIF but IEC958 and the controls should be named accordingly. 4) It would help greatly if the controls were arranged in a systematic order within each group, such as: master controls, playback controls, capture controls Presently the controls do not always follow a regular order and the result is that GUI mixer programs lay the controls out in a more confusing way than they otherwise would. I realize that the mixer programs should be written so that control layout can be customized, but there is nothing wrong with providing a default order that is, er, orderly. Please reply with comments if you would like me to submit a patch that addresses these concerns. Thanks very much for all your hard work. Thomas Hood
--- alsa-driver-0.9+0beta4-5/lowlevel/isa/cs4236.c_ORIG Fri Mar 23 16:10:50 2001 +++ alsa-driver-0.9+0beta4-5/lowlevel/isa/cs4236.c Wed Jul 18 11:18:38 2001 @@ -695,58 +695,56 @@ return change; } -#define CS4236_CONTROLS (sizeof(snd_cs4236_controls)/sizeof(snd_kcontrol_new_t)) - -static snd_kcontrol_new_t snd_cs4236_controls[] = { - -CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), -CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), - -CS4236_DOUBLE("Capture Boost Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), - -CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), - -CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), -CS4236_DOUBLE("DSP Playback Volume", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1), - -CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), -CS4236_DOUBLE("FM Playback Volume", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1), - -CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), -CS4236_DOUBLE("Wavetable Playback Volume", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1), - -CS4231_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -CS4231_DOUBLE("Synth Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), -CS4231_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -CS4231_DOUBLE("Synth Capture Bypass", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1), - -CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), -CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), -CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), -CS4236_DOUBLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), - -CS4231_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Line Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), -CS4231_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -CS4231_DOUBLE("Line Capture Bypass", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1), +#define CS4236_SERIAL_ENABLE(xname, xindex) \ +{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex, \ + info: snd_cs4236_info_single, \ + get: snd_cs4236_get_serial_switch, put: snd_cs4236_put_serial_switch, \ + private_value: 1 << 16 } -CS4231_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("CD Volume", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), -CS4231_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), +static int snd_cs4236_get_serial_switch(snd_kcontrol_t * kcontrol, +snd_ctl_elem_value_t * ucontrol) +{ + cs4231_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&chip->reg_lock, flags); + ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? +1 : 0; + spin_unlock_irqrestore(&chip->reg_lock, flags); + return 0; +} -CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), -CS4236_DOUBLE1("Mono Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), -CS4231_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), +static int snd_cs4236_put_serial_switch(snd_kcontrol_t * kcontrol, +snd_ctl_elem_value_t * ucontrol) +{ + cs4231_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + unsigned short enable, val; + + enable = ucontrol->value.integer.value[0] & 1; -CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -CS4231_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), + down(&chip->mce_mutex); + snd_cs4231_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x02) | (enable << 1); + change = val != chip->image[CS4231_ALT_FEATURE_1]; + snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, val); + val = (snd_cs4236_ctrl_in(chip, 4) & ~0x80) | (enable << 7); + change |= snd_cs4236_ctrl_in(chip, 4) != val; + snd_cs4236_ctrl_out(chip, 4, val); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_cs4231_mce_down(chip); + up(&chip->mce_mutex); -CS4231_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1) -}; +#if 0 + printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 += 0x%x\n", + snd_cs4231_in(chip, CS4231_ALT_FEATURE_1), + snd_cs4236_ctrl_in(chip, 3), + snd_cs4236_ctrl_in(chip, 4), + snd_cs4236_ctrl_in(chip, 5), + snd_cs4236_ctrl_in(chip, 6), + snd_cs4236_ctrl_in(chip, 8)); +#endif + return change; +} #define CS4235_CONTROLS (sizeof(snd_cs4235_controls)/sizeof(snd_kcontrol_new_t)) @@ -797,67 +795,72 @@ CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), }; -#define CS4236_IEC958_ENABLE(xname, xindex) \ -{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex, \ - info: snd_cs4236_info_single, \ - get: snd_cs4236_get_iec958_switch, put: snd_cs4236_put_iec958_switch, \ - private_value: 1 << 16 } +#define CS4236_CONTROLS (sizeof(snd_cs4236_controls)/sizeof(snd_kcontrol_new_t)) -static int snd_cs4236_get_iec958_switch(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - cs4231_t *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - - spin_lock_irqsave(&chip->reg_lock, flags); - ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; -} +static snd_kcontrol_new_t snd_cs4236_controls[] = { -static int snd_cs4236_put_iec958_switch(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - cs4231_t *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int change; - unsigned short enable, val; - - enable = ucontrol->value.integer.value[0] & 1; +CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, +7, 1, 1), +CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, +0, 63, 1), - down(&chip->mce_mutex); - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x02) | (enable << 1); - change = val != chip->image[CS4231_ALT_FEATURE_1]; - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, val); - val = (snd_cs4236_ctrl_in(chip, 4) & ~0x80) | (enable << 7); - change |= snd_cs4236_ctrl_in(chip, 4) != val; - snd_cs4236_ctrl_out(chip, 4, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); - up(&chip->mce_mutex); +CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), +CS4236_DOUBLE("FM Playback Volume", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1), -#if 0 - printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n", - snd_cs4231_in(chip, CS4231_ALT_FEATURE_1), - snd_cs4236_ctrl_in(chip, 3), - snd_cs4236_ctrl_in(chip, 4), - snd_cs4236_ctrl_in(chip, 5), - snd_cs4236_ctrl_in(chip, 6), - snd_cs4236_ctrl_in(chip, 8)); -#endif - return change; -} +CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, +7, 1, 1), +CS4236_DOUBLE("Wavetable Playback Volume", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, +0, 63, 1), + +CS4236_SERIAL_ENABLE("Serial Switch", 0), +CS4236_DOUBLE("Serial Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, +1, 1), +CS4236_DOUBLE("Serial Playback Volume", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, +63, 1), + +CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, +7, 6, 1, 1), +CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, +CS4236_RIGHT_MASTER, 7, 7, 1, 1), +CS4236_MASTER_DIGITAL("Master Digital Volume", 0), + +CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), +CS4236_DOUBLE("Mic Playback Boost 20dB Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, +5, 5, 1, 0), +CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, +1), +CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), + +CS4231_DOUBLE("Synth Capture Bypass Switch", 0, CS4231_LEFT_LINE_IN, +CS4231_RIGHT_LINE_IN, 5, 5, 1, 1), +CS4231_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, +6, 6, 1, 1), +CS4231_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, +7, 7, 1, 1), +CS4231_DOUBLE("Synth Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, +1), + +CS4231_DOUBLE("Aux Capture Bypass Switch", 0, CS4231_AUX1_LEFT_INPUT, +CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1), +CS4231_DOUBLE("Aux Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, +CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), +CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, +CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), +CS4231_DOUBLE("Aux Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, +31, 1), + +CS4231_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, +CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), +CS4231_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, +CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), +CS4231_DOUBLE("CD Volume", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, +31, 1), + +CS4236_DOUBLE1("Mono Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, +7, 1, 1), +CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +CS4231_SINGLE("Mono Mono Output Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), + +CS4231_DOUBLE("Hardware Master Capture Switch", 0, CS4231_LEFT_INPUT, +CS4231_RIGHT_INPUT, 7, 7, 1, 0), +CS4236_DOUBLE1("Hardware Master Mono Output Switch", 0, CS4231_MONO_CTRL, +CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), + +CS4231_SINGLE("ADC Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), +CS4236_DOUBLE1("ADC Playback Volume", 0, CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, +0, 63, 1), +CS4236_DOUBLE("ADC Boost Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, +5, 3, 1), +CS4231_DOUBLE("ADC Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0) + +}; + +/* The CS4237B and CS4238B have IEC958 capability */ #define CS4236_IEC958_CONTROLS (sizeof(snd_cs4236_iec958_controls)/sizeof(snd_kcontrol_new_t)) static snd_kcontrol_new_t snd_cs4236_iec958_controls[] = { -CS4236_IEC958_ENABLE("S/PDIF Output Enable", 0), -CS4236_SINGLEC("S/PDIF Output Validity", 0, 4, 4, 1, 0), -CS4236_SINGLEC("S/PDIF Output User", 0, 4, 5, 1, 0), -CS4236_SINGLEC("S/PDIF Output CSBR", 0, 4, 6, 1, 0), -CS4236_SINGLEC("S/PDIF Output 3D", 0, 3, 5, 1, 0), -CS4236_SINGLEC("S/PDIF Output Channel Status Low", 0, 5, 1, 127, 0), -CS4236_SINGLEC("S/PDIF Output Channel Status High", 0, 6, 0, 255, 0) +CS4236_SINGLEC("IEC958 Serial Switch", 0, 4, 7, 1, 0), +CS4236_SINGLEC("IEC958 Serial Master-Digital/ADC Select Switch", 0, 3, 5, 1, 0), +CS4236_SINGLEC("IEC958 Serial Validity Bit", 0, 4, 4, 1, 0), +CS4236_SINGLEC("IEC958 Serial User Bit", 0, 4, 5, 1, 0), +CS4236_SINGLEC("IEC958 Serial Channel Status Block Reset", 0, 4, 6, 1, 0), +CS4236_SINGLEC("IEC958 Serial Channel Status Low", 0, 5, 1, 127, 0), +CS4236_SINGLEC("IEC958 Serial Channel Status High", 0, 6, 0, 255, 0) }; #define CS4236_3D_CONTROLS_CS4235 (sizeof(snd_cs4236_3d_controls_cs4235)/sizeof(snd_kcontrol_new_t)) @@ -871,10 +874,9 @@ static snd_kcontrol_new_t snd_cs4236_3d_controls_cs4237[] = { CS4236_SINGLEC("3D Control - Switch", 0, 3, 7, 1, 0), +CS4236_SINGLEC("3D Control - Mono-to-Stereo Switch", 0, 3, 6, 1, 0), CS4236_SINGLEC("3D Control - Space", 0, 2, 0, 15, 1), -CS4236_SINGLEC("3D Control - Center", 0, 2, 4, 15, 1), -CS4236_SINGLEC("3D Control - Mono", 0, 3, 6, 1, 0), -CS4236_SINGLEC("3D Control - S/PDIF", 0, 3, 5, 1, 0) +CS4236_SINGLEC("3D Control - Center", 0, 2, 4, 15, 1) }; #define CS4236_3D_CONTROLS_CS4238 (sizeof(snd_cs4236_3d_controls_cs4238)/sizeof(snd_kcontrol_new_t)) @@ -882,8 +884,7 @@ static snd_kcontrol_new_t snd_cs4236_3d_controls_cs4238[] = { CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0), CS4236_SINGLEC("3D Control - Space", 0, 2, 0, 15, 1), -CS4236_SINGLEC("3D Control - Volume", 0, 2, 4, 15, 1), -CS4236_SINGLEC("3D Control - S/PDIF", 0, 3, 5, 1, 0) +CS4236_SINGLEC("3D Control - Volume", 0, 2, 4, 15, 1) }; int snd_cs4236_mixer(cs4231_t *chip)