summaryrefslogtreecommitdiff
path: root/kernel/drv/oss_envy24/envy24_6fire.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drv/oss_envy24/envy24_6fire.c')
-rw-r--r--kernel/drv/oss_envy24/envy24_6fire.c781
1 files changed, 781 insertions, 0 deletions
diff --git a/kernel/drv/oss_envy24/envy24_6fire.c b/kernel/drv/oss_envy24/envy24_6fire.c
new file mode 100644
index 0000000..469ceab
--- /dev/null
+++ b/kernel/drv/oss_envy24/envy24_6fire.c
@@ -0,0 +1,781 @@
+/*
+ * Purpose: Card specific routines for Terratec DMX6fire.
+ */
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "oss_config.h"
+#include "ac97.h"
+#include "envy24.h"
+
+#if 0
+# define PRT_STATUS(v) outb(v&0xff, 0x378)
+#else
+# define PRT_STATUS(v)
+#endif
+
+#define DEFAULT_FRONTBOX_SETUP 0xfd
+
+extern int envy24_gain_sliders;
+extern int envy24_virtualout;
+
+#define EWX_DIG_ADDR 0x24 /* IIC address of digital traceiver chip of 6fire */
+
+/*=============================================================================
+ Function : IIC_GetSDA
+-------------------------------------------------------------------------------
+ Description :
+ Returns : unsigned char ->
+ Parameters : unsigned long dwPortAddr ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static unsigned char
+IIC_GetSDA (envy24_devc * devc)
+{
+
+ unsigned char bReg, bSDA;
+
+ /* FMB TEST: RW line */
+ /* set write mask */
+ bReg = ~(0x08); /* writeable */
+ envy24_write_cci (devc, 0x21, bReg);
+
+ /* set RW line LOW */
+ bReg = 0; /* writeable */
+ envy24_write_cci (devc, 0x20, bReg);
+
+ /* Set direction: SDA to input and SCL to output */
+ bReg = envy24_read_cci (devc, 0x22);
+ bReg |= 0x20; /* SCL output = 1 */
+ bReg &= ~0x10; /* SDA input = 0 */
+ envy24_write_cci (devc, 0x22, bReg);
+
+ /* Get SDA line state */
+ bSDA = envy24_read_cci (devc, 0x20);
+
+
+ /* set RW line HIGH */
+ bReg = 0x08; /* writeable */
+ envy24_write_cci (devc, 0x20, bReg);
+
+ return 1;
+ /* return ((bSDA & 0x10) == 0x10); */
+
+}
+
+/*=============================================================================
+ Function : IIC_SetIic
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+ Parameters : unsigned int dwPortAddr ->
+ : unsigned char fSDA ->
+ : unsigned char fSCL ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+IIC_SetIic (envy24_devc * devc, unsigned char fSDA, unsigned char fSCL)
+{
+ unsigned char bReg;
+
+ /* Set direction: SDA and SCL to output */
+ bReg = envy24_read_cci (devc, 0x22);
+ bReg |= (0x20 | 0x10); /* 1 -> output */
+ envy24_write_cci (devc, 0x22, bReg);
+
+ /* set write mask */
+ bReg = ~(0x20 | 0x10); /* writeable */
+ envy24_write_cci (devc, 0x21, bReg);
+
+ /* Set line state */
+ /* FMB TEST: RW line */
+ bReg = 0x08;
+ if (fSDA)
+ bReg += 0x10;
+ if (fSCL)
+ bReg += 0x20;
+ envy24_write_cci (devc, 0x20, bReg);
+
+}
+
+/*=============================================================================
+ Function : IIC_Start
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+ Parameters : unsigned int dwPortAddr ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+/*__inline */
+static void
+IIC_Start (envy24_devc * devc)
+{
+ /* falling edge of SDA while SCL is HIGH */
+ IIC_SetIic (devc, 1, 1);
+ oss_udelay (30);
+ IIC_SetIic (devc, 0, 1);
+}
+
+/*=============================================================================
+ Function : IIC_Stop
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+ Parameters : unsigned int dwPortAddr ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+/*__inline */
+
+static void
+IIC_Stop (envy24_devc * devc)
+{
+ /* rising edge of SDA while SCL is HIGH */
+ IIC_SetIic (devc, 0, 1);
+ IIC_SetIic (devc, 1, 1);
+}
+
+
+/*=============================================================================
+ Function : IIC_SendByte
+-------------------------------------------------------------------------------
+ Description :
+ Returns : unsigned char ->
+ Parameters : unsigned int dwPortAddr ->
+ : unsigned char bByte ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+/*__inline */
+static unsigned char
+IIC_SendByte (envy24_devc * devc, unsigned char bByte)
+{
+ unsigned char bDataBit, bAck;
+ int i;
+
+ for (i = 7; i >= 0; i--) /* send byte (MSB first) */
+ {
+ bDataBit = (bByte >> i) & 0x01;
+
+ IIC_SetIic (devc, bDataBit, 0);
+ IIC_SetIic (devc, bDataBit, 1);
+ IIC_SetIic (devc, bDataBit, 0);
+ } /* end for i */
+
+ IIC_SetIic (devc, 1, 0);
+
+ /* Get acknowledge */
+ IIC_SetIic (devc, 1, 1);
+ bAck = IIC_GetSDA (devc);
+ /* FMB this is a start condition but never mind */
+ IIC_SetIic (devc, 0, 0);
+#if 0
+ if (bAck)
+ cmn_err (CE_CONT, "SendByte failed %02x\n", bByte);
+ else
+ cmn_err (CE_CONT, "SendByte OK %02x\n", bByte);
+#endif
+ return 1;
+ /* return (!bAck); *//* bAck = 0 --> success */
+}
+
+#if 0
+/*=============================================================================
+ Function : IIC_WriteByte
+-------------------------------------------------------------------------------
+ Description :
+ Returns : unsigned char ->
+ Parameters : unsigned int dwPortAddr ->
+ : unsigned char bIicAddress ->
+ : unsigned char bByte ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static unsigned char
+IIC_WriteByte (envy24_devc * devc, unsigned char bIicAddress,
+ unsigned char bByte)
+{
+ IIC_Start (devc);
+
+ /* send IIC address and data byte */
+ if (!IIC_SendByte (devc, bIicAddress))
+ {
+ cmn_err (CE_CONT, "IIC_SendByte 1 failed\n");
+ goto FAILED;
+ }
+ if (!IIC_SendByte (devc, bByte))
+ {
+ cmn_err (CE_CONT, "IIC_SendByte 2 failed\n");
+ goto FAILED;
+ }
+
+ IIC_Stop (devc);
+ return 1;
+
+FAILED:
+ IIC_Stop (devc);
+ return 0;
+}
+#endif
+
+static unsigned char
+IIC_WriteWord (envy24_devc * devc, unsigned char bIicAddress,
+ unsigned char reg, unsigned char bByte)
+{
+ IIC_Start (devc);
+
+ /* send IIC address and data byte */
+ if (!IIC_SendByte (devc, bIicAddress))
+ {
+ cmn_err (CE_CONT, "IIC_SendByte 1 failed\n");
+ goto FAILED;
+ }
+ if (!IIC_SendByte (devc, reg))
+ {
+ cmn_err (CE_CONT, "IIC_SendByte 2 failed\n");
+ goto FAILED;
+ }
+ if (!IIC_SendByte (devc, bByte))
+ {
+ cmn_err (CE_CONT, "IIC_SendByte 3 failed\n");
+ goto FAILED;
+ }
+
+ IIC_Stop (devc);
+ return 1;
+
+FAILED:
+ IIC_Stop (devc);
+ return 0;
+}
+
+static void
+FrontboxControl (envy24_devc * devc, int b)
+{
+ IIC_WriteWord (devc, 0x40, 0x01, b); /* Output register */
+ devc->gpio_tmp = b;
+}
+
+static int
+HW_AK4525_SetChipSelect (envy24_devc * devc, unsigned char bCsMask)
+{
+ unsigned char b;
+ /* check validity */
+ if (bCsMask > 0x07)
+ {
+ cmn_err (CE_CONT, "Invalid bCsMask %02x\n", bCsMask);
+ return 0; /* invalid */
+ }
+
+ envy24_write_cci (devc, 0x21, 0x00);
+ envy24_write_cci (devc, 0x22, 0xff);
+ b = envy24_read_cci (devc, 0x20);
+ b &= ~0x07;
+
+ b |= bCsMask & 0x07;
+
+ envy24_write_cci (devc, 0x20, b);
+
+ return 1;
+}
+
+#define HW_AK4525_SetLines IIC_SetIic
+
+/*=============================================================================
+ FUNCTION: HW_AK4525_WriteRegister
+-------------------------------------------------------------------------------
+ PURPOSE:
+ PARAMETERS: unsigned int port - port address for IIC port
+ unsigned char bCsMask - CoDec bitmask (bits 0..3)
+ or 0xFF for all codecs together
+ unsigned char bRegIdx - offset to desired register
+ unsigned char bReg - new register value
+ RETURNS:
+-------------------------------------------------------------------------------
+ NOTES: The Chip Selects must have been set prior to this call
+ PCF8574_CODEC_IIC_ADDRESS
+
+ +-----------------------------------------------------------------+
+ | B15 B14 B13 B12 B11 B10 B09 B08|B07 B06 B05 B04 B03 B02 B01 B00 |
+ +--------+---+-------------------+--------------------------------+
+ | C1 C0 |R/W|A4 A3 A2 A1 A0 |D7 D6 D5 D4 D3 D2 D1 D0 |
+ | 1 0 |1 | <= 7 | data |
+ +--------+---+-------------------+--------------------------------+
+
+=============================================================================*/
+static unsigned char
+HW_AK4525_WriteRegister (envy24_devc * devc, unsigned char bCsMask,
+ unsigned char bRegIdx, unsigned char bRegData)
+{
+
+ unsigned short wCmd;
+ unsigned char i;
+ unsigned char fData;
+
+ /* format buffer */
+ wCmd = 0xA000 + /* chip address + R/W */
+ (((unsigned short) bRegIdx) << 8) + /* register address */
+ bRegData;
+
+ HW_AK4525_SetLines (devc, 0, 0);
+
+ /* start write cycle */
+ if (!HW_AK4525_SetChipSelect (devc, bCsMask))
+ {
+ cmn_err (CE_CONT, "HW_AK4525_SetChipSelect failed\n");
+ return 0; /* = CS to LOW -> data latched */
+ }
+
+
+ for (i = 0; i < 16; i++)
+ {
+ fData = (wCmd & 0x8000) ? 1 : 0;
+ HW_AK4525_SetLines (devc, fData, 0);
+ HW_AK4525_SetLines (devc, fData, 1); /* data is clocked in on rising edge of CCLK */
+ HW_AK4525_SetLines (devc, fData, 0);
+ wCmd <<= 1;
+ }
+
+ /* leave data line HIGH (= default for IIC) */
+ HW_AK4525_SetLines (devc, fData, 0); /* data is clocked in on rising edge of CCLK */
+
+ /* end write cycle */
+ if (!HW_AK4525_SetChipSelect (devc, 0x00))
+ {
+ cmn_err (CE_CONT, "HW_AK4525_SetChipSelect 2 failed\n");
+ return 0; /* = all CS to HIGH -> CS to default */
+ }
+
+ /* default */
+ HW_AK4525_SetLines (devc, 1, 1); /* data is clocked in on rising edge of CCLK */
+
+ return 1;
+}
+
+
+/* Register offsets */
+enum
+{
+ AK4525_REG_POWER,
+ AK4525_REG_RESET,
+ AK4525_REG_FORMAT,
+ AK4525_REG_DEEMPHASIS,
+ AK4525_REG_LEFT_INPUT,
+ AK4525_REG_RIGHT_INPUT,
+ AK4525_REG_LEFT_OUTPUT,
+ AK4525_REG_RIGHT_OUTPUT
+};
+
+
+/*=============================================================================
+ Function : HW_AK4525_Reset
+-------------------------------------------------------------------------------
+ Description :
+ Returns : unsigned char
+ Parameters : PCUST_HW_INSTANCE_DATA devc -
+ int nCodecIdx -> 0..3 index of Codec ,-1 -> all
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static unsigned char
+HW_AK4525_Reset (envy24_devc * devc, int nCodecIdx)
+{
+ unsigned char bCodecMask = 0;
+ if (nCodecIdx == -1)
+ bCodecMask = 0x07;
+ else
+ bCodecMask = 0x01 << (nCodecIdx);
+
+ if (!HW_AK4525_WriteRegister (devc, bCodecMask, /* 0x0F -> set mode for all codecs */
+ AK4525_REG_RESET, 0x00)) /* DACs,ADCs -> reset */
+ {
+ cmn_err (CE_CONT, "REG_RESET failed\n");
+ return 0;
+ }
+
+ if (!HW_AK4525_WriteRegister (devc, bCodecMask, /* 0x0F -> set mode for all codecs */
+ AK4525_REG_FORMAT, 0x60)) /* IIS, 256 fsn, normal speed */
+ return 0;
+
+ if (!HW_AK4525_WriteRegister (devc, bCodecMask, /* 0x0F -> set mode for all codecs */
+ AK4525_REG_RESET, 0x03)) /* DACs,ADCs -> normal operation */
+ return 0;
+
+ if (!HW_AK4525_WriteRegister (devc, bCodecMask, /* 0x0F -> set mode for all codecs */
+ AK4525_REG_POWER, 0x07)) /* power on */
+ return 0;
+
+ if (!HW_AK4525_WriteRegister (devc, bCodecMask, /* soft mute timeout --> short */
+ AK4525_REG_DEEMPHASIS, 0x19))
+ return 0;
+
+ if (!HW_AK4525_WriteRegister (devc,
+ bCodecMask, AK4525_REG_LEFT_INPUT, 0x7f))
+ return 0;
+
+ if (!HW_AK4525_WriteRegister (devc,
+ bCodecMask, AK4525_REG_RIGHT_INPUT, 0x7f))
+ return 0;
+
+ if (!HW_AK4525_WriteRegister (devc,
+ bCodecMask, AK4525_REG_LEFT_OUTPUT, 0x7f))
+ return 0;
+
+ if (!HW_AK4525_WriteRegister (devc,
+ bCodecMask, AK4525_REG_RIGHT_OUTPUT, 0x7f))
+ return 0;
+
+ return 1;
+}
+
+static void
+set_dmx6fire_speed (envy24_devc * devc)
+{
+ unsigned char tmp;
+
+ tmp = devc->speedbits;
+ if (devc->syncsource != SYNC_INTERNAL)
+ {
+ tmp |= 0x10; /* S/PDIF input clock select */
+ if (devc->model_data->flags & MF_WCLOCK) /* Has world clock too */
+ {
+ int cmd = envy24_read_cci (devc, 0x20);
+ cmd |= 0x10; /* S/PDIF */
+ if (devc->syncsource == SYNC_WCLOCK)
+ cmd &= ~0x10; /* World clock */
+ envy24_write_cci (devc, 0x20, cmd);
+ }
+ }
+ OUTB (devc->osdev, tmp, devc->mt_base + 0x01);
+}
+
+#if 0
+/*
+ * S/PDIF register access doesn't work so this feature is not enabled.
+ */
+
+#define EWX_CLK 0x20
+#define EWX_DTA 0x10
+
+static void
+dmx6fire_iic_write_byte (envy24_devc * devc, unsigned char data,
+ unsigned char save)
+{
+ int i;
+ unsigned char gpio;
+
+ for (i = 0; i < 8; i++)
+ {
+ int fData = (data & 0x80) ? 1 : 0;
+
+ gpio = 0x08;
+ if (fData)
+ gpio |= EWX_DTA; /* DATA */
+ envy24_write_cci (devc, 0x20, gpio | save);
+ envy24_write_cci (devc, 0x20, gpio | EWX_CLK | save); /* Clock pulse */
+ envy24_write_cci (devc, 0x20, gpio | save);
+
+ data <<= 1;
+ }
+
+ envy24_write_cci (devc, 0x20, EWX_DTA | save);
+ envy24_write_cci (devc, 0x20, EWX_DTA | EWX_CLK | save); /* Clock pulse (ACK) */
+ envy24_write_cci (devc, 0x20, EWX_DTA | save);
+}
+
+static unsigned char
+dmx6fire_iic_read_byte (envy24_devc * devc, unsigned char save)
+{
+ int i;
+ unsigned char data = 0;
+ int b;
+
+ PRT_STATUS (0x01);
+ save |= EWX_DTA;
+ envy24_write_cci (devc, 0x20, save);
+ oss_udelay (10);
+#if 1
+ save &= ~8; /* R/W bit */
+ envy24_write_cci (devc, 0x22, ~EWX_DTA); /* GPIO direction */
+ envy24_write_cci (devc, 0x21, EWX_DTA); /* GPIO write mask */
+#endif
+
+ for (i = 0; i < 8; i++)
+ {
+
+ envy24_write_cci (devc, 0x20, EWX_CLK | save); /* Clock pulse */
+ b = envy24_read_cci (devc, 0x20);
+ if (b & EWX_DTA)
+ data |= 0x80;
+ envy24_write_cci (devc, 0x20, save);
+
+ data >>= 1;
+ }
+
+ envy24_write_cci (devc, 0x22, 0xff); /* GPIO direction */
+ envy24_write_cci (devc, 0x21, 0x00); /* GPIO write mask */
+ envy24_write_cci (devc, 0x20, (save & ~EWX_DTA) | 0x08); /* Low for the ACK bit */
+ envy24_write_cci (devc, 0x20, (save & ~EWX_DTA) | 0x08 | EWX_CLK); /* Clock for the ACK bit */
+ envy24_write_cci (devc, 0x20, save | 0x08);
+ oss_udelay (10);
+ return data;
+}
+
+#if 0
+static void
+dmx6fire_iic_write (envy24_devc * devc, int addr,
+ unsigned char bRegIdx, unsigned char bRegData)
+{
+ unsigned char save;
+
+ /* start write cycle */
+ envy24_write_cci (devc, 0x22, 0xff); /* GPIO direction */
+ envy24_write_cci (devc, 0x21, 0x00); /* GPIO write mask */
+
+ save = (envy24_read_cci (devc, 0x20) & ~(EWX_CLK | EWX_DTA)) | 0x08 /* R/W bit */
+ ;
+ /* Send start */
+ envy24_write_cci (devc, 0x20, save | EWX_CLK | EWX_DTA);
+ envy24_write_cci (devc, 0x20, save | EWX_CLK);
+ envy24_write_cci (devc, 0x20, save);
+
+ dmx6fire_iic_write_byte (devc, addr, save);
+ dmx6fire_iic_write_byte (devc, bRegIdx, save);
+ dmx6fire_iic_write_byte (devc, bRegData, save);
+
+ /* Send stop */
+ envy24_write_cci (devc, 0x20, save);
+ envy24_write_cci (devc, 0x20, save | EWX_CLK);
+ envy24_write_cci (devc, 0x20, save | EWX_CLK | EWX_DTA);
+}
+#endif
+
+static unsigned char
+dmx6fire_iic_read (envy24_devc * devc, int addr, unsigned char bRegIdx)
+{
+ unsigned char save, data;
+
+ /* dmx6fire_iic_write(devc, addr, bRegIdx, 0x55); */
+ PRT_STATUS (0x80);
+
+ envy24_write_cci (devc, 0x22, 0xff); /* GPIO direction */
+ envy24_write_cci (devc, 0x21, 0x00); /* GPIO write mask */
+
+ save = (envy24_read_cci (devc, 0x20) & ~(EWX_DTA | EWX_CLK)) | 0x08 /* R/W bit */
+ ;
+ PRT_STATUS (0x02);
+ /* Send start */
+ envy24_write_cci (devc, 0x20, save | EWX_CLK | EWX_DTA);
+ envy24_write_cci (devc, 0x20, save | EWX_CLK);
+ envy24_write_cci (devc, 0x20, save);
+
+ dmx6fire_iic_write_byte (devc, addr | 0x01, save);
+ data = dmx6fire_iic_read_byte (devc, save);
+
+ /* Send stop */
+ envy24_write_cci (devc, 0x20, save);
+ envy24_write_cci (devc, 0x20, save | EWX_CLK);
+ envy24_write_cci (devc, 0x20, save | EWX_CLK | EWX_DTA);
+ PRT_STATUS (0x00);
+ return data;
+}
+
+static int
+read_dmx6fire_spdif_reg (envy24_devc * devc, int bRegister)
+/*
+*****************************************************************************
+* Reads a byte from a specific CS8427 register.
+****************************************************************************/
+{
+
+ unsigned char ret;
+ ret = dmx6fire_iic_read (devc, EWX_DIG_ADDR, bRegister);
+
+ return ret;
+}
+
+static void
+write_dmx6fire_spdif_reg (envy24_devc * devc, int bRegister, int bData)
+{
+
+ /*dmx6fire_iic_write(devc, EWX_DIG_ADDR, bRegister, bData); */
+ IIC_WriteWord (devc, EWX_DIG_ADDR, bRegister, bData);
+}
+#else
+static int
+read_dmx6fire_spdif_reg (envy24_devc * devc, int bRegister)
+{
+ return 0;
+}
+
+static void
+write_dmx6fire_spdif_reg (envy24_devc * devc, int bRegister, int bData)
+{
+}
+#endif
+
+static void
+dmx6fire_card_init (envy24_devc * devc)
+{
+ envy24_write_cci (devc, 0x20, 0xff);
+ envy24_write_cci (devc, 0x21, 0x00);
+ envy24_write_cci (devc, 0x22, 0xff);
+ envy24_write_cci (devc, 0x20, 0xff);
+ HW_AK4525_SetChipSelect (devc, 0x00);
+#if 1
+
+ IIC_WriteWord (devc, 0x40, 0x02, 0x00); /* Polarity register */
+ IIC_WriteWord (devc, 0x40, 0x03, 0x00); /* Direction register */
+
+ FrontboxControl (devc, DEFAULT_FRONTBOX_SETUP); /* Set default values */
+
+ if (!HW_AK4525_Reset (devc, -1))
+ cmn_err (CE_CONT, "Envy24: DMX6fire reset failed\n");;
+#endif
+
+}
+
+static int
+dmx6fire_mixer_set (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24_devc *devc = mixer_devs[dev]->devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ switch (ctrl)
+ {
+ case 1:
+ if (devc->skipdevs == 2)
+ return devc->rec_portc[2].riaa_filter;
+ else
+ return devc->rec_portc[4].riaa_filter;
+ break;
+
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ switch (ctrl)
+ {
+ case 1:
+ if (devc->skipdevs == 2)
+ return devc->rec_portc[2].riaa_filter = !!value;
+ else
+ return devc->rec_portc[4].riaa_filter = !!value;
+ break;
+
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+dmx6fire_mix_init (envy24_devc * devc, int dev, int group)
+{
+ int err;
+#if 0
+ int i, mask = devc->outportmask, skip, codec, ports;
+ int range = 3;
+ int typ = MIXT_ENUM;
+ if ((group = mixer_ext_create_group (dev, 0, "ENVY24_GAIN")) < 0)
+ return group;
+
+ skip = devc->skipdevs;
+ if (skip != 2)
+ skip = 1;
+
+ if (envy24_gain_sliders)
+ {
+ typ = MIXT_MONOSLIDER;
+ range = 164;
+
+ for (i = 0; i < 0xff; i++)
+ devc->akm_gains[i] = 0x7f;
+ }
+ else
+ for (i = 0; i < 0xff; i++)
+ devc->akm_gains[i] = 0;
+
+ for (i = 0; i < 8; i += skip)
+ {
+ char tmp[32];
+
+ if (!(mask & (1 << i)))
+ continue; /* Not present */
+
+ if (devc->skipdevs == 2)
+ {
+ if (i == 8)
+ strcpy (tmp, "ENVY24_SPDOUT");
+ else
+ sprintf (tmp, "ENVY24_OUT%d/%d", i + 1, i + 2);
+
+ codec = (i > 1) ? AKM_B : AKM_A;
+ ports = 0x0c; /* Both output ports */
+ if ((err = mixer_ext_create_control (dev, group,
+ codec | ports, envy24_set_tdif,
+ typ,
+ tmp, range,
+ MIXF_MAINVOL |
+ MIXF_READABLE |
+ MIXF_WRITEABLE)) < 0)
+ return err;
+ }
+ else
+ {
+ if (i == 8)
+ strcpy (tmp, "ENVY24_SPDOUTL");
+ else if (i == 9)
+ strcpy (tmp, "ENVY24_SPDOUTR");
+ else
+ sprintf (tmp, "ENVY24_OUT%d", i + 1);
+
+ codec = (i > 1) ? AKM_B : AKM_A;
+ ports = (i & 1) ? 0x08 : 0x04;
+ if ((err = mixer_ext_create_control (dev, group,
+ codec | ports, envy24_set_tdif,
+ typ,
+ tmp, range,
+ MIXF_MAINVOL |
+ MIXF_READABLE |
+ MIXF_WRITEABLE)) < 0)
+ return err;
+ }
+ }
+#endif
+
+ if ((group = mixer_ext_create_group (dev, 0, "ENVY24_6FIRE")) < 0)
+ return group;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, dmx6fire_mixer_set,
+ MIXT_ONOFF,
+ "6FIRE_RIAA", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ return 0;
+}
+
+envy24_auxdrv_t dmx6fire_auxdrv = {
+ dmx6fire_card_init,
+ dmx6fire_mix_init,
+ init_cs8427_spdif,
+ write_cs8427_spdif,
+ NULL,
+ read_dmx6fire_spdif_reg,
+ write_dmx6fire_spdif_reg,
+ set_dmx6fire_speed,
+ NULL,
+ cs8427_spdif_mixer_init
+};