add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
snd-au8810-objs := au8810.o
snd-au8820-objs := au8820.o
snd-au8830-objs := au8830.o
obj-$(CONFIG_SND_AU8810) += snd-au8810.o
obj-$(CONFIG_SND_AU8820) += snd-au8820.o
obj-$(CONFIG_SND_AU8830) += snd-au8830.o

View File

@@ -0,0 +1,16 @@
#include "au8810.h"
#include "au88x0.h"
static struct pci_device_id snd_vortex_ids[] = {
{PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,},
{0,}
};
#include "au88x0_core.c"
#include "au88x0_pcm.c"
#include "au88x0_mixer.c"
#include "au88x0_mpu401.c"
#include "au88x0_game.c"
#include "au88x0_eq.c"
#include "au88x0_a3d.c"
#include "au88x0_xtalk.c"
#include "au88x0.c"

View File

@@ -0,0 +1,224 @@
/*
Aureal Advantage Soundcard driver.
*/
#define CHIP_AU8810
#define CARD_NAME "Aureal Advantage 3D Sound Processor"
#define CARD_NAME_SHORT "au8810"
#define NR_ADB 0x10
#define NR_WT 0x00
#define NR_SRC 0x10
#define NR_A3D 0x10
#define NR_MIXIN 0x20
#define NR_MIXOUT 0x10
/* ADBDMA */
#define VORTEX_ADBDMA_STAT 0x27e00 /* read only, subbuffer, DMA pos */
#define POS_MASK 0x00000fff
#define POS_SHIFT 0x0
#define ADB_SUBBUF_MASK 0x00003000 /* ADB only. */
#define ADB_SUBBUF_SHIFT 0xc /* ADB only. */
#define VORTEX_ADBDMA_CTRL 0x27180 /* write only; format, flags, DMA pos */
#define OFFSET_MASK 0x00000fff
#define OFFSET_SHIFT 0x0
#define IE_MASK 0x00001000 /* interrupt enable. */
#define IE_SHIFT 0xc
#define DIR_MASK 0x00002000 /* Direction */
#define DIR_SHIFT 0xd
#define FMT_MASK 0x0003c000
#define FMT_SHIFT 0xe
// The ADB masks and shift also are valid for the wtdma, except if specified otherwise.
#define VORTEX_ADBDMA_BUFCFG0 0x27100
#define VORTEX_ADBDMA_BUFCFG1 0x27104
#define VORTEX_ADBDMA_BUFBASE 0x27000
#define VORTEX_ADBDMA_START 0x27c00 /* Which subbuffer starts */
#define VORTEX_ADBDMA_STATUS 0x27A90 /* stored at AdbDma->this_10 / 2 DWORD in size. */
/* WTDMA */
#define VORTEX_WTDMA_CTRL 0x27fd8 /* format, DMA pos */
#define VORTEX_WTDMA_STAT 0x27fe8 /* DMA subbuf, DMA pos */
#define WT_SUBBUF_MASK 0x3
#define WT_SUBBUF_SHIFT 0xc
#define VORTEX_WTDMA_BUFBASE 0x27fc0
#define VORTEX_WTDMA_BUFCFG0 0x27fd0
#define VORTEX_WTDMA_BUFCFG1 0x27fd4
#define VORTEX_WTDMA_START 0x27fe4 /* which subbuffer is first */
/* ADB */
#define VORTEX_ADB_SR 0x28400 /* Samplerates enable/disable */
#define VORTEX_ADB_RTBASE 0x28000
#define VORTEX_ADB_RTBASE_COUNT 173
#define VORTEX_ADB_CHNBASE 0x282b4
#define VORTEX_ADB_CHNBASE_COUNT 24
#define ROUTE_MASK 0xffff
#define SOURCE_MASK 0xff00
#define ADB_MASK 0xff
#define ADB_SHIFT 0x8
/* ADB address */
#define OFFSET_ADBDMA 0x00
#define OFFSET_SRCIN 0x40
#define OFFSET_SRCOUT 0x20
#define OFFSET_MIXIN 0x50
#define OFFSET_MIXOUT 0x30
#define OFFSET_CODECIN 0x70
#define OFFSET_CODECOUT 0x88
#define OFFSET_SPORTIN 0x78 /* ch 0x13 */
#define OFFSET_SPORTOUT 0x90
#define OFFSET_SPDIFOUT 0x92 /* ch 0x14 check this! */
#define OFFSET_EQIN 0xa0
#define OFFSET_EQOUT 0x7e /* 2 routes on ch 0x11 */
#define OFFSET_XTALKOUT 0x66 /* crosstalk canceller (source) */
#define OFFSET_XTALKIN 0x96 /* crosstalk canceller (sink) */
#define OFFSET_A3DIN 0x70 /* ADB sink. */
#define OFFSET_A3DOUT 0xA6 /* ADB source. 2 routes per slice = 8 */
#define OFFSET_EFXIN 0x80 /* ADB sink. */
#define OFFSET_EFXOUT 0x68 /* ADB source. */
/* ADB route translate helper */
#define ADB_DMA(x) (x)
#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN)
#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
#define ADB_SPDIFOUT(x) (x + OFFSET_SPDIFOUT)
#define ADB_EQIN(x) (x + OFFSET_EQIN)
#define ADB_EQOUT(x) (x + OFFSET_EQOUT)
#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT) /* 0x10 A3D blocks */
#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
#define ADB_XTALKIN(x) (x + OFFSET_XTALKIN)
#define ADB_XTALKOUT(x) (x + OFFSET_XTALKOUT)
#define MIX_OUTL 0xe
#define MIX_OUTR 0xf
#define MIX_INL 0x1e
#define MIX_INR 0x1f
#define MIX_DEFIGAIN 0x08 /* 0x8 => 6dB */
#define MIX_DEFOGAIN 0x08
/* MIXER */
#define VORTEX_MIXER_SR 0x21f00
#define VORTEX_MIXER_CLIP 0x21f80
#define VORTEX_MIXER_CHNBASE 0x21e40
#define VORTEX_MIXER_RTBASE 0x21e00
#define MIXER_RTBASE_SIZE 0x38
#define VORTEX_MIX_ENIN 0x21a00 /* Input enable bits. 4 bits wide. */
#define VORTEX_MIX_SMP 0x21c00 /* AU8820: 0x9c00 */
/* MIX */
#define VORTEX_MIX_INVOL_A 0x21000 /* in? */
#define VORTEX_MIX_INVOL_B 0x20000 /* out? */
#define VORTEX_MIX_VOL_A 0x21800
#define VORTEX_MIX_VOL_B 0x20800
#define VOL_MIN 0x80 /* Input volume when muted. */
#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */
/* SRC */
#define VORTEX_SRC_CHNBASE 0x26c40
#define VORTEX_SRC_RTBASE 0x26c00
#define VORTEX_SRCBLOCK_SR 0x26cc0
#define VORTEX_SRC_SOURCE 0x26cc4
#define VORTEX_SRC_SOURCESIZE 0x26cc8
/* Params
0x26e00 : 1 U0
0x26e40 : 2 CR
0x26e80 : 3 U3
0x26ec0 : 4 DRIFT1
0x26f00 : 5 U1
0x26f40 : 6 DRIFT2
0x26f80 : 7 U2 : Target rate, direction
*/
#define VORTEX_SRC_CONVRATIO 0x26e40
#define VORTEX_SRC_DRIFT0 0x26e80
#define VORTEX_SRC_DRIFT1 0x26ec0
#define VORTEX_SRC_DRIFT2 0x26f40
#define VORTEX_SRC_U0 0x26e00
#define U0_SLOWLOCK 0x200
#define VORTEX_SRC_U1 0x26f00
#define VORTEX_SRC_U2 0x26f80
#define VORTEX_SRC_DATA 0x26800 /* 0xc800 */
#define VORTEX_SRC_DATA0 0x26000
/* FIFO */
#define VORTEX_FIFO_ADBCTRL 0x16100 /* Control bits. */
#define VORTEX_FIFO_WTCTRL 0x16000
#define FIFO_RDONLY 0x00000001
#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */
#define FIFO_VALID 0x00000010
#define FIFO_EMPTY 0x00000020
#define FIFO_U0 0x00001000 /* Unknown. */
#define FIFO_U1 0x00010000
#define FIFO_SIZE_BITS 5
#define FIFO_SIZE (1<<FIFO_SIZE_BITS) // 0x20
#define FIFO_MASK (FIFO_SIZE-1) //0x1f /* at shift left 0xc */
//#define FIFO_MASK 0x1f /* at shift left 0xb */
//#define FIFO_SIZE 0x20
#define FIFO_BITS 0x03880000
#define VORTEX_FIFO_ADBDATA 0x14000
#define VORTEX_FIFO_WTDATA 0x10000
/* CODEC */
#define VORTEX_CODEC_CTRL 0x29184
#define VORTEX_CODEC_EN 0x29190
#define EN_CODEC0 0x00000300
#define EN_AC98 0x00000c00 /* Modem AC98 slots. */
#define EN_CODEC1 0x00003000
#define EN_CODEC (EN_CODEC0 | EN_CODEC1)
#define EN_SPORT 0x00030000
#define EN_SPDIF 0x000c0000
#define VORTEX_CODEC_CHN 0x29080
#define VORTEX_CODEC_IO 0x29188
/* SPDIF */
#define VORTEX_SPDIF_FLAGS 0x2205c
#define VORTEX_SPDIF_CFG0 0x291D0
#define VORTEX_SPDIF_CFG1 0x291D4
#define VORTEX_SPDIF_SMPRATE 0x29194
/* Sample timer */
#define VORTEX_SMP_TIME 0x29198
#define VORTEX_MODEM_CTRL 0x291ac
/* IRQ */
#define VORTEX_IRQ_SOURCE 0x2a000 /* Interrupt source flags. */
#define VORTEX_IRQ_CTRL 0x2a004 /* Interrupt source mask. */
#define VORTEX_STAT 0x2a008 /* Status */
#define VORTEX_CTRL 0x2a00c
#define CTRL_MIDI_EN 0x00000001
#define CTRL_MIDI_PORT 0x00000060
#define CTRL_GAME_EN 0x00000008
#define CTRL_GAME_PORT 0x00000e00
//#define CTRL_IRQ_ENABLE 0x01004000
#define CTRL_IRQ_ENABLE 0x00004000
/* write: Timer period config / read: TIMER IRQ ack. */
#define VORTEX_IRQ_STAT 0x2919c
/* DMA */
#define VORTEX_ENGINE_CTRL 0x27ae8
#define ENGINE_INIT 0x1380000
/* MIDI *//* GAME. */
#define VORTEX_MIDI_DATA 0x28800
#define VORTEX_MIDI_CMD 0x28804 /* Write command / Read status */
#define VORTEX_CTRL2 0x2880c
#define CTRL2_GAME_ADCMODE 0x40
#define VORTEX_GAME_LEGACY 0x28808
#define VORTEX_GAME_AXIS 0x28810
#define AXIS_SIZE 4
#define AXIS_RANGE 0x1fff

View File

@@ -0,0 +1,14 @@
#include "au8820.h"
#include "au88x0.h"
static struct pci_device_id snd_vortex_ids[] = {
{PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,},
{0,}
};
#include "au88x0_synth.c"
#include "au88x0_core.c"
#include "au88x0_pcm.c"
#include "au88x0_mpu401.c"
#include "au88x0_game.c"
#include "au88x0_mixer.c"
#include "au88x0.c"

View File

@@ -0,0 +1,204 @@
/*
Aureal Vortex Soundcard driver.
IO addr collected from asp4core.vxd:
function address
0005D5A0 13004
00080674 14004
00080AFF 12818
*/
#define CHIP_AU8820
#define CARD_NAME "Aureal Vortex 3D Sound Processor"
#define CARD_NAME_SHORT "au8820"
/* Number of ADB and WT channels */
#define NR_ADB 0x10
#define NR_WT 0x20
#define NR_SRC 0x10
#define NR_A3D 0x00
#define NR_MIXIN 0x10
#define NR_MIXOUT 0x10
/* ADBDMA */
#define VORTEX_ADBDMA_STAT 0x105c0 /* read only, subbuffer, DMA pos */
#define POS_MASK 0x00000fff
#define POS_SHIFT 0x0
#define ADB_SUBBUF_MASK 0x00003000 /* ADB only. */
#define ADB_SUBBUF_SHIFT 0xc /* ADB only. */
#define VORTEX_ADBDMA_CTRL 0x10580 /* write only, format, flags, DMA pos */
#define OFFSET_MASK 0x00000fff
#define OFFSET_SHIFT 0x0
#define IE_MASK 0x00001000 /* interrupt enable. */
#define IE_SHIFT 0xc
#define DIR_MASK 0x00002000 /* Direction. */
#define DIR_SHIFT 0xd
#define FMT_MASK 0x0003c000
#define FMT_SHIFT 0xe
// The masks and shift also work for the wtdma, if not specified otherwise.
#define VORTEX_ADBDMA_BUFCFG0 0x10400
#define VORTEX_ADBDMA_BUFCFG1 0x10404
#define VORTEX_ADBDMA_BUFBASE 0x10200
#define VORTEX_ADBDMA_START 0x106c0 /* Which subbuffer starts */
#define VORTEX_ADBDMA_STATUS 0x10600 /* stored at AdbDma->this_10 / 2 DWORD in size. */
/* ADB */
#define VORTEX_ADB_SR 0x10a00 /* Samplerates enable/disable */
#define VORTEX_ADB_RTBASE 0x10800
#define VORTEX_ADB_RTBASE_COUNT 103
#define VORTEX_ADB_CHNBASE 0x1099c
#define VORTEX_ADB_CHNBASE_COUNT 22
#define ROUTE_MASK 0x3fff
#define ADB_MASK 0x7f
#define ADB_SHIFT 0x7
//#define ADB_MIX_MASK 0xf
/* ADB address */
#define OFFSET_ADBDMA 0x00
#define OFFSET_SRCOUT 0x10 /* on channel 0x11 */
#define OFFSET_SRCIN 0x10 /* on channel < 0x11 */
#define OFFSET_MIXOUT 0x20 /* source */
#define OFFSET_MIXIN 0x30 /* sink */
#define OFFSET_CODECIN 0x48 /* ADB source */
#define OFFSET_CODECOUT 0x58 /* ADB sink/target */
#define OFFSET_SPORTOUT 0x60 /* sink */
#define OFFSET_SPORTIN 0x50 /* source */
#define OFFSET_EFXOUT 0x50 /* sink */
#define OFFSET_EFXIN 0x40 /* source */
#define OFFSET_A3DOUT 0x00 /* This card has no HRTF :( */
#define OFFSET_A3DIN 0x00
#define OFFSET_WTOUT 0x58 /* */
/* ADB route translate helper */
#define ADB_DMA(x) (x + OFFSET_ADBDMA)
#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN) /* */
#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT) /* 8 A3D blocks */
#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
#define ADB_WTOUT(x,y) (y + OFFSET_WTOUT)
/* WTDMA */
#define VORTEX_WTDMA_CTRL 0x10500 /* format, DMA pos */
#define VORTEX_WTDMA_STAT 0x10500 /* DMA subbuf, DMA pos */
#define WT_SUBBUF_MASK (0x3 << WT_SUBBUF_SHIFT)
#define WT_SUBBUF_SHIFT 0x15
#define VORTEX_WTDMA_BUFBASE 0x10000
#define VORTEX_WTDMA_BUFCFG0 0x10300
#define VORTEX_WTDMA_BUFCFG1 0x10304
#define VORTEX_WTDMA_START 0x10640 /* which subbuffer is first */
#define VORTEX_WT_BASE 0x9000
/* MIXER */
#define VORTEX_MIXER_SR 0x9f00
#define VORTEX_MIXER_CLIP 0x9f80
#define VORTEX_MIXER_CHNBASE 0x9e40
#define VORTEX_MIXER_RTBASE 0x9e00
#define MIXER_RTBASE_SIZE 0x26
#define VORTEX_MIX_ENIN 0x9a00 /* Input enable bits. 4 bits wide. */
#define VORTEX_MIX_SMP 0x9c00
/* MIX */
#define VORTEX_MIX_INVOL_A 0x9000 /* in? */
#define VORTEX_MIX_INVOL_B 0x8000 /* out? */
#define VORTEX_MIX_VOL_A 0x9800
#define VORTEX_MIX_VOL_B 0x8800
#define VOL_MIN 0x80 /* Input volume when muted. */
#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */
//#define MIX_OUTL 0xe
//#define MIX_OUTR 0xf
//#define MIX_INL 0xe
//#define MIX_INR 0xf
#define MIX_DEFIGAIN 0x08 /* 0x8 => 6dB */
#define MIX_DEFOGAIN 0x08
/* SRC */
#define VORTEX_SRCBLOCK_SR 0xccc0
#define VORTEX_SRC_CHNBASE 0xcc40
#define VORTEX_SRC_RTBASE 0xcc00
#define VORTEX_SRC_SOURCE 0xccc4
#define VORTEX_SRC_SOURCESIZE 0xccc8
#define VORTEX_SRC_U0 0xce00
#define VORTEX_SRC_DRIFT0 0xce80
#define VORTEX_SRC_DRIFT1 0xcec0
#define VORTEX_SRC_U1 0xcf00
#define VORTEX_SRC_DRIFT2 0xcf40
#define VORTEX_SRC_U2 0xcf80
#define VORTEX_SRC_DATA 0xc800
#define VORTEX_SRC_DATA0 0xc000
#define VORTEX_SRC_CONVRATIO 0xce40
//#define SRC_RATIO(x) ((((x<<15)/48000) + 1)/2) /* Playback */
//#define SRC_RATIO2(x) ((((48000<<15)/x) + 1)/2) /* Recording */
/* FIFO */
#define VORTEX_FIFO_ADBCTRL 0xf800 /* Control bits. */
#define VORTEX_FIFO_WTCTRL 0xf840
#define FIFO_RDONLY 0x00000001
#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */
#define FIFO_VALID 0x00000010
#define FIFO_EMPTY 0x00000020
#define FIFO_U0 0x00001000 /* Unknown. */
#define FIFO_U1 0x00010000
#define FIFO_SIZE_BITS 5
#define FIFO_SIZE (1<<FIFO_SIZE_BITS) // 0x20
#define FIFO_MASK (FIFO_SIZE-1) //0x1f /* at shift left 0xc */
#define VORTEX_FIFO_ADBDATA 0xe000
#define VORTEX_FIFO_WTDATA 0xe800
/* CODEC */
#define VORTEX_CODEC_CTRL 0x11984
#define VORTEX_CODEC_EN 0x11990
#define EN_CODEC 0x00000300
#define EN_SPORT 0x00030000
#define EN_SPDIF 0x000c0000
#define VORTEX_CODEC_CHN 0x11880
#define VORTEX_CODEC_IO 0x11988
#define VORTEX_SPDIF_FLAGS 0x1005c /* FIXME */
#define VORTEX_SPDIF_CFG0 0x119D0
#define VORTEX_SPDIF_CFG1 0x119D4
#define VORTEX_SPDIF_SMPRATE 0x11994
/* Sample timer */
#define VORTEX_SMP_TIME 0x11998
/* IRQ */
#define VORTEX_IRQ_SOURCE 0x12800 /* Interrupt source flags. */
#define VORTEX_IRQ_CTRL 0x12804 /* Interrupt source mask. */
#define VORTEX_STAT 0x12808 /* ?? */
#define VORTEX_CTRL 0x1280c
#define CTRL_MIDI_EN 0x00000001
#define CTRL_MIDI_PORT 0x00000060
#define CTRL_GAME_EN 0x00000008
#define CTRL_GAME_PORT 0x00000e00
#define CTRL_IRQ_ENABLE 0x4000
/* write: Timer period config / read: TIMER IRQ ack. */
#define VORTEX_IRQ_STAT 0x1199c
/* DMA */
#define VORTEX_DMA_BUFFER 0x10200
#define VORTEX_ENGINE_CTRL 0x1060c
#define ENGINE_INIT 0x0L
/* MIDI *//* GAME. */
#define VORTEX_MIDI_DATA 0x11000
#define VORTEX_MIDI_CMD 0x11004 /* Write command / Read status */
#define VORTEX_GAME_LEGACY 0x11008
#define VORTEX_CTRL2 0x1100c
#define CTRL2_GAME_ADCMODE 0x40
#define VORTEX_GAME_AXIS 0x11010
#define AXIS_SIZE 4
#define AXIS_RANGE 0x1fff

View File

@@ -0,0 +1,17 @@
#include "au8830.h"
#include "au88x0.h"
static struct pci_device_id snd_vortex_ids[] = {
{PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,},
{0,}
};
#include "au88x0_synth.c"
#include "au88x0_core.c"
#include "au88x0_pcm.c"
#include "au88x0_mixer.c"
#include "au88x0_mpu401.c"
#include "au88x0_game.c"
#include "au88x0_eq.c"
#include "au88x0_a3d.c"
#include "au88x0_xtalk.c"
#include "au88x0.c"

View File

@@ -0,0 +1,251 @@
/*
Aureal Vortex Soundcard driver.
IO addr collected from asp4core.vxd:
function address
0005D5A0 13004
00080674 14004
00080AFF 12818
*/
#define CHIP_AU8830
#define CARD_NAME "Aureal Vortex 2 3D Sound Processor"
#define CARD_NAME_SHORT "au8830"
#define NR_ADB 0x20
#define NR_SRC 0x10
#define NR_A3D 0x10
#define NR_MIXIN 0x20
#define NR_MIXOUT 0x10
#define NR_WT 0x40
/* ADBDMA */
#define VORTEX_ADBDMA_STAT 0x27e00 /* read only, subbuffer, DMA pos */
#define POS_MASK 0x00000fff
#define POS_SHIFT 0x0
#define ADB_SUBBUF_MASK 0x00003000 /* ADB only. */
#define ADB_SUBBUF_SHIFT 0xc /* ADB only. */
#define VORTEX_ADBDMA_CTRL 0x27a00 /* write only; format, flags, DMA pos */
#define OFFSET_MASK 0x00000fff
#define OFFSET_SHIFT 0x0
#define IE_MASK 0x00001000 /* interrupt enable. */
#define IE_SHIFT 0xc
#define DIR_MASK 0x00002000 /* Direction. */
#define DIR_SHIFT 0xd
#define FMT_MASK 0x0003c000
#define FMT_SHIFT 0xe
#define ADB_FIFO_EN_SHIFT 0x15
#define ADB_FIFO_EN (1 << 0x15)
// The ADB masks and shift also are valid for the wtdma, except if specified otherwise.
#define VORTEX_ADBDMA_BUFCFG0 0x27800
#define VORTEX_ADBDMA_BUFCFG1 0x27804
#define VORTEX_ADBDMA_BUFBASE 0x27400
#define VORTEX_ADBDMA_START 0x27c00 /* Which subbuffer starts */
#define VORTEX_ADBDMA_STATUS 0x27A90 /* stored at AdbDma->this_10 / 2 DWORD in size. */
/* Starting at the MSB, each pair of bits seem to be the current DMA page. */
/* This current page bits are consistent (same value) with VORTEX_ADBDMA_STAT) */
/* DMA */
#define VORTEX_ENGINE_CTRL 0x27ae8
#define ENGINE_INIT 0x1380000
/* WTDMA */
#define VORTEX_WTDMA_CTRL 0x27900 /* format, DMA pos */
#define VORTEX_WTDMA_STAT 0x27d00 /* DMA subbuf, DMA pos */
#define WT_SUBBUF_MASK 0x3
#define WT_SUBBUF_SHIFT 0xc
#define VORTEX_WTDMA_BUFBASE 0x27000
#define VORTEX_WTDMA_BUFCFG0 0x27600
#define VORTEX_WTDMA_BUFCFG1 0x27604
#define VORTEX_WTDMA_START 0x27b00 /* which subbuffer is first */
/* ADB */
#define VORTEX_ADB_SR 0x28400 /* Samplerates enable/disable */
#define VORTEX_ADB_RTBASE 0x28000
#define VORTEX_ADB_RTBASE_COUNT 173
#define VORTEX_ADB_CHNBASE 0x282b4
#define VORTEX_ADB_CHNBASE_COUNT 24
#define ROUTE_MASK 0xffff
#define SOURCE_MASK 0xff00
#define ADB_MASK 0xff
#define ADB_SHIFT 0x8
/* ADB address */
#define OFFSET_ADBDMA 0x00
#define OFFSET_ADBDMAB 0x20
#define OFFSET_SRCIN 0x40
#define OFFSET_SRCOUT 0x20 /* ch 0x11 */
#define OFFSET_MIXIN 0x50 /* ch 0x11 */
#define OFFSET_MIXOUT 0x30 /* ch 0x11 */
#define OFFSET_CODECIN 0x70 /* ch 0x11 */ /* adb source */
#define OFFSET_CODECOUT 0x88 /* ch 0x11 */ /* adb target */
#define OFFSET_SPORTIN 0x78 /* ch 0x13 ADB source. 2 routes. */
#define OFFSET_SPORTOUT 0x90 /* ch 0x13 ADB sink. 2 routes. */
#define OFFSET_SPDIFIN 0x7A /* ch 0x14 ADB source. */
#define OFFSET_SPDIFOUT 0x92 /* ch 0x14 ADB sink. */
#define OFFSET_AC98IN 0x7c /* ch 0x14 ADB source. */
#define OFFSET_AC98OUT 0x94 /* ch 0x14 ADB sink. */
#define OFFSET_EQIN 0xa0 /* ch 0x11 */
#define OFFSET_EQOUT 0x7e /* ch 0x11 */ /* 2 routes on ch 0x11 */
#define OFFSET_A3DIN 0x70 /* ADB sink. */
#define OFFSET_A3DOUT 0xA6 /* ADB source. 2 routes per slice = 8 */
#define OFFSET_WT0 0x40 /* WT bank 0 output. 0x40 - 0x65 */
#define OFFSET_WT1 0x80 /* WT bank 1 output. 0x80 - 0xA5 */
/* WT sources offset : 0x00-0x1f Direct stream. */
/* WT sources offset : 0x20-0x25 Mixed Output. */
#define OFFSET_XTALKOUT 0x66 /* crosstalk canceller (source) 2 routes */
#define OFFSET_XTALKIN 0x96 /* crosstalk canceller (sink). 10 routes */
#define OFFSET_EFXOUT 0x68 /* ADB source. 8 routes. */
#define OFFSET_EFXIN 0x80 /* ADB sink. 8 routes. */
/* ADB route translate helper */
#define ADB_DMA(x) (x)
#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN)
#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
#define ADB_SPDIFIN(x) (x + OFFSET_SPDIFIN)
#define ADB_SPDIFOUT(x) (x + OFFSET_SPDIFOUT)
#define ADB_EQIN(x) (x + OFFSET_EQIN)
#define ADB_EQOUT(x) (x + OFFSET_EQOUT)
#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT) /* 0x10 A3D blocks */
#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
//#define ADB_WTOUT(x) ((x<x20)?(x + OFFSET_WT0):(x + OFFSET_WT1))
#define ADB_WTOUT(x,y) (((x)==0)?((y) + OFFSET_WT0):((y) + OFFSET_WT1))
#define ADB_XTALKIN(x) ((x) + OFFSET_XTALKIN)
#define ADB_XTALKOUT(x) ((x) + OFFSET_XTALKOUT)
#define MIX_DEFIGAIN 0x08
#define MIX_DEFOGAIN 0x08 /* 0x8->6dB (6dB = x4) 16 to 18 bit conversion? */
/* MIXER */
#define VORTEX_MIXER_SR 0x21f00
#define VORTEX_MIXER_CLIP 0x21f80
#define VORTEX_MIXER_CHNBASE 0x21e40
#define VORTEX_MIXER_RTBASE 0x21e00
#define MIXER_RTBASE_SIZE 0x38
#define VORTEX_MIX_ENIN 0x21a00 /* Input enable bits. 4 bits wide. */
#define VORTEX_MIX_SMP 0x21c00 /* wave data buffers. AU8820: 0x9c00 */
/* MIX */
#define VORTEX_MIX_INVOL_B 0x20000 /* Input volume current */
#define VORTEX_MIX_VOL_B 0x20800 /* Output Volume current */
#define VORTEX_MIX_INVOL_A 0x21000 /* Input Volume target */
#define VORTEX_MIX_VOL_A 0x21800 /* Output Volume target */
#define VOL_MIN 0x80 /* Input volume when muted. */
#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */
/* SRC */
#define VORTEX_SRC_CHNBASE 0x26c40
#define VORTEX_SRC_RTBASE 0x26c00
#define VORTEX_SRCBLOCK_SR 0x26cc0
#define VORTEX_SRC_SOURCE 0x26cc4
#define VORTEX_SRC_SOURCESIZE 0x26cc8
/* Params
0x26e00 : 1 U0
0x26e40 : 2 CR
0x26e80 : 3 U3
0x26ec0 : 4 DRIFT1
0x26f00 : 5 U1
0x26f40 : 6 DRIFT2
0x26f80 : 7 U2 : Target rate, direction
*/
#define VORTEX_SRC_CONVRATIO 0x26e40
#define VORTEX_SRC_DRIFT0 0x26e80
#define VORTEX_SRC_DRIFT1 0x26ec0
#define VORTEX_SRC_DRIFT2 0x26f40
#define VORTEX_SRC_U0 0x26e00
#define U0_SLOWLOCK 0x200
#define VORTEX_SRC_U1 0x26f00
#define VORTEX_SRC_U2 0x26f80
#define VORTEX_SRC_DATA 0x26800 /* 0xc800 */
#define VORTEX_SRC_DATA0 0x26000
/* FIFO */
#define VORTEX_FIFO_ADBCTRL 0x16100 /* Control bits. */
#define VORTEX_FIFO_WTCTRL 0x16000
#define FIFO_RDONLY 0x00000001
#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */
#define FIFO_VALID 0x00000010
#define FIFO_EMPTY 0x00000020
#define FIFO_U0 0x00002000 /* Unknown. */
#define FIFO_U1 0x00040000
#define FIFO_SIZE_BITS 6
#define FIFO_SIZE (1<<(FIFO_SIZE_BITS)) // 0x40
#define FIFO_MASK (FIFO_SIZE-1) //0x3f /* at shift left 0xc */
#define FIFO_BITS 0x1c400000
#define VORTEX_FIFO_ADBDATA 0x14000
#define VORTEX_FIFO_WTDATA 0x10000
#define VORTEX_FIFO_GIRT 0x17000 /* wt0, wt1, adb */
#define GIRT_COUNT 3
/* CODEC */
#define VORTEX_CODEC_CHN 0x29080 /* The name "CHN" is wrong. */
#define VORTEX_CODEC_CTRL 0x29184
#define VORTEX_CODEC_IO 0x29188
#define VORTEX_CODEC_SPORTCTRL 0x2918c
#define VORTEX_CODEC_EN 0x29190
#define EN_AUDIO0 0x00000300
#define EN_MODEM 0x00000c00
#define EN_AUDIO1 0x00003000
#define EN_SPORT 0x00030000
#define EN_SPDIF 0x000c0000
#define EN_CODEC (EN_AUDIO1 | EN_AUDIO0)
#define VORTEX_SPDIF_SMPRATE 0x29194
#define VORTEX_SPDIF_FLAGS 0x2205c
#define VORTEX_SPDIF_CFG0 0x291D0 /* status data */
#define VORTEX_SPDIF_CFG1 0x291D4
#define VORTEX_SMP_TIME 0x29198 /* Sample counter/timer */
#define VORTEX_SMP_TIMER 0x2919c
#define VORTEX_CODEC2_CTRL 0x291a0
#define VORTEX_MODEM_CTRL 0x291ac
/* IRQ */
#define VORTEX_IRQ_SOURCE 0x2a000 /* Interrupt source flags. */
#define VORTEX_IRQ_CTRL 0x2a004 /* Interrupt source mask. */
//#define VORTEX_IRQ_U0 0x2a008 /* ?? */
#define VORTEX_STAT 0x2a008 /* Some sort of status */
#define STAT_IRQ 0x00000001 /* This bitis set if the IRQ is valid. */
#define VORTEX_CTRL 0x2a00c
#define CTRL_MIDI_EN 0x00000001
#define CTRL_MIDI_PORT 0x00000060
#define CTRL_GAME_EN 0x00000008
#define CTRL_GAME_PORT 0x00000e00
#define CTRL_IRQ_ENABLE 0x00004000
#define CTRL_SPDIF 0x00000000 /* unknown. Please find this value */
#define CTRL_SPORT 0x00200000
#define CTRL_RST 0x00800000
#define CTRL_UNKNOWN 0x01000000
/* write: Timer period config / read: TIMER IRQ ack. */
#define VORTEX_IRQ_STAT 0x2919c
/* MIDI *//* GAME. */
#define VORTEX_MIDI_DATA 0x28800
#define VORTEX_MIDI_CMD 0x28804 /* Write command / Read status */
#define VORTEX_GAME_LEGACY 0x28808
#define VORTEX_CTRL2 0x2880c
#define CTRL2_GAME_ADCMODE 0x40
#define VORTEX_GAME_AXIS 0x28810 /* Axis base register. 4 axis's */
#define AXIS_SIZE 4
#define AXIS_RANGE 0x1fff

View File

@@ -0,0 +1,397 @@
/*
* ALSA driver for the Aureal Vortex family of soundprocessors.
* Author: Manuel Jander (mjander@embedded.cl)
*
* This driver is the result of the OpenVortex Project from Savannah
* (savannah.nongnu.org/projects/openvortex). I would like to thank
* the developers of OpenVortex, Jeff Muizelaar and Kester Maddock, from
* whom i got plenty of help, and their codebase was invaluable.
* Thanks to the ALSA developers, they helped a lot working out
* the ALSA part.
* Thanks also to Sourceforge for maintaining the old binary drivers,
* and the forum, where developers could comunicate.
*
* Now at least i can play Legacy DOOM with MIDI music :-)
*/
#include "au88x0.h"
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/dma-mapping.h>
#include <sound/initval.h>
// module parameters (see "Module Parameters")
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
static int pcifix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 255 };
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
module_param_array(pcifix, int, NULL, 0444);
MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard.");
MODULE_DESCRIPTION("Aureal vortex");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}");
MODULE_DEVICE_TABLE(pci, snd_vortex_ids);
static void vortex_fix_latency(struct pci_dev *vortex)
{
int rc;
if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
printk(KERN_INFO CARD_NAME
": vortex latency is 0xff\n");
} else {
printk(KERN_WARNING CARD_NAME
": could not set vortex latency: pci error 0x%x\n", rc);
}
}
static void vortex_fix_agp_bridge(struct pci_dev *via)
{
int rc;
u8 value;
/*
* only set the bit (Extend PCI#2 Internal Master for
* Efficient Handling of Dummy Requests) if the can
* read the config and it is not already set
*/
if (!(rc = pci_read_config_byte(via, 0x42, &value))
&& ((value & 0x10)
|| !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) {
printk(KERN_INFO CARD_NAME
": bridge config is 0x%x\n", value | 0x10);
} else {
printk(KERN_WARNING CARD_NAME
": could not set vortex latency: pci error 0x%x\n", rc);
}
}
static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix)
{
struct pci_dev *via = NULL;
/* autodetect if workarounds are required */
if (fix == 255) {
/* VIA KT133 */
via = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_8365_1, NULL);
/* VIA Apollo */
if (via == NULL) {
via = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C598_1, NULL);
/* AMD Irongate */
if (via == NULL)
via = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL);
}
if (via) {
printk(KERN_INFO CARD_NAME ": Activating latency workaround...\n");
vortex_fix_latency(vortex);
vortex_fix_agp_bridge(via);
}
} else {
if (fix & 0x1)
vortex_fix_latency(vortex);
if ((fix & 0x2) && (via = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_8365_1, NULL)))
vortex_fix_agp_bridge(via);
if ((fix & 0x4) && (via = pci_get_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_82C598_1, NULL)))
vortex_fix_agp_bridge(via);
if ((fix & 0x8) && (via = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL)))
vortex_fix_agp_bridge(via);
}
pci_dev_put(via);
}
// component-destructor
// (see "Management of Cards and Components")
static int snd_vortex_dev_free(struct snd_device *device)
{
vortex_t *vortex = device->device_data;
vortex_gameport_unregister(vortex);
vortex_core_shutdown(vortex);
// Take down PCI interface.
free_irq(vortex->irq, vortex);
iounmap(vortex->mmio);
pci_release_regions(vortex->pci_dev);
pci_disable_device(vortex->pci_dev);
kfree(vortex);
return 0;
}
// chip-specific constructor
// (see "Management of Cards and Components")
static int __devinit
snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
{
vortex_t *chip;
int err;
static struct snd_device_ops ops = {
.dev_free = snd_vortex_dev_free,
};
*rchip = NULL;
// check PCI availability (DMA).
if ((err = pci_enable_device(pci)) < 0)
return err;
if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
printk(KERN_ERR "error to set DMA mask\n");
pci_disable_device(pci);
return -ENXIO;
}
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL) {
pci_disable_device(pci);
return -ENOMEM;
}
chip->card = card;
// initialize the stuff
chip->pci_dev = pci;
chip->io = pci_resource_start(pci, 0);
chip->vendor = pci->vendor;
chip->device = pci->device;
chip->card = card;
chip->irq = -1;
// (1) PCI resource allocation
// Get MMIO area
//
if ((err = pci_request_regions(pci, CARD_NAME_SHORT)) != 0)
goto regions_out;
chip->mmio = pci_ioremap_bar(pci, 0);
if (!chip->mmio) {
printk(KERN_ERR "MMIO area remap failed.\n");
err = -ENOMEM;
goto ioremap_out;
}
/* Init audio core.
* This must be done before we do request_irq otherwise we can get spurious
* interrupts that we do not handle properly and make a mess of things */
if ((err = vortex_core_init(chip)) != 0) {
printk(KERN_ERR "hw core init failed\n");
goto core_out;
}
if ((err = request_irq(pci->irq, vortex_interrupt,
IRQF_SHARED, CARD_NAME_SHORT,
chip)) != 0) {
printk(KERN_ERR "cannot grab irq\n");
goto irq_out;
}
chip->irq = pci->irq;
pci_set_master(pci);
// End of PCI setup.
// Register alsa root device.
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
goto alloc_out;
}
snd_card_set_dev(card, &pci->dev);
*rchip = chip;
return 0;
alloc_out:
free_irq(chip->irq, chip);
irq_out:
vortex_core_shutdown(chip);
core_out:
iounmap(chip->mmio);
ioremap_out:
pci_release_regions(chip->pci_dev);
regions_out:
pci_disable_device(chip->pci_dev);
//FIXME: this not the right place to unregister the gameport
vortex_gameport_unregister(chip);
kfree(chip);
return err;
}
// constructor -- see "Constructor" sub-section
static int __devinit
snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
{
static int dev;
struct snd_card *card;
vortex_t *chip;
int err;
// (1)
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
dev++;
return -ENOENT;
}
// (2)
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0)
return err;
// (3)
if ((err = snd_vortex_create(card, pci, &chip)) < 0) {
snd_card_free(card);
return err;
}
snd_vortex_workaround(pci, pcifix[dev]);
// Card details needed in snd_vortex_midi
strcpy(card->driver, CARD_NAME_SHORT);
sprintf(card->shortname, "Aureal Vortex %s", CARD_NAME_SHORT);
sprintf(card->longname, "%s at 0x%lx irq %i",
card->shortname, chip->io, chip->irq);
// (4) Alloc components.
// ADB pcm.
if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) {
snd_card_free(card);
return err;
}
#ifndef CHIP_AU8820
// ADB SPDIF
if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_SPDIF, 1)) < 0) {
snd_card_free(card);
return err;
}
// A3D
if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_A3D, NR_A3D)) < 0) {
snd_card_free(card);
return err;
}
#endif
/*
// ADB I2S
if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_I2S, 1)) < 0) {
snd_card_free(card);
return err;
}
*/
#ifndef CHIP_AU8810
// WT pcm.
if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_WT, NR_WT)) < 0) {
snd_card_free(card);
return err;
}
#endif
// snd_ac97_mixer and Vortex mixer.
if ((err = snd_vortex_mixer(chip)) < 0) {
snd_card_free(card);
return err;
}
if ((err = snd_vortex_midi(chip)) < 0) {
snd_card_free(card);
return err;
}
vortex_gameport_register(chip);
#if 0
if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
sizeof(snd_vortex_synth_arg_t), &wave) < 0
|| wave == NULL) {
snd_printk(KERN_ERR "Can't initialize Aureal wavetable synth\n");
} else {
snd_vortex_synth_arg_t *arg;
arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
strcpy(wave->name, "Aureal Synth");
arg->hwptr = vortex;
arg->index = 1;
arg->seq_ports = seq_ports[dev];
arg->max_voices = max_synth_voices[dev];
}
#endif
// (5)
if ((err = pci_read_config_word(pci, PCI_DEVICE_ID,
&(chip->device))) < 0) {
snd_card_free(card);
return err;
}
if ((err = pci_read_config_word(pci, PCI_VENDOR_ID,
&(chip->vendor))) < 0) {
snd_card_free(card);
return err;
}
chip->rev = pci->revision;
#ifdef CHIP_AU8830
if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
printk(KERN_ALERT
"vortex: The revision (%x) of your card has not been seen before.\n",
chip->rev);
printk(KERN_ALERT
"vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
snd_card_free(card);
err = -ENODEV;
return err;
}
#endif
// (6)
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
}
// (7)
pci_set_drvdata(pci, card);
dev++;
vortex_connect_default(chip, 1);
vortex_enable_int(chip);
return 0;
}
// destructor -- see "Destructor" sub-section
static void __devexit snd_vortex_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
pci_set_drvdata(pci, NULL);
}
// pci_driver definition
static struct pci_driver driver = {
.name = CARD_NAME_SHORT,
.id_table = snd_vortex_ids,
.probe = snd_vortex_probe,
.remove = __devexit_p(snd_vortex_remove),
};
// initialization of the module
static int __init alsa_card_vortex_init(void)
{
return pci_register_driver(&driver);
}
// clean up the module
static void __exit alsa_card_vortex_exit(void)
{
pci_unregister_driver(&driver);
}
module_init(alsa_card_vortex_init)
module_exit(alsa_card_vortex_exit)

View File

@@ -0,0 +1,285 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOUND_AU88X0_H
#define __SOUND_AU88X0_H
#ifdef __KERNEL__
#include <linux/pci.h>
#include <asm/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/rawmidi.h>
#include <sound/mpu401.h>
#include <sound/hwdep.h>
#include <sound/ac97_codec.h>
#endif
#ifndef CHIP_AU8820
#include "au88x0_eq.h"
#include "au88x0_a3d.h"
#endif
#ifndef CHIP_AU8810
#include "au88x0_wt.h"
#endif
#define hwread(x,y) readl((x)+(y))
#define hwwrite(x,y,z) writel((z),(x)+(y))
/* Vortex MPU401 defines. */
#define MIDI_CLOCK_DIV 0x61
/* Standart MPU401 defines. */
#define MPU401_RESET 0xff
#define MPU401_ENTER_UART 0x3f
#define MPU401_ACK 0xfe
// Get src register value to convert from x to y.
#define SRC_RATIO(x,y) ((((x<<15)/y) + 1)/2)
/* FIFO software state constants. */
#define FIFO_STOP 0
#define FIFO_START 1
#define FIFO_PAUSE 2
/* IRQ flags */
#define IRQ_ERR_MASK 0x00ff
#define IRQ_FATAL 0x0001
#define IRQ_PARITY 0x0002
#define IRQ_REG 0x0004
#define IRQ_FIFO 0x0008
#define IRQ_DMA 0x0010
#define IRQ_PCMOUT 0x0020 /* PCM OUT page crossing */
#define IRQ_TIMER 0x1000
#define IRQ_MIDI 0x2000
#define IRQ_MODEM 0x4000
/* ADB Resource */
#define VORTEX_RESOURCE_DMA 0x00000000
#define VORTEX_RESOURCE_SRC 0x00000001
#define VORTEX_RESOURCE_MIXIN 0x00000002
#define VORTEX_RESOURCE_MIXOUT 0x00000003
#define VORTEX_RESOURCE_A3D 0x00000004
#define VORTEX_RESOURCE_LAST 0x00000005
/* codec io: VORTEX_CODEC_IO bits */
#define VORTEX_CODEC_ID_SHIFT 24
#define VORTEX_CODEC_WRITE 0x00800000
#define VORTEX_CODEC_ADDSHIFT 16
#define VORTEX_CODEC_ADDMASK 0x7f0000
#define VORTEX_CODEC_DATSHIFT 0
#define VORTEX_CODEC_DATMASK 0xffff
/* Check for SDAC bit in "Extended audio ID" AC97 register */
//#define VORTEX_IS_QUAD(x) (((x)->codec == NULL) ? 0 : ((x)->codec->ext_id&0x80))
#define VORTEX_IS_QUAD(x) ((x)->isquad)
/* Check if chip has bug. */
#define IS_BAD_CHIP(x) (\
(x->rev == 0xfe && x->device == PCI_DEVICE_ID_AUREAL_VORTEX_2) || \
(x->rev == 0xfe && x->device == PCI_DEVICE_ID_AUREAL_ADVANTAGE))
/* PCM devices */
#define VORTEX_PCM_ADB 0
#define VORTEX_PCM_SPDIF 1
#define VORTEX_PCM_A3D 2
#define VORTEX_PCM_WT 3
#define VORTEX_PCM_I2S 4
#define VORTEX_PCM_LAST 5
#define MIX_CAPT(x) (vortex->mixcapt[x])
#define MIX_PLAYB(x) (vortex->mixplayb[x])
#define MIX_SPDIF(x) (vortex->mixspdif[x])
#define NR_WTPB 0x20 /* WT channels per eahc bank. */
/* Structs */
typedef struct {
//int this_08; /* Still unknown */
int fifo_enabled; /* this_24 */
int fifo_status; /* this_1c */
u32 dma_ctrl; /* this_78 (ADB), this_7c (WT) */
int dma_unknown; /* this_74 (ADB), this_78 (WT). WDM: +8 */
int cfg0;
int cfg1;
int nr_ch; /* Nr of PCM channels in use */
int type; /* Output type (ac97, a3d, spdif, i2s, dsp) */
int dma; /* Hardware DMA index. */
int dir; /* Stream Direction. */
u32 resources[5];
/* Virtual page extender stuff */
int nr_periods;
int period_bytes;
int period_real;
int period_virt;
struct snd_pcm_substream *substream;
} stream_t;
typedef struct snd_vortex vortex_t;
struct snd_vortex {
/* ALSA structs. */
struct snd_card *card;
struct snd_pcm *pcm[VORTEX_PCM_LAST];
struct snd_rawmidi *rmidi; /* Legacy Midi interface. */
struct snd_ac97 *codec;
/* Stream structs. */
stream_t dma_adb[NR_ADB];
int spdif_sr;
#ifndef CHIP_AU8810
stream_t dma_wt[NR_WT];
wt_voice_t wt_voice[NR_WT]; /* WT register cache. */
char mixwt[(NR_WT / NR_WTPB) * 6]; /* WT mixin objects */
#endif
/* Global resources */
s8 mixcapt[2];
s8 mixplayb[4];
#ifndef CHIP_AU8820
s8 mixspdif[2];
s8 mixa3d[2]; /* mixers which collect all a3d streams. */
s8 mixxtlk[2]; /* crosstalk canceler mixer inputs. */
#endif
u32 fixed_res[5];
#ifndef CHIP_AU8820
/* Hardware equalizer structs */
eqlzr_t eq;
/* A3D structs */
a3dsrc_t a3d[NR_A3D];
/* Xtalk canceler */
int xt_mode; /* 1: speakers, 0:headphones. */
#endif
int isquad; /* cache of extended ID codec flag. */
/* Gameport stuff. */
struct gameport *gameport;
/* PCI hardware resources */
unsigned long io;
void __iomem *mmio;
unsigned int irq;
spinlock_t lock;
/* PCI device */
struct pci_dev *pci_dev;
u16 vendor;
u16 device;
u8 rev;
};
/* Functions. */
/* SRC */
static void vortex_adb_setsrc(vortex_t * vortex, int adbdma,
unsigned int cvrt, int dir);
/* DMA Engines. */
static void vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
int size, int count);
static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie,
int dir, int fmt, int d,
u32 offset);
static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb);
#ifndef CHIP_AU8810
static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
int size, int count);
static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d, /*int e, */
u32 offset);
static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb);
#endif
static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma);
//static void vortex_adbdma_stopfifo(vortex_t *vortex, int adbdma);
static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma);
static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma);
static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma);
static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma);
#ifndef CHIP_AU8810
static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma);
static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma);
static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma);
static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma);
static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma);
#endif
/* global stuff. */
static void vortex_codec_init(vortex_t * vortex);
static void vortex_codec_write(struct snd_ac97 * codec, unsigned short addr,
unsigned short data);
static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short addr);
static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode);
static int vortex_core_init(vortex_t * card);
static int vortex_core_shutdown(vortex_t * card);
static void vortex_enable_int(vortex_t * card);
static irqreturn_t vortex_interrupt(int irq, void *dev_id);
static int vortex_alsafmt_aspfmt(int alsafmt);
/* Connection stuff. */
static void vortex_connect_default(vortex_t * vortex, int en);
static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch,
int dir, int type);
static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out,
int restype);
#ifndef CHIP_AU8810
static int vortex_wt_allocroute(vortex_t * vortex, int dma, int nr_ch);
static void vortex_wt_connect(vortex_t * vortex, int en);
static void vortex_wt_init(vortex_t * vortex);
#endif
static void vortex_route(vortex_t * vortex, int en, unsigned char channel,
unsigned char source, unsigned char dest);
#if 0
static void vortex_routes(vortex_t * vortex, int en, unsigned char channel,
unsigned char source, unsigned char dest0,
unsigned char dest1);
#endif
static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
unsigned char mixin,
unsigned char mix, int a);
static void vortex_mix_setinputvolumebyte(vortex_t * vortex,
unsigned char mix, int mixin,
unsigned char vol);
static void vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix,
unsigned char vol);
/* A3D functions. */
#ifndef CHIP_AU8820
static void vortex_Vort3D_enable(vortex_t * v);
static void vortex_Vort3D_disable(vortex_t * v);
static void vortex_Vort3D_connect(vortex_t * vortex, int en);
static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en);
#endif
/* Driver stuff. */
static int vortex_gameport_register(vortex_t * card);
static void vortex_gameport_unregister(vortex_t * card);
#ifndef CHIP_AU8820
static int vortex_eq_init(vortex_t * vortex);
static int vortex_eq_free(vortex_t * vortex);
#endif
/* ALSA stuff. */
static int snd_vortex_new_pcm(vortex_t * vortex, int idx, int nr);
static int snd_vortex_mixer(vortex_t * vortex);
static int snd_vortex_midi(vortex_t * vortex);
#endif

View File

@@ -0,0 +1,914 @@
/***************************************************************************
* au88x0_a3d.c
*
* Fri Jul 18 14:16:22 2003
* Copyright 2003 mjander
* mjander@users.sourceforge.net
*
* A3D. You may think i'm crazy, but this may work someday. Who knows...
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "au88x0_a3d.h"
#include "au88x0_a3ddata.c"
#include "au88x0_xtalk.h"
#include "au88x0.h"
static void
a3dsrc_SetTimeConsts(a3dsrc_t * a, short HrtfTrack, short ItdTrack,
short GTrack, short CTrack)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_HrtfTrackTC), HrtfTrack);
hwwrite(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_ITDTrackTC), ItdTrack);
hwwrite(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_GainTrackTC), GTrack);
hwwrite(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_CoeffTrackTC), CTrack);
}
#if 0
static void
a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack,
short *GTrack, short *CTrack)
{
// stub!
}
#endif
/* Atmospheric absorbtion. */
static void
a3dsrc_SetAtmosTarget(a3dsrc_t * a, short aa, short b, short c, short d,
short e)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_A21Target),
(e << 0x10) | d);
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_B10Target),
(b << 0x10) | aa);
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_B2Target), c);
}
static void
a3dsrc_SetAtmosCurrent(a3dsrc_t * a, short aa, short b, short c, short d,
short e)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_A12Current),
(e << 0x10) | d);
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_B01Current),
(b << 0x10) | aa);
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_B2Current), c);
}
static void
a3dsrc_SetAtmosState(a3dsrc_t * a, short x1, short x2, short y1, short y2)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x1), x1);
hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x2), x2);
hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y1), y1);
hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y2), y2);
}
#if 0
static void
a3dsrc_GetAtmosTarget(a3dsrc_t * a, short *aa, short *b, short *c,
short *d, short *e)
{
}
static void
a3dsrc_GetAtmosCurrent(a3dsrc_t * a, short *bb01, short *ab01, short *b2,
short *aa12, short *ba12)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*aa12 =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_A12Current));
*ba12 =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_A12Current));
*ab01 =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_B01Current));
*bb01 =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_B01Current));
*b2 =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_B2Current));
}
static void
a3dsrc_GetAtmosState(a3dsrc_t * a, short *x1, short *x2, short *y1, short *y2)
{
}
#endif
/* HRTF */
static void
a3dsrc_SetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
for (i = 0; i < HRTF_SZ; i++)
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source,
A3D_B_HrtfTarget) + (i << 2),
(b[i] << 0x10) | aa[i]);
}
static void
a3dsrc_SetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
for (i = 0; i < HRTF_SZ; i++)
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source,
A3D_B_HrtfCurrent) + (i << 2),
(b[i] << 0x10) | aa[i]);
}
static void
a3dsrc_SetHrtfState(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
for (i = 0; i < HRTF_SZ; i++)
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source,
A3D_B_HrtfDelayLine) + (i << 2),
(b[i] << 0x10) | aa[i]);
}
static void a3dsrc_SetHrtfOutput(a3dsrc_t * a, short left, short right)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL), left);
hwwrite(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR), right);
}
#if 0
static void a3dsrc_GetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
for (i = 0; i < HRTF_SZ; i++)
aa[i] =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source,
A3D_A_HrtfTarget + (i << 2)));
for (i = 0; i < HRTF_SZ; i++)
b[i] =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source,
A3D_B_HrtfTarget + (i << 2)));
}
static void a3dsrc_GetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
for (i = 0; i < HRTF_SZ; i++)
aa[i] =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source,
A3D_A_HrtfCurrent + (i << 2)));
for (i = 0; i < HRTF_SZ; i++)
b[i] =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source,
A3D_B_HrtfCurrent + (i << 2)));
}
static void a3dsrc_GetHrtfState(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
// FIXME: verify this!
for (i = 0; i < HRTF_SZ; i++)
aa[i] =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source,
A3D_A_HrtfDelayLine + (i << 2)));
for (i = 0; i < HRTF_SZ; i++)
b[i] =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source,
A3D_B_HrtfDelayLine + (i << 2)));
}
static void a3dsrc_GetHrtfOutput(a3dsrc_t * a, short *left, short *right)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*left =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL));
*right =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR));
}
#endif
/* Interaural Time Difference.
* "The other main clue that humans use to locate sounds, is called
* Interaural Time Difference (ITD). The differences in distance from
* the sound source to a listeners ears means that the sound will
* reach one ear slightly before the other....", found somewhere with google.*/
static void a3dsrc_SetItdTarget(a3dsrc_t * a, short litd, short ritd)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
if (litd < 0)
litd = 0;
if (litd > 0x57FF)
litd = 0x57FF;
if (ritd < 0)
ritd = 0;
if (ritd > 0x57FF)
ritd = 0x57FF;
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_ITDTarget),
(ritd << 0x10) | litd);
//hwwrite(vortex->mmio, addr(0x191DF+5, this04, this08), (ritd<<0x10)|litd);
}
static void a3dsrc_SetItdCurrent(a3dsrc_t * a, short litd, short ritd)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
if (litd < 0)
litd = 0;
if (litd > 0x57FF)
litd = 0x57FF;
if (ritd < 0)
ritd = 0;
if (ritd > 0x57FF)
ritd = 0x57FF;
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent),
(ritd << 0x10) | litd);
//hwwrite(vortex->mmio, addr(0x191DF+1, this04, this08), (ritd<<0x10)|litd);
}
static void a3dsrc_SetItdDline(a3dsrc_t * a, a3d_ItdDline_t const dline)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
/* 45 != 40 -> Check this ! */
for (i = 0; i < DLINE_SZ; i++)
hwwrite(vortex->mmio,
a3d_addrA(a->slice, a->source,
A3D_A_ITDDelayLine) + (i << 2), dline[i]);
}
#if 0
static void a3dsrc_GetItdTarget(a3dsrc_t * a, short *litd, short *ritd)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*ritd =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_ITDTarget));
*litd =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_ITDTarget));
}
static void a3dsrc_GetItdCurrent(a3dsrc_t * a, short *litd, short *ritd)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*ritd =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_ITDCurrent));
*litd =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent));
}
static void a3dsrc_GetItdDline(a3dsrc_t * a, a3d_ItdDline_t dline)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
for (i = 0; i < DLINE_SZ; i++)
dline[i] =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source,
A3D_A_ITDDelayLine + (i << 2)));
}
#endif
/* This is may be used for ILD Interaural Level Difference. */
static void a3dsrc_SetGainTarget(a3dsrc_t * a, short left, short right)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_GainTarget),
(right << 0x10) | left);
}
static void a3dsrc_SetGainCurrent(a3dsrc_t * a, short left, short right)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_GainCurrent),
(right << 0x10) | left);
}
#if 0
static void a3dsrc_GetGainTarget(a3dsrc_t * a, short *left, short *right)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*right =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_GainTarget));
*left =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_GainTarget));
}
static void a3dsrc_GetGainCurrent(a3dsrc_t * a, short *left, short *right)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*right =
hwread(vortex->mmio,
a3d_addrA(a->slice, a->source, A3D_A_GainCurrent));
*left =
hwread(vortex->mmio,
a3d_addrB(a->slice, a->source, A3D_B_GainCurrent));
}
/* CA3dIO this func seems to be inlined all over this place. */
static void CA3dIO_WriteReg(a3dsrc_t * a, unsigned long addr, short aa, short b)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio, addr, (aa << 0x10) | b);
}
#endif
/* Generic A3D stuff */
static void a3dsrc_SetA3DSampleRate(a3dsrc_t * a, int sr)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int esp0 = 0;
esp0 = (((esp0 & 0x7fffffff) | 0xB8000000) & 0x7) | ((sr & 0x1f) << 3);
hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), esp0);
//hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), esp0);
}
static void a3dsrc_EnableA3D(a3dsrc_t * a)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd),
0xF0000001);
//hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), 0xF0000001);
}
static void a3dsrc_DisableA3D(a3dsrc_t * a)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd),
0xF0000000);
}
static void a3dsrc_SetA3DControlReg(a3dsrc_t * a, unsigned long ctrl)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), ctrl);
}
static void a3dsrc_SetA3DPointerReg(a3dsrc_t * a, unsigned long ptr)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
hwwrite(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd), ptr);
}
#if 0
static void a3dsrc_GetA3DSampleRate(a3dsrc_t * a, int *sr)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*sr = ((hwread(vortex->mmio, A3D_SLICE_Control + (a->slice << 0xd))
>> 3) & 0x1f);
//*sr = ((hwread(vortex->mmio, 0x19C38 + (this08<<0xd))>>3)&0x1f);
}
static void a3dsrc_GetA3DControlReg(a3dsrc_t * a, unsigned long *ctrl)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*ctrl = hwread(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd));
}
static void a3dsrc_GetA3DPointerReg(a3dsrc_t * a, unsigned long *ptr)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
*ptr = hwread(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd));
}
#endif
static void a3dsrc_ZeroSliceIO(a3dsrc_t * a)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
int i;
for (i = 0; i < 8; i++)
hwwrite(vortex->mmio,
A3D_SLICE_VDBDest +
((((a->slice) << 0xb) + i) << 2), 0);
for (i = 0; i < 4; i++)
hwwrite(vortex->mmio,
A3D_SLICE_VDBSource +
((((a->slice) << 0xb) + i) << 2), 0);
}
/* Reset Single A3D source. */
static void a3dsrc_ZeroState(a3dsrc_t * a)
{
/*
printk(KERN_DEBUG "vortex: ZeroState slice: %d, source %d\n",
a->slice, a->source);
*/
a3dsrc_SetAtmosState(a, 0, 0, 0, 0);
a3dsrc_SetHrtfState(a, A3dHrirZeros, A3dHrirZeros);
a3dsrc_SetItdDline(a, A3dItdDlineZeros);
a3dsrc_SetHrtfOutput(a, 0, 0);
a3dsrc_SetTimeConsts(a, 0, 0, 0, 0);
a3dsrc_SetAtmosCurrent(a, 0, 0, 0, 0, 0);
a3dsrc_SetAtmosTarget(a, 0, 0, 0, 0, 0);
a3dsrc_SetItdCurrent(a, 0, 0);
a3dsrc_SetItdTarget(a, 0, 0);
a3dsrc_SetGainCurrent(a, 0, 0);
a3dsrc_SetGainTarget(a, 0, 0);
a3dsrc_SetHrtfCurrent(a, A3dHrirZeros, A3dHrirZeros);
a3dsrc_SetHrtfTarget(a, A3dHrirZeros, A3dHrirZeros);
}
/* Reset entire A3D engine */
static void a3dsrc_ZeroStateA3D(a3dsrc_t * a)
{
int i, var, var2;
if ((a->vortex) == NULL) {
printk(KERN_ERR "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n");
return;
}
a3dsrc_SetA3DControlReg(a, 0);
a3dsrc_SetA3DPointerReg(a, 0);
var = a->slice;
var2 = a->source;
for (i = 0; i < 4; i++) {
a->slice = i;
a3dsrc_ZeroSliceIO(a);
//a3dsrc_ZeroState(a);
}
a->source = var2;
a->slice = var;
}
/* Program A3D block as pass through */
static void a3dsrc_ProgramPipe(a3dsrc_t * a)
{
a3dsrc_SetTimeConsts(a, 0, 0, 0, 0);
a3dsrc_SetAtmosCurrent(a, 0, 0x4000, 0, 0, 0);
a3dsrc_SetAtmosTarget(a, 0x4000, 0, 0, 0, 0);
a3dsrc_SetItdCurrent(a, 0, 0);
a3dsrc_SetItdTarget(a, 0, 0);
a3dsrc_SetGainCurrent(a, 0x7fff, 0x7fff);
a3dsrc_SetGainTarget(a, 0x7fff, 0x7fff);
/* SET HRTF HERE */
/* Single spike leads to identity transfer function. */
a3dsrc_SetHrtfCurrent(a, A3dHrirImpulse, A3dHrirImpulse);
a3dsrc_SetHrtfTarget(a, A3dHrirImpulse, A3dHrirImpulse);
/* Test: Sounds saturated. */
//a3dsrc_SetHrtfCurrent(a, A3dHrirSatTest, A3dHrirSatTest);
//a3dsrc_SetHrtfTarget(a, A3dHrirSatTest, A3dHrirSatTest);
}
/* VDB = Vortex audio Dataflow Bus */
#if 0
static void a3dsrc_ClearVDBData(a3dsrc_t * a, unsigned long aa)
{
vortex_t *vortex = (vortex_t *) (a->vortex);
// ((aa >> 2) << 8) - (aa >> 2)
hwwrite(vortex->mmio,
a3d_addrS(a->slice, A3D_SLICE_VDBDest) + (a->source << 2), 0);
hwwrite(vortex->mmio,
a3d_addrS(a->slice,
A3D_SLICE_VDBDest + 4) + (a->source << 2), 0);
/*
hwwrite(vortex->mmio, 0x19c00 + (((aa>>2)*255*4)+aa)*8, 0);
hwwrite(vortex->mmio, 0x19c04 + (((aa>>2)*255*4)+aa)*8, 0);
*/
}
#endif
/* A3D HwSource stuff. */
static void vortex_A3dSourceHw_Initialize(vortex_t * v, int source, int slice)
{
a3dsrc_t *a3dsrc = &(v->a3d[source + (slice * 4)]);
//a3dsrc_t *a3dsrc = &(v->a3d[source + (slice*4)]);
a3dsrc->vortex = (void *)v;
a3dsrc->source = source; /* source */
a3dsrc->slice = slice; /* slice */
a3dsrc_ZeroState(a3dsrc);
/* Added by me. */
a3dsrc_SetA3DSampleRate(a3dsrc, 0x11);
}
static int Vort3DRend_Initialize(vortex_t * v, unsigned short mode)
{
v->xt_mode = mode; /* this_14 */
vortex_XtalkHw_init(v);
vortex_XtalkHw_SetGainsAllChan(v);
switch (v->xt_mode) {
case XT_SPEAKER0:
vortex_XtalkHw_ProgramXtalkNarrow(v);
break;
case XT_SPEAKER1:
vortex_XtalkHw_ProgramXtalkWide(v);
break;
default:
case XT_HEADPHONE:
vortex_XtalkHw_ProgramPipe(v);
break;
case XT_DIAMOND:
vortex_XtalkHw_ProgramDiamondXtalk(v);
break;
}
vortex_XtalkHw_SetSampleRate(v, 0x11);
vortex_XtalkHw_Enable(v);
return 0;
}
/* 3D Sound entry points. */
static int vortex_a3d_register_controls(vortex_t * vortex);
static void vortex_a3d_unregister_controls(vortex_t * vortex);
/* A3D base support init/shudown */
static void __devinit vortex_Vort3D_enable(vortex_t * v)
{
int i;
Vort3DRend_Initialize(v, XT_HEADPHONE);
for (i = 0; i < NR_A3D; i++) {
vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2);
a3dsrc_ZeroStateA3D(&(v->a3d[0]));
}
/* Register ALSA controls */
vortex_a3d_register_controls(v);
}
static void vortex_Vort3D_disable(vortex_t * v)
{
vortex_XtalkHw_Disable(v);
vortex_a3d_unregister_controls(v);
}
/* Make A3D subsystem connections. */
static void vortex_Vort3D_connect(vortex_t * v, int en)
{
int i;
// Disable AU8810 routes, since they seem to be wrong (in au8810.h).
#ifdef CHIP_AU8810
return;
#endif
#if 1
/* Alloc Xtalk mixin resources */
v->mixxtlk[0] =
vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
if (v->mixxtlk[0] < 0) {
printk
("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
return;
}
v->mixxtlk[1] =
vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
if (v->mixxtlk[1] < 0) {
printk
("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
return;
}
#endif
/* Connect A3D -> XTALK */
for (i = 0; i < 4; i++) {
// 2 outputs per each A3D slice.
vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2), ADB_XTALKIN(i));
vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2) + 1, ADB_XTALKIN(5 + i));
}
#if 0
vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_EQIN(2));
vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_EQIN(3));
#else
/* Connect XTalk -> mixer */
vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_MIXIN(v->mixxtlk[0]));
vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_MIXIN(v->mixxtlk[1]));
vortex_connection_mixin_mix(v, en, v->mixxtlk[0], v->mixplayb[0], 0);
vortex_connection_mixin_mix(v, en, v->mixxtlk[1], v->mixplayb[1], 0);
vortex_mix_setinputvolumebyte(v, v->mixplayb[0], v->mixxtlk[0],
en ? MIX_DEFIGAIN : VOL_MIN);
vortex_mix_setinputvolumebyte(v, v->mixplayb[1], v->mixxtlk[1],
en ? MIX_DEFIGAIN : VOL_MIN);
if (VORTEX_IS_QUAD(v)) {
vortex_connection_mixin_mix(v, en, v->mixxtlk[0],
v->mixplayb[2], 0);
vortex_connection_mixin_mix(v, en, v->mixxtlk[1],
v->mixplayb[3], 0);
vortex_mix_setinputvolumebyte(v, v->mixplayb[2],
v->mixxtlk[0],
en ? MIX_DEFIGAIN : VOL_MIN);
vortex_mix_setinputvolumebyte(v, v->mixplayb[3],
v->mixxtlk[1],
en ? MIX_DEFIGAIN : VOL_MIN);
}
#endif
}
/* Initialize one single A3D source. */
static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en)
{
if (a->vortex == NULL) {
printk
("vortex: Vort3D_InitializeSource: A3D source not initialized\n");
return;
}
if (en) {
a3dsrc_ProgramPipe(a);
a3dsrc_SetA3DSampleRate(a, 0x11);
a3dsrc_SetTimeConsts(a, HrtfTCDefault,
ItdTCDefault, GainTCDefault,
CoefTCDefault);
/* Remark: zero gain is muted. */
//a3dsrc_SetGainTarget(a,0,0);
//a3dsrc_SetGainCurrent(a,0,0);
a3dsrc_EnableA3D(a);
} else {
a3dsrc_DisableA3D(a);
a3dsrc_ZeroState(a);
}
}
/* Conversion of coordinates into 3D parameters. */
static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord)
{
/* FIXME: implement this. */
}
static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord)
{
/* FIXME: implement this. */
}
static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right)
{
/* FIXME: implement this. */
}
static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params)
{
/* FIXME: implement this. */
}
/* ALSA control interface. */
static int
snd_vortex_a3d_hrtf_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 6;
uinfo->value.integer.min = 0x00000000;
uinfo->value.integer.max = 0xffffffff;
return 0;
}
static int
snd_vortex_a3d_itd_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0x00000000;
uinfo->value.integer.max = 0xffffffff;
return 0;
}
static int
snd_vortex_a3d_ild_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0x00000000;
uinfo->value.integer.max = 0xffffffff;
return 0;
}
static int
snd_vortex_a3d_filter_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 4;
uinfo->value.integer.min = 0x00000000;
uinfo->value.integer.max = 0xffffffff;
return 0;
}
static int
snd_vortex_a3d_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
//a3dsrc_t *a = kcontrol->private_data;
/* No read yet. Would this be really useable/needed ? */
return 0;
}
static int
snd_vortex_a3d_hrtf_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
a3dsrc_t *a = kcontrol->private_data;
int changed = 1, i;
int coord[6];
for (i = 0; i < 6; i++)
coord[i] = ucontrol->value.integer.value[i];
/* Translate orientation coordinates to a3d params. */
vortex_a3d_coord2hrtf(a->hrtf[0], coord);
vortex_a3d_coord2hrtf(a->hrtf[1], coord);
a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]);
a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]);
return changed;
}
static int
snd_vortex_a3d_itd_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
a3dsrc_t *a = kcontrol->private_data;
int coord[6];
int i, changed = 1;
for (i = 0; i < 6; i++)
coord[i] = ucontrol->value.integer.value[i];
/* Translate orientation coordinates to a3d params. */
vortex_a3d_coord2itd(a->hrtf[0], coord);
vortex_a3d_coord2itd(a->hrtf[1], coord);
/* Inter aural time difference. */
a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]);
a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]);
a3dsrc_SetItdDline(a, a->dline);
return changed;
}
static int
snd_vortex_a3d_ild_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
a3dsrc_t *a = kcontrol->private_data;
int changed = 1;
int l, r;
/* There may be some scale tranlation needed here. */
l = ucontrol->value.integer.value[0];
r = ucontrol->value.integer.value[1];
vortex_a3d_coord2ild(a->ild, l, r);
/* Left Right panning. */
a3dsrc_SetGainTarget(a, l, r);
a3dsrc_SetGainCurrent(a, l, r);
return changed;
}
static int
snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
a3dsrc_t *a = kcontrol->private_data;
int i, changed = 1;
int params[6];
for (i = 0; i < 6; i++)
params[i] = ucontrol->value.integer.value[i];
/* Translate generic filter params to a3d filter params. */
vortex_a3d_translate_filter(a->filter, params);
/* Atmospheric absorbtion and filtering. */
a3dsrc_SetAtmosTarget(a, a->filter[0],
a->filter[1], a->filter[2],
a->filter[3], a->filter[4]);
a3dsrc_SetAtmosCurrent(a, a->filter[0],
a->filter[1], a->filter[2],
a->filter[3], a->filter[4]);
return changed;
}
static struct snd_kcontrol_new vortex_a3d_kcontrol __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Playback PCM advanced processing",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_vortex_a3d_hrtf_info,
.get = snd_vortex_a3d_get,
.put = snd_vortex_a3d_hrtf_put,
};
/* Control (un)registration. */
static int __devinit vortex_a3d_register_controls(vortex_t * vortex)
{
struct snd_kcontrol *kcontrol;
int err, i;
/* HRTF controls. */
for (i = 0; i < NR_A3D; i++) {
if ((kcontrol =
snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL)
return -ENOMEM;
kcontrol->id.numid = CTRLID_HRTF;
kcontrol->info = snd_vortex_a3d_hrtf_info;
kcontrol->put = snd_vortex_a3d_hrtf_put;
if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
return err;
}
/* ITD controls. */
for (i = 0; i < NR_A3D; i++) {
if ((kcontrol =
snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL)
return -ENOMEM;
kcontrol->id.numid = CTRLID_ITD;
kcontrol->info = snd_vortex_a3d_itd_info;
kcontrol->put = snd_vortex_a3d_itd_put;
if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
return err;
}
/* ILD (gains) controls. */
for (i = 0; i < NR_A3D; i++) {
if ((kcontrol =
snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL)
return -ENOMEM;
kcontrol->id.numid = CTRLID_GAINS;
kcontrol->info = snd_vortex_a3d_ild_info;
kcontrol->put = snd_vortex_a3d_ild_put;
if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
return err;
}
/* Filter controls. */
for (i = 0; i < NR_A3D; i++) {
if ((kcontrol =
snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL)
return -ENOMEM;
kcontrol->id.numid = CTRLID_FILTER;
kcontrol->info = snd_vortex_a3d_filter_info;
kcontrol->put = snd_vortex_a3d_filter_put;
if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
return err;
}
return 0;
}
static void vortex_a3d_unregister_controls(vortex_t * vortex)
{
}
/* End of File*/

View File

@@ -0,0 +1,123 @@
/***************************************************************************
* au88x0_a3d.h
*
* Fri Jul 18 14:16:03 2003
* Copyright 2003 mjander
* mjander@users.sourceforge.net
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _AU88X0_A3D_H
#define _AU88X0_A3D_H
//#include <openal.h>
#define HRTF_SZ 0x38
#define DLINE_SZ 0x28
#define CTRLID_HRTF 1
#define CTRLID_ITD 2
#define CTRLID_ILD 4
#define CTRLID_FILTER 8
#define CTRLID_GAINS 16
/* 3D parameter structs */
typedef unsigned short int a3d_Hrtf_t[HRTF_SZ];
typedef unsigned short int a3d_ItdDline_t[DLINE_SZ];
typedef unsigned short int a3d_atmos_t[5];
typedef unsigned short int a3d_LRGains_t[2];
typedef unsigned short int a3d_Itd_t[2];
typedef unsigned short int a3d_Ild_t[2];
typedef struct {
void *vortex; // Formerly CAsp4HwIO*, now vortex_t*.
unsigned int source; /* this_04 */
unsigned int slice; /* this_08 */
a3d_Hrtf_t hrtf[2];
a3d_Itd_t itd;
a3d_Ild_t ild;
a3d_ItdDline_t dline;
a3d_atmos_t filter;
} a3dsrc_t;
/* First Register bank */
#define A3D_A_HrtfCurrent 0x18000 /* 56 ULONG */
#define A3D_A_GainCurrent 0x180E0
#define A3D_A_GainTarget 0x180E4
#define A3D_A_A12Current 0x180E8 /* Atmospheric current. */
#define A3D_A_A21Target 0x180EC /* Atmospheric target */
#define A3D_A_B01Current 0x180F0 /* Atmospheric current */
#define A3D_A_B10Target 0x180F4 /* Atmospheric target */
#define A3D_A_B2Current 0x180F8 /* Atmospheric current */
#define A3D_A_B2Target 0x180FC /* Atmospheric target */
#define A3D_A_HrtfTarget 0x18100 /* 56 ULONG */
#define A3D_A_ITDCurrent 0x181E0
#define A3D_A_ITDTarget 0x181E4
#define A3D_A_HrtfDelayLine 0x181E8 /* 56 ULONG */
#define A3D_A_ITDDelayLine 0x182C8 /* 40/45 ULONG */
#define A3D_A_HrtfTrackTC 0x1837C /* Time Constants */
#define A3D_A_GainTrackTC 0x18380
#define A3D_A_CoeffTrackTC 0x18384
#define A3D_A_ITDTrackTC 0x18388
#define A3D_A_x1 0x1838C
#define A3D_A_x2 0x18390
#define A3D_A_y1 0x18394
#define A3D_A_y2 0x18398
#define A3D_A_HrtfOutL 0x1839C
#define A3D_A_HrtfOutR 0x183A0
#define A3D_A_TAIL 0x183A4
/* Second register bank */
#define A3D_B_HrtfCurrent 0x19000 /* 56 ULONG */
#define A3D_B_GainCurrent 0x190E0
#define A3D_B_GainTarget 0x190E4
#define A3D_B_A12Current 0x190E8
#define A3D_B_A21Target 0x190EC
#define A3D_B_B01Current 0x190F0
#define A3D_B_B10Target 0x190F4
#define A3D_B_B2Current 0x190F8
#define A3D_B_B2Target 0x190FC
#define A3D_B_HrtfTarget 0x19100 /* 56 ULONG */
#define A3D_B_ITDCurrent 0x191E0
#define A3D_B_ITDTarget 0x191E4
#define A3D_B_HrtfDelayLine 0x191E8 /* 56 ULONG */
#define A3D_B_TAIL 0x192C8
/* There are 4 slices, 4 a3d each = 16 a3d sources. */
#define A3D_SLICE_BANK_A 0x18000 /* 4 sources */
#define A3D_SLICE_BANK_B 0x19000 /* 4 sources */
#define A3D_SLICE_VDBDest 0x19C00 /* 8 ULONG */
#define A3D_SLICE_VDBSource 0x19C20 /* 4 ULONG */
#define A3D_SLICE_ABReg 0x19C30
#define A3D_SLICE_CReg 0x19C34
#define A3D_SLICE_Control 0x19C38
#define A3D_SLICE_DebugReserved 0x19C3c /* Dangerous! */
#define A3D_SLICE_Pointers 0x19C40
#define A3D_SLICE_TAIL 0x1A000
// Slice size: 0x2000
// Source size: 0x3A4, 0x2C8
/* Address generator macro. */
#define a3d_addrA(slice,source,reg) (((slice)<<0xd)+((source)*0x3A4)+(reg))
#define a3d_addrB(slice,source,reg) (((slice)<<0xd)+((source)*0x2C8)+(reg))
#define a3d_addrS(slice,reg) (((slice)<<0xd)+(reg))
//#define a3d_addr(slice,source,reg) (((reg)>=0x19000) ? a3d_addr2((slice),(source),(reg)) : a3d_addr1((slice),(source),(reg)))
#endif /* _AU88X0_A3D_H */

View File

@@ -0,0 +1,91 @@
/***************************************************************************
* au88x0_a3ddata.c
*
* Wed Nov 19 21:11:32 2003
* Copyright 2003 mjander
* mjander@users.sourceforge.org
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Constant initializer values. */
static const a3d_Hrtf_t A3dHrirZeros = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0
};
static const a3d_Hrtf_t A3dHrirImpulse = {
0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0
};
static const a3d_Hrtf_t A3dHrirOnes = {
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
0x7fff,
0x7fff,
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
0x7fff,
0x7fff,
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
0x7fff,
0x7fff,
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
0x7fff,
0x7fff,
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff
};
static const a3d_Hrtf_t A3dHrirSatTest = {
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
0x7fff,
0x7fff,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x8001,
0x8001,
0x7fff, 0x0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const a3d_Hrtf_t A3dHrirDImpulse = {
0, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
0, 0, 0
};
static const a3d_ItdDline_t A3dItdDlineZeros = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static short const GainTCDefault = 0x300;
static short const ItdTCDefault = 0x0C8;
static short const HrtfTCDefault = 0x147;
static short const CoefTCDefault = 0x300;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,928 @@
/***************************************************************************
* au88x0_eq.c
* Aureal Vortex Hardware EQ control/access.
*
* Sun Jun 8 18:19:19 2003
* 2003 Manuel Jander (mjander@users.sourceforge.net)
*
* 02 July 2003: First time something works :)
* November 2003: A3D Bypass code completed but untested.
*
* TODO:
* - Debug (testing)
* - Test peak visualization support.
*
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
The Aureal Hardware EQ is found on AU8810 and AU8830 chips only.
it has 4 inputs (2 for general mix, 2 for A3D) and 2 outputs (supposed
to be routed to the codec).
*/
#include "au88x0.h"
#include "au88x0_eq.h"
#include "au88x0_eqdata.c"
#define VORTEX_EQ_BASE 0x2b000
#define VORTEX_EQ_DEST (VORTEX_EQ_BASE + 0x410)
#define VORTEX_EQ_SOURCE (VORTEX_EQ_BASE + 0x430)
#define VORTEX_EQ_CTRL (VORTEX_EQ_BASE + 0x440)
#define VORTEX_BAND_COEFF_SIZE 0x30
/* CEqHw.s */
static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 gain, u16 level)
{
hwwrite(vortex->mmio, 0x2b3c4, gain);
hwwrite(vortex->mmio, 0x2b3c8, level);
}
static inline u16 sign_invert(u16 a)
{
/* -(-32768) -> -32768 so we do -(-32768) -> 32767 to make the result positive */
if (a == (u16)-32768)
return 32767;
else
return -a;
}
static void vortex_EqHw_SetLeftCoefs(vortex_t * vortex, u16 coefs[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int i = 0, n /*esp2c */;
for (n = 0; n < eqhw->this04; n++) {
hwwrite(vortex->mmio, 0x2b000 + n * 0x30, coefs[i + 0]);
hwwrite(vortex->mmio, 0x2b004 + n * 0x30, coefs[i + 1]);
if (eqhw->this08 == 0) {
hwwrite(vortex->mmio, 0x2b008 + n * 0x30, coefs[i + 2]);
hwwrite(vortex->mmio, 0x2b00c + n * 0x30, coefs[i + 3]);
hwwrite(vortex->mmio, 0x2b010 + n * 0x30, coefs[i + 4]);
} else {
hwwrite(vortex->mmio, 0x2b008 + n * 0x30, sign_invert(coefs[2 + i]));
hwwrite(vortex->mmio, 0x2b00c + n * 0x30, sign_invert(coefs[3 + i]));
hwwrite(vortex->mmio, 0x2b010 + n * 0x30, sign_invert(coefs[4 + i]));
}
i += 5;
}
}
static void vortex_EqHw_SetRightCoefs(vortex_t * vortex, u16 coefs[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int i = 0, n /*esp2c */;
for (n = 0; n < eqhw->this04; n++) {
hwwrite(vortex->mmio, 0x2b1e0 + n * 0x30, coefs[0 + i]);
hwwrite(vortex->mmio, 0x2b1e4 + n * 0x30, coefs[1 + i]);
if (eqhw->this08 == 0) {
hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, coefs[2 + i]);
hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, coefs[3 + i]);
hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, coefs[4 + i]);
} else {
hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, sign_invert(coefs[2 + i]));
hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, sign_invert(coefs[3 + i]));
hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, sign_invert(coefs[4 + i]));
}
i += 5;
}
}
static void vortex_EqHw_SetLeftStates(vortex_t * vortex, u16 a[], u16 b[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int i = 0, ebx;
hwwrite(vortex->mmio, 0x2b3fc, a[0]);
hwwrite(vortex->mmio, 0x2b400, a[1]);
for (ebx = 0; ebx < eqhw->this04; ebx++) {
hwwrite(vortex->mmio, 0x2b014 + (i * 0xc), b[i]);
hwwrite(vortex->mmio, 0x2b018 + (i * 0xc), b[1 + i]);
hwwrite(vortex->mmio, 0x2b01c + (i * 0xc), b[2 + i]);
hwwrite(vortex->mmio, 0x2b020 + (i * 0xc), b[3 + i]);
i += 4;
}
}
static void vortex_EqHw_SetRightStates(vortex_t * vortex, u16 a[], u16 b[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int i = 0, ebx;
hwwrite(vortex->mmio, 0x2b404, a[0]);
hwwrite(vortex->mmio, 0x2b408, a[1]);
for (ebx = 0; ebx < eqhw->this04; ebx++) {
hwwrite(vortex->mmio, 0x2b1f4 + (i * 0xc), b[i]);
hwwrite(vortex->mmio, 0x2b1f8 + (i * 0xc), b[1 + i]);
hwwrite(vortex->mmio, 0x2b1fc + (i * 0xc), b[2 + i]);
hwwrite(vortex->mmio, 0x2b200 + (i * 0xc), b[3 + i]);
i += 4;
}
}
#if 0
static void vortex_EqHw_GetTimeConsts(vortex_t * vortex, u16 * a, u16 * b)
{
*a = hwread(vortex->mmio, 0x2b3c4);
*b = hwread(vortex->mmio, 0x2b3c8);
}
static void vortex_EqHw_GetLeftCoefs(vortex_t * vortex, u16 a[])
{
}
static void vortex_EqHw_GetRightCoefs(vortex_t * vortex, u16 a[])
{
}
static void vortex_EqHw_GetLeftStates(vortex_t * vortex, u16 * a, u16 b[])
{
}
static void vortex_EqHw_GetRightStates(vortex_t * vortex, u16 * a, u16 b[])
{
}
#endif
/* Mix Gains */
static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b)
{
eqhw_t *eqhw = &(vortex->eq.this04);
if (eqhw->this08 == 0) {
hwwrite(vortex->mmio, 0x2b3d4, a);
hwwrite(vortex->mmio, 0x2b3ec, b);
} else {
hwwrite(vortex->mmio, 0x2b3d4, sign_invert(a));
hwwrite(vortex->mmio, 0x2b3ec, sign_invert(b));
}
}
static void vortex_EqHw_SetA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
{
hwwrite(vortex->mmio, 0x2b3e0, a);
hwwrite(vortex->mmio, 0x2b3f8, b);
}
#if 0
static void vortex_EqHw_SetCurrBypassGain(vortex_t * vortex, u16 a, u16 b)
{
hwwrite(vortex->mmio, 0x2b3d0, a);
hwwrite(vortex->mmio, 0x2b3e8, b);
}
static void vortex_EqHw_SetCurrA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
{
hwwrite(vortex->mmio, 0x2b3dc, a);
hwwrite(vortex->mmio, 0x2b3f4, b);
}
#endif
static void
vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
{
hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b);
}
static void
vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
{
hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b);
}
static void vortex_EqHw_SetLeftGainsTarget(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx;
for (ebx = 0; ebx < eqhw->this04; ebx++) {
hwwrite(vortex->mmio, 0x2b02c + ebx * 0x30, a[ebx]);
}
}
static void vortex_EqHw_SetRightGainsTarget(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx;
for (ebx = 0; ebx < eqhw->this04; ebx++) {
hwwrite(vortex->mmio, 0x2b20c + ebx * 0x30, a[ebx]);
}
}
static void vortex_EqHw_SetLeftGainsCurrent(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx;
for (ebx = 0; ebx < eqhw->this04; ebx++) {
hwwrite(vortex->mmio, 0x2b028 + ebx * 0x30, a[ebx]);
}
}
static void vortex_EqHw_SetRightGainsCurrent(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx;
for (ebx = 0; ebx < eqhw->this04; ebx++) {
hwwrite(vortex->mmio, 0x2b208 + ebx * 0x30, a[ebx]);
}
}
#if 0
static void vortex_EqHw_GetLeftGainsTarget(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx = 0;
if (eqhw->this04 < 0)
return;
do {
a[ebx] = hwread(vortex->mmio, 0x2b02c + ebx * 0x30);
ebx++;
}
while (ebx < eqhw->this04);
}
static void vortex_EqHw_GetRightGainsTarget(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx = 0;
if (eqhw->this04 < 0)
return;
do {
a[ebx] = hwread(vortex->mmio, 0x2b20c + ebx * 0x30);
ebx++;
}
while (ebx < eqhw->this04);
}
static void vortex_EqHw_GetLeftGainsCurrent(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx = 0;
if (eqhw->this04 < 0)
return;
do {
a[ebx] = hwread(vortex->mmio, 0x2b028 + ebx * 0x30);
ebx++;
}
while (ebx < eqhw->this04);
}
static void vortex_EqHw_GetRightGainsCurrent(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx = 0;
if (eqhw->this04 < 0)
return;
do {
a[ebx] = hwread(vortex->mmio, 0x2b208 + ebx * 0x30);
ebx++;
}
while (ebx < eqhw->this04);
}
#endif
/* EQ band levels settings */
static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 peaks[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int i;
/* set left peaks */
for (i = 0; i < eqhw->this04; i++) {
hwwrite(vortex->mmio, 0x2b024 + i * VORTEX_BAND_COEFF_SIZE, peaks[i]);
}
hwwrite(vortex->mmio, 0x2b3cc, peaks[eqhw->this04]);
hwwrite(vortex->mmio, 0x2b3d8, peaks[eqhw->this04 + 1]);
/* set right peaks */
for (i = 0; i < eqhw->this04; i++) {
hwwrite(vortex->mmio, 0x2b204 + i * VORTEX_BAND_COEFF_SIZE,
peaks[i + (eqhw->this04 + 2)]);
}
hwwrite(vortex->mmio, 0x2b3e4, peaks[2 + (eqhw->this04 * 2)]);
hwwrite(vortex->mmio, 0x2b3f0, peaks[3 + (eqhw->this04 * 2)]);
}
#if 0
static void vortex_EqHw_GetLevels(vortex_t * vortex, u16 a[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int ebx;
if (eqhw->this04 < 0)
return;
ebx = 0;
do {
a[ebx] = hwread(vortex->mmio, 0x2b024 + ebx * 0x30);
ebx++;
}
while (ebx < eqhw->this04);
a[eqhw->this04] = hwread(vortex->mmio, 0x2b3cc);
a[eqhw->this04 + 1] = hwread(vortex->mmio, 0x2b3d8);
ebx = 0;
do {
a[ebx + (eqhw->this04 + 2)] =
hwread(vortex->mmio, 0x2b204 + ebx * 0x30);
ebx++;
}
while (ebx < eqhw->this04);
a[2 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3e4);
a[3 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3f0);
}
#endif
/* Global Control */
static void vortex_EqHw_SetControlReg(vortex_t * vortex, u32 reg)
{
hwwrite(vortex->mmio, 0x2b440, reg);
}
static void vortex_EqHw_SetSampleRate(vortex_t * vortex, u32 sr)
{
hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800);
}
#if 0
static void vortex_EqHw_GetControlReg(vortex_t * vortex, u32 *reg)
{
*reg = hwread(vortex->mmio, 0x2b440);
}
static void vortex_EqHw_GetSampleRate(vortex_t * vortex, u32 *sr)
{
*sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f;
}
#endif
static void vortex_EqHw_Enable(vortex_t * vortex)
{
hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf001);
}
static void vortex_EqHw_Disable(vortex_t * vortex)
{
hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf000);
}
/* Reset (zero) buffers */
static void vortex_EqHw_ZeroIO(vortex_t * vortex)
{
int i;
for (i = 0; i < 0x8; i++)
hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
for (i = 0; i < 0x4; i++)
hwwrite(vortex->mmio, VORTEX_EQ_SOURCE + (i << 2), 0x0);
}
static void vortex_EqHw_ZeroA3DIO(vortex_t * vortex)
{
int i;
for (i = 0; i < 0x4; i++)
hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
}
static void vortex_EqHw_ZeroState(vortex_t * vortex)
{
vortex_EqHw_SetControlReg(vortex, 0);
vortex_EqHw_ZeroIO(vortex);
hwwrite(vortex->mmio, 0x2b3c0, 0);
vortex_EqHw_SetTimeConsts(vortex, 0, 0);
vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros);
vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros);
vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero);
vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero);
vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero);
vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero);
vortex_EqHw_SetBypassGain(vortex, 0, 0);
//vortex_EqHw_SetCurrBypassGain(vortex, 0, 0);
vortex_EqHw_SetA3DBypassGain(vortex, 0, 0);
//vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0);
vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros);
vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros);
vortex_EqHw_SetLevels(vortex, (u16 *) eq_levels);
}
/* Program coeficients as pass through */
static void vortex_EqHw_ProgramPipe(vortex_t * vortex)
{
vortex_EqHw_SetTimeConsts(vortex, 0, 0);
vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes);
vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes);
vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current);
vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current);
vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current);
vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_current);
}
/* Program EQ block as 10 band Equalizer */
static void
vortex_EqHw_Program10Band(vortex_t * vortex, auxxEqCoeffSet_t * coefset)
{
vortex_EqHw_SetTimeConsts(vortex, 0xc, 0x7fe0);
vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs);
vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs);
vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains);
vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains);
vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains);
vortex_EqHw_SetRightGainsCurrent(vortex, coefset->RightGains);
}
/* Read all EQ peaks. (think VU meter) */
static void vortex_EqHw_GetTenBandLevels(vortex_t * vortex, u16 peaks[])
{
eqhw_t *eqhw = &(vortex->eq.this04);
int i;
if (eqhw->this04 <= 0)
return;
for (i = 0; i < eqhw->this04; i++)
peaks[i] = hwread(vortex->mmio, 0x2B024 + i * 0x30);
for (i = 0; i < eqhw->this04; i++)
peaks[i + eqhw->this04] =
hwread(vortex->mmio, 0x2B204 + i * 0x30);
}
/* CEqlzr.s */
static int vortex_Eqlzr_GetLeftGain(vortex_t * vortex, u16 index, u16 * gain)
{
eqlzr_t *eq = &(vortex->eq);
if (eq->this28) {
*gain = eq->this130[index];
return 0;
}
return 1;
}
static void vortex_Eqlzr_SetLeftGain(vortex_t * vortex, u16 index, u16 gain)
{
eqlzr_t *eq = &(vortex->eq);
if (eq->this28 == 0)
return;
eq->this130[index] = gain;
if (eq->this54)
return;
vortex_EqHw_SetLeftGainsSingleTarget(vortex, index, gain);
}
static int vortex_Eqlzr_GetRightGain(vortex_t * vortex, u16 index, u16 * gain)
{
eqlzr_t *eq = &(vortex->eq);
if (eq->this28) {
*gain = eq->this130[index + eq->this10];
return 0;
}
return 1;
}
static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain)
{
eqlzr_t *eq = &(vortex->eq);
if (eq->this28 == 0)
return;
eq->this130[index + eq->this10] = gain;
if (eq->this54)
return;
vortex_EqHw_SetRightGainsSingleTarget(vortex, index, gain);
}
#if 0
static int
vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, s32 *cnt)
{
eqlzr_t *eq = &(vortex->eq);
int si = 0;
if (eq->this10 == 0)
return 1;
{
if (vortex_Eqlzr_GetLeftGain(vortex, si, &gains[si]))
return 1;
if (vortex_Eqlzr_GetRightGain
(vortex, si, &gains[si + eq->this10]))
return 1;
si++;
}
while (eq->this10 > si) ;
*cnt = si * 2;
return 0;
}
#endif
static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex)
{
eqlzr_t *eq = &(vortex->eq);
vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130);
vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
return 0;
}
static int
vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], s32 count)
{
eqlzr_t *eq = &(vortex->eq);
int i;
if (((eq->this10) * 2 != count) || (eq->this28 == 0))
return 1;
for (i = 0; i < count; i++) {
eq->this130[i] = gains[i];
}
if (eq->this54)
return 0;
return vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
}
static void
vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, u32 a, u32 b)
{
eqlzr_t *eq = &(vortex->eq);
u32 eax, ebx;
eq->this58 = a;
eq->this5c = b;
if (eq->this54)
eax = eq->this0e;
else
eax = eq->this0a;
ebx = (eax * eq->this58) >> 0x10;
eax = (eax * eq->this5c) >> 0x10;
vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
}
static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex)
{
eqlzr_t *eq = &(vortex->eq);
u32 eax, ebx;
if (eq->this54)
eax = eq->this0e;
else
eax = eq->this0a;
ebx = (eax * eq->this58) >> 0x10;
eax = (eax * eq->this5c) >> 0x10;
vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
}
static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex)
{
if (vortex != NULL)
vortex_EqHw_ZeroA3DIO(vortex);
}
static void vortex_Eqlzr_SetBypass(vortex_t * vortex, u32 bp)
{
eqlzr_t *eq = &(vortex->eq);
if ((eq->this28) && (bp == 0)) {
/* EQ enabled */
vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
} else {
/* EQ disabled. */
vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array);
vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array);
vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
}
vortex_Eqlzr_ProgramA3dBypassGain(vortex);
}
static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex)
{
eqlzr_t *eq = &(vortex->eq);
/* Set EQ BiQuad filter coeficients */
memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t));
/* Set EQ Band gain levels and dump into hardware registers. */
vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2);
}
static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count)
{
eqlzr_t *eq = &(vortex->eq);
if (eq->this10 == 0)
return 1;
*count = eq->this10 * 2;
vortex_EqHw_GetTenBandLevels(vortex, peaks);
return 0;
}
#if 0
static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex)
{
eqlzr_t *eq = &(vortex->eq);
return (&(eq->coefset));
}
#endif
static void vortex_Eqlzr_init(vortex_t * vortex)
{
eqlzr_t *eq = &(vortex->eq);
/* Object constructor */
//eq->this04 = 0;
eq->this08 = 0; /* Bypass gain with EQ in use. */
eq->this0a = 0x5999;
eq->this0c = 0x5999; /* Bypass gain with EQ disabled. */
eq->this0e = 0x5999;
eq->this10 = 0xa; /* 10 eq frequency bands. */
eq->this04.this04 = eq->this10;
eq->this28 = 0x1; /* if 1 => Allow read access to this130 (gains) */
eq->this54 = 0x0; /* if 1 => Dont Allow access to hardware (gains) */
eq->this58 = 0xffff;
eq->this5c = 0xffff;
/* Set gains. */
memset(eq->this14_array, 0, sizeof(eq->this14_array));
/* Actual init. */
vortex_EqHw_ZeroState(vortex);
vortex_EqHw_SetSampleRate(vortex, 0x11);
vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex);
vortex_EqHw_Program10Band(vortex, &(eq->coefset));
vortex_Eqlzr_SetBypass(vortex, eq->this54);
vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0);
vortex_EqHw_Enable(vortex);
}
static void vortex_Eqlzr_shutdown(vortex_t * vortex)
{
vortex_Eqlzr_ShutDownA3d(vortex);
vortex_EqHw_ProgramPipe(vortex);
vortex_EqHw_Disable(vortex);
}
/* ALSA interface */
/* Control interface */
#define snd_vortex_eqtoggle_info snd_ctl_boolean_mono_info
static int
snd_vortex_eqtoggle_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
eqlzr_t *eq = &(vortex->eq);
//int i = kcontrol->private_value;
ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1;
return 0;
}
static int
snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
eqlzr_t *eq = &(vortex->eq);
//int i = kcontrol->private_value;
eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1;
vortex_Eqlzr_SetBypass(vortex, eq->this54);
return 1; /* Allways changes */
}
static struct snd_kcontrol_new vortex_eqtoggle_kcontrol __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "EQ Enable",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = 0,
.info = snd_vortex_eqtoggle_info,
.get = snd_vortex_eqtoggle_get,
.put = snd_vortex_eqtoggle_put
};
static int
snd_vortex_eq_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0x0000;
uinfo->value.integer.max = 0x7fff;
return 0;
}
static int
snd_vortex_eq_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
int i = kcontrol->private_value;
u16 gainL = 0, gainR = 0;
vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
ucontrol->value.integer.value[0] = gainL;
ucontrol->value.integer.value[1] = gainR;
return 0;
}
static int
snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
int changed = 0, i = kcontrol->private_value;
u16 gainL = 0, gainR = 0;
vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
if (gainL != ucontrol->value.integer.value[0]) {
vortex_Eqlzr_SetLeftGain(vortex, i,
ucontrol->value.integer.value[0]);
changed = 1;
}
if (gainR != ucontrol->value.integer.value[1]) {
vortex_Eqlzr_SetRightGain(vortex, i,
ucontrol->value.integer.value[1]);
changed = 1;
}
return changed;
}
static struct snd_kcontrol_new vortex_eq_kcontrol __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = " .",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.private_value = 0,
.info = snd_vortex_eq_info,
.get = snd_vortex_eq_get,
.put = snd_vortex_eq_put
};
static int
snd_vortex_peaks_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 20;
uinfo->value.integer.min = 0x0000;
uinfo->value.integer.max = 0x7fff;
return 0;
}
static int
snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
int i, count = 0;
u16 peaks[20];
vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
if (count != 20) {
printk(KERN_ERR "vortex: peak count error 20 != %d \n", count);
return -1;
}
for (i = 0; i < 20; i++)
ucontrol->value.integer.value[i] = peaks[i];
return 0;
}
static struct snd_kcontrol_new vortex_levels_kcontrol __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "EQ Peaks",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.info = snd_vortex_peaks_info,
.get = snd_vortex_peaks_get,
};
/* EQ band gain labels. */
static char *EqBandLabels[10] __devinitdata = {
"EQ0 31Hz\0",
"EQ1 63Hz\0",
"EQ2 125Hz\0",
"EQ3 250Hz\0",
"EQ4 500Hz\0",
"EQ5 1KHz\0",
"EQ6 2KHz\0",
"EQ7 4KHz\0",
"EQ8 8KHz\0",
"EQ9 16KHz\0",
};
/* ALSA driver entry points. Init and exit. */
static int __devinit vortex_eq_init(vortex_t * vortex)
{
struct snd_kcontrol *kcontrol;
int err, i;
vortex_Eqlzr_init(vortex);
if ((kcontrol =
snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL)
return -ENOMEM;
kcontrol->private_value = 0;
if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
return err;
/* EQ gain controls */
for (i = 0; i < 10; i++) {
if ((kcontrol =
snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL)
return -ENOMEM;
strcpy(kcontrol->id.name, EqBandLabels[i]);
kcontrol->private_value = i;
if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
return err;
//vortex->eqctrl[i] = kcontrol;
}
/* EQ band levels */
if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL)
return -ENOMEM;
if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
return err;
return 0;
}
static int vortex_eq_free(vortex_t * vortex)
{
/*
//FIXME: segfault because vortex->eqctrl[i] == 4
int i;
for (i=0; i<10; i++) {
if (vortex->eqctrl[i])
snd_ctl_remove(vortex->card, vortex->eqctrl[i]);
}
*/
vortex_Eqlzr_shutdown(vortex);
return 0;
}
/* End */

View File

@@ -0,0 +1,43 @@
#ifndef AU88X0_EQ_H
#define AU88X0_EQ_H
/***************************************************************************
* au88x0_eq.h
*
* Definitions and constant data for the Aureal Hardware EQ.
*
* Sun Jun 8 18:23:38 2003
* Author: Manuel Jander (mjander@users.sourceforge.net)
****************************************************************************/
typedef struct {
u16 LeftCoefs[50]; //0x4
u16 RightCoefs[50]; // 0x68
u16 LeftGains[10]; //0xd0
u16 RightGains[10]; //0xe4
} auxxEqCoeffSet_t;
typedef struct {
s32 this04; /* How many filters for each side (default = 10) */
s32 this08; /* inited to cero. Stereo flag? */
} eqhw_t;
typedef struct {
eqhw_t this04; /* CHwEq */
u16 this08; /* Bad codec flag ? SetBypassGain: bypass gain */
u16 this0a;
u16 this0c; /* SetBypassGain: bypass gain when this28 is not set. */
u16 this0e;
s32 this10; /* How many gains are used for each side (right or left). */
u16 this14_array[10]; /* SetLeftGainsTarget: Left (and right?) EQ gains */
s32 this28; /* flag related to EQ enabled or not. Gang flag ? */
s32 this54; /* SetBypass */
s32 this58;
s32 this5c;
/*0x60 */ auxxEqCoeffSet_t coefset;
/* 50 u16 word each channel. */
u16 this130[20]; /* Left and Right gains */
} eqlzr_t;
#endif

View File

@@ -0,0 +1,116 @@
/* Data structs */
static u16 asEqCoefsZeros[50] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
static u16 asEqCoefsPipes[64] = {
0x0000, 0x0000,
0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0666, 0x0000, 0x0000, 0x066a,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000
};
/* More coef sets can be found in the win2k "inf" file. */
static auxxEqCoeffSet_t asEqCoefsNormal = {
.LeftCoefs = {
0x7e60, 0xc19e, 0x0001, 0x0002, 0x0001,
0x7fa0, 0xc05f, 0x004f, 0x0000, 0xffb1,
0x7f3f, 0xc0bc, 0x00c2, 0x0000, 0xff3e,
0x7e78, 0xc177, 0x011f, 0x0000, 0xfee1,
0x7cd6, 0xc2e5, 0x025c, 0x0000, 0xfda4,
0x7949, 0xc5aa, 0x0467, 0x0000, 0xfb99,
0x7120, 0xcadf, 0x0864, 0x0000, 0xf79c,
0x5d33, 0xd430, 0x0f7e, 0x0000, 0xf082,
0x2beb, 0xe3ca, 0x1bd3, 0x0000, 0xe42d,
0xd740, 0xf01d, 0x2ac5, 0x0000, 0xd53b},
.RightCoefs = {
0x7e60, 0xc19e, 0x0001, 0x0002, 0x0001,
0x7fa0, 0xc05f, 0x004f, 0x0000, 0xffb1,
0x7f3f, 0xc0bc, 0x00c2, 0x0000, 0xff3e,
0x7e78, 0xc177, 0x011f, 0x0000, 0xfee1,
0x7cd6, 0xc2e5, 0x025c, 0x0000, 0xfda4,
0x7949, 0xc5aa, 0x0467, 0x0000, 0xfb99,
0x7120, 0xcadf, 0x0864, 0x0000, 0xf79c,
0x5d33, 0xd430, 0x0f7e, 0x0000, 0xf082,
0x2beb, 0xe3ca, 0x1bd3, 0x0000, 0xe42d,
0xd740, 0xf01d, 0x2ac5, 0x0000, 0xd53b},
.LeftGains = {
0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96},
.RightGains = {
0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96}
};
static u16 eq_gains_normal[20] = {
0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96
};
/* _rodatab60 */
static u16 eq_gains_zero[10] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};
/* _rodatab7c: ProgramPipe */
static u16 eq_gains_current[12] = {
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
0x7fff,
0x7fff, 0x7fff, 0x7fff
};
/* _rodatab78 */
static u16 eq_states_zero[2] = { 0x0000, 0x0000 };
static u16 asEqOutStateZeros[48] = {
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000
};
/*_rodataba0:*/
static u16 eq_levels[64] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};

View File

@@ -0,0 +1,132 @@
/*
* Manuel Jander.
*
* Based on the work of:
* Vojtech Pavlik
* Raymond Ingles
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
* Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
*
* Based 90% on Vojtech Pavlik pcigame driver.
* Merged and modified by Manuel Jander, for the OpenVortex
* driver. (email: mjander@embedded.cl).
*/
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <sound/core.h>
#include "au88x0.h"
#include <linux/gameport.h>
#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
#define VORTEX_GAME_DWAIT 20 /* 20 ms */
static unsigned char vortex_game_read(struct gameport *gameport)
{
vortex_t *vortex = gameport_get_port_data(gameport);
return hwread(vortex->mmio, VORTEX_GAME_LEGACY);
}
static void vortex_game_trigger(struct gameport *gameport)
{
vortex_t *vortex = gameport_get_port_data(gameport);
hwwrite(vortex->mmio, VORTEX_GAME_LEGACY, 0xff);
}
static int
vortex_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
{
vortex_t *vortex = gameport_get_port_data(gameport);
int i;
*buttons = (~hwread(vortex->mmio, VORTEX_GAME_LEGACY) >> 4) & 0xf;
for (i = 0; i < 4; i++) {
axes[i] =
hwread(vortex->mmio, VORTEX_GAME_AXIS + (i * AXIS_SIZE));
if (axes[i] == AXIS_RANGE)
axes[i] = -1;
}
return 0;
}
static int vortex_game_open(struct gameport *gameport, int mode)
{
vortex_t *vortex = gameport_get_port_data(gameport);
switch (mode) {
case GAMEPORT_MODE_COOKED:
hwwrite(vortex->mmio, VORTEX_CTRL2,
hwread(vortex->mmio,
VORTEX_CTRL2) | CTRL2_GAME_ADCMODE);
msleep(VORTEX_GAME_DWAIT);
return 0;
case GAMEPORT_MODE_RAW:
hwwrite(vortex->mmio, VORTEX_CTRL2,
hwread(vortex->mmio,
VORTEX_CTRL2) & ~CTRL2_GAME_ADCMODE);
return 0;
default:
return -1;
}
return 0;
}
static int __devinit vortex_gameport_register(vortex_t * vortex)
{
struct gameport *gp;
vortex->gameport = gp = gameport_allocate_port();
if (!gp) {
printk(KERN_ERR "vortex: cannot allocate memory for gameport\n");
return -ENOMEM;
};
gameport_set_name(gp, "AU88x0 Gameport");
gameport_set_phys(gp, "pci%s/gameport0", pci_name(vortex->pci_dev));
gameport_set_dev_parent(gp, &vortex->pci_dev->dev);
gp->read = vortex_game_read;
gp->trigger = vortex_game_trigger;
gp->cooked_read = vortex_game_cooked_read;
gp->open = vortex_game_open;
gameport_set_port_data(gp, vortex);
gp->fuzz = 64;
gameport_register_port(gp);
return 0;
}
static void vortex_gameport_unregister(vortex_t * vortex)
{
if (vortex->gameport) {
gameport_unregister_port(vortex->gameport);
vortex->gameport = NULL;
}
}
#else
static inline int vortex_gameport_register(vortex_t * vortex) { return -ENOSYS; }
static inline void vortex_gameport_unregister(vortex_t * vortex) { }
#endif

View File

@@ -0,0 +1,32 @@
/*
* Vortex Mixer support.
*
* There is much more than just the AC97 mixer...
*
*/
#include <linux/time.h>
#include <linux/init.h>
#include <sound/core.h>
#include "au88x0.h"
static int __devinit snd_vortex_mixer(vortex_t * vortex)
{
struct snd_ac97_bus *pbus;
struct snd_ac97_template ac97;
int err;
static struct snd_ac97_bus_ops ops = {
.write = vortex_codec_write,
.read = vortex_codec_read,
};
if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
return err;
memset(&ac97, 0, sizeof(ac97));
// Intialize AC97 codec stuff.
ac97.private_data = vortex;
ac97.scaps = AC97_SCAP_NO_SPDIF;
err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
vortex->isquad = ((vortex->codec == NULL) ? 0 : (vortex->codec->ext_id&0x80));
return err;
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of MPU-401 in UART mode
*
* Modified for the Aureal Vortex based Soundcards
* by Manuel Jander (mjande@embedded.cl).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/time.h>
#include <linux/init.h>
#include <sound/core.h>
#include <sound/mpu401.h>
#include "au88x0.h"
/* Check for mpu401 mmio support. */
/* MPU401 legacy support is only provided as a emergency fallback *
* for older versions of ALSA. Its usage is strongly discouraged. */
#ifndef MPU401_HW_AUREAL
#define VORTEX_MPU401_LEGACY
#endif
/* Vortex MPU401 defines. */
#define MIDI_CLOCK_DIV 0x61
/* Standart MPU401 defines. */
#define MPU401_RESET 0xff
#define MPU401_ENTER_UART 0x3f
#define MPU401_ACK 0xfe
static int __devinit snd_vortex_midi(vortex_t * vortex)
{
struct snd_rawmidi *rmidi;
int temp, mode;
struct snd_mpu401 *mpu;
unsigned long port;
#ifdef VORTEX_MPU401_LEGACY
/* EnableHardCodedMPU401Port() */
/* Enable Legacy MIDI Interface port. */
port = (0x03 << 5); /* FIXME: static address. 0x330 */
temp =
(hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) |
CTRL_MIDI_EN | port;
hwwrite(vortex->mmio, VORTEX_CTRL, temp);
#else
/* Disable Legacy MIDI Interface port. */
temp =
(hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) &
~CTRL_MIDI_EN;
hwwrite(vortex->mmio, VORTEX_CTRL, temp);
#endif
/* Mpu401UartInit() */
mode = 1;
temp = hwread(vortex->mmio, VORTEX_CTRL2) & 0xffff00cf;
temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4;
hwwrite(vortex->mmio, VORTEX_CTRL2, temp);
hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET);
/* Check if anything is OK. */
temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
if (temp != MPU401_ACK /*0xfe */ ) {
printk(KERN_ERR "midi port doesn't acknowledge!\n");
return -ENODEV;
}
/* Enable MPU401 interrupts. */
hwwrite(vortex->mmio, VORTEX_IRQ_CTRL,
hwread(vortex->mmio, VORTEX_IRQ_CTRL) | IRQ_MIDI);
/* Create MPU401 instance. */
#ifdef VORTEX_MPU401_LEGACY
if ((temp =
snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330,
0, 0, 0, &rmidi)) != 0) {
hwwrite(vortex->mmio, VORTEX_CTRL,
(hwread(vortex->mmio, VORTEX_CTRL) &
~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
return temp;
}
#else
port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA);
if ((temp =
snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port,
MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO,
0, 0, &rmidi)) != 0) {
hwwrite(vortex->mmio, VORTEX_CTRL,
(hwread(vortex->mmio, VORTEX_CTRL) &
~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
return temp;
}
mpu = rmidi->private_data;
mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD);
#endif
/* Overwrite MIDI name */
snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI %d", CARD_NAME_SHORT , vortex->card->number);
vortex->rmidi = rmidi;
return 0;
}

View File

@@ -0,0 +1,555 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* Vortex PCM ALSA driver.
*
* Supports ADB and WT DMA. Unfortunately, WT channels do not run yet.
* It remains stuck,and DMA transfers do not happen.
*/
#include <sound/asoundef.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include "au88x0.h"
#define VORTEX_PCM_TYPE(x) (x->name[40])
/* hardware definition */
static struct snd_pcm_hardware snd_vortex_playback_hw_adb = {
.info =
(SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 5000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 0x10000,
.period_bytes_min = 0x1,
.period_bytes_max = 0x1000,
.periods_min = 2,
.periods_max = 32,
};
#ifndef CHIP_AU8820
static struct snd_pcm_hardware snd_vortex_playback_hw_a3d = {
.info =
(SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 5000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 1,
.buffer_bytes_max = 0x10000,
.period_bytes_min = 0x100,
.period_bytes_max = 0x1000,
.periods_min = 2,
.periods_max = 64,
};
#endif
static struct snd_pcm_hardware snd_vortex_playback_hw_spdif = {
.info =
(SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW |
SNDRV_PCM_FMTBIT_A_LAW,
.rates =
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
.rate_min = 32000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 0x10000,
.period_bytes_min = 0x100,
.period_bytes_max = 0x1000,
.periods_min = 2,
.periods_max = 64,
};
#ifndef CHIP_AU8810
static struct snd_pcm_hardware snd_vortex_playback_hw_wt = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 0x10000,
.period_bytes_min = 0x0400,
.period_bytes_max = 0x1000,
.periods_min = 2,
.periods_max = 64,
};
#endif
#ifdef CHIP_AU8830
static unsigned int au8830_channels[3] = {
1, 2, 4,
};
static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = {
.count = ARRAY_SIZE(au8830_channels),
.list = au8830_channels,
.mask = 0,
};
#endif
/* open callback */
static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
{
vortex_t *vortex = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
/* Force equal size periods */
if ((err =
snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
/* Avoid PAGE_SIZE boundary to fall inside of a period. */
if ((err =
snd_pcm_hw_constraint_pow2(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
#ifndef CHIP_AU8820
if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) {
runtime->hw = snd_vortex_playback_hw_a3d;
}
#endif
if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) {
runtime->hw = snd_vortex_playback_hw_spdif;
switch (vortex->spdif_sr) {
case 32000:
runtime->hw.rates = SNDRV_PCM_RATE_32000;
break;
case 44100:
runtime->hw.rates = SNDRV_PCM_RATE_44100;
break;
case 48000:
runtime->hw.rates = SNDRV_PCM_RATE_48000;
break;
}
}
if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB
|| VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)
runtime->hw = snd_vortex_playback_hw_adb;
#ifdef CHIP_AU8830
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
runtime->hw.channels_max = 4;
snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
&hw_constraints_au8830_channels);
}
#endif
substream->runtime->private_data = NULL;
}
#ifndef CHIP_AU8810
else {
runtime->hw = snd_vortex_playback_hw_wt;
substream->runtime->private_data = NULL;
}
#endif
return 0;
}
/* close callback */
static int snd_vortex_pcm_close(struct snd_pcm_substream *substream)
{
//vortex_t *chip = snd_pcm_substream_chip(substream);
stream_t *stream = (stream_t *) substream->runtime->private_data;
// the hardware-specific codes will be here
if (stream != NULL) {
stream->substream = NULL;
stream->nr_ch = 0;
}
substream->runtime->private_data = NULL;
return 0;
}
/* hw_params callback */
static int
snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
vortex_t *chip = snd_pcm_substream_chip(substream);
stream_t *stream = (stream_t *) (substream->runtime->private_data);
int err;
// Alloc buffer memory.
err =
snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0) {
printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
return err;
}
/*
printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
params_period_bytes(hw_params), params_channels(hw_params));
*/
spin_lock_irq(&chip->lock);
// Make audio routes and config buffer DMA.
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
int dma, type = VORTEX_PCM_TYPE(substream->pcm);
/* Dealloc any routes. */
if (stream != NULL)
vortex_adb_allocroute(chip, stream->dma,
stream->nr_ch, stream->dir,
stream->type);
/* Alloc routes. */
dma =
vortex_adb_allocroute(chip, -1,
params_channels(hw_params),
substream->stream, type);
if (dma < 0) {
spin_unlock_irq(&chip->lock);
return dma;
}
stream = substream->runtime->private_data = &chip->dma_adb[dma];
stream->substream = substream;
/* Setup Buffers. */
vortex_adbdma_setbuffers(chip, dma,
params_period_bytes(hw_params),
params_periods(hw_params));
}
#ifndef CHIP_AU8810
else {
/* if (stream != NULL)
vortex_wt_allocroute(chip, substream->number, 0); */
vortex_wt_allocroute(chip, substream->number,
params_channels(hw_params));
stream = substream->runtime->private_data =
&chip->dma_wt[substream->number];
stream->dma = substream->number;
stream->substream = substream;
vortex_wtdma_setbuffers(chip, substream->number,
params_period_bytes(hw_params),
params_periods(hw_params));
}
#endif
spin_unlock_irq(&chip->lock);
return 0;
}
/* hw_free callback */
static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream)
{
vortex_t *chip = snd_pcm_substream_chip(substream);
stream_t *stream = (stream_t *) (substream->runtime->private_data);
spin_lock_irq(&chip->lock);
// Delete audio routes.
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
if (stream != NULL)
vortex_adb_allocroute(chip, stream->dma,
stream->nr_ch, stream->dir,
stream->type);
}
#ifndef CHIP_AU8810
else {
if (stream != NULL)
vortex_wt_allocroute(chip, stream->dma, 0);
}
#endif
substream->runtime->private_data = NULL;
spin_unlock_irq(&chip->lock);
return snd_pcm_lib_free_pages(substream);
}
/* prepare callback */
static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream)
{
vortex_t *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
stream_t *stream = (stream_t *) substream->runtime->private_data;
int dma = stream->dma, fmt, dir;
// set up the hardware with the current configuration.
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = 1;
else
dir = 0;
fmt = vortex_alsafmt_aspfmt(runtime->format);
spin_lock_irq(&chip->lock);
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
vortex_adbdma_setmode(chip, dma, 1, dir, fmt, 0 /*? */ ,
0);
vortex_adbdma_setstartbuffer(chip, dma, 0);
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF)
vortex_adb_setsrc(chip, dma, runtime->rate, dir);
}
#ifndef CHIP_AU8810
else {
vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0);
// FIXME: Set rate (i guess using vortex_wt_writereg() somehow).
vortex_wtdma_setstartbuffer(chip, dma, 0);
}
#endif
spin_unlock_irq(&chip->lock);
return 0;
}
/* trigger callback */
static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
vortex_t *chip = snd_pcm_substream_chip(substream);
stream_t *stream = (stream_t *) substream->runtime->private_data;
int dma = stream->dma;
spin_lock(&chip->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
// do something to start the PCM engine
//printk(KERN_INFO "vortex: start %d\n", dma);
stream->fifo_enabled = 1;
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
vortex_adbdma_resetup(chip, dma);
vortex_adbdma_startfifo(chip, dma);
}
#ifndef CHIP_AU8810
else {
printk(KERN_INFO "vortex: wt start %d\n", dma);
vortex_wtdma_startfifo(chip, dma);
}
#endif
break;
case SNDRV_PCM_TRIGGER_STOP:
// do something to stop the PCM engine
//printk(KERN_INFO "vortex: stop %d\n", dma);
stream->fifo_enabled = 0;
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
vortex_adbdma_pausefifo(chip, dma);
//vortex_adbdma_stopfifo(chip, dma);
#ifndef CHIP_AU8810
else {
printk(KERN_INFO "vortex: wt stop %d\n", dma);
vortex_wtdma_stopfifo(chip, dma);
}
#endif
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
//printk(KERN_INFO "vortex: pause %d\n", dma);
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
vortex_adbdma_pausefifo(chip, dma);
#ifndef CHIP_AU8810
else
vortex_wtdma_pausefifo(chip, dma);
#endif
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
//printk(KERN_INFO "vortex: resume %d\n", dma);
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
vortex_adbdma_resumefifo(chip, dma);
#ifndef CHIP_AU8810
else
vortex_wtdma_resumefifo(chip, dma);
#endif
break;
default:
spin_unlock(&chip->lock);
return -EINVAL;
}
spin_unlock(&chip->lock);
return 0;
}
/* pointer callback */
static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream)
{
vortex_t *chip = snd_pcm_substream_chip(substream);
stream_t *stream = (stream_t *) substream->runtime->private_data;
int dma = stream->dma;
snd_pcm_uframes_t current_ptr = 0;
spin_lock(&chip->lock);
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
current_ptr = vortex_adbdma_getlinearpos(chip, dma);
#ifndef CHIP_AU8810
else
current_ptr = vortex_wtdma_getlinearpos(chip, dma);
#endif
//printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);
spin_unlock(&chip->lock);
return (bytes_to_frames(substream->runtime, current_ptr));
}
/* operators */
static struct snd_pcm_ops snd_vortex_playback_ops = {
.open = snd_vortex_pcm_open,
.close = snd_vortex_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_vortex_pcm_hw_params,
.hw_free = snd_vortex_pcm_hw_free,
.prepare = snd_vortex_pcm_prepare,
.trigger = snd_vortex_pcm_trigger,
.pointer = snd_vortex_pcm_pointer,
.page = snd_pcm_sgbuf_ops_page,
};
/*
* definitions of capture are omitted here...
*/
static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
"AU88x0 ADB",
"AU88x0 SPDIF",
"AU88x0 A3D",
"AU88x0 WT",
"AU88x0 I2S",
};
static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
"adb",
"spdif",
"a3d",
"wt",
"i2s",
};
/* SPDIF kcontrol */
static int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;
return 0;
}
static int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.iec958.status[0] = 0xff;
ucontrol->value.iec958.status[1] = 0xff;
ucontrol->value.iec958.status[2] = 0xff;
ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
return 0;
}
static int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
ucontrol->value.iec958.status[0] = 0x00;
ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID;
ucontrol->value.iec958.status[2] = 0x00;
switch (vortex->spdif_sr) {
case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break;
case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break;
case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break;
}
return 0;
}
static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
int spdif_sr = 48000;
switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) {
case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break;
case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break;
case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break;
}
if (spdif_sr == vortex->spdif_sr)
return 0;
vortex->spdif_sr = spdif_sr;
vortex_spdif_init(vortex, vortex->spdif_sr, 1);
return 1;
}
/* spdif controls */
static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = snd_vortex_spdif_info,
.get = snd_vortex_spdif_get,
.put = snd_vortex_spdif_put,
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_vortex_spdif_info,
.get = snd_vortex_spdif_mask_get
},
};
/* create a pcm device */
static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
{
struct snd_pcm *pcm;
struct snd_kcontrol *kctl;
int i;
int err, nr_capt;
if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST)
return -ENODEV;
/* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the
* same dma engine. WT uses it own separate dma engine whcih cant capture. */
if (idx == VORTEX_PCM_ADB)
nr_capt = nr;
else
nr_capt = 0;
err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,
nr_capt, &pcm);
if (err < 0)
return err;
strcpy(pcm->name, vortex_pcm_name[idx]);
chip->pcm[idx] = pcm;
// This is an evil hack, but it saves a lot of duplicated code.
VORTEX_PCM_TYPE(pcm) = idx;
pcm->private_data = chip;
/* set operators */
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
&snd_vortex_playback_ops);
if (idx == VORTEX_PCM_ADB)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&snd_vortex_playback_ops);
/* pre-allocation of Scatter-Gather buffers */
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci_dev),
0x10000, 0x10000);
if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);
if (!kctl)
return -ENOMEM;
if ((err = snd_ctl_add(chip->card, kctl)) < 0)
return err;
}
}
return 0;
}

View File

@@ -0,0 +1,418 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* Someday its supposed to make use of the WT DMA engine
* for a Wavetable synthesizer.
*/
#include "au88x0.h"
#include "au88x0_wt.h"
static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en);
static void vortex_connection_adb_mixin(vortex_t * vortex, int en,
unsigned char channel,
unsigned char source,
unsigned char mixin);
static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
unsigned char mixin,
unsigned char mix, int a);
static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j);
static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
u32 val);
/* WT */
/* Put 2 WT channels together for one stereo interlaced channel. */
static void vortex_wt_setstereo(vortex_t * vortex, u32 wt, u32 stereo)
{
int temp;
//temp = hwread(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2));
temp = hwread(vortex->mmio, WT_STEREO(wt));
temp = (temp & 0xfe) | (stereo & 1);
//hwwrite(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2), temp);
hwwrite(vortex->mmio, WT_STEREO(wt), temp);
}
/* Join to mixdown route. */
static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en)
{
int temp;
/* There is one DSREG register for each bank (32 voices each). */
temp = hwread(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0));
if (en)
temp |= (1 << (wt & 0x1f));
else
temp &= (1 << ~(wt & 0x1f));
hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp);
}
/* Setup WT route. */
static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
{
wt_voice_t *voice = &(vortex->wt_voice[wt]);
int temp;
//FIXME: WT audio routing.
if (nr_ch) {
vortex_fifo_wtinitialize(vortex, wt, 1);
vortex_fifo_setwtvalid(vortex, wt, 1);
vortex_wt_setstereo(vortex, wt, nr_ch - 1);
} else
vortex_fifo_setwtvalid(vortex, wt, 0);
/* Set mixdown mode. */
vortex_wt_setdsout(vortex, wt, 1);
/* Set other parameter registers. */
hwwrite(vortex->mmio, WT_SRAMP(0), 0x880000);
//hwwrite(vortex->mmio, WT_GMODE(0), 0xffffffff);
#ifdef CHIP_AU8830
hwwrite(vortex->mmio, WT_SRAMP(1), 0x880000);
//hwwrite(vortex->mmio, WT_GMODE(1), 0xffffffff);
#endif
hwwrite(vortex->mmio, WT_PARM(wt, 0), 0);
hwwrite(vortex->mmio, WT_PARM(wt, 1), 0);
hwwrite(vortex->mmio, WT_PARM(wt, 2), 0);
temp = hwread(vortex->mmio, WT_PARM(wt, 3));
printk(KERN_DEBUG "vortex: WT PARM3: %x\n", temp);
//hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
hwwrite(vortex->mmio, WT_DELAY(wt, 1), 0);
hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0);
hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0);
printk(KERN_DEBUG "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
voice->parm0 = voice->parm1 = 0xcfb23e2f;
hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
printk(KERN_DEBUG "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
return 0;
}
static void vortex_wt_connect(vortex_t * vortex, int en)
{
int i, ii, mix;
#define NR_WTROUTES 6
#ifdef CHIP_AU8830
#define NR_WTBLOCKS 2
#else
#define NR_WTBLOCKS 1
#endif
for (i = 0; i < NR_WTBLOCKS; i++) {
for (ii = 0; ii < NR_WTROUTES; ii++) {
mix =
vortex_adb_checkinout(vortex,
vortex->fixed_res, en,
VORTEX_RESOURCE_MIXIN);
vortex->mixwt[(i * NR_WTROUTES) + ii] = mix;
vortex_route(vortex, en, 0x11,
ADB_WTOUT(i, ii + 0x20), ADB_MIXIN(mix));
vortex_connection_mixin_mix(vortex, en, mix,
vortex->mixplayb[ii % 2], 0);
if (VORTEX_IS_QUAD(vortex))
vortex_connection_mixin_mix(vortex, en,
mix,
vortex->mixplayb[2 +
(ii % 2)], 0);
}
}
for (i = 0; i < NR_WT; i++) {
hwwrite(vortex->mmio, WT_RUN(i), 1);
}
}
/* Read WT Register */
#if 0
static int vortex_wt_GetReg(vortex_t * vortex, char reg, int wt)
{
//int eax, esi;
if (reg == 4) {
return hwread(vortex->mmio, WT_PARM(wt, 3));
}
if (reg == 7) {
return hwread(vortex->mmio, WT_GMODE(wt));
}
return 0;
}
/* WT hardware abstraction layer generic register interface. */
static int
vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt,
u16 val)
{
/*
int eax, edx;
if (wt >= NR_WT) // 0x40 -> NR_WT
return 0;
if ((reg - 0x20) > 0) {
if ((reg - 0x21) != 0)
return 0;
eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x208; // param 2
} else {
eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x20a; // param 3
}
hwwrite(vortex->mmio, eax, c);
*/
return 1;
}
/*public: static void __thiscall CWTHal::SetReg(unsigned char,int,unsigned long) */
#endif
static int
vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
u32 val)
{
int ecx;
if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
if (wt >= (NR_WT / NR_WT_PB)) {
printk
("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
reg, wt);
return 0;
}
} else {
if (wt >= NR_WT) {
printk(KERN_ERR "vortex: WT SetReg: voice out of range\n");
return 0;
}
}
if (reg > 0xc)
return 0;
switch (reg) {
/* Voice specific parameters */
case 0: /* running */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
WT_RUN(wt), (int)val);
*/
hwwrite(vortex->mmio, WT_RUN(wt), val);
return 0xc;
break;
case 1: /* param 0 */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
WT_PARM(wt,0), (int)val);
*/
hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
return 0xc;
break;
case 2: /* param 1 */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
WT_PARM(wt,1), (int)val);
*/
hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
return 0xc;
break;
case 3: /* param 2 */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
WT_PARM(wt,2), (int)val);
*/
hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
return 0xc;
break;
case 4: /* param 3 */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
WT_PARM(wt,3), (int)val);
*/
hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
return 0xc;
break;
case 6: /* mute */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
WT_MUTE(wt), (int)val);
*/
hwwrite(vortex->mmio, WT_MUTE(wt), val);
return 0xc;
break;
case 0xb:
{ /* delay */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
WT_DELAY(wt,0), (int)val);
*/
hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
hwwrite(vortex->mmio, WT_DELAY(wt, 2), val);
hwwrite(vortex->mmio, WT_DELAY(wt, 1), val);
hwwrite(vortex->mmio, WT_DELAY(wt, 0), val);
return 0xc;
}
break;
/* Global WT block parameters */
case 5: /* sramp */
ecx = WT_SRAMP(wt);
break;
case 8: /* aramp */
ecx = WT_ARAMP(wt);
break;
case 9: /* mramp */
ecx = WT_MRAMP(wt);
break;
case 0xa: /* ctrl */
ecx = WT_CTRL(wt);
break;
case 0xc: /* ds_reg */
ecx = WT_DSREG(wt);
break;
default:
return 0;
break;
}
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
*/
hwwrite(vortex->mmio, ecx, val);
return 1;
}
static void vortex_wt_init(vortex_t * vortex)
{
u32 var4, var8, varc, var10 = 0, edi;
var10 &= 0xFFFFFFE3;
var10 |= 0x22;
var10 &= 0xFFFFFEBF;
var10 |= 0x80;
var10 |= 0x200;
var10 &= 0xfffffffe;
var10 &= 0xfffffbff;
var10 |= 0x1800;
// var10 = 0x1AA2
var4 = 0x10000000;
varc = 0x00830000;
var8 = 0x00830000;
/* Init Bank registers. */
for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++) {
vortex_wt_SetReg(vortex, 0xc, edi, 0); /* ds_reg */
vortex_wt_SetReg(vortex, 0xa, edi, var10); /* ctrl */
vortex_wt_SetReg(vortex, 0x9, edi, var4); /* mramp */
vortex_wt_SetReg(vortex, 0x8, edi, varc); /* aramp */
vortex_wt_SetReg(vortex, 0x5, edi, var8); /* sramp */
}
/* Init Voice registers. */
for (edi = 0; edi < NR_WT; edi++) {
vortex_wt_SetReg(vortex, 0x4, edi, 0); /* param 3 0x20c */
vortex_wt_SetReg(vortex, 0x3, edi, 0); /* param 2 0x208 */
vortex_wt_SetReg(vortex, 0x2, edi, 0); /* param 1 0x204 */
vortex_wt_SetReg(vortex, 0x1, edi, 0); /* param 0 0x200 */
vortex_wt_SetReg(vortex, 0xb, edi, 0); /* delay 0x400 - 0x40c */
}
var10 |= 1;
for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++)
vortex_wt_SetReg(vortex, 0xa, edi, var10); /* ctrl */
}
/* Extract of CAdbTopology::SetVolume(struct _ASPVOLUME *) */
#if 0
static void vortex_wt_SetVolume(vortex_t * vortex, int wt, int vol[])
{
wt_voice_t *voice = &(vortex->wt_voice[wt]);
int ecx = vol[1], eax = vol[0];
/* This is pure guess */
voice->parm0 &= 0xff00ffff;
voice->parm0 |= (vol[0] & 0xff) << 0x10;
voice->parm1 &= 0xff00ffff;
voice->parm1 |= (vol[1] & 0xff) << 0x10;
/* This is real */
hwwrite(vortex, WT_PARM(wt, 0), voice->parm0);
hwwrite(vortex, WT_PARM(wt, 1), voice->parm0);
if (voice->this_1D0 & 4) {
eax >>= 8;
ecx = eax;
if (ecx < 0x80)
ecx = 0x7f;
voice->parm3 &= 0xFFFFC07F;
voice->parm3 |= (ecx & 0x7f) << 7;
voice->parm3 &= 0xFFFFFF80;
voice->parm3 |= (eax & 0x7f);
} else {
voice->parm3 &= 0xFFE03FFF;
voice->parm3 |= (eax & 0xFE00) << 5;
}
hwwrite(vortex, WT_PARM(wt, 3), voice->parm3);
}
/* Extract of CAdbTopology::SetFrequency(unsigned long arg_0) */
static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
{
wt_voice_t *voice = &(vortex->wt_voice[wt]);
u32 eax, edx;
//FIXME: 64 bit operation.
eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff;
edx = (((sr << 0xf) * 0x57619F1)) >> 0x20;
edx >>= 0xa;
edx <<= 1;
if (edx) {
if (edx & 0x0FFF80000)
eax = 0x7fff;
else {
edx <<= 0xd;
eax = 7;
while ((edx & 0x80000000) == 0) {
edx <<= 1;
eax--;
if (eax == 0)
break;
}
if (eax)
edx <<= 1;
eax <<= 0xc;
edx >>= 0x14;
eax |= edx;
}
} else
eax = 0;
voice->parm0 &= 0xffff0001;
voice->parm0 |= (eax & 0x7fff) << 1;
voice->parm1 = voice->parm0 | 1;
// Wt: this_1D4
//AuWt::WriteReg((ulong)(this_1DC<<4)+0x200, (ulong)this_1E4);
//AuWt::WriteReg((ulong)(this_1DC<<4)+0x204, (ulong)this_1E8);
hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
}
#endif
/* End of File */

View File

@@ -0,0 +1,65 @@
/***************************************************************************
* WT register offsets.
*
* Wed Oct 22 13:50:20 2003
* Copyright 2003 mjander
* mjander@users.sourceforge.org
****************************************************************************/
#ifndef _AU88X0_WT_H
#define _AU88X0_WT_H
/* WT channels are grouped in banks. Each bank has 0x20 channels. */
/* Bank register address boundary is 0x8000 */
#define NR_WT_PB 0x20
/* WT bank base register (as dword address). */
#define WT_BAR(x) (((x)&0xffe0)<<0x8)
#define WT_BANK(x) (x>>5)
/* WT Bank registers */
#define WT_CTRL(bank) (((((bank)&1)<<0xd) + 0x00)<<2) /* 0x0000 */
#define WT_SRAMP(bank) (((((bank)&1)<<0xd) + 0x01)<<2) /* 0x0004 */
#define WT_DSREG(bank) (((((bank)&1)<<0xd) + 0x02)<<2) /* 0x0008 */
#define WT_MRAMP(bank) (((((bank)&1)<<0xd) + 0x03)<<2) /* 0x000c */
#define WT_GMODE(bank) (((((bank)&1)<<0xd) + 0x04)<<2) /* 0x0010 */
#define WT_ARAMP(bank) (((((bank)&1)<<0xd) + 0x05)<<2) /* 0x0014 */
/* WT Voice registers */
#define WT_STEREO(voice) ((WT_BAR(voice)+ 0x20 +(((voice)&0x1f)>>1))<<2) /* 0x0080 */
#define WT_MUTE(voice) ((WT_BAR(voice)+ 0x40 +((voice)&0x1f))<<2) /* 0x0100 */
#define WT_RUN(voice) ((WT_BAR(voice)+ 0x60 +((voice)&0x1f))<<2) /* 0x0180 */
/* Some kind of parameters. */
/* PARM0, PARM1 : Filter (0xFF000000), SampleRate (0x0000FFFF) */
/* PARM2, PARM3 : Still unknown */
#define WT_PARM(x,y) (((WT_BAR(x))+ 0x80 +(((x)&0x1f)<<2)+(y))<<2) /* 0x0200 */
#define WT_DELAY(x,y) (((WT_BAR(x))+ 0x100 +(((x)&0x1f)<<2)+(y))<<2) /* 0x0400 */
/* Numeric indexes used by SetReg() and GetReg() */
#if 0
enum {
run = 0, /* 0 W 1:run 0:stop */
parm0, /* 1 W filter, samplerate */
parm1, /* 2 W filter, samplerate */
parm2, /* 3 W */
parm3, /* 4 RW volume. This value is calculated using floating point ops. */
sramp, /* 5 W */
mute, /* 6 W 1:mute, 0:unmute */
gmode, /* 7 RO Looks like only bit0 is used. */
aramp, /* 8 W */
mramp, /* 9 W */
ctrl, /* a W */
delay, /* b W All 4 values are written at once with same value. */
dsreg, /* c (R)W */
} wt_reg;
#endif
typedef struct {
u32 parm0; /* this_1E4 */
u32 parm1; /* this_1E8 */
u32 parm2; /* this_1EC */
u32 parm3; /* this_1F0 */
u32 this_1D0;
} wt_voice_t;
#endif /* _AU88X0_WT_H */
/* End of file */

View File

@@ -0,0 +1,770 @@
/***************************************************************************
* au88x0_cxtalk.c
*
* Wed Nov 19 16:29:47 2003
* Copyright 2003 mjander
* mjander@users.sourceforge.org
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "au88x0_xtalk.h"
/* Data (a whole lot of data.... ) */
static short const sXtalkWideKLeftEq = 0x269C;
static short const sXtalkWideKRightEq = 0x269C;
static short const sXtalkWideKLeftXt = 0xF25E;
static short const sXtalkWideKRightXt = 0xF25E;
static short const sXtalkWideShiftLeftEq = 1;
static short const sXtalkWideShiftRightEq = 1;
static short const sXtalkWideShiftLeftXt = 0;
static short const sXtalkWideShiftRightXt = 0;
static unsigned short const wXtalkWideLeftDelay = 0xd;
static unsigned short const wXtalkWideRightDelay = 0xd;
static short const sXtalkNarrowKLeftEq = 0x468D;
static short const sXtalkNarrowKRightEq = 0x468D;
static short const sXtalkNarrowKLeftXt = 0xF82E;
static short const sXtalkNarrowKRightXt = 0xF82E;
static short const sXtalkNarrowShiftLeftEq = 0x3;
static short const sXtalkNarrowShiftRightEq = 0x3;
static short const sXtalkNarrowShiftLeftXt = 0;
static short const sXtalkNarrowShiftRightXt = 0;
static unsigned short const wXtalkNarrowLeftDelay = 0x7;
static unsigned short const wXtalkNarrowRightDelay = 0x7;
static xtalk_gains_t const asXtalkGainsDefault = {
0x4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000,
0x4000
};
static xtalk_gains_t const asXtalkGainsTest = {
0x8000, 0x7FFF, 0, 0xFFFF, 0x0001, 0xC000, 0x4000, 0xFFFE, 0x0002,
0
};
static xtalk_gains_t const asXtalkGains1Chan = {
0x7FFF, 0, 0, 0, 0x7FFF, 0, 0, 0, 0, 0
};
// Input gain for 4 A3D slices. One possible input pair is left zero.
static xtalk_gains_t const asXtalkGainsAllChan = {
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0
//0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff
};
static xtalk_gains_t const asXtalkGainsZeros;
static xtalk_dline_t const alXtalkDlineZeros;
static xtalk_dline_t const alXtalkDlineTest = {
0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
};
static xtalk_instate_t const asXtalkInStateZeros;
static xtalk_instate_t const asXtalkInStateTest =
{ 0xFF80, 0x0080, 0xFFFF, 0x0001 };
static xtalk_state_t const asXtalkOutStateZeros;
static short const sDiamondKLeftEq = 0x401d;
static short const sDiamondKRightEq = 0x401d;
static short const sDiamondKLeftXt = 0xF90E;
static short const sDiamondKRightXt = 0xF90E;
static short const sDiamondShiftLeftEq = 1; /* 0xF90E Is this a bug ??? */
static short const sDiamondShiftRightEq = 1;
static short const sDiamondShiftLeftXt = 0;
static short const sDiamondShiftRightXt = 0;
static unsigned short const wDiamondLeftDelay = 0xb;
static unsigned short const wDiamondRightDelay = 0xb;
static xtalk_coefs_t const asXtalkWideCoefsLeftEq = {
{0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0},
{0x5F60, 0xCBCB, 0xFC26, 0x0305, 0},
{0x340B, 0xf504, 0x6CE8, 0x0D23, 0x00E4},
{0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA},
{0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0}
};
static xtalk_coefs_t const asXtalkWideCoefsRightEq = {
{0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0},
{0x5F60, 0xCBCB, 0xFC26, 0x0305, 0},
{0x340B, 0xF504, 0x6CE8, 0x0D23, 0x00E4},
{0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA},
{0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0}
};
static xtalk_coefs_t const asXtalkWideCoefsLeftXt = {
{0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047},
{0x6000, 0x206A, 0xC6CA, 0x40FF, 0},
{0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001},
{0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0},
{0, 0, 0, 0, 0}
};
static xtalk_coefs_t const asXtalkWideCoefsRightXt = {
{0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047},
{0x6000, 0x206A, 0xC6CA, 0x40FF, 0},
{0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001},
{0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0},
{0, 0, 0, 0, 0}
};
static xtalk_coefs_t const asXtalkNarrowCoefsLeftEq = {
{0x50B5, 0xD07C, 0x026D, 0xFD21, 0},
{0x460F, 0xE44F, 0xF75E, 0xEFA6, 0},
{0x556D, 0xDCAB, 0x2098, 0xF0F2, 0},
{0x7E03, 0xC1F0, 0x007D, 0xFF89, 0},
{0x383E, 0xFD9D, 0xB278, 0x4547, 0}
};
static xtalk_coefs_t const asXtalkNarrowCoefsRightEq = {
{0x50B5, 0xD07C, 0x026D, 0xFD21, 0},
{0x460F, 0xE44F, 0xF75E, 0xEFA6, 0},
{0x556D, 0xDCAB, 0x2098, 0xF0F2, 0},
{0x7E03, 0xC1F0, 0x007D, 0xFF89, 0},
{0x383E, 0xFD9D, 0xB278, 0x4547, 0}
};
static xtalk_coefs_t const asXtalkNarrowCoefsLeftXt = {
{0x3CB2, 0xDF49, 0xF6EA, 0x095B, 0},
{0x6777, 0xC915, 0xFEAF, 0x00B1, 0},
{0x7762, 0xC7D9, 0x025B, 0xFDA6, 0},
{0x6B7A, 0xD2AA, 0xF2FB, 0x0B64, 0},
{0, 0, 0, 0, 0}
};
static xtalk_coefs_t const asXtalkNarrowCoefsRightXt = {
{0x3CB2, 0xDF49, 0xF6EA, 0x095B, 0},
{0x6777, 0xC915, 0xFEAF, 0x00B1, 0},
{0x7762, 0xC7D9, 0x025B, 0xFDA6, 0},
{0x6B7A, 0xD2AA, 0xF2FB, 0x0B64, 0},
{0, 0, 0, 0, 0}
};
static xtalk_coefs_t const asXtalkCoefsZeros;
static xtalk_coefs_t const asXtalkCoefsPipe = {
{0, 0, 0x0FA0, 0, 0},
{0, 0, 0x0FA0, 0, 0},
{0, 0, 0x0FA0, 0, 0},
{0, 0, 0x0FA0, 0, 0},
{0, 0, 0x1180, 0, 0},
};
static xtalk_coefs_t const asXtalkCoefsNegPipe = {
{0, 0, 0xF380, 0, 0},
{0, 0, 0xF380, 0, 0},
{0, 0, 0xF380, 0, 0},
{0, 0, 0xF380, 0, 0},
{0, 0, 0xF200, 0, 0}
};
static xtalk_coefs_t const asXtalkCoefsNumTest = {
{0, 0, 0xF380, 0x8000, 0x6D60},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
static xtalk_coefs_t const asXtalkCoefsDenTest = {
{0xC000, 0x2000, 0x4000, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
static xtalk_state_t const asXtalkOutStateTest = {
{0x7FFF, 0x0004, 0xFFFC, 0},
{0xFE00, 0x0008, 0xFFF8, 0x4000},
{0x200, 0x0010, 0xFFF0, 0xC000},
{0x8000, 0x0020, 0xFFE0, 0},
{0, 0, 0, 0}
};
static xtalk_coefs_t const asDiamondCoefsLeftEq = {
{0x0F1E, 0x2D05, 0xF8E3, 0x07C8, 0},
{0x45E2, 0xCA51, 0x0448, 0xFCE7, 0},
{0xA93E, 0xDBD5, 0x022C, 0x028A, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
static xtalk_coefs_t const asDiamondCoefsRightEq = {
{0x0F1E, 0x2D05, 0xF8E3, 0x07C8, 0},
{0x45E2, 0xCA51, 0x0448, 0xFCE7, 0},
{0xA93E, 0xDBD5, 0x022C, 0x028A, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
static xtalk_coefs_t const asDiamondCoefsLeftXt = {
{0x3B50, 0xFE08, 0xF959, 0x0060, 0},
{0x9FCB, 0xD8F1, 0x00A2, 0x003A, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
static xtalk_coefs_t const asDiamondCoefsRightXt = {
{0x3B50, 0xFE08, 0xF959, 0x0060, 0},
{0x9FCB, 0xD8F1, 0x00A2, 0x003A, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}
};
/**/
/* XTalk EQ and XT */
static void
vortex_XtalkHw_SetLeftEQ(vortex_t * vortex, short arg_0, short arg_4,
xtalk_coefs_t const coefs)
{
int i;
for (i = 0; i < 5; i++) {
hwwrite(vortex->mmio, 0x24200 + i * 0x24, coefs[i][0]);
hwwrite(vortex->mmio, 0x24204 + i * 0x24, coefs[i][1]);
hwwrite(vortex->mmio, 0x24208 + i * 0x24, coefs[i][2]);
hwwrite(vortex->mmio, 0x2420c + i * 0x24, coefs[i][3]);
hwwrite(vortex->mmio, 0x24210 + i * 0x24, coefs[i][4]);
}
hwwrite(vortex->mmio, 0x24538, arg_0 & 0xffff);
hwwrite(vortex->mmio, 0x2453C, arg_4 & 0xffff);
}
static void
vortex_XtalkHw_SetRightEQ(vortex_t * vortex, short arg_0, short arg_4,
xtalk_coefs_t const coefs)
{
int i;
for (i = 0; i < 5; i++) {
hwwrite(vortex->mmio, 0x242b4 + i * 0x24, coefs[i][0]);
hwwrite(vortex->mmio, 0x242b8 + i * 0x24, coefs[i][1]);
hwwrite(vortex->mmio, 0x242bc + i * 0x24, coefs[i][2]);
hwwrite(vortex->mmio, 0x242c0 + i * 0x24, coefs[i][3]);
hwwrite(vortex->mmio, 0x242c4 + i * 0x24, coefs[i][4]);
}
hwwrite(vortex->mmio, 0x24540, arg_0 & 0xffff);
hwwrite(vortex->mmio, 0x24544, arg_4 & 0xffff);
}
static void
vortex_XtalkHw_SetLeftXT(vortex_t * vortex, short arg_0, short arg_4,
xtalk_coefs_t const coefs)
{
int i;
for (i = 0; i < 5; i++) {
hwwrite(vortex->mmio, 0x24368 + i * 0x24, coefs[i][0]);
hwwrite(vortex->mmio, 0x2436c + i * 0x24, coefs[i][1]);
hwwrite(vortex->mmio, 0x24370 + i * 0x24, coefs[i][2]);
hwwrite(vortex->mmio, 0x24374 + i * 0x24, coefs[i][3]);
hwwrite(vortex->mmio, 0x24378 + i * 0x24, coefs[i][4]);
}
hwwrite(vortex->mmio, 0x24548, arg_0 & 0xffff);
hwwrite(vortex->mmio, 0x2454C, arg_4 & 0xffff);
}
static void
vortex_XtalkHw_SetRightXT(vortex_t * vortex, short arg_0, short arg_4,
xtalk_coefs_t const coefs)
{
int i;
for (i = 0; i < 5; i++) {
hwwrite(vortex->mmio, 0x2441C + i * 0x24, coefs[i][0]);
hwwrite(vortex->mmio, 0x24420 + i * 0x24, coefs[i][1]);
hwwrite(vortex->mmio, 0x24424 + i * 0x24, coefs[i][2]);
hwwrite(vortex->mmio, 0x24428 + i * 0x24, coefs[i][3]);
hwwrite(vortex->mmio, 0x2442C + i * 0x24, coefs[i][4]);
}
hwwrite(vortex->mmio, 0x24550, arg_0 & 0xffff);
hwwrite(vortex->mmio, 0x24554, arg_4 & 0xffff);
}
static void
vortex_XtalkHw_SetLeftEQStates(vortex_t * vortex,
xtalk_instate_t const arg_0,
xtalk_state_t const coefs)
{
int i;
for (i = 0; i < 5; i++) {
hwwrite(vortex->mmio, 0x24214 + i * 0x24, coefs[i][0]);
hwwrite(vortex->mmio, 0x24218 + i * 0x24, coefs[i][1]);
hwwrite(vortex->mmio, 0x2421C + i * 0x24, coefs[i][2]);
hwwrite(vortex->mmio, 0x24220 + i * 0x24, coefs[i][3]);
}
hwwrite(vortex->mmio, 0x244F8 + i * 0x24, arg_0[0]);
hwwrite(vortex->mmio, 0x244FC + i * 0x24, arg_0[1]);
hwwrite(vortex->mmio, 0x24500 + i * 0x24, arg_0[2]);
hwwrite(vortex->mmio, 0x24504 + i * 0x24, arg_0[3]);
}
static void
vortex_XtalkHw_SetRightEQStates(vortex_t * vortex,
xtalk_instate_t const arg_0,
xtalk_state_t const coefs)
{
int i;
for (i = 0; i < 5; i++) {
hwwrite(vortex->mmio, 0x242C8 + i * 0x24, coefs[i][0]);
hwwrite(vortex->mmio, 0x242CC + i * 0x24, coefs[i][1]);
hwwrite(vortex->mmio, 0x242D0 + i * 0x24, coefs[i][2]);
hwwrite(vortex->mmio, 0x244D4 + i * 0x24, coefs[i][3]);
}
hwwrite(vortex->mmio, 0x24508 + i * 0x24, arg_0[0]);
hwwrite(vortex->mmio, 0x2450C + i * 0x24, arg_0[1]);
hwwrite(vortex->mmio, 0x24510 + i * 0x24, arg_0[2]);
hwwrite(vortex->mmio, 0x24514 + i * 0x24, arg_0[3]);
}
static void
vortex_XtalkHw_SetLeftXTStates(vortex_t * vortex,
xtalk_instate_t const arg_0,
xtalk_state_t const coefs)
{
int i;
for (i = 0; i < 5; i++) {
hwwrite(vortex->mmio, 0x2437C + i * 0x24, coefs[i][0]);
hwwrite(vortex->mmio, 0x24380 + i * 0x24, coefs[i][1]);
hwwrite(vortex->mmio, 0x24384 + i * 0x24, coefs[i][2]);
hwwrite(vortex->mmio, 0x24388 + i * 0x24, coefs[i][3]);
}
hwwrite(vortex->mmio, 0x24518 + i * 0x24, arg_0[0]);
hwwrite(vortex->mmio, 0x2451C + i * 0x24, arg_0[1]);
hwwrite(vortex->mmio, 0x24520 + i * 0x24, arg_0[2]);
hwwrite(vortex->mmio, 0x24524 + i * 0x24, arg_0[3]);
}
static void
vortex_XtalkHw_SetRightXTStates(vortex_t * vortex,
xtalk_instate_t const arg_0,
xtalk_state_t const coefs)
{
int i;
for (i = 0; i < 5; i++) {
hwwrite(vortex->mmio, 0x24430 + i * 0x24, coefs[i][0]);
hwwrite(vortex->mmio, 0x24434 + i * 0x24, coefs[i][1]);
hwwrite(vortex->mmio, 0x24438 + i * 0x24, coefs[i][2]);
hwwrite(vortex->mmio, 0x2443C + i * 0x24, coefs[i][3]);
}
hwwrite(vortex->mmio, 0x24528 + i * 0x24, arg_0[0]);
hwwrite(vortex->mmio, 0x2452C + i * 0x24, arg_0[1]);
hwwrite(vortex->mmio, 0x24530 + i * 0x24, arg_0[2]);
hwwrite(vortex->mmio, 0x24534 + i * 0x24, arg_0[3]);
}
#if 0
static void
vortex_XtalkHw_GetLeftEQ(vortex_t * vortex, short *arg_0, short *arg_4,
xtalk_coefs_t coefs)
{
int i;
for (i = 0; i < 5; i++) {
coefs[i][0] = hwread(vortex->mmio, 0x24200 + i * 0x24);
coefs[i][1] = hwread(vortex->mmio, 0x24204 + i * 0x24);
coefs[i][2] = hwread(vortex->mmio, 0x24208 + i * 0x24);
coefs[i][3] = hwread(vortex->mmio, 0x2420c + i * 0x24);
coefs[i][4] = hwread(vortex->mmio, 0x24210 + i * 0x24);
}
*arg_0 = hwread(vortex->mmio, 0x24538) & 0xffff;
*arg_4 = hwread(vortex->mmio, 0x2453c) & 0xffff;
}
static void
vortex_XtalkHw_GetRightEQ(vortex_t * vortex, short *arg_0, short *arg_4,
xtalk_coefs_t coefs)
{
int i;
for (i = 0; i < 5; i++) {
coefs[i][0] = hwread(vortex->mmio, 0x242b4 + i * 0x24);
coefs[i][1] = hwread(vortex->mmio, 0x242b8 + i * 0x24);
coefs[i][2] = hwread(vortex->mmio, 0x242bc + i * 0x24);
coefs[i][3] = hwread(vortex->mmio, 0x242c0 + i * 0x24);
coefs[i][4] = hwread(vortex->mmio, 0x242c4 + i * 0x24);
}
*arg_0 = hwread(vortex->mmio, 0x24540) & 0xffff;
*arg_4 = hwread(vortex->mmio, 0x24544) & 0xffff;
}
static void
vortex_XtalkHw_GetLeftXT(vortex_t * vortex, short *arg_0, short *arg_4,
xtalk_coefs_t coefs)
{
int i;
for (i = 0; i < 5; i++) {
coefs[i][0] = hwread(vortex->mmio, 0x24368 + i * 0x24);
coefs[i][1] = hwread(vortex->mmio, 0x2436C + i * 0x24);
coefs[i][2] = hwread(vortex->mmio, 0x24370 + i * 0x24);
coefs[i][3] = hwread(vortex->mmio, 0x24374 + i * 0x24);
coefs[i][4] = hwread(vortex->mmio, 0x24378 + i * 0x24);
}
*arg_0 = hwread(vortex->mmio, 0x24548) & 0xffff;
*arg_4 = hwread(vortex->mmio, 0x2454C) & 0xffff;
}
static void
vortex_XtalkHw_GetRightXT(vortex_t * vortex, short *arg_0, short *arg_4,
xtalk_coefs_t coefs)
{
int i;
for (i = 0; i < 5; i++) {
coefs[i][0] = hwread(vortex->mmio, 0x2441C + i * 0x24);
coefs[i][1] = hwread(vortex->mmio, 0x24420 + i * 0x24);
coefs[i][2] = hwread(vortex->mmio, 0x24424 + i * 0x24);
coefs[i][3] = hwread(vortex->mmio, 0x24428 + i * 0x24);
coefs[i][4] = hwread(vortex->mmio, 0x2442C + i * 0x24);
}
*arg_0 = hwread(vortex->mmio, 0x24550) & 0xffff;
*arg_4 = hwread(vortex->mmio, 0x24554) & 0xffff;
}
static void
vortex_XtalkHw_GetLeftEQStates(vortex_t * vortex, xtalk_instate_t arg_0,
xtalk_state_t coefs)
{
int i;
for (i = 0; i < 5; i++) {
coefs[i][0] = hwread(vortex->mmio, 0x24214 + i * 0x24);
coefs[i][1] = hwread(vortex->mmio, 0x24218 + i * 0x24);
coefs[i][2] = hwread(vortex->mmio, 0x2421C + i * 0x24);
coefs[i][3] = hwread(vortex->mmio, 0x24220 + i * 0x24);
}
arg_0[0] = hwread(vortex->mmio, 0x244F8 + i * 0x24);
arg_0[1] = hwread(vortex->mmio, 0x244FC + i * 0x24);
arg_0[2] = hwread(vortex->mmio, 0x24500 + i * 0x24);
arg_0[3] = hwread(vortex->mmio, 0x24504 + i * 0x24);
}
static void
vortex_XtalkHw_GetRightEQStates(vortex_t * vortex, xtalk_instate_t arg_0,
xtalk_state_t coefs)
{
int i;
for (i = 0; i < 5; i++) {
coefs[i][0] = hwread(vortex->mmio, 0x242C8 + i * 0x24);
coefs[i][1] = hwread(vortex->mmio, 0x242CC + i * 0x24);
coefs[i][2] = hwread(vortex->mmio, 0x242D0 + i * 0x24);
coefs[i][3] = hwread(vortex->mmio, 0x242D4 + i * 0x24);
}
arg_0[0] = hwread(vortex->mmio, 0x24508 + i * 0x24);
arg_0[1] = hwread(vortex->mmio, 0x2450C + i * 0x24);
arg_0[2] = hwread(vortex->mmio, 0x24510 + i * 0x24);
arg_0[3] = hwread(vortex->mmio, 0x24514 + i * 0x24);
}
static void
vortex_XtalkHw_GetLeftXTStates(vortex_t * vortex, xtalk_instate_t arg_0,
xtalk_state_t coefs)
{
int i;
for (i = 0; i < 5; i++) {
coefs[i][0] = hwread(vortex->mmio, 0x2437C + i * 0x24);
coefs[i][1] = hwread(vortex->mmio, 0x24380 + i * 0x24);
coefs[i][2] = hwread(vortex->mmio, 0x24384 + i * 0x24);
coefs[i][3] = hwread(vortex->mmio, 0x24388 + i * 0x24);
}
arg_0[0] = hwread(vortex->mmio, 0x24518 + i * 0x24);
arg_0[1] = hwread(vortex->mmio, 0x2451C + i * 0x24);
arg_0[2] = hwread(vortex->mmio, 0x24520 + i * 0x24);
arg_0[3] = hwread(vortex->mmio, 0x24524 + i * 0x24);
}
static void
vortex_XtalkHw_GetRightXTStates(vortex_t * vortex, xtalk_instate_t arg_0,
xtalk_state_t coefs)
{
int i;
for (i = 0; i < 5; i++) {
coefs[i][0] = hwread(vortex->mmio, 0x24430 + i * 0x24);
coefs[i][1] = hwread(vortex->mmio, 0x24434 + i * 0x24);
coefs[i][2] = hwread(vortex->mmio, 0x24438 + i * 0x24);
coefs[i][3] = hwread(vortex->mmio, 0x2443C + i * 0x24);
}
arg_0[0] = hwread(vortex->mmio, 0x24528 + i * 0x24);
arg_0[1] = hwread(vortex->mmio, 0x2452C + i * 0x24);
arg_0[2] = hwread(vortex->mmio, 0x24530 + i * 0x24);
arg_0[3] = hwread(vortex->mmio, 0x24534 + i * 0x24);
}
#endif
/* Gains */
static void
vortex_XtalkHw_SetGains(vortex_t * vortex, xtalk_gains_t const gains)
{
int i;
for (i = 0; i < XTGAINS_SZ; i++) {
hwwrite(vortex->mmio, 0x244D0 + (i * 4), gains[i]);
}
}
static void
vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex)
{
vortex_XtalkHw_SetGains(vortex, asXtalkGainsAllChan);
}
#if 0
static void vortex_XtalkHw_GetGains(vortex_t * vortex, xtalk_gains_t gains)
{
int i;
for (i = 0; i < XTGAINS_SZ; i++)
gains[i] = hwread(vortex->mmio, 0x244D0 + i * 4);
}
#endif
/* Delay parameters */
static void
vortex_XtalkHw_SetDelay(vortex_t * vortex, unsigned short right,
unsigned short left)
{
u32 esp0 = 0;
esp0 &= 0x1FFFFFFF;
esp0 |= 0xA0000000;
esp0 = (esp0 & 0xffffE0ff) | ((right & 0x1F) << 8);
esp0 = (esp0 & 0xfffc1fff) | ((left & 0x1F) << 0xd);
hwwrite(vortex->mmio, 0x24660, esp0);
}
static void
vortex_XtalkHw_SetLeftDline(vortex_t * vortex, xtalk_dline_t const dline)
{
int i;
for (i = 0; i < 0x20; i++) {
hwwrite(vortex->mmio, 0x24000 + (i << 2), dline[i] & 0xffff);
hwwrite(vortex->mmio, 0x24080 + (i << 2), dline[i] >> 0x10);
}
}
static void
vortex_XtalkHw_SetRightDline(vortex_t * vortex, xtalk_dline_t const dline)
{
int i;
for (i = 0; i < 0x20; i++) {
hwwrite(vortex->mmio, 0x24100 + (i << 2), dline[i] & 0xffff);
hwwrite(vortex->mmio, 0x24180 + (i << 2), dline[i] >> 0x10);
}
}
#if 0
static void
vortex_XtalkHw_GetDelay(vortex_t * vortex, unsigned short *right,
unsigned short *left)
{
int esp0;
esp0 = hwread(vortex->mmio, 0x24660);
*right = (esp0 >> 8) & 0x1f;
*left = (esp0 >> 0xd) & 0x1f;
}
static void vortex_XtalkHw_GetLeftDline(vortex_t * vortex, xtalk_dline_t dline)
{
int i;
for (i = 0; i < 0x20; i++) {
dline[i] =
(hwread(vortex->mmio, 0x24000 + (i << 2)) & 0xffff) |
(hwread(vortex->mmio, 0x24080 + (i << 2)) << 0x10);
}
}
static void vortex_XtalkHw_GetRightDline(vortex_t * vortex, xtalk_dline_t dline)
{
int i;
for (i = 0; i < 0x20; i++) {
dline[i] =
(hwread(vortex->mmio, 0x24100 + (i << 2)) & 0xffff) |
(hwread(vortex->mmio, 0x24180 + (i << 2)) << 0x10);
}
}
#endif
/* Control/Global stuff */
#if 0
static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, u32 ctrl)
{
hwwrite(vortex->mmio, 0x24660, ctrl);
}
static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, u32 *ctrl)
{
*ctrl = hwread(vortex->mmio, 0x24660);
}
#endif
static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, u32 sr)
{
u32 temp;
temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
temp = (temp & 0xffffff07) | ((sr & 0x1f) << 3);
hwwrite(vortex->mmio, 0x24660, temp);
}
#if 0
static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, u32 *sr)
{
*sr = (hwread(vortex->mmio, 0x24660) >> 3) & 0x1f;
}
#endif
static void vortex_XtalkHw_Enable(vortex_t * vortex)
{
u32 temp;
temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
temp |= 1;
hwwrite(vortex->mmio, 0x24660, temp);
}
static void vortex_XtalkHw_Disable(vortex_t * vortex)
{
u32 temp;
temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
temp &= 0xfffffffe;
hwwrite(vortex->mmio, 0x24660, temp);
}
static void vortex_XtalkHw_ZeroIO(vortex_t * vortex)
{
int i;
for (i = 0; i < 20; i++)
hwwrite(vortex->mmio, 0x24600 + (i << 2), 0);
for (i = 0; i < 4; i++)
hwwrite(vortex->mmio, 0x24650 + (i << 2), 0);
}
static void vortex_XtalkHw_ZeroState(vortex_t * vortex)
{
vortex_XtalkHw_ZeroIO(vortex); // inlined
vortex_XtalkHw_SetLeftEQ(vortex, 0, 0, asXtalkCoefsZeros);
vortex_XtalkHw_SetRightEQ(vortex, 0, 0, asXtalkCoefsZeros);
vortex_XtalkHw_SetLeftXT(vortex, 0, 0, asXtalkCoefsZeros);
vortex_XtalkHw_SetRightXT(vortex, 0, 0, asXtalkCoefsZeros);
vortex_XtalkHw_SetGains(vortex, asXtalkGainsZeros); // inlined
vortex_XtalkHw_SetDelay(vortex, 0, 0); // inlined
vortex_XtalkHw_SetLeftDline(vortex, alXtalkDlineZeros); // inlined
vortex_XtalkHw_SetRightDline(vortex, alXtalkDlineZeros); // inlined
vortex_XtalkHw_SetLeftDline(vortex, alXtalkDlineZeros); // inlined
vortex_XtalkHw_SetRightDline(vortex, alXtalkDlineZeros); // inlined
vortex_XtalkHw_SetLeftEQStates(vortex, asXtalkInStateZeros,
asXtalkOutStateZeros);
vortex_XtalkHw_SetRightEQStates(vortex, asXtalkInStateZeros,
asXtalkOutStateZeros);
vortex_XtalkHw_SetLeftXTStates(vortex, asXtalkInStateZeros,
asXtalkOutStateZeros);
vortex_XtalkHw_SetRightXTStates(vortex, asXtalkInStateZeros,
asXtalkOutStateZeros);
}
static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex)
{
vortex_XtalkHw_SetLeftEQ(vortex, 0, 1, asXtalkCoefsPipe);
vortex_XtalkHw_SetRightEQ(vortex, 0, 1, asXtalkCoefsPipe);
vortex_XtalkHw_SetLeftXT(vortex, 0, 0, asXtalkCoefsZeros);
vortex_XtalkHw_SetRightXT(vortex, 0, 0, asXtalkCoefsZeros);
vortex_XtalkHw_SetDelay(vortex, 0, 0); // inlined
}
static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex)
{
vortex_XtalkHw_SetLeftEQ(vortex, sXtalkWideKLeftEq,
sXtalkWideShiftLeftEq, asXtalkWideCoefsLeftEq);
vortex_XtalkHw_SetRightEQ(vortex, sXtalkWideKRightEq,
sXtalkWideShiftRightEq,
asXtalkWideCoefsRightEq);
vortex_XtalkHw_SetLeftXT(vortex, sXtalkWideKLeftXt,
sXtalkWideShiftLeftXt, asXtalkWideCoefsLeftXt);
vortex_XtalkHw_SetRightXT(vortex, sXtalkWideKLeftXt,
sXtalkWideShiftLeftXt,
asXtalkWideCoefsLeftXt);
vortex_XtalkHw_SetDelay(vortex, wXtalkWideRightDelay, wXtalkWideLeftDelay); // inlined
}
static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex)
{
vortex_XtalkHw_SetLeftEQ(vortex, sXtalkNarrowKLeftEq,
sXtalkNarrowShiftLeftEq,
asXtalkNarrowCoefsLeftEq);
vortex_XtalkHw_SetRightEQ(vortex, sXtalkNarrowKRightEq,
sXtalkNarrowShiftRightEq,
asXtalkNarrowCoefsRightEq);
vortex_XtalkHw_SetLeftXT(vortex, sXtalkNarrowKLeftXt,
sXtalkNarrowShiftLeftXt,
asXtalkNarrowCoefsLeftXt);
vortex_XtalkHw_SetRightXT(vortex, sXtalkNarrowKLeftXt,
sXtalkNarrowShiftLeftXt,
asXtalkNarrowCoefsLeftXt);
vortex_XtalkHw_SetDelay(vortex, wXtalkNarrowRightDelay, wXtalkNarrowLeftDelay); // inlined
}
static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex)
{
//sDiamondKLeftEq,sDiamondKRightXt,asDiamondCoefsLeftEq
vortex_XtalkHw_SetLeftEQ(vortex, sDiamondKLeftEq,
sDiamondShiftLeftEq, asDiamondCoefsLeftEq);
vortex_XtalkHw_SetRightEQ(vortex, sDiamondKRightEq,
sDiamondShiftRightEq, asDiamondCoefsRightEq);
vortex_XtalkHw_SetLeftXT(vortex, sDiamondKLeftXt,
sDiamondShiftLeftXt, asDiamondCoefsLeftXt);
vortex_XtalkHw_SetRightXT(vortex, sDiamondKLeftXt,
sDiamondShiftLeftXt, asDiamondCoefsLeftXt);
vortex_XtalkHw_SetDelay(vortex, wDiamondRightDelay, wDiamondLeftDelay); // inlined
}
static void vortex_XtalkHw_init(vortex_t * vortex)
{
vortex_XtalkHw_ZeroState(vortex);
}
/* End of file */

View File

@@ -0,0 +1,61 @@
/***************************************************************************
* au88x0_cxtalk.h
*
* Wed Nov 19 19:07:17 2003
* Copyright 2003 mjander
* mjander@users.sourceforge.org
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* The crosstalk canceler supports 5 stereo input channels. The result is
available at one single output route pair (stereo). */
#ifndef _AU88X0_CXTALK_H
#define _AU88X0_CXTALK_H
#include "au88x0.h"
#define XTDLINE_SZ 32
#define XTGAINS_SZ 10
#define XTINST_SZ 4
#define XT_HEADPHONE 1
#define XT_SPEAKER0 2
#define XT_SPEAKER1 3
#define XT_DIAMOND 4
typedef u32 xtalk_dline_t[XTDLINE_SZ];
typedef u16 xtalk_gains_t[XTGAINS_SZ];
typedef u16 xtalk_instate_t[XTINST_SZ];
typedef u16 xtalk_coefs_t[5][5];
typedef u16 xtalk_state_t[5][4];
static void vortex_XtalkHw_SetGains(vortex_t * vortex,
xtalk_gains_t const gains);
static void vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex);
static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, u32 sr);
static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex);
static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex);
static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex);
static void vortex_XtalkHw_Enable(vortex_t * vortex);
static void vortex_XtalkHw_Disable(vortex_t * vortex);
static void vortex_XtalkHw_init(vortex_t * vortex);
#endif /* _AU88X0_CXTALK_H */