summaryrefslogtreecommitdiff
path: root/kernel/drv/oss_envy24ht
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
commit1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch)
tree4495d23e7b54ab5700e3839081e797c1eafe0db9 /kernel/drv/oss_envy24ht
downloadoss4-upstream.tar.gz
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'kernel/drv/oss_envy24ht')
-rw-r--r--kernel/drv/oss_envy24ht/.changelog1
-rw-r--r--kernel/drv/oss_envy24ht/.devices12
-rw-r--r--kernel/drv/oss_envy24ht/.name1
-rw-r--r--kernel/drv/oss_envy24ht/.params5
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht.h230
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht_ac97.c137
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht_ap192.c617
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht_aureon.c2536
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht_julia.c547
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht_revo51.c938
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht_revo71.c338
-rw-r--r--kernel/drv/oss_envy24ht/envy24ht_via.c.save324
-rw-r--r--kernel/drv/oss_envy24ht/oss_envy24ht.c2411
-rw-r--r--kernel/drv/oss_envy24ht/oss_envy24ht.man24
14 files changed, 8121 insertions, 0 deletions
diff --git a/kernel/drv/oss_envy24ht/.changelog b/kernel/drv/oss_envy24ht/.changelog
new file mode 100644
index 0000000..972605e
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/.changelog
@@ -0,0 +1 @@
+800802xx by Artem Antonov: Added support for ESI Juli@
diff --git a/kernel/drv/oss_envy24ht/.devices b/kernel/drv/oss_envy24ht/.devices
new file mode 100644
index 0000000..b90025d
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/.devices
@@ -0,0 +1,12 @@
+oss_envy24ht pci1412,1724 Generic ENVY24HT based sound card
+oss_envy24ht pcs1412,3630 M Audio Revolution 7.1
+oss_envy24ht pcs1412,3631 M Audio Revolution 5.1
+oss_envy24ht pcs1412,6321 M Audio Audiophile 192
+oss_envy24ht pcs153b,1145 Terratec Aureon 7.1 Space
+oss_envy24ht pcs153b,1147 Terratec Aureon 7.1 Sky
+oss_envy24ht pcs153b,1149 Terratec PHASE 28
+oss_envy24ht pcs153b,1153 Terratec Aureon 7.1 Universe
+oss_envy24ht pcs3031,4553 Ego Systems Juli@ *BETA*
+oss_envy24ht pcs4933,4553 Audiotrak Prodigy 7.1
+oss_envy24ht pcs3137,4154 Audiotrak Prodigy HD2
+oss_envy24ht pcs1412,2401 Audiotrak Prodigy HD2 Advance DE
diff --git a/kernel/drv/oss_envy24ht/.name b/kernel/drv/oss_envy24ht/.name
new file mode 100644
index 0000000..77fd7c1
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/.name
@@ -0,0 +1 @@
+VIA Envy24HT/PT (ICE1724) sound chipset
diff --git a/kernel/drv/oss_envy24ht/.params b/kernel/drv/oss_envy24ht/.params
new file mode 100644
index 0000000..4e6831b
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/.params
@@ -0,0 +1,5 @@
+int envy24ht_model = -1;
+/*
+ * Select the Model number if the card isn't autodetected
+ * Values: 0 = Envy24ht 1=Envy24PT/HT-s compatible -1=Autodetect Default: -1
+ */
diff --git a/kernel/drv/oss_envy24ht/envy24ht.h b/kernel/drv/oss_envy24ht/envy24ht.h
new file mode 100644
index 0000000..f11029b
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht.h
@@ -0,0 +1,230 @@
+/*
+ * Purpose: Common definitions for envy24ht driver files
+ */
+/*
+ *
+ * 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 "ac97.h"
+#include "midi_core.h"
+
+/*
+ * Various subvendor device ID's
+ */
+#define SSID_AUREON_SPACE 0x1145153b
+#define SSID_AUREON_SKY 0x1147153b
+#define SSID_AUREON_UNIVERSE 0x1153153b
+#define SSID_PHASE28 0x1149153b
+#define SSID_PRODIGY71 0x45534933
+#define SSID_PRODIGYHD2 0x41543137
+#define SSID_PRODIGYHD2_ADE 0x24011412
+#define SSID_JULIA 0x45533031
+#define SSID_AP192 0x36321412
+
+typedef struct
+{
+ unsigned int dwSubVendorID; /* PCI[2C-2F], in BIG ENDIAN format */
+ unsigned char bSize; /* size of EEPROM image in bytes */
+ unsigned char bVersion; /* version equal 1 for this structure. */
+ unsigned char bCodecConfig; /* PCI[60] */
+ unsigned char bACLinkConfig; /* PCI[61] */
+ unsigned char bI2SID; /* PCI[62] */
+ unsigned char bSpdifConfig; /* PCI[63] */
+ unsigned char bGPIOInitMask0; /* Corresponding bits need to be inited */
+ /* 0 means write bit and 1 means cannot write */
+ unsigned char bGPIOInitState0; /* Initial state of GPIO pins */
+ unsigned char bGPIODirection0; /* GPIO Direction State */
+ unsigned char bGPIOInitMask1;
+ unsigned char bGPIOInitState1;
+ unsigned char bGPIODirection1;
+ unsigned char bGPIOInitMask2;
+ unsigned char bGPIOInitState2;
+ unsigned char bGPIODirection2;
+ unsigned char bAC97RecSrc;
+ unsigned char bDACID[4]; /* I2S IDs for DACs [0 ~ 3] */
+ unsigned char bADCID[4]; /* I2S IDs for ADCs [0 ~ 3] */
+ unsigned char bDACID4; /* I2S ID for DAC#4 */
+ unsigned char Reserved[32];
+} eeprom_data_t;
+
+typedef struct envy24ht_auxdrv envy24ht_auxdrv_t;
+
+typedef struct
+{
+ unsigned int svid;
+ char *product;
+ int nr_outs, nr_ins; /* # of analog channels */
+ int flags;
+#define MF_MIDI 0x00000001 /* Has MIDI port */
+#define MF_192K 0x00000002 /* Supports 192kHz */
+#define MF_SPDIFIN 0x00000004 /* Has S/PDIF input */
+#define MF_SPDIFOUT 0x00000008 /* Has S/PDIF output */
+#define MF_ENVY24PT 0x00000010 /* Envy24PT chip (no EEPROM) */
+#define MF_NOAC97 0x00000020 /* Ignore AC97 codec */
+ const envy24ht_auxdrv_t *auxdrv;
+ unsigned char *eeprom_data;
+}
+card_spec;
+
+#define ICENSEMBLE_VENDOR_ID 0x1412
+#define ICENSEMBLE_ENVY24HT_ID 0x1724
+#define MAX_ENVY24HT_CARD 8
+
+#ifdef USE_LICENSING
+extern int options_data;
+#endif
+
+#define MAX_ODEV 5
+#define MAX_IDEV 2
+
+typedef struct
+{
+ int dev;
+ int open_mode;
+ int direction;
+ int fmt;
+ char *name;
+
+ int channels;
+ volatile int is_active;
+ volatile int trigger_bits;
+ oss_native_word base;
+ unsigned char mask;
+ int dev_flags;
+#define DF_MULTICH 0x00000001
+#define DF_SPDIF 0x00000002
+#define DF_AC3 0x00000004
+#define DF_DUPLEX 0x00000008
+ int chmask;
+ int used_chmask;
+
+ int state_bits;
+}
+envy24ht_portc;
+
+typedef struct
+{
+ int dta, clk;
+} oss_i2c_t;
+
+/*****************/
+
+typedef struct
+{
+ oss_device_t *osdev;
+ oss_mutex_t mutex;
+ oss_mutex_t low_mutex;
+ const envy24ht_auxdrv_t *auxdrv;
+ int codec_type;
+#define CODEC_I2S 0
+#define CODEC_AC97 1
+ int mpu1_attached, mpu2_attached;
+ oss_native_word ccs_base, mt_base;
+ int irq;
+ card_spec *model_data;
+ unsigned int subvendor;
+ eeprom_data_t eeprom;
+ char channel_names[4][10];
+ unsigned short gpio_shadow_L;
+ unsigned char gpio_shadow_H;
+
+ oss_i2c_t i2c;
+/*
+ * MT mixer
+ */
+
+ int mixer_dev;
+ ac97_devc ac97devc;
+
+ int nr_outdevs, nr_indevs;
+ envy24ht_portc play_portc[MAX_ODEV];
+ envy24ht_portc rec_portc[MAX_IDEV];
+
+ int outportmask, inportmask;
+ int nr_play_channels, nr_rec_channels;
+ int first_dev;
+
+ int open_count;
+ int speed, pending_speed, pending_speed_sel, speedbits, configured_rate_sel;
+ int prev_speed; /* Strictly for use by low level modules */
+ int max_ratesel;
+ int syncsource;
+
+ int use_src;
+ int ratelock;
+ int external_sync;
+ int busy_play_channels;
+ int busy_rec_channels;
+
+ spdif_devc spdc;
+ int gains[6];
+ int monitor[5];
+ int recsrc;
+
+/*
+ * MIDI
+ */
+ int midi_opened;
+ int midi_attached;
+ oss_midi_inputbyte_t midi_input_intr;
+ oss_midi_outputintr_t midi_output_intr;
+ volatile unsigned char input_byte;
+ int midi_dev;
+
+/*
+ * Low level stuff
+ */
+ unsigned char dac1val[5], dac2val[11]; /* M Audio Revo 7.1 */
+ unsigned short m_AC97Volume[6]; /* Terratec Aureon */
+ unsigned char m_fAC97Mute[6]; /* Terratec Aureon */
+ int m_DigInSource; /* Aureon */
+ int m_LineInSource; /* Aureon */
+ int m_SPDIFSource; /* Aureon */
+ int m_ADCIndex; /* Aureon */
+ int m_f1724SPDIF; /* Aureon */
+ int m_SPDIFConfig; /* Aureon */
+ int m_Frontjack; /* Aureon */
+ unsigned char m_fDACMute[12]; /* Aureon */
+ unsigned char m_DACVolume[13]; /* Aureon & Juli@ */
+ unsigned short m_ADCVolume[8]; /* Aureon */
+ unsigned char m_ADCMux; /* Aureon */
+ unsigned char m_fSPDIFRecord; /* Aureon */
+ unsigned char m_AuxMux; /* Aureon */
+ unsigned int m_ClockSource; /* Aureon */
+ unsigned int m_Out0Source; /* Aureon */
+
+ int mute;
+ int reclevel;
+ timeout_id_t timeout_id; /* Juli@ */
+
+ unsigned char syncstart_mask;
+}
+envy24ht_devc;
+
+struct envy24ht_auxdrv
+{
+ void (*card_init) (envy24ht_devc * devc);
+ int (*mixer_init) (envy24ht_devc * devc, int dev, int group);
+ void (*set_rate) (envy24ht_devc * devc);
+ int (*get_locked_status) (envy24ht_devc * devc);
+ int (*spdif_mixer_init) (envy24ht_devc * devc, int dev, int group);
+ int (*private1) (envy24ht_devc * devc, int value);
+ int (*audio_ioctl) (envy24ht_devc * devc, envy24ht_portc * portc, unsigned int cmd,
+ ioctl_arg arg);
+ void (*card_uninit) (envy24ht_devc * devc);
+};
+
+struct speed_sel
+{
+ int speed, speedbits;
+};
+
+void envy24ht_write_cci (envy24ht_devc * devc, int pos, int data);
+int envy24ht_read_cci (envy24ht_devc * devc, int pos);
diff --git a/kernel/drv/oss_envy24ht/envy24ht_ac97.c b/kernel/drv/oss_envy24ht/envy24ht_ac97.c
new file mode 100644
index 0000000..46d2382
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht_ac97.c
@@ -0,0 +1,137 @@
+/*
+ * Purpose: Low level routines for AC97 based Envy24HT boards (mainly Envy24-PT).
+ */
+/*
+ *
+ * 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_envy24ht_cfg.h"
+
+#include "spdif.h"
+#include "envy24ht.h"
+
+#define AKM_ADDRESS 0x10
+#if 0
+# define PRT_STATUS(v) outb(v&0xff, 0x378)
+#else
+# define PRT_STATUS(v)
+#endif
+
+#if 0
+static unsigned char
+i2c_read (envy24ht_devc * devc, unsigned char addr, unsigned char pos)
+{
+ int i;
+ unsigned char data;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ OUTB (devc->osdev, pos, devc->ccs_base + 0x11); /* Offset */
+ OUTB (devc->osdev, addr << 1, devc->ccs_base + 0x10); /* Read address */
+
+ for (i = 0; i < 2000; i++)
+ {
+ unsigned char status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+
+ oss_udelay (1);
+ data = INB (devc->osdev, devc->ccs_base + 0x12);
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+
+ return data;
+}
+
+static void
+i2c_write (envy24ht_devc * devc, unsigned char addr, unsigned char pos,
+ unsigned char data)
+{
+ int i;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ OUTB (devc->osdev, pos, devc->ccs_base + 0x11); /* Offset */
+ OUTB (devc->osdev, data, devc->ccs_base + 0x12); /* Data */
+ OUTB (devc->osdev, (addr << 1) | 1, devc->ccs_base + 0x10); /* Write address */
+
+ for (i = 0; i < 2000; i++)
+ {
+ unsigned char status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+}
+#endif
+
+/*ARGSUSED*/
+static void
+init_cs8415a (envy24ht_devc * devc)
+{
+}
+
+/*ARGSUSED*/
+static void
+init_wm8728 (envy24ht_devc * devc)
+{
+
+#if 0
+ printk ("Regs=");
+ for (i = 0; i < 0x18; i++)
+ {
+ PRT_STATUS (2);
+ printk ("%02x ", i2c_read (devc, addr, i));
+ PRT_STATUS (0);
+ }
+ printk ("\n");
+#endif
+}
+
+static void
+ac97_card_init (envy24ht_devc * devc)
+{
+
+ PRT_STATUS (0);
+ PRT_STATUS (0x01);
+ PRT_STATUS (0);
+
+ OUTW (devc->osdev, 0x000f, devc->ccs_base + 0x14); /* GPIO */
+
+ oss_udelay (1000);
+
+ devc->recsrc = 0;
+ init_cs8415a (devc);
+ init_wm8728 (devc);
+}
+
+/*ARGSUSED*/
+static int
+ac97_mixer_init (envy24ht_devc * devc, int dev, int group)
+{
+ return 0;
+}
+
+#if 0
+static int
+ac97_private1 (envy24ht_devc * devc, int value)
+{
+ i2c_write (devc, AKM_ADDRESS, (value >> 8) & 0xff, value & 0xff);
+ return 0;
+}
+#endif
+
+envy24ht_auxdrv_t envy24ht_ac97_auxdrv = {
+ ac97_card_init,
+ ac97_mixer_init
+};
diff --git a/kernel/drv/oss_envy24ht/envy24ht_ap192.c b/kernel/drv/oss_envy24ht/envy24ht_ap192.c
new file mode 100644
index 0000000..9929c27
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht_ap192.c
@@ -0,0 +1,617 @@
+/*
+ * Purpose: Low level routines for M Audio Audiophile 192
+ */
+/*
+ *
+ * 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_envy24ht_cfg.h"
+
+#include "spdif.h"
+#include "envy24ht.h"
+
+static char channel_names[4][10] = {
+ "main",
+ "unused1",
+ "unused2",
+ "unused3"
+};
+
+#define BIT(x) (1<<(x))
+#define BIT3 BIT(3)
+
+/*----- SPI bus for CODEC communication. */
+/* */
+#define SPI_CLK 1 /* Clock output to CODEC's, rising edge clocks data. */
+#define SPI_DIN 2 /* Data input from the CODEC. */
+#define SPI_DOUT 3 /* Data output to the CODEC. */
+#define SPI_CS0n (1<<4) /* Selects first chip. */
+#define SPI_CS1n (1<<5) /* Selects second chip. */
+
+#define SPI_CC_AK4358 0x02 /* C1:C0 for ak4358. */
+#define SPI_CC_AK4114 0x02 /* C1:C0 for ak4114. */
+#define WRITEMASK 0xffff
+/*----- Revolution defines. */
+/* */
+#define ap192_AK4114 (1) /* iDevice value for AK4114 DIR. */
+#define ap192_AK4358 (2) /* iDevice value for AK4358 D/A. */
+
+static unsigned int
+GpioReadAll (envy24ht_devc * devc)
+{
+ return INW (devc->osdev, devc->ccs_base + 0x14);
+}
+
+static void
+GPIOWriteAll (envy24ht_devc * devc, unsigned int data)
+{
+ OUTW (devc->osdev, 0xffff, devc->ccs_base + 0x18); /* GPIO direction */
+ OUTW (devc->osdev, 0x0000, devc->ccs_base + 0x16); /* GPIO write mask */
+
+ OUTW (devc->osdev, data, devc->ccs_base + 0x14);
+}
+
+static void
+GPIOWrite (envy24ht_devc * devc, int pos, int bit)
+{
+ int data = GpioReadAll (devc);
+
+ bit = (bit != 0);
+
+ data &= ~(1 << pos);
+ data |= (bit << pos);
+
+ GPIOWriteAll (devc, data);
+}
+
+void
+ap192_Assert_CS (envy24ht_devc * devc, int iDevice)
+/*
+*****************************************************************************
+* Assert chip select to specified GPIO-connected device.
+* iDevice: ap192_AK4114=DIG, ap192_AK4358=DAC.
+****************************************************************************/
+{
+ unsigned int dwGPIO; /* Current GPIO's. */
+ dwGPIO = GpioReadAll (devc); /* Read current GPIO's. */
+ dwGPIO |= (SPI_CS0n | SPI_CS1n); /* Reset CS bits. */
+ switch (iDevice) /* Select CS#. */
+ {
+ case ap192_AK4358:
+ dwGPIO &= ~SPI_CS0n;
+ break; /* DAC */
+ case ap192_AK4114:
+ dwGPIO &= ~SPI_CS1n;
+ break; /* DIG */
+ default:
+ break;
+ }
+ GPIOWriteAll (devc, dwGPIO); /* Write hardware. */
+}
+
+void
+ap192_DeAssert_CS (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* De-Assert all chip selects.
+****************************************************************************/
+{
+ unsigned int dwGPIO = GpioReadAll (devc); /* Current GPIO's. */
+ dwGPIO |= (SPI_CS0n | SPI_CS1n); /* Clear CS bits. */
+ GPIOWriteAll (devc, dwGPIO); /* Write back to hardware. */
+}
+
+/*#define _delay() oss_udelay(1) */
+#define _delay() {}
+
+void
+ap192_WriteSpiAddr (envy24ht_devc * devc, int iDevice, unsigned char bReg)
+/*
+*****************************************************************************
+* Write the address byte part of the SPI serial stream.
+* iDevice: ap192_AK4358=DAC, ap192_AK4114=DIG, etc.
+****************************************************************************/
+{
+ unsigned char bHdr;
+ unsigned char bNum;
+/* Built 8-bit packet header: C1,C0,R/W,A4,A3,A2,A1,A0. */
+/* */
+ switch (iDevice)
+ {
+ case ap192_AK4358:
+ bHdr = SPI_CC_AK4358 << 6;
+ break;
+ case ap192_AK4114:
+ bHdr = SPI_CC_AK4114 << 6;
+ break;
+ default:
+ bHdr = 0;
+ break;
+ }
+ bHdr = bHdr | 0x20 | (bReg & 0x1F); /* "write" + address. */
+/* Write header to SPI. */
+/* */
+ for (bNum = 0; bNum < 8; bNum++)
+ {
+ GPIOWrite (devc, SPI_CLK, 0); /* Drop clock low. */
+ _delay ();
+ GPIOWrite (devc, SPI_DOUT, 0x080 & bHdr); /* Write data bit. */
+ _delay ();
+ GPIOWrite (devc, SPI_CLK, 1); /* Raise clock. */
+ _delay ();
+ bHdr <<= 1; /* Next bit. */
+ }
+}
+
+void
+ap192_WriteSpiReg (envy24ht_devc * devc, int iDevice, unsigned char bReg,
+ unsigned char bData)
+/*
+*****************************************************************************
+* Writes one register in specified CHIP.
+* devc = PCI slot code of specific board.
+* iDevice: ap192_AK4358=DAC, ap192_AK4114=DIG, etc.
+****************************************************************************/
+{
+ unsigned char bNum;
+ GPIOWrite (devc, SPI_DOUT, 0); /* Init SPI signals. */
+ GPIOWrite (devc, SPI_CLK, 1); /* */
+/* Drop the chip select low. */
+/* Wait at least 150 nS. */
+/* */
+ ap192_Assert_CS (devc, iDevice);
+ _delay ();
+/* Write the address byte. */
+/* */
+ ap192_WriteSpiAddr (devc, iDevice, bReg);
+/* Write the data byte. */
+/* */
+ for (bNum = 0; bNum < 8; bNum++)
+ {
+ GPIOWrite (devc, SPI_CLK, 0); /* Drop clock low. */
+ _delay ();
+ GPIOWrite (devc, SPI_DOUT, 0x080 & bData); /* Write data bit. */
+ _delay ();
+ GPIOWrite (devc, SPI_CLK, 1); /* Raise clock. */
+ _delay ();
+ bData <<= 1; /* Next bit. */
+ }
+/* De-assert chip selects. */
+/* */
+ ap192_DeAssert_CS (devc);
+ _delay ();
+}
+
+
+#define GPIO_MUTEn 22 /* Converter mute signal. */
+void
+ap192_Mute (envy24ht_devc * devc, int bMute)
+/*
+*****************************************************************************
+* Mutes all outputs if bMute=TRUE.
+****************************************************************************/
+{
+ if (bMute)
+ {
+/* Soft-mute. Delay currently unspecified, try ½ second. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 1, 0x03);
+ _delay ();
+/* Switch mute transistors on. */
+ GPIOWrite (devc, GPIO_MUTEn, 0);
+ }
+ else
+ {
+/* Switch mute transistors off. Delay currently unspecified, try ½ second. */
+ GPIOWrite (devc, GPIO_MUTEn, 1);
+ _delay ();
+/* Release Soft-mute. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 1, 0x01);
+ }
+
+ devc->mute = bMute;
+}
+
+
+void
+ap192_Set_OutAttn (envy24ht_devc * devc, unsigned char bChan, int iAttn)
+/*
+*****************************************************************************
+* Sets the attenuation on one output channel.
+* bChan = Channel number (0..7).
+* Channel 0:1 = front, 2:3 = center/sub, 4:5 = rear, 6:7 = headphones.
+* Registers are 0x04, 05, 06, 07, 08, 09, 0B, 0C respectively
+* iAttn = Number of steps to attenuate CODEC.
+* Each step equals .5dB (-127..0)
+****************************************************************************/
+{
+ unsigned char bIndex;
+ unsigned char bAttn;
+ if (bChan > 7 || iAttn > 0 || iAttn < -127) /* parameter test */
+ {
+ cmn_err (CE_CONT, "Dnvalid data! %d=bChan, %d=iAttn", bChan, iAttn);
+ return;
+ }
+ if (bChan < 6)
+ bIndex = 0x04 + bChan; /* for registers 0x04..0x09 */
+ else
+ bIndex = 0x05 + bChan; /* for registers 0x0B..0x0C */
+ bAttn = (0x80 + (unsigned char) (iAttn + 127)); /* 7F is max volume. */
+/* MSB enables attenuation. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, bIndex, bAttn);
+}
+
+static void
+ap192_Set_48K_Mode (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* Sets Chip and Envy24 for 8kHz-48kHz sample rates.
+****************************************************************************/
+{
+/* ICE MCLK = 256x. */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 2) & ~BIT3,
+ devc->mt_base + 2);
+/* DFS=normal, RESET. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x4E);
+/* DFS=normal, NORMAL OPERATION. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x4F);
+
+ /* Set ADC modes */
+ GPIOWrite (devc, 8, 0); /* CKS0 = 0. MCLK = 256x */
+ GPIOWrite (devc, 9, 0); /* DFS0 = 0. */
+ GPIOWrite (devc, 10, 0); /* DFS1 = 0. Single speed mode. */
+
+ /* Reset ADC timing */
+ GPIOWrite (devc, 11, 0);
+ _delay ();
+ GPIOWrite (devc, 11, 1);
+}
+
+static void
+ap192_Set_96K_Mode (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* Sets CODEC and Envy24 for 60kHz-96kHz sample rates.
+****************************************************************************/
+{
+/* ICE MCLK = 256x. */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 2) & ~BIT3,
+ devc->mt_base + 2);
+/* DFS=double-speed, RESET. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x5E);
+/* DFS=double-speed, NORMAL OPERATION. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x5F);
+
+ /* Set ADC modes */
+ GPIOWrite (devc, 8, 0); /* CKS0 = 0. MCLK = 256x */
+ GPIOWrite (devc, 9, 1); /* DFS0 = 0. */
+ GPIOWrite (devc, 10, 0); /* DFS1 = 0. Single speed mode. */
+
+ /* Reset ADC timing */
+ GPIOWrite (devc, 11, 0);
+ _delay ();
+ GPIOWrite (devc, 11, 1);
+}
+
+static void
+ap192_Set_192K_Mode (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* Sets CODEC and Envy24 for 120kHz-192kHz sample rate.
+****************************************************************************/
+{
+/* ICE MCLK = 128x. */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 2) | BIT3,
+ devc->mt_base + 2);
+ _delay ();
+/*----- SET THE D/A. */
+/* DFS=quad-speed, RESET. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x6E);
+ _delay ();
+/* DFS=quad-speed, NORMAL OPERATION. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x6F);
+
+ /* SPDIF */
+ ap192_WriteSpiReg (devc, ap192_AK4114, 0x00, 0x0d);
+ ap192_WriteSpiReg (devc, ap192_AK4114, 0x00, 0x0f);
+
+ /* Set ADC modes */
+ GPIOWrite (devc, 8, 1); /* CKS0 = 0. MCLK = 256x */
+ GPIOWrite (devc, 9, 0); /* DFS0 = 0. */
+ GPIOWrite (devc, 10, 1); /* DFS1 = 0. Single speed mode. */
+
+ /* Reset ADC timing */
+ GPIOWrite (devc, 11, 0);
+ _delay ();
+ GPIOWrite (devc, 11, 1);
+}
+
+static int
+set_dac (envy24ht_devc * devc, int reg, int level)
+{
+ if (level < 0)
+ level = 0;
+ if (level > 0x7f)
+ level = 0x7f;
+
+ ap192_WriteSpiReg (devc, ap192_AK4358, reg, level | 0x80);
+
+ return level;
+}
+
+static void
+AK4358_Init (envy24ht_devc * devc)
+{
+/*===== AK4358 D/A initialization. Leave soft-muted. */
+/* */
+/* Power down, reset, normal mode. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x00);
+/* Power up, reset, normal mode */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x4E);
+/* Reset timing, Mode 3(I2S), disable auto clock detect, sharp roll off. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 0, 0x06);
+/* Soft mute, reset timing. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 1, 0x02);
+/* De-emphasis off. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 3, 0x01);
+/* Max volume on all 8 channels. */
+ set_dac (devc, 0x04, 0x7f);
+ set_dac (devc, 0x05, 0x7f);
+ set_dac (devc, 0x06, 0x7f);
+ set_dac (devc, 0x07, 0x7f);
+ set_dac (devc, 0x08, 0x7f);
+ set_dac (devc, 0x09, 0x7f);
+ set_dac (devc, 0x0b, 0x7f);
+ set_dac (devc, 0x0c, 0x7f);
+
+/* Datt mode 0, DZF non-invert, DCLK polarity 0, PCM mode, DCKS 512fs, TDM normal. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 0xA, 0x00);
+/* DZF control disabled. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 0xD, 0x00);
+ ap192_WriteSpiReg (devc, ap192_AK4358, 0xE, 0x00);
+ ap192_WriteSpiReg (devc, ap192_AK4358, 0xF, 0x00);
+/* Power up, normal operation. */
+ ap192_WriteSpiReg (devc, ap192_AK4358, 2, 0x4F);
+}
+
+static void
+ap192_set_rate (envy24ht_devc * devc)
+{
+ int tmp;
+
+ tmp = INB (devc->osdev, devc->mt_base + 0x02);
+ if (devc->speed <= 48000)
+ {
+ ap192_Set_48K_Mode (devc);
+ OUTB (devc->osdev, tmp & ~BIT (3), devc->mt_base + 0x02);
+ return;
+ }
+
+ if (devc->speed <= 96000)
+ {
+ ap192_Set_96K_Mode (devc);
+
+ return;
+ }
+
+ ap192_Set_192K_Mode (devc);
+ OUTB (devc->osdev, tmp | BIT (3), devc->mt_base + 0x02);
+}
+
+static int
+ap192_audio_ioctl (envy24ht_devc * devc, envy24ht_portc * portc, unsigned int cmd,
+ ioctl_arg arg)
+{
+ int left, right, value;
+
+ switch (cmd)
+ {
+ case SNDCTL_DSP_GETPLAYVOL:
+ if (portc != &devc->play_portc[0])
+ return OSS_EINVAL;
+ left = (devc->gains[0] & 0xff) * 100 / 0x7f;
+ right = ((devc->gains[0] >> 8) & 0xff) * 100 / 0x7f;
+ return *arg = (left | (right << 8));
+ break;
+
+ case SNDCTL_DSP_SETPLAYVOL:
+ if (portc != &devc->play_portc[0])
+ return OSS_EINVAL;
+ value = *arg;
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ left = (left * 0x7f) / 100;
+ right = (right * 0x7f) / 100;
+ left = set_dac (devc, 0x04, left);
+ right = set_dac (devc, 0x05, right);
+ devc->gains[0] = left | (right << 8);
+ mixer_devs[devc->mixer_dev]->modify_counter++;
+ return 0;
+ break;
+ }
+ return OSS_EINVAL;
+}
+
+static int
+ap192_set_control (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ switch (ctrl)
+ {
+ case 0:
+ return devc->mute;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ switch (ctrl)
+ {
+ case 0:
+ value = !!value;
+ ap192_Mute (devc, value);
+ return devc->mute;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+ap192_set_ak4358 (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ if (ctrl < 0 || ctrl > 4)
+ return OSS_EIO;
+
+ return devc->gains[ctrl];
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ int left, right;
+
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ switch (ctrl)
+ {
+ case 0: /* PCM */
+ left = set_dac (devc, 0x04, left);
+ right = set_dac (devc, 0x05, right);
+ break;
+
+ case 1: /* Line IN */
+ /* Line IN monitor permits panning but we don't support it */
+ left = set_dac (devc, 0x06, left);
+ set_dac (devc, 0x07, 0);
+ set_dac (devc, 0x08, 0);
+ right = set_dac (devc, 0x09, right);
+ break;
+
+ case 2: /* S/PDIF */
+ left = set_dac (devc, 0x0b, left);
+ left = set_dac (devc, 0x0c, right);
+ break;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ value = left | (right << 8);
+ return devc->gains[ctrl] = value;
+ }
+
+ return OSS_EINVAL;
+}
+
+#if 0
+/*ARGSUSED*/
+static int
+set_mongain (envy24ht_devc * devc, int reg, int value)
+{
+ if (value < 0)
+ value = 0;
+ if (value > 79)
+ value = 79;
+
+ return value;
+}
+#endif
+
+/*ARGSUSED*/
+static int
+ap192_mixer_init (envy24ht_devc * devc, int dev, int g)
+{
+ int group = g;
+ int err;
+
+ if ((group = mixer_ext_create_group (dev, g, "VOL")) < 0)
+ return group;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, ap192_set_control,
+ MIXT_ONOFF,
+ "ENVY24_MUTE", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, ap192_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_PCM", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, ap192_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_IN", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, ap192_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_SPDIF", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ return 0;
+}
+
+static void
+ap192_card_init (envy24ht_devc * devc)
+{
+
+ int i;
+
+#if 1
+ OUTW (devc->osdev, 0xffff, devc->ccs_base + 0x18); /* GPIO direction */
+ OUTW (devc->osdev, 0x0000, devc->ccs_base + 0x16); /* GPIO write mask */
+ OUTW (devc->osdev, 0xffff, devc->ccs_base + 0x14); /* Initial bit state */
+
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x1a); /* GPIO direction for bits 16:22 */
+ OUTB (devc->osdev, 0x00, devc->ccs_base + 0x1f); /* GPIO mask for bits 16:22 */
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x1e); /* GPIO data for bits 16:22 */
+#endif
+
+ memcpy (devc->channel_names, channel_names, sizeof (channel_names));
+ AK4358_Init (devc);
+ ap192_Set_48K_Mode (devc);
+
+ for (i = 0; i < 5; i++)
+ devc->gains[i] = 0x7f7f;
+
+ ap192_Mute (devc, 0);
+
+ GPIOWrite (devc, 5, 0); /* Select S/PDIF output mux */
+ GPIOWrite (devc, 5, 0); /* Select S/PDIF output mux */
+
+}
+
+envy24ht_auxdrv_t envy24ht_ap192_auxdrv = {
+ ap192_card_init,
+ ap192_mixer_init,
+ ap192_set_rate,
+ NULL,
+ NULL,
+ NULL, /* ap192_private1 */
+ ap192_audio_ioctl
+};
diff --git a/kernel/drv/oss_envy24ht/envy24ht_aureon.c b/kernel/drv/oss_envy24ht/envy24ht_aureon.c
new file mode 100644
index 0000000..98c8d72
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht_aureon.c
@@ -0,0 +1,2536 @@
+/*
+ * Purpose: Low level routines for Terrate Aureon 7.1 family
+ */
+/*
+ *
+ * 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_envy24ht_cfg.h"
+
+#define IN
+#define OUT
+#define UCHAR unsigned char
+#define PUCHAR UCHAR*
+#define BYTE unsigned char
+#define PBYTE BYTE*
+#define BOOLEAN unsigned char
+#define ULONG unsigned int
+#define PULONG ULONG*
+#define USHORT unsigned short
+#define PUSHORT USHORT*
+
+#define WORD USHORT
+#define PWORD PUSHORT
+
+/*
+ * Default levels
+ */
+#define WM_OUT_DEFAULT 0x7F
+#define WM_OUT_MAX 0x7F
+#define WM_INP_DEFAULT 0x0C /* for 0dB */
+#define AC97_INP_DEFAULT 0x1f1f
+#define AC97_INP_MAX 0x1f
+
+#define REG_CCS 1
+#define REG_MT 2
+
+#define WM_MASTER_MODE_CNTRL 0
+
+/* List of the WKN CCS Control Registers. */
+#define WKN_CONTROL_REG 0x00
+#define WKN_INT_MASK_REG 0x01
+#define WKN_INT_STAT_REG 0x02
+#define WKN_DMA_INT 0x10
+#define WKN_UART_RECV 0x80
+#define WKN_UART_TRAN 0x20
+
+/* #define WKN_INDEX_REG 0x03 */
+
+#define WKN_SYS_CONFIG 0x04
+#define WKN_49MHZ 0x40
+#define WKN_ACLINK_CONFIG 0x05
+#define CODEC_AKM 0x80
+
+#define WKN_I2S_CONFIG 0x06
+#define WKN_SPDIF_CONFIG 0x07
+
+#define SPDIF_ENABLE_MASK 0x00010000
+
+/* #define WKN_AC97_INDEX 0x08 */
+/* #define WKN_AC97_CMDSTAT 0x09 */
+#define WKN_TX_QUE 0x0A
+#define WKN_RX_QUE 0x0B
+
+#define WKN_MIDI_PORT1_DATA_REG 0x0C
+#define WKN_MIDI_PORT1_CMD_REG 0x0D
+#define WKN_NMI_EXTSTAT_REG 0x0E
+
+#define WKN_I2C_DEVADDR 0x10
+#define WKN_I2C_AKM 0x20
+#define WKN_I2C_WRITE 0x01
+#define WKN_I2C_READ 0x00
+#define WKN_I2C_BYTEADDR 0x11
+#define WKN_I2C_DATA 0x12
+#define WKN_I2C_STATUS 0x13
+#define WKN_I2C_BUSY 0x01
+#define WKN_GPIO_DATA0 0x14
+#define WKN_GPIO_DATA1 0x15
+#define WKN_GPIO_DATA2 0x1E
+#define WKN_GPIO_WRT_MASK0 0x16
+#define WKN_GPIO_WRT_MASK1 0x17
+#define WKN_GPIO_WRT_MASK2 0x1F
+#define WKN_GPIO_DIR0 0x18
+#define WKN_GPIO_DIR1 0x19
+#define WKN_GPIO_DIR2 0x1A
+#define WKN_GPIO_DATA16 0x1E
+#define WKN_GPIO_WRT_MASK16 0x1F
+
+#define GPIO_DATA_ADR_MASK 0x000000FF
+#define GPIO_LD_DATA_H_MASK 0x00000100
+#define GPIO_LD_DATA_L_MASK 0x00000200
+#define GPIO_LD_ADR_MASK 0x00000400
+#define GPIO_GO_MASK 0x00000800
+#define GPIO_WM8770_CS_MASK 0x00001000
+#define GPIO_INT_REST_MASK 0x00002000
+#define GPIO_REMOTE_MASK 0x00004000
+#define GPIO_HEADPHONE_MASK 0x00004000
+#define GPIO_DIGITAL_SEL 0x00008000
+#define GPIO_AC97_RESET_MASK 0x00010000
+#define GPIO_SDA_TX_MASK 0x00020000
+#define GPIO_SDA_MASK 0x00040000
+#define GPIO_SCL_MASK 0x00080000
+#define GPIO_WM8770_RS_MASK 0x00100000
+#define GPIO_CS8415_CDTO_MASK 0x00200000
+#define GPIO_CS8415_CS_MASK 0x00400000
+
+#define WM_DAC1_VOL_CNTRL 0x00
+#define WM_DAC2_VOL_CNTRL 0x02
+#define WM_DAC3_VOL_CNTRL 0x04
+#define WM_DAC4_VOL_CNTRL 0x06
+#define WM_MASTER_VOL_CNTRL 0x08
+#define WM_POWER_CNTRL 0x18
+#define WM_ADC_GAIN_CNTRL 0x19
+#define WM_ADC_INPUT_MX 0x1B
+#define WM_OUT12_SELECT 0x1C
+#define WM_OUT34_SELECT 0x1D
+
+#define CS_CONTROL_1 0x01
+#define CS_CONTROL_2 0x02
+#define CS_CLK_SRC_CNTRL 0x04
+#define CS_SER_OUT_FORMAT 0x06
+
+#define MT_SAMPLE_RATE_REG 0x01
+#define MT_48KHZ 0x0
+#define MT_24KHZ 0x01
+#define MT_12KHZ 0x02
+#define MT_9p6KHZ 0x03
+#define MT_32KHZ 0x04
+#define MT_16KHZ 0x05
+#define MT_8KHZ 0x06
+#define MT_96KHZ 0x07
+#define MT_192KHZ 0x0E
+#define MT_64KHZ 0x0F
+#define MT_44p1KHZ 0x08
+#define MT_22p05KHZ 0x09
+#define MT_11p025KHZ 0x0A
+#define MT_88p2KHZ 0x0B
+#define MT_176p4KHZ 0x0C
+
+#define MT_DATA_FORMAT_REG 0x02
+#define MT_128X 0x08
+#define MT_INTR_MASK_REG 0x03
+
+#define SRC_PDMA 0x00
+#define SRC_PSDIN0_L 0x02
+#define SRC_PSDIN0_R 0x03
+#define SRC_SPDIN_L 0x06
+#define SRC_SPDIN_R 0x07
+#define SRC_MASK 0x07
+
+static const UCHAR gWMRegister[] = { WM_DAC1_VOL_CNTRL,
+ WM_DAC1_VOL_CNTRL + 1,
+ WM_DAC2_VOL_CNTRL,
+ WM_DAC2_VOL_CNTRL + 1,
+ WM_DAC3_VOL_CNTRL,
+ WM_DAC3_VOL_CNTRL + 1,
+ WM_DAC4_VOL_CNTRL,
+ WM_DAC4_VOL_CNTRL + 1,
+ WM_MASTER_VOL_CNTRL,
+ WM_MASTER_VOL_CNTRL + 1,
+ WM_ADC_GAIN_CNTRL,
+ WM_ADC_GAIN_CNTRL + 1
+};
+
+#define AC97_IDXREG_RESET 0x00
+#define AC97_IDXREG_STEREO_OUT 0x02
+#define AC97_IDXREG_MONO_OUT 0x06
+#define AC97_IDXREG_PCBEEP 0x0A
+#define AC97_IDXREG_PHONE 0x0C
+#define AC97_IDXREG_MIC_IN 0x0E
+#define AC97_IDXREG_LINE_IN 0x10
+#define AC97_IDXREG_CD_IN 0x12
+#define AC97_IDXREG_VIDEO_IN 0x14
+#define AC97_IDXREG_AUX_IN 0x16
+#define AC97_IDXREG_PCM_OUT 0x18
+#define AC97_IDXREG_RECORD_SELECT 0x1A
+#define AC97_IDXREG_RECORD_GAIN 0x1C
+#define AC97_IDXREG_GEN_PURPOSE 0x20
+#define AC97_IDXREG_POWER_DOWN 0x26
+#define AC97_IDXREG_TEST_CONTROL 0x5A
+#define AC97_IDXREG_VENDOR_RESV 0x7A
+#define AC97_IDXREG_VENDOR_ID1 0x7C
+#define AC97_IDXREG_VENDOR_ID2 0x7E
+/* AC97 register - AC97_IDXREG_RECORD_SELECT */
+#define AC97_REC_SELECT_MIC 0x0000
+#define AC97_REC_SELECT_LINEIN 0x0404
+#define AC97_REC_SELECT_ST_MIX 0x0505
+
+/*
+ * List of the Channel IDs
+ */
+#define CH_MASTER_LEFT ((OUT_MASTER<<16)|CH_LEFT)
+#define CH_MASTER_RIGHT ((OUT_MASTER<<16)|CH_RIGHT)
+#define CH_MASTER_BOTH ((OUT_MASTER<<16)|CH_BOTH)
+
+#define CH_OUT12_LEFT ((OUT_12<<16)|CH_LEFT)
+#define CH_OUT12_RIGHT ((OUT_12<<16)|CH_RIGHT)
+#define CH_OUT12_BOTH ((OUT_12<<16)|CH_BOTH)
+#define CH_OUT34_LEFT ((OUT_34<<16)|CH_LEFT)
+#define CH_OUT34_RIGHT ((OUT_34<<16)|CH_RIGHT)
+#define CH_OUT34_BOTH ((OUT_34<<16)|CH_BOTH)
+#define CH_OUT56_LEFT ((OUT_56<<16)|CH_LEFT)
+#define CH_OUT56_RIGHT ((OUT_56<<16)|CH_RIGHT)
+#define CH_OUT56_BOTH ((OUT_56<<16)|CH_BOTH)
+#define CH_OUT78_LEFT ((OUT_78<<16)|CH_LEFT)
+#define CH_OUT78_RIGHT ((OUT_78<<16)|CH_RIGHT)
+#define CH_OUT78_BOTH ((OUT_78<<16)|CH_BOTH)
+
+#define CH_IN12_LEFT ((IN_12<<16)|CH_LEFT)
+#define CH_IN12_RIGHT ((IN_12<<16)|CH_RIGHT)
+#define CH_IN12_BOTH ((IN_12<<16)|CH_BOTH)
+
+#define CH_FRONT_BOTH CH_OUT12_BOTH
+#define CH_REAR_BOTH CH_OUT34_BOTH
+#define CH_CENTER CH_OUT56_LEFT
+#define CH_LFE CH_OUT56_RIGHT
+#define CH_BS_BOTH CH_OUT78_BOTH
+
+#define MAX_VOLUME 0x7F
+#define MIN_VOLUME 0x00
+
+#define MAX_GAIN 0x1F
+
+#define MT_PLAY_REC_UNDOVR 0x01A
+#define MT_INTR_STATUS_REG 0x00
+#define MT_INTR_MASK_REG 0x03
+#define MT_SPDIF_REG 0x3C
+
+/* List of AC97 inputs */
+#define AC97_CD 0
+#define AC97_AUX 1
+#define AC97_LINE 2
+#define AC97_MIC 3
+#define AC97_PHONO 4
+#define AC97_LINE2 5
+#define AC97_COUNT 6 /* Must match devc->m_AC97Volume definition in envy24ht.h */
+
+/* Channel def */
+#define CH_LEFT 0x00000001
+#define CH_RIGHT 0x00000002
+#define CH_BOTH (CH_LEFT|CH_RIGHT)
+#define CH_NOP 0xFFFFFFFF
+
+/*
+ * List of inputs
+ */
+#define ADC_CD 0
+#define ADC_AUX 1
+#define ADC_LINE 2
+#define ADC_MIC 3
+#define ADC_PHONO 4
+#define ADC_WTL 5
+#define ADC_LINE_REAR 6
+#define ADC_STEREO_MIX 7
+#define ADC_COUNT 8 /* Must match the size of m_ADCVolume */
+
+/*
+ * List of Lines
+ */
+#define LINE_OUT_1L 0x00000000
+#define LINE_OUT_1R 0x00000001
+#define LINE_OUT_2L 0x00000002
+#define LINE_OUT_2R 0x00000003
+#define LINE_OUT_3L 0x00000004
+#define LINE_OUT_3R 0x00000005
+#define LINE_OUT_4L 0x00000006
+#define LINE_OUT_4R 0x00000007
+#define LINE_MASTER 0x00000008
+#define LINE_MASTER_ 0x00000009
+#define LINE_GAIN_L 0x0000000a
+#define LINE_GAIN_R 0x0000000b
+#define LINE_S_NUM 0x0000000c /* 12 - Should match devc->m_fDACMute size */
+
+/*
+ * List of Stereo Lines
+ */
+#define OUT_12 0x00000000
+#define OUT_34 0x00000001
+#define OUT_56 0x00000002
+#define OUT_78 0x00000003
+#define OUT_MASTER 0x00000004
+#define IN_12 0x00000005
+#define NUM_LINES 0x00000006
+
+/*
+ * SPDIF Out Source
+ */
+enum
+{
+ DIGOUT_DIG_IN = 0,
+ DIGOUT_ANA_IN,
+ DIGOUT_WAVE
+};
+/*
+ * Digital IN Source
+ */
+enum
+{
+ DIGIN_OPTICAL = 0,
+ DIGIN_COAX,
+ DIGIN_CD_IN
+};
+/*
+ * Out-0 Source
+ */
+enum
+{
+ SRC_DMA1 = 0,
+ SRC_PSDIN0,
+ SRC_SPDIN
+};
+
+/*
+ * Line IN Source (Aureon 7.1 Universe only)
+ */
+#define SRC_AUX 0
+#define SRC_WTL 1
+#define SRC_LINE_REAR 2
+#define SRC_GROUND 3
+
+/*
+ * Clock Source
+ */
+enum
+{
+ ICE_INTERNAL_CLOCK = 0,
+ ICE_SPDIF_CLOCK
+};
+/*
+ * Function of Frontjack
+ */
+enum
+{
+ FRONT_JACK_LINEIN = 0,
+ FRONT_JACK_HEADPHONE
+};
+
+enum MUX_TP_PIN
+{
+ CD_IN_MUX_TP_PIN = 1,
+ LINE_IN_MUX_TP_PIN,
+ AUX_IN_MUX_TP_PIN,
+ PHONO_IN_MUX_PIN,
+ LINE2_IN_MUX_PIN,
+ MIC_IN_MUX_TP_PIN,
+ DIG_IN_MUX_TP_PIN,
+ STEREO_MIX_MUX_TP_PIN
+};
+
+#define AUREON_REMOTE_CNTRL 0x32
+/* #define AUREON_REMOTE_ID 0x0016 */
+#define AUREON_REMOTE_ID 0x6B86
+#define AUREON_PCA_BASEBOARD 0x40
+
+#define MT_LOOPBK_CONTROL 0x02C
+#define MT_LOOPBK_CONTROL_DAC_REG 0x030
+#define MT_LOOPBK_CONTROL_SPDIF_OUT_REG 0x032
+
+#define WIDTH_BYTE 1
+#define WIDTH_WORD 2
+#define WIDTH_DWORD 4
+
+#define BITS_ON 0x10
+#define BITS_OFF 0x00
+#define TOGGLE_ON 0x20
+
+#define CRITSEC_ON 0x00000001
+
+#define WIDTH_MASK 0x0f
+
+#include "spdif.h"
+#include "envy24ht.h"
+
+/*! \fn =======================================================================
+ Function : WritePort
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : dwRegType ->
+ : dwIndex ->
+ : dwValue ->
+ : dwWidth ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void WritePort
+ (envy24ht_devc * devc,
+ IN ULONG dwRegType, IN ULONG dwIndex, IN ULONG dwValue, IN ULONG dwWidth)
+{
+ oss_native_word pPort = devc->ccs_base;
+
+ switch (dwRegType)
+ {
+ case REG_CCS:
+ pPort = devc->ccs_base;
+ break;
+
+ case REG_MT:
+ pPort = devc->mt_base;
+ break;
+ }
+
+ /* registers are addressible in byte, word or dword */
+ switch (dwWidth)
+ {
+ case WIDTH_BYTE:
+ OUTB (devc->osdev, dwValue, pPort + dwIndex);
+ break;
+ case WIDTH_WORD:
+ OUTW (devc->osdev, dwValue, pPort + dwIndex);
+
+ break;
+ case WIDTH_DWORD:
+ OUTL (devc->osdev, dwValue, pPort + dwIndex);
+ break;
+ }
+}
+
+
+/*! \fn =======================================================================
+ Function : ReadPort
+-------------------------------------------------------------------------------
+ Description :
+ Returns : ->
+ Parameters : IN ULONG dwWidth ->
+ IN ULONG dwWidth
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static ULONG ReadPort
+ (envy24ht_devc * devc,
+ IN ULONG dwRegType, IN ULONG dwIndex, IN ULONG dwWidth)
+{
+ oss_native_word pPort = devc->ccs_base;
+ ULONG dwData = 0;
+
+ switch (dwRegType)
+ {
+ case REG_CCS:
+ pPort = devc->ccs_base;
+ break;
+
+ case REG_MT:
+ pPort = devc->mt_base;
+ break;
+ }
+
+ /* all other registers are addressible in byte, word or dword */
+ switch (dwWidth)
+ {
+ case WIDTH_BYTE:
+ dwData = INB (devc->osdev, pPort + dwIndex);
+ break;
+ case WIDTH_WORD:
+ dwData = INW (devc->osdev, pPort + dwIndex);
+ break;
+ case WIDTH_DWORD:
+ dwData = INL (devc->osdev, pPort + dwIndex);
+ break;
+ }
+
+
+ return dwData;
+}
+
+/*! \fn =======================================================================
+ Function : ReadModifyWritePort
+-------------------------------------------------------------------------------
+ Description :
+ Returns : VOID ->
+ Parameters : wRegType ->
+ : dwMask ->
+ : dwControl ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void ReadModifyWritePort
+ (envy24ht_devc * devc,
+ IN ULONG dwRegType, IN ULONG dwIndex, IN ULONG dwMask, IN ULONG dwControl
+ /* dwControl: */
+ /* bit[3:0] : data width, 1 => byte, 2 => word, 4 => dword */
+ /* bit[4] : 1 => turn on bit(s); 0 => turn off bit(s) */
+ /* bit[5] : 1 => toggle bit(s) */
+ /* bit[6] : 1 => turn on Hw access critical section */
+ )
+{
+ ULONG dwValue;
+ ULONG dwWidth;
+ oss_native_word flags;
+
+ dwWidth = dwControl & WIDTH_MASK;
+
+ if (dwControl & CRITSEC_ON)
+ {
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ }
+
+ dwValue = ReadPort (devc, dwRegType, dwIndex, dwWidth);
+
+ /* see whether we should turn on or off the bit(s) */
+ if (dwControl & BITS_ON)
+ dwValue |= dwMask;
+ else
+ dwValue &= ~dwMask;
+
+ WritePort (devc, dwRegType, dwIndex, dwValue, dwWidth);
+
+ /* see if we need to toggle the bit(s) */
+ if (dwControl & TOGGLE_ON)
+ {
+ dwValue ^= dwMask;
+ WritePort (devc, dwRegType, dwIndex, dwValue, dwWidth);
+ }
+
+ if (dwControl & CRITSEC_ON)
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+ }
+
+}
+
+/*! \fn =======================================================================
+ Function : WriteGPIO
+-------------------------------------------------------------------------------
+ Description : Writes masked Data to GPIO Port
+ Parameters : IN ULONG Data ->
+ : IN ULONG Mask ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+WriteGPIO (envy24ht_devc * devc, IN ULONG Data, IN ULONG Mask)
+{
+ USHORT MaskL;
+ UCHAR MaskH;
+ USHORT DataL;
+ UCHAR DataH;
+
+ /* Do the masking. */
+ MaskL = (USHORT) Mask;
+ MaskH = (UCHAR) (Mask >> 16);
+ DataL = (USHORT) Data;
+ DataH = (UCHAR) (Data >> 16);
+ devc->gpio_shadow_L &= ~MaskL;
+ devc->gpio_shadow_H &= ~MaskH;
+ devc->gpio_shadow_L |= (MaskL & DataL);
+ devc->gpio_shadow_H |= (MaskH & DataH);
+
+ /* Write Data */
+ WritePort (devc, REG_CCS, WKN_GPIO_DATA0, devc->gpio_shadow_L, WIDTH_WORD);
+ WritePort (devc, REG_CCS, WKN_GPIO_DATA2, devc->gpio_shadow_H, WIDTH_BYTE);
+}
+
+/*! \fn =======================================================================
+ Function : SetSDADir
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+ Parameters : IN BOOLEAN fOut ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetSDADir (envy24ht_devc * devc, IN BOOLEAN fOut)
+{
+ if (fOut)
+ {
+ /* Set GPIO 18 direction to output */
+ WritePort (devc, REG_CCS, WKN_GPIO_DIR2, 0xDF, WIDTH_BYTE);
+ /* Turn IIC logic to SDA write */
+ WriteGPIO (devc, GPIO_SDA_TX_MASK, GPIO_SDA_TX_MASK);
+ }
+ else
+ {
+ WriteGPIO (devc, 0, GPIO_SDA_TX_MASK);
+ /* Direction "Read" for GPIO 18 (SDA) */
+ WritePort (devc, REG_CCS, WKN_GPIO_DIR2, 0xDB, WIDTH_BYTE);
+ }
+}
+
+/*! \fn =======================================================================
+ Function : SetSDA
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : BOOLEAN fSet
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetSDA (envy24ht_devc * devc, BOOLEAN fSet)
+{
+ /* Set GPIO 18 direction to output */
+ SetSDADir (devc, 1);
+ /* Write SDA */
+ WriteGPIO (devc, fSet ? GPIO_SDA_MASK : 0, GPIO_SDA_MASK);
+}
+
+/*! \fn =======================================================================
+ Function : GetSDA
+-------------------------------------------------------------------------------
+ Description :
+ Returns :
+UCHAR ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static UCHAR
+GetSDA (envy24ht_devc * devc)
+{
+ UCHAR ulData;
+
+ /* Turn IIC logic to SDA read */
+ SetSDADir (devc, 0);
+ ulData =
+ ((ReadPort (devc, REG_CCS, WKN_GPIO_DATA2, WIDTH_BYTE) & 0x04) == 0x04);
+ return ulData;
+}
+
+/*! \fn =======================================================================
+ Function : SetIIC
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN BOOLEAN fSDA ->
+ : IN BOOLEAN fCLK ->
+ : IN ULONG ulSleep ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void SetIIC
+ (envy24ht_devc * devc, IN BOOLEAN fSDA, IN BOOLEAN fCLK, IN ULONG ulSleep)
+{
+ SetSDA (devc, fSDA);
+ if (fCLK)
+ WriteGPIO (devc, GPIO_SCL_MASK, GPIO_SCL_MASK);
+ else
+ WriteGPIO (devc, 0, GPIO_SCL_MASK);
+ if (ulSleep)
+ oss_udelay (ulSleep);
+}
+
+/*! \fn =======================================================================
+ Function : IICStart
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : ULONG ulSleep ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+IICStart (envy24ht_devc * devc, ULONG ulSleep)
+{
+ /* falling edge of SDA while SCL is HIGH */
+ SetIIC (devc, 1, 1, ulSleep);
+ SetIIC (devc, 0, 1, ulSleep);
+}
+
+/*! \fn =======================================================================
+ Function : IICStop
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : ULONG ulSleep ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+IICStop (envy24ht_devc * devc, ULONG ulSleep)
+{
+ /* rising edge of SDA while SCL is HIGH */
+ SetIIC (devc, 0, 1, ulSleep);
+ SetIIC (devc, 1, 1, ulSleep);
+ /* Reset Lines (No IIC requirement, but for prevent conflicts with SPI) */
+ /*SetIIC(0,0,ulSleep); */
+}
+
+/*! \fn =======================================================================
+ Function : IICSendByte
+-------------------------------------------------------------------------------
+ Description :
+ Returns : UCHAR ->
+ Parameters : CHAR bByte ->
+ : ULONG ulSleep ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static UCHAR IICSendByte
+ (envy24ht_devc * devc, IN UCHAR bByte, IN ULONG ulSleep)
+{
+ UCHAR bDataBit, bAck;
+ int i;
+ for (i = 7; i >= 0; i--) /* send byte (MSB first) */
+ {
+ bDataBit = (bByte >> i) & 0x01;
+
+ SetIIC (devc, bDataBit, 0, ulSleep);
+ SetIIC (devc, bDataBit, 1, ulSleep);
+ SetIIC (devc, bDataBit, 0, ulSleep);
+ } /* end for i */
+
+ SetIIC (devc, 1, 0, ulSleep);
+
+ /* This is neccesary for PLC */
+ SetSDADir (devc, 0);
+ /* Get acknowledge */
+ SetIIC (devc, 1, 1, ulSleep);
+ bAck = GetSDA (devc);
+ /*if (fAddress) */
+ /* SetIIC(devc, 1,0,ulSleep); */
+ /* else */
+ /* this is a start condition but never mind */
+ SetIIC (devc, 0, 0, ulSleep);
+ return (!bAck); /* bAck = 0 --> success */
+}
+
+#if 0
+/*! \fn =======================================================================
+ Function : IICReceiveByte
+-------------------------------------------------------------------------------
+ Description :
+ Returns : UCHAR ->
+ Parameters : CHAR fLastByte ->
+ : ULONG ulSleep ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static UCHAR IICReceiveByte
+ (envy24ht_devc * devc, UCHAR fLastByte, ULONG ulSleep)
+{
+ UCHAR bRead = 0;
+ int i;
+
+ for (i = 7; i >= 0; i--)
+ {
+ SetIIC (devc, 1, 0, ulSleep);
+ SetIIC (devc, 1, 1, ulSleep);
+ bRead <<= 1;
+ bRead += GetSDA (devc);
+ }
+
+ /* -> no acknowledge for last received byte */
+ SetIIC (devc, fLastByte, 0, ulSleep); /* SDA = HIGH for last byte */
+ SetIIC (devc, fLastByte, 1, ulSleep);
+ SetIIC (devc, fLastByte, 0, ulSleep); /* clock -> LOW */
+
+ return bRead;
+}
+#endif
+
+/*! \fn =======================================================================
+ Function : IICWriteBuffer
+-------------------------------------------------------------------------------
+ Description :
+ Returns : UCHAR ->
+ Parameters : CHAR bIicAddress ->
+ : PUCHAR pbByte ->
+ : USHORT nNoBytes ->
+ : ULONG ulSleep ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static UCHAR IICWriteBuffer
+ (envy24ht_devc * devc,
+ UCHAR bIicAddress, PUCHAR pbByte, USHORT nNoBytes, ULONG ulSleep)
+{
+ IICStart (devc, ulSleep);
+
+ /* send IIC address and data byte */
+ if (!IICSendByte (devc, bIicAddress, ulSleep))
+ goto FAILED;
+ /* send buffer */
+ do
+ {
+ if (!IICSendByte (devc, *pbByte, ulSleep))
+ goto FAILED; /* got no acknowledge */
+ pbByte++;
+ nNoBytes--;
+ }
+ while (nNoBytes);
+
+ IICStop (devc, ulSleep);
+ return 1;
+
+FAILED:
+ IICStop (devc, ulSleep);
+ return 0;
+}
+
+/*! \fn =======================================================================
+ Function : WriteCS8415
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN UCHAR Register ->
+ : IN UCHAR Value ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void WriteCS8415
+ (envy24ht_devc * devc, IN UCHAR Register, IN UCHAR Value)
+{
+ ULONG i;
+ BOOLEAN fData;
+ ULONG ulCmd;
+ ULONG ulCount;
+
+ /* m_pAdapter->HwEnter(); *//* TODO */
+
+ /* Clock low to prevent IIC Startcondition */
+ WriteGPIO (devc, 0, GPIO_SCL_MASK);
+
+ SetSDA (devc, 0);
+ /* Chip select (CS low) */
+ WriteGPIO (devc, 0, GPIO_CS8415_CS_MASK);
+
+ /* format buffer */
+ ulCmd = 0x200000 + /* chip address + R/W */
+ (((ULONG) Register) << 8) + /* register address */
+ Value; /* Value */
+ ulCmd <<= 8;
+ ulCount = 24; /* (AddressOnly) ? 16:24; */
+ for (i = 0; i < ulCount; i++)
+ {
+ fData = (ulCmd & 0x80000000) ? 1 : 0;
+ /* CCLK -> low */
+ WriteGPIO (devc, 0, GPIO_SCL_MASK);
+ oss_udelay (3);
+ /* CDTI -> Set data */
+ SetSDA (devc, fData);
+ oss_udelay (3);
+ /* CCLK -> high */
+ WriteGPIO (devc, GPIO_SCL_MASK, GPIO_SCL_MASK);
+ ulCmd <<= 1;
+ }
+ WriteGPIO (devc, 0, GPIO_SCL_MASK); /* CCLK -> low */
+
+ /* Chip deselect (CS high) */
+ WriteGPIO (devc, GPIO_CS8415_CS_MASK, GPIO_CS8415_CS_MASK);
+ /* m_pAdapter->HwLeave(); *//* TODO */
+}
+
+#if 0
+/*! \fn =======================================================================
+ Function : ReadCS8415
+-------------------------------------------------------------------------------
+ Description :
+ Returns : UCHAR ->
+ Parameters : IN UCHAR Register ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+ /*ARGSUSED*/ static UCHAR
+ReadCS8415 (envy24ht_devc * devc, IN UCHAR Register)
+{
+ ULONG i;
+ BOOLEAN fData;
+ UCHAR cValue = 0;
+ USHORT wCmd;
+
+ /* m_pAdapter->HwEnter(); *//* TODO */
+
+ /* Clock low to prevent IIC Startcondition */
+ WriteGPIO (devc, 0, GPIO_SCL_MASK);
+
+ SetSDA (devc, 0);
+
+ /* Chip select (CS low) */
+ WriteGPIO (devc, 0, GPIO_CS8415_CS_MASK);
+ /* Set GPIO21 to read direction */
+ WritePort (devc, REG_CCS, WKN_GPIO_DIR2, 0xDF, WIDTH_BYTE);
+
+ wCmd = 0x2100; /* + *//* chip address + R/W */
+ /*(((USHORT)Register) << 8); *//* register address */
+ for (i = 0; i < 16; i++)
+ {
+ fData = (wCmd & 0x8000) ? 1 : 0;
+ /* CCLK -> low */
+ WriteGPIO (devc, 0, GPIO_SCL_MASK);
+ /* CDTI -> Set data */
+ SetSDA (devc, fData);
+ oss_udelay (3);
+ /* CCLK -> high */
+ WriteGPIO (devc, GPIO_SCL_MASK, GPIO_SCL_MASK);
+ wCmd <<= 1;
+ if (i > 7)
+ {
+ /* Read CDTO */
+ cValue <<= 1;
+ cValue +=
+ ((ReadPort (devc, REG_CCS, WKN_GPIO_DATA2, WIDTH_BYTE) & 0x20) ==
+ 0x20);
+ }
+ }
+
+ WriteGPIO (devc, 0, GPIO_SCL_MASK); /* CCLK -> low */
+
+ /* Chip deselect (CS high) */
+ WriteGPIO (devc, GPIO_CS8415_CS_MASK, GPIO_CS8415_CS_MASK);
+
+ /* m_pAdapter->HwLeave(); *//* TODO */
+ return cValue;
+}
+#endif
+
+/*
+ * Definition of PCA I/Os
+ */
+typedef union tagPCA_CFG
+{
+ unsigned char cReg;
+ struct
+ {
+ unsigned char P00_SourceSel:2; /* LineIN Selector */
+ /* 00 -> Aux */
+ /* 01 -> Wavetable */
+ /* 11 -> LineIN Rear */
+ unsigned char P02_DigSel:1; /* DigitalIN Selector */
+ /* 0 -> Coax */
+ /* 1 -> Optical */
+
+ unsigned char P03_LineLED:1; /* LineLED */
+ /* 0 -> Off */
+ /* 1 -> On */
+ unsigned char P04_unused:4; /* unused */
+ } Bits;
+} PCA_CFG;
+
+/*! \fn =======================================================================
+ Function : WritePCA
+-------------------------------------------------------------------------------
+ Description :
+ Returns : NTSTATUS ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+WritePCA (envy24ht_devc * devc)
+{
+ PCA_CFG tCFG;
+ BYTE bByte[2];
+
+ tCFG.cReg = 0;
+
+ switch (devc->m_LineInSource)
+ {
+ case SRC_AUX:
+ tCFG.Bits.P00_SourceSel = 0;
+ break;
+ case SRC_WTL:
+ tCFG.Bits.P00_SourceSel = 1;
+ break;
+ case SRC_LINE_REAR:
+ tCFG.Bits.P00_SourceSel = 2;
+ break;
+ case SRC_GROUND:
+ tCFG.Bits.P00_SourceSel = 3;
+ break;
+
+ }
+
+ /* Switch LineLED when Line is selected for record */
+ if (devc->m_ADCIndex == ADC_LINE)
+ tCFG.Bits.P03_LineLED = 1;
+ if (devc->m_DigInSource == DIGIN_OPTICAL)
+ tCFG.Bits.P02_DigSel = 1;
+ /* Set all I/Os to Output */
+ bByte[0] = 3;
+ bByte[1] = 0;
+ IICWriteBuffer (devc, AUREON_PCA_BASEBOARD, bByte, 2, 30);
+ /* Write config */
+ bByte[0] = 0x01;
+ bByte[1] = tCFG.cReg;
+ IICWriteBuffer (devc, AUREON_PCA_BASEBOARD, bByte, 2, 30);
+}
+
+/*! \fn =======================================================================
+ Function : SetDigInSource
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+ Parameters : IN ULONG Source ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetDigInSource (envy24ht_devc * devc, IN ULONG Source)
+{
+ switch (Source)
+ {
+ case DIGIN_OPTICAL:
+ case DIGIN_COAX:
+ WriteCS8415 (devc, CS_CONTROL_2, 0x01);
+ break;
+ case DIGIN_CD_IN:
+ WriteCS8415 (devc, CS_CONTROL_2, 0x00);
+ break;
+ }
+ devc->m_DigInSource = Source;
+ WritePCA (devc);
+}
+
+/*! \fn =======================================================================
+ Function : SetOUT0Source
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+ Parameters : IN ULONG Source ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetOUT0Source (envy24ht_devc * devc, IN ULONG Source)
+{
+ ULONG ulShiftL, ulShiftR;
+ ULONG aulShiftL[] = { 0, 8, 11, 14, 17 };
+ ULONG aulShiftR[] = { 3, 20, 23, 26, 29 };
+ ULONG ulSourceL, ulSourceR;
+ int i;
+
+ /* No DigMonitor when Clock is internal */
+ if ((devc->m_ClockSource == ICE_INTERNAL_CLOCK) && (Source == SRC_SPDIN))
+ return;
+ for (i = 0; i < 5; i++)
+ {
+ ulShiftL = aulShiftL[i];
+ ulShiftR = aulShiftR[i];
+ switch (Source)
+ {
+ case SRC_DMA1:
+ ulSourceL = SRC_PDMA;
+ ulSourceR = SRC_PDMA;
+ break;
+ case SRC_PSDIN0:
+ ulSourceL = SRC_PSDIN0_L;
+ ulSourceR = SRC_PSDIN0_R;
+ break;
+ case SRC_SPDIN:
+ ulSourceL = SRC_SPDIN_L;
+ ulSourceR = SRC_SPDIN_R;
+ break;
+ default: /* Do nothing */
+ return;
+ }
+ /* First reset all relevant bits */
+ ReadModifyWritePort (devc, REG_MT, MT_LOOPBK_CONTROL,
+ SRC_MASK << ulShiftL, WIDTH_DWORD | BITS_OFF);
+ ReadModifyWritePort (devc, REG_MT, MT_LOOPBK_CONTROL,
+ SRC_MASK << ulShiftR, WIDTH_DWORD | BITS_OFF);
+ /* ..and set routing mask */
+ ReadModifyWritePort (devc, REG_MT, MT_LOOPBK_CONTROL,
+ ulSourceL << ulShiftL, WIDTH_DWORD | BITS_ON);
+ ReadModifyWritePort (devc, REG_MT, MT_LOOPBK_CONTROL,
+ ulSourceR << ulShiftR, WIDTH_DWORD | BITS_ON);
+ }
+ devc->m_Out0Source = Source;
+}
+static void SetADCMux (envy24ht_devc * devc, IN ULONG Value);
+
+/*! \fn =======================================================================
+ Function : SetLineSource
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN ULONG Source ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetLineSource (envy24ht_devc * devc, IN ULONG Source)
+{
+ switch (Source)
+ {
+ case SRC_AUX:
+ devc->m_AuxMux = 0x00;
+ break;
+ case SRC_WTL:
+ devc->m_AuxMux = 0x44;
+ break;
+ case SRC_LINE_REAR:
+ devc->m_AuxMux = 0x66;
+ break;
+
+ }
+ /* Update ADCMux */
+ SetADCMux (devc, devc->m_ADCMux);
+ devc->m_LineInSource = Source;
+ WritePCA (devc);
+}
+
+/*! \fn =======================================================================
+ Function : SetClockSource
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN ULONG ClockSource ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetClockSource (envy24ht_devc * devc, IN ULONG ClockSource)
+{
+
+ if (ClockSource == ICE_INTERNAL_CLOCK)
+ {
+ ReadModifyWritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, 0x10,
+ WIDTH_BYTE | BITS_OFF);
+ /* Disable DigMonitor to avoid noisy output */
+ if (devc->m_Out0Source == SRC_SPDIN)
+ SetOUT0Source (devc, SRC_DMA1);
+ }
+ else
+ {
+ ReadModifyWritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, 0x10,
+ WIDTH_BYTE | BITS_ON);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ }
+ devc->m_ClockSource = ClockSource;
+}
+
+/*! \fn =======================================================================
+ Function : ResetGPIO
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+ResetGPIO (envy24ht_devc * devc)
+{
+
+ /* Enable all lower GPIOs */
+ WritePort (devc, REG_CCS, WKN_GPIO_WRT_MASK0, 0x0, WIDTH_WORD);
+ /* Enable all upper GPIOs */
+ WritePort (devc, REG_CCS, WKN_GPIO_WRT_MASK2, 0x0, WIDTH_BYTE);
+ /* Set GPIO direction */
+ if (devc->subvendor == SSID_AUREON_UNIVERSE)
+ {
+ /* -> all output except GPIO_CS8415_CDTO_MASK */
+ /* and GPIO_REMOTE_MASK */
+ WritePort (devc, REG_CCS, WKN_GPIO_DIR0,
+ ~(GPIO_CS8415_CDTO_MASK | GPIO_REMOTE_MASK), WIDTH_DWORD);
+ }
+ else
+ {
+ /* All output except GPIO_CS8415_CDTO_MASK */
+ WritePort (devc, REG_CCS, WKN_GPIO_DIR0, ~GPIO_CS8415_CDTO_MASK,
+ WIDTH_DWORD);
+ }
+
+ oss_udelay (100);
+
+ /*----------------------------------------------------------------------------
+ Reset AC97 Interface
+ -----------------------------------------------------------------------------*/
+
+ WriteGPIO (devc, GPIO_AC97_RESET_MASK, GPIO_AC97_RESET_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, 0, GPIO_AC97_RESET_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, GPIO_AC97_RESET_MASK, GPIO_AC97_RESET_MASK);
+
+ /*----------------------------------------------------------------------------
+ Enable Remote-Control Interrupts
+ -----------------------------------------------------------------------------*/
+ WriteGPIO (devc, GPIO_INT_REST_MASK, GPIO_INT_REST_MASK);
+
+ /* Select optical input */
+ /* WriteGPIO(devc, GPIO_DIGITAL_SEL, 0); */
+}
+
+/*! \fn =======================================================================
+ Function : SetSPDIFConfig
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+ Parameters : IN ULONG Config ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetSPDIFConfig (envy24ht_devc * devc, IN ULONG Config)
+{
+ ReadModifyWritePort (devc, REG_CCS, WKN_SPDIF_CONFIG, 0x80,
+ WIDTH_BYTE | BITS_OFF);
+ if (Config & SPDIF_ENABLE_MASK)
+ {
+ devc->m_f1724SPDIF = 1;
+ }
+ else
+ {
+ devc->m_f1724SPDIF = 0;
+ }
+ /* Reset SPDIF Config */
+ ReadModifyWritePort (devc, REG_MT, MT_SPDIF_REG, 0x000F,
+ WIDTH_WORD | BITS_OFF);
+ /* Set new Config */
+ ReadModifyWritePort (devc, REG_MT, MT_SPDIF_REG, Config & 0xFFFF,
+ WIDTH_WORD | BITS_ON);
+ devc->m_SPDIFConfig = Config;
+ if (devc->m_f1724SPDIF)
+ ReadModifyWritePort (devc, REG_CCS, WKN_SPDIF_CONFIG, 0x80,
+ WIDTH_BYTE | BITS_ON);
+ /* Force saving of registers */
+ /* devc->m_pAdapter->SetDirty(); *//* TODO */
+}
+
+/*! \fn =======================================================================
+ Function : SetFrontjack
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN ULONG Frontjack ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetFrontjack (envy24ht_devc * devc, IN ULONG Frontjack)
+{
+
+ switch (Frontjack)
+ {
+ case FRONT_JACK_LINEIN:
+ WriteGPIO (devc, 0, GPIO_HEADPHONE_MASK);
+ break;
+ case FRONT_JACK_HEADPHONE:
+ WriteGPIO (devc, GPIO_HEADPHONE_MASK, GPIO_HEADPHONE_MASK);
+ break;
+ }
+ devc->m_Frontjack = Frontjack;
+ /* Force saving of registers */
+ /* devc->m_pAdapter->SetDirty(); *//* TODO */
+
+}
+
+/*! \fn =======================================================================
+ Function : Init1724
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+Init1724 (envy24ht_devc * devc)
+{
+ /* System Config: 4 DACs, one ADC & SPDIF, MPU enabled, 24,576Mhz crystal */
+ /* WritePort(REG_CCS, WKN_SYS_CONFIG, 0x2B, WIDTH_BYTE); */
+ /* CL_NOTE: New Setings */
+ /* System Config: 4 DACs, one ADC & SPDIF, MPU disabled, 24,576Mhz crystal */
+ WritePort (devc, REG_CCS, WKN_SYS_CONFIG, 0x0B, WIDTH_BYTE);
+
+ /* Config I2S Interface */
+ WritePort (devc, REG_CCS, WKN_ACLINK_CONFIG, 0x80, WIDTH_BYTE);
+ WritePort (devc, REG_CCS, WKN_I2S_CONFIG, 0xF9, WIDTH_BYTE);
+ WritePort (devc, REG_CCS, WKN_SPDIF_CONFIG, 0x83, WIDTH_BYTE);
+
+ /* Config Interrupt behaviour */
+ WritePort (devc, REG_MT, MT_PLAY_REC_UNDOVR, 0, WIDTH_BYTE);
+ WritePort (devc, REG_MT, MT_INTR_STATUS_REG, 0, WIDTH_BYTE);
+ WritePort (devc, REG_MT, MT_INTR_MASK_REG, 0xFF, WIDTH_BYTE);
+ WritePort (devc, REG_CCS, WKN_INT_STAT_REG, 0, WIDTH_BYTE);
+ WritePort (devc, REG_CCS, WKN_INT_MASK_REG, 0xFE, WIDTH_BYTE);
+
+ SetSPDIFConfig (devc, 0);
+ /* SetSDPIFSource(devc, DIGOUT_WAVE); */
+ SetDigInSource (devc, DIGIN_OPTICAL);
+ SetFrontjack (devc, FRONT_JACK_LINEIN);
+}
+
+/*! \fn =======================================================================
+ Function : WriteWM8770
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN UCHAR Register ->
+ : IN UCHAR Value ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+void
+WriteWM8770 (envy24ht_devc * devc, IN UCHAR Register, IN USHORT Value)
+{
+ int i;
+ BOOLEAN fData;
+ USHORT wCmd;
+/* KIRQL OldIrql; */
+
+ /* m_pAdapter->HwEnter(); */
+
+ /* KeAcquireSpinLock (&m_SPILock,&OldIrql); */
+
+
+ /* Clock low to prevent IIC Startcondition */
+ WriteGPIO (devc, 0, GPIO_SCL_MASK);
+
+ SetSDA (devc, 0);
+
+ /* Chip select (CS low) */
+ WriteGPIO (devc, 0, GPIO_WM8770_CS_MASK);
+
+ /* format buffer */
+ wCmd = (((USHORT) Register) << 9) + Value;
+
+
+ for (i = 0; i < 16; i++)
+ {
+ fData = (wCmd & 0x8000) ? 1 : 0;
+ /* CCLK -> low */
+ WriteGPIO (devc, 0, GPIO_SCL_MASK);
+ oss_udelay (3);
+ /* CDTI -> Set data */
+ SetSDA (devc, fData);
+ oss_udelay (3);
+ /* CCLK -> high */
+ WriteGPIO (devc, GPIO_SCL_MASK, GPIO_SCL_MASK);
+ wCmd <<= 1;
+ }
+ WriteGPIO (devc, 0, GPIO_SCL_MASK); /* CCLK -> low */
+
+ /* Chip deselect */
+ WriteGPIO (devc, GPIO_WM8770_CS_MASK, GPIO_WM8770_CS_MASK);
+}
+
+/*! \fn =======================================================================
+ Function : SetVolReg
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN ULONG LineIdx ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetVolReg (envy24ht_devc * devc, IN ULONG LineIdx)
+{
+ int iVol, ChnlVol;
+
+ ChnlVol = devc->m_DACVolume[LineIdx];
+
+ /* See if we want to mute anything */
+ if (devc->m_fDACMute[LineIdx] || devc->m_fDACMute[LINE_MASTER])
+ {
+ WriteWM8770 (devc, gWMRegister[LineIdx], 0x100);
+ return;
+ }
+
+ /* Since master volume is virtualized, we add the attenuations for both */
+ /* master volume and channel volume to obtain the overall attenuation */
+
+ /* Get total attenuation */
+ iVol = ChnlVol + devc->m_DACVolume[LINE_MASTER] - MAX_VOLUME;
+ /* Check against bounds */
+ iVol = (iVol < MAX_VOLUME) ? iVol : MAX_VOLUME;
+ if (iVol < MIN_VOLUME)
+ iVol = MIN_VOLUME;
+ WriteWM8770 (devc, gWMRegister[LineIdx], iVol | 0x180);
+}
+
+
+/*! \fn =======================================================================
+ Function : SetMute
+-------------------------------------------------------------------------------
+ Description :
+ Returns : VOID ->
+ Parameters : IN ULONG ChannelID ->
+ : IN BOOLEAN Mute ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void SetDACMute
+ (envy24ht_devc * devc, IN ULONG ChannelID, IN BOOLEAN Mute)
+{
+ ULONG LineIndex;
+
+ /* Convert ChannelID to line index */
+ /* If it is for left channel, we will need to add one */
+ LineIndex = ChannelID >> 15;
+
+ /* See if this is for master volume */
+ if (LineIndex == LINE_MASTER)
+ {
+ /* if current setting is not the same as previous setting */
+ if (devc->m_fDACMute[LINE_MASTER] != Mute)
+ {
+ int i;
+
+ devc->m_fDACMute[LINE_MASTER] = Mute;
+
+ /* Need to do it for every single line (excluding Master and Gain) */
+ for (i = 0; i <= LINE_OUT_4R; i++)
+ {
+ SetVolReg (devc, i);
+ }
+ return;
+ }
+ }
+
+ /* See if this is for left channel */
+ if (ChannelID & CH_LEFT)
+ {
+ /* if current setting is not the same as previous setting */
+ if (devc->m_fDACMute[LineIndex] != Mute)
+ {
+ devc->m_fDACMute[LineIndex] = Mute;
+ if (LineIndex == LINE_GAIN_L)
+ {
+ WriteWM8770 (devc, gWMRegister[LINE_GAIN_L],
+ devc->
+ m_DACVolume[LINE_GAIN_L] | ((Mute) ? 0x20 : 0x00));
+ }
+ else
+ {
+ SetVolReg (devc, LineIndex);
+ }
+ }
+ }
+
+ /* See if this is for right channel */
+ if (ChannelID & CH_RIGHT)
+ {
+ LineIndex++;
+ /* if current setting is not the same as previous setting */
+ if (devc->m_fDACMute[LineIndex] != Mute)
+ {
+ devc->m_fDACMute[LineIndex] = Mute;
+ if (LineIndex == LINE_GAIN_R)
+ {
+ WriteWM8770 (devc, gWMRegister[LINE_GAIN_R],
+ devc->
+ m_DACVolume[LINE_GAIN_R] | ((Mute) ? 0x20 : 0x00));
+ }
+ else
+ {
+ SetVolReg (devc, LineIndex);
+ }
+ }
+ }
+ /* m_pAdapter->SetDirty(); *//* TODO */
+}
+
+
+
+/*=============================================================================
+ Function : SetVolume
+-------------------------------------------------------------------------------
+ Description :
+ Returns : VOID ->
+ Parameters : IN ICE_HW_PARAM* HwParm ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void SetDACVolume
+ (envy24ht_devc * devc, IN ULONG ChannelID, IN UCHAR Volume)
+{
+ ULONG LineIndex;
+ WORD LeftRight;
+ BOOLEAN VolChnged = 0;
+
+ /* Convert ChannelID to line index */
+ LineIndex = ChannelID >> 15;
+ /* Get the left/right side */
+ LeftRight = (WORD) (ChannelID & 0xffff);
+
+ /* Check if left volume is changed */
+ if (LeftRight & CH_LEFT)
+ {
+ if (devc->m_DACVolume[LineIndex] != Volume)
+ {
+ devc->m_DACVolume[LineIndex] = Volume;
+ VolChnged = 1;
+ }
+ }
+
+ /* Check if right volume is changed */
+ if (LeftRight & CH_RIGHT)
+ {
+ if (devc->m_DACVolume[LineIndex + 1] != Volume)
+ {
+ devc->m_DACVolume[LineIndex + 1] = Volume;
+ VolChnged = 1;
+ }
+ }
+
+ /* If any volume is changed, need to touch hardware */
+ if (VolChnged)
+ {
+ /* check if this is for input gain */
+ if ((ChannelID >> 16) == IN_12)
+ {
+ USHORT WMValue = (USHORT) Volume;
+#ifdef NULL_DB
+ WMValue = 0x0C;
+#endif
+ if (LeftRight & CH_LEFT)
+ WriteWM8770 (devc, gWMRegister[LineIndex], WMValue);
+ if (LeftRight & CH_RIGHT)
+ WriteWM8770 (devc, gWMRegister[LineIndex + 1], WMValue);
+ }
+ else
+ /* Yap, now check if this is for master volume */
+ if ((ChannelID >> 16) == OUT_MASTER)
+ {
+ int i;
+ /* Need to do it for every single line (excluding Master and Gain) */
+ for (i = 0; i <= LINE_OUT_4R; i++)
+ {
+ SetVolReg (devc, i);
+ }
+ }
+ else
+ {
+ if (LeftRight & CH_LEFT)
+ SetVolReg (devc, LineIndex);
+ if (LeftRight & CH_RIGHT)
+ SetVolReg (devc, LineIndex + 1);
+ }
+ }
+ /* m_pAdapter->SetDirty(); TODO */
+}
+
+
+/*! \fn =======================================================================
+ Function : GetVolume
+-------------------------------------------------------------------------------
+ Description :
+ Returns : UCHAR ->
+ Parameters : IN ULONG ChannelID ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static UCHAR
+GetDACVolume (envy24ht_devc * devc, IN ULONG ChannelID)
+{
+ UCHAR Value;
+ USHORT LeftRight;
+ ULONG LineIndex;
+
+ /* Convert ChannelID to line index */
+ LineIndex = ChannelID >> 15;
+ /* Get the left/right side */
+ LeftRight = (USHORT) (ChannelID & 0xffff);
+
+ if (LeftRight == CH_LEFT)
+ {
+ Value = devc->m_DACVolume[LineIndex];
+ }
+ else
+ {
+ Value = devc->m_DACVolume[LineIndex + 1];
+ }
+ return Value;
+}
+
+
+#if 0
+/*! \fn =======================================================================
+ Function : GetMute
+-------------------------------------------------------------------------------
+ Description :
+ Returns : BOOLEAN ->
+ Parameters : IN ULONG ChannelID ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static BOOLEAN
+GetDACMute (envy24ht_devc * devc, IN ULONG ChannelID)
+{
+ BOOLEAN Value;
+ USHORT LeftRight;
+ ULONG LineIndex;
+
+ /* Convert ChannelID to line index */
+ LineIndex = ChannelID >> 15;
+ /* Get the left/right side */
+ LeftRight = (USHORT) (ChannelID & 0xffff);
+
+ if (LeftRight == CH_LEFT)
+ {
+ Value = devc->m_fDACMute[LineIndex];
+ }
+ else
+ {
+ Value = devc->m_fDACMute[LineIndex + 1];
+ }
+ return Value;
+}
+#endif
+
+/*! \fn =======================================================================
+ Function : SetADCGain
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN ULONG Index ->
+ : IN ULONG Value ->
+ : IN ULONG Channel ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void SetADCGain
+ (envy24ht_devc * devc, IN ULONG Index, IN USHORT Value, IN ULONG Channel)
+{
+ UCHAR WMReg = 0x19;
+ USHORT WMValue;
+
+ /* Set only selected Line */
+ if (Index != devc->m_ADCIndex)
+ return;
+
+ switch (Channel)
+ {
+ case CH_LEFT:
+ devc->m_ADCVolume[Index] =
+ (Value << 8) | (devc->m_ADCVolume[Index] & 0x00FF);
+ break;
+ case CH_BOTH:
+ devc->m_ADCVolume[Index] = (Value << 8) | Value;
+ break;
+ case CH_NOP:
+ /* Hold Value */
+ break;
+ case CH_RIGHT:
+ default:
+ devc->m_ADCVolume[Index] = Value | (devc->m_ADCVolume[Index] & 0xFF00);
+
+ }
+ WMValue =
+ ((devc->m_ADCVolume[Index] & 0x00FF) <
+ 0x1F) ? (devc->m_ADCVolume[Index] & 0x00FF) : 0x1F;
+#ifdef NULL_DB
+ WMValue = 0x0C;
+#endif
+ WriteWM8770 (devc, WMReg, WMValue);
+ WMValue = (((devc->m_ADCVolume[Index] >> 8) & 0x00FF) < 0x1F) ?
+ ((devc->m_ADCVolume[Index] >> 8) & 0x00FF) : 0x1F;
+#ifdef NULL_DB
+ WMValue = 0x0C;
+#endif
+ WriteWM8770 (devc, WMReg + 1, WMValue);
+ /* Force saving of registers */
+ /* devc->m_pAdapter->SetDirty(); TODO */
+}
+
+#if 0
+/*! \fn =======================================================================
+ Function : GetADCGain
+-------------------------------------------------------------------------------
+ Description :
+ Returns : UCHAR ->
+ Parameters : IN ULONG Index ->
+ : IN ULONG Channel ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static UCHAR GetADCGain
+ (envy24ht_devc * devc, IN ULONG Index, IN ULONG Channel)
+{
+ UCHAR Value;
+
+ if (Channel == CH_LEFT)
+ {
+ Value = (UCHAR) ((devc->m_ADCVolume[Index] >> 8) & 0xFF);
+ }
+ else
+ {
+ Value = (UCHAR) (devc->m_ADCVolume[Index] & 0xFF);
+ }
+ return Value;
+}
+#endif
+
+/*! \fn =======================================================================
+ Function : SetADCMux
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN Value ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetADCMux (envy24ht_devc * devc, IN ULONG Value)
+{
+ UCHAR MuxVal = 0;
+ BOOLEAN fAU;
+
+ /* Store to shadow register */
+ devc->m_ADCMux = Value;
+ devc->m_fSPDIFRecord = 0;
+ fAU = (devc->subvendor == SSID_AUREON_UNIVERSE);
+ switch (Value)
+ {
+ case CD_IN_MUX_TP_PIN:
+ devc->m_ADCIndex = ADC_CD;
+ MuxVal = (fAU) ? 0x11 : 0x00;
+ break;
+ case LINE_IN_MUX_TP_PIN:
+ devc->m_ADCIndex = ADC_LINE;
+ MuxVal = (fAU) ? 0x33 : 0x22;
+ break;
+ case AUX_IN_MUX_TP_PIN:
+ devc->m_ADCIndex = ADC_AUX;
+ MuxVal = (fAU) ? devc->m_AuxMux : 0x11;
+ break;
+ case MIC_IN_MUX_TP_PIN:
+ devc->m_ADCIndex = ADC_MIC;
+ MuxVal = (fAU) ? 0x55 : 0x33;
+ break;
+ case DIG_IN_MUX_TP_PIN:
+ /* Use SPDIF DMA channel */
+ devc->m_fSPDIFRecord = 1;
+ break;
+ case PHONO_IN_MUX_PIN:
+ devc->m_ADCIndex = ADC_PHONO;
+ MuxVal = 0x22;
+ break;
+ case STEREO_MIX_MUX_TP_PIN:
+ devc->m_ADCIndex = ADC_STEREO_MIX;
+ MuxVal = (fAU) ? 0x77 : 0x44;
+ break;
+
+ default:
+ devc->m_ADCIndex = ADC_LINE;
+ MuxVal = 0x22;
+
+ }
+ WriteWM8770 (devc, WM_ADC_INPUT_MX, (UCHAR) MuxVal);
+ /* Reset GAIN */
+ SetADCGain (devc, devc->m_ADCIndex, 0, CH_NOP);
+ /* Update PCA config */
+ WritePCA (devc);
+ /* Force saving of registers */
+ /*devc->m_pAdapter->SetDirty(); TODO */
+}
+
+/*! \fn =======================================================================
+ Function : InitWM8770
+-------------------------------------------------------------------------------
+ Description :
+-------------------------------------------------------------------------------
+ Notes : Call before Registry Read
+=============================================================================*/
+static void
+InitWM8770 (envy24ht_devc * devc)
+{
+ /*----------------------------------------------------------------------------
+ Reset WM8770
+ -----------------------------------------------------------------------------*/
+ /* Set SPI Mode */
+ WriteGPIO (devc, 0, GPIO_WM8770_RS_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, GPIO_WM8770_CS_MASK, GPIO_WM8770_CS_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, GPIO_WM8770_RS_MASK, GPIO_WM8770_RS_MASK);
+ oss_udelay (100);
+
+ /*----------------------------------------------------------------------------
+ Set defaults
+ -----------------------------------------------------------------------------*/
+
+ /* Output defaults */
+ SetDACVolume (devc, CH_MASTER_BOTH, WM_OUT_DEFAULT);
+ SetDACVolume (devc, CH_FRONT_BOTH, WM_OUT_DEFAULT);
+ SetDACVolume (devc, CH_REAR_BOTH, WM_OUT_DEFAULT);
+ SetDACVolume (devc, CH_CENTER, WM_OUT_DEFAULT);
+ SetDACVolume (devc, CH_LFE, WM_OUT_DEFAULT);
+ SetDACVolume (devc, CH_BS_BOTH, WM_OUT_DEFAULT);
+ SetDACMute (devc, CH_MASTER_BOTH, 0);
+ SetDACMute (devc, CH_FRONT_BOTH, 0);
+ SetDACMute (devc, CH_REAR_BOTH, 0);
+ SetDACMute (devc, CH_CENTER, 0);
+ SetDACMute (devc, CH_LFE, 0);
+ SetDACMute (devc, CH_BS_BOTH, 0);
+ /* Input */
+ SetADCGain (devc, ADC_CD, WM_INP_DEFAULT, CH_BOTH);
+ SetADCGain (devc, ADC_AUX, WM_INP_DEFAULT, CH_BOTH);
+ SetADCGain (devc, ADC_LINE, WM_INP_DEFAULT, CH_BOTH);
+ SetADCGain (devc, ADC_MIC, WM_INP_DEFAULT, CH_BOTH);
+ /* Mux */
+ SetADCMux (devc, STEREO_MIX_MUX_TP_PIN);
+
+ /* At least Power DAC & ADC */
+ WriteWM8770 (devc, WM_POWER_CNTRL, 0x0000);
+ /* Power ADC Input Mux */
+ WriteWM8770 (devc, WM_ADC_INPUT_MX, 0x0000);
+ /* Enable Aux-Output */
+
+ if (devc->subvendor == SSID_PHASE28)
+ {
+ WriteWM8770 (devc, WM_OUT12_SELECT, 0x0009);
+ WriteWM8770 (devc, WM_OUT34_SELECT, 0x0009);
+ }
+ else
+ {
+ WriteWM8770 (devc, WM_OUT12_SELECT, 0x000b);
+ WriteWM8770 (devc, WM_OUT34_SELECT, 0x0009);
+ }
+ /* Init Master Mode Register */
+ WriteWM8770 (devc, WM_MASTER_MODE_CNTRL, 0x0012);
+
+}
+
+/*! \fn =======================================================================
+ Function : InitCS8415
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+-------------------------------------------------------------------------------
+ Notes : Has to be called after InitWM8770 since RST must be "high"
+=============================================================================*/
+static void
+InitCS8415 (envy24ht_devc * devc)
+{
+
+ /* Init Remote-Controller */
+ if (devc->subvendor == SSID_AUREON_UNIVERSE)
+ {
+ UCHAR bByte[2];
+ bByte[0] = (UCHAR) ((AUREON_REMOTE_ID >> 8) & 0xFF);
+ bByte[1] = (UCHAR) AUREON_REMOTE_ID;
+ IICWriteBuffer (devc, AUREON_REMOTE_CNTRL, bByte, 2, 200);
+ }
+ /*----------------------------------------------------------------------------
+ Reset CS8415
+ -----------------------------------------------------------------------------*/
+ /* Set SPI Mode */
+ WriteGPIO (devc, GPIO_CS8415_CS_MASK, GPIO_CS8415_CS_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, 0, GPIO_CS8415_CS_MASK);
+ oss_udelay (100);
+
+ /* Set defaults */
+ WriteCS8415 (devc, CS_CONTROL_1, 0x80);
+ /* SPDIF mux to RXP1 */
+ WriteCS8415 (devc, CS_CONTROL_2, 0x01);
+ WriteCS8415 (devc, CS_CLK_SRC_CNTRL, 0x41);
+ WriteCS8415 (devc, CS_SER_OUT_FORMAT, 0x05);
+
+ /* all other register remain to their defaults */
+
+}
+
+#define GPIO_WAIT 10
+
+/*! \fn =======================================================================
+ Function : WriteAC97Codec
+-------------------------------------------------------------------------------
+ Description : Writes to TT-AC97 Interface
+ Parameters : IN ULONG Register ->
+ : IN ULONG Data ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void WriteAC97Codec
+ (envy24ht_devc * devc, IN ULONG Register, IN ULONG Data)
+{
+ UCHAR TTData;
+
+#ifdef TTTT
+ /* CL_TEST */
+ /* Reset AC97 */
+ WriteGPIO (devc, GPIO_AC97_RESET_MASK, GPIO_AC97_RESET_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, 0, GPIO_AC97_RESET_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, GPIO_AC97_RESET_MASK, GPIO_AC97_RESET_MASK);
+ oss_udelay (3);
+ /* Unmute Master */
+ WriteAC97Codec (devc, 0x02, 0x00);
+#endif
+
+ /* m_pAdapter->HwEnter(); TODO */
+
+ oss_udelay (GPIO_WAIT);
+
+ /* Reset all LD Pins and GO Pin */
+ WriteGPIO (devc, 0,
+ GPIO_LD_DATA_H_MASK | GPIO_LD_DATA_L_MASK | GPIO_LD_ADR_MASK |
+ GPIO_GO_MASK);
+
+
+ /* apply address to TT-AC97 Interface */
+ WriteGPIO (devc, Register, GPIO_DATA_ADR_MASK);
+
+ /* Set "Load Address" Pin */
+ oss_udelay (GPIO_WAIT);
+ WriteGPIO (devc, GPIO_LD_ADR_MASK, GPIO_LD_ADR_MASK);
+
+ /* Reset "Load Address" Pin */
+ oss_udelay (GPIO_WAIT);
+ WriteGPIO (devc, 0, GPIO_LD_ADR_MASK);
+
+ /* apply data low to TT-AC97 Interface */
+ oss_udelay (GPIO_WAIT);
+ TTData = (UCHAR) (Data & 0x000000FF);
+ WriteGPIO (devc, TTData, GPIO_DATA_ADR_MASK);
+
+ /* Set "Load Data low" Pin */
+ oss_udelay (GPIO_WAIT);
+ WriteGPIO (devc, GPIO_LD_DATA_L_MASK, GPIO_LD_DATA_L_MASK);
+
+ /* Reset "Load Data low" Pin */
+ oss_udelay (GPIO_WAIT);
+ WriteGPIO (devc, 0, GPIO_LD_DATA_L_MASK);
+
+ /* apply data high to TT-AC97 Interface */
+ oss_udelay (GPIO_WAIT);
+ TTData = (UCHAR) ((Data >> 8) & 0x000000FF);
+ WriteGPIO (devc, TTData, GPIO_DATA_ADR_MASK);
+
+ /* Set "Load Data high" Pin */
+ oss_udelay (GPIO_WAIT);
+ WriteGPIO (devc, GPIO_LD_DATA_H_MASK, GPIO_LD_DATA_H_MASK);
+
+ /* Reset "Load Data high" Pin */
+ oss_udelay (GPIO_WAIT);
+ WriteGPIO (devc, 0, GPIO_LD_DATA_H_MASK);
+
+ /* Set and immediately reset "GO" Pin */
+ oss_udelay (GPIO_WAIT);
+ WriteGPIO (devc, GPIO_GO_MASK, GPIO_GO_MASK);
+ WriteGPIO (devc, 0, GPIO_GO_MASK);
+ /* m_pAdapter->HwLeave(); *//* TODO */
+
+}
+
+/*! \fn =======================================================================
+ Function : SetAC97Volume
+-------------------------------------------------------------------------------
+ Description :
+ Parameters : IN ULONG Index ->
+ : IN UHSORT Value ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void SetAC97Volume
+ (envy24ht_devc * devc, IN ULONG Index, IN USHORT left, IN USHORT right)
+{
+ int AC97Reg = 0, value;
+
+ devc->m_AC97Volume[Index] = left | (right << 8);
+
+ left = AC97_INP_MAX - left;
+ right = AC97_INP_MAX - right;
+
+ value = (left << 8) | right;
+
+ switch (devc->subvendor)
+ {
+ case SSID_AUREON_SKY:
+ case SSID_PRODIGY71:
+ case SSID_AUREON_SPACE:
+ switch (Index)
+ {
+ case AC97_MIC:
+ AC97Reg = AC97_IDXREG_MIC_IN;
+ break;
+ case AC97_LINE:
+ AC97Reg = AC97_IDXREG_LINE_IN;
+ break;
+ case AC97_CD:
+ AC97Reg = AC97_IDXREG_CD_IN;
+ break;
+ case AC97_AUX:
+ AC97Reg = AC97_IDXREG_AUX_IN;
+ break;
+ default:
+ cmn_err (CE_CONT, "Aureon: Bad index %d\n", Index);
+ return;
+ }
+ break;
+ case SSID_AUREON_UNIVERSE:
+ switch (Index)
+ {
+ case AC97_MIC:
+ AC97Reg = AC97_IDXREG_MIC_IN;
+ break;
+ case AC97_LINE:
+ AC97Reg = AC97_IDXREG_LINE_IN;
+ break;
+ case AC97_CD:
+ AC97Reg = AC97_IDXREG_AUX_IN;
+ break;
+ case AC97_PHONO:
+ AC97Reg = AC97_IDXREG_CD_IN;
+ break;
+ case AC97_AUX:
+ case AC97_LINE2:
+ AC97Reg = AC97_IDXREG_VIDEO_IN;
+ break;
+ default:
+ cmn_err (CE_CONT, "Aureon: Bad index %d\n", Index);
+ return;
+
+ }
+ break;
+ }
+ if (!devc->m_fAC97Mute[Index])
+ {
+ WriteAC97Codec (devc, AC97Reg, value);
+ }
+ /* Force saving of registers */
+ /* m_pAdapter->SetDirty(); TODO */
+}
+
+
+/*! \fn =======================================================================
+ Function : GetAC97Volume
+-------------------------------------------------------------------------------
+ Description :
+ Returns : UCHAR ->
+ Parameters : IN ULONG Index ->
+ : IN ULONG Channel ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static USHORT
+GetAC97Volume (envy24ht_devc * devc, IN ULONG Index)
+{
+ return devc->m_AC97Volume[Index];
+}
+
+/*! \fn =======================================================================
+ Function : SetAC97Mute
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+ Parameters : IN ULONG Index ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetAC97Mute (envy24ht_devc * devc, IN ULONG Index, BOOLEAN OnOff)
+{
+ UCHAR AC97Reg = 0;
+ devc->m_fAC97Mute[Index] = OnOff;
+ switch (devc->subvendor)
+ {
+ case SSID_AUREON_SKY:
+ case SSID_PRODIGY71:
+ case SSID_AUREON_SPACE:
+ switch (Index)
+ {
+ case AC97_MIC:
+ AC97Reg = AC97_IDXREG_MIC_IN;
+ break;
+ case AC97_LINE:
+ AC97Reg = AC97_IDXREG_LINE_IN;
+ break;
+ case AC97_CD:
+ AC97Reg = AC97_IDXREG_CD_IN;
+ break;
+ case AC97_AUX:
+ AC97Reg = AC97_IDXREG_AUX_IN;
+ break;
+ default:
+ cmn_err (CE_CONT, "Aureon: Bad index %d\n", Index);
+ return;
+ }
+ break;
+ case SSID_AUREON_UNIVERSE:
+ switch (Index)
+ {
+ case AC97_MIC:
+ AC97Reg = AC97_IDXREG_MIC_IN;
+ break;
+ case AC97_LINE:
+ AC97Reg = AC97_IDXREG_LINE_IN;
+ break;
+ case AC97_CD:
+ AC97Reg = AC97_IDXREG_AUX_IN;
+ break;
+ case AC97_PHONO:
+ AC97Reg = AC97_IDXREG_CD_IN;
+ break;
+ case AC97_AUX:
+ case AC97_LINE2:
+ AC97Reg = AC97_IDXREG_VIDEO_IN;
+ break;
+ default:
+ cmn_err (CE_CONT, "Aureon: Bad index %d\n", Index);
+ return;
+ }
+ break;
+ }
+#ifdef AC97_MUTE
+ WriteAC97Codec (devc, AC97Reg, 0x8000);
+#else
+ WriteAC97Codec (devc, AC97Reg,
+ (OnOff) ? 0x8000 : devc->m_AC97Volume[Index]);
+#endif
+
+ /* Force saving of registers */
+ /* m_pAdapter->SetDirty(); *//* TODO */
+}
+
+/*! \fn =======================================================================
+ Function : InitAC97
+-------------------------------------------------------------------------------
+ Description :
+ Returns : void ->
+-------------------------------------------------------------------------------
+ Notes : Call before Registry Read
+=============================================================================*/
+static void
+InitAC97 (envy24ht_devc * devc)
+{
+ /* Reset AC97 */
+ oss_udelay (30);
+ WriteGPIO (devc, GPIO_AC97_RESET_MASK, GPIO_AC97_RESET_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, 0, GPIO_AC97_RESET_MASK);
+ oss_udelay (3);
+ WriteGPIO (devc, GPIO_AC97_RESET_MASK, GPIO_AC97_RESET_MASK);
+ oss_udelay (3);
+
+ /* Unmute Master */
+ WriteAC97Codec (devc, 0x02, 0x00);
+
+ /*----------------------------------------------------------------------------
+ Set defaults
+ -----------------------------------------------------------------------------*/
+ /* Volume */
+ SetAC97Volume (devc, AC97_MIC, AC97_INP_DEFAULT, AC97_INP_DEFAULT);
+ SetAC97Volume (devc, AC97_LINE, AC97_INP_DEFAULT, AC97_INP_DEFAULT);
+ SetAC97Volume (devc, AC97_AUX, AC97_INP_DEFAULT, AC97_INP_DEFAULT);
+ SetAC97Volume (devc, AC97_CD, AC97_INP_DEFAULT, AC97_INP_DEFAULT);
+ /* Mute */
+ SetAC97Mute (devc, AC97_MIC, 0);
+ SetAC97Mute (devc, AC97_LINE, 0);
+ SetAC97Mute (devc, AC97_AUX, 0);
+ SetAC97Mute (devc, AC97_CD, 0);
+}
+
+/*! \fn =======================================================================
+ Function : SetSampleRate
+-------------------------------------------------------------------------------
+ Description :
+ Returns : NTSTATUS ->
+ Parameters : IN ULONG SampleRate ->
+-------------------------------------------------------------------------------
+ Notes :
+=============================================================================*/
+static void
+SetSampleRate (envy24ht_devc * devc, IN ULONG SampleRate)
+{
+ WriteWM8770 (devc, WM_MASTER_MODE_CNTRL, 0x0012);
+
+ switch (SampleRate)
+ {
+ case 48000:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_48KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ /* WRITE_PORT_UCHAR(WKNMTBase + MT_DATA_FORMAT_REG,(~MT_128X)&READ_PORT_UCHAR(WKNMTBase + MT_DATA_FORMAT_REG)); */
+ break;
+ case 24000:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_24KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 12000:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_12KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 9600:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_9p6KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 32000:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_32KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 16000:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_16KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 8000:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_8KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 96000:
+ WriteWM8770 (devc, WM_MASTER_MODE_CNTRL, 0x001A);
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_96KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 192000:
+ WriteWM8770 (devc, WM_MASTER_MODE_CNTRL, 0x001A);
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_192KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_ON);
+ break;
+ case 64000:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_64KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 44100:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_44p1KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 22050:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_22p05KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 11025:
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_11p025KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 88200:
+ WriteWM8770 (devc, WM_MASTER_MODE_CNTRL, 0x001A);
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_88p2KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ case 176400:
+ WriteWM8770 (devc, WM_MASTER_MODE_CNTRL, 0x001A);
+ WritePort (devc, REG_MT, MT_SAMPLE_RATE_REG, MT_176p4KHZ, WIDTH_BYTE);
+ ReadModifyWritePort (devc, REG_MT, MT_DATA_FORMAT_REG, MT_128X,
+ WIDTH_BYTE | BITS_OFF);
+ break;
+ default:
+ break;
+
+ }
+}
+
+static void
+aureon_card_init (envy24ht_devc * devc)
+{
+
+/* Do not change the order of the following lines */
+ Init1724 (devc);
+ ResetGPIO (devc);
+
+ if (devc->subvendor != SSID_PHASE28)
+ InitAC97 (devc);
+ InitWM8770 (devc);
+ InitCS8415 (devc);
+/* Do not change the order of the above lines */
+
+ SetSPDIFConfig (devc, 0);
+ /* SetSDPIFSource(devc, DIGOUT_WAVE); */
+ SetDigInSource (devc, DIGIN_COAX);
+ SetFrontjack (devc, FRONT_JACK_HEADPHONE);
+ SetLineSource (devc, SRC_LINE_REAR);
+ SetClockSource (devc, ICE_INTERNAL_CLOCK);
+
+}
+
+static void
+aureon_set_rate (envy24ht_devc * devc)
+{
+ SetSampleRate (devc, devc->speed);
+}
+
+static int
+aureon_set_ctl (int dev, int ctl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ switch (ctl)
+ {
+ case 1:
+ return devc->m_LineInSource;
+ case 3:
+ return devc->m_DigInSource;
+ case 4:
+ return devc->m_Frontjack;
+ }
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ switch (ctl)
+ {
+ case 1:
+ SetLineSource (devc, value);
+ return devc->m_LineInSource;
+ case 3:
+ SetDigInSource (devc, value);
+ return devc->m_DigInSource;
+ case 4:
+ SetFrontjack (devc, value);
+ return devc->m_Frontjack;
+ }
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+aureon_set_vol (int dev, int ChannelID, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->devc;
+ ULONG LineIndex;
+ WORD LeftRight;
+ int left, right;
+
+ /* Convert ChannelID to line index */
+ LineIndex = ChannelID >> 15;
+ /* Get the left/right side */
+ LeftRight = (WORD) (ChannelID & 0xffff);
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ left = right = 0;
+ if (LeftRight & CH_LEFT)
+ left = GetDACVolume (devc, (LineIndex << 15) | CH_LEFT);
+ if (LeftRight & CH_RIGHT)
+ right = GetDACVolume (devc, (LineIndex << 15) | CH_RIGHT);
+
+ if (left == 0)
+ left = right;
+ else if (right == 0)
+ right = left;
+
+ return left | (right << 8);
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ left = (value & 0xff);
+ right = ((value >> 8) & 0xff);
+
+ if (LeftRight != CH_BOTH)
+ right = left;
+
+ if (LeftRight & CH_LEFT)
+ SetDACVolume (devc, (LineIndex << 15) | CH_LEFT, left);
+
+ if (LeftRight & CH_RIGHT)
+ SetDACVolume (devc, (LineIndex << 15) | CH_RIGHT, right);
+
+ return left | (right << 8);
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+aureon_set_ac97 (int dev, int Index, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->devc;
+ int left, right;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ return GetAC97Volume (devc, Index);
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ left = (value & 0xff);
+ right = ((value >> 8) & 0xff);
+
+ SetAC97Volume (devc, Index, left, right);
+
+ return left | (right << 8);
+ }
+
+ return OSS_EINVAL;
+}
+
+ /*ARGSUSED*/ static int
+aureon_mixer_init_common (envy24ht_devc * devc, int dev, int root)
+{
+ int ctl, group;
+
+ if ((group = mixer_ext_create_group (dev, root, "VOL")) < 0)
+ return group;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ CH_MASTER_BOTH,
+ aureon_set_vol,
+ MIXT_STEREOSLIDER, "MASTER",
+ WM_OUT_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ CH_FRONT_BOTH,
+ aureon_set_vol,
+ MIXT_STEREOSLIDER, "FRONT", WM_OUT_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ CH_REAR_BOTH,
+ aureon_set_vol,
+ MIXT_STEREOSLIDER, "SURROUND",
+ WM_OUT_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ CH_CENTER,
+ aureon_set_vol,
+ MIXT_MONOSLIDER, "CENTER", WM_OUT_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ CH_LFE,
+ aureon_set_vol,
+ MIXT_MONOSLIDER, "LFE", WM_OUT_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ CH_BS_BOTH,
+ aureon_set_vol,
+ MIXT_STEREOSLIDER, "REAR", WM_OUT_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((group =
+ mixer_ext_create_group_flags (dev, root, "TERRATEC", MIXF_FLAT)) < 0)
+ return group;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ 1,
+ aureon_set_ctl,
+ MIXT_ENUM, "LINESRC", 4,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+ mixer_ext_set_strings (dev, ctl, "AUX WTL REAR GROUND", 0);
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ 3,
+ aureon_set_ctl,
+ MIXT_ENUM, "DIGIN", 3,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+ mixer_ext_set_strings (dev, ctl, "OPTICAL COAX CD", 0);
+
+ return 0;
+}
+
+ /*ARGSUSED*/ static int
+aureon_mixer_init_universe (envy24ht_devc * devc, int dev, int group)
+{
+ int ctl;
+
+ if ((group = mixer_ext_create_group (dev, group, "ENVY24_UNIVERSE")) < 0)
+ return group;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ 4,
+ aureon_set_ctl,
+ MIXT_ENUM, "FRONTJACK", 3,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+ mixer_ext_set_strings (dev, ctl, "LINEIN HEADPH", 0);
+
+ return 0;
+}
+
+ /*ARGSUSED*/ static int
+aureon_mixer_init_ac97 (envy24ht_devc * devc, int dev, int group)
+{
+ int ctl;
+
+ if ((group = mixer_ext_create_group (dev, group, "ENVY24_AC97")) < 0)
+ return group;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ AC97_MIC,
+ aureon_set_ac97,
+ MIXT_STEREOSLIDER, "MIC", AC97_INP_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ AC97_LINE,
+ aureon_set_ac97,
+ MIXT_STEREOSLIDER, "LINE",
+ AC97_INP_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ AC97_CD,
+ aureon_set_ac97,
+ MIXT_STEREOSLIDER, "CD", AC97_INP_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ AC97_PHONO,
+ aureon_set_ac97,
+ MIXT_STEREOSLIDER, "PHONO",
+ AC97_INP_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ if ((ctl = mixer_ext_create_control (dev, group,
+ AC97_AUX,
+ aureon_set_ac97,
+ MIXT_STEREOSLIDER, "AUX", AC97_INP_MAX,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return ctl;
+
+ return 0;
+}
+
+static int
+aureon_mixer_init (envy24ht_devc * devc, int dev, int root)
+{
+ aureon_mixer_init_common (devc, dev, root);
+
+ if (devc->subvendor == SSID_AUREON_UNIVERSE)
+ aureon_mixer_init_universe (devc, dev, root);
+
+ if (devc->subvendor != SSID_PHASE28)
+ aureon_mixer_init_ac97 (devc, dev, root);
+ return 0;
+}
+
+envy24ht_auxdrv_t envy24ht_aureon_auxdrv = {
+ aureon_card_init,
+ aureon_mixer_init,
+ aureon_set_rate,
+ NULL,
+ NULL,
+ NULL, /* aureon_private1 */
+};
diff --git a/kernel/drv/oss_envy24ht/envy24ht_julia.c b/kernel/drv/oss_envy24ht/envy24ht_julia.c
new file mode 100644
index 0000000..544dd08
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht_julia.c
@@ -0,0 +1,547 @@
+/*
+ * Purpose: Low level routines for the ESI (Egosys) Juli@ card
+ */
+/*
+ *
+ * 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_envy24ht_cfg.h"
+
+#include "spdif.h"
+#include "envy24ht.h"
+
+#define AK4358_ADDRESS 0x11
+#define AK4114_ADDRESS 0x10
+
+static unsigned char
+i2c_read (envy24ht_devc * devc, unsigned char addr, unsigned char pos)
+{
+ int i;
+ unsigned char data;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ OUTB (devc->osdev, pos, devc->ccs_base + 0x11); /* Offset */
+ OUTB (devc->osdev, addr << 1, devc->ccs_base + 0x10); /* Read address */
+
+ for (i = 0; i < 2000; i++)
+ {
+ unsigned char status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+
+ oss_udelay (1);
+ data = INB (devc->osdev, devc->ccs_base + 0x12);
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+
+ return data;
+}
+
+static void
+i2c_write (envy24ht_devc * devc, unsigned char addr, unsigned char pos,
+ unsigned char data)
+{
+ int i;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+
+ for (i = 0; i < 2000; i++)
+ {
+ unsigned char status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+
+ OUTB (devc->osdev, pos, devc->ccs_base + 0x11); /* Offset */
+ OUTB (devc->osdev, data, devc->ccs_base + 0x12); /* Data */
+ OUTB (devc->osdev, (addr << 1) | 1, devc->ccs_base + 0x10); /* Write address */
+
+ for (i = 0; i < 2000; i++)
+ {
+ unsigned char status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+
+ if ((addr == AK4358_ADDRESS) && (pos <= 0x0c))
+ devc->m_DACVolume[pos] = data;
+}
+
+static void
+GPIOWrite (envy24ht_devc * devc, int pos, int bit)
+{
+ int data = INW (devc->osdev, devc->ccs_base + 0x14);
+
+ bit = (bit != 0);
+
+ data &= ~(1 << pos);
+ data |= (bit << pos);
+
+ OUTW (devc->osdev, data, devc->ccs_base + 0x14);
+}
+
+static int
+set_dac (envy24ht_devc * devc, int reg, int level)
+{
+ if (level < 0)
+ level = 0;
+ if (level > 0x7f)
+ level = 0x7f;
+
+ i2c_write (devc, AK4358_ADDRESS, reg, level | 0x80);
+
+ return level;
+}
+
+static struct {
+ int rate, spdifin, clks;
+} rate_sel[] = {
+ {32000, 0x30, 0x08},
+ {44100, 0x00, 0x09},
+ {48000, 0x20, 0x0A},
+ {88200, 0x80, 0x05},
+ {96000, 0xA0, 0x06},
+ {176400, 0xC0, 0x01},
+ {192000, 0xE0, 0x02},
+ {16000, -1, 0x0C},
+ {22050, -1, 0x0D},
+ {24000, -1, 0x0E},
+ {64000, -1, 0x04},
+ {128000, -1, 0x00},
+ {-1, -1, -1}
+};
+
+static void
+julia_set_deemph (envy24ht_devc * devc, int mode)
+{
+ int deemph = 0x01; /* OFF */
+
+ if (mode == 0)
+ i2c_write (devc, AK4358_ADDRESS, 0x03, deemph);
+ else {
+
+ if (devc->speed == 44100)
+ deemph = 0x00;
+ else if (devc->speed == 48000)
+ deemph = 0x02;
+ else if (devc->speed == 32000)
+ deemph = 0x03;
+
+ i2c_write (devc, AK4358_ADDRESS, 0x03, deemph);
+ }
+}
+
+static void
+julia_Monitor (envy24ht_devc * devc, int bMonitor, int num)
+{
+ switch (num)
+ {
+ case 0: /* MUTE */
+ if (bMonitor)
+ {
+ i2c_write (devc, AK4358_ADDRESS, 1, 0x03);
+ GPIOWrite (devc, 15, 1);
+ } else {
+ i2c_write (devc, AK4358_ADDRESS, 1, 0x01);
+ GPIOWrite (devc, 15, 0);
+ }
+ break;
+
+ case 1: /* LINEIN */
+ if (bMonitor)
+ GPIOWrite (devc, 13, 1);
+ else
+ GPIOWrite (devc, 13, 0);
+ break;
+
+ case 2: /* SPDIFOUT */
+ if (bMonitor)
+ GPIOWrite (devc, 11, 1);
+ else
+ GPIOWrite (devc, 11, 0);
+ break;
+ case 3: /* SPDIFIN */
+ if (bMonitor)
+ GPIOWrite (devc, 12, 1);
+ else
+ GPIOWrite (devc, 12, 0);
+ break;
+ case 4: /* De-emphasis */
+ julia_set_deemph (devc, bMonitor);
+ break;
+ }
+ devc->monitor[num] = bMonitor;
+}
+
+static void
+ak4114_init (envy24ht_devc * devc)
+{
+ /*
+ * AK4114 S/PDIF interface initialization
+ */
+ i2c_write (devc, AK4114_ADDRESS, 0x00, 0x0f);
+ i2c_write (devc, AK4114_ADDRESS, 0x01, 0x70);
+ i2c_write (devc, AK4114_ADDRESS, 0x02, 0x80);
+ i2c_write (devc, AK4114_ADDRESS, 0x03, 0x49);
+ i2c_write (devc, AK4114_ADDRESS, 0x04, 0x00);
+ i2c_write (devc, AK4114_ADDRESS, 0x05, 0x00);
+
+ i2c_write (devc, AK4114_ADDRESS, 0x0d, 0x41);
+ i2c_write (devc, AK4114_ADDRESS, 0x0e, 0x02);
+ i2c_write (devc, AK4114_ADDRESS, 0x0f, 0x2c);
+ i2c_write (devc, AK4114_ADDRESS, 0x10, 0x00);
+ i2c_write (devc, AK4114_ADDRESS, 0x11, 0x00);
+}
+
+static void
+julia_set_rate (envy24ht_devc * devc)
+{
+ int i, data;
+ int adc = 0x00;
+
+ if (devc->speed <= 48000)
+ devc->m_DACVolume[2] = 0x4f; /* DFS=normal-speed */
+ else if (devc->speed <= 96000)
+ {
+ adc = 0x04;
+ devc->m_DACVolume[2] = 0x5f; /* DFS=double-speed */
+ }
+ else
+ {
+ adc = 0x03;
+ devc->m_DACVolume[2] = 0x6f; /* DFS=quad-speed */
+ }
+
+ data = INW (devc->osdev, devc->ccs_base + 0x14);
+ data &= ~0x70f;
+ data |= adc << 8;
+
+ for (i = 0; rate_sel[i].rate; i++)
+ if (rate_sel[i].rate == devc->speed)
+ data |= rate_sel[i].clks;
+
+ OUTW (devc->osdev, data, devc->ccs_base + 0x14);
+
+ OUTB (devc->osdev, 0x80, devc->mt_base + 0x05); /* RESET */
+ OUTB (devc->osdev, 0x00, devc->mt_base + 0x05);
+
+ if (devc->speed == 8000)
+ OUTB (devc->osdev, 0x06, devc->mt_base + 0x01);
+ else if (devc->speed == 9600)
+ OUTB (devc->osdev, 0x03, devc->mt_base + 0x01);
+ else if (devc->speed == 11025)
+ OUTB (devc->osdev, 0x0a, devc->mt_base + 0x01);
+ else if (devc->speed == 12000)
+ OUTB (devc->osdev, 0x02, devc->mt_base + 0x01);
+ else
+ OUTB (devc->osdev, 0x10, devc->mt_base + 0x01);
+
+ /* Restore ak4358 regs and set DFS */
+ for (i = 0; i <= 0x0c; i++)
+ i2c_write (devc, AK4358_ADDRESS, i, devc->m_DACVolume[i]);
+ /* Restore ak4114 */
+ ak4114_init (devc);
+ if (devc->monitor[4] == 1)
+ julia_set_deemph (devc, 1);
+}
+
+static void
+julia_sync_ak4114 (void *arg)
+{
+ envy24ht_devc *devc = arg;
+ int i;
+ int spdifin = i2c_read (devc, AK4114_ADDRESS, 7);
+
+ for (i = 0; rate_sel[i].rate; i++)
+ if (rate_sel[i].spdifin == spdifin)
+ {
+ if (devc->speed != rate_sel[i].rate)
+ {
+ devc->speed = rate_sel[i].rate;
+ mixer_devs[devc->mixer_dev]->modify_counter++;
+ julia_set_rate (devc);
+ }
+ break;
+ }
+
+ if (devc->syncsource == 1)
+ devc->timeout_id = timeout (julia_sync_ak4114, devc, OSS_HZ);
+}
+
+static int
+julia_set_syncsource (envy24ht_devc * devc, int value)
+{
+ if (value == 1)
+ {
+ GPIOWrite (devc, 4, 0);
+ devc->timeout_id = timeout (julia_sync_ak4114, devc, OSS_HZ);
+ } else {
+ if (devc->timeout_id != 0)
+ untimeout (devc->timeout_id);
+ devc->timeout_id = 0;
+
+ GPIOWrite (devc, 4, 1);
+
+ if (devc->speed != devc->pending_speed)
+ {
+ devc->speed = devc->pending_speed;
+ mixer_devs[devc->mixer_dev]->modify_counter++;
+ julia_set_rate (devc);
+ }
+ }
+
+ return 0;
+}
+
+static int
+julia_audio_ioctl (envy24ht_devc * devc, envy24ht_portc * portc, unsigned int cmd,
+ ioctl_arg arg)
+{
+ int left, right, value;
+
+ switch (cmd)
+ {
+ case SNDCTL_DSP_GETPLAYVOL:
+ if (portc != &devc->play_portc[0])
+ return OSS_EINVAL;
+ left = (devc->gains[0] & 0xff) * 100 / 0x7f;
+ right = ((devc->gains[0] >> 8) & 0xff) * 100 / 0x7f;
+ return *arg = (left | (right << 8));
+ break;
+
+ case SNDCTL_DSP_SETPLAYVOL:
+ if (portc != &devc->play_portc[0])
+ return OSS_EINVAL;
+ value = *arg;
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ left = (left * 0x7f) / 100;
+ right = (right * 0x7f) / 100;
+ left = set_dac (devc, 0x04, left);
+ right = set_dac (devc, 0x05, right);
+ devc->gains[0] = left | (right << 8);
+ mixer_devs[devc->mixer_dev]->modify_counter++;
+ return 0;
+ break;
+ }
+ return OSS_EINVAL;
+}
+
+static int
+julia_set_control (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ if (ctrl < 0 || ctrl > 4)
+ return OSS_EINVAL;
+
+ return devc->monitor[ctrl];
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ if (ctrl < 0 || ctrl > 4)
+ return OSS_EINVAL;
+
+ value = !!value;
+ julia_Monitor (devc, value, ctrl);
+ return devc->monitor[ctrl];
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+julia_set_ak4358 (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ if (ctrl < 0 || ctrl > 4)
+ return OSS_EIO;
+
+ return devc->gains[ctrl];
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ int left, right;
+
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ switch (ctrl)
+ {
+ case 0: /* PCM */
+ left = set_dac (devc, 0x04, left);
+ right = set_dac (devc, 0x05, right);
+ break;
+ case 1: /* LINEIN */
+ left = set_dac (devc, 0x06, left);
+ right = set_dac (devc, 0x07, right);
+ break;
+ case 2: /* SPDIFOUT */
+ left = set_dac (devc, 0x08, left);
+ right = set_dac (devc, 0x09, right);
+ break;
+ case 3: /* SPDIFIN */
+ left = set_dac (devc, 0x0B, left);
+ right = set_dac (devc, 0x0C, right);
+ break;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ value = left | (right << 8);
+ return devc->gains[ctrl] = value;
+ }
+
+ return OSS_EINVAL;
+}
+
+ /*ARGSUSED*/ static int
+julia_mixer_init (envy24ht_devc * devc, int dev, int g)
+{
+ int group = g;
+ int err, monitor;
+
+ if ((group = mixer_ext_create_group (dev, g, "VOL")) < 0)
+ return group;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, julia_set_control,
+ MIXT_ONOFF,
+ "ENVY24_MUTE", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, julia_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_PCM", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, julia_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_LINEIN", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, julia_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_SPDIFOUT", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 3, julia_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_SPDIFIN", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((monitor = mixer_ext_create_group (dev, g, "MONITOR")) < 0)
+ return monitor;
+
+ if ((err = mixer_ext_create_control (dev, monitor,
+ 1, julia_set_control,
+ MIXT_ONOFF,
+ "ENVY24_LINEIN", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, monitor,
+ 2, julia_set_control,
+ MIXT_ONOFF,
+ "ENVY24_SPDIFOUT", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, monitor,
+ 3, julia_set_control,
+ MIXT_ONOFF,
+ "ENVY24_SPDIFIN", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, monitor,
+ 4, julia_set_control,
+ MIXT_ENUM,
+ "ENVY24_DEEMPH", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ mixer_ext_set_strings (dev, err, "OFF 50/15usec", 0);
+
+ return 0;
+}
+
+static void
+julia_card_init (envy24ht_devc * devc)
+{
+ ak4114_init (devc);
+/*
+ * AK4358 DAC initialization
+ */
+ i2c_write (devc, AK4358_ADDRESS, 2, 0x00);
+ i2c_write (devc, AK4358_ADDRESS, 2, 0x4E);
+ i2c_write (devc, AK4358_ADDRESS, 0, 0x06);
+ i2c_write (devc, AK4358_ADDRESS, 1, 0x02);
+ i2c_write (devc, AK4358_ADDRESS, 3, 0x01);
+
+ set_dac (devc, 0x04, 0x7f);
+ set_dac (devc, 0x05, 0x7f);
+ set_dac (devc, 0x06, 0x7f);
+ set_dac (devc, 0x07, 0x7f);
+ set_dac (devc, 0x08, 0x7f);
+ set_dac (devc, 0x09, 0x7f);
+ set_dac (devc, 0x0b, 0x7f);
+ set_dac (devc, 0x0c, 0x7f);
+
+ i2c_write (devc, AK4358_ADDRESS, 0xA, 0x00);
+ i2c_write (devc, AK4358_ADDRESS, 0xD, 0x00);
+ i2c_write (devc, AK4358_ADDRESS, 0xE, 0x00);
+ i2c_write (devc, AK4358_ADDRESS, 0xF, 0x00);
+ i2c_write (devc, AK4358_ADDRESS, 2, 0x4F);
+
+ julia_Monitor (devc, 0, 0); /* Unmute */
+}
+
+static void
+julia_card_uninit (envy24ht_devc * devc)
+{
+ if (devc->timeout_id != 0)
+ untimeout (devc->timeout_id);
+}
+
+envy24ht_auxdrv_t envy24ht_julia_auxdrv = {
+ julia_card_init,
+ julia_mixer_init,
+ julia_set_rate,
+ NULL,
+ NULL,
+ julia_set_syncsource,
+ julia_audio_ioctl,
+ julia_card_uninit
+};
diff --git a/kernel/drv/oss_envy24ht/envy24ht_revo51.c b/kernel/drv/oss_envy24ht/envy24ht_revo51.c
new file mode 100644
index 0000000..e84cb6a
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht_revo51.c
@@ -0,0 +1,938 @@
+/*
+ * Purpose: Low level routines for M Audio Revolution 5.1
+ */
+/*
+ *
+ * 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_envy24ht_cfg.h"
+
+#include "spdif.h"
+#include "envy24ht.h"
+
+static char channel_names[4][10] = {
+ "front",
+ "c/l",
+ "surround",
+ "headph"
+};
+
+#define BIT(x) (1<<(x))
+#define BIT3 BIT(3)
+
+/*----- SPI bus for CODEC communication. */
+/* */
+#define SPI_CLK 1 /* Clock output to CODEC's, rising edge clocks data. */
+#define SPI_DOUT 3 /* Data output to the CODEC. */
+#define SPI_CS0n (1<<4) /* Selects first chip. */
+#define SPI_CS1n (1<<5) /* Selects second chip. */
+#define SPI_CC_AK4358 0x02 /* C1:C0 for ak4358. */
+#define SPI_CC_AK5365 0x02 /* C1:C0 for ak5365. */
+#define WRITEMASK 0xffff
+/*----- Revolution defines. */
+/* */
+#define REVO51_AK5365 (1) /* iDevice value for AK5365 A/D. */
+#define REVO51_AK4358 (2) /* iDevice value for AK4358 D/A. */
+
+static unsigned int
+GpioReadAll (envy24ht_devc * devc)
+{
+ return INW (devc->osdev, devc->ccs_base + 0x14);
+}
+
+static void
+GpioWriteAll (envy24ht_devc * devc, unsigned int data)
+{
+ OUTW (devc->osdev, 0xffff, devc->ccs_base + 0x18); /* GPIO direction */
+ OUTW (devc->osdev, 0x0000, devc->ccs_base + 0x16); /* GPIO write mask */
+
+ OUTW (devc->osdev, data, devc->ccs_base + 0x14);
+}
+
+static void
+GpioWrite (envy24ht_devc * devc, int pos, int bit)
+{
+ int data = GpioReadAll (devc);
+
+ bit = (bit != 0);
+
+ data &= ~(1 << pos);
+ data |= (bit << pos);
+
+ GpioWriteAll (devc, data);
+}
+
+void
+REVO51_Assert_CS (envy24ht_devc * devc, int iDevice)
+/*
+*****************************************************************************
+* Assert chip select to specified GPIO-connected device.
+* iDevice: REVO51_AK5365=ADC, REVO51_AK4358=DAC.
+****************************************************************************/
+{
+ unsigned int dwGPIO; /* Current GPIO's. */
+ dwGPIO = GpioReadAll (devc); /* Read current GPIO's. */
+ dwGPIO |= (SPI_CS0n | SPI_CS1n); /* Reset CS bits. */
+ switch (iDevice) /* Select CS#. */
+ {
+ case REVO51_AK4358:
+ dwGPIO &= ~SPI_CS0n;
+ break; /* DAC */
+ case REVO51_AK5365:
+ dwGPIO &= ~SPI_CS1n;
+ break; /* ADC */
+ default:
+ break;
+ }
+ GpioWriteAll (devc, dwGPIO); /* Write hardware. */
+}
+
+void
+REVO51_DeAssert_CS (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* De-Assert all chip selects.
+****************************************************************************/
+{
+ unsigned int dwGPIO = GpioReadAll (devc); /* Current GPIO's. */
+ dwGPIO |= (SPI_CS0n | SPI_CS1n); /* Clear CS bits. */
+ GpioWriteAll (devc, dwGPIO); /* Write back to hardware. */
+}
+
+/*#define _delay() oss_udelay(1) */
+#define _delay() {}
+
+void
+REVO51_WriteSpiAddr (envy24ht_devc * devc, int iDevice, unsigned char bReg)
+/*
+*****************************************************************************
+* Write the address byte part of the SPI serial stream.
+* iDevice: REVO51_AK4358=DAC, REVO51_AK5365=ADC, etc.
+****************************************************************************/
+{
+ unsigned char bHdr;
+ unsigned char bNum;
+/* Built 8-bit packet header: C1,C0,R/W,A4,A3,A2,A1,A0. */
+/* */
+ switch (iDevice)
+ {
+ case REVO51_AK4358:
+ bHdr = SPI_CC_AK4358 << 6;
+ break;
+ case REVO51_AK5365:
+ bHdr = SPI_CC_AK5365 << 6;
+ break;
+ default:
+ bHdr = 0;
+ break;
+ }
+ bHdr = bHdr | 0x20 | (bReg & 0x1F); /* "write" + address. */
+/* Write header to SPI. */
+/* */
+ for (bNum = 0; bNum < 8; bNum++)
+ {
+ GpioWrite (devc, SPI_CLK, 0); /* Drop clock low. */
+ _delay ();
+ GpioWrite (devc, SPI_DOUT, 0x080 & bHdr); /* Write data bit. */
+ _delay ();
+ GpioWrite (devc, SPI_CLK, 1); /* Raise clock. */
+ _delay ();
+ bHdr <<= 1; /* Next bit. */
+ }
+}
+
+void
+REVO51_WriteSpiReg (envy24ht_devc * devc, int iDevice, unsigned char bReg,
+ unsigned char bData)
+/*
+*****************************************************************************
+* Writes one register in specified CHIP.
+* devc = PCI slot code of specific board.
+* iDevice: REVO51_AK4358=DAC, REVO51_AK5365=ADC, etc.
+****************************************************************************/
+{
+ unsigned char bNum;
+ GpioWrite (devc, SPI_DOUT, 0); /* Init SPI signals. */
+ GpioWrite (devc, SPI_CLK, 1); /* */
+/* Drop the chip select low. */
+/* Wait at least 150 nS. */
+/* */
+ REVO51_Assert_CS (devc, iDevice);
+ _delay ();
+/* Write the address byte. */
+/* */
+ REVO51_WriteSpiAddr (devc, iDevice, bReg);
+/* Write the data byte. */
+/* */
+ for (bNum = 0; bNum < 8; bNum++)
+ {
+ GpioWrite (devc, SPI_CLK, 0); /* Drop clock low. */
+ _delay ();
+ GpioWrite (devc, SPI_DOUT, 0x080 & bData); /* Write data bit. */
+ _delay ();
+ GpioWrite (devc, SPI_CLK, 1); /* Raise clock. */
+ _delay ();
+ bData <<= 1; /* Next bit. */
+ }
+/* De-assert chip selects. */
+/* */
+ REVO51_DeAssert_CS (devc);
+ _delay ();
+}
+
+
+#define GPIO_MUTEn 22 /* Converter mute signal. */
+void
+REVO51_Mute (envy24ht_devc * devc, int bMute)
+/*
+*****************************************************************************
+* Mutes all outputs if bMute=1.
+****************************************************************************/
+{
+ if (bMute)
+ {
+/* Soft-mute. Delay currently unspecified, try ½ second. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 1, 0x03);
+ _delay ();
+/* Switch mute transistors on. */
+ GpioWrite (devc, GPIO_MUTEn, 0);
+ }
+ else
+ {
+/* Switch mute transistors off. Delay currently unspecified, try ½ second. */
+ GpioWrite (devc, GPIO_MUTEn, 1);
+ _delay ();
+/* Release Soft-mute. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 1, 0x01);
+ }
+
+ devc->mute = bMute;
+}
+
+
+void
+REVO51_Set_OutAttn (envy24ht_devc * devc, unsigned char bChan, int iAttn)
+/*
+*****************************************************************************
+* Sets the attenuation on one output channel.
+* bChan = Channel number (0..7).
+* Channel 0:1 = front, 2:3 = center/sub, 4:5 = rear, 6:7 = headphones.
+* Registers are 0x04, 05, 06, 07, 08, 09, 0B, 0C respectively
+* iAttn = Number of steps to attenuate CODEC.
+* Each step equals .5dB (-127..0)
+****************************************************************************/
+{
+ unsigned char bIndex;
+ unsigned char bAttn;
+ if (bChan > 7 || iAttn > 0 || iAttn < -127) /* parameter test */
+ {
+ cmn_err (CE_CONT, "\ninvalid data! %d=bChan, %d=iAttn", bChan, iAttn);
+ return;
+ }
+ if (bChan < 6)
+ bIndex = 0x04 + bChan; /* for registers 0x04..0x09 */
+ else
+ bIndex = 0x05 + bChan; /* for registers 0x0B..0x0C */
+ bAttn = (0x80 + (unsigned char) (iAttn + 127)); /* 7F is max volume. */
+/* MSB enables attenuation. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, bIndex, bAttn);
+}
+
+static void
+ADC_Set_Chan (envy24ht_devc * devc, int iChan)
+/***************************************************************************
+* Makes input selection for ADC.
+* 0=mic, 1=line, 2=aux
+****************************************************************************/
+{
+/*Check param */
+ if (2 < iChan)
+#define GPIO_SDA 6 /* SDA pin */
+ cmn_err (CE_CONT, "\nInvalid Input channel parameter");
+ else
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 1, (unsigned char) iChan);
+}
+
+#define GPIO_SCL 7 /* SCL pin */
+static void
+start_bit (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* Send I2C Start Bit.
+****************************************************************************/
+{
+ GpioWrite (devc, GPIO_SDA, 1); /* Make sure DATA high. */
+ _delay ();
+ GpioWrite (devc, GPIO_SCL, 1); /* Set clock high. */
+ _delay ();
+ GpioWrite (devc, GPIO_SDA, 0); /* Falling edge indicates start bit. */
+ _delay ();
+ GpioWrite (devc, GPIO_SCL, 0); /* Start clock train. */
+}
+
+static void
+byte_out (envy24ht_devc * devc, unsigned char b8)
+/*
+*****************************************************************************
+* Send current 8 input bits in B8. Msb is first written.
+****************************************************************************/
+{
+ int bnum; /* bit number */
+ for (bnum = 7; bnum >= 0; bnum--)
+ {
+ GpioWrite (devc, GPIO_SDA, b8 & 0x80); /* Set bit. */
+ _delay (); /* */
+ GpioWrite (devc, GPIO_SCL, 1); /* Set clock high. */
+ _delay (); /* */
+ GpioWrite (devc, GPIO_SCL, 0); /* Return clock low. */
+ b8 = b8 << 1; /* Next position. */
+ }
+/* No ACK, but we need to clock a false "9th" bit. */
+ _delay (); /* */
+ GpioWrite (devc, GPIO_SCL, 1); /* Set clock high. */
+ _delay (); /* */
+ GpioWrite (devc, GPIO_SCL, 0); /* Return clock low. */
+}
+
+static void
+stop_bit (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* Send I2C Stop Bit.
+****************************************************************************/
+{
+ GpioWrite (devc, GPIO_SDA, 0); /* Make sure data is low. */
+ _delay ();
+ GpioWrite (devc, GPIO_SCL, 1); /* Set clock high. */
+ _delay ();
+ GpioWrite (devc, GPIO_SDA, 1); /* Rising edge indicates stop bit. */
+}
+static void
+PT2258S_Write_Data (envy24ht_devc * devc, int cnt, unsigned char *aData)
+/*
+************************************************************************ *****
+* Write an array of bytes (aData) to address VADDR in PT2258S.
+* Assumes I2C Bus is inactive, i.e., SCL=1,SDA=1 and both are outputs.
+* This routine waits for the byte to complete writing.
+************************************************************************ ****/
+{
+ int i;
+ start_bit (devc); /* Send start bit. */
+ byte_out (devc, (unsigned char) 0x80); /* Set address to write data to. */
+ for (i = 0; i < cnt; i++)
+ byte_out (devc, aData[i]); /* Write data to address. */
+ stop_bit (devc); /* Stop bit ends operation. */
+}
+static void
+PT2258S_Write_Byte (envy24ht_devc * devc, unsigned char vdata)
+/*
+*****************************************************************************
+* Write a byte VDATA to address VADDR in PT2258S.
+* Assumes I2C Bus is inactive, i.e., SCL=1,SDA=1 and both are outputs.
+* This routine waits for the byte to complete writing.
+****************************************************************************/
+{
+ start_bit (devc); /* Send start bit. */
+ byte_out (devc, (unsigned char) 0x80); /* Set address to write data to. */
+ byte_out (devc, vdata); /* Write data to address. */
+ stop_bit (devc); /* Stop bit ends operation. */
+}
+
+static void
+PT2258S_Set_Attn (envy24ht_devc * devc, unsigned char bChan, int iAttn)
+/*
+************************************************************************ *****
+* Set the attenuation of a specific channel.
+* bChan = 0..5.
+* iAttn = 0..-79.
+************************************************************************ ****/
+{
+ static unsigned char bXlat[] = { 0x90, 0x50, 0x10, 0x30, 0x70, 0xB0 };
+ unsigned char aAttn[2];
+ aAttn[1] = (-iAttn) % 10; /* 1's digit */
+ aAttn[0] = (-iAttn) / 10; /* 10's digit */
+/* Check parameters. */
+ if ((bChan > 5) || (iAttn < (-79) || iAttn > 0))
+ {
+ cmn_err (CE_CONT, "\nPT2258S_Set_Attn() parameter out of range!");
+ return;
+ }
+/* Always set 10's digit, then 1's. */
+ aAttn[0] += bXlat[bChan] - 0x10;
+ aAttn[1] += bXlat[bChan];
+ PT2258S_Write_Data (devc, 2, aAttn);
+}
+static void
+PT2258S_Mute (envy24ht_devc * devc, int bMute)
+/*
+*****************************************************************************
+* Mute all 6 outputs of the monitoring volume control.
+* Unmuting returns volume to previous levels.
+****************************************************************************/
+{
+ if (bMute)
+ PT2258S_Write_Byte (devc, (unsigned char) 0xF9);
+ else
+ PT2258S_Write_Byte (devc, (unsigned char) 0xF8);
+}
+
+
+static void
+REVO51_Set_48K_Mode (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* Sets Chip and Envy24 for 8kHz-48kHz sample rates.
+****************************************************************************/
+{
+/* ICE MCLK = 256x. */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 2) & ~BIT3,
+ devc->mt_base + 2);
+/* DFS=normal, RESET. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x4E);
+/* DFS=normal, NORMAL OPERATION. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x4F);
+}
+
+static void
+REVO51_Set_96K_Mode (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* Sets CODEC and Envy24 for 60kHz-96kHz sample rates.
+****************************************************************************/
+{
+/* ICE MCLK = 256x. */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 2) & ~BIT3,
+ devc->mt_base + 2);
+/* DFS=double-speed, RESET. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x5E);
+/* DFS=double-speed, NORMAL OPERATION. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x5F);
+}
+
+static void
+REVO51_Set_192K_Mode (envy24ht_devc * devc)
+/*
+*****************************************************************************
+* Sets CODEC and Envy24 for 120kHz-192kHz sample rate.
+****************************************************************************/
+{
+/* ICE MCLK = 128x. */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 2) | BIT3,
+ devc->mt_base + 2);
+ _delay ();
+/*----- SET THE D/A. */
+/* DFS=quad-speed, RESET. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x6E);
+ _delay ();
+/* DFS=quad-speed, NORMAL OPERATION. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x6F);
+/*------ POWER DOWN THE A/D -- doesn't support 192K. */
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 0, 0x00);
+}
+
+static int
+set_dac (envy24ht_devc * devc, int reg, int level)
+{
+ if (level < 0)
+ level = 0;
+ if (level > 0x7f)
+ level = 0x7f;
+
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, reg, level | 0x80);
+
+ return level;
+}
+
+static void
+AK4358_Init (envy24ht_devc * devc)
+{
+/*===== AK4358 D/A initialization. Leave soft-muted. */
+/* */
+/* Power down, reset, normal mode. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x00);
+/* Power up, reset, normal mode */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x4E);
+/* Reset timing, Mode 3(I2S), disable auto clock detect, sharp roll off. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 0, 0x06);
+/* Soft mute, reset timing. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 1, 0x02);
+/* De-emphasis off. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 3, 0x01);
+/* Max volume on all 8 channels. */
+ set_dac (devc, 0x04, 0x7f);
+ set_dac (devc, 0x05, 0x7f);
+ set_dac (devc, 0x06, 0x7f);
+ set_dac (devc, 0x07, 0x7f);
+ set_dac (devc, 0x08, 0x7f);
+ set_dac (devc, 0x09, 0x7f);
+ set_dac (devc, 0x0b, 0x7f);
+ set_dac (devc, 0x0c, 0x7f);
+
+/* Datt mode 0, DZF non-invert, DCLK polarity 0, PCM mode, DCKS 512fs, TDM normal. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 0xA, 0x00);
+/* DZF control disabled. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 0xD, 0x00);
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 0xE, 0x00);
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 0xF, 0x00);
+/* Power up, normal operation. */
+ REVO51_WriteSpiReg (devc, REVO51_AK4358, 2, 0x4F);
+}
+
+static void
+PT2258_init (envy24ht_devc * devc)
+{
+/*===== PT2258 initialization. */
+/* */
+/* Initializes and clears register . */
+ PT2258S_Write_Byte (devc, (unsigned char) 0xC0);
+/*Example of 2-line command controlling all channels. */
+/*This sets all channels to max volume. */
+/*PT2258S_Write_Byte(devc, (unsigned char)0xE0); */
+/*PT2258S_Write_Byte(devc, (unsigned char)0xD0); */
+/* set volumes */
+ PT2258S_Set_Attn (devc, 0, 0);
+ PT2258S_Set_Attn (devc, 1, 0);
+ PT2258S_Set_Attn (devc, 2, 0);
+ PT2258S_Set_Attn (devc, 3, 0);
+ PT2258S_Set_Attn (devc, 4, 0);
+ PT2258S_Set_Attn (devc, 5, 0);
+/*mute, true or false */
+ PT2258S_Mute (devc, 0);
+}
+
+static void
+REVO51_set_recsrc (envy24ht_devc * devc, int src)
+{
+ devc->recsrc = src;
+
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 1, src);
+}
+
+static void
+AK5365_Init (envy24ht_devc * devc)
+{
+/*===== AK5365 2-ch A/D initialization. Leave soft-muted. */
+/* */
+/* Power down. */
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 0, 0x00);
+/* Set input to (LINE IN). */
+ REVO51_set_recsrc (devc, 0);
+/* Clock freq 256fs, I2S mode, mute off. */
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 2, 0x08);
+/* ALC settings (ALC is disabled, so rewrite default values). */
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 3, 0x2B);
+/* Neutral analog and digital gain. */
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 4, 0x7F);
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 5, 0x7F);
+/* ALC settings (ALC is disabled, so rewrite default values). */
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 6, 0x28);
+/* ALC settings (ALC is disabled, so rewrite default values). */
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 7, 0x89);
+/* Power up. */
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 0, 0x01);
+}
+
+static void
+revo51_set_rate (envy24ht_devc * devc)
+{
+ int tmp;
+
+ tmp = INB (devc->osdev, devc->mt_base + 0x02);
+ if (devc->speed <= 48000)
+ {
+ REVO51_Set_48K_Mode (devc);
+ OUTB (devc->osdev, tmp & ~BIT (3), devc->mt_base + 0x02);
+ return;
+ }
+
+ if (devc->speed <= 96000)
+ {
+ REVO51_Set_96K_Mode (devc);
+
+ return;
+ }
+
+ REVO51_Set_192K_Mode (devc);
+ OUTB (devc->osdev, tmp | BIT (3), devc->mt_base + 0x02);
+}
+
+static int
+revo51_audio_ioctl (envy24ht_devc * devc, envy24ht_portc * portc, unsigned int cmd,
+ ioctl_arg arg)
+{
+ int value;
+
+ switch (cmd)
+ {
+ case SNDCTL_DSP_GET_RECSRC_NAMES:
+ return oss_encode_enum ((oss_mixer_enuminfo *) arg, "mic line aux", 0);
+ break;
+
+ case SNDCTL_DSP_GET_RECSRC:
+ return *arg = devc->recsrc;
+ break;
+
+ case SNDCTL_DSP_SET_RECSRC:
+ value = *arg;
+ if (value < 0 || value > 2)
+ return OSS_EINVAL;
+ REVO51_set_recsrc (devc, value);
+ return *arg = devc->recsrc;
+ break;
+
+ case SNDCTL_DSP_GET_PLAYTGT:
+ case SNDCTL_DSP_SET_PLAYTGT:
+ return *arg = 0;
+ break;
+
+ case SNDCTL_DSP_GET_PLAYTGT_NAMES:
+ return oss_encode_enum ((oss_mixer_enuminfo *) arg, portc->name, 0);
+ break;
+
+
+ default:
+ return OSS_EINVAL;
+ }
+}
+
+static int
+set_reclevel (envy24ht_devc * devc, int value)
+{
+ int left, right;
+
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ if (left > 0x98)
+ left = 0x98;
+ if (right > 0x98)
+ right = 0x98;
+
+ value = left | (right << 8);
+
+ devc->reclevel = value;
+
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 4, left);
+ REVO51_WriteSpiReg (devc, REVO51_AK5365, 5, right);
+
+ return value;
+}
+
+static int
+revo51_set_control (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ switch (ctrl)
+ {
+ case 0:
+ return devc->mute;
+
+ case 1:
+ return devc->recsrc;
+
+ case 2:
+ return devc->reclevel;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ switch (ctrl)
+ {
+ case 0:
+ value = !!value;
+ REVO51_Mute (devc, value);
+ return devc->mute;
+
+ case 1:
+ if (value < 0 || value > 2)
+ return devc->recsrc;
+ REVO51_set_recsrc (devc, value);
+ return devc->recsrc;
+
+ case 2:
+ return set_reclevel (devc, value);
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+revo51_set_ak4358 (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ if (ctrl < 0 || ctrl > 4)
+ return OSS_EIO;
+
+ return devc->gains[ctrl];
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ int left, right;
+
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ switch (ctrl)
+ {
+ case 0: /* Front */
+ left = set_dac (devc, 0x04, left);
+ right = set_dac (devc, 0x05, right);
+ break;
+
+ case 1: /* Center */
+ left = set_dac (devc, 0x06, left);
+ right = left;
+ break;
+
+ case 2: /* LFE */
+ left = set_dac (devc, 0x07, left);
+ right = left;
+ break;
+
+ case 3: /* Surround */
+ left = set_dac (devc, 0x08, left);
+ left = set_dac (devc, 0x09, right);
+ break;
+
+ case 4: /* Headphones */
+ left = set_dac (devc, 0x0b, left);
+ left = set_dac (devc, 0x0c, right);
+ break;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ value = left | (right << 8);
+ return devc->gains[ctrl] = value;
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+set_mongain (envy24ht_devc * devc, int reg, int value)
+{
+ if (value < 0)
+ value = 0;
+ if (value > 79)
+ value = 79;
+
+ PT2258S_Set_Attn (devc, reg, value - 79);
+ return value;
+}
+
+static int
+revo51_set_monitor (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ if (ctrl < 0 || ctrl > 3)
+ return OSS_EIO;
+
+ return devc->monitor[ctrl];
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ int left, right;
+
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ switch (ctrl)
+ {
+ case 0: /* Mic */
+ left = set_mongain (devc, 0, left);
+ right = set_mongain (devc, 1, right);
+ break;
+
+ case 1: /* Line */
+ left = set_mongain (devc, 2, left);
+ right = set_mongain (devc, 3, right);
+ break;
+
+ case 2: /* Aux */
+ left = set_mongain (devc, 4, left);
+ right = set_mongain (devc, 5, right);
+ break;
+
+ case 3: /* Mute */
+ value = !!value;
+ PT2258S_Mute (devc, value);
+ return devc->monitor[3] = value;
+ break;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ value = left | (right << 8);
+ return devc->monitor[ctrl] = value;
+ }
+
+ return OSS_EINVAL;
+}
+
+ /*ARGSUSED*/ static int
+revo51_mixer_init (envy24ht_devc * devc, int dev, int g)
+{
+ int group = 0;
+ int err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, revo51_set_control,
+ MIXT_ONOFF,
+ "ENVY24_MUTE", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, revo51_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_FRONT", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, revo51_set_ak4358,
+ MIXT_SLIDER,
+ "ENVY24_CENTER", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, revo51_set_ak4358,
+ MIXT_SLIDER,
+ "ENVY24_LFE", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 3, revo51_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_SURROUND", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 4, revo51_set_ak4358,
+ MIXT_STEREOSLIDER,
+ "ENVY24_HEADPH", 0x7f,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, revo51_set_control,
+ MIXT_STEREOSLIDER,
+ "ENVY24_REC", 0x98,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, revo51_set_control,
+ MIXT_ENUM,
+ "ENVY24_RECSRC", 3,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ mixer_ext_set_strings (dev, err, "mic line aux", 0);
+
+ if ((group = mixer_ext_create_group (dev, g, "MONITOR")) < 0)
+ return group;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 3, revo51_set_monitor,
+ MIXT_ONOFF,
+ "MON_MUTE", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, revo51_set_monitor,
+ MIXT_STEREOSLIDER,
+ "ENVY24_MIC", 79,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, revo51_set_monitor,
+ MIXT_STEREOSLIDER,
+ "ENVY24_LINE", 79,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, revo51_set_monitor,
+ MIXT_STEREOSLIDER,
+ "ENVY24_AUX", 79,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ return 0;
+}
+
+static void
+revo51_card_init (envy24ht_devc * devc)
+{
+
+ int i;
+
+#if 1
+ OUTW (devc->osdev, 0xffff, devc->ccs_base + 0x18); /* GPIO direction */
+ OUTW (devc->osdev, 0x0000, devc->ccs_base + 0x16); /* GPIO write mask */
+ OUTW (devc->osdev, 0xffff, devc->ccs_base + 0x14); /* Initial bit state */
+
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x1a); /* GPIO direction for bits 16:22 */
+ OUTB (devc->osdev, 0x00, devc->ccs_base + 0x1f); /* GPIO mask for bits 16:22 */
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x1e); /* GPIO data for bits 16:22 */
+#endif
+
+ memcpy (devc->channel_names, channel_names, sizeof (channel_names));
+ AK4358_Init (devc);
+ AK5365_Init (devc);
+ PT2258_init (devc);
+ ADC_Set_Chan (devc, 0); /* TODO */
+ REVO51_Set_48K_Mode (devc);
+
+ for (i = 0; i < 5; i++)
+ devc->gains[i] = 0x7f7f;
+ for (i = 0; i < 3; i++)
+ devc->monitor[i] = 79 | (79 << 8);
+ devc->monitor[3] = 0; /* Unmuted */
+
+ set_reclevel (devc, 0x7f7f); /* +0 dB */
+
+ REVO51_Mute (devc, 0);
+}
+
+envy24ht_auxdrv_t envy24ht_revo51_auxdrv = {
+ revo51_card_init,
+ revo51_mixer_init,
+ revo51_set_rate,
+ NULL,
+ NULL,
+ NULL, /* revo51_private1 */
+ revo51_audio_ioctl
+};
diff --git a/kernel/drv/oss_envy24ht/envy24ht_revo71.c b/kernel/drv/oss_envy24ht/envy24ht_revo71.c
new file mode 100644
index 0000000..fd3a9bb
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht_revo71.c
@@ -0,0 +1,338 @@
+/*
+ * Purpose: Low level routines for M Audio Revolution 7.1
+ */
+/*
+ *
+ * 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_envy24ht_cfg.h"
+
+#include "spdif.h"
+#include "envy24ht.h"
+
+#define BIT(x) (1<<(x))
+
+#define CCLK (1<<1)
+#define CDIN (1<<2) /* Currently not connected */
+#define CDTI (1<<3)
+#define CSDIG (1<<4)
+#define CSN1 (1<<5)
+#define CSN2 (1<<6)
+
+#define WRITEMASK (CSN1|CSN2|CDTI|CCLK)
+
+#define DAC1 0x01 /* 2ch Front DAC (AK4381) */
+#define DAC2 0x03 /* 6ch Surround DAC (AK4355) */
+
+
+static void
+writereg (envy24ht_devc * devc, int csn, int chip, unsigned char reg,
+ unsigned char val)
+{
+ int i;
+ unsigned short v, tmp;
+
+ tmp = INW (devc->osdev, devc->ccs_base + 0x14) & ~(csn | CCLK | CDTI);
+ OUTW (devc->osdev, tmp, devc->ccs_base + 0x14);
+
+ reg = (reg & 0x1f) | 0x20 | (chip << 6); /* Chip address (variable), write */
+ /* Address bits */
+
+ for (i = 7; i >= 0; i--)
+ {
+ v = (reg & (1 << i)) ? CDTI : 0;
+ OUTW (devc->osdev, v | tmp, devc->ccs_base + 0x14); /* Tack */
+ OUTW (devc->osdev, v | CCLK | tmp, devc->ccs_base + 0x14); /* Tick */
+ }
+
+ /* Data bits */
+
+ for (i = 7; i >= 0; i--)
+ {
+ v = (val & (1 << i)) ? CDTI : 0;
+ OUTW (devc->osdev, v | tmp, devc->ccs_base + 0x14); /* Tack */
+ OUTW (devc->osdev, v | CCLK | tmp, devc->ccs_base + 0x14); /* Tick */
+ }
+
+ OUTW (devc->osdev, v | tmp, devc->ccs_base + 0x14); /* Tack */
+ OUTW (devc->osdev, tmp | csn | CDTI | CCLK, devc->ccs_base + 0x14); /* Release */
+
+}
+
+static void
+writedac1 (envy24ht_devc * devc, unsigned char reg, unsigned char data)
+{
+ writereg (devc, CSN1, DAC1, reg, data);
+ devc->dac1val[reg] = data;
+}
+
+static void
+writedac2 (envy24ht_devc * devc, unsigned char reg, unsigned char data)
+{
+ writereg (devc, CSN2, DAC2, reg, data);
+ devc->dac2val[reg] = data;
+}
+
+static void
+revo71_mute (envy24ht_devc * devc, int mute)
+{
+ if (mute)
+ {
+ writedac1 (devc, 1, devc->dac1val[1] | BIT (0));
+ writedac2 (devc, 1, devc->dac2val[1] | BIT (1));
+ oss_udelay (1000);
+/* OUTB (devc->osdev, INB (devc->osdev, devc->ccs_base + 0x1e) & ~BIT(22-16), */
+/* devc->ccs_base + 0x1e); */
+ }
+ else
+ {
+/* OUTB (devc->osdev, INB (devc->osdev, devc->ccs_base + 0x1e) | ~BIT(22-16), */
+/* devc->ccs_base + 0x1e); */
+ oss_udelay (1000);
+ writedac1 (devc, 1, devc->dac1val[1] & ~BIT (0));
+ writedac2 (devc, 1, devc->dac2val[1] & ~BIT (1));
+ }
+}
+
+static void
+revo71_card_init (envy24ht_devc * devc)
+{
+ int i;
+
+ OUTL (devc->osdev, WRITEMASK | 0x400000, devc->ccs_base + 0x18); /* GPIO direction */
+ OUTW (devc->osdev, ~WRITEMASK, devc->ccs_base + 0x16); /* GPIO write mask */
+ OUTB (devc->osdev, 0x40, devc->ccs_base + 0x1f);
+ OUTW (devc->osdev, WRITEMASK, devc->ccs_base + 0x14); /* Initial bit state */
+
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x1a); /* GPIO direction for bits 16:22 */
+ OUTB (devc->osdev, 0x00, devc->ccs_base + 0x1f); /* GPIO mask for bits 16:22 */
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x1e); /* GPIO data for bits 16:22 */
+
+#if 0
+ for (i = 0; i < 7; i++)
+ {
+ OUTW (devc->osdev, 1 << i, devc->ccs_base + 0x14); /* Test bit */
+ OUTW (devc->osdev, 0, devc->ccs_base + 0x14); /* Test bit */
+ }
+#endif
+
+ OUTW (devc->osdev, WRITEMASK, devc->ccs_base + 0x14); /* Initial bit state */
+ oss_udelay (10);
+
+ revo71_mute (devc, 1);
+/*
+ * Init front DAC (AK4381)
+ */
+ writedac1 (devc, 0x00, 0x0c);
+ writedac1 (devc, 0x01, 0x03);
+ writedac1 (devc, 0x02, 0x00);
+
+ writedac1 (devc, 0x03, 0xff); /* Initial volume */
+ writedac1 (devc, 0x04, 0xff); /* Initial volume */
+
+ writedac1 (devc, 0x00, 0x0f);
+/*
+ * Init surround DAC (AK4355)
+ */
+ writedac2 (devc, 0x01, 0x02);
+ writedac2 (devc, 0x00, 0x06);
+ oss_udelay (10);
+ writedac2 (devc, 0x02, 0x0e);
+ writedac2 (devc, 0x03, 0x01);
+
+ for (i = 4; i < 10; i++)
+ writedac2 (devc, i, 0xff); /* Initial volumes */
+ writedac2 (devc, 0x0a, 0x00);
+
+ writedac2 (devc, 0x01, 0x01);
+ revo71_mute (devc, 0);
+}
+
+static void
+revo71_set_rate (envy24ht_devc * devc)
+{
+ int rate = devc->speed, i;
+ unsigned char tmp;
+
+ if (devc->speed == devc->prev_speed)
+ return;
+ devc->prev_speed = devc->speed;
+
+ revo71_mute (devc, 1);
+
+ /* Pulse the PRST# signal to reset converters */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x05) | 0x80,
+ devc->mt_base + 0x05);
+ oss_udelay (5000);
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x05) & ~0x80,
+ devc->mt_base + 0x05);
+ oss_udelay (5000);
+
+ tmp = 0x03;
+ if (rate <= 48000)
+ tmp |= 0x00;
+ else
+ {
+ if (rate <= 96000)
+ tmp |= 0x04;
+ else
+ tmp |= 0x08;
+ }
+
+ /* Front DAC */
+
+ writedac1 (devc, 0, 0x0c);
+ writedac1 (devc, 1, tmp);
+ writedac1 (devc, 2, 0x00);
+ writedac1 (devc, 3, devc->dac1val[3]);
+ writedac1 (devc, 4, devc->dac1val[4]);
+ writedac1 (devc, 0, 0x0f);
+
+ /* Surround DAC */
+ writedac2 (devc, 1, 0x02);
+ writedac2 (devc, 0, 0x06);
+
+ tmp = 0x0e;
+
+ if (devc->speed > 60000)
+ {
+ if (devc->speed > 120000)
+ tmp |= 0x20;
+ else
+ tmp |= 0x10;
+ }
+ writedac2 (devc, 2, tmp);
+ writedac2 (devc, 3, 0x01);
+
+ for (i = 4; i < 10; i++)
+ writedac2 (devc, i, devc->dac2val[i]);
+
+ writedac2 (devc, 0xa, 0x00);
+ writedac2 (devc, 1, 0x03);
+
+ revo71_mute (devc, 0);
+}
+
+static int
+revo71_set_akm (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ if (ctrl < 0 || ctrl > 4)
+ return OSS_EIO;
+
+ return devc->gains[ctrl];
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ int left, right;
+
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+
+ switch (ctrl)
+ {
+ case 0: /* Front */
+ writedac1 (devc, 0x03, left);
+ writedac1 (devc, 0x04, right);
+ break;
+
+ case 1: /* Rear */
+ writedac2 (devc, 0x06, left);
+ writedac2 (devc, 0x07, right);
+ break;
+
+ case 2: /* Center */
+ writedac2 (devc, 0x04, left);
+ right = left;
+ break;
+
+ case 3: /* LFE */
+ writedac2 (devc, 0x05, left);
+ right = left;
+ break;
+
+ case 4: /* Surround */
+ writedac2 (devc, 0x08, left);
+ writedac2 (devc, 0x09, right);
+ break;
+
+ default:
+ return OSS_EINVAL;
+ }
+
+ value = left | (right << 8);
+ return devc->gains[ctrl] = value;
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+revo71_mixer_init (envy24ht_devc * devc, int dev, int group)
+{
+ int i, err;
+
+ for (i = 0; i < 6; i++)
+ devc->gains[i] = 0xffff;
+
+ if ((group = mixer_ext_create_group (dev, 0, "ENVY24HT_GAIN")) < 0)
+ return group;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, revo71_set_akm,
+ MIXT_STEREOSLIDER,
+ "GAIN_FRONT", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, revo71_set_akm,
+ MIXT_STEREOSLIDER,
+ "GAIN_REAR", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, revo71_set_akm,
+ MIXT_MONOSLIDER,
+ "GAIN_CENTER", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 3, revo71_set_akm,
+ MIXT_MONOSLIDER,
+ "GAIN_LFE", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 4, revo71_set_akm,
+ MIXT_STEREOSLIDER,
+ "GAIN_surround", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ return 0;
+}
+
+envy24ht_auxdrv_t envy24ht_revo71_auxdrv = {
+ revo71_card_init,
+ revo71_mixer_init,
+ revo71_set_rate,
+ NULL,
+ NULL,
+ NULL, /* revo71_private1 */
+};
diff --git a/kernel/drv/oss_envy24ht/envy24ht_via.c.save b/kernel/drv/oss_envy24ht/envy24ht_via.c.save
new file mode 100644
index 0000000..49d4199
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/envy24ht_via.c.save
@@ -0,0 +1,324 @@
+/*
+ * Purpose: Low level routines for VIA's Envy24HT reference board (AKM codec)
+ *
+ * Notice:
+ *
+ * This driver is currently disabled because no known real world device
+ * is based on this design. To enable this driver againa just rename it to
+ * envy24ht_via.c and edit the models[] table in envy24ht.c.
+ */
+/*
+ *
+ * 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_envy24ht_cfg.h"
+
+#include "spdif.h"
+#include "envy24ht.h"
+
+#define AKM_ADDRESS 0x10
+
+static unsigned char
+i2c_read (envy24ht_devc * devc, unsigned char addr, unsigned char pos)
+{
+ int i;
+ unsigned char data;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ OUTB (devc->osdev, pos, devc->ccs_base + 0x11); /* Offset */
+ OUTB (devc->osdev, addr << 1, devc->ccs_base + 0x10); /* Read address */
+
+ for (i = 0; i < 2000; i++)
+ {
+ unsigned char status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+
+ oss_udelay (1);
+ data = INB (devc->osdev, devc->ccs_base + 0x12);
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+
+ return data;
+}
+
+static void
+i2c_write (envy24ht_devc * devc, unsigned char addr, unsigned char pos,
+ unsigned char data)
+{
+ int i;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ OUTB (devc->osdev, pos, devc->ccs_base + 0x11); /* Offset */
+ OUTB (devc->osdev, data, devc->ccs_base + 0x12); /* Data */
+ OUTB (devc->osdev, (addr << 1) | 1, devc->ccs_base + 0x10); /* Write address */
+
+ for (i = 0; i < 2000; i++)
+ {
+ unsigned char status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+}
+
+static void
+viaref_card_init (envy24ht_devc * devc)
+{
+ int addr = AKM_ADDRESS;
+
+ if (devc->codec_type != CODEC_I2S)
+ return;
+
+ OUTW (devc->osdev, 0x000f, devc->ccs_base + 0x14); /* GPIO */
+
+ oss_udelay (1000);
+
+ i2c_write (devc, addr, 0, 0x00);
+ i2c_write (devc, addr, 0, 0x0f);
+ i2c_write (devc, addr, 1, 0x00);
+ i2c_write (devc, addr, 2, 0x01);
+ i2c_write (devc, addr, 5, 0x07);
+ i2c_write (devc, addr, 6, 0x00);
+ i2c_write (devc, addr, 7, 0x00);
+
+ i2c_write (devc, addr, 6, 0x00);
+ i2c_write (devc, addr, 7, 0x00);
+ i2c_write (devc, addr, 8, 0x00);
+ i2c_write (devc, addr, 9, 0x00);
+ i2c_write (devc, addr, 10, 0x00);
+ i2c_write (devc, addr, 11, 0x00);
+
+ devc->recsrc = 0;
+
+#if 0
+ cmn_err(CE_CONT, "Regs=");
+ for (i = 0; i < 0x18; i++)
+ {
+ cmn_err(CE_CONT, "%02x ", i2c_read (devc, addr, i));
+ }
+ cmn_err(CE_CONT, "\n");
+#endif
+}
+
+static int
+viaref_set_akm (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+ int left, right, val;
+ unsigned char tmp, tmp2, old, old2;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ switch (ctrl)
+ {
+ /* Output gain controls */
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ return devc->gains[ctrl];
+
+ case 10: /* Loopback enable */
+ return !!(i2c_read (devc, AKM_ADDRESS, 0x01) & 0x30);
+
+ case 11: /* codec.recsrc (ANALOG OPTICAL COAX CD AUX) */
+ return devc->recsrc;
+ break;
+
+ default:
+ return OSS_EINVAL;
+ }
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ {
+ oss_native_word flags;
+ left = value & 0xff;
+ right = (value >> 8) & 0xff;
+ val = left | (right << 8);
+
+ switch (ctrl)
+ {
+ case 0:
+ left = 0xff - left;
+ right = 0xff - right;
+ i2c_write (devc, AKM_ADDRESS, 0x06, left);
+ i2c_write (devc, AKM_ADDRESS, 0x07, right);
+ return devc->gains[ctrl] = val;
+
+ case 1:
+ left = 0xff - left;
+ right = 0xff - right;
+ i2c_write (devc, AKM_ADDRESS, 0x08, left);
+ i2c_write (devc, AKM_ADDRESS, 0x09, right);
+ return devc->gains[ctrl] = val;
+
+ case 2:
+ val = left | (left << 8);
+ left = 0xff - left;
+ i2c_write (devc, AKM_ADDRESS, 0x0a, left);
+ return devc->gains[ctrl] = val;
+
+ case 3:
+ val = left | (left << 8);
+ left = 0xff - left;
+ i2c_write (devc, AKM_ADDRESS, 0x0b, left);
+ return devc->gains[ctrl] = val;
+
+ case 10: /* Loopback enable */
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ old = tmp = i2c_read (devc, AKM_ADDRESS, 0x01);
+ value = !!value;
+ if (value)
+ tmp |= 0x10;
+ else
+ tmp &= ~0x30;
+
+ if (tmp != old)
+ {
+ i2c_write (devc, AKM_ADDRESS, 0x01, tmp);
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return value;
+
+ case 11: /* codec.recsrc (ANALOG OPTICAL COAX CD AUX) */
+ if (value < 0 || value > 4)
+ return devc->recsrc;
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ old = tmp = i2c_read (devc, AKM_ADDRESS, 0x01);
+ old2 = tmp2 = i2c_read (devc, AKM_ADDRESS, 0x02);
+
+ tmp &= ~0x0c;
+ tmp2 &= ~0x03;
+
+ switch (value)
+ {
+ case 0: /* Analog */
+ tmp2 |= 0x01;
+ break;
+
+ case 1: /* Optical (RX2) */
+ tmp |= 0x04;
+ tmp2 |= 0x00;
+ break;
+
+ case 2: /* Coax (RX1) */
+ tmp |= 0x00;
+ tmp2 |= 0x00;
+ break;
+
+ case 3: /* CD digital input (RX3) */
+ tmp |= 0x08;
+ tmp2 |= 0x00;
+ break;
+
+ case 4: /* Unused digital input (RX4) */
+ tmp |= 0x08;
+ tmp2 |= 0x00;
+ break;
+ }
+
+ if (tmp != old)
+ i2c_write (devc, AKM_ADDRESS, 0x01, tmp);
+ if (tmp2 != old2)
+ i2c_write (devc, AKM_ADDRESS, 0x02, tmp2);
+
+ devc->recsrc = value;
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return devc->recsrc;
+ break;
+
+ }
+ return OSS_EIO;
+ }
+
+ return OSS_EIO;
+}
+
+static int
+viaref_mixer_init (envy24ht_devc * devc, int dev, int group)
+{
+ int i, err;
+ if (devc->codec_type != CODEC_I2S)
+ return 0;
+
+ for (i = 0; i < 4; i++)
+ devc->gains[i] = 0xffff;
+
+ if ((group = mixer_ext_create_group (dev, 0, "ENVY24HT_GAIN")) < 0)
+ return group;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 0, viaref_set_akm,
+ MIXT_STEREOSLIDER,
+ "GAIN_FRONT", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, viaref_set_akm,
+ MIXT_STEREOSLIDER,
+ "GAIN_REAR", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, viaref_set_akm,
+ MIXT_MONOSLIDER,
+ "GAIN_CENTER", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 3, viaref_set_akm,
+ MIXT_MONOSLIDER,
+ "GAIN_LFE", 255,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((group = mixer_ext_create_group (dev, 0, "ENVY24HT_CODEC")) < 0)
+ return group;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 11, viaref_set_akm,
+ MIXT_ENUM,
+ "CODEC_RECSRC", 5,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 10, viaref_set_akm,
+ MIXT_ONOFF,
+ "CODEC_LOOPBACK", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ return 0;
+}
+
+#if 0
+static int
+viaref_private1 (envy24ht_devc * devc, int value)
+{
+ i2c_write (devc, AKM_ADDRESS, (value >> 8) & 0xff, value & 0xff);
+ return 0;
+}
+#endif
+
+envy24ht_auxdrv_t envy24ht_viaref_auxdrv = {
+ viaref_card_init,
+ viaref_mixer_init
+};
diff --git a/kernel/drv/oss_envy24ht/oss_envy24ht.c b/kernel/drv/oss_envy24ht/oss_envy24ht.c
new file mode 100644
index 0000000..11fb75b
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/oss_envy24ht.c
@@ -0,0 +1,2411 @@
+/*
+ * Purpose: VIA ENVY24HT chipset driver.
+ */
+/*
+ *
+ * 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_envy24ht_cfg.h"
+#include <oss_pci.h>
+
+#define SUPPORTED_FORMAT AFMT_S32_LE
+
+#include <spdif.h>
+#include "envy24ht.h"
+
+/* extern envy24ht_auxdrv_t envy24ht_viaref_auxdrv; */
+extern envy24ht_auxdrv_t envy24ht_ac97_auxdrv;
+extern envy24ht_auxdrv_t envy24ht_revo51_auxdrv;
+extern envy24ht_auxdrv_t envy24ht_revo71_auxdrv;
+extern envy24ht_auxdrv_t envy24ht_aureon_auxdrv;
+extern envy24ht_auxdrv_t envy24ht_julia_auxdrv;
+extern envy24ht_auxdrv_t envy24ht_ap192_auxdrv;
+
+#define OUTCH_NAMES "front c/l side rear"
+static char channel_names[4][10] = {
+ "front",
+ "c/l",
+ "side",
+ "rear"
+};
+
+static card_spec models[] = {
+ {0x17241412, "Generic Envy24PT motherboard audio", 6, 2,
+ MF_SPDIFOUT | MF_ENVY24PT, &envy24ht_ac97_auxdrv},
+ {0xf641270f, "Chaintech ZNF3-150", 6, 2,
+ MF_SPDIFOUT | MF_ENVY24PT, &envy24ht_ac97_auxdrv},
+ {0x2723270f, "Chaintech 9CJS", 6, 2,
+ MF_SPDIFOUT | MF_ENVY24PT, &envy24ht_ac97_auxdrv},
+ {0x50361297, "Shuttle SN25P", 6, 2,
+ MF_SPDIFOUT | MF_ENVY24PT, &envy24ht_ac97_auxdrv},
+ {0x020010b0, "Gainward Hollywood Envy24HT-S", 6, 2,
+ MF_SPDIFOUT | MF_ENVY24PT, &envy24ht_ac97_auxdrv},
+ {0x36311412, "M Audio Revolution 5.1", 6, 2,
+ MF_SPDIFOUT | MF_192K, &envy24ht_revo51_auxdrv},
+ {0x36301412, "M Audio Revolution 7.1", 8, 2,
+ MF_SPDIFOUT | MF_192K, &envy24ht_revo71_auxdrv},
+ {SSID_AUREON_SPACE, "Terratec Aureon 7.1 Space", 8, 2,
+ MF_SPDIFOUT | MF_192K | MF_NOAC97, &envy24ht_aureon_auxdrv},
+ {SSID_AUREON_UNIVERSE, "Terratec Aureon 7.1 Universe", 8, 2,
+ MF_SPDIFOUT | MF_192K | MF_NOAC97, &envy24ht_aureon_auxdrv},
+ {SSID_AUREON_SKY, "Terratec Aureon 7.1 Sky", 8, 2,
+ MF_SPDIFOUT | MF_192K | MF_NOAC97, &envy24ht_aureon_auxdrv},
+ {SSID_PRODIGY71, "Audiotrak Prodigy 7.1", 8, 2,
+ MF_SPDIFOUT | MF_192K | MF_NOAC97, &envy24ht_aureon_auxdrv},
+ {SSID_JULIA, "Ego Systems Juli@", 2, 2,
+ MF_SPDIFOUT | MF_SPDIFIN | MF_192K | MF_NOAC97 | MF_MIDI,
+ &envy24ht_julia_auxdrv},
+ {SSID_PHASE28, "Terratec PHASE 28", 8, 2,
+ MF_SPDIFOUT | MF_192K | MF_NOAC97 | MF_MIDI, &envy24ht_aureon_auxdrv},
+ {SSID_AP192, "M-Audio Audiophile 192", 2, 2,
+ MF_SPDIFOUT | MF_SPDIFIN | MF_192K | MF_NOAC97 | MF_MIDI,
+ &envy24ht_ap192_auxdrv},
+ {0x24031412, "VIA Vinyl Tremor Audio", 6, 2,
+ MF_SPDIFOUT | MF_ENVY24PT, &envy24ht_ac97_auxdrv},
+ /* XXX Do a separate auxdrv, to adjust for Envy24HT-S and other differences. */
+ {SSID_PRODIGYHD2, "Audiotrak Prodigy HD2", 2, 2,
+ MF_SPDIFOUT | MF_192K | MF_NOAC97, &envy24ht_ap192_auxdrv},
+ {SSID_PRODIGYHD2_ADE, "Audiotrak Prodigy HD2 Advance DE", 2, 2,
+ MF_SPDIFOUT | MF_192K | MF_NOAC97, &envy24ht_ap192_auxdrv},
+ /* {0x17241412, "VIA Envy24HT reference design", 6, 2, */
+ /* MF_SPDIFOUT | MF_MIDI, &envy24ht_viaref_auxdrv}, */
+ {0}
+};
+
+static struct speed_sel speed_tab[] = {
+ {
+ 8000, 0x06}
+ ,
+ {
+ 9600, 0x03}
+ ,
+ {
+ 11025, 0x0a}
+ ,
+ {
+ 12000, 0x02}
+ ,
+ {
+ 16000, 0x05}
+ ,
+ {
+ 22050, 0x09}
+ ,
+ {
+ 24000, 0x01}
+ ,
+ {
+ 32000, 0x04}
+ ,
+ {
+ 44100, 0x08}
+ ,
+ {
+ 48000, 0x00}
+ ,
+ {
+ 64000, 0x0f}
+ ,
+ {
+ 88200, 0x0b}
+ ,
+ {
+ 96000, 0x07}
+ ,
+ {
+ 176400, 0x0c}
+ ,
+ {
+ 192000, 0x0e}
+ ,
+ {-1, 0x10}
+ ,
+};
+
+static const envy24ht_auxdrv_t dummy_auxdrv = { NULL };
+
+static int
+ac97_read (void *devc_, int wAddr)
+{
+ envy24ht_devc *devc = devc_;
+ oss_native_word flags;
+ int n = 0, dat;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ while (n++ < 10000 && INB (devc->osdev, devc->mt_base + 0x05) & 0x30);
+ OUTB (devc->osdev, wAddr, devc->mt_base + 0x04);
+ OUTB (devc->osdev, 0x10, devc->mt_base + 0x05); /* Codec read */
+
+ n = 0;
+ while (n++ < 10000 && INB (devc->osdev, devc->mt_base + 0x05) & 0x10);
+ dat = INW (devc->osdev, devc->mt_base + 0x06);
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+
+ return dat;
+}
+
+static int
+ac97_write (void *devc_, int wAddr, int wData)
+{
+ envy24ht_devc *devc = devc_;
+ oss_native_word flags;
+ int n = 0;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ while (n++ < 10000 && INB (devc->osdev, devc->mt_base + 0x05) & 0x30);
+
+ OUTB (devc->osdev, wAddr, devc->mt_base + 0x04);
+ OUTW (devc->osdev, wData, devc->mt_base + 0x06);
+ OUTB (devc->osdev, 0x20, devc->mt_base + 0x05); /* Codec write */
+
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+
+ return 0;
+}
+
+static __inline__ int
+input_avail (envy24ht_devc * devc)
+{
+ unsigned char status;
+
+ status = INB (devc->osdev, devc->ccs_base + 0x0b);
+ return status & 0x1f; /* Number of bytes in RX queue */
+}
+
+static __inline__ int
+output_ready (envy24ht_devc * devc)
+{
+ unsigned char status;
+
+ status = INB (devc->osdev, devc->ccs_base + 0x0a);
+ return (31 - (status & 0x1f)) > 0; /* Number of free bytes in TX queue */
+}
+
+static __inline__ void
+midi_cmd (envy24ht_devc * devc, unsigned char cmd)
+{
+ OUTB (devc->osdev, cmd, devc->ccs_base + 0x0d);
+}
+
+static __inline__ int
+midi_read (envy24ht_devc * devc)
+{
+ return INB (devc->osdev, devc->ccs_base + 0x0c);
+}
+
+static __inline__ void
+midi_write (envy24ht_devc * devc, unsigned char byte)
+{
+ OUTB (devc->osdev, byte, devc->ccs_base + 0x0c);
+}
+
+static void reset_midi (envy24ht_devc * devc);
+static void enter_uart_mode (envy24ht_devc * devc);
+
+static void
+midi_input_loop (envy24ht_devc * devc)
+{
+ int n = 0;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ while (input_avail (devc) && n++ < 33)
+ {
+ unsigned char c = midi_read (devc);
+
+ devc->input_byte = c;
+ if (devc->midi_opened & OPEN_READ && devc->midi_input_intr)
+ devc->midi_input_intr (devc->midi_dev, c);
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+static void
+midiintr (envy24ht_devc * devc)
+{
+ int status;
+
+ status = INB (devc->osdev, devc->ccs_base + 0x02);
+ if (status & 0x80)
+ midi_input_loop (devc);
+ if ((status & 0x20))
+ {
+ OUTB (devc->osdev, INB (devc->osdev, devc->ccs_base + 0x01) | 0x20,
+ devc->ccs_base + 0x01);
+
+#if 0
+ if (devc->midi_output_intr)
+ devc->midi_output_intr (devc->midi_dev);
+#endif
+ }
+}
+
+/*ARGSUSED*/
+static int
+midi_open (int dev, int mode, oss_midi_inputbyte_t inputbyte,
+ oss_midi_inputbuf_t inputbuf, oss_midi_outputintr_t outputintr)
+{
+ envy24ht_devc *devc = (envy24ht_devc *) midi_devs[dev]->devc;
+ int n = 0, tmp;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+
+ if (devc->midi_opened & mode)
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return OSS_EBUSY;
+ }
+ devc->midi_opened |= mode;
+
+ if (mode & OPEN_READ)
+ {
+ while (n++ < 33 && input_avail (devc))
+ midi_read (devc);
+
+ devc->midi_input_intr = inputbyte;
+ devc->midi_output_intr = outputintr;
+ }
+ enter_uart_mode (devc);
+ tmp = INB (devc->osdev, devc->ccs_base + 0x01);
+ if (mode & OPEN_READ)
+ tmp &= ~0x80;
+ OUTB (devc->osdev, tmp, devc->ccs_base + 0x01);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+
+ return 0;
+}
+
+static void
+midi_close (int dev, int mode)
+{
+ envy24ht_devc *devc = (envy24ht_devc *) midi_devs[dev]->devc;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ reset_midi (devc);
+ enter_uart_mode (devc);
+ reset_midi (devc);
+ OUTB (devc->osdev, INB (devc->osdev, devc->ccs_base + 0x01) | 0xa0,
+ devc->ccs_base + 0x01);
+ devc->midi_opened &= ~mode;
+ devc->midi_input_intr = NULL;
+ devc->midi_output_intr = NULL;
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+static int
+midi_out (int dev, unsigned char midi_byte)
+{
+ envy24ht_devc *devc = (envy24ht_devc *) midi_devs[dev]->devc;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ if (!output_ready (devc))
+ {
+ OUTB (devc->osdev, INB (devc->osdev, devc->ccs_base + 0x01) & ~0x20,
+ devc->ccs_base + 0x01);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return 0;
+ }
+
+ midi_write (devc, midi_byte);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return 1;
+}
+
+/*ARGSUSED*/
+static int
+midi_ioctl (int dev, unsigned cmd, ioctl_arg arg)
+{
+ return OSS_EINVAL;
+}
+
+static midi_driver_t envy24ht_midi_driver = {
+ midi_open,
+ midi_close,
+ midi_ioctl,
+ midi_out
+};
+
+static void
+enter_uart_mode (envy24ht_devc * devc)
+{
+ devc->input_byte = 0;
+ midi_cmd (devc, 1);
+}
+
+void
+attach_midi (envy24ht_devc * devc)
+{
+ char name[128];
+ enter_uart_mode (devc);
+
+ sprintf (name, "%s input", devc->model_data->product);
+ devc->midi_dev = oss_install_mididev (OSS_MIDI_DRIVER_VERSION, "ENVY24HT", name, &envy24ht_midi_driver, sizeof (midi_driver_t),
+ MFLAG_INPUT, devc, devc->osdev);
+ sprintf (name, "%s output", devc->model_data->product);
+ devc->midi_dev = oss_install_mididev (OSS_MIDI_DRIVER_VERSION, "ENVY24HT", name, &envy24ht_midi_driver, sizeof (midi_driver_t),
+ MFLAG_OUTPUT, devc, devc->osdev);
+ devc->midi_opened = 0;
+ devc->midi_attached = 1;
+}
+
+static void
+reset_midi (envy24ht_devc * devc)
+{
+ /*
+ * Send the RESET command. Try again if no success at the first time.
+ */
+
+ midi_cmd (devc, 0);
+}
+
+void
+unload_midi (envy24ht_devc * devc)
+{
+ if (devc->midi_attached)
+ reset_midi (devc);
+ devc->midi_attached = 0;
+}
+
+static int
+envy24htintr (oss_device_t * osdev)
+{
+ envy24ht_devc *devc = osdev->devc;
+ int port, status, mt_status, serviced = 0;
+
+ status = INB (devc->osdev, devc->ccs_base + 0x02);
+ if (status != 0)
+ serviced = 1;
+
+ if (status & 0xa0)
+ midiintr (devc);
+
+/*
+ * Handle audio interrupts
+ */
+ mt_status = INB (devc->osdev, devc->mt_base + 0x00);
+
+ if (mt_status & 0x08) /* FIFO underrun/overrun */
+ {
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x1A),
+ devc->mt_base + 0x1A);
+ serviced = 1;
+ }
+
+ if ((status & 0x10) || mt_status != 0)
+ {
+
+ for (port = 0; port < devc->nr_outdevs; port++)
+ {
+ envy24ht_portc *portc = &devc->play_portc[port];
+
+ if (mt_status & portc->mask)
+ {
+ oss_audio_outputintr (portc->dev, 1);
+ }
+ }
+
+ for (port = 0; port < devc->nr_indevs; port++)
+ {
+ envy24ht_portc *portc = &devc->rec_portc[port];
+
+ if (mt_status & portc->mask)
+ {
+ oss_audio_inputintr (portc->dev, 0);
+ }
+ }
+ }
+ OUTB (devc->osdev, mt_status, devc->mt_base + 0x00);
+ OUTB (devc->osdev, status, devc->ccs_base + 0x02);
+
+ return serviced;
+}
+
+/*ARGSUSED*/
+static int
+envy24ht_mixer_ioctl (int dev, int audiodev, unsigned int cmd, ioctl_arg arg)
+{
+ return OSS_EINVAL;
+}
+
+static mixer_driver_t envy24ht_mixer_driver = {
+ envy24ht_mixer_ioctl
+};
+
+static int
+envy24ht_set_route (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+ unsigned int tmp;
+ oss_native_word flags;
+
+ if (ctrl < 0 || ctrl > 8)
+ return OSS_EINVAL;
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ tmp = INL (devc->osdev, devc->mt_base + 0x2c);
+
+ switch (ctrl)
+ {
+ case 0:
+ tmp >>= 8;
+ break;
+ case 2:
+ tmp >>= 11;
+ break;
+ case 4:
+ tmp >>= 14;
+ break;
+ case 6:
+ tmp >>= 17;
+ break;
+ }
+
+ tmp = (tmp & 0x03) >> 1;
+
+ if (tmp == 3)
+ return 2;
+ return tmp;
+ }
+ else if (cmd == SNDCTL_MIX_WRITE)
+ {
+ int left_shift = 0, right_shift = 0;
+
+ static const unsigned char cnv_tab[3] = { 0x00, 0x02, 0x06 };
+ if (value < 0 || value > 2)
+ return OSS_EINVAL;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+ tmp = INL (devc->osdev, devc->mt_base + 0x2c);
+
+ switch (ctrl)
+ {
+ case 0:
+ left_shift = 8;
+ right_shift = 20;
+ break;
+ case 2:
+ left_shift = 11;
+ right_shift = 23;
+ break;
+ case 4:
+ left_shift = 14;
+ right_shift = 26;
+ break;
+ case 6:
+ left_shift = 17;
+ right_shift = 29;
+ break;
+ case 8:
+ left_shift = 0;
+ right_shift = 3;
+ break;
+ }
+
+ tmp &= ~(0x7 << left_shift);
+ tmp &= ~(0x7 << right_shift);
+ tmp |= cnv_tab[value] << left_shift;
+ if (ctrl != 8)
+ tmp |= (cnv_tab[value] + 1) << right_shift;
+ else
+ tmp |= cnv_tab[value] << right_shift;
+
+ OUTL (devc->osdev, tmp, devc->mt_base + 0x2c);
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+
+ return value;
+ }
+ return OSS_EINVAL;
+}
+
+static int
+read_peak (envy24ht_devc * devc, int ch)
+{
+ int tmp;
+
+ if (ch >= 22)
+ return 0;
+
+ OUTB (devc->osdev, ch, devc->mt_base + 0x3e);
+ tmp = INB (devc->osdev, devc->mt_base + 0x3f);
+
+ return tmp;
+}
+
+/*ARGSUSED*/
+static int
+envy24ht_get_peak (int dev, int ctrl, unsigned int cmd, int value)
+{
+ static const unsigned char peak_cnv[256] = {
+ 0, 18, 29, 36, 42, 47, 51, 54, 57, 60, 62, 65, 67, 69, 71, 72,
+ 74, 75, 77, 78, 79, 81, 82, 83, 84, 85, 86, 87, 88, 89, 89, 90,
+ 91, 92, 93, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99, 100, 100, 101,
+ 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
+ 108,
+ 109, 109, 110, 110, 110, 111, 111, 111, 112, 112, 113, 113, 113, 114, 114,
+ 114,
+ 115, 115, 115, 115, 116, 116, 116, 117, 117, 117, 118, 118, 118, 118, 119,
+ 119,
+ 119, 119, 120, 120, 120, 121, 121, 121, 121, 122, 122, 122, 122, 122, 123,
+ 123,
+ 123, 123, 124, 124, 124, 124, 125, 125, 125, 125, 125, 126, 126, 126, 126,
+ 126,
+ 127, 127, 127, 127, 127, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129,
+ 130,
+ 130, 130, 130, 130, 130, 131, 131, 131, 131, 131, 131, 132, 132, 132, 132,
+ 132,
+ 132, 133, 133, 133, 133, 133, 133, 134, 134, 134, 134, 134, 134, 134, 135,
+ 135,
+ 135, 135, 135, 135, 135, 136, 136, 136, 136, 136, 136, 136, 137, 137, 137,
+ 137,
+ 137, 137, 137, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139,
+ 139,
+ 139, 139, 139, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141,
+ 141,
+ 141, 141, 141, 141, 142, 142, 142, 142, 142, 142, 142, 142, 142, 143, 143,
+ 143,
+ 143, 143, 143, 143, 143, 143, 144, 144, 144, 144, 144, 144, 144, 144, 144,
+ 144,
+ };
+
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+
+ int i, orign, n = -1, left = 0, right = 0;
+
+ for (i = 0; i < 12 && n == -1; i++)
+ if (ctrl & (1 << i))
+ n = i;
+
+ if (n == -1)
+ return OSS_EINVAL;
+
+ orign = n;
+ if (ctrl & 0x80000000)
+ n += 10; /* Recording stream */
+
+ if (cmd == SNDCTL_MIX_READ)
+ {
+ left = read_peak (devc, n);
+ if (ctrl & (1 << (orign + 1))) /* Stereo mode? */
+ right = read_peak (devc, n + 1);
+ else
+ right = left;
+
+ left = peak_cnv[left];
+ right = peak_cnv[right];
+ return left | (right << 8);
+ }
+
+ return OSS_EINVAL;
+}
+
+/*ARGSUSED*/
+static int
+create_peak_mixer (int dev, envy24ht_devc * devc, int root)
+{
+ int i, mask = devc->outportmask, group, err, num, skip;
+ int nc = devc->nr_play_channels;
+ char tmp[64];
+
+ if ((group = mixer_ext_create_group (dev, 0, "ENVY24_PEAK")) < 0)
+ return group;
+
+ skip = 2;
+
+ for (i = 0; i < nc; i += skip)
+ {
+
+ num = 1 << i;
+ if (!(mask & num))
+ continue; /* Not present */
+
+ {
+ if (i == 8)
+ strcpy (tmp, "ENVY24_SPDIFOUT");
+ else
+ sprintf (tmp, devc->channel_names[i / 2], i + 1, i + 2);
+
+ num |= 1 << (i + 1);
+ if ((err = mixer_ext_create_control (dev, group,
+ num, envy24ht_get_peak,
+ MIXT_STEREOPEAK,
+ tmp, 144,
+ MIXF_READABLE | MIXF_DECIBEL)) <
+ 0)
+ return err;
+ }
+ }
+
+ mask = devc->inportmask;
+ for (i = 0; i < devc->nr_rec_channels; i += skip)
+ {
+
+ num = 1 << i;
+ if (!(mask & num))
+ continue; /* Not present */
+
+ num |= 0x80000000; /* Input flag */
+
+ {
+ if (i == 8)
+ strcpy (tmp, "ENVY24_SPDIFIN");
+ else
+ strcpy (tmp, "ENVY24_IN");
+
+ num |= 1 << (i + 1);
+ if ((err = mixer_ext_create_control (dev, group,
+ num, envy24ht_get_peak,
+ MIXT_STEREOPEAK,
+ tmp, 144,
+ MIXF_READABLE | MIXF_DECIBEL)) <
+ 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+create_rout_mixer (int dev, envy24ht_devc * devc, int root)
+{
+ int i, mask = devc->outportmask, group, ret, num;
+ char *name;
+
+ if ((group =
+ mixer_ext_create_group_flags (dev, 0, "ENVY24_ROUTE", MIXF_FLAT)) < 0)
+ return group;
+
+ for (i = 0; i < 8; i += 2)
+ {
+
+ num = 1 << i;
+ if (!(mask & num))
+ continue; /* Not present */
+
+ name = devc->channel_names[i / 2];
+
+ if ((ret = mixer_ext_create_control (dev, group,
+ i,
+ envy24ht_set_route,
+ MIXT_ENUM, name, 3,
+ MIXF_READABLE |
+ MIXF_WRITEABLE)) < 0)
+ return ret;
+ mixer_ext_set_strings (dev, ret, "DMA ANALOGIN DIGITALIN", 0);
+ }
+
+ if (devc->model_data == NULL)
+ {
+ cmn_err (CE_CONT, "Internal error: No model data\n");
+ return 0;
+ }
+
+ mask = devc->inportmask;
+
+ if (devc->model_data->flags & MF_SPDIFOUT)
+ {
+ if ((ret = mixer_ext_create_control (dev, group,
+ 8, envy24ht_set_route,
+ MIXT_ENUM,
+ "ENVY24_SPDIFOUT", 3,
+ MIXF_READABLE |
+ MIXF_WRITEABLE)) < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * S/PDIF lowlevel driver
+ */
+/*ARGSUSED*/
+static int
+default_reprogram_device (void *_devc, void *_portc,
+ oss_digital_control * ctl, unsigned int mask)
+{
+ unsigned char c;
+ unsigned short cbits = 0;
+ envy24ht_devc *devc = _devc;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->low_mutex, flags);
+
+ cbits |= (ctl->rate_bits & 0x0f) << 12; /* Sample rate */
+
+ if (ctl->out_vbit == VBIT_ON)
+ cbits |= 0x8000; /* Turn on the V bit */
+
+ cbits |= ctl->cbitout[0] & 0x07; /* Consumer/pro, audio/data, copyright */
+ cbits |= (!!(ctl->cbitout[1] & 0x80)) << 11; /* Generation level */
+ cbits |= (ctl->cbitout[1] & 0x7f) << 4; /* Category code */
+ cbits |= (ctl->emphasis_type & 1) << 3; /* Pre-emphasis */
+
+ if (cbits != INW (devc->osdev, devc->mt_base + 0x3c))
+ {
+ c = INB (devc->osdev, devc->ccs_base + 0x07);
+ OUTB (devc->osdev, c & ~0x80, devc->ccs_base + 0x07); /* Disable S/PDIF transmitter */
+ OUTW (devc->osdev, cbits, devc->mt_base + 0x3c);
+ OUTB (devc->osdev, c | 0x80, devc->ccs_base + 0x07); /* (Re)enable S/PDIF transmitter */
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->low_mutex, flags);
+ return 0;
+}
+
+spdif_driver_t default_spdif_driver = {
+/* reprogram_device: */ default_reprogram_device,
+};
+
+
+static void
+setup_sample_rate (envy24ht_devc * devc)
+{
+ unsigned char bits;
+ int change = 0;
+
+ devc->speedbits = bits = speed_tab[devc->pending_speed_sel].speedbits;
+ if (devc->speed != speed_tab[devc->pending_speed_sel].speed)
+ change = 1;
+ devc->speed = devc->pending_speed =
+ speed_tab[devc->pending_speed_sel].speed;
+ mixer_devs[devc->mixer_dev]->modify_counter++;
+
+ if (change)
+ {
+ oss_spdif_setrate (&devc->spdc, devc->speed);
+
+ if (devc->model_data->svid == SSID_JULIA)
+ goto JULIA;
+
+ if (devc->syncsource != 0) /* External sync */
+ bits |= 0x10;
+
+ if (devc->speed > 120000)
+ {
+ OUTB (devc->osdev, 0x08, devc->mt_base + 0x02); /* 128x I2S setup */
+ }
+ else
+ {
+ OUTB (devc->osdev, 0x00, devc->mt_base + 0x02); /* 256x I2S setup */
+ }
+
+ OUTB (devc->osdev, bits & 0x0f, devc->mt_base + 0x01); /* Sampling rate */
+JULIA:
+ if (devc->auxdrv->set_rate)
+ devc->auxdrv->set_rate (devc);
+ }
+}
+
+static int
+envy24ht_set_control (int dev, int ctrl, unsigned int cmd, int value)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+ oss_native_word flags;
+
+ if (cmd == SNDCTL_MIX_READ)
+ switch (ctrl)
+ {
+ case 1:
+ return devc->pending_speed_sel;
+ break;
+
+ case 2:
+ return devc->syncsource;
+ break;
+
+ case 3:
+ return devc->use_src;
+ break;
+
+ case 5:
+ return devc->ratelock;
+ break;
+
+ case 6:
+ return devc->speed;
+ break;
+
+ case 7:
+ return 1;
+
+ default:
+ return OSS_EIO;
+ }
+
+ if (cmd == SNDCTL_MIX_WRITE)
+ switch (ctrl)
+ {
+ case 1:
+ if (value < 0 || value > devc->max_ratesel)
+ return OSS_EIO;
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ if (devc->configured_rate_sel != value)
+ {
+ devc->configured_rate_sel = value;
+ if (devc->open_count < 1)
+ {
+ devc->pending_speed_sel = devc->configured_rate_sel;
+ setup_sample_rate (devc);
+ }
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return devc->configured_rate_sel;
+ break;
+
+ case 2:
+ if (value < 0 || value > 2)
+ return OSS_EIO;
+ devc->syncsource = value;
+ if (devc->model_data->svid == SSID_JULIA)
+ devc->auxdrv->private1 (devc, value);
+ return devc->syncsource;
+ break;
+
+ case 3:
+ devc->use_src = !!value;
+ return devc->use_src;
+ break;
+
+ case 5:
+ return devc->ratelock = !!value;
+ break;
+
+ case 6:
+ return devc->speed;
+ break;
+
+ case 7:
+ return 1;
+ break;
+
+ default:
+ return OSS_EIO;
+ }
+
+ return OSS_EINVAL;
+}
+
+static int
+envy24ht_mix_init (int dev)
+{
+ envy24ht_devc *devc = mixer_devs[dev]->hw_devc;
+ int group, err, n;
+
+ if ((group =
+ mixer_ext_create_group_flags (dev, 0, "ENVY24", MIXF_FLAT)) < 0)
+ return group;
+
+ if ((err = create_peak_mixer (dev, devc, group)) < 0)
+ return err;
+
+ if ((err = create_rout_mixer (dev, devc, group)) < 0)
+ return err;
+
+ n = devc->max_ratesel + 1;
+ if ((err = mixer_ext_create_control (dev, group,
+ 1, envy24ht_set_control,
+ MIXT_ENUM,
+ "ENVY24_RATE", n,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+ mixer_ext_set_strings (dev, err,
+ "8000 9600 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 176400 192000", 0);
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 2, envy24ht_set_control,
+ MIXT_ENUM,
+ "ENVY24_SYNC", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 3, envy24ht_set_control,
+ MIXT_ONOFF,
+ "ENVY24_SRC", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 5, envy24ht_set_control,
+ MIXT_ONOFF,
+ "ENVY24_RATELOCK", 2,
+ MIXF_READABLE | MIXF_WRITEABLE)) < 0)
+ return err;
+
+ if ((err = mixer_ext_create_control (dev, group,
+ 6, envy24ht_set_control,
+ MIXT_VALUE,
+ "ENVY24_ACTRATE", 192000,
+ MIXF_READABLE)) < 0)
+ return err;
+
+ if (devc->auxdrv->mixer_init)
+ if ((err = devc->auxdrv->mixer_init (devc, dev, 0)) < 0)
+ return err;
+
+ if ((err = oss_spdif_mix_init (&devc->spdc)) < 0)
+ return err;
+
+ return 0;
+}
+
+static int
+eeprom_read (envy24ht_devc * devc, int pos)
+{
+ int i, status;
+
+ for (i = 0; i < 0x10000; i++)
+ {
+ status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+
+ OUTB (devc->osdev, pos, devc->ccs_base + 0x11); /* Offset */
+ OUTB (devc->osdev, 0xa0, devc->ccs_base + 0x10); /* EEPROM read */
+
+ for (i = 0; i < 0x10000; i++)
+ {
+ status = INB (devc->osdev, devc->ccs_base + 0x13);
+ if (!(status & 1))
+ break;
+
+ }
+
+ oss_udelay (1);
+ return INB (devc->osdev, devc->ccs_base + 0x12);
+}
+
+static void
+envy24pt_init (envy24ht_devc * devc)
+{
+ int gpio;
+
+ gpio = INW (devc->osdev, devc->ccs_base + 0x14);
+ gpio |= INB (devc->osdev, devc->ccs_base + 0x1e) << 16;
+
+#if 0
+#define GPBIT(nn) !!(1<<nn)
+ cmn_err (CE_CONT, "GPIO=%06x\n", gpio);
+ cmn_err (CE_CONT, "With SPDIF_IN 'optical' connector: %d\n", GPBIT (1));
+ cmn_err (CE_CONT, "With SPDIF_IN 'coaxial' connector: %d\n", GPBIT (2));
+
+ cmn_err (CE_CONT, "AC97 with stereo DAC for 7.1: %d\n", !GPBIT (8));
+ cmn_err (CE_CONT, "Extra ADC/DAC connected to S/PDIF pins: %d\n",
+ GPBIT (9));
+ cmn_err (CE_CONT, "S/PDIF connected to RDMA1: %d\n", !GPBIT (10));
+ cmn_err (CE_CONT, "Smart 5.1 function supported: %d\n", GPBIT (11));
+ cmn_err (CE_CONT, "De-POP function supported: %d\n", !GPBIT (12));
+ cmn_err (CE_CONT, "PDMA4 DAC: 0=cs4321 1=WM8728: %d\n", GPBIT (13));
+#endif
+
+ OUTB (devc->osdev, 0x00, devc->ccs_base + 0x04); /* System configuration */
+ OUTB (devc->osdev, 0x02, devc->ccs_base + 0x05); /* AC-link configuration */
+ OUTB (devc->osdev, 0x00, devc->ccs_base + 0x06); /* I2S configuration */
+ OUTB (devc->osdev, 0x83, devc->ccs_base + 0x07); /* S/PDIF configuration */
+
+ /* TODO: GPIO initialization */
+}
+
+static void
+julia_eeprom_init (envy24ht_devc * devc)
+{
+ OUTB (devc->osdev, 0x39, devc->ccs_base + 0x04); /* System configuration */
+ OUTB (devc->osdev, 0x80, devc->ccs_base + 0x05); /* AC-link configuration */
+ OUTB (devc->osdev, 0x78, devc->ccs_base + 0x06); /* I2S configuration */
+ OUTB (devc->osdev, 0xc3, devc->ccs_base + 0x07); /* S/PDIF configuration */
+
+ OUTW (devc->osdev, 0xffff, devc->ccs_base + 0x18); /* GPIO direction */
+ OUTW (devc->osdev, 0x0000, devc->ccs_base + 0x16); /* GPIO write mask */
+ OUTW (devc->osdev, 0x801A, devc->ccs_base + 0x14); /* Initital bit state */
+}
+
+static int
+init_eeprom_v2 (envy24ht_devc * devc)
+{
+ unsigned char *eeprom = (unsigned char *) &devc->eeprom;
+
+ OUTB (devc->osdev, eeprom[6], devc->ccs_base + 0x04);
+ OUTB (devc->osdev, eeprom[7], devc->ccs_base + 0x05);
+ OUTB (devc->osdev, eeprom[8], devc->ccs_base + 0x06);
+ OUTB (devc->osdev, eeprom[9], devc->ccs_base + 0x07);
+
+ OUTB (devc->osdev, eeprom[10], devc->ccs_base + 0x18);
+ OUTB (devc->osdev, eeprom[11], devc->ccs_base + 0x19);
+ OUTB (devc->osdev, eeprom[12], devc->ccs_base + 0x1a);
+
+ OUTB (devc->osdev, eeprom[13], devc->ccs_base + 0x16);
+ OUTB (devc->osdev, eeprom[14], devc->ccs_base + 0x17);
+ OUTB (devc->osdev, eeprom[15], devc->ccs_base + 0x1f);
+
+ OUTB (devc->osdev, eeprom[16], devc->ccs_base + 0x14);
+ OUTB (devc->osdev, eeprom[17], devc->ccs_base + 0x15);
+ OUTB (devc->osdev, eeprom[18], devc->ccs_base + 0x1e);
+ return 1;
+}
+
+static int
+load_eeprom (envy24ht_devc * devc)
+{
+ int status, i, check;
+ unsigned char *eeprom = (unsigned char *) &devc->eeprom, c;
+ static const char resolutions[4] = { 16, 18, 20, 24 };
+
+ c = 0;
+
+ status = INB (devc->osdev, devc->ccs_base + 0x13);
+
+ if (!(status & 0x80))
+ return 0; /* No EEPROM */
+
+ devc->eeprom.bSize = sizeof (devc->eeprom); /* Guess the size */
+
+ for (i = 0; i < devc->eeprom.bSize; i++)
+ {
+ eeprom[i] = eeprom_read (devc, i);
+ eeprom[i] = eeprom_read (devc, i);
+
+ if (devc->eeprom.bSize > sizeof (devc->eeprom))
+ devc->eeprom.bSize = sizeof (devc->eeprom);
+ }
+#if 1
+ DDB (cmn_err (CE_CONT, "EEPROM="));
+ for (i = 0; i < devc->eeprom.bSize; i++)
+ DDB (cmn_err (CE_CONT, "0x%02x, ", eeprom[i]));
+ DDB (cmn_err (CE_CONT, "\n"));
+#endif
+
+ check = 0;
+ for (i = 0; i < 4; i++)
+ {
+ check <<= 8;
+ check |= eeprom[i];
+ }
+
+ if (check != devc->model_data->svid)
+ cmn_err (CE_CONT,
+ "Envy24 WARNING: Possible EEPROM read error %08x != %08x\n",
+ check, devc->model_data->svid);
+
+ DDB (cmn_err (CE_CONT, "EEPROM version %d\n", devc->eeprom.bVersion));
+
+ if (devc->eeprom.bVersion == 2)
+ {
+ return init_eeprom_v2 (devc);
+ }
+
+ /* Init the controller registers based on the EEPROM data */
+
+ OUTB (devc->osdev, devc->eeprom.bCodecConfig, devc->ccs_base + 0x04);
+ OUTB (devc->osdev, devc->eeprom.bACLinkConfig, devc->ccs_base + 0x05);
+ OUTB (devc->osdev, devc->eeprom.bI2SID, devc->ccs_base + 0x06);
+ OUTB (devc->osdev, devc->eeprom.bSpdifConfig, devc->ccs_base + 0x07);
+
+ /* GPIO ports */
+
+ OUTB (devc->osdev, devc->eeprom.bGPIODirection2, devc->ccs_base + 0x18);
+ OUTB (devc->osdev, devc->eeprom.bGPIODirection1, devc->ccs_base + 0x19);
+ OUTB (devc->osdev, devc->eeprom.bGPIODirection0, devc->ccs_base + 0x1a);
+
+ OUTB (devc->osdev, devc->eeprom.bGPIOInitMask2, devc->ccs_base + 0x14);
+ OUTB (devc->osdev, devc->eeprom.bGPIOInitMask1, devc->ccs_base + 0x15);
+ OUTB (devc->osdev, devc->eeprom.bGPIOInitMask0, devc->ccs_base + 0x1f);
+
+ OUTB (devc->osdev, devc->eeprom.bGPIOInitState2, devc->ccs_base + 0x14);
+ OUTB (devc->osdev, devc->eeprom.bGPIOInitState1, devc->ccs_base + 0x15);
+ OUTB (devc->osdev, devc->eeprom.bGPIOInitState0, devc->ccs_base + 0x1e);
+
+#if 1
+ DDB (cmn_err (CE_CONT, "GPIO=%02x%02x%02x (%02x%02x%02x, %02x%02x%02x)\n",
+ devc->eeprom.bGPIOInitState2,
+ devc->eeprom.bGPIOInitState1,
+ devc->eeprom.bGPIOInitState0,
+ devc->eeprom.bGPIODirection2,
+ devc->eeprom.bGPIODirection1,
+ devc->eeprom.bGPIODirection0,
+ devc->eeprom.bGPIOInitMask2,
+ devc->eeprom.bGPIOInitMask1, devc->eeprom.bGPIOInitMask0));
+
+ c = devc->eeprom.bCodecConfig;
+ switch ((c >> 6) % 0x03)
+ {
+ case 0:
+ DDB (cmn_err (CE_CONT, "24.576MHz crystal\n"));
+ break;
+ case 1:
+ DDB (cmn_err (CE_CONT, "49.152MHz crystal\n"));
+ break;
+ default:
+ DDB (cmn_err (CE_CONT, "Unknown crystal frequency\n"));
+ }
+
+ if (c & 0x20)
+ {
+ DDB (cmn_err (CE_CONT, "Has MPU401 UART\n"));
+ }
+ else
+ {
+ DDB (cmn_err (CE_CONT, "No MPU401 UART\n"));
+ }
+ DDB (cmn_err
+ (CE_CONT, "%d stereo ADC pairs connected\n", ((c >> 2) & 0x03) + 1));
+ DDB (cmn_err (CE_CONT, "%d stereo DAC pairs connected\n", (c & 0x03) + 1));
+
+ c = devc->eeprom.bACLinkConfig;
+ DDB (cmn_err
+ (CE_CONT, "Converter type: %s\n", (c & 0x80) ? "I2S" : "AC97"));
+ if (!(c & 0x80))
+ {
+ if (!(devc->model_data->flags & MF_NOAC97))
+ devc->codec_type = CODEC_AC97;
+
+ DDB (cmn_err (CE_NOTE,
+ "AC link connection mode type: %s\n",
+ (c & 0x02) ? "packed" : "split"));
+ }
+ else
+ {
+ c = devc->eeprom.bI2SID;
+
+ DDB (cmn_err (CE_CONT, "I2C codec has volume control/mute: %s\n",
+ (c % 0x80) ? "YES" : "NO"));
+ DDB (cmn_err (CE_CONT, "I2C codec has 96 KHz S/R support: %s\n",
+ (c % 0x40) ? "YES" : "NO"));
+ DDB (cmn_err (CE_CONT, "I2C codec has 192 KHz S/R support: %s\n",
+ (c % 0x08) ? "YES" : "NO"));
+
+ DDB (cmn_err (CE_CONT,
+ "Converter resolution %d bits\n",
+ resolutions[(c >> 4) & 0x03]));
+ }
+
+ c = INB (devc->osdev, devc->ccs_base + 0x07);
+ DDB (cmn_err (CE_CONT,
+ "Internal S/PDIF out implemented: %s\n",
+ (c & 0x40) ? "YES" : "NO"));
+ DDB (cmn_err
+ (CE_CONT, "Internal S/PDIF out enabled: %s\n",
+ (c & 0x80) ? "YES" : "NO"));
+ DDB (cmn_err
+ (CE_CONT, "External S/PDIF out implemented: %s\n",
+ (c & 0x01) ? "YES" : "NO"));
+ DDB (cmn_err
+ (CE_CONT, "S/PDIF input present: %s\n", (c & 0x02) ? "YES" : "NO"));
+ DDB (cmn_err (CE_CONT, "S/PDIF chip IDs %x\n", (c >> 2) & 0x0f));
+#endif
+
+ return 1;
+}
+
+/*ARGSUSED*/
+static void
+dump_regs (envy24ht_devc * devc, char *lbl)
+{
+#if 0
+ int i;
+
+ cmn_err (CE_CONT, "\nDump registers: %s\n", lbl);
+
+ for (i = 0; i < 0x20; i += 4)
+ {
+ if (!(i % (8 * 4)))
+ cmn_err (CE_CONT, "\nCCS%02x: ", i);
+ cmn_err (CE_CONT, "%08x ", INL (devc->osdev, devc->ccs_base + i));
+ }
+ cmn_err (CE_CONT, "\n");
+
+ for (i = 0; i < 0x80; i += 4)
+ {
+ if (!(i % (8 * 4)))
+ cmn_err (CE_CONT, "\nMT%02x: ", i);
+ cmn_err (CE_CONT, "%08x ", INL (devc->osdev, devc->mt_base + i));
+ }
+ cmn_err (CE_CONT, "\n");
+#endif
+}
+
+static int
+verify_rate (envy24ht_devc * devc, int arg)
+{
+ if (devc->codec_type == CODEC_AC97 && arg > 48000)
+ arg = 48000;
+ if (arg > 96000 && !(devc->model_data->flags & MF_192K))
+ arg = 96000;
+
+ return arg;
+}
+
+static int
+envy24ht_set_rate (int dev, int arg)
+{
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ int i, ix, diff, bestdiff;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+
+ if (arg == 0)
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return devc->pending_speed;
+ }
+
+ arg = verify_rate (devc, arg);
+/*
+ * Don't permit changing the sampling rate if we have multiple clients.
+ */
+ if (devc->open_count != 1 || devc->ratelock)
+ {
+ DDB (cmn_err (CE_CONT, "Can't set speed: open_count %d, ratelock %d\n",
+ devc->open_count, devc->ratelock));
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ if (arg != devc->pending_speed)
+ {
+ audio_engines[dev]->fixed_rate = devc->speed;
+ audio_engines[dev]->min_rate = devc->speed;
+ audio_engines[dev]->max_rate = devc->speed;
+ audio_engines[dev]->flags |= ADEV_FIXEDRATE;
+ }
+ else
+ {
+ audio_engines[dev]->min_rate = 8000;
+ audio_engines[dev]->max_rate = 192000;
+ audio_engines[dev]->flags &= ~ADEV_FIXEDRATE;
+ }
+ return devc->pending_speed;
+ }
+
+ if (portc->dev_flags & DF_SPDIF)
+ {
+ /* Allow only supported S/PDIF rates */
+ if (arg < 32000)
+ arg = 32000;
+ if (arg > 96000)
+ arg = 96000;
+ }
+
+ ix = 9;
+ bestdiff = 1000000;
+ i = 0;
+ audio_engines[dev]->flags &= ~ADEV_FIXEDRATE;
+
+ while (speed_tab[i].speed != -1)
+ {
+ diff = speed_tab[i].speed - arg;
+ if (diff < 0)
+ diff = -diff;
+ if (diff < bestdiff)
+ {
+ ix = i;
+ bestdiff = diff;
+ }
+ i++;
+ }
+
+ devc->pending_speed = speed_tab[ix].speed;
+ devc->pending_speed_sel = ix;
+ /*cmn_err(CE_CONT, "Requested sampling rate %d, got %d\n", arg, devc->pending_speed); */
+
+ //setup_sample_rate (devc);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return devc->pending_speed;
+}
+
+static short
+envy24ht_set_channels (int dev, short arg)
+{
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ oss_native_word flags;
+
+ if (arg == 0)
+ return portc->channels;
+
+ if (portc->dev_flags & DF_MULTICH)
+ {
+ int n = 2, ch, i, mask;
+
+ if (arg < 2)
+ arg = 2;
+
+ arg = ((arg + 1) / 2) * 2; /* Round to even number of channels */
+
+ if (arg > devc->model_data->nr_outs)
+ arg = devc->model_data->nr_outs;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+
+ devc->busy_play_channels &= ~portc->used_chmask;
+
+ for (ch = 2; ch <= arg; ch += 2)
+ {
+ mask = 0;
+
+ for (i = 0; i < ch; i++)
+ mask |= (1 << i);
+
+ if (devc->busy_play_channels & mask)
+ break;
+ n = ch;
+ }
+
+ portc->channels = n;
+ portc->used_chmask = 0;
+ for (i = 0; i < n; i++)
+ portc->used_chmask |= (1 << i);
+
+ devc->busy_play_channels |= portc->used_chmask;
+ /* MT19: Channel allocation */
+ OUTB (devc->osdev, 4 - n / 2, devc->mt_base + 0x19);
+ /* cmn_err(CE_CONT, "%d channels: MT19=%02x\n", n, INB(devc->osdev, devc->mt_base+0x19)); */
+
+ if (portc->channels == 6)
+ {
+ /* The fragment size must be a multiple of 6 */
+ audio_engines[dev]->min_block = 4 * 288;
+ audio_engines[dev]->max_block = 4 * 288;
+
+ }
+ else
+ {
+ audio_engines[dev]->min_block = 0;
+ audio_engines[dev]->max_block = 0;
+ }
+
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return portc->channels;
+ }
+
+ return portc->channels = 2;
+}
+
+/*ARGSUSED*/
+static int
+ac3_write (adev_t * adev,
+ dmap_t * dmap,
+ void *frombuf, void *tobuf, int maxspace, int *fromlen, int *tolen)
+{
+/*
+ * This routine takes AC3 input 16 bits at time and packs them to
+ * 32 bit words.
+ */
+ int i, l;
+ unsigned short *ip;
+ unsigned int *op;
+
+ l = *fromlen * 2;
+ if (l > maxspace)
+ {
+ l = maxspace;
+ }
+
+ *tolen = l;
+ *fromlen = l / 2;
+ l /= 4;
+
+ ip = frombuf;
+ op = tobuf;
+
+ for (i = 0; i < l; i++)
+ {
+ *op++ = (*ip++) << 16;
+ }
+
+ return 0;
+}
+
+static unsigned int
+envy24ht_set_format (int dev, unsigned int arg)
+{
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+
+ if (arg == 0)
+ return portc->fmt;
+
+ if (arg == AFMT_AC3 && (portc->dev_flags & DF_AC3))
+ {
+ audio_engines[dev]->dmap_out->device_write = ac3_write;
+ return portc->fmt = AFMT_AC3;
+ }
+ audio_engines[dev]->dmap_out->device_write = NULL;
+ return portc->fmt = SUPPORTED_FORMAT;
+}
+
+static int
+envy24ht_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
+{
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+
+ switch (cmd)
+ {
+ case SNDCTL_DSP_GET_CHNORDER:
+ *(oss_uint64_t *) arg = CHNORDER_NORMAL;
+ return 0;
+ }
+
+ if (portc->dev_flags & DF_SPDIF)
+ {
+ int ret;
+ ret = oss_spdif_ioctl (&devc->spdc, portc->open_mode, cmd, arg);
+ if (ret != SPDIF_NOIOCTL)
+ return ret;
+ }
+
+ if (devc->auxdrv->audio_ioctl)
+ return devc->auxdrv->audio_ioctl (devc, portc, cmd, arg);
+ return OSS_EINVAL;
+}
+
+static void envy24ht_trigger (int dev, int state);
+
+static void
+envy24ht_reset (int dev)
+{
+ envy24ht_trigger (dev, 0);
+}
+
+/*ARGSUSED*/
+static int
+envy24ht_open_input (int dev, int mode, int open_flags)
+{
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ adev_p adev = audio_engines[dev];
+ oss_native_word flags;
+
+ if (mode & OPEN_WRITE)
+ {
+ cmn_err (CE_CONT, "Playback is not possible with %s\n", adev->devnode);
+ return OSS_ENOTSUP;
+ }
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+
+ if (portc->open_mode || (devc->busy_rec_channels & portc->chmask))
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return OSS_EBUSY;
+ }
+ portc->open_mode = mode;
+ devc->open_count++;
+ if (devc->open_count == 1)
+ {
+ devc->pending_speed_sel = devc->configured_rate_sel;
+ }
+
+ if (portc->dev_flags & DF_SPDIF)
+ oss_spdif_open (&devc->spdc, mode);
+
+ portc->used_chmask = portc->chmask;
+ devc->busy_rec_channels |= portc->chmask;
+
+ if (!devc->use_src)
+ adev->flags |= ADEV_NOSRC;
+ else
+ adev->flags &= ~ADEV_NOSRC;
+
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+envy24ht_open_output (int dev, int mode, int open_flags)
+{
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ oss_native_word flags;
+ adev_p adev = audio_engines[dev];
+
+ if (mode & OPEN_READ)
+ {
+ cmn_err (CE_CONT, "Recording is not possible with %s\n", adev->devnode);
+ return OSS_ENOTSUP;
+ }
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+
+ if (portc->open_mode || (devc->busy_play_channels & portc->chmask))
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return OSS_EBUSY;
+ }
+
+ portc->open_mode = mode;
+ portc->used_chmask = portc->chmask;
+ devc->busy_play_channels |= portc->chmask;
+ audio_engines[dev]->dmap_out->device_write = NULL;
+
+ devc->open_count++;
+ if (devc->open_count == 1)
+ {
+ devc->pending_speed_sel = devc->configured_rate_sel;
+ }
+
+ if (portc->dev_flags & DF_SPDIF)
+ oss_spdif_open (&devc->spdc, mode);
+
+ if (!devc->use_src)
+ adev->flags |= ADEV_NOSRC;
+ else
+ adev->flags &= ~ADEV_NOSRC;
+
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return 0;
+}
+
+static void
+envy24ht_close (int dev, int mode)
+{
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ devc->open_count--;
+
+ if (portc->open_mode & OPEN_READ)
+ devc->busy_rec_channels &= ~portc->used_chmask;
+ if (portc->open_mode & OPEN_WRITE)
+ devc->busy_play_channels &= ~portc->used_chmask;
+ portc->open_mode = 0;
+
+ if (portc->dev_flags & DF_MULTICH)
+ {
+ OUTB (devc->osdev, 0x03, devc->mt_base + 0x19); /* Channel allocation */
+ portc->chmask = 0x003; /* Just the front channels */
+ }
+
+ if (portc->dev_flags & DF_SPDIF)
+ oss_spdif_close (&devc->spdc, mode);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+}
+
+/*ARGSUSED*/
+static void
+envy24ht_output_block (int dev, oss_native_word buf, int count, int fragsize,
+ int intrflag)
+{
+}
+
+/*ARGSUSED*/
+static void
+envy24ht_start_input (int dev, oss_native_word buf, int count, int fragsize,
+ int intrflag)
+{
+}
+
+static void
+envy24ht_trigger (int dev, int state)
+{
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ unsigned char enable, intrmask;
+ oss_native_word flags;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ enable = INB (devc->osdev, devc->mt_base + 0x18);
+ intrmask = INB (devc->osdev, devc->mt_base + 0x03);
+
+ if (portc->state_bits == state) /* No change */
+ {
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+ return;
+ }
+ portc->state_bits = state;
+
+ if (portc->open_mode & OPEN_WRITE)
+ {
+ if (state & PCM_ENABLE_OUTPUT)
+ {
+ enable |= portc->mask;
+ intrmask &= ~portc->mask;
+ }
+ else
+ {
+ enable &= ~portc->mask;
+ intrmask |= portc->mask;
+ }
+ }
+
+ if (portc->open_mode & OPEN_READ)
+ {
+ if (state & PCM_ENABLE_INPUT)
+ {
+ enable |= portc->mask;
+ intrmask &= ~portc->mask;
+ }
+ else
+ {
+ enable &= ~portc->mask;
+ intrmask |= portc->mask;
+ }
+ }
+ OUTB (devc->osdev, enable, devc->mt_base + 0x18);
+ OUTB (devc->osdev, intrmask, devc->mt_base + 0x03);
+
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+
+ if (state)
+ dump_regs (devc, "trigger");
+}
+
+/*ARGSUSED*/
+static int
+envy24ht_prepare_for_input (int dev, int bsize, int bcount)
+{
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ dmap_p dmap = audio_engines[dev]->dmap_in;
+ int buffsize, fragsize;
+ oss_native_word flags;
+
+ if (audio_engines[dev]->flags & ADEV_NOINPUT)
+ return OSS_EACCES;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ setup_sample_rate (devc);
+ buffsize = dmap->bytes_in_use / 4 - 1;
+ fragsize = dmap->fragment_size / 4 - 1;
+
+ OUTL (devc->osdev, dmap->dmabuf_phys, portc->base + 0x00);
+ OUTW (devc->osdev, buffsize, portc->base + 0x04);
+ OUTW (devc->osdev, fragsize, portc->base + 0x06);
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+envy24ht_prepare_for_output (int dev, int bsize, int bcount)
+{
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ dmap_p dmap = audio_engines[dev]->dmap_out;
+ int buffsize, fragsize;
+ oss_native_word flags;
+
+ if (audio_engines[dev]->flags & ADEV_NOOUTPUT)
+ return OSS_EACCES;
+
+ MUTEX_ENTER_IRQDISABLE (devc->mutex, flags);
+ setup_sample_rate (devc);
+ buffsize = dmap->bytes_in_use / 4 - 1;
+ fragsize = dmap->fragment_size / 4 - 1;
+
+ if (portc->dev_flags & DF_MULTICH)
+ {
+ /* Multi ch device */
+ OUTL (devc->osdev, dmap->dmabuf_phys, devc->mt_base + 0x10);
+ OUTL (devc->osdev, buffsize, devc->mt_base + 0x14);
+ OUTL (devc->osdev, fragsize, devc->mt_base + 0x1c);
+ }
+ else
+ {
+ OUTL (devc->osdev, dmap->dmabuf_phys, portc->base + 0x00);
+ OUTW (devc->osdev, buffsize, portc->base + 0x04);
+ OUTW (devc->osdev, fragsize, portc->base + 0x06);
+ }
+ MUTEX_EXIT_IRQRESTORE (devc->mutex, flags);
+
+ return 0;
+}
+
+/*ARGSUSED*/
+static int
+envy24ht_get_buffer_pointer (int dev, dmap_t * dmap, int direction)
+{
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ envy24ht_devc *devc;
+ int pos;
+
+ devc = audio_engines[dev]->devc;
+ pos = (INW (devc->osdev, portc->base + 0x04) + 1) * 4;
+ return dmap->bytes_in_use - pos;
+}
+
+static int
+envy24ht_sync_control(int dev, int event, int mode)
+{
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+ envy24ht_portc *portc = audio_engines[dev]->portc;
+ unsigned char enable, intrmask;
+ oss_native_word flags;
+ MUTEX_ENTER_IRQDISABLE(devc->mutex, flags);
+ if(event == SYNC_PREPARE)
+ {
+ devc->syncstart_mask |= portc->mask;
+ portc->state_bits = mode;
+ }
+ else if(event == SYNC_TRIGGER)
+ {
+ if(devc->syncstart_mask)
+ {
+ enable = INB (devc->osdev, devc->mt_base + 0x18);
+ intrmask = INB (devc->osdev, devc->mt_base + 0x03);
+ enable |= devc->syncstart_mask;
+ intrmask &= ~devc->syncstart_mask;
+ OUTB (devc->osdev, enable, devc->mt_base + 0x18);
+ OUTB (devc->osdev, intrmask, devc->mt_base + 0x03);
+ devc->syncstart_mask = 0;
+ }
+ }
+ MUTEX_EXIT_IRQRESTORE(devc->mutex, flags);
+ return 0;
+}
+
+#if 0
+static int
+envy24ht_check_output (int dev)
+{
+ int pos;
+ envy24ht_devc *devc = audio_engines[dev]->devc;
+
+ pos = envy24ht_get_buffer_pointer (dev, audio_engines[dev]->dmap_out, 0);
+
+ cmn_err (CE_CONT,
+ "Envy24ht: Output timeout on device %d (%d, %02x, %02x)\n", dev,
+ pos, INB (devc->osdev, devc->ccs_base + 0x02), INB (devc->osdev,
+ devc->
+ ccs_base +
+ 0x00));
+ return OSS_EIO;
+}
+#endif
+
+static audiodrv_t envy24ht_output_driver = {
+ envy24ht_open_output,
+ envy24ht_close,
+ envy24ht_output_block,
+ envy24ht_start_input,
+ envy24ht_ioctl,
+ envy24ht_prepare_for_input,
+ envy24ht_prepare_for_output,
+ envy24ht_reset,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ envy24ht_trigger,
+ envy24ht_set_rate,
+ envy24ht_set_format,
+ envy24ht_set_channels,
+ NULL,
+ NULL,
+ NULL, /* check input */
+ NULL, /* envy24ht_check_output */
+ NULL, /* envy24ht_alloc_buffer */
+ NULL, /* envy24ht_free_buffer */
+ NULL,
+ NULL,
+ envy24ht_get_buffer_pointer,
+ NULL,
+ envy24ht_sync_control
+};
+
+
+static audiodrv_t envy24ht_input_driver = {
+ envy24ht_open_input,
+ envy24ht_close,
+ envy24ht_output_block,
+ envy24ht_start_input,
+ envy24ht_ioctl,
+ envy24ht_prepare_for_input,
+ envy24ht_prepare_for_output,
+ envy24ht_reset,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ envy24ht_trigger,
+ envy24ht_set_rate,
+ envy24ht_set_format,
+ envy24ht_set_channels,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* envy24ht_alloc_buffer */
+ NULL, /* envy24ht_free_buffer */
+ NULL,
+ NULL,
+ envy24ht_get_buffer_pointer,
+ NULL,
+ envy24ht_sync_control
+};
+
+static const int bindings[MAX_ODEV] = {
+ DSP_BIND_FRONT,
+ DSP_BIND_CENTER_LFE,
+ DSP_BIND_SURR,
+ DSP_BIND_REAR
+};
+
+static int
+init_play_device (envy24ht_devc * devc, int chmask, int offset,
+ unsigned char mask, char *name, int dev_flags,
+ char *port_id, char *devfile_name)
+{
+ int opts, dev, formats;
+ char tmp[80];
+ envy24ht_portc *portc = NULL;
+ int i;
+ adev_p adev;
+
+ sprintf (tmp, "%s %s out", devc->model_data->product, name);
+
+ if (devc->nr_outdevs >= MAX_ODEV)
+ {
+ cmn_err (CE_CONT, "Envy24ht: Too many audio devices\n");
+ return OSS_ENXIO;
+ }
+
+ opts = ADEV_AUTOMODE | ADEV_NOINPUT;
+
+ if (dev_flags & DF_SPDIF)
+ opts |= ADEV_SPECIAL;
+
+ formats = SUPPORTED_FORMAT;
+ if (dev_flags & DF_AC3)
+ formats |= AFMT_AC3;
+
+ if (dev_flags & DF_MULTICH)
+ opts |= ADEV_COLD;
+ else
+ opts |= ADEV_SPECIAL;
+
+ if ((dev = oss_install_audiodev_with_devname (OSS_AUDIO_DRIVER_VERSION,
+ devc->osdev,
+ devc->osdev,
+ tmp,
+ &envy24ht_output_driver,
+ sizeof (audiodrv_t),
+ opts, formats, devc, -1,
+ devfile_name)) < 0)
+ {
+ return dev;
+ }
+
+ if (devc->first_dev == -1)
+ {
+ devc->first_dev = dev;
+ audio_engines[dev]->outch_names = OUTCH_NAMES;
+ }
+ adev = audio_engines[dev];
+
+ portc = &devc->play_portc[devc->nr_outdevs];
+ for (i = 0; speed_tab[i].speed != -1; i++)
+ adev->rates[adev->nrates++] = speed_tab[i].speed;
+
+ portc->name = port_id;
+ audio_engines[dev]->portc = portc;
+ audio_engines[dev]->mixer_dev = devc->mixer_dev;
+ audio_engines[dev]->rate_source = devc->first_dev;
+ audio_engines[dev]->min_rate = 8000;
+ audio_engines[dev]->max_rate = 192000;
+ audio_engines[dev]->binding = bindings[devc->nr_outdevs];
+ if (dev_flags & DF_SPDIF)
+ audio_engines[dev]->binding = DSP_BIND_SPDIF;
+
+ portc->dev = dev;
+ portc->open_mode = 0;
+ portc->fmt = SUPPORTED_FORMAT;
+ portc->base = devc->mt_base + offset;
+ portc->mask = mask;
+ portc->dev_flags = dev_flags;
+ portc->chmask = chmask;
+ portc->state_bits = 0;
+ portc->direction = PCM_ENABLE_OUTPUT;
+
+ audio_engines[dev]->min_channels = 2;
+ audio_engines[dev]->max_channels = 2;
+
+ if (dev_flags & DF_SPDIF)
+ audio_engines[dev]->caps |= PCM_CAP_DIGITALOUT | DSP_CH_STEREO;
+ else
+ {
+ if (dev_flags & DF_MULTICH)
+ {
+ audio_engines[dev]->caps |= PCM_CAP_ANALOGOUT;
+ audio_engines[dev]->caps |= DSP_CH_STEREO;
+ audio_engines[dev]->min_channels = 2;
+ audio_engines[dev]->max_channels = devc->model_data->nr_outs;
+ }
+ else
+ audio_engines[dev]->caps |= PCM_CAP_ANALOGOUT | DSP_CH_STEREO;
+ }
+ devc->nr_outdevs++;
+
+ return dev;
+}
+
+static int
+init_rec_device (envy24ht_devc * devc, int chmask, int offset,
+ unsigned char mask, char *name, int dev_flags, char *devfile_name)
+{
+ int opts, dev, formats;
+ adev_p adev;
+ int i;
+ envy24ht_portc *portc = NULL;
+ char tmp[80];
+ sprintf (tmp, "%s %s in", devc->model_data->product, name);
+
+ if (devc->nr_indevs >= MAX_IDEV)
+ {
+ cmn_err (CE_CONT, "Envy24ht: Too many audio devices\n");
+ return OSS_ENXIO;
+ }
+
+ opts = ADEV_AUTOMODE | ADEV_NOOUTPUT | ADEV_COLD;
+
+ if (dev_flags & DF_SPDIF)
+ opts |= ADEV_SPECIAL;
+
+ formats = SUPPORTED_FORMAT;
+ if (dev_flags & DF_AC3)
+ formats |= AFMT_AC3;
+
+ if ((dev = oss_install_audiodev_with_devname (OSS_AUDIO_DRIVER_VERSION,
+ devc->osdev,
+ devc->osdev,
+ tmp,
+ &envy24ht_input_driver,
+ sizeof (audiodrv_t),
+ opts, formats, devc, -1,
+ devfile_name)) < 0)
+ {
+ return dev;
+ }
+
+ if (devc->first_dev == -1)
+ devc->first_dev = dev;
+ portc = &devc->rec_portc[devc->nr_indevs];
+ adev = audio_engines[dev];
+
+ for (i = 0; speed_tab[i].speed != -1; i++)
+ adev->rates[adev->nrates++] = speed_tab[i].speed;
+
+ audio_engines[dev]->portc = portc;
+ audio_engines[dev]->mixer_dev = devc->mixer_dev;
+ audio_engines[dev]->rate_source = devc->first_dev;
+ audio_engines[dev]->min_rate = 8000;
+ audio_engines[dev]->max_rate = 192000;
+
+ portc->dev = dev;
+ portc->name = "rec";
+ portc->open_mode = 0;
+ portc->base = devc->mt_base + offset;
+ portc->mask = mask;
+ portc->state_bits = 0;
+ portc->fmt = SUPPORTED_FORMAT;
+ portc->dev_flags = dev_flags;
+ portc->chmask = chmask;
+ portc->direction = PCM_ENABLE_INPUT;
+ if (dev_flags & DF_SPDIF)
+ audio_engines[dev]->caps |= PCM_CAP_DIGITALIN | DSP_CH_STEREO;
+ else
+ audio_engines[dev]->caps |= PCM_CAP_ANALOGIN | DSP_CH_STEREO;
+ devc->nr_indevs++;
+
+ return dev;
+}
+
+static void
+init_devices (envy24ht_devc * devc)
+{
+ int front_engine, rec_engine;
+
+ OUTB (devc->osdev, 0x03, devc->mt_base + 0x19); /* Channel allocation */
+ OUTB (devc->osdev, 0x00, devc->mt_base + 0x1b); /* Unpause ALL channels */
+
+ devc->first_dev = -1;
+
+ front_engine=init_play_device (devc, 0x003, 0x10, 0x01, devc->channel_names[0],
+ DF_MULTICH, "front", "");
+
+ if (devc->model_data->nr_outs > 2)
+ init_play_device (devc, 0x00c, 0x70, 0x10, devc->channel_names[1], 0,
+ "C/LFE", "");
+
+ if (devc->model_data->nr_outs > 4)
+ init_play_device (devc, 0x030, 0x60, 0x20, devc->channel_names[2], 0,
+ "side", "");
+
+ if (devc->model_data->nr_outs > 6)
+ init_play_device (devc, 0x0c0, 0x50, 0x40, devc->channel_names[3], 0,
+ "rear", "");
+
+ if (devc->model_data->flags & MF_SPDIFOUT)
+ {
+ init_play_device (devc, 0x300, 0x40, 0x80, "digital",
+ DF_SPDIF | DF_AC3, "spdif", "spdout");
+ }
+
+ rec_engine = init_rec_device (devc, 0x003, 0x20, 0x02, "analog", 0, "");
+
+ if (devc->model_data->flags & MF_SPDIFIN)
+ {
+ init_rec_device (devc, 0x00c, 0x30, 0x04, "digital", DF_SPDIF, "spdin");
+ }
+
+#ifdef CONFIG_OSS_VMIX
+ if (rec_engine < 0)
+ rec_engine = -1; /* Not available */
+
+ if (front_engine >= 0)
+ vmix_attach_audiodev(devc->osdev, front_engine, rec_engine, 0);
+#endif
+}
+
+static void
+install_ac97_mixer (envy24ht_devc * devc)
+{
+ int tmp;
+ tmp = 0;
+
+ DDB (cmn_err (CE_CONT, "Installing AC97 mixer\n"));
+
+ devc->mixer_dev =
+ ac97_install (&devc->ac97devc, devc->model_data->product, ac97_read,
+ ac97_write, devc, devc->osdev);
+ if (devc->mixer_dev < 0)
+ {
+ cmn_err (CE_CONT, "Envy24ht: Mixer install failed\n");
+ return;
+ }
+ ac97_init_ext (devc->mixer_dev, &devc->ac97devc, envy24ht_mix_init, 50);
+
+#if 1
+ /* AD1616 specific stuff. Check this if there is some other AC97 chip */
+ /* Maybe this should be moved to ac97.c in a way or another */
+
+ /* Turn surround dacs ON */
+ tmp = ac97_read (devc, 0x2a);
+ tmp &= ~0x3800;
+ ac97_write (devc, 0x2a, tmp);
+
+ tmp = ac97_read (devc, 0x5a);
+ tmp &= ~0x8000;
+ tmp |= 0x1800;
+ ac97_write (devc, 0x5a, tmp);
+#endif
+
+#if 0
+ for (tmp = 0; tmp < 0x3f; tmp += 2)
+ cmn_err (CE_CONT, "%02x: %04x\n", tmp, ac97_read (devc, tmp));
+ for (tmp = 0x5a; tmp < 0x5d; tmp += 2)
+ cmn_err (CE_CONT, "%02x: %04x\n", tmp, ac97_read (devc, tmp));
+ for (tmp = 0x7a; tmp < 0x7f; tmp += 2)
+ cmn_err (CE_CONT, "%02x: %04x\n", tmp, ac97_read (devc, tmp));
+#endif
+}
+
+int
+oss_envy24ht_attach (oss_device_t * osdev)
+{
+ envy24ht_devc *devc;
+ extern int envy24ht_model;
+ unsigned char pci_irq_line;
+ unsigned short pci_command, vendor, device;
+ unsigned int subvendor;
+ unsigned int pci_ioaddr, pci_ioaddr1;
+ int i, err;
+
+ char *name = "Generic ENVY24HT";
+
+ DDB (cmn_err (CE_CONT, "Entered Envy24HT probe routine\n"));
+
+ pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor);
+ pci_read_config_word (osdev, PCI_DEVICE_ID, &device);
+
+ if (vendor != ICENSEMBLE_VENDOR_ID || device != ICENSEMBLE_ENVY24HT_ID)
+ return 0;
+
+ if ((devc = PMALLOC (osdev, sizeof (*devc))) == NULL)
+ {
+ cmn_err (CE_WARN, "Out of memory\n");
+ return 0;
+ }
+
+ devc->osdev = osdev;
+ osdev->devc = devc;
+ MUTEX_INIT (osdev, devc->mutex, MH_DRV);
+ MUTEX_INIT (osdev, devc->low_mutex, MH_DRV + 1);
+
+ pci_read_config_dword (osdev, PCI_BASE_ADDRESS_0, &pci_ioaddr);
+ pci_read_config_dword (osdev, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
+ pci_read_config_word (osdev, PCI_COMMAND, &pci_command);
+ pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line);
+ pci_read_config_dword (osdev, 0x2c, &subvendor);
+
+ DDB (cmn_err (CE_CONT,
+ "Device found at I/O %x, %x\n", pci_ioaddr & ~3,
+ pci_ioaddr1 & ~3));
+
+ devc->subvendor = subvendor;
+
+ devc->ccs_base = MAP_PCI_IOADDR (devc->osdev, 0, pci_ioaddr) & ~0x3;
+ DDB (cmn_err (CE_CONT, "CCS base %x/%lx\n", pci_ioaddr, devc->ccs_base));
+
+ devc->mt_base = MAP_PCI_IOADDR (devc->osdev, 1, pci_ioaddr1) & ~0x3;
+ DDB (cmn_err (CE_CONT, "MT base %x/%lx\n", pci_ioaddr1, devc->mt_base));
+
+ /* Reset the chip */
+ OUTB (devc->osdev, 0x81, devc->ccs_base + 0x00);
+ oss_udelay (1000);
+
+ /* Release reset */
+ OUTB (devc->osdev, 0x00, devc->ccs_base + 0x00);
+ oss_udelay (1000);
+
+ pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
+ pci_write_config_word (osdev, PCI_COMMAND, pci_command);
+
+ devc->nr_outdevs = devc->nr_indevs = 0;
+ i = 0;
+
+ if ((envy24ht_model > -1)
+ && (envy24ht_model < (sizeof (models) / sizeof (card_spec)) - 1))
+ i = envy24ht_model;
+ else
+ while (models[i].svid != 0)
+ {
+ if (models[i].svid == subvendor)
+ {
+ name = models[i].product;
+ devc->model_data = &models[i];
+ DDB (cmn_err (CE_CONT, "Card id '%s'\n", name));
+
+ break;
+ }
+
+ i++;
+ }
+
+ if (models[i].svid == 0)
+ {
+ cmn_err (CE_CONT, "Unknown device ID (%08x).\n", subvendor);
+ cmn_err (CE_CONT, "This card may not be supported (yet).\n");
+ i = 0; /* Assume AC97 based Envy23PT */
+ }
+
+ oss_register_device (osdev, name);
+
+ if (devc->model_data == NULL)
+ {
+ cmn_err (CE_CONT, "Envy24ht: This card was not recognized: %08x\n",
+ subvendor);
+ return 0;
+ }
+
+ /* Disable all interrupts */
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x01);
+ OUTB (devc->osdev, 0xff, devc->mt_base + 0x03);
+
+ if (devc->model_data->flags & MF_ENVY24PT)
+ {
+ devc->codec_type = CODEC_AC97;
+ envy24pt_init (devc);
+ }
+ else if (devc->model_data->svid == SSID_JULIA)
+ {
+ julia_eeprom_init (devc);
+ }
+ else
+ load_eeprom (devc);
+
+ devc->irq = pci_irq_line;
+ if ((err =
+ oss_register_interrupts (devc->osdev, 0, envy24htintr, NULL)) < 0)
+ {
+ cmn_err (CE_WARN, "Can't register interrupt handler, err=%d\n", err);
+ return 0;
+ }
+
+ i = 0;
+ devc->max_ratesel = 0;
+
+ while (speed_tab[i].speed != -1)
+ {
+ int rate = speed_tab[i].speed;
+
+ if (verify_rate (devc, rate) == rate)
+ devc->max_ratesel = i;
+
+ i++;
+ }
+
+ OUTB (devc->osdev, ~0x10, devc->ccs_base + 0x01); /* Enable audio interrupts */
+
+ if (devc->model_data->flags & MF_MIDI)
+ {
+ attach_midi (devc);
+ }
+ i = 0;
+ devc->max_ratesel = 0;
+
+ while (speed_tab[i].speed != -1)
+ {
+ int rate = speed_tab[i].speed;
+
+ if (verify_rate (devc, rate) == rate)
+ devc->max_ratesel = i;
+
+ i++;
+ }
+
+ devc->syncstart_mask = 0;
+ devc->speedbits = 0;
+ devc->speed = 0;
+ devc->pending_speed = 0;
+ devc->prev_speed = 0;
+ devc->pending_speed_sel = 9;
+ devc->configured_rate_sel = devc->pending_speed_sel;
+ devc->open_count = 0;
+ memcpy (devc->channel_names, channel_names, sizeof (channel_names));
+
+ devc->nr_play_channels = 10;
+ devc->nr_rec_channels = 10;
+#define setmask(m, b) m|=(1<<(b))
+
+ devc->inportmask = 0;
+ devc->outportmask = 0;
+ devc->busy_play_channels = 0;
+ devc->busy_rec_channels = 0;
+
+ for (i = 0; i < devc->model_data->nr_outs; i++)
+ setmask (devc->outportmask, i);
+ if (devc->model_data->flags & MF_SPDIFOUT)
+ {
+ setmask (devc->outportmask, 8); /* SPDIF */
+ setmask (devc->outportmask, 9); /* SPDIF */
+ }
+ for (i = 0; i < devc->model_data->nr_ins; i++)
+ setmask (devc->inportmask, i);
+ if (devc->model_data->flags & MF_SPDIFIN)
+ {
+ setmask (devc->inportmask, 8); /* SPDIF */
+ setmask (devc->inportmask, 9); /* SPDIF */
+ }
+
+ if (devc->model_data->auxdrv == NULL)
+ {
+ devc->auxdrv = &dummy_auxdrv;
+ }
+ else
+ {
+ devc->auxdrv = devc->model_data->auxdrv;
+ if (devc->auxdrv->card_init)
+ devc->auxdrv->card_init (devc);
+ }
+
+ if (devc->codec_type == CODEC_AC97)
+ install_ac97_mixer (devc);
+ else
+ {
+ if ((devc->mixer_dev = oss_install_mixer (OSS_MIXER_DRIVER_VERSION,
+ devc->osdev,
+ devc->osdev,
+ devc->model_data->
+ product,
+ &envy24ht_mixer_driver,
+ sizeof (mixer_driver_t),
+ devc)) >= 0)
+ {
+ int n = 50;
+
+ mixer_devs[devc->mixer_dev]->hw_devc = devc;
+ mixer_ext_set_init_fn (devc->mixer_dev, envy24ht_mix_init, n);
+ mixer_devs[devc->mixer_dev]->priority = 1; /* Possible default mixer candidate */
+ }
+ }
+
+ if (devc->model_data->flags & (MF_SPDIFOUT | MF_SPDIFIN))
+ {
+ int err;
+
+ if ((err = oss_spdif_install (&devc->spdc, devc->osdev,
+ &default_spdif_driver,
+ sizeof (spdif_driver_t), devc, NULL,
+ devc->mixer_dev, SPDF_OUT,
+ DIG_PASSTHROUGH | DIG_EXACT |
+ DIG_CBITOUT_LIMITED | DIG_VBITOUT |
+ DIG_PRO | DIG_CONSUMER)) != 0)
+ {
+ cmn_err (CE_CONT,
+ "S/PDIF driver install failed. error %d\n", err);
+ return 0;
+ }
+ }
+ OUTB (devc->osdev, ~0x10, devc->ccs_base + 0x01); /* Enable audio interrupts */
+ init_devices (devc);
+ setup_sample_rate (devc);
+
+
+ return 1;
+}
+
+int
+oss_envy24ht_detach (oss_device_t * osdev)
+{
+ envy24ht_devc *devc = osdev->devc;
+
+ if (oss_disable_device (osdev) < 0)
+ return 0;
+
+ /* Disable all interrupts */
+ OUTB (devc->osdev, 0xff, devc->ccs_base + 0x01);
+ /* disable DMA interrupt mask */
+ OUTB (devc->osdev, 0xff, devc->mt_base + 0x00);
+
+ /* Stop playback */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x18) & ~0x01,
+ devc->mt_base + 0x18);
+ oss_udelay (100);
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x18) & ~0x01,
+ devc->mt_base + 0x18);
+
+ /* Stop recording */
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x18) & ~0x04,
+ devc->mt_base + 0x18);
+ oss_udelay (100);
+ OUTB (devc->osdev, INB (devc->osdev, devc->mt_base + 0x18) & ~0x04,
+ devc->mt_base + 0x18);
+
+ unload_midi (devc);
+
+ if (devc->auxdrv->card_uninit)
+ devc->auxdrv->card_uninit(devc);
+
+ oss_unregister_interrupts (devc->osdev);
+
+ if (devc->model_data->flags & (MF_SPDIFOUT | MF_SPDIFIN))
+ {
+ oss_spdif_uninstall (&devc->spdc);
+ }
+
+ MUTEX_CLEANUP (devc->mutex);
+ MUTEX_CLEANUP (devc->low_mutex);
+ UNMAP_PCI_IOADDR (devc->osdev, 0);
+ UNMAP_PCI_IOADDR (devc->osdev, 1);
+
+ oss_unregister_device (osdev);
+ return 1;
+}
diff --git a/kernel/drv/oss_envy24ht/oss_envy24ht.man b/kernel/drv/oss_envy24ht/oss_envy24ht.man
new file mode 100644
index 0000000..f87d928
--- /dev/null
+++ b/kernel/drv/oss_envy24ht/oss_envy24ht.man
@@ -0,0 +1,24 @@
+NAME
+oss_envy24ht - VIA Envy24HT/PT audio driver.
+
+DESCRIPTION
+Open Sound System driver for Envy24HT, Envy24HT-S, Envy24PT based sound
+cards.
+
+Envy24HT device characteristics:
+ o 8/16 bit playback/record
+ o mono/stereo/4ch/5.1ch/7.1ch playback
+ o mono/sterero recording
+ o 8KHz to 192Khz sample rate.
+
+OPTIONS
+ o envy24ht_model = -1|0|1
+ Select the Model number if the card isn't autodetected
+ Values: 0 = Envy24ht 1=Envy24PT/HT-s compatible -1=Autodetect Default: -1
+
+FILES
+CONFIGFILEPATH/oss_envy24ht.conf Device configuration file
+
+AUTHOR
+4Front Technologies
+