summaryrefslogtreecommitdiff
path: root/kernel/framework/ac97/ac97_ext.inc
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/framework/ac97/ac97_ext.inc')
-rw-r--r--kernel/framework/ac97/ac97_ext.inc1453
1 files changed, 1453 insertions, 0 deletions
diff --git a/kernel/framework/ac97/ac97_ext.inc b/kernel/framework/ac97/ac97_ext.inc
new file mode 100644
index 0000000..425dee7
--- /dev/null
+++ b/kernel/framework/ac97/ac97_ext.inc
@@ -0,0 +1,1453 @@
+
+/*
+ *
+ * Purpose: AC97 chip specific Mixer extension handlers
+ *
+ * This file is included from ac97.c and it implements codec specific
+ * extensions such as S/PDIF control.
+ */
+/*
+ *
+ * This file is part of Open Sound System.
+ *
+ * Copyright (C) 4Front Technologies 1996-2008.
+ *
+ * This this source file is released under GPL v2 license (no other versions).
+ * See the COPYING file included in the main directory of this source
+ * distribution for the license terms and conditions.
+ *
+ */
+
+extern int ac97_recselect;
+
+void
+ac97_enable_spdif (ac97_devc * devc)
+{
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ codec_write (devc, 0x68, codec_read (devc, 0x68) | 0x8000);
+ break;
+ case CX_SPDIFOUT:
+ codec_write (devc, 0x5c, codec_read (devc, 0x5c) | 0x08);
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ codec_write (devc, 0x2a,
+ (codec_read (devc, 0x2a) & 0xffc3) | 0x4 | devc->
+ spdif_slot);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+ac97_disable_spdif (ac97_devc * devc)
+{
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ codec_write (devc, 0x68, codec_read (devc, 0x68) & ~0x8000);
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ codec_write (devc, 0x2a, (codec_read (devc, 0x2a) & 0xffc3) & ~0x4);
+ break;
+ case CX_SPDIFOUT:
+ codec_write (devc, 0x5c, codec_read (devc, 0x5c) & ~0x8);
+ break;
+ default:
+ break;
+ }
+}
+
+/********************AC97 SPDIFIN Control *************************/
+int
+ac97_spdifin_ctl (int dev, int ctrl, unsigned int cmd, int value)
+{
+ ac97_devc *devc = mixer_devs[dev]->devc;
+
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ value = 0;
+ switch (ctrl)
+ {
+ case SPDIFIN_ENABLE: /* Enable/disable SPDIF IN */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x7A) & 0x8000) ? 1 : 0;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x6c) & 0x1) ? 1 : 0;
+ break;
+ case SPDIFIN_PRO: /* Pro */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x60) & 0x1) ? 1 : 0;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x68) & 0x1) ? 1 : 0;
+ break;
+ case SPDIFIN_AUDIO: /* /Audio */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x60) & 0x2) ? 1 : 0;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x68) & 0x1) ? 1 : 0;
+ break;
+ case SPDIFIN_COPY: /* Copy */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x60) & 0x4) ? 1 : 0;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x68) & 0x4) ? 1 : 0;
+ break;
+ case SPDIFIN_PREEMPH: /* Pre */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x60) & 0x38) >> 3;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x68) & 0x38) >> 3;
+ break;
+ case SPDIFIN_MODE: /* Mode */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x60) & 0xc0) ? 1 : 0;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x68) & 0xc0) ? 1 : 0;
+ break;
+ case SPDIFIN_CATEGORY: /* Category */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x60) & 0x7f00) >> 8;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x68) & 0x7f00) >> 8;
+ break;
+ case SPDIFIN_GENERATION: /* Level */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x60) & 0x8000) ? 1 : 0;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x68) & 0x8000) ? 1 : 0;
+ break;
+ case SPDIFIN_SOURCE: /* Source */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = codec_read (devc, 0x62) & 0xf;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = codec_read (devc, 0x6a) & 0xf;
+ break;
+ case SPDIFIN_CHAN: /* Channel */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x62) & 0xf0) >> 4;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x6a) & 0xf0) >> 4;
+ break;
+ case SPDIFIN_RATE: /* Sampling Rate */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x62) & 0xf00) >> 8;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x6a) & 0xf00) >> 8;
+ switch (value)
+ {
+ case 0:
+ value = 44100;
+ break;
+ case 2:
+ value = 48000;
+ break;
+ case 3:
+ value = 32000;
+ break;
+ }
+ break;
+ case SPDIFIN_CLOCK: /* Clock Accuracy */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x62) & 0x3000) >> 12;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = (codec_read (devc, 0x6a) & 0x3000) >> 12;
+ break;
+ case SPDIFIN_SIGNAL: /* Lock */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x62) & 0x4000) ? 1 : 0;
+ break;
+ case SPDIFIN_VBIT: /* VBit */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = (codec_read (devc, 0x62) & 0x8000) ? 1 : 0;
+ break;
+
+ case SPDIFIN_MON: /* SPDIF Input Mon */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ value = codec_read (devc, 0x6A) & (1 << 13) ? 1 : 0;
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ value = codec_read (devc, 0x6c) & 0x8 ? 1 : 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ switch (ctrl)
+ {
+ case SPDIFIN_ENABLE: /* SPDIF Record Enable */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ {
+ if (value)
+ {
+ /* Set 0x7a enable SPDIF Input */
+ /* set 0x6a: PCM Input from SPDIFIN */
+ codec_write (devc, 0x7a, codec_read (devc, 0x7a) | 0x2);
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x8000);
+ }
+ else
+ {
+ codec_write (devc, 0x7a, codec_read (devc, 0x7a) & ~0x2);
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x8000);
+ }
+ }
+
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ {
+ if (value)
+ {
+ codec_write (devc, 0x6c, codec_read (devc, 0x6c) | 1);
+ codec_write (devc, 0x6c, codec_read (devc, 0x6c) | 0x10);
+ }
+ else
+ {
+ codec_write (devc, 0x6c, codec_read (devc, 0x6c) & ~1);
+ codec_write (devc, 0x6c, codec_read (devc, 0x6c) & ~0x10);
+ }
+ }
+ break;
+
+ case SPDIFIN_MON: /* SPDIF input monitor on analog DAC */
+ if (devc->spdifin_support == ALC_SPDIFIN)
+ {
+ if (value)
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | (1 << 13));
+ else
+ codec_write (devc, 0x6a,
+ codec_read (devc, 0x6a) & ~(1 << 13));
+ }
+
+ if (devc->spdifin_support == CMI_SPDIFIN)
+ {
+ if (value)
+ codec_write (devc, 0x6c, codec_read (devc, 0x6c) | 0x8);
+ else
+ codec_write (devc, 0x6c, codec_read (devc, 0x6c) & ~0x8);
+ }
+ break;
+
+ }
+ }
+ return value;
+}
+
+static int
+spdifin_ext_init (int dev)
+{
+ int group, err;
+
+ if ((group = mixer_ext_create_group_flags (dev, 0, "SPDIN", MIXF_FLAT)) < 0)
+ return group;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_ENABLE, ac97_spdifin_ctl,
+ MIXT_ONOFF, "SPDIN_Enable", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_MON, ac97_spdifin_ctl,
+ MIXT_ONOFF, "SPDIN_Monitor", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+#if 1
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_PRO, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Pro", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_AUDIO, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Audio", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_COPY, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Copy", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_PREEMPH,
+ ac97_spdifin_ctl, MIXT_VALUE,
+ "SPDIN_Pre-emph", 1, MIXF_READABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_MODE, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Mode", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_CATEGORY,
+ ac97_spdifin_ctl, MIXT_VALUE,
+ "SPDIN_CATEGORY", 1, MIXF_READABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_GENERATION,
+ ac97_spdifin_ctl, MIXT_VALUE,
+ "SPDIN_GenLevel", 1, MIXF_READABLE)) < 0)
+ return err;
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_SOURCE, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Source", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_CHAN, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Channel", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_RATE, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Rate", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_CLOCK, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Clock", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_SIGNAL, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_Signal", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFIN_VBIT, ac97_spdifin_ctl,
+ MIXT_VALUE, "SPDIN_VBit", 1,
+ MIXF_READABLE)) < 0)
+ return err;
+#endif
+ return 0;
+}
+
+/********************AC97 SPDIFOUT Control *************************/
+int
+ac97_spdifout_ctl (int dev, int ctrl, unsigned int cmd, int value)
+{
+ int tmp = 0;
+ static int flag;
+ ac97_devc *devc = mixer_devs[dev]->devc;
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ value = 0;
+ switch (ctrl)
+ {
+ case SPDIFOUT_ENABLE: /* SPDIF OUT */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ value = (codec_read (devc, 0x68) & 0x8000) ? 1 : 0;
+ break;
+ case CX_SPDIFOUT:
+ value = (codec_read (devc, 0x5c) & 0x08) ? 1 : 0;
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ value = (codec_read (devc, 0x2a) & 0x4) ? 1 : 0;
+ break;
+ }
+ break;
+
+ case SPDIFOUT_PRO: /* Consumer/PRO */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ value = (codec_read (devc, 0x68) & 0x1) ? 1 : 0;
+ break;
+ case CX_SPDIFOUT:
+ value = (codec_read (devc, 0x5c) & 0x1) ? 1 : 0;
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ value = (codec_read (devc, 0x3a) & 0x1) ? 1 : 0;
+ break;
+ }
+ break;
+
+ case SPDIFOUT_AUDIO: /* PCM/AC3 */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ value = (codec_read (devc, 0x68) & 0x2) ? 1 : 0;
+ break;
+ case CX_SPDIFOUT:
+ value = (codec_read (devc, 0x5c) & 0x2) ? 1 : 0;
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ value = (codec_read (devc, 0x3a) & 0x2) ? 1 : 0;
+ break;
+ }
+ break;
+
+ case SPDIFOUT_COPY: /* Copy Prot */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ value = (codec_read (devc, 0x68) & 0x4) ? 1 : 0;
+ break;
+ case CX_SPDIFOUT:
+ value = (codec_read (devc, 0x5c) & 0x4) ? 1 : 0;
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ value = (codec_read (devc, 0x3a) & 0x4) ? 1 : 0;
+ break;
+ }
+ break;
+
+ case SPDIFOUT_PREEMPH: /* Pre emphasis */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ value = codec_read (devc, 0x68) & 0x8 ? 1 : 0;
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ value = (codec_read (devc, 0x3a) & 0x8) ? 1 : 0;
+ break;
+ }
+ break;
+
+ case SPDIFOUT_RATE: /* Sampling Rate */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ {
+ tmp = codec_read (devc, 0x68) & 0x1000;
+ switch (tmp)
+ {
+ case 0x1000:
+ value = 0;
+ break;
+ case 0x0000:
+ value = 1;
+ break;
+ default:
+ cmn_err (CE_NOTE, "unsupported SPDIF F/S rate\n");
+ break;
+ }
+
+ }
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ {
+ tmp = codec_read (devc, 0x3a) & 0x3000;
+ switch (tmp)
+ {
+ case 0x2000:
+ value = 0;
+ break;
+ case 0x0000:
+ value = 1;
+ break;
+ case 0x3000:
+ value = 2;
+ break;
+ default:
+ cmn_err (CE_NOTE, "unsupported SPDIF F/S rate\n");
+ value = 0;
+ break;
+ }
+ }
+ break;
+ }
+ break;
+
+ case SPDIFOUT_VBIT: /* V Bit */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ value = codec_read (devc, 0x68) & 0x4000 ? 1 : 0;
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ value = codec_read (devc, 0x3a) & 0x8000 ? 1 : 0;
+ break;
+ }
+ break;
+
+ case SPDIFOUT_ADC: /* Analog In to SPDIF Out */
+ switch (devc->spdifout_support)
+ {
+ case ALC_SPDIFOUT:
+ value = codec_read (devc, 0x6a) & (1 << 12) ? 1 : 0;
+ break;
+
+ case AD_SPDIFOUT:
+ value = codec_read (devc, 0x74) & 0x4 ? 1 : 0;
+ break;
+
+ case CS_SPDIFOUT:
+ value = codec_read (devc, 0x5e) & (1 << 11) ? 1 : 0;
+ break;
+
+ case STAC_SPDIFOUT:
+ value = codec_read (devc, 0x6a) & 0x2 ? 1 : 0;
+ break;
+
+ case YMF_SPDIFOUT:
+ value = codec_read (devc, 0x66) & 0x2 ? 1 : 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ ac97_disable_spdif (devc);
+ switch (ctrl)
+ {
+ case SPDIFOUT_ENABLE: /* Enable SPDIF OUT */
+ if (value)
+ {
+ ac97_enable_spdif (devc);
+ flag = 1;
+ }
+ else
+ {
+ ac97_disable_spdif (devc);
+ flag = 0;
+ }
+ break;
+
+ case SPDIFOUT_PRO: /* consumer/pro audio */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x68, codec_read (devc, 0x68) | 1);
+ else
+ codec_write (devc, 0x68, codec_read (devc, 0x68) & ~1);
+ break;
+ case CX_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x5c, codec_read (devc, 0x5c) | 1);
+ else
+ codec_write (devc, 0x5c, codec_read (devc, 0x5c) & ~1);
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 1);
+ else
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~1);
+ break;
+ }
+ break;
+
+ case SPDIFOUT_AUDIO: /* PCM/AC3 */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x68, codec_read (devc, 0x68) | 0x2);
+ else
+ codec_write (devc, 0x68, codec_read (devc, 0x68) & ~2);
+ break;
+ case CX_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x5c, codec_read (devc, 0x5c) | 0x2);
+ else
+ codec_write (devc, 0x5c, codec_read (devc, 0x5c) & ~2);
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 0x2);
+ else
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~2);
+ break;
+ }
+ break;
+
+ case SPDIFOUT_COPY: /* copy prot */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x68, codec_read (devc, 0x68) | 4);
+ else
+ codec_write (devc, 0x68, codec_read (devc, 0x68) & ~4);
+ break;
+ case CX_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x5c, codec_read (devc, 0x5c) | 4);
+ else
+ codec_write (devc, 0x5c, codec_read (devc, 0x5c) & ~4);
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 4);
+ else
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~4);
+ break;
+ }
+ break;
+
+ case SPDIFOUT_PREEMPH: /* preemphasis */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x68, codec_read (devc, 0x68) | 8);
+ else
+ codec_write (devc, 0x68, codec_read (devc, 0x68) & ~8);
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 8);
+ else
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~8);
+ break;
+ }
+ break;
+
+ case SPDIFOUT_RATE: /* Frequency */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ switch (value)
+ {
+ case 0:
+ codec_write (devc, 0x68,
+ (codec_read (devc, 0x68) & 0xEFFF) | 0x1000);
+ break;
+ case 1:
+ codec_write (devc, 0x68,
+ (codec_read (devc, 0x68) & 0xEFFF) | 0);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ switch (value)
+ {
+ case 0: /* 48000 */
+ codec_write (devc, 0x3a,
+ (codec_read (devc, 0x3a) & 0xcfff) | 0x2000);
+ break;
+ case 1: /* 44100 */
+ codec_write (devc, 0x3a,
+ (codec_read (devc, 0x3a) & 0xcfff) | 0x0);
+ break;
+ case 2: /* 32000 */
+ codec_write (devc, 0x3a,
+ (codec_read (devc, 0x3a) & 0xcfff) | 0x3000);
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ break;
+
+ case SPDIFOUT_VBIT: /* V Bit */
+ switch (devc->spdifout_support)
+ {
+ case CS_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x68, codec_read (devc, 0x68) | 0x4000);
+ else
+ codec_write (devc, 0x68, codec_read (devc, 0x68) & ~0x4000);
+ break;
+ case AD_SPDIFOUT:
+ case ALC_SPDIFOUT:
+ case VIA_SPDIFOUT:
+ case STAC_SPDIFOUT:
+ case CMI_SPDIFOUT:
+ case YMF_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 0x8000);
+ else
+ codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~0x8000);
+ break;
+ }
+ break;
+
+ case SPDIFOUT_ADC: /* Analog In to SPDIF Out */
+ switch (devc->spdifout_support)
+ {
+ case ALC_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | (1 << 12));
+ else
+ codec_write (devc, 0x6a,
+ codec_read (devc, 0x6a) & ~(1 << 12));
+ break;
+
+ case AD_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x74, codec_read (devc, 0x74) | 0x4);
+ else
+ codec_write (devc, 0x74, codec_read (devc, 0x74) & ~0x4);
+ break;
+
+ case CS_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x5e, codec_read (devc, 0x5e) | (1 << 11));
+ else
+ codec_write (devc, 0x5e,
+ codec_read (devc, 0x5e) & ~(1 << 11));
+ break;
+
+ case STAC_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x2);
+ else
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x2);
+ break;
+
+ case CMI_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x6c, codec_read (devc, 0x6c) | 0x2);
+ else
+ codec_write (devc, 0x6c, codec_read (devc, 0x6c) & ~0x2);
+ break;
+
+ case YMF_SPDIFOUT:
+ if (value)
+ codec_write (devc, 0x66, codec_read (devc, 0x66) | 0x2);
+ else
+ codec_write (devc, 0x66, codec_read (devc, 0x66) & ~0x2);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (flag)
+ ac97_enable_spdif (devc);
+ }
+
+ return value;
+}
+
+static int
+spdifout_ext_init (int dev)
+{
+ int group, err;
+ if ((group =
+ mixer_ext_create_group_flags (dev, 0, "SPDOUT", MIXF_FLAT)) < 0)
+ return group;
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFOUT_ENABLE,
+ ac97_spdifout_ctl, MIXT_ONOFF,
+ "SPDOUT_ENABLE", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFOUT_ADC,
+ ac97_spdifout_ctl, MIXT_ONOFF,
+ "SPDOUT_ADC/DAC", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFOUT_PRO,
+ ac97_spdifout_ctl, MIXT_ENUM,
+ "SPDOUT_Pro", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFOUT_AUDIO,
+ ac97_spdifout_ctl, MIXT_ENUM,
+ "SPDOUT_Audio", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFOUT_COPY,
+ ac97_spdifout_ctl, MIXT_ONOFF,
+ "SPDOUT_Copy", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFOUT_PREEMPH,
+ ac97_spdifout_ctl, MIXT_ONOFF,
+ "SPDOUT_Pre-emph", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFOUT_RATE,
+ ac97_spdifout_ctl, MIXT_ENUM,
+ "SPDOUT_Rate", 3,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPDIFOUT_VBIT,
+ ac97_spdifout_ctl, MIXT_ONOFF,
+ "SPDOUT_VBit", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ return 0;
+}
+
+/**********************Mixer Extensions ********************/
+int
+ac97_mixext_ctl (int dev, int ctrl, unsigned int cmd, int value)
+{
+ int left, right;
+ ac97_devc *devc = mixer_devs[dev]->devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ value = 0;
+ switch (ctrl)
+ {
+ case VOL_CENTER: /* Left line in to output connection */
+ value = devc->extmixlevels[CENTER_VOL]; /* LFE/Center */
+ break;
+
+ case VOL_REAR:
+ value = devc->extmixlevels[REAR_VOL]; /* Rear/Surround */
+ break;
+
+ case VOL_SIDE:
+ value = devc->extmixlevels[SIDE_VOL]; /* Side Surround */
+ break;
+
+ case REAR2LINE: /* Rear to Line In */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ value = (codec_read (devc, 0x6A) & 0x200) ? 1 : 0;
+ if (devc->mixer_ext == CMI9739_MIXER_EXT)
+ value = (codec_read (devc, 0x64) & 0x400) ? 1 : 0;
+ if (devc->mixer_ext == STAC9758_MIXER_EXT)
+ value = (codec_read (devc, 0x64) & 0x50) ? 1 : 0;
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ value = (codec_read (devc, 0x76) & (1 << 11)) ? 0 : 1;
+ break;
+
+ case CENTER2MIC: /* Center to Mic */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ value = (codec_read (devc, 0x6A) & 0x400) ? 1 : 0;
+ if (devc->mixer_ext == CMI9739_MIXER_EXT)
+ value = (codec_read (devc, 0x64) & 0x1000) ? 1 : 0;
+ if (devc->mixer_ext == STAC9758_MIXER_EXT)
+ value = (codec_read (devc, 0x64) & 0x0C) ? 1 : 0;
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ value = (codec_read (devc, 0x76) & (1 << 12)) ? 0 : 1;
+ break;
+
+ case SPREAD: /* Duplicate front on lfe/rear */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ value = (codec_read (devc, 0x6A) & 0x1) ? 1 : 0;
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ value = (codec_read (devc, 0x76) & 0x80) ? 1 : 0;
+ if (devc->mixer_ext == VIA1616_MIXER_EXT)
+ value = (codec_read (devc, 0x5a) & 0x8000) ? 1 : 0;
+ break;
+
+ case MICBOOST: /* 30db Mic boost */
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ value = (codec_read (devc, 0x76) & 0x2) ? 1 : 0;
+ if (devc->mixer_ext == CMI9739_MIXER_EXT)
+ value = (codec_read (devc, 0x64) & 0x1) ? 1 : 0;
+ break;
+
+ case DOWNMIX_LFE: /* Downmix LFE to Front */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ value = (codec_read (devc, 0x6A) & 0x4) ? 1 : 0;
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ value = (codec_read (devc, 0x76) & 0x100) ? 1 : 0;
+ if (devc->mixer_ext == VIA1616_MIXER_EXT)
+ value = (codec_read (devc, 0x5a) & 0x1000) ? 1 : 0;
+ break;
+
+ case DOWNMIX_REAR: /* Downmix Rear to Front */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ value = (codec_read (devc, 0x6A) & 0x2) ? 1 : 0;
+ if (devc->mixer_ext == VIA1616_MIXER_EXT)
+ value = (codec_read (devc, 0x5a) & 0x800) ? 1 : 0;
+ break;
+ }
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ switch (ctrl)
+ {
+ case VOL_CENTER: /* Center/LFE volume */
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+ value = left | (right << 8);
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ codec_write (devc, 0x66,
+ mix_scale (left, right, devc->centervol_bits));
+ devc->extmixlevels[CENTER_VOL] = value;
+ break;
+
+ case VOL_REAR: /* Rear/Surround volume */
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+ value = left | (right << 8);
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ codec_write (devc, 0x64,
+ mix_scale (left, right, devc->rearvol_bits));
+ devc->extmixlevels[REAR_VOL] = value;
+ break;
+
+ case VOL_SIDE: /* Side Surround volume */
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+ value = left | (right << 8);
+ if (devc->mixer_ext == CMI9780_MIXER_EXT)
+ codec_write (devc, 0x60,
+ mix_scale (left, right, devc->sidevol_bits));
+ devc->extmixlevels[SIDE_VOL] = value;
+ break;
+
+ case REAR2LINE: /* Surround to Line In */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x200);
+ else
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x200);
+ }
+
+ if ((devc->mixer_ext == CMI9739_MIXER_EXT)
+ || (devc->mixer_ext == CMI9780_MIXER_EXT))
+ {
+ if (value)
+ codec_write (devc, 0x64, codec_read (devc, 0x64) | 0x400);
+ else
+ codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0x400);
+ }
+
+ if (devc->mixer_ext == STAC9758_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x64, codec_read (devc, 0x64) | 0x50);
+ else
+ codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0x50);
+ }
+
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x76,
+ codec_read (devc, 0x76) & ~(1 << 11));
+ else
+ codec_write (devc, 0x76, codec_read (devc, 0x76) | (1 << 11));
+ }
+
+ break;
+
+ case CENTER2MIC: /* Center/LFE to Mic In */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x400);
+ else
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x400);
+ }
+
+ if ((devc->mixer_ext == CMI9739_MIXER_EXT)
+ || (devc->mixer_ext == CMI9780_MIXER_EXT))
+ {
+ if (value)
+ codec_write (devc, 0x64, codec_read (devc, 0x64) | 0x1000);
+ else
+ codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0x1000);
+ }
+
+ if (devc->mixer_ext == STAC9758_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x64, codec_read (devc, 0x64) | 0xC);
+ else
+ codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0xC);
+ }
+
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x76,
+ codec_read (devc, 0x76) & ~(1 << 12));
+ else
+ codec_write (devc, 0x76, codec_read (devc, 0x76) | (1 << 12));
+ }
+ break;
+
+ case SPREAD: /* 4 Speaker output - LF/RF duplicate on Rear */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ {
+ if (value)
+ {
+ /* enable Line-In jack to play Surround out */
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x200);
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 1);
+ }
+ else
+ {
+ /* disable Line-In jack to play Surround out */
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x200);
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~1);
+ }
+ }
+
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x76, codec_read (devc, 0x76) | 0x80);
+ else
+ codec_write (devc, 0x76, codec_read (devc, 0x76) & ~0x80);
+ }
+
+ if (devc->mixer_ext == VIA1616_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x5a, codec_read (devc, 0x5a) | 0x8000);
+ else
+ codec_write (devc, 0x5a, codec_read (devc, 0x5a) & ~0x8000);
+ }
+ break;
+
+ case MICBOOST:
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x76, codec_read (devc, 0x76) | 0x2);
+ else
+ codec_write (devc, 0x76, codec_read (devc, 0x76) & ~0x2);
+ }
+
+ if ((devc->mixer_ext == CMI9739_MIXER_EXT)
+ || (devc->mixer_ext == CMI9780_MIXER_EXT))
+ {
+ if (value)
+ codec_write (devc, 0x64, codec_read (devc, 0x64) | 0x1);
+ else
+ codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0x1);
+ }
+ break;
+
+ case DOWNMIX_LFE: /* Downmix LFE to Front */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x4);
+ else
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x4);
+ }
+
+ if (devc->mixer_ext == AD1980_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x76, codec_read (devc, 0x76) | 0x300);
+ else
+ codec_write (devc, 0x76, codec_read (devc, 0x76) & ~0x300);
+ }
+
+ if (devc->mixer_ext == VIA1616_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x5a, codec_read (devc, 0x5a) | 0x1000);
+ else
+ codec_write (devc, 0x5a, codec_read (devc, 0x5a) & ~0x1000);
+ }
+ break;
+
+ case DOWNMIX_REAR: /* Downmix Rear to Front */
+ if (devc->mixer_ext == ALC650_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x2);
+ else
+ codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x2);
+ }
+
+ if (devc->mixer_ext == VIA1616_MIXER_EXT)
+ {
+ if (value)
+ codec_write (devc, 0x5a, codec_read (devc, 0x5a) | 0x800);
+ else
+ codec_write (devc, 0x5a, codec_read (devc, 0x5a) & ~0x800);
+ }
+ break;
+ }
+ }
+ return value;
+}
+
+static int
+ac97_micboost_ctl (int dev, int ctrl, unsigned int cmd, int value)
+{
+ ac97_devc *devc = mixer_devs[dev]->devc;
+ int tmp;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ return !!devc->micboost;
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ value = !!value;
+
+ tmp = codec_read (devc, 0x0e);
+
+ if (value)
+ devc->micboost = 0x40;
+ else
+ devc->micboost = 0x00;
+
+ codec_write (devc, 0x0e, (tmp & ~0x40) | devc->micboost);
+
+ return value;
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+ac97_recselect_ctl (int dev, int ctrl, unsigned int cmd, int value)
+{
+ int tmp;
+ ac97_devc *devc = mixer_devs[dev]->devc;
+
+ if (ctrl < 0 || ctrl > 1)
+ return OSS_EINVAL;
+
+ tmp = codec_read (devc, 0x1a);
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ return (tmp >> (ctrl * 8)) & 0x07;
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ if (value < 0 || value > 7)
+ return OSS_EINVAL;
+
+ tmp &= ~(0x7 << (ctrl * 8));
+ tmp |= (value << (ctrl * 8));
+ codec_write (devc, 0x1a, tmp);
+ return value;
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+ac97_mixext_init (int dev)
+{
+ ac97_devc *devc = mixer_devs[dev]->devc;
+ unsigned int mixflags = 0;
+
+ int group, err, ctl;
+
+ if ((ctl =
+ mixer_ext_create_control (dev, 0, 0,
+ ac97_micboost_ctl, MIXT_ONOFF,
+ "micboost", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if (ac97_recselect)
+ {
+ if ((group =
+ mixer_ext_create_group_flags (dev, 0, "AC97_RECSEL",
+ MIXF_FLAT)) < 0)
+ return group;
+
+ if ((ctl =
+ mixer_ext_create_control (dev, group, 1,
+ ac97_recselect_ctl, MIXT_ENUM,
+ "LEFT", 8,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+ mixer_ext_set_strings (dev, ctl,
+ "MIC CD VIDEO AUX LINE STEREOMIX MONOMIX PHONE",
+ 0);
+
+ if ((ctl =
+ mixer_ext_create_control (dev, group, 0,
+ ac97_recselect_ctl, MIXT_ENUM,
+ "RIGHT", 8,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+ mixer_ext_set_strings (dev, ctl,
+ "MIC CD VIDEO AUX LINE STEREOMIX MONOMIX PHONE",
+ 0);
+ }
+
+/*
+ * Don't use flat groups with AC97 chips that have slider controls (ALC650 at this moment)
+ */
+ if (devc->mixer_ext != ALC650_MIXER_EXT)
+ mixflags = MIXF_FLAT;
+
+ if ((group =
+ mixer_ext_create_group_flags (dev, 0, "AC97_MIXEXT", mixflags)) < 0)
+ return group;
+
+ if ((devc->mixer_ext == ALC650_MIXER_EXT)
+ || (devc->mixer_ext == CMI9780_MIXER_EXT))
+ {
+ if ((err =
+ mixer_ext_create_control (dev, group, VOL_CENTER,
+ ac97_mixext_ctl, MIXT_STEREOSLIDER,
+ "CENTERVOL", 100,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ ac97_mixext_ctl (dev, VOL_CENTER, SNDCTL_MIX_WRITE, 100 | (100 << 8));
+
+ if ((err =
+ mixer_ext_create_control (dev, group, VOL_REAR, ac97_mixext_ctl,
+ MIXT_STEREOSLIDER, "REARVOL", 100,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ ac97_mixext_ctl (dev, VOL_REAR, SNDCTL_MIX_WRITE, 100 | (100 << 8));
+
+ if ((err =
+ mixer_ext_create_control (dev, group, VOL_SIDE, ac97_mixext_ctl,
+ MIXT_STEREOSLIDER, "SIDEVOL", 100,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ ac97_mixext_ctl (dev, VOL_SIDE, SNDCTL_MIX_WRITE, 100 | (100 << 8));
+ }
+
+
+ if ((devc->mixer_ext == CMI9739_MIXER_EXT)
+ || (devc->mixer_ext == CMI9780_MIXER_EXT)
+ || (devc->mixer_ext == ALC650_MIXER_EXT)
+ || (devc->mixer_ext == AD1980_MIXER_EXT)
+ || (devc->mixer_ext == STAC9758_MIXER_EXT))
+ {
+ if ((err =
+ mixer_ext_create_control (dev, group, REAR2LINE,
+ ac97_mixext_ctl, MIXT_ONOFF,
+ "REAR2LINEJACK", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ }
+
+ if ((devc->mixer_ext == CMI9739_MIXER_EXT)
+ || (devc->mixer_ext == CMI9780_MIXER_EXT)
+ || (devc->mixer_ext == ALC650_MIXER_EXT)
+ || (devc->mixer_ext == AD1980_MIXER_EXT)
+ || (devc->mixer_ext == STAC9758_MIXER_EXT))
+ {
+
+ if ((err =
+ mixer_ext_create_control (dev, group, CENTER2MIC,
+ ac97_mixext_ctl, MIXT_ONOFF,
+ "CENTER2MICJACK", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ }
+
+ if ((devc->mixer_ext == AD1980_MIXER_EXT)
+ || (devc->mixer_ext == VIA1616_MIXER_EXT)
+ || (devc->mixer_ext == ALC650_MIXER_EXT))
+ {
+
+ if ((err =
+ mixer_ext_create_control (dev, group, SPREAD,
+ ac97_mixext_ctl, MIXT_ENUM,
+ "SPKMODE", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ }
+
+ if ((devc->mixer_ext == AD1980_MIXER_EXT)
+ || (devc->mixer_ext == VIA1616_MIXER_EXT)
+ || (devc->mixer_ext == ALC650_MIXER_EXT))
+ {
+ if ((err =
+ mixer_ext_create_control (dev, group, DOWNMIX_LFE,
+ ac97_mixext_ctl, MIXT_ONOFF,
+ "MIX-LFE2FRONT", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ }
+
+ if ((devc->mixer_ext == VIA1616_MIXER_EXT)
+ || (devc->mixer_ext == ALC650_MIXER_EXT))
+ {
+ if ((err =
+ mixer_ext_create_control (dev, group, DOWNMIX_REAR,
+ ac97_mixext_ctl, MIXT_ONOFF,
+ "MIX-REAR2FRONT", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ }
+
+ if ((devc->mixer_ext == AD1980_MIXER_EXT)
+ || (devc->mixer_ext == CMI9739_MIXER_EXT)
+ || (devc->mixer_ext == CMI9780_MIXER_EXT))
+ {
+ if ((err =
+ mixer_ext_create_control (dev, group, MICBOOST,
+ ac97_mixext_ctl, MIXT_ONOFF,
+ "MICBOOST", 1,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ }
+ return 0;
+}
+
+/********************END of Mixer Extensions **************/
+
+/* AC97 Mixer Extensions */
+
+static int
+ac97mixer_ext_init (int dev)
+{
+ ac97_devc *devc = mixer_devs[dev]->devc;
+ int err;
+
+ if (devc->client_mixer_init != NULL)
+ if ((err = devc->client_mixer_init (dev)) < 0)
+ return err;
+
+ if ((devc->mixer_ext > 0) || ac97_recselect)
+ if ((err = ac97_mixext_init (dev)) < 0)
+ return err;
+
+ if (devc->spdifout_support)
+ if ((err = spdifout_ext_init (dev)) < 0)
+ return err;
+
+ if (devc->spdifin_support)
+ if ((err = spdifin_ext_init (dev)) < 0)
+ return err;
+ return 0;
+}
+
+void
+ac97_spdif_setup (int dev, int speed, int bits)
+{
+ int val;
+
+ val = ac97_spdifout_ctl (dev, SPDIFOUT_RATE, SNDCTL_MIX_READ, 0);
+
+ mixer_devs[dev]->modify_counter++;
+
+ switch (speed)
+ {
+ case 48000:
+ if (val != 0)
+ ac97_spdifout_ctl (dev, SPDIFOUT_RATE, SNDCTL_MIX_WRITE, 0);
+ break;
+
+ case 44100:
+ if (val != 1)
+ ac97_spdifout_ctl (dev, SPDIFOUT_RATE, SNDCTL_MIX_WRITE, 1);
+ break;
+
+ case 32000:
+ if (val != 2)
+ ac97_spdifout_ctl (dev, SPDIFOUT_RATE, SNDCTL_MIX_WRITE, 2);
+ break;
+
+ default:
+ break;
+ }
+
+ if (bits == AFMT_AC3)
+ ac97_spdifout_ctl (dev, SPDIFOUT_AUDIO, SNDCTL_MIX_WRITE, 1);
+ else
+ ac97_spdifout_ctl (dev, SPDIFOUT_AUDIO, SNDCTL_MIX_WRITE, 0);
+}