aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/au88x0
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/pci/au88x0
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'sound/pci/au88x0')
-rw-r--r--sound/pci/au88x0/Makefile7
-rw-r--r--sound/pci/au88x0/au8810.c17
-rw-r--r--sound/pci/au88x0/au8810.h229
-rw-r--r--sound/pci/au88x0/au8820.c15
-rw-r--r--sound/pci/au88x0/au8820.h209
-rw-r--r--sound/pci/au88x0/au8830.c18
-rw-r--r--sound/pci/au88x0/au8830.h256
-rw-r--r--sound/pci/au88x0/au88x0.c388
-rw-r--r--sound/pci/au88x0/au88x0.h284
-rw-r--r--sound/pci/au88x0/au88x0_a3d.c914
-rw-r--r--sound/pci/au88x0/au88x0_a3d.h123
-rw-r--r--sound/pci/au88x0/au88x0_a3ddata.c91
-rw-r--r--sound/pci/au88x0/au88x0_core.c2837
-rw-r--r--sound/pci/au88x0/au88x0_eq.c937
-rw-r--r--sound/pci/au88x0/au88x0_eq.h46
-rw-r--r--sound/pci/au88x0/au88x0_eqdata.c112
-rw-r--r--sound/pci/au88x0/au88x0_game.c135
-rw-r--r--sound/pci/au88x0/au88x0_mixer.c33
-rw-r--r--sound/pci/au88x0/au88x0_mpu401.c112
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c548
-rw-r--r--sound/pci/au88x0/au88x0_sb.h40
-rw-r--r--sound/pci/au88x0/au88x0_synth.c395
-rw-r--r--sound/pci/au88x0/au88x0_wt.h65
-rw-r--r--sound/pci/au88x0/au88x0_xtalk.c787
-rw-r--r--sound/pci/au88x0/au88x0_xtalk.h61
25 files changed, 8659 insertions, 0 deletions
diff --git a/sound/pci/au88x0/Makefile b/sound/pci/au88x0/Makefile
new file mode 100644
index 000000000000..d0a66bc5d4a7
--- /dev/null
+++ b/sound/pci/au88x0/Makefile
@@ -0,0 +1,7 @@
1snd-au8810-objs := au8810.o
2snd-au8820-objs := au8820.o
3snd-au8830-objs := au8830.o
4
5obj-$(CONFIG_SND_AU8810) += snd-au8810.o
6obj-$(CONFIG_SND_AU8820) += snd-au8820.o
7obj-$(CONFIG_SND_AU8830) += snd-au8830.o
diff --git a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c
new file mode 100644
index 000000000000..fce22c7af0ea
--- /dev/null
+++ b/sound/pci/au88x0/au8810.c
@@ -0,0 +1,17 @@
1#include "au8810.h"
2#include "au88x0.h"
3static struct pci_device_id snd_vortex_ids[] = {
4 {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE,
5 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1,},
6 {0,}
7};
8
9#include "au88x0_core.c"
10#include "au88x0_pcm.c"
11#include "au88x0_mixer.c"
12#include "au88x0_mpu401.c"
13#include "au88x0_game.c"
14#include "au88x0_eq.c"
15#include "au88x0_a3d.c"
16#include "au88x0_xtalk.c"
17#include "au88x0.c"
diff --git a/sound/pci/au88x0/au8810.h b/sound/pci/au88x0/au8810.h
new file mode 100644
index 000000000000..3837d2ba5e67
--- /dev/null
+++ b/sound/pci/au88x0/au8810.h
@@ -0,0 +1,229 @@
1/*
2 Aureal Advantage Soundcard driver.
3 */
4
5#define CHIP_AU8810
6
7#define CARD_NAME "Aureal Advantage 3D Sound Processor"
8#define CARD_NAME_SHORT "au8810"
9
10#define NR_ADB 0x10
11#define NR_WT 0x00
12#define NR_SRC 0x10
13#define NR_A3D 0x10
14#define NR_MIXIN 0x20
15#define NR_MIXOUT 0x10
16
17
18/* ADBDMA */
19#define VORTEX_ADBDMA_STAT 0x27e00 /* read only, subbuffer, DMA pos */
20#define POS_MASK 0x00000fff
21#define POS_SHIFT 0x0
22#define ADB_SUBBUF_MASK 0x00003000 /* ADB only. */
23#define ADB_SUBBUF_SHIFT 0xc /* ADB only. */
24#define VORTEX_ADBDMA_CTRL 0x27180 /* write only; format, flags, DMA pos */
25#define OFFSET_MASK 0x00000fff
26#define OFFSET_SHIFT 0x0
27#define IE_MASK 0x00001000 /* interrupt enable. */
28#define IE_SHIFT 0xc
29#define DIR_MASK 0x00002000 /* Direction */
30#define DIR_SHIFT 0xd
31#define FMT_MASK 0x0003c000
32#define FMT_SHIFT 0xe
33// The ADB masks and shift also are valid for the wtdma, except if specified otherwise.
34#define VORTEX_ADBDMA_BUFCFG0 0x27100
35#define VORTEX_ADBDMA_BUFCFG1 0x27104
36#define VORTEX_ADBDMA_BUFBASE 0x27000
37#define VORTEX_ADBDMA_START 0x27c00 /* Which subbuffer starts */
38
39#define VORTEX_ADBDMA_STATUS 0x27A90 /* stored at AdbDma->this_10 / 2 DWORD in size. */
40
41/* WTDMA */
42#define VORTEX_WTDMA_CTRL 0x27fd8 /* format, DMA pos */
43#define VORTEX_WTDMA_STAT 0x27fe8 /* DMA subbuf, DMA pos */
44#define WT_SUBBUF_MASK 0x3
45#define WT_SUBBUF_SHIFT 0xc
46#define VORTEX_WTDMA_BUFBASE 0x27fc0
47#define VORTEX_WTDMA_BUFCFG0 0x27fd0
48#define VORTEX_WTDMA_BUFCFG1 0x27fd4
49#define VORTEX_WTDMA_START 0x27fe4 /* which subbuffer is first */
50
51/* ADB */
52#define VORTEX_ADB_SR 0x28400 /* Samplerates enable/disable */
53#define VORTEX_ADB_RTBASE 0x28000
54#define VORTEX_ADB_RTBASE_COUNT 173
55#define VORTEX_ADB_CHNBASE 0x282b4
56#define VORTEX_ADB_CHNBASE_COUNT 24
57#define ROUTE_MASK 0xffff
58#define SOURCE_MASK 0xff00
59#define ADB_MASK 0xff
60#define ADB_SHIFT 0x8
61
62/* ADB address */
63#define OFFSET_ADBDMA 0x00
64#define OFFSET_SRCIN 0x40
65#define OFFSET_SRCOUT 0x20
66#define OFFSET_MIXIN 0x50
67#define OFFSET_MIXOUT 0x30
68#define OFFSET_CODECIN 0x70
69#define OFFSET_CODECOUT 0x88
70#define OFFSET_SPORTIN 0x78 /* ch 0x13 */
71#define OFFSET_SPORTOUT 0x90
72#define OFFSET_SPDIFOUT 0x92 /* ch 0x14 check this! */
73#define OFFSET_EQIN 0xa0
74#define OFFSET_EQOUT 0x7e /* 2 routes on ch 0x11 */
75#define OFFSET_XTALKOUT 0x66 /* crosstalk canceller (source) */
76#define OFFSET_XTALKIN 0x96 /* crosstalk canceller (sink) */
77#define OFFSET_A3DIN 0x70 /* ADB sink. */
78#define OFFSET_A3DOUT 0xA6 /* ADB source. 2 routes per slice = 8 */
79#define OFFSET_EFXIN 0x80 /* ADB sink. */
80#define OFFSET_EFXOUT 0x68 /* ADB source. */
81
82/* ADB route translate helper */
83#define ADB_DMA(x) (x)
84#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
85#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
86#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
87#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
88#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
89#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
90#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN)
91#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
92#define ADB_SPDIFOUT(x) (x + OFFSET_SPDIFOUT)
93#define ADB_EQIN(x) (x + OFFSET_EQIN)
94#define ADB_EQOUT(x) (x + OFFSET_EQOUT)
95#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT) /* 0x10 A3D blocks */
96#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
97#define ADB_XTALKIN(x) (x + OFFSET_XTALKIN)
98#define ADB_XTALKOUT(x) (x + OFFSET_XTALKOUT)
99
100#define MIX_OUTL 0xe
101#define MIX_OUTR 0xf
102#define MIX_INL 0x1e
103#define MIX_INR 0x1f
104#define MIX_DEFIGAIN 0x08 /* 0x8 => 6dB */
105#define MIX_DEFOGAIN 0x08
106
107/* MIXER */
108#define VORTEX_MIXER_SR 0x21f00
109#define VORTEX_MIXER_CLIP 0x21f80
110#define VORTEX_MIXER_CHNBASE 0x21e40
111#define VORTEX_MIXER_RTBASE 0x21e00
112#define MIXER_RTBASE_SIZE 0x38
113#define VORTEX_MIX_ENIN 0x21a00 /* Input enable bits. 4 bits wide. */
114#define VORTEX_MIX_SMP 0x21c00 /* AU8820: 0x9c00 */
115
116/* MIX */
117#define VORTEX_MIX_INVOL_A 0x21000 /* in? */
118#define VORTEX_MIX_INVOL_B 0x20000 /* out? */
119#define VORTEX_MIX_VOL_A 0x21800
120#define VORTEX_MIX_VOL_B 0x20800
121
122#define VOL_MIN 0x80 /* Input volume when muted. */
123#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */
124
125/* SRC */
126#define VORTEX_SRC_CHNBASE 0x26c40
127#define VORTEX_SRC_RTBASE 0x26c00
128#define VORTEX_SRCBLOCK_SR 0x26cc0
129#define VORTEX_SRC_SOURCE 0x26cc4
130#define VORTEX_SRC_SOURCESIZE 0x26cc8
131/* Params
132 0x26e00 : 1 U0
133 0x26e40 : 2 CR
134 0x26e80 : 3 U3
135 0x26ec0 : 4 DRIFT1
136 0x26f00 : 5 U1
137 0x26f40 : 6 DRIFT2
138 0x26f80 : 7 U2 : Target rate, direction
139*/
140
141#define VORTEX_SRC_CONVRATIO 0x26e40
142#define VORTEX_SRC_DRIFT0 0x26e80
143#define VORTEX_SRC_DRIFT1 0x26ec0
144#define VORTEX_SRC_DRIFT2 0x26f40
145#define VORTEX_SRC_U0 0x26e00
146#define U0_SLOWLOCK 0x200
147#define VORTEX_SRC_U1 0x26f00
148#define VORTEX_SRC_U2 0x26f80
149#define VORTEX_SRC_DATA 0x26800 /* 0xc800 */
150#define VORTEX_SRC_DATA0 0x26000
151
152/* FIFO */
153#define VORTEX_FIFO_ADBCTRL 0x16100 /* Control bits. */
154#define VORTEX_FIFO_WTCTRL 0x16000
155#define FIFO_RDONLY 0x00000001
156#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */
157#define FIFO_VALID 0x00000010
158#define FIFO_EMPTY 0x00000020
159#define FIFO_U0 0x00001000 /* Unknown. */
160#define FIFO_U1 0x00010000
161#define FIFO_SIZE_BITS 5
162#define FIFO_SIZE (1<<FIFO_SIZE_BITS) // 0x20
163#define FIFO_MASK (FIFO_SIZE-1) //0x1f /* at shift left 0xc */
164//#define FIFO_MASK 0x1f /* at shift left 0xb */
165//#define FIFO_SIZE 0x20
166#define FIFO_BITS 0x03880000
167#define VORTEX_FIFO_ADBDATA 0x14000
168#define VORTEX_FIFO_WTDATA 0x10000
169
170/* CODEC */
171#define VORTEX_CODEC_CTRL 0x29184
172#define VORTEX_CODEC_EN 0x29190
173#define EN_CODEC0 0x00000300
174#define EN_AC98 0x00000c00 /* Modem AC98 slots. */
175#define EN_CODEC1 0x00003000
176#define EN_CODEC (EN_CODEC0 | EN_CODEC1)
177#define EN_SPORT 0x00030000
178#define EN_SPDIF 0x000c0000
179
180#define VORTEX_CODEC_CHN 0x29080
181#define VORTEX_CODEC_WRITE 0x00800000
182#define VORTEX_CODEC_ADDSHIFT 16
183#define VORTEX_CODEC_ADDMASK 0x7f0000 /* 0x000f0000 */
184#define VORTEX_CODEC_DATSHIFT 0
185#define VORTEX_CODEC_DATMASK 0xffff
186#define VORTEX_CODEC_IO 0x29188
187
188/* SPDIF */
189#define VORTEX_SPDIF_FLAGS 0x2205c
190#define VORTEX_SPDIF_CFG0 0x291D0
191#define VORTEX_SPDIF_CFG1 0x291D4
192#define VORTEX_SPDIF_SMPRATE 0x29194
193
194/* Sample timer */
195#define VORTEX_SMP_TIME 0x29198
196
197#define VORTEX_MODEM_CTRL 0x291ac
198
199/* IRQ */
200#define VORTEX_IRQ_SOURCE 0x2a000 /* Interrupt source flags. */
201#define VORTEX_IRQ_CTRL 0x2a004 /* Interrupt source mask. */
202
203#define VORTEX_STAT 0x2a008 /* Status */
204
205#define VORTEX_CTRL 0x2a00c
206#define CTRL_MIDI_EN 0x00000001
207#define CTRL_MIDI_PORT 0x00000060
208#define CTRL_GAME_EN 0x00000008
209#define CTRL_GAME_PORT 0x00000e00
210//#define CTRL_IRQ_ENABLE 0x01004000
211#define CTRL_IRQ_ENABLE 0x00004000
212
213/* write: Timer period config / read: TIMER IRQ ack. */
214#define VORTEX_IRQ_STAT 0x2919c
215
216/* DMA */
217#define VORTEX_ENGINE_CTRL 0x27ae8
218#define ENGINE_INIT 0x1380000
219
220/* MIDI *//* GAME. */
221#define VORTEX_MIDI_DATA 0x28800
222#define VORTEX_MIDI_CMD 0x28804 /* Write command / Read status */
223
224#define VORTEX_CTRL2 0x2880c
225#define CTRL2_GAME_ADCMODE 0x40
226#define VORTEX_GAME_LEGACY 0x28808
227#define VORTEX_GAME_AXIS 0x28810
228#define AXIS_SIZE 4
229#define AXIS_RANGE 0x1fff
diff --git a/sound/pci/au88x0/au8820.c b/sound/pci/au88x0/au8820.c
new file mode 100644
index 000000000000..d1fbcce07257
--- /dev/null
+++ b/sound/pci/au88x0/au8820.c
@@ -0,0 +1,15 @@
1#include "au8820.h"
2#include "au88x0.h"
3static struct pci_device_id snd_vortex_ids[] = {
4 {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1,
5 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
6 {0,}
7};
8
9#include "au88x0_synth.c"
10#include "au88x0_core.c"
11#include "au88x0_pcm.c"
12#include "au88x0_mpu401.c"
13#include "au88x0_game.c"
14#include "au88x0_mixer.c"
15#include "au88x0.c"
diff --git a/sound/pci/au88x0/au8820.h b/sound/pci/au88x0/au8820.h
new file mode 100644
index 000000000000..be8022e78714
--- /dev/null
+++ b/sound/pci/au88x0/au8820.h
@@ -0,0 +1,209 @@
1/*
2 Aureal Vortex Soundcard driver.
3
4 IO addr collected from asp4core.vxd:
5 function address
6 0005D5A0 13004
7 00080674 14004
8 00080AFF 12818
9
10 */
11
12#define CHIP_AU8820
13
14#define CARD_NAME "Aureal Vortex 3D Sound Processor"
15#define CARD_NAME_SHORT "au8820"
16
17/* Number of ADB and WT channels */
18#define NR_ADB 0x10
19#define NR_WT 0x20
20#define NR_SRC 0x10
21#define NR_A3D 0x00
22#define NR_MIXIN 0x10
23#define NR_MIXOUT 0x10
24
25
26/* ADBDMA */
27#define VORTEX_ADBDMA_STAT 0x105c0 /* read only, subbuffer, DMA pos */
28#define POS_MASK 0x00000fff
29#define POS_SHIFT 0x0
30#define ADB_SUBBUF_MASK 0x00003000 /* ADB only. */
31#define ADB_SUBBUF_SHIFT 0xc /* ADB only. */
32#define VORTEX_ADBDMA_CTRL 0x10580 /* write only, format, flags, DMA pos */
33#define OFFSET_MASK 0x00000fff
34#define OFFSET_SHIFT 0x0
35#define IE_MASK 0x00001000 /* interrupt enable. */
36#define IE_SHIFT 0xc
37#define DIR_MASK 0x00002000 /* Direction. */
38#define DIR_SHIFT 0xd
39#define FMT_MASK 0x0003c000
40#define FMT_SHIFT 0xe
41// The masks and shift also work for the wtdma, if not specified otherwise.
42#define VORTEX_ADBDMA_BUFCFG0 0x10400
43#define VORTEX_ADBDMA_BUFCFG1 0x10404
44#define VORTEX_ADBDMA_BUFBASE 0x10200
45#define VORTEX_ADBDMA_START 0x106c0 /* Which subbuffer starts */
46#define VORTEX_ADBDMA_STATUS 0x10600 /* stored at AdbDma->this_10 / 2 DWORD in size. */
47
48/* ADB */
49#define VORTEX_ADB_SR 0x10a00 /* Samplerates enable/disable */
50#define VORTEX_ADB_RTBASE 0x10800
51#define VORTEX_ADB_RTBASE_COUNT 103
52#define VORTEX_ADB_CHNBASE 0x1099c
53#define VORTEX_ADB_CHNBASE_COUNT 22
54#define ROUTE_MASK 0x3fff
55#define ADB_MASK 0x7f
56#define ADB_SHIFT 0x7
57//#define ADB_MIX_MASK 0xf
58/* ADB address */
59#define OFFSET_ADBDMA 0x00
60#define OFFSET_SRCOUT 0x10 /* on channel 0x11 */
61#define OFFSET_SRCIN 0x10 /* on channel < 0x11 */
62#define OFFSET_MIXOUT 0x20 /* source */
63#define OFFSET_MIXIN 0x30 /* sink */
64#define OFFSET_CODECIN 0x48 /* ADB source */
65#define OFFSET_CODECOUT 0x58 /* ADB sink/target */
66#define OFFSET_SPORTOUT 0x60 /* sink */
67#define OFFSET_SPORTIN 0x50 /* source */
68#define OFFSET_EFXOUT 0x50 /* sink */
69#define OFFSET_EFXIN 0x40 /* source */
70#define OFFSET_A3DOUT 0x00 /* This card has no HRTF :( */
71#define OFFSET_A3DIN 0x00
72#define OFFSET_WTOUT 0x58 /* */
73
74/* ADB route translate helper */
75#define ADB_DMA(x) (x + OFFSET_ADBDMA)
76#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
77#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
78#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
79#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
80#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
81#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
82#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
83#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN) /* */
84#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT) /* 8 A3D blocks */
85#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
86#define ADB_WTOUT(x,y) (y + OFFSET_WTOUT)
87
88/* WTDMA */
89#define VORTEX_WTDMA_CTRL 0x10500 /* format, DMA pos */
90#define VORTEX_WTDMA_STAT 0x10500 /* DMA subbuf, DMA pos */
91#define WT_SUBBUF_MASK (0x3 << WT_SUBBUF_SHIFT)
92#define WT_SUBBUF_SHIFT 0x15
93#define VORTEX_WTDMA_BUFBASE 0x10000
94#define VORTEX_WTDMA_BUFCFG0 0x10300
95#define VORTEX_WTDMA_BUFCFG1 0x10304
96#define VORTEX_WTDMA_START 0x10640 /* which subbuffer is first */
97
98#define VORTEX_WT_BASE 0x9000
99
100/* MIXER */
101#define VORTEX_MIXER_SR 0x9f00
102#define VORTEX_MIXER_CLIP 0x9f80
103#define VORTEX_MIXER_CHNBASE 0x9e40
104#define VORTEX_MIXER_RTBASE 0x9e00
105#define MIXER_RTBASE_SIZE 0x26
106#define VORTEX_MIX_ENIN 0x9a00 /* Input enable bits. 4 bits wide. */
107#define VORTEX_MIX_SMP 0x9c00
108
109/* MIX */
110#define VORTEX_MIX_INVOL_A 0x9000 /* in? */
111#define VORTEX_MIX_INVOL_B 0x8000 /* out? */
112#define VORTEX_MIX_VOL_A 0x9800
113#define VORTEX_MIX_VOL_B 0x8800
114
115#define VOL_MIN 0x80 /* Input volume when muted. */
116#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */
117
118//#define MIX_OUTL 0xe
119//#define MIX_OUTR 0xf
120//#define MIX_INL 0xe
121//#define MIX_INR 0xf
122#define MIX_DEFIGAIN 0x08 /* 0x8 => 6dB */
123#define MIX_DEFOGAIN 0x08
124
125/* SRC */
126#define VORTEX_SRCBLOCK_SR 0xccc0
127#define VORTEX_SRC_CHNBASE 0xcc40
128#define VORTEX_SRC_RTBASE 0xcc00
129#define VORTEX_SRC_SOURCE 0xccc4
130#define VORTEX_SRC_SOURCESIZE 0xccc8
131#define VORTEX_SRC_U0 0xce00
132#define VORTEX_SRC_DRIFT0 0xce80
133#define VORTEX_SRC_DRIFT1 0xcec0
134#define VORTEX_SRC_U1 0xcf00
135#define VORTEX_SRC_DRIFT2 0xcf40
136#define VORTEX_SRC_U2 0xcf80
137#define VORTEX_SRC_DATA 0xc800
138#define VORTEX_SRC_DATA0 0xc000
139#define VORTEX_SRC_CONVRATIO 0xce40
140//#define SRC_RATIO(x) ((((x<<15)/48000) + 1)/2) /* Playback */
141//#define SRC_RATIO2(x) ((((48000<<15)/x) + 1)/2) /* Recording */
142
143/* FIFO */
144#define VORTEX_FIFO_ADBCTRL 0xf800 /* Control bits. */
145#define VORTEX_FIFO_WTCTRL 0xf840
146#define FIFO_RDONLY 0x00000001
147#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */
148#define FIFO_VALID 0x00000010
149#define FIFO_EMPTY 0x00000020
150#define FIFO_U0 0x00001000 /* Unknown. */
151#define FIFO_U1 0x00010000
152#define FIFO_SIZE_BITS 5
153#define FIFO_SIZE (1<<FIFO_SIZE_BITS) // 0x20
154#define FIFO_MASK (FIFO_SIZE-1) //0x1f /* at shift left 0xc */
155#define VORTEX_FIFO_ADBDATA 0xe000
156#define VORTEX_FIFO_WTDATA 0xe800
157
158/* CODEC */
159#define VORTEX_CODEC_CTRL 0x11984
160#define VORTEX_CODEC_EN 0x11990
161#define EN_CODEC 0x00000300
162#define EN_SPORT 0x00030000
163#define EN_SPDIF 0x000c0000
164#define VORTEX_CODEC_CHN 0x11880
165#define VORTEX_CODEC_WRITE 0x00800000
166#define VORTEX_CODEC_ADDSHIFT 16
167#define VORTEX_CODEC_ADDMASK 0x7f0000 /* 0x000f0000 */
168#define VORTEX_CODEC_DATSHIFT 0
169#define VORTEX_CODEC_DATMASK 0xffff
170#define VORTEX_CODEC_IO 0x11988
171
172#define VORTEX_SPDIF_FLAGS 0x1005c /* FIXME */
173#define VORTEX_SPDIF_CFG0 0x119D0
174#define VORTEX_SPDIF_CFG1 0x119D4
175#define VORTEX_SPDIF_SMPRATE 0x11994
176
177/* Sample timer */
178#define VORTEX_SMP_TIME 0x11998
179
180/* IRQ */
181#define VORTEX_IRQ_SOURCE 0x12800 /* Interrupt source flags. */
182#define VORTEX_IRQ_CTRL 0x12804 /* Interrupt source mask. */
183
184#define VORTEX_STAT 0x12808 /* ?? */
185
186#define VORTEX_CTRL 0x1280c
187#define CTRL_MIDI_EN 0x00000001
188#define CTRL_MIDI_PORT 0x00000060
189#define CTRL_GAME_EN 0x00000008
190#define CTRL_GAME_PORT 0x00000e00
191#define CTRL_IRQ_ENABLE 0x4000
192
193/* write: Timer period config / read: TIMER IRQ ack. */
194#define VORTEX_IRQ_STAT 0x1199c
195
196/* DMA */
197#define VORTEX_DMA_BUFFER 0x10200
198#define VORTEX_ENGINE_CTRL 0x1060c
199#define ENGINE_INIT 0x0L
200
201 /* MIDI *//* GAME. */
202#define VORTEX_MIDI_DATA 0x11000
203#define VORTEX_MIDI_CMD 0x11004 /* Write command / Read status */
204#define VORTEX_GAME_LEGACY 0x11008
205#define VORTEX_CTRL2 0x1100c
206#define CTRL2_GAME_ADCMODE 0x40
207#define VORTEX_GAME_AXIS 0x11010
208#define AXIS_SIZE 4
209#define AXIS_RANGE 0x1fff
diff --git a/sound/pci/au88x0/au8830.c b/sound/pci/au88x0/au8830.c
new file mode 100644
index 000000000000..d4f2717c14fb
--- /dev/null
+++ b/sound/pci/au88x0/au8830.c
@@ -0,0 +1,18 @@
1#include "au8830.h"
2#include "au88x0.h"
3static struct pci_device_id snd_vortex_ids[] = {
4 {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2,
5 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
6 {0,}
7};
8
9#include "au88x0_synth.c"
10#include "au88x0_core.c"
11#include "au88x0_pcm.c"
12#include "au88x0_mixer.c"
13#include "au88x0_mpu401.c"
14#include "au88x0_game.c"
15#include "au88x0_eq.c"
16#include "au88x0_a3d.c"
17#include "au88x0_xtalk.c"
18#include "au88x0.c"
diff --git a/sound/pci/au88x0/au8830.h b/sound/pci/au88x0/au8830.h
new file mode 100644
index 000000000000..aa77826b5e59
--- /dev/null
+++ b/sound/pci/au88x0/au8830.h
@@ -0,0 +1,256 @@
1/*
2 Aureal Vortex Soundcard driver.
3
4 IO addr collected from asp4core.vxd:
5 function address
6 0005D5A0 13004
7 00080674 14004
8 00080AFF 12818
9
10 */
11
12#define CHIP_AU8830
13
14#define CARD_NAME "Aureal Vortex 2 3D Sound Processor"
15#define CARD_NAME_SHORT "au8830"
16
17#define NR_ADB 0x20
18#define NR_SRC 0x10
19#define NR_A3D 0x10
20#define NR_MIXIN 0x20
21#define NR_MIXOUT 0x10
22#define NR_WT 0x40
23
24/* ADBDMA */
25#define VORTEX_ADBDMA_STAT 0x27e00 /* read only, subbuffer, DMA pos */
26#define POS_MASK 0x00000fff
27#define POS_SHIFT 0x0
28#define ADB_SUBBUF_MASK 0x00003000 /* ADB only. */
29#define ADB_SUBBUF_SHIFT 0xc /* ADB only. */
30#define VORTEX_ADBDMA_CTRL 0x27a00 /* write only; format, flags, DMA pos */
31#define OFFSET_MASK 0x00000fff
32#define OFFSET_SHIFT 0x0
33#define IE_MASK 0x00001000 /* interrupt enable. */
34#define IE_SHIFT 0xc
35#define DIR_MASK 0x00002000 /* Direction. */
36#define DIR_SHIFT 0xd
37#define FMT_MASK 0x0003c000
38#define FMT_SHIFT 0xe
39#define ADB_FIFO_EN_SHIFT 0x15
40#define ADB_FIFO_EN (1 << 0x15)
41// The ADB masks and shift also are valid for the wtdma, except if specified otherwise.
42#define VORTEX_ADBDMA_BUFCFG0 0x27800
43#define VORTEX_ADBDMA_BUFCFG1 0x27804
44#define VORTEX_ADBDMA_BUFBASE 0x27400
45#define VORTEX_ADBDMA_START 0x27c00 /* Which subbuffer starts */
46
47#define VORTEX_ADBDMA_STATUS 0x27A90 /* stored at AdbDma->this_10 / 2 DWORD in size. */
48/* Starting at the MSB, each pair of bits seem to be the current DMA page. */
49/* This current page bits are consistent (same value) with VORTEX_ADBDMA_STAT) */
50
51/* DMA */
52#define VORTEX_ENGINE_CTRL 0x27ae8
53#define ENGINE_INIT 0x1380000
54
55/* WTDMA */
56#define VORTEX_WTDMA_CTRL 0x27900 /* format, DMA pos */
57#define VORTEX_WTDMA_STAT 0x27d00 /* DMA subbuf, DMA pos */
58#define WT_SUBBUF_MASK 0x3
59#define WT_SUBBUF_SHIFT 0xc
60#define VORTEX_WTDMA_BUFBASE 0x27000
61#define VORTEX_WTDMA_BUFCFG0 0x27600
62#define VORTEX_WTDMA_BUFCFG1 0x27604
63#define VORTEX_WTDMA_START 0x27b00 /* which subbuffer is first */
64
65/* ADB */
66#define VORTEX_ADB_SR 0x28400 /* Samplerates enable/disable */
67#define VORTEX_ADB_RTBASE 0x28000
68#define VORTEX_ADB_RTBASE_COUNT 173
69#define VORTEX_ADB_CHNBASE 0x282b4
70#define VORTEX_ADB_CHNBASE_COUNT 24
71#define ROUTE_MASK 0xffff
72#define SOURCE_MASK 0xff00
73#define ADB_MASK 0xff
74#define ADB_SHIFT 0x8
75/* ADB address */
76#define OFFSET_ADBDMA 0x00
77#define OFFSET_ADBDMAB 0x20
78#define OFFSET_SRCIN 0x40
79#define OFFSET_SRCOUT 0x20 /* ch 0x11 */
80#define OFFSET_MIXIN 0x50 /* ch 0x11 */
81#define OFFSET_MIXOUT 0x30 /* ch 0x11 */
82#define OFFSET_CODECIN 0x70 /* ch 0x11 */ /* adb source */
83#define OFFSET_CODECOUT 0x88 /* ch 0x11 */ /* adb target */
84#define OFFSET_SPORTIN 0x78 /* ch 0x13 ADB source. 2 routes. */
85#define OFFSET_SPORTOUT 0x90 /* ch 0x13 ADB sink. 2 routes. */
86#define OFFSET_SPDIFIN 0x7A /* ch 0x14 ADB source. */
87#define OFFSET_SPDIFOUT 0x92 /* ch 0x14 ADB sink. */
88#define OFFSET_AC98IN 0x7c /* ch 0x14 ADB source. */
89#define OFFSET_AC98OUT 0x94 /* ch 0x14 ADB sink. */
90#define OFFSET_EQIN 0xa0 /* ch 0x11 */
91#define OFFSET_EQOUT 0x7e /* ch 0x11 */ /* 2 routes on ch 0x11 */
92#define OFFSET_A3DIN 0x70 /* ADB sink. */
93#define OFFSET_A3DOUT 0xA6 /* ADB source. 2 routes per slice = 8 */
94#define OFFSET_WT0 0x40 /* WT bank 0 output. 0x40 - 0x65 */
95#define OFFSET_WT1 0x80 /* WT bank 1 output. 0x80 - 0xA5 */
96/* WT sources offset : 0x00-0x1f Direct stream. */
97/* WT sources offset : 0x20-0x25 Mixed Output. */
98#define OFFSET_XTALKOUT 0x66 /* crosstalk canceller (source) 2 routes */
99#define OFFSET_XTALKIN 0x96 /* crosstalk canceller (sink). 10 routes */
100#define OFFSET_EFXOUT 0x68 /* ADB source. 8 routes. */
101#define OFFSET_EFXIN 0x80 /* ADB sink. 8 routes. */
102
103/* ADB route translate helper */
104#define ADB_DMA(x) (x)
105#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT)
106#define ADB_SRCIN(x) (x + OFFSET_SRCIN)
107#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT)
108#define ADB_MIXIN(x) (x + OFFSET_MIXIN)
109#define ADB_CODECIN(x) (x + OFFSET_CODECIN)
110#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT)
111#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN)
112#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT)
113#define ADB_SPDIFIN(x) (x + OFFSET_SPDIFIN)
114#define ADB_SPDIFOUT(x) (x + OFFSET_SPDIFOUT)
115#define ADB_EQIN(x) (x + OFFSET_EQIN)
116#define ADB_EQOUT(x) (x + OFFSET_EQOUT)
117#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT) /* 0x10 A3D blocks */
118#define ADB_A3DIN(x) (x + OFFSET_A3DIN)
119//#define ADB_WTOUT(x) ((x<x20)?(x + OFFSET_WT0):(x + OFFSET_WT1))
120#define ADB_WTOUT(x,y) (((x)==0)?((y) + OFFSET_WT0):((y) + OFFSET_WT1))
121#define ADB_XTALKIN(x) ((x) + OFFSET_XTALKIN)
122#define ADB_XTALKOUT(x) ((x) + OFFSET_XTALKOUT)
123
124#define MIX_DEFIGAIN 0x08
125#define MIX_DEFOGAIN 0x08 /* 0x8->6dB (6dB = x4) 16 to 18 bit conversion? */
126
127/* MIXER */
128#define VORTEX_MIXER_SR 0x21f00
129#define VORTEX_MIXER_CLIP 0x21f80
130#define VORTEX_MIXER_CHNBASE 0x21e40
131#define VORTEX_MIXER_RTBASE 0x21e00
132#define MIXER_RTBASE_SIZE 0x38
133#define VORTEX_MIX_ENIN 0x21a00 /* Input enable bits. 4 bits wide. */
134#define VORTEX_MIX_SMP 0x21c00 /* wave data buffers. AU8820: 0x9c00 */
135
136/* MIX */
137#define VORTEX_MIX_INVOL_B 0x20000 /* Input volume current */
138#define VORTEX_MIX_VOL_B 0x20800 /* Output Volume current */
139#define VORTEX_MIX_INVOL_A 0x21000 /* Input Volume target */
140#define VORTEX_MIX_VOL_A 0x21800 /* Output Volume target */
141
142#define VOL_MIN 0x80 /* Input volume when muted. */
143#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */
144
145/* SRC */
146#define VORTEX_SRC_CHNBASE 0x26c40
147#define VORTEX_SRC_RTBASE 0x26c00
148#define VORTEX_SRCBLOCK_SR 0x26cc0
149#define VORTEX_SRC_SOURCE 0x26cc4
150#define VORTEX_SRC_SOURCESIZE 0x26cc8
151/* Params
152 0x26e00 : 1 U0
153 0x26e40 : 2 CR
154 0x26e80 : 3 U3
155 0x26ec0 : 4 DRIFT1
156 0x26f00 : 5 U1
157 0x26f40 : 6 DRIFT2
158 0x26f80 : 7 U2 : Target rate, direction
159*/
160
161#define VORTEX_SRC_CONVRATIO 0x26e40
162#define VORTEX_SRC_DRIFT0 0x26e80
163#define VORTEX_SRC_DRIFT1 0x26ec0
164#define VORTEX_SRC_DRIFT2 0x26f40
165#define VORTEX_SRC_U0 0x26e00
166#define U0_SLOWLOCK 0x200
167#define VORTEX_SRC_U1 0x26f00
168#define VORTEX_SRC_U2 0x26f80
169#define VORTEX_SRC_DATA 0x26800 /* 0xc800 */
170#define VORTEX_SRC_DATA0 0x26000
171
172/* FIFO */
173#define VORTEX_FIFO_ADBCTRL 0x16100 /* Control bits. */
174#define VORTEX_FIFO_WTCTRL 0x16000
175#define FIFO_RDONLY 0x00000001
176#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */
177#define FIFO_VALID 0x00000010
178#define FIFO_EMPTY 0x00000020
179#define FIFO_U0 0x00002000 /* Unknown. */
180#define FIFO_U1 0x00040000
181#define FIFO_SIZE_BITS 6
182#define FIFO_SIZE (1<<(FIFO_SIZE_BITS)) // 0x40
183#define FIFO_MASK (FIFO_SIZE-1) //0x3f /* at shift left 0xc */
184#define FIFO_BITS 0x1c400000
185#define VORTEX_FIFO_ADBDATA 0x14000
186#define VORTEX_FIFO_WTDATA 0x10000
187
188#define VORTEX_FIFO_GIRT 0x17000 /* wt0, wt1, adb */
189#define GIRT_COUNT 3
190
191/* CODEC */
192
193#define VORTEX_CODEC_CHN 0x29080 /* The name "CHN" is wrong. */
194
195#define VORTEX_CODEC_CTRL 0x29184
196#define VORTEX_CODEC_IO 0x29188
197#define VORTEX_CODEC_WRITE 0x00800000
198#define VORTEX_CODEC_ADDSHIFT 16
199#define VORTEX_CODEC_ADDMASK 0x7f0000 /* 0x000f0000 */
200#define VORTEX_CODEC_DATSHIFT 0
201#define VORTEX_CODEC_DATMASK 0xffff
202
203#define VORTEX_CODEC_SPORTCTRL 0x2918c
204
205#define VORTEX_CODEC_EN 0x29190
206#define EN_AUDIO0 0x00000300
207#define EN_MODEM 0x00000c00
208#define EN_AUDIO1 0x00003000
209#define EN_SPORT 0x00030000
210#define EN_SPDIF 0x000c0000
211#define EN_CODEC (EN_AUDIO1 | EN_AUDIO0)
212
213#define VORTEX_SPDIF_SMPRATE 0x29194
214
215#define VORTEX_SPDIF_FLAGS 0x2205c
216#define VORTEX_SPDIF_CFG0 0x291D0 /* status data */
217#define VORTEX_SPDIF_CFG1 0x291D4
218
219#define VORTEX_SMP_TIME 0x29198 /* Sample counter/timer */
220#define VORTEX_SMP_TIMER 0x2919c
221#define VORTEX_CODEC2_CTRL 0x291a0
222
223#define VORTEX_MODEM_CTRL 0x291ac
224
225/* IRQ */
226#define VORTEX_IRQ_SOURCE 0x2a000 /* Interrupt source flags. */
227#define VORTEX_IRQ_CTRL 0x2a004 /* Interrupt source mask. */
228
229//#define VORTEX_IRQ_U0 0x2a008 /* ?? */
230#define VORTEX_STAT 0x2a008 /* Some sort of status */
231#define STAT_IRQ 0x00000001 /* This bitis set if the IRQ is valid. */
232
233#define VORTEX_CTRL 0x2a00c
234#define CTRL_MIDI_EN 0x00000001
235#define CTRL_MIDI_PORT 0x00000060
236#define CTRL_GAME_EN 0x00000008
237#define CTRL_GAME_PORT 0x00000e00
238#define CTRL_IRQ_ENABLE 0x00004000
239#define CTRL_SPDIF 0x00000000 /* unknown. Please find this value */
240#define CTRL_SPORT 0x00200000
241#define CTRL_RST 0x00800000
242#define CTRL_UNKNOWN 0x01000000
243
244/* write: Timer period config / read: TIMER IRQ ack. */
245#define VORTEX_IRQ_STAT 0x2919c
246
247 /* MIDI *//* GAME. */
248#define VORTEX_MIDI_DATA 0x28800
249#define VORTEX_MIDI_CMD 0x28804 /* Write command / Read status */
250
251#define VORTEX_GAME_LEGACY 0x28808
252#define VORTEX_CTRL2 0x2880c
253#define CTRL2_GAME_ADCMODE 0x40
254#define VORTEX_GAME_AXIS 0x28810 /* Axis base register. 4 axis's */
255#define AXIS_SIZE 4
256#define AXIS_RANGE 0x1fff
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
new file mode 100644
index 000000000000..889b4a1a51a1
--- /dev/null
+++ b/sound/pci/au88x0/au88x0.c
@@ -0,0 +1,388 @@
1/*
2 * ALSA driver for the Aureal Vortex family of soundprocessors.
3 * Author: Manuel Jander (mjander@embedded.cl)
4 *
5 * This driver is the result of the OpenVortex Project from Savannah
6 * (savannah.nongnu.org/projects/openvortex). I would like to thank
7 * the developers of OpenVortex, Jeff Muizelaar and Kester Maddock, from
8 * whom i got plenty of help, and their codebase was invaluable.
9 * Thanks to the ALSA developers, they helped a lot working out
10 * the ALSA part.
11 * Thanks also to Sourceforge for maintaining the old binary drivers,
12 * and the forum, where developers could comunicate.
13 *
14 * Now at least i can play Legacy DOOM with MIDI music :-)
15 */
16
17#include "au88x0.h"
18#include <linux/init.h>
19#include <linux/pci.h>
20#include <linux/slab.h>
21#include <linux/interrupt.h>
22#include <linux/moduleparam.h>
23#include <sound/initval.h>
24
25// module parameters (see "Module Parameters")
26static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
27static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
28static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
29static int pcifix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 255 };
30
31module_param_array(index, int, NULL, 0444);
32MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
33module_param_array(id, charp, NULL, 0444);
34MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
35module_param_array(enable, bool, NULL, 0444);
36MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
37module_param_array(pcifix, int, NULL, 0444);
38MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard.");
39
40MODULE_DESCRIPTION("Aureal vortex");
41MODULE_LICENSE("GPL");
42MODULE_SUPPORTED_DEVICE("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}");
43
44MODULE_DEVICE_TABLE(pci, snd_vortex_ids);
45
46static void vortex_fix_latency(struct pci_dev *vortex)
47{
48 int rc;
49 if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
50 printk(KERN_INFO CARD_NAME
51 ": vortex latency is 0xff\n");
52 } else {
53 printk(KERN_WARNING CARD_NAME
54 ": could not set vortex latency: pci error 0x%x\n", rc);
55 }
56}
57
58static void vortex_fix_agp_bridge(struct pci_dev *via)
59{
60 int rc;
61 u8 value;
62
63 /*
64 * only set the bit (Extend PCI#2 Internal Master for
65 * Efficient Handling of Dummy Requests) if the can
66 * read the config and it is not already set
67 */
68
69 if (!(rc = pci_read_config_byte(via, 0x42, &value))
70 && ((value & 0x10)
71 || !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) {
72 printk(KERN_INFO CARD_NAME
73 ": bridge config is 0x%x\n", value | 0x10);
74 } else {
75 printk(KERN_WARNING CARD_NAME
76 ": could not set vortex latency: pci error 0x%x\n", rc);
77 }
78}
79
80static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix)
81{
82 struct pci_dev *via;
83
84 /* autodetect if workarounds are required */
85 if (fix == 255) {
86 /* VIA KT133 */
87 via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8365_1, NULL);
88 /* VIA Apollo */
89 if (via == NULL) {
90 via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, NULL);
91 }
92 /* AMD Irongate */
93 if (via == NULL) {
94 via = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL);
95 }
96 if (via) {
97 printk(KERN_INFO CARD_NAME ": Activating latency workaround...\n");
98 vortex_fix_latency(vortex);
99 vortex_fix_agp_bridge(via);
100 }
101 } else {
102 if (fix & 0x1)
103 vortex_fix_latency(vortex);
104 if ((fix & 0x2) && (via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8365_1, NULL)))
105 vortex_fix_agp_bridge(via);
106 if ((fix & 0x4) && (via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, NULL)))
107 vortex_fix_agp_bridge(via);
108 if ((fix & 0x8) && (via = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL)))
109 vortex_fix_agp_bridge(via);
110 }
111}
112
113// component-destructor
114// (see "Management of Cards and Components")
115static int snd_vortex_dev_free(snd_device_t * device)
116{
117 vortex_t *vortex = device->device_data;
118
119 vortex_gameport_unregister(vortex);
120 vortex_core_shutdown(vortex);
121 // Take down PCI interface.
122 synchronize_irq(vortex->irq);
123 free_irq(vortex->irq, vortex);
124 pci_release_regions(vortex->pci_dev);
125 pci_disable_device(vortex->pci_dev);
126 kfree(vortex);
127
128 return 0;
129}
130
131// chip-specific constructor
132// (see "Management of Cards and Components")
133static int __devinit
134snd_vortex_create(snd_card_t * card, struct pci_dev *pci, vortex_t ** rchip)
135{
136 vortex_t *chip;
137 int err;
138 static snd_device_ops_t ops = {
139 .dev_free = snd_vortex_dev_free,
140 };
141
142 *rchip = NULL;
143
144 // check PCI availability (DMA).
145 if ((err = pci_enable_device(pci)) < 0)
146 return err;
147 if (!pci_dma_supported(pci, VORTEX_DMA_MASK)) {
148 printk(KERN_ERR "error to set DMA mask\n");
149 return -ENXIO;
150 }
151 pci_set_dma_mask(pci, VORTEX_DMA_MASK);
152
153 chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
154 if (chip == NULL)
155 return -ENOMEM;
156
157 chip->card = card;
158
159 // initialize the stuff
160 chip->pci_dev = pci;
161 chip->io = pci_resource_start(pci, 0);
162 chip->vendor = pci->vendor;
163 chip->device = pci->device;
164 chip->card = card;
165 chip->irq = -1;
166
167 // (1) PCI resource allocation
168 // Get MMIO area
169 //
170 if ((err = pci_request_regions(pci, CARD_NAME_SHORT)) != 0)
171 goto regions_out;
172
173 chip->mmio = ioremap_nocache(pci_resource_start(pci, 0),
174 pci_resource_len(pci, 0));
175 if (!chip->mmio) {
176 printk(KERN_ERR "MMIO area remap failed.\n");
177 err = -ENOMEM;
178 goto ioremap_out;
179 }
180
181 /* Init audio core.
182 * This must be done before we do request_irq otherwise we can get spurious
183 * interupts that we do not handle properly and make a mess of things */
184 if ((err = vortex_core_init(chip)) != 0) {
185 printk(KERN_ERR "hw core init failed\n");
186 goto core_out;
187 }
188
189 if ((err = request_irq(pci->irq, vortex_interrupt,
190 SA_INTERRUPT | SA_SHIRQ, CARD_NAME_SHORT,
191 chip)) != 0) {
192 printk(KERN_ERR "cannot grab irq\n");
193 goto irq_out;
194 }
195 chip->irq = pci->irq;
196
197 pci_set_master(pci);
198 // End of PCI setup.
199
200 // Register alsa root device.
201 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
202 goto alloc_out;
203 }
204
205 *rchip = chip;
206
207 return 0;
208
209 alloc_out:
210 synchronize_irq(chip->irq);
211 free_irq(chip->irq, chip);
212 irq_out:
213 vortex_core_shutdown(chip);
214 core_out:
215 iounmap(chip->mmio);
216 ioremap_out:
217 pci_release_regions(chip->pci_dev);
218 regions_out:
219 pci_disable_device(chip->pci_dev);
220 //FIXME: this not the right place to unregister the gameport
221 vortex_gameport_unregister(chip);
222 return err;
223}
224
225// constructor -- see "Constructor" sub-section
226static int __devinit
227snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
228{
229 static int dev;
230 snd_card_t *card;
231 vortex_t *chip;
232 int err;
233
234 // (1)
235 if (dev >= SNDRV_CARDS)
236 return -ENODEV;
237 if (!enable[dev]) {
238 dev++;
239 return -ENOENT;
240 }
241 // (2)
242 card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
243 if (card == NULL)
244 return -ENOMEM;
245
246 // (3)
247 if ((err = snd_vortex_create(card, pci, &chip)) < 0) {
248 snd_card_free(card);
249 return err;
250 }
251 snd_vortex_workaround(pci, pcifix[dev]);
252 // (4) Alloc components.
253 // ADB pcm.
254 if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) {
255 snd_card_free(card);
256 return err;
257 }
258#ifndef CHIP_AU8820
259 // ADB SPDIF
260 if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_SPDIF, 1)) < 0) {
261 snd_card_free(card);
262 return err;
263 }
264 // A3D
265 if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_A3D, NR_A3D)) < 0) {
266 snd_card_free(card);
267 return err;
268 }
269#endif
270 /*
271 // ADB I2S
272 if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_I2S, 1)) < 0) {
273 snd_card_free(card);
274 return err;
275 }
276 */
277#ifndef CHIP_AU8810
278 // WT pcm.
279 if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_WT, NR_WT)) < 0) {
280 snd_card_free(card);
281 return err;
282 }
283#endif
284 // snd_ac97_mixer and Vortex mixer.
285 if ((err = snd_vortex_mixer(chip)) < 0) {
286 snd_card_free(card);
287 return err;
288 }
289 if ((err = snd_vortex_midi(chip)) < 0) {
290 snd_card_free(card);
291 return err;
292 }
293
294 vortex_gameport_register(chip);
295
296#if 0
297 if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
298 sizeof(snd_vortex_synth_arg_t), &wave) < 0
299 || wave == NULL) {
300 snd_printk("Can't initialize Aureal wavetable synth\n");
301 } else {
302 snd_vortex_synth_arg_t *arg;
303
304 arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
305 strcpy(wave->name, "Aureal Synth");
306 arg->hwptr = vortex;
307 arg->index = 1;
308 arg->seq_ports = seq_ports[dev];
309 arg->max_voices = max_synth_voices[dev];
310 }
311#endif
312
313 // (5)
314 strcpy(card->driver, CARD_NAME_SHORT);
315 strcpy(card->shortname, CARD_NAME_SHORT);
316 sprintf(card->longname, "%s at 0x%lx irq %i",
317 card->shortname, chip->io, chip->irq);
318
319 if ((err = pci_read_config_word(pci, PCI_DEVICE_ID,
320 &(chip->device))) < 0) {
321 snd_card_free(card);
322 return err;
323 }
324 if ((err = pci_read_config_word(pci, PCI_VENDOR_ID,
325 &(chip->vendor))) < 0) {
326 snd_card_free(card);
327 return err;
328 }
329 if ((err = pci_read_config_byte(pci, PCI_REVISION_ID,
330 &(chip->rev))) < 0) {
331 snd_card_free(card);
332 return err;
333 }
334#ifdef CHIP_AU8830
335 if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
336 printk(KERN_ALERT
337 "vortex: The revision (%x) of your card has not been seen before.\n",
338 chip->rev);
339 printk(KERN_ALERT
340 "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
341 snd_card_free(card);
342 err = -ENODEV;
343 return err;
344 }
345#endif
346
347 // (6)
348 if ((err = snd_card_register(card)) < 0) {
349 snd_card_free(card);
350 return err;
351 }
352 // (7)
353 pci_set_drvdata(pci, card);
354 dev++;
355 vortex_connect_default(chip, 1);
356 vortex_enable_int(chip);
357 return 0;
358}
359
360// destructor -- see "Destructor" sub-section
361static void __devexit snd_vortex_remove(struct pci_dev *pci)
362{
363 snd_card_free(pci_get_drvdata(pci));
364 pci_set_drvdata(pci, NULL);
365}
366
367// pci_driver definition
368static struct pci_driver driver = {
369 .name = CARD_NAME_SHORT,
370 .id_table = snd_vortex_ids,
371 .probe = snd_vortex_probe,
372 .remove = __devexit_p(snd_vortex_remove),
373};
374
375// initialization of the module
376static int __init alsa_card_vortex_init(void)
377{
378 return pci_module_init(&driver);
379}
380
381// clean up the module
382static void __exit alsa_card_vortex_exit(void)
383{
384 pci_unregister_driver(&driver);
385}
386
387module_init(alsa_card_vortex_init)
388module_exit(alsa_card_vortex_exit)
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
new file mode 100644
index 000000000000..ee1ede1979f6
--- /dev/null
+++ b/sound/pci/au88x0/au88x0.h
@@ -0,0 +1,284 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17#ifndef __SOUND_AU88X0_H
18#define __SOUND_AU88X0_H
19
20#ifdef __KERNEL__
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/pci.h>
24#include <asm/io.h>
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include <sound/rawmidi.h>
28#include <sound/mpu401.h>
29#include <sound/hwdep.h>
30#include <sound/ac97_codec.h>
31
32#endif
33
34#ifndef CHIP_AU8820
35#include "au88x0_eq.h"
36#include "au88x0_a3d.h"
37#endif
38#ifndef CHIP_AU8810
39#include "au88x0_wt.h"
40#endif
41
42#define VORTEX_DMA_MASK 0xffffffff
43
44#define hwread(x,y) readl((x)+((y)>>2))
45#define hwwrite(x,y,z) writel((z),(x)+((y)>>2))
46
47/* Vortex MPU401 defines. */
48#define MIDI_CLOCK_DIV 0x61
49/* Standart MPU401 defines. */
50#define MPU401_RESET 0xff
51#define MPU401_ENTER_UART 0x3f
52#define MPU401_ACK 0xfe
53
54// Get src register value to convert from x to y.
55#define SRC_RATIO(x,y) ((((x<<15)/y) + 1)/2)
56
57/* FIFO software state constants. */
58#define FIFO_STOP 0
59#define FIFO_START 1
60#define FIFO_PAUSE 2
61
62/* IRQ flags */
63#define IRQ_ERR_MASK 0x00ff
64#define IRQ_FATAL 0x0001
65#define IRQ_PARITY 0x0002
66#define IRQ_REG 0x0004
67#define IRQ_FIFO 0x0008
68#define IRQ_DMA 0x0010
69#define IRQ_PCMOUT 0x0020 /* PCM OUT page crossing */
70#define IRQ_TIMER 0x1000
71#define IRQ_MIDI 0x2000
72#define IRQ_MODEM 0x4000
73
74/* ADB Resource */
75#define VORTEX_RESOURCE_DMA 0x00000000
76#define VORTEX_RESOURCE_SRC 0x00000001
77#define VORTEX_RESOURCE_MIXIN 0x00000002
78#define VORTEX_RESOURCE_MIXOUT 0x00000003
79#define VORTEX_RESOURCE_A3D 0x00000004
80#define VORTEX_RESOURCE_LAST 0x00000005
81
82/* Check for SDAC bit in "Extended audio ID" AC97 register */
83//#define VORTEX_IS_QUAD(x) (((x)->codec == NULL) ? 0 : ((x)->codec->ext_id&0x80))
84#define VORTEX_IS_QUAD(x) ((x)->isquad)
85/* Check if chip has bug. */
86#define IS_BAD_CHIP(x) (\
87 (x->rev == 0xfe && x->device == PCI_DEVICE_ID_AUREAL_VORTEX_2) || \
88 (x->rev == 0xfe && x->device == PCI_DEVICE_ID_AUREAL_ADVANTAGE))
89
90
91/* PCM devices */
92#define VORTEX_PCM_ADB 0
93#define VORTEX_PCM_SPDIF 1
94#define VORTEX_PCM_A3D 2
95#define VORTEX_PCM_WT 3
96#define VORTEX_PCM_I2S 4
97#define VORTEX_PCM_LAST 5
98
99#define MIX_CAPT(x) (vortex->mixcapt[x])
100#define MIX_PLAYB(x) (vortex->mixplayb[x])
101#define MIX_SPDIF(x) (vortex->mixspdif[x])
102
103#define NR_WTPB 0x20 /* WT channels per eahc bank. */
104
105/* Structs */
106typedef struct {
107 //int this_08; /* Still unknown */
108 int fifo_enabled; /* this_24 */
109 int fifo_status; /* this_1c */
110 int dma_ctrl; /* this_78 (ADB), this_7c (WT) */
111 int dma_unknown; /* this_74 (ADB), this_78 (WT). WDM: +8 */
112 int cfg0;
113 int cfg1;
114
115 int nr_ch; /* Nr of PCM channels in use */
116 int type; /* Output type (ac97, a3d, spdif, i2s, dsp) */
117 int dma; /* Hardware DMA index. */
118 int dir; /* Stream Direction. */
119 u32 resources[5];
120
121 /* Virtual page extender stuff */
122 int nr_periods;
123 int period_bytes;
124 snd_pcm_sgbuf_t *sgbuf; /* DMA Scatter Gather struct */
125 int period_real;
126 int period_virt;
127
128 snd_pcm_substream_t *substream;
129} stream_t;
130
131typedef struct snd_vortex vortex_t;
132struct snd_vortex {
133 /* ALSA structs. */
134 snd_card_t *card;
135 snd_pcm_t *pcm[VORTEX_PCM_LAST];
136
137 snd_rawmidi_t *rmidi; /* Legacy Midi interface. */
138 ac97_t *codec;
139
140 /* Stream structs. */
141 stream_t dma_adb[NR_ADB];
142 int spdif_sr;
143#ifndef CHIP_AU8810
144 stream_t dma_wt[NR_WT];
145 wt_voice_t wt_voice[NR_WT]; /* WT register cache. */
146 char mixwt[(NR_WT / NR_WTPB) * 6]; /* WT mixin objects */
147#endif
148
149 /* Global resources */
150 s8 mixcapt[2];
151 s8 mixplayb[4];
152#ifndef CHIP_AU8820
153 s8 mixspdif[2];
154 s8 mixa3d[2]; /* mixers which collect all a3d streams. */
155 s8 mixxtlk[2]; /* crosstalk canceler mixer inputs. */
156#endif
157 u32 fixed_res[5];
158
159#ifndef CHIP_AU8820
160 /* Hardware equalizer structs */
161 eqlzr_t eq;
162 /* A3D structs */
163 a3dsrc_t a3d[NR_A3D];
164 /* Xtalk canceler */
165 int xt_mode; /* 1: speakers, 0:headphones. */
166#endif
167
168 int isquad; /* cache of extended ID codec flag. */
169
170 /* Gameport stuff. */
171 struct gameport *gameport;
172
173 /* PCI hardware resources */
174 unsigned long io;
175 unsigned long __iomem *mmio;
176 unsigned int irq;
177 spinlock_t lock;
178
179 /* PCI device */
180 struct pci_dev *pci_dev;
181 u16 vendor;
182 u16 device;
183 u8 rev;
184};
185
186/* Functions. */
187
188/* SRC */
189static void vortex_adb_setsrc(vortex_t * vortex, int adbdma,
190 unsigned int cvrt, int dir);
191
192/* DMA Engines. */
193static void vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
194 snd_pcm_sgbuf_t * sgbuf, int size,
195 int count);
196static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie,
197 int dir, int fmt, int d,
198 unsigned long offset);
199static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb);
200#ifndef CHIP_AU8810
201static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
202 snd_pcm_sgbuf_t * sgbuf, int size,
203 int count);
204static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d, /*int e, */
205 unsigned long offset);
206static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb);
207#endif
208
209static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma);
210//static void vortex_adbdma_stopfifo(vortex_t *vortex, int adbdma);
211static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma);
212static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma);
213static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma);
214static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma);
215
216#ifndef CHIP_AU8810
217static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma);
218static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma);
219static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma);
220static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma);
221static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma);
222#endif
223
224/* global stuff. */
225static void vortex_codec_init(vortex_t * vortex);
226static void vortex_codec_write(ac97_t * codec, unsigned short addr,
227 unsigned short data);
228static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr);
229static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode);
230
231static int vortex_core_init(vortex_t * card);
232static int vortex_core_shutdown(vortex_t * card);
233static void vortex_enable_int(vortex_t * card);
234static irqreturn_t vortex_interrupt(int irq, void *dev_id,
235 struct pt_regs *regs);
236static int vortex_alsafmt_aspfmt(int alsafmt);
237
238/* Connection stuff. */
239static void vortex_connect_default(vortex_t * vortex, int en);
240static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch,
241 int dir, int type);
242static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out,
243 int restype);
244#ifndef CHIP_AU8810
245static int vortex_wt_allocroute(vortex_t * vortex, int dma, int nr_ch);
246static void vortex_wt_connect(vortex_t * vortex, int en);
247static void vortex_wt_init(vortex_t * vortex);
248#endif
249
250static void vortex_route(vortex_t * vortex, int en, unsigned char channel,
251 unsigned char source, unsigned char dest);
252#if 0
253static void vortex_routes(vortex_t * vortex, int en, unsigned char channel,
254 unsigned char source, unsigned char dest0,
255 unsigned char dest1);
256#endif
257static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
258 unsigned char mixin,
259 unsigned char mix, int a);
260static void vortex_mix_setinputvolumebyte(vortex_t * vortex,
261 unsigned char mix, int mixin,
262 unsigned char vol);
263static void vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix,
264 unsigned char vol);
265
266/* A3D functions. */
267#ifndef CHIP_AU8820
268static void vortex_Vort3D(vortex_t * v, int en);
269static void vortex_Vort3D_connect(vortex_t * vortex, int en);
270static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en);
271#endif
272
273/* Driver stuff. */
274static int __devinit vortex_gameport_register(vortex_t * card);
275static void vortex_gameport_unregister(vortex_t * card);
276#ifndef CHIP_AU8820
277static int __devinit vortex_eq_init(vortex_t * vortex);
278static int __devexit vortex_eq_free(vortex_t * vortex);
279#endif
280/* ALSA stuff. */
281static int __devinit snd_vortex_new_pcm(vortex_t * vortex, int idx, int nr);
282static int __devinit snd_vortex_mixer(vortex_t * vortex);
283static int __devinit snd_vortex_midi(vortex_t * vortex);
284#endif
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
new file mode 100644
index 000000000000..9ea2ba7bc3c8
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_a3d.c
@@ -0,0 +1,914 @@
1/***************************************************************************
2 * au88x0_a3d.c
3 *
4 * Fri Jul 18 14:16:22 2003
5 * Copyright 2003 mjander
6 * mjander@users.sourceforge.net
7 *
8 * A3D. You may think i'm crazy, but this may work someday. Who knows...
9 ****************************************************************************/
10
11/*
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27#include "au88x0_a3d.h"
28#include "au88x0_a3ddata.c"
29#include "au88x0_xtalk.h"
30#include "au88x0.h"
31
32static void
33a3dsrc_SetTimeConsts(a3dsrc_t * a, short HrtfTrack, short ItdTrack,
34 short GTrack, short CTrack)
35{
36 vortex_t *vortex = (vortex_t *) (a->vortex);
37 hwwrite(vortex->mmio,
38 a3d_addrA(a->slice, a->source, A3D_A_HrtfTrackTC), HrtfTrack);
39 hwwrite(vortex->mmio,
40 a3d_addrA(a->slice, a->source, A3D_A_ITDTrackTC), ItdTrack);
41 hwwrite(vortex->mmio,
42 a3d_addrA(a->slice, a->source, A3D_A_GainTrackTC), GTrack);
43 hwwrite(vortex->mmio,
44 a3d_addrA(a->slice, a->source, A3D_A_CoeffTrackTC), CTrack);
45}
46
47#if 0
48static void
49a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack,
50 short *GTrack, short *CTrack)
51{
52 // stub!
53}
54
55#endif
56/* Atmospheric absorbtion. */
57
58static void
59a3dsrc_SetAtmosTarget(a3dsrc_t * a, short aa, short b, short c, short d,
60 short e)
61{
62 vortex_t *vortex = (vortex_t *) (a->vortex);
63 hwwrite(vortex->mmio,
64 a3d_addrB(a->slice, a->source, A3D_B_A21Target),
65 (e << 0x10) | d);
66 hwwrite(vortex->mmio,
67 a3d_addrB(a->slice, a->source, A3D_B_B10Target),
68 (b << 0x10) | aa);
69 hwwrite(vortex->mmio,
70 a3d_addrB(a->slice, a->source, A3D_B_B2Target), c);
71}
72
73static void
74a3dsrc_SetAtmosCurrent(a3dsrc_t * a, short aa, short b, short c, short d,
75 short e)
76{
77 vortex_t *vortex = (vortex_t *) (a->vortex);
78 hwwrite(vortex->mmio,
79 a3d_addrB(a->slice, a->source, A3D_B_A12Current),
80 (e << 0x10) | d);
81 hwwrite(vortex->mmio,
82 a3d_addrB(a->slice, a->source, A3D_B_B01Current),
83 (b << 0x10) | aa);
84 hwwrite(vortex->mmio,
85 a3d_addrB(a->slice, a->source, A3D_B_B2Current), c);
86}
87
88static void
89a3dsrc_SetAtmosState(a3dsrc_t * a, short x1, short x2, short y1, short y2)
90{
91 vortex_t *vortex = (vortex_t *) (a->vortex);
92 hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x1), x1);
93 hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x2), x2);
94 hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y1), y1);
95 hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y2), y2);
96}
97
98#if 0
99static void
100a3dsrc_GetAtmosTarget(a3dsrc_t * a, short *aa, short *b, short *c,
101 short *d, short *e)
102{
103}
104static void
105a3dsrc_GetAtmosCurrent(a3dsrc_t * a, short *bb01, short *ab01, short *b2,
106 short *aa12, short *ba12)
107{
108 vortex_t *vortex = (vortex_t *) (a->vortex);
109 *aa12 =
110 hwread(vortex->mmio,
111 a3d_addrA(a->slice, a->source, A3D_A_A12Current));
112 *ba12 =
113 hwread(vortex->mmio,
114 a3d_addrB(a->slice, a->source, A3D_B_A12Current));
115 *ab01 =
116 hwread(vortex->mmio,
117 a3d_addrA(a->slice, a->source, A3D_A_B01Current));
118 *bb01 =
119 hwread(vortex->mmio,
120 a3d_addrB(a->slice, a->source, A3D_B_B01Current));
121 *b2 =
122 hwread(vortex->mmio,
123 a3d_addrA(a->slice, a->source, A3D_A_B2Current));
124}
125
126static void
127a3dsrc_GetAtmosState(a3dsrc_t * a, short *x1, short *x2, short *y1, short *y2)
128{
129
130}
131
132#endif
133/* HRTF */
134
135static void
136a3dsrc_SetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
137{
138 vortex_t *vortex = (vortex_t *) (a->vortex);
139 int i;
140
141 for (i = 0; i < HRTF_SZ; i++)
142 hwwrite(vortex->mmio,
143 a3d_addrB(a->slice, a->source,
144 A3D_B_HrtfTarget) + (i << 2),
145 (b[i] << 0x10) | aa[i]);
146}
147
148static void
149a3dsrc_SetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
150{
151 vortex_t *vortex = (vortex_t *) (a->vortex);
152 int i;
153
154 for (i = 0; i < HRTF_SZ; i++)
155 hwwrite(vortex->mmio,
156 a3d_addrB(a->slice, a->source,
157 A3D_B_HrtfCurrent) + (i << 2),
158 (b[i] << 0x10) | aa[i]);
159}
160
161static void
162a3dsrc_SetHrtfState(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b)
163{
164 vortex_t *vortex = (vortex_t *) (a->vortex);
165 int i;
166
167 for (i = 0; i < HRTF_SZ; i++)
168 hwwrite(vortex->mmio,
169 a3d_addrB(a->slice, a->source,
170 A3D_B_HrtfDelayLine) + (i << 2),
171 (b[i] << 0x10) | aa[i]);
172}
173
174static void a3dsrc_SetHrtfOutput(a3dsrc_t * a, short left, short right)
175{
176 vortex_t *vortex = (vortex_t *) (a->vortex);
177 hwwrite(vortex->mmio,
178 a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL), left);
179 hwwrite(vortex->mmio,
180 a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR), right);
181}
182
183#if 0
184static void a3dsrc_GetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
185{
186 vortex_t *vortex = (vortex_t *) (a->vortex);
187 int i;
188
189 for (i = 0; i < HRTF_SZ; i++)
190 aa[i] =
191 hwread(vortex->mmio,
192 a3d_addrA(a->slice, a->source,
193 A3D_A_HrtfTarget + (i << 2)));
194 for (i = 0; i < HRTF_SZ; i++)
195 b[i] =
196 hwread(vortex->mmio,
197 a3d_addrB(a->slice, a->source,
198 A3D_B_HrtfTarget + (i << 2)));
199}
200
201static void a3dsrc_GetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
202{
203 vortex_t *vortex = (vortex_t *) (a->vortex);
204 int i;
205
206 for (i = 0; i < HRTF_SZ; i++)
207 aa[i] =
208 hwread(vortex->mmio,
209 a3d_addrA(a->slice, a->source,
210 A3D_A_HrtfCurrent + (i << 2)));
211 for (i = 0; i < HRTF_SZ; i++)
212 b[i] =
213 hwread(vortex->mmio,
214 a3d_addrB(a->slice, a->source,
215 A3D_B_HrtfCurrent + (i << 2)));
216}
217
218static void a3dsrc_GetHrtfState(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b)
219{
220 vortex_t *vortex = (vortex_t *) (a->vortex);
221 int i;
222 // FIXME: verify this!
223 for (i = 0; i < HRTF_SZ; i++)
224 aa[i] =
225 hwread(vortex->mmio,
226 a3d_addrA(a->slice, a->source,
227 A3D_A_HrtfDelayLine + (i << 2)));
228 for (i = 0; i < HRTF_SZ; i++)
229 b[i] =
230 hwread(vortex->mmio,
231 a3d_addrB(a->slice, a->source,
232 A3D_B_HrtfDelayLine + (i << 2)));
233}
234
235static void a3dsrc_GetHrtfOutput(a3dsrc_t * a, short *left, short *right)
236{
237 vortex_t *vortex = (vortex_t *) (a->vortex);
238 *left =
239 hwread(vortex->mmio,
240 a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL));
241 *right =
242 hwread(vortex->mmio,
243 a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR));
244}
245
246#endif
247
248/* Interaural Time Difference.
249 * "The other main clue that humans use to locate sounds, is called
250 * Interaural Time Difference (ITD). The differences in distance from
251 * the sound source to a listeners ears means that the sound will
252 * reach one ear slightly before the other....", found somewhere with google.*/
253static void a3dsrc_SetItdTarget(a3dsrc_t * a, short litd, short ritd)
254{
255 vortex_t *vortex = (vortex_t *) (a->vortex);
256
257 if (litd < 0)
258 litd = 0;
259 if (litd > 0x57FF)
260 litd = 0x57FF;
261 if (ritd < 0)
262 ritd = 0;
263 if (ritd > 0x57FF)
264 ritd = 0x57FF;
265 hwwrite(vortex->mmio,
266 a3d_addrB(a->slice, a->source, A3D_B_ITDTarget),
267 (ritd << 0x10) | litd);
268 //hwwrite(vortex->mmio, addr(0x191DF+5, this04, this08), (ritd<<0x10)|litd);
269}
270
271static void a3dsrc_SetItdCurrent(a3dsrc_t * a, short litd, short ritd)
272{
273 vortex_t *vortex = (vortex_t *) (a->vortex);
274
275 if (litd < 0)
276 litd = 0;
277 if (litd > 0x57FF)
278 litd = 0x57FF;
279 if (ritd < 0)
280 ritd = 0;
281 if (ritd > 0x57FF)
282 ritd = 0x57FF;
283 hwwrite(vortex->mmio,
284 a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent),
285 (ritd << 0x10) | litd);
286 //hwwrite(vortex->mmio, addr(0x191DF+1, this04, this08), (ritd<<0x10)|litd);
287}
288
289static void a3dsrc_SetItdDline(a3dsrc_t * a, a3d_ItdDline_t const dline)
290{
291 vortex_t *vortex = (vortex_t *) (a->vortex);
292 int i;
293 /* 45 != 40 -> Check this ! */
294 for (i = 0; i < DLINE_SZ; i++)
295 hwwrite(vortex->mmio,
296 a3d_addrA(a->slice, a->source,
297 A3D_A_ITDDelayLine) + (i << 2), dline[i]);
298}
299
300#if 0
301static void a3dsrc_GetItdTarget(a3dsrc_t * a, short *litd, short *ritd)
302{
303 vortex_t *vortex = (vortex_t *) (a->vortex);
304 *ritd =
305 hwread(vortex->mmio,
306 a3d_addrA(a->slice, a->source, A3D_A_ITDTarget));
307 *litd =
308 hwread(vortex->mmio,
309 a3d_addrB(a->slice, a->source, A3D_B_ITDTarget));
310}
311
312static void a3dsrc_GetItdCurrent(a3dsrc_t * a, short *litd, short *ritd)
313{
314 vortex_t *vortex = (vortex_t *) (a->vortex);
315
316 *ritd =
317 hwread(vortex->mmio,
318 a3d_addrA(a->slice, a->source, A3D_A_ITDCurrent));
319 *litd =
320 hwread(vortex->mmio,
321 a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent));
322}
323
324static void a3dsrc_GetItdDline(a3dsrc_t * a, a3d_ItdDline_t dline)
325{
326 vortex_t *vortex = (vortex_t *) (a->vortex);
327 int i;
328
329 for (i = 0; i < DLINE_SZ; i++)
330 dline[i] =
331 hwread(vortex->mmio,
332 a3d_addrA(a->slice, a->source,
333 A3D_A_ITDDelayLine + (i << 2)));
334}
335
336#endif
337/* This is may be used for ILD Interaural Level Difference. */
338
339static void a3dsrc_SetGainTarget(a3dsrc_t * a, short left, short right)
340{
341 vortex_t *vortex = (vortex_t *) (a->vortex);
342 hwwrite(vortex->mmio,
343 a3d_addrB(a->slice, a->source, A3D_B_GainTarget),
344 (right << 0x10) | left);
345}
346
347static void a3dsrc_SetGainCurrent(a3dsrc_t * a, short left, short right)
348{
349 vortex_t *vortex = (vortex_t *) (a->vortex);
350 hwwrite(vortex->mmio,
351 a3d_addrB(a->slice, a->source, A3D_B_GainCurrent),
352 (right << 0x10) | left);
353}
354
355#if 0
356static void a3dsrc_GetGainTarget(a3dsrc_t * a, short *left, short *right)
357{
358 vortex_t *vortex = (vortex_t *) (a->vortex);
359 *right =
360 hwread(vortex->mmio,
361 a3d_addrA(a->slice, a->source, A3D_A_GainTarget));
362 *left =
363 hwread(vortex->mmio,
364 a3d_addrB(a->slice, a->source, A3D_B_GainTarget));
365}
366
367static void a3dsrc_GetGainCurrent(a3dsrc_t * a, short *left, short *right)
368{
369 vortex_t *vortex = (vortex_t *) (a->vortex);
370 *right =
371 hwread(vortex->mmio,
372 a3d_addrA(a->slice, a->source, A3D_A_GainCurrent));
373 *left =
374 hwread(vortex->mmio,
375 a3d_addrB(a->slice, a->source, A3D_B_GainCurrent));
376}
377
378/* CA3dIO this func seems to be inlined all over this place. */
379static void CA3dIO_WriteReg(a3dsrc_t * a, unsigned long addr, short aa, short b)
380{
381 vortex_t *vortex = (vortex_t *) (a->vortex);
382 hwwrite(vortex->mmio, addr, (aa << 0x10) | b);
383}
384
385#endif
386/* Generic A3D stuff */
387
388static void a3dsrc_SetA3DSampleRate(a3dsrc_t * a, int sr)
389{
390 vortex_t *vortex = (vortex_t *) (a->vortex);
391 int esp0 = 0;
392
393 esp0 = (((esp0 & 0x7fffffff) | 0xB8000000) & 0x7) | ((sr & 0x1f) << 3);
394 hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), esp0);
395 //hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), esp0);
396}
397
398static void a3dsrc_EnableA3D(a3dsrc_t * a)
399{
400 vortex_t *vortex = (vortex_t *) (a->vortex);
401 hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd),
402 0xF0000001);
403 //hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), 0xF0000001);
404}
405
406static void a3dsrc_DisableA3D(a3dsrc_t * a)
407{
408 vortex_t *vortex = (vortex_t *) (a->vortex);
409 hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd),
410 0xF0000000);
411}
412
413static void a3dsrc_SetA3DControlReg(a3dsrc_t * a, unsigned long ctrl)
414{
415 vortex_t *vortex = (vortex_t *) (a->vortex);
416 hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), ctrl);
417}
418
419static void a3dsrc_SetA3DPointerReg(a3dsrc_t * a, unsigned long ptr)
420{
421 vortex_t *vortex = (vortex_t *) (a->vortex);
422 hwwrite(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd), ptr);
423}
424
425#if 0
426static void a3dsrc_GetA3DSampleRate(a3dsrc_t * a, int *sr)
427{
428 vortex_t *vortex = (vortex_t *) (a->vortex);
429 *sr = ((hwread(vortex->mmio, A3D_SLICE_Control + (a->slice << 0xd))
430 >> 3) & 0x1f);
431 //*sr = ((hwread(vortex->mmio, 0x19C38 + (this08<<0xd))>>3)&0x1f);
432}
433
434static void a3dsrc_GetA3DControlReg(a3dsrc_t * a, unsigned long *ctrl)
435{
436 vortex_t *vortex = (vortex_t *) (a->vortex);
437 *ctrl = hwread(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd));
438}
439
440static void a3dsrc_GetA3DPointerReg(a3dsrc_t * a, unsigned long *ptr)
441{
442 vortex_t *vortex = (vortex_t *) (a->vortex);
443 *ptr = hwread(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd));
444}
445
446#endif
447static void a3dsrc_ZeroSliceIO(a3dsrc_t * a)
448{
449 vortex_t *vortex = (vortex_t *) (a->vortex);
450 int i;
451
452 for (i = 0; i < 8; i++)
453 hwwrite(vortex->mmio,
454 A3D_SLICE_VDBDest +
455 ((((a->slice) << 0xb) + i) << 2), 0);
456 for (i = 0; i < 4; i++)
457 hwwrite(vortex->mmio,
458 A3D_SLICE_VDBSource +
459 ((((a->slice) << 0xb) + i) << 2), 0);
460}
461
462/* Reset Single A3D source. */
463static void a3dsrc_ZeroState(a3dsrc_t * a)
464{
465
466 //printk("vortex: ZeroState slice: %d, source %d\n", a->slice, a->source);
467
468 a3dsrc_SetAtmosState(a, 0, 0, 0, 0);
469 a3dsrc_SetHrtfState(a, A3dHrirZeros, A3dHrirZeros);
470 a3dsrc_SetItdDline(a, A3dItdDlineZeros);
471 a3dsrc_SetHrtfOutput(a, 0, 0);
472 a3dsrc_SetTimeConsts(a, 0, 0, 0, 0);
473
474 a3dsrc_SetAtmosCurrent(a, 0, 0, 0, 0, 0);
475 a3dsrc_SetAtmosTarget(a, 0, 0, 0, 0, 0);
476 a3dsrc_SetItdCurrent(a, 0, 0);
477 a3dsrc_SetItdTarget(a, 0, 0);
478 a3dsrc_SetGainCurrent(a, 0, 0);
479 a3dsrc_SetGainTarget(a, 0, 0);
480
481 a3dsrc_SetHrtfCurrent(a, A3dHrirZeros, A3dHrirZeros);
482 a3dsrc_SetHrtfTarget(a, A3dHrirZeros, A3dHrirZeros);
483}
484
485/* Reset entire A3D engine */
486static void a3dsrc_ZeroStateA3D(a3dsrc_t * a)
487{
488 int i, var, var2;
489
490 if ((a->vortex) == NULL) {
491 printk("vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n");
492 return;
493 }
494
495 a3dsrc_SetA3DControlReg(a, 0);
496 a3dsrc_SetA3DPointerReg(a, 0);
497
498 var = a->slice;
499 var2 = a->source;
500 for (i = 0; i < 4; i++) {
501 a->slice = i;
502 a3dsrc_ZeroSliceIO(a);
503 //a3dsrc_ZeroState(a);
504 }
505 a->source = var2;
506 a->slice = var;
507}
508
509/* Program A3D block as pass through */
510static void a3dsrc_ProgramPipe(a3dsrc_t * a)
511{
512 a3dsrc_SetTimeConsts(a, 0, 0, 0, 0);
513 a3dsrc_SetAtmosCurrent(a, 0, 0x4000, 0, 0, 0);
514 a3dsrc_SetAtmosTarget(a, 0x4000, 0, 0, 0, 0);
515 a3dsrc_SetItdCurrent(a, 0, 0);
516 a3dsrc_SetItdTarget(a, 0, 0);
517 a3dsrc_SetGainCurrent(a, 0x7fff, 0x7fff);
518 a3dsrc_SetGainTarget(a, 0x7fff, 0x7fff);
519
520 /* SET HRTF HERE */
521
522 /* Single spike leads to identity transfer function. */
523 a3dsrc_SetHrtfCurrent(a, A3dHrirImpulse, A3dHrirImpulse);
524 a3dsrc_SetHrtfTarget(a, A3dHrirImpulse, A3dHrirImpulse);
525
526 /* Test: Sounds saturated. */
527 //a3dsrc_SetHrtfCurrent(a, A3dHrirSatTest, A3dHrirSatTest);
528 //a3dsrc_SetHrtfTarget(a, A3dHrirSatTest, A3dHrirSatTest);
529}
530
531/* VDB = Vortex audio Dataflow Bus */
532#if 0
533static void a3dsrc_ClearVDBData(a3dsrc_t * a, unsigned long aa)
534{
535 vortex_t *vortex = (vortex_t *) (a->vortex);
536
537 // ((aa >> 2) << 8) - (aa >> 2)
538 hwwrite(vortex->mmio,
539 a3d_addrS(a->slice, A3D_SLICE_VDBDest) + (a->source << 2), 0);
540 hwwrite(vortex->mmio,
541 a3d_addrS(a->slice,
542 A3D_SLICE_VDBDest + 4) + (a->source << 2), 0);
543 /*
544 hwwrite(vortex->mmio, 0x19c00 + (((aa>>2)*255*4)+aa)*8, 0);
545 hwwrite(vortex->mmio, 0x19c04 + (((aa>>2)*255*4)+aa)*8, 0);
546 */
547}
548#endif
549
550/* A3D HwSource stuff. */
551
552static void vortex_A3dSourceHw_Initialize(vortex_t * v, int source, int slice)
553{
554 a3dsrc_t *a3dsrc = &(v->a3d[source + (slice * 4)]);
555 //a3dsrc_t *a3dsrc = &(v->a3d[source + (slice*4)]);
556
557 a3dsrc->vortex = (void *)v;
558 a3dsrc->source = source; /* source */
559 a3dsrc->slice = slice; /* slice */
560 a3dsrc_ZeroState(a3dsrc);
561 /* Added by me. */
562 a3dsrc_SetA3DSampleRate(a3dsrc, 0x11);
563}
564
565static int Vort3DRend_Initialize(vortex_t * v, unsigned short mode)
566{
567 v->xt_mode = mode; /* this_14 */
568
569 vortex_XtalkHw_init(v);
570 vortex_XtalkHw_SetGainsAllChan(v);
571 switch (v->xt_mode) {
572 case XT_SPEAKER0:
573 vortex_XtalkHw_ProgramXtalkNarrow(v);
574 break;
575 case XT_SPEAKER1:
576 vortex_XtalkHw_ProgramXtalkWide(v);
577 break;
578 default:
579 case XT_HEADPHONE:
580 vortex_XtalkHw_ProgramPipe(v);
581 break;
582 case XT_DIAMOND:
583 vortex_XtalkHw_ProgramDiamondXtalk(v);
584 break;
585 }
586 vortex_XtalkHw_SetSampleRate(v, 0x11);
587 vortex_XtalkHw_Enable(v);
588 return 0;
589}
590
591/* 3D Sound entry points. */
592
593static int vortex_a3d_register_controls(vortex_t * vortex);
594static void vortex_a3d_unregister_controls(vortex_t * vortex);
595/* A3D base support init/shudown */
596static void vortex_Vort3D(vortex_t * v, int en)
597{
598 int i;
599 if (en) {
600 Vort3DRend_Initialize(v, XT_HEADPHONE);
601 for (i = 0; i < NR_A3D; i++) {
602 vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2);
603 a3dsrc_ZeroStateA3D(&(v->a3d[0]));
604 }
605 } else {
606 vortex_XtalkHw_Disable(v);
607 }
608 /* Register ALSA controls */
609 if (en) {
610 vortex_a3d_register_controls(v);
611 } else {
612 vortex_a3d_unregister_controls(v);
613 }
614}
615
616/* Make A3D subsystem connections. */
617static void vortex_Vort3D_connect(vortex_t * v, int en)
618{
619 int i;
620
621// Disable AU8810 routes, since they seem to be wrong (in au8810.h).
622#ifdef CHIP_AU8810
623 return;
624#endif
625
626#if 1
627 /* Alloc Xtalk mixin resources */
628 v->mixxtlk[0] =
629 vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
630 if (v->mixxtlk[0] < 0) {
631 printk
632 ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
633 return;
634 }
635 v->mixxtlk[1] =
636 vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
637 if (v->mixxtlk[1] < 0) {
638 printk
639 ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
640 return;
641 }
642#endif
643
644 /* Connect A3D -> XTALK */
645 for (i = 0; i < 4; i++) {
646 // 2 outputs per each A3D slice.
647 vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2), ADB_XTALKIN(i));
648 vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2) + 1, ADB_XTALKIN(5 + i));
649 }
650#if 0
651 vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_EQIN(2));
652 vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_EQIN(3));
653#else
654 /* Connect XTalk -> mixer */
655 vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_MIXIN(v->mixxtlk[0]));
656 vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_MIXIN(v->mixxtlk[1]));
657 vortex_connection_mixin_mix(v, en, v->mixxtlk[0], v->mixplayb[0], 0);
658 vortex_connection_mixin_mix(v, en, v->mixxtlk[1], v->mixplayb[1], 0);
659 vortex_mix_setinputvolumebyte(v, v->mixplayb[0], v->mixxtlk[0],
660 en ? MIX_DEFIGAIN : VOL_MIN);
661 vortex_mix_setinputvolumebyte(v, v->mixplayb[1], v->mixxtlk[1],
662 en ? MIX_DEFIGAIN : VOL_MIN);
663 if (VORTEX_IS_QUAD(v)) {
664 vortex_connection_mixin_mix(v, en, v->mixxtlk[0],
665 v->mixplayb[2], 0);
666 vortex_connection_mixin_mix(v, en, v->mixxtlk[1],
667 v->mixplayb[3], 0);
668 vortex_mix_setinputvolumebyte(v, v->mixplayb[2],
669 v->mixxtlk[0],
670 en ? MIX_DEFIGAIN : VOL_MIN);
671 vortex_mix_setinputvolumebyte(v, v->mixplayb[3],
672 v->mixxtlk[1],
673 en ? MIX_DEFIGAIN : VOL_MIN);
674 }
675#endif
676}
677
678/* Initialize one single A3D source. */
679static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en)
680{
681 if (a->vortex == NULL) {
682 printk
683 ("vortex: Vort3D_InitializeSource: A3D source not initialized\n");
684 return;
685 }
686 if (en) {
687 a3dsrc_ProgramPipe(a);
688 a3dsrc_SetA3DSampleRate(a, 0x11);
689 a3dsrc_SetTimeConsts(a, HrtfTCDefault,
690 ItdTCDefault, GainTCDefault,
691 CoefTCDefault);
692 /* Remark: zero gain is muted. */
693 //a3dsrc_SetGainTarget(a,0,0);
694 //a3dsrc_SetGainCurrent(a,0,0);
695 a3dsrc_EnableA3D(a);
696 } else {
697 a3dsrc_DisableA3D(a);
698 a3dsrc_ZeroState(a);
699 }
700}
701
702/* Conversion of coordinates into 3D parameters. */
703
704static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord)
705{
706 /* FIXME: implement this. */
707
708}
709static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord)
710{
711 /* FIXME: implement this. */
712
713}
714static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right)
715{
716 /* FIXME: implement this. */
717
718}
719static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params)
720{
721 /* FIXME: implement this. */
722
723}
724
725/* ALSA control interface. */
726
727static int
728snd_vortex_a3d_hrtf_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
729{
730 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
731 uinfo->count = 6;
732 uinfo->value.integer.min = 0x00000000;
733 uinfo->value.integer.max = 0xffffffff;
734 return 0;
735}
736static int
737snd_vortex_a3d_itd_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
738{
739 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
740 uinfo->count = 2;
741 uinfo->value.integer.min = 0x00000000;
742 uinfo->value.integer.max = 0xffffffff;
743 return 0;
744}
745static int
746snd_vortex_a3d_ild_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
747{
748 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
749 uinfo->count = 2;
750 uinfo->value.integer.min = 0x00000000;
751 uinfo->value.integer.max = 0xffffffff;
752 return 0;
753}
754static int
755snd_vortex_a3d_filter_info(snd_kcontrol_t *
756 kcontrol, snd_ctl_elem_info_t * uinfo)
757{
758 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
759 uinfo->count = 4;
760 uinfo->value.integer.min = 0x00000000;
761 uinfo->value.integer.max = 0xffffffff;
762 return 0;
763}
764
765static int
766snd_vortex_a3d_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
767{
768 //a3dsrc_t *a = kcontrol->private_data;
769 /* No read yet. Would this be really useable/needed ? */
770
771 return 0;
772}
773
774static int
775snd_vortex_a3d_hrtf_put(snd_kcontrol_t *
776 kcontrol, snd_ctl_elem_value_t * ucontrol)
777{
778 a3dsrc_t *a = kcontrol->private_data;
779 int changed = 1, i;
780 int coord[6];
781 for (i = 0; i < 6; i++)
782 coord[i] = ucontrol->value.integer.value[i];
783 /* Translate orientation coordinates to a3d params. */
784 vortex_a3d_coord2hrtf(a->hrtf[0], coord);
785 vortex_a3d_coord2hrtf(a->hrtf[1], coord);
786 a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]);
787 a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]);
788 return changed;
789}
790
791static int
792snd_vortex_a3d_itd_put(snd_kcontrol_t *
793 kcontrol, snd_ctl_elem_value_t * ucontrol)
794{
795 a3dsrc_t *a = kcontrol->private_data;
796 int coord[6];
797 int i, changed = 1;
798 for (i = 0; i < 6; i++)
799 coord[i] = ucontrol->value.integer.value[i];
800 /* Translate orientation coordinates to a3d params. */
801 vortex_a3d_coord2itd(a->hrtf[0], coord);
802 vortex_a3d_coord2itd(a->hrtf[1], coord);
803 /* Inter aural time difference. */
804 a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]);
805 a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]);
806 a3dsrc_SetItdDline(a, a->dline);
807 return changed;
808}
809
810static int
811snd_vortex_a3d_ild_put(snd_kcontrol_t *
812 kcontrol, snd_ctl_elem_value_t * ucontrol)
813{
814 a3dsrc_t *a = kcontrol->private_data;
815 int changed = 1;
816 int l, r;
817 /* There may be some scale tranlation needed here. */
818 l = ucontrol->value.integer.value[0];
819 r = ucontrol->value.integer.value[1];
820 vortex_a3d_coord2ild(a->ild, l, r);
821 /* Left Right panning. */
822 a3dsrc_SetGainTarget(a, l, r);
823 a3dsrc_SetGainCurrent(a, l, r);
824 return changed;
825}
826
827static int
828snd_vortex_a3d_filter_put(snd_kcontrol_t
829 * kcontrol, snd_ctl_elem_value_t * ucontrol)
830{
831 a3dsrc_t *a = kcontrol->private_data;
832 int i, changed = 1;
833 int params[6];
834 for (i = 0; i < 6; i++)
835 params[i] = ucontrol->value.integer.value[i];
836 /* Translate generic filter params to a3d filter params. */
837 vortex_a3d_translate_filter(a->filter, params);
838 /* Atmospheric absorbtion and filtering. */
839 a3dsrc_SetAtmosTarget(a, a->filter[0],
840 a->filter[1], a->filter[2],
841 a->filter[3], a->filter[4]);
842 a3dsrc_SetAtmosCurrent(a, a->filter[0],
843 a->filter[1], a->filter[2],
844 a->filter[3], a->filter[4]);
845 return changed;
846}
847
848static snd_kcontrol_new_t vortex_a3d_kcontrol __devinitdata = {
849 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
850 .name = "Playback PCM advanced processing",
851 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
852 .info = snd_vortex_a3d_hrtf_info,
853 .get = snd_vortex_a3d_get,
854 .put = snd_vortex_a3d_hrtf_put,
855};
856
857/* Control (un)registration. */
858static int vortex_a3d_register_controls(vortex_t * vortex)
859{
860 snd_kcontrol_t *kcontrol;
861 int err, i;
862 /* HRTF controls. */
863 for (i = 0; i < NR_A3D; i++) {
864 if ((kcontrol =
865 snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL)
866 return -ENOMEM;
867 kcontrol->id.numid = CTRLID_HRTF;
868 kcontrol->info = snd_vortex_a3d_hrtf_info;
869 kcontrol->put = snd_vortex_a3d_hrtf_put;
870 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
871 return err;
872 }
873 /* ITD controls. */
874 for (i = 0; i < NR_A3D; i++) {
875 if ((kcontrol =
876 snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL)
877 return -ENOMEM;
878 kcontrol->id.numid = CTRLID_ITD;
879 kcontrol->info = snd_vortex_a3d_itd_info;
880 kcontrol->put = snd_vortex_a3d_itd_put;
881 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
882 return err;
883 }
884 /* ILD (gains) controls. */
885 for (i = 0; i < NR_A3D; i++) {
886 if ((kcontrol =
887 snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL)
888 return -ENOMEM;
889 kcontrol->id.numid = CTRLID_GAINS;
890 kcontrol->info = snd_vortex_a3d_ild_info;
891 kcontrol->put = snd_vortex_a3d_ild_put;
892 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
893 return err;
894 }
895 /* Filter controls. */
896 for (i = 0; i < NR_A3D; i++) {
897 if ((kcontrol =
898 snd_ctl_new1(&vortex_a3d_kcontrol, &vortex->a3d[i])) == NULL)
899 return -ENOMEM;
900 kcontrol->id.numid = CTRLID_FILTER;
901 kcontrol->info = snd_vortex_a3d_filter_info;
902 kcontrol->put = snd_vortex_a3d_filter_put;
903 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
904 return err;
905 }
906 return 0;
907}
908
909static void vortex_a3d_unregister_controls(vortex_t * vortex)
910{
911
912}
913
914/* End of File*/
diff --git a/sound/pci/au88x0/au88x0_a3d.h b/sound/pci/au88x0/au88x0_a3d.h
new file mode 100644
index 000000000000..0584c65bcab0
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_a3d.h
@@ -0,0 +1,123 @@
1/***************************************************************************
2 * au88x0_a3d.h
3 *
4 * Fri Jul 18 14:16:03 2003
5 * Copyright 2003 mjander
6 * mjander@users.sourceforge.net
7 ****************************************************************************/
8
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25#ifndef _AU88X0_A3D_H
26#define _AU88X0_A3D_H
27
28//#include <openal.h>
29
30#define HRTF_SZ 0x38
31#define DLINE_SZ 0x28
32
33#define CTRLID_HRTF 1
34#define CTRLID_ITD 2
35#define CTRLID_ILD 4
36#define CTRLID_FILTER 8
37#define CTRLID_GAINS 16
38
39/* 3D parameter structs */
40typedef unsigned short int a3d_Hrtf_t[HRTF_SZ];
41typedef unsigned short int a3d_ItdDline_t[DLINE_SZ];
42typedef unsigned short int a3d_atmos_t[5];
43typedef unsigned short int a3d_LRGains_t[2];
44typedef unsigned short int a3d_Itd_t[2];
45typedef unsigned short int a3d_Ild_t[2];
46
47typedef struct {
48 void *vortex; // Formerly CAsp4HwIO*, now vortex_t*.
49 unsigned int source; /* this_04 */
50 unsigned int slice; /* this_08 */
51 a3d_Hrtf_t hrtf[2];
52 a3d_Itd_t itd;
53 a3d_Ild_t ild;
54 a3d_ItdDline_t dline;
55 a3d_atmos_t filter;
56} a3dsrc_t;
57
58/* First Register bank */
59
60#define A3D_A_HrtfCurrent 0x18000 /* 56 ULONG */
61#define A3D_A_GainCurrent 0x180E0
62#define A3D_A_GainTarget 0x180E4
63#define A3D_A_A12Current 0x180E8 /* Atmospheric current. */
64#define A3D_A_A21Target 0x180EC /* Atmospheric target */
65#define A3D_A_B01Current 0x180F0 /* Atmospheric current */
66#define A3D_A_B10Target 0x180F4 /* Atmospheric target */
67#define A3D_A_B2Current 0x180F8 /* Atmospheric current */
68#define A3D_A_B2Target 0x180FC /* Atmospheric target */
69#define A3D_A_HrtfTarget 0x18100 /* 56 ULONG */
70#define A3D_A_ITDCurrent 0x181E0
71#define A3D_A_ITDTarget 0x181E4
72#define A3D_A_HrtfDelayLine 0x181E8 /* 56 ULONG */
73#define A3D_A_ITDDelayLine 0x182C8 /* 40/45 ULONG */
74#define A3D_A_HrtfTrackTC 0x1837C /* Time Constants */
75#define A3D_A_GainTrackTC 0x18380
76#define A3D_A_CoeffTrackTC 0x18384
77#define A3D_A_ITDTrackTC 0x18388
78#define A3D_A_x1 0x1838C
79#define A3D_A_x2 0x18390
80#define A3D_A_y1 0x18394
81#define A3D_A_y2 0x18398
82#define A3D_A_HrtfOutL 0x1839C
83#define A3D_A_HrtfOutR 0x183A0
84#define A3D_A_TAIL 0x183A4
85
86/* Second register bank */
87#define A3D_B_HrtfCurrent 0x19000 /* 56 ULONG */
88#define A3D_B_GainCurrent 0x190E0
89#define A3D_B_GainTarget 0x190E4
90#define A3D_B_A12Current 0x190E8
91#define A3D_B_A21Target 0x190EC
92#define A3D_B_B01Current 0x190F0
93#define A3D_B_B10Target 0x190F4
94#define A3D_B_B2Current 0x190F8
95#define A3D_B_B2Target 0x190FC
96#define A3D_B_HrtfTarget 0x19100 /* 56 ULONG */
97#define A3D_B_ITDCurrent 0x191E0
98#define A3D_B_ITDTarget 0x191E4
99#define A3D_B_HrtfDelayLine 0x191E8 /* 56 ULONG */
100#define A3D_B_TAIL 0x192C8
101
102/* There are 4 slices, 4 a3d each = 16 a3d sources. */
103#define A3D_SLICE_BANK_A 0x18000 /* 4 sources */
104#define A3D_SLICE_BANK_B 0x19000 /* 4 sources */
105#define A3D_SLICE_VDBDest 0x19C00 /* 8 ULONG */
106#define A3D_SLICE_VDBSource 0x19C20 /* 4 ULONG */
107#define A3D_SLICE_ABReg 0x19C30
108#define A3D_SLICE_CReg 0x19C34
109#define A3D_SLICE_Control 0x19C38
110#define A3D_SLICE_DebugReserved 0x19C3c /* Dangerous! */
111#define A3D_SLICE_Pointers 0x19C40
112#define A3D_SLICE_TAIL 0x1A000
113
114// Slice size: 0x2000
115// Source size: 0x3A4, 0x2C8
116
117/* Address generator macro. */
118#define a3d_addrA(slice,source,reg) (((slice)<<0xd)+((source)*0x3A4)+(reg))
119#define a3d_addrB(slice,source,reg) (((slice)<<0xd)+((source)*0x2C8)+(reg))
120#define a3d_addrS(slice,reg) (((slice)<<0xd)+(reg))
121//#define a3d_addr(slice,source,reg) (((reg)>=0x19000) ? a3d_addr2((slice),(source),(reg)) : a3d_addr1((slice),(source),(reg)))
122
123#endif /* _AU88X0_A3D_H */
diff --git a/sound/pci/au88x0/au88x0_a3ddata.c b/sound/pci/au88x0/au88x0_a3ddata.c
new file mode 100644
index 000000000000..6fab4bba5a05
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_a3ddata.c
@@ -0,0 +1,91 @@
1/***************************************************************************
2 * au88x0_a3ddata.c
3 *
4 * Wed Nov 19 21:11:32 2003
5 * Copyright 2003 mjander
6 * mjander@users.sourceforge.org
7 ****************************************************************************/
8
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25/* Constant initializer values. */
26
27static const a3d_Hrtf_t A3dHrirZeros = {
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29 0, 0, 0,
30 0, 0, 0,
31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32 0, 0, 0,
33 0, 0, 0
34};
35
36static const a3d_Hrtf_t A3dHrirImpulse = {
37 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38 0, 0, 0,
39 0, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
41 0, 0, 0,
42 0, 0, 0
43};
44
45static const a3d_Hrtf_t A3dHrirOnes = {
46 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
47 0x7fff,
48 0x7fff,
49 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
50 0x7fff,
51 0x7fff,
52 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
53 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
54 0x7fff,
55 0x7fff,
56 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
57 0x7fff,
58 0x7fff,
59 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff
60};
61
62static const a3d_Hrtf_t A3dHrirSatTest = {
63 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
64 0x7fff,
65 0x7fff,
66 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
67 0x8001,
68 0x8001,
69 0x7fff, 0x0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
72};
73
74static const a3d_Hrtf_t A3dHrirDImpulse = {
75 0, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76 0, 0, 0,
77 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0,
80 0, 0, 0
81};
82
83static const a3d_ItdDline_t A3dItdDlineZeros = {
84 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
86};
87
88static short const GainTCDefault = 0x300;
89static short const ItdTCDefault = 0x0C8;
90static short const HrtfTCDefault = 0x147;
91static short const CoefTCDefault = 0x300;
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
new file mode 100644
index 000000000000..f0eda4bbbb39
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -0,0 +1,2837 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17/*
18 Vortex core low level functions.
19
20 Author: Manuel Jander (mjander@users.sourceforge.cl)
21 These functions are mainly the result of translations made
22 from the original disassembly of the au88x0 binary drivers,
23 written by Aureal before they went down.
24 Many thanks to the Jeff Muizelaar, Kester Maddock, and whoever
25 contributed to the OpenVortex project.
26 The author of this file, put the few available pieces together
27 and translated the rest of the riddle (Mix, Src and connection stuff).
28 Some things are still to be discovered, and their meanings are unclear.
29
30 Some of these functions aren't intended to be really used, rather
31 to help to understand how does the AU88X0 chips work. Keep them in, because
32 they could be used somewhere in the future.
33
34 This code hasn't been tested or proof read thoroughly. If you wanna help,
35 take a look at the AU88X0 assembly and check if this matches.
36 Functions tested ok so far are (they show the desired effect
37 at least):
38 vortex_routes(); (1 bug fixed).
39 vortex_adb_addroute();
40 vortex_adb_addroutes();
41 vortex_connect_codecplay();
42 vortex_src_flushbuffers();
43 vortex_adbdma_setmode(); note: still some unknown arguments!
44 vortex_adbdma_startfifo();
45 vortex_adbdma_stopfifo();
46 vortex_fifo_setadbctrl(); note: still some unknown arguments!
47 vortex_mix_setinputvolumebyte();
48 vortex_mix_enableinput();
49 vortex_mixer_addWTD(); (fixed)
50 vortex_connection_adbdma_src_src();
51 vortex_connection_adbdma_src();
52 vortex_src_change_convratio();
53 vortex_src_addWTD(); (fixed)
54
55 History:
56
57 01-03-2003 First revision.
58 01-21-2003 Some bug fixes.
59 17-02-2003 many bugfixes after a big versioning mess.
60 18-02-2003 JAAAAAHHHUUUUUU!!!! The mixer works !! I'm just so happy !
61 (2 hours later...) I cant believe it! Im really lucky today.
62 Now the SRC is working too! Yeah! XMMS works !
63 20-02-2003 First steps into the ALSA world.
64 28-02-2003 As my birthday present, i discovered how the DMA buffer pages really
65 work :-). It was all wrong.
66 12-03-2003 ALSA driver starts working (2 channels).
67 16-03-2003 More srcblock_setupchannel discoveries.
68 12-04-2003 AU8830 playback support. Recording in the works.
69 17-04-2003 vortex_route() and vortex_routes() bug fixes. AU8830 recording
70 works now, but chipn' dale effect is still there.
71 16-05-2003 SrcSetupChannel cleanup. Moved the Src setup stuff entirely
72 into au88x0_pcm.c .
73 06-06-2003 Buffer shifter bugfix. Mixer volume fix.
74 07-12-2003 A3D routing finally fixed. Believed to be OK.
75 25-03-2004 Many thanks to Claudia, for such valuable bug reports.
76
77*/
78
79#include "au88x0.h"
80#include "au88x0_a3d.h"
81#include <linux/delay.h>
82
83/* MIXER (CAsp4Mix.s and CAsp4Mixer.s) */
84
85// FIXME: get rid of this.
86static int mchannels[NR_MIXIN];
87static int rampchs[NR_MIXIN];
88
89static void vortex_mixer_en_sr(vortex_t * vortex, int channel)
90{
91 hwwrite(vortex->mmio, VORTEX_MIXER_SR,
92 hwread(vortex->mmio, VORTEX_MIXER_SR) | (0x1 << channel));
93}
94static void vortex_mixer_dis_sr(vortex_t * vortex, int channel)
95{
96 hwwrite(vortex->mmio, VORTEX_MIXER_SR,
97 hwread(vortex->mmio, VORTEX_MIXER_SR) & ~(0x1 << channel));
98}
99
100#if 0
101static void
102vortex_mix_muteinputgain(vortex_t * vortex, unsigned char mix,
103 unsigned char channel)
104{
105 hwwrite(vortex->mmio, VORTEX_MIX_INVOL_A + ((mix << 5) + channel),
106 0x80);
107 hwwrite(vortex->mmio, VORTEX_MIX_INVOL_B + ((mix << 5) + channel),
108 0x80);
109}
110
111static int vortex_mix_getvolume(vortex_t * vortex, unsigned char mix)
112{
113 int a;
114 a = hwread(vortex->mmio, VORTEX_MIX_VOL_A + (mix << 2)) & 0xff;
115 //FP2LinearFrac(a);
116 return (a);
117}
118
119static int
120vortex_mix_getinputvolume(vortex_t * vortex, unsigned char mix,
121 int channel, int *vol)
122{
123 int a;
124 if (!(mchannels[mix] & (1 << channel)))
125 return 0;
126 a = hwread(vortex->mmio,
127 VORTEX_MIX_INVOL_A + (((mix << 5) + channel) << 2));
128 /*
129 if (rampchs[mix] == 0)
130 a = FP2LinearFrac(a);
131 else
132 a = FP2LinearFracWT(a);
133 */
134 *vol = a;
135 return (0);
136}
137
138static unsigned int vortex_mix_boost6db(unsigned char vol)
139{
140 return (vol + 8); /* WOW! what a complex function! */
141}
142
143static void vortex_mix_rampvolume(vortex_t * vortex, int mix)
144{
145 int ch;
146 char a;
147 // This function is intended for ramping down only (see vortex_disableinput()).
148 for (ch = 0; ch < 0x20; ch++) {
149 if (((1 << ch) & rampchs[mix]) == 0)
150 continue;
151 a = hwread(vortex->mmio,
152 VORTEX_MIX_INVOL_B + (((mix << 5) + ch) << 2));
153 if (a > -126) {
154 a -= 2;
155 hwwrite(vortex->mmio,
156 VORTEX_MIX_INVOL_A +
157 (((mix << 5) + ch) << 2), a);
158 hwwrite(vortex->mmio,
159 VORTEX_MIX_INVOL_B +
160 (((mix << 5) + ch) << 2), a);
161 } else
162 vortex_mix_killinput(vortex, mix, ch);
163 }
164}
165
166static int
167vortex_mix_getenablebit(vortex_t * vortex, unsigned char mix, int mixin)
168{
169 int addr, temp;
170 if (mixin >= 0)
171 addr = mixin;
172 else
173 addr = mixin + 3;
174 addr = ((mix << 3) + (addr >> 2)) << 2;
175 temp = hwread(vortex->mmio, VORTEX_MIX_ENIN + addr);
176 return ((temp >> (mixin & 3)) & 1);
177}
178#endif
179static void
180vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix,
181 unsigned char vol)
182{
183 int temp;
184 hwwrite(vortex->mmio, VORTEX_MIX_VOL_A + (mix << 2), vol);
185 if (1) { /*if (this_10) */
186 temp = hwread(vortex->mmio, VORTEX_MIX_VOL_B + (mix << 2));
187 if ((temp != 0x80) || (vol == 0x80))
188 return;
189 }
190 hwwrite(vortex->mmio, VORTEX_MIX_VOL_B + (mix << 2), vol);
191}
192
193static void
194vortex_mix_setinputvolumebyte(vortex_t * vortex, unsigned char mix,
195 int mixin, unsigned char vol)
196{
197 int temp;
198
199 hwwrite(vortex->mmio,
200 VORTEX_MIX_INVOL_A + (((mix << 5) + mixin) << 2), vol);
201 if (1) { /* this_10, initialized to 1. */
202 temp =
203 hwread(vortex->mmio,
204 VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2));
205 if ((temp != 0x80) || (vol == 0x80))
206 return;
207 }
208 hwwrite(vortex->mmio,
209 VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2), vol);
210}
211
212static void
213vortex_mix_setenablebit(vortex_t * vortex, unsigned char mix, int mixin, int en)
214{
215 int temp, addr;
216
217 if (mixin < 0)
218 addr = (mixin + 3);
219 else
220 addr = mixin;
221 addr = ((mix << 3) + (addr >> 2)) << 2;
222 temp = hwread(vortex->mmio, VORTEX_MIX_ENIN + addr);
223 if (en)
224 temp |= (1 << (mixin & 3));
225 else
226 temp &= ~(1 << (mixin & 3));
227 /* Mute input. Astatic void crackling? */
228 hwwrite(vortex->mmio,
229 VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2), 0x80);
230 /* Looks like clear buffer. */
231 hwwrite(vortex->mmio, VORTEX_MIX_SMP + (mixin << 2), 0x0);
232 hwwrite(vortex->mmio, VORTEX_MIX_SMP + 4 + (mixin << 2), 0x0);
233 /* Write enable bit. */
234 hwwrite(vortex->mmio, VORTEX_MIX_ENIN + addr, temp);
235}
236
237static void
238vortex_mix_killinput(vortex_t * vortex, unsigned char mix, int mixin)
239{
240 rampchs[mix] &= ~(1 << mixin);
241 vortex_mix_setinputvolumebyte(vortex, mix, mixin, 0x80);
242 mchannels[mix] &= ~(1 << mixin);
243 vortex_mix_setenablebit(vortex, mix, mixin, 0);
244}
245
246static void
247vortex_mix_enableinput(vortex_t * vortex, unsigned char mix, int mixin)
248{
249 vortex_mix_killinput(vortex, mix, mixin);
250 if ((mchannels[mix] & (1 << mixin)) == 0) {
251 vortex_mix_setinputvolumebyte(vortex, mix, mixin, 0x80); /*0x80 : mute */
252 mchannels[mix] |= (1 << mixin);
253 }
254 vortex_mix_setenablebit(vortex, mix, mixin, 1);
255}
256
257static void
258vortex_mix_disableinput(vortex_t * vortex, unsigned char mix, int channel,
259 int ramp)
260{
261 if (ramp) {
262 rampchs[mix] |= (1 << channel);
263 // Register callback.
264 //vortex_mix_startrampvolume(vortex);
265 vortex_mix_killinput(vortex, mix, channel);
266 } else
267 vortex_mix_killinput(vortex, mix, channel);
268}
269
270static int
271vortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
272{
273 int temp, lifeboat = 0, prev;
274
275 temp = hwread(vortex->mmio, VORTEX_MIXER_SR);
276 if ((temp & (1 << ch)) == 0) {
277 hwwrite(vortex->mmio, VORTEX_MIXER_CHNBASE + (ch << 2), mix);
278 vortex_mixer_en_sr(vortex, ch);
279 return 1;
280 }
281 prev = VORTEX_MIXER_CHNBASE + (ch << 2);
282 temp = hwread(vortex->mmio, prev);
283 while (temp & 0x10) {
284 prev = VORTEX_MIXER_RTBASE + ((temp & 0xf) << 2);
285 temp = hwread(vortex->mmio, prev);
286 //printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp);
287 if ((++lifeboat) > 0xf) {
288 printk(KERN_ERR
289 "vortex_mixer_addWTD: lifeboat overflow\n");
290 return 0;
291 }
292 }
293 hwwrite(vortex->mmio, VORTEX_MIXER_RTBASE + ((temp & 0xf) << 2), mix);
294 hwwrite(vortex->mmio, prev, (temp & 0xf) | 0x10);
295 return 1;
296}
297
298static int
299vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
300{
301 int esp14 = -1, esp18, eax, ebx, edx, ebp, esi = 0;
302 //int esp1f=edi(while)=src, esp10=ch;
303
304 eax = hwread(vortex->mmio, VORTEX_MIXER_SR);
305 if (((1 << ch) & eax) == 0) {
306 printk(KERN_ERR "mix ALARM %x\n", eax);
307 return 0;
308 }
309 ebp = VORTEX_MIXER_CHNBASE + (ch << 2);
310 esp18 = hwread(vortex->mmio, ebp);
311 if (esp18 & 0x10) {
312 ebx = (esp18 & 0xf);
313 if (mix == ebx) {
314 ebx = VORTEX_MIXER_RTBASE + (mix << 2);
315 edx = hwread(vortex->mmio, ebx);
316 //7b60
317 hwwrite(vortex->mmio, ebp, edx);
318 hwwrite(vortex->mmio, ebx, 0);
319 } else {
320 //7ad3
321 edx =
322 hwread(vortex->mmio,
323 VORTEX_MIXER_RTBASE + (ebx << 2));
324 //printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
325 while ((edx & 0xf) != mix) {
326 if ((esi) > 0xf) {
327 printk(KERN_ERR
328 "vortex: mixdelWTD: error lifeboat overflow\n");
329 return 0;
330 }
331 esp14 = ebx;
332 ebx = edx & 0xf;
333 ebp = ebx << 2;
334 edx =
335 hwread(vortex->mmio,
336 VORTEX_MIXER_RTBASE + ebp);
337 //printk(KERN_INFO "vortex: mixdelWTD: while addr=%x, val=%x\n", ebp, edx);
338 esi++;
339 }
340 //7b30
341 ebp = ebx << 2;
342 if (edx & 0x10) { /* Delete entry in between others */
343 ebx = VORTEX_MIXER_RTBASE + ((edx & 0xf) << 2);
344 edx = hwread(vortex->mmio, ebx);
345 //7b60
346 hwwrite(vortex->mmio,
347 VORTEX_MIXER_RTBASE + ebp, edx);
348 hwwrite(vortex->mmio, ebx, 0);
349 //printk(KERN_INFO "vortex mixdelWTD between addr= 0x%x, val= 0x%x\n", ebp, edx);
350 } else { /* Delete last entry */
351 //7b83
352 if (esp14 == -1)
353 hwwrite(vortex->mmio,
354 VORTEX_MIXER_CHNBASE +
355 (ch << 2), esp18 & 0xef);
356 else {
357 ebx = (0xffffffe0 & edx) | (0xf & ebx);
358 hwwrite(vortex->mmio,
359 VORTEX_MIXER_RTBASE +
360 (esp14 << 2), ebx);
361 //printk(KERN_INFO "vortex mixdelWTD last addr= 0x%x, val= 0x%x\n", esp14, ebx);
362 }
363 hwwrite(vortex->mmio,
364 VORTEX_MIXER_RTBASE + ebp, 0);
365 return 1;
366 }
367 }
368 } else {
369 //printk(KERN_INFO "removed last mix\n");
370 //7be0
371 vortex_mixer_dis_sr(vortex, ch);
372 hwwrite(vortex->mmio, ebp, 0);
373 }
374 return 1;
375}
376
377static void vortex_mixer_init(vortex_t * vortex)
378{
379 unsigned long addr;
380 int x;
381
382 // FIXME: get rid of this crap.
383 memset(mchannels, 0, NR_MIXOUT * sizeof(int));
384 memset(rampchs, 0, NR_MIXOUT * sizeof(int));
385
386 addr = VORTEX_MIX_SMP + 0x17c;
387 for (x = 0x5f; x >= 0; x--) {
388 hwwrite(vortex->mmio, addr, 0);
389 addr -= 4;
390 }
391 addr = VORTEX_MIX_ENIN + 0x1fc;
392 for (x = 0x7f; x >= 0; x--) {
393 hwwrite(vortex->mmio, addr, 0);
394 addr -= 4;
395 }
396 addr = VORTEX_MIX_SMP + 0x17c;
397 for (x = 0x5f; x >= 0; x--) {
398 hwwrite(vortex->mmio, addr, 0);
399 addr -= 4;
400 }
401 addr = VORTEX_MIX_INVOL_A + 0x7fc;
402 for (x = 0x1ff; x >= 0; x--) {
403 hwwrite(vortex->mmio, addr, 0x80);
404 addr -= 4;
405 }
406 addr = VORTEX_MIX_VOL_A + 0x3c;
407 for (x = 0xf; x >= 0; x--) {
408 hwwrite(vortex->mmio, addr, 0x80);
409 addr -= 4;
410 }
411 addr = VORTEX_MIX_INVOL_B + 0x7fc;
412 for (x = 0x1ff; x >= 0; x--) {
413 hwwrite(vortex->mmio, addr, 0x80);
414 addr -= 4;
415 }
416 addr = VORTEX_MIX_VOL_B + 0x3c;
417 for (x = 0xf; x >= 0; x--) {
418 hwwrite(vortex->mmio, addr, 0x80);
419 addr -= 4;
420 }
421 addr = VORTEX_MIXER_RTBASE + (MIXER_RTBASE_SIZE - 1) * 4;
422 for (x = (MIXER_RTBASE_SIZE - 1); x >= 0; x--) {
423 hwwrite(vortex->mmio, addr, 0x0);
424 addr -= 4;
425 }
426 hwwrite(vortex->mmio, VORTEX_MIXER_SR, 0);
427
428 /* Set clipping ceiling (this may be all wrong). */
429 /*
430 for (x = 0; x > 0x80; x++) {
431 hwwrite(vortex->mmio, VORTEX_MIXER_CLIP + (x << 2), 0x3ffff);
432 }
433 */
434 /*
435 call CAsp4Mix__Initialize_CAsp4HwIO____CAsp4Mixer____
436 Register ISR callback for volume smooth fade out.
437 Maybe this avoids clicks when press "stop" ?
438 */
439}
440
441/* SRC (CAsp4Src.s and CAsp4SrcBlock) */
442
443static void vortex_src_en_sr(vortex_t * vortex, int channel)
444{
445 hwwrite(vortex->mmio, VORTEX_SRCBLOCK_SR,
446 hwread(vortex->mmio, VORTEX_SRCBLOCK_SR) | (0x1 << channel));
447}
448
449static void vortex_src_dis_sr(vortex_t * vortex, int channel)
450{
451 hwwrite(vortex->mmio, VORTEX_SRCBLOCK_SR,
452 hwread(vortex->mmio, VORTEX_SRCBLOCK_SR) & ~(0x1 << channel));
453}
454
455static void vortex_src_flushbuffers(vortex_t * vortex, unsigned char src)
456{
457 int i;
458
459 for (i = 0x1f; i >= 0; i--)
460 hwwrite(vortex->mmio,
461 VORTEX_SRC_DATA0 + (src << 7) + (i << 2), 0);
462 hwwrite(vortex->mmio, VORTEX_SRC_DATA + (src << 3), 0);
463 hwwrite(vortex->mmio, VORTEX_SRC_DATA + (src << 3) + 4, 0);
464}
465
466static void vortex_src_cleardrift(vortex_t * vortex, unsigned char src)
467{
468 hwwrite(vortex->mmio, VORTEX_SRC_DRIFT0 + (src << 2), 0);
469 hwwrite(vortex->mmio, VORTEX_SRC_DRIFT1 + (src << 2), 0);
470 hwwrite(vortex->mmio, VORTEX_SRC_DRIFT2 + (src << 2), 1);
471}
472
473static void
474vortex_src_set_throttlesource(vortex_t * vortex, unsigned char src, int en)
475{
476 int temp;
477
478 temp = hwread(vortex->mmio, VORTEX_SRC_SOURCE);
479 if (en)
480 temp |= 1 << src;
481 else
482 temp &= ~(1 << src);
483 hwwrite(vortex->mmio, VORTEX_SRC_SOURCE, temp);
484}
485
486static int
487vortex_src_persist_convratio(vortex_t * vortex, unsigned char src, int ratio)
488{
489 int temp, lifeboat = 0;
490
491 do {
492 hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio);
493 temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2));
494 if ((++lifeboat) > 0x9) {
495 printk(KERN_ERR "Vortex: Src cvr fail\n");
496 break;
497 }
498 }
499 while (temp != ratio);
500 return temp;
501}
502
503#if 0
504static void vortex_src_slowlock(vortex_t * vortex, unsigned char src)
505{
506 int temp;
507
508 hwwrite(vortex->mmio, VORTEX_SRC_DRIFT2 + (src << 2), 1);
509 hwwrite(vortex->mmio, VORTEX_SRC_DRIFT0 + (src << 2), 0);
510 temp = hwread(vortex->mmio, VORTEX_SRC_U0 + (src << 2));
511 if (temp & 0x200)
512 hwwrite(vortex->mmio, VORTEX_SRC_U0 + (src << 2),
513 temp & ~0x200L);
514}
515
516static void
517vortex_src_change_convratio(vortex_t * vortex, unsigned char src, int ratio)
518{
519 int temp, a;
520
521 if ((ratio & 0x10000) && (ratio != 0x10000)) {
522 if (ratio & 0x3fff)
523 a = (0x11 - ((ratio >> 0xe) & 0x3)) - 1;
524 else
525 a = (0x11 - ((ratio >> 0xe) & 0x3)) - 2;
526 } else
527 a = 0xc;
528 temp = hwread(vortex->mmio, VORTEX_SRC_U0 + (src << 2));
529 if (((temp >> 4) & 0xf) != a)
530 hwwrite(vortex->mmio, VORTEX_SRC_U0 + (src << 2),
531 (temp & 0xf) | ((a & 0xf) << 4));
532
533 vortex_src_persist_convratio(vortex, src, ratio);
534}
535
536static int
537vortex_src_checkratio(vortex_t * vortex, unsigned char src,
538 unsigned int desired_ratio)
539{
540 int hw_ratio, lifeboat = 0;
541
542 hw_ratio = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2));
543
544 while (hw_ratio != desired_ratio) {
545 hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), desired_ratio);
546
547 if ((lifeboat++) > 15) {
548 printk(KERN_ERR "Vortex: could not set src-%d from %d to %d\n",
549 src, hw_ratio, desired_ratio);
550 break;
551 }
552 }
553
554 return hw_ratio;
555}
556
557#endif
558/*
559 Objective: Set samplerate for given SRC module.
560 Arguments:
561 card: pointer to vortex_t strcut.
562 src: Integer index of the SRC module.
563 cr: Current sample rate conversion factor.
564 b: unknown 16 bit value.
565 sweep: Enable Samplerate fade from cr toward tr flag.
566 dirplay: 1: playback, 0: recording.
567 sl: Slow Lock flag.
568 tr: Target samplerate conversion.
569 thsource: Throttle source flag (no idea what that means).
570*/
571static void vortex_src_setupchannel(vortex_t * card, unsigned char src,
572 unsigned int cr, unsigned int b, int sweep, int d,
573 int dirplay, int sl, unsigned int tr, int thsource)
574{
575 // noplayback: d=2,4,7,0xa,0xb when using first 2 src's.
576 // c: enables pitch sweep.
577 // looks like g is c related. Maybe g is a sweep parameter ?
578 // g = cvr
579 // dirplay: 0 = recording, 1 = playback
580 // d = src hw index.
581
582 int esi, ebp = 0, esp10;
583
584 vortex_src_flushbuffers(card, src);
585
586 if (sweep) {
587 if ((tr & 0x10000) && (tr != 0x10000)) {
588 tr = 0;
589 esi = 0x7;
590 } else {
591 if ((((short)tr) < 0) && (tr != 0x8000)) {
592 tr = 0;
593 esi = 0x8;
594 } else {
595 tr = 1;
596 esi = 0xc;
597 }
598 }
599 } else {
600 if ((cr & 0x10000) && (cr != 0x10000)) {
601 tr = 0; /*ebx = 0 */
602 esi = 0x11 - ((cr >> 0xe) & 7);
603 if (cr & 0x3fff)
604 esi -= 1;
605 else
606 esi -= 2;
607 } else {
608 tr = 1;
609 esi = 0xc;
610 }
611 }
612 vortex_src_cleardrift(card, src);
613 vortex_src_set_throttlesource(card, src, thsource);
614
615 if ((dirplay == 0) && (sweep == 0)) {
616 if (tr)
617 esp10 = 0xf;
618 else
619 esp10 = 0xc;
620 ebp = 0;
621 } else {
622 if (tr)
623 ebp = 0xf;
624 else
625 ebp = 0xc;
626 esp10 = 0;
627 }
628 hwwrite(card->mmio, VORTEX_SRC_U0 + (src << 2),
629 (sl << 0x9) | (sweep << 0x8) | ((esi & 0xf) << 4) | d);
630 /* 0xc0 esi=0xc c=f=0 d=0 */
631 vortex_src_persist_convratio(card, src, cr);
632 hwwrite(card->mmio, VORTEX_SRC_U1 + (src << 2), b & 0xffff);
633 /* 0 b=0 */
634 hwwrite(card->mmio, VORTEX_SRC_U2 + (src << 2),
635 (tr << 0x11) | (dirplay << 0x10) | (ebp << 0x8) | esp10);
636 /* 0x30f00 e=g=1 esp10=0 ebp=f */
637 //printk(KERN_INFO "vortex: SRC %d, d=0x%x, esi=0x%x, esp10=0x%x, ebp=0x%x\n", src, d, esi, esp10, ebp);
638}
639
640static void vortex_srcblock_init(vortex_t * vortex)
641{
642 unsigned long addr;
643 int x;
644 hwwrite(vortex->mmio, VORTEX_SRC_SOURCESIZE, 0x1ff);
645 /*
646 for (x=0; x<0x10; x++) {
647 vortex_src_init(&vortex_src[x], x);
648 }
649 */
650 //addr = 0xcc3c;
651 //addr = 0x26c3c;
652 addr = VORTEX_SRC_RTBASE + 0x3c;
653 for (x = 0xf; x >= 0; x--) {
654 hwwrite(vortex->mmio, addr, 0);
655 addr -= 4;
656 }
657 //addr = 0xcc94;
658 //addr = 0x26c94;
659 addr = VORTEX_SRC_CHNBASE + 0x54;
660 for (x = 0x15; x >= 0; x--) {
661 hwwrite(vortex->mmio, addr, 0);
662 addr -= 4;
663 }
664}
665
666static int
667vortex_src_addWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
668{
669 int temp, lifeboat = 0, prev;
670 // esp13 = src
671
672 temp = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR);
673 if ((temp & (1 << ch)) == 0) {
674 hwwrite(vortex->mmio, VORTEX_SRC_CHNBASE + (ch << 2), src);
675 vortex_src_en_sr(vortex, ch);
676 return 1;
677 }
678 prev = VORTEX_SRC_CHNBASE + (ch << 2); /*ebp */
679 temp = hwread(vortex->mmio, prev);
680 //while (temp & NR_SRC) {
681 while (temp & 0x10) {
682 prev = VORTEX_SRC_RTBASE + ((temp & 0xf) << 2); /*esp12 */
683 //prev = VORTEX_SRC_RTBASE + ((temp & (NR_SRC-1)) << 2); /*esp12*/
684 temp = hwread(vortex->mmio, prev);
685 //printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp);
686 if ((++lifeboat) > 0xf) {
687 printk(KERN_ERR
688 "vortex_src_addWTD: lifeboat overflow\n");
689 return 0;
690 }
691 }
692 hwwrite(vortex->mmio, VORTEX_SRC_RTBASE + ((temp & 0xf) << 2), src);
693 //hwwrite(vortex->mmio, prev, (temp & (NR_SRC-1)) | NR_SRC);
694 hwwrite(vortex->mmio, prev, (temp & 0xf) | 0x10);
695 return 1;
696}
697
698static int
699vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
700{
701 int esp14 = -1, esp18, eax, ebx, edx, ebp, esi = 0;
702 //int esp1f=edi(while)=src, esp10=ch;
703
704 eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR);
705 if (((1 << ch) & eax) == 0) {
706 printk(KERN_ERR "src alarm\n");
707 return 0;
708 }
709 ebp = VORTEX_SRC_CHNBASE + (ch << 2);
710 esp18 = hwread(vortex->mmio, ebp);
711 if (esp18 & 0x10) {
712 ebx = (esp18 & 0xf);
713 if (src == ebx) {
714 ebx = VORTEX_SRC_RTBASE + (src << 2);
715 edx = hwread(vortex->mmio, ebx);
716 //7b60
717 hwwrite(vortex->mmio, ebp, edx);
718 hwwrite(vortex->mmio, ebx, 0);
719 } else {
720 //7ad3
721 edx =
722 hwread(vortex->mmio,
723 VORTEX_SRC_RTBASE + (ebx << 2));
724 //printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
725 while ((edx & 0xf) != src) {
726 if ((esi) > 0xf) {
727 printk
728 ("vortex: srcdelWTD: error, lifeboat overflow\n");
729 return 0;
730 }
731 esp14 = ebx;
732 ebx = edx & 0xf;
733 ebp = ebx << 2;
734 edx =
735 hwread(vortex->mmio,
736 VORTEX_SRC_RTBASE + ebp);
737 //printk(KERN_INFO "vortex: srcdelWTD: while addr=%x, val=%x\n", ebp, edx);
738 esi++;
739 }
740 //7b30
741 ebp = ebx << 2;
742 if (edx & 0x10) { /* Delete entry in between others */
743 ebx = VORTEX_SRC_RTBASE + ((edx & 0xf) << 2);
744 edx = hwread(vortex->mmio, ebx);
745 //7b60
746 hwwrite(vortex->mmio,
747 VORTEX_SRC_RTBASE + ebp, edx);
748 hwwrite(vortex->mmio, ebx, 0);
749 //printk(KERN_INFO "vortex srcdelWTD between addr= 0x%x, val= 0x%x\n", ebp, edx);
750 } else { /* Delete last entry */
751 //7b83
752 if (esp14 == -1)
753 hwwrite(vortex->mmio,
754 VORTEX_SRC_CHNBASE +
755 (ch << 2), esp18 & 0xef);
756 else {
757 ebx = (0xffffffe0 & edx) | (0xf & ebx);
758 hwwrite(vortex->mmio,
759 VORTEX_SRC_RTBASE +
760 (esp14 << 2), ebx);
761 //printk(KERN_INFO"vortex srcdelWTD last addr= 0x%x, val= 0x%x\n", esp14, ebx);
762 }
763 hwwrite(vortex->mmio,
764 VORTEX_SRC_RTBASE + ebp, 0);
765 return 1;
766 }
767 }
768 } else {
769 //7be0
770 vortex_src_dis_sr(vortex, ch);
771 hwwrite(vortex->mmio, ebp, 0);
772 }
773 return 1;
774}
775
776 /*FIFO*/
777
778static void
779vortex_fifo_clearadbdata(vortex_t * vortex, int fifo, int x)
780{
781 for (x--; x >= 0; x--)
782 hwwrite(vortex->mmio,
783 VORTEX_FIFO_ADBDATA +
784 (((fifo << FIFO_SIZE_BITS) + x) << 2), 0);
785}
786
787#if 0
788static void vortex_fifo_adbinitialize(vortex_t * vortex, int fifo, int j)
789{
790 vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE);
791#ifdef CHIP_AU8820
792 hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2),
793 (FIFO_U1 | ((j & FIFO_MASK) << 0xb)));
794#else
795 hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2),
796 (FIFO_U1 | ((j & FIFO_MASK) << 0xc)));
797#endif
798}
799#endif
800static void vortex_fifo_setadbvalid(vortex_t * vortex, int fifo, int en)
801{
802 hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2),
803 (hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2)) &
804 0xffffffef) | ((1 & en) << 4) | FIFO_U1);
805}
806
807static void
808vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int b, int priority,
809 int empty, int valid, int f)
810{
811 int temp, lifeboat = 0;
812 //int this_8[NR_ADB] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* position */
813 int this_4 = 0x2;
814 /* f seems priority related.
815 * CAsp4AdbDma::SetPriority is the only place that calls SetAdbCtrl with f set to 1
816 * every where else it is set to 0. It seems, however, that CAsp4AdbDma::SetPriority
817 * is never called, thus the f related bits remain a mystery for now.
818 */
819 do {
820 temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2));
821 if (lifeboat++ > 0xbb8) {
822 printk(KERN_ERR
823 "Vortex: vortex_fifo_setadbctrl fail\n");
824 break;
825 }
826 }
827 while (temp & FIFO_RDONLY);
828
829 // AU8830 semes to take some special care about fifo content (data).
830 // But i'm just to lazy to translate that :)
831 if (valid) {
832 if ((temp & FIFO_VALID) == 0) {
833 //this_8[fifo] = 0;
834 vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE); // this_4
835#ifdef CHIP_AU8820
836 temp = (this_4 & 0x1f) << 0xb;
837#else
838 temp = (this_4 & 0x3f) << 0xc;
839#endif
840 temp = (temp & 0xfffffffd) | ((b & 1) << 1);
841 temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
842 temp = (temp & 0xffffffef) | ((valid & 1) << 4);
843 temp |= FIFO_U1;
844 temp = (temp & 0xffffffdf) | ((empty & 1) << 5);
845#ifdef CHIP_AU8820
846 temp = (temp & 0xfffbffff) | ((f & 1) << 0x12);
847#endif
848#ifdef CHIP_AU8830
849 temp = (temp & 0xf7ffffff) | ((f & 1) << 0x1b);
850 temp = (temp & 0xefffffff) | ((f & 1) << 0x1c);
851#endif
852#ifdef CHIP_AU8810
853 temp = (temp & 0xfeffffff) | ((f & 1) << 0x18);
854 temp = (temp & 0xfdffffff) | ((f & 1) << 0x19);
855#endif
856 }
857 } else {
858 if (temp & FIFO_VALID) {
859#ifdef CHIP_AU8820
860 temp = ((f & 1) << 0x12) | (temp & 0xfffbffef);
861#endif
862#ifdef CHIP_AU8830
863 temp =
864 ((f & 1) << 0x1b) | (temp & 0xe7ffffef) | FIFO_BITS;
865#endif
866#ifdef CHIP_AU8810
867 temp =
868 ((f & 1) << 0x18) | (temp & 0xfcffffef) | FIFO_BITS;
869#endif
870 } else
871 /*if (this_8[fifo]) */
872 vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE);
873 }
874 hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2), temp);
875 hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2));
876}
877
878#ifndef CHIP_AU8810
879static void vortex_fifo_clearwtdata(vortex_t * vortex, int fifo, int x)
880{
881 if (x < 1)
882 return;
883 for (x--; x >= 0; x--)
884 hwwrite(vortex->mmio,
885 VORTEX_FIFO_WTDATA +
886 (((fifo << FIFO_SIZE_BITS) + x) << 2), 0);
887}
888
889static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j)
890{
891 vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);
892#ifdef CHIP_AU8820
893 hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2),
894 (FIFO_U1 | ((j & FIFO_MASK) << 0xb)));
895#else
896 hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2),
897 (FIFO_U1 | ((j & FIFO_MASK) << 0xc)));
898#endif
899}
900
901static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en)
902{
903 hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2),
904 (hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)) &
905 0xffffffef) | ((en & 1) << 4) | FIFO_U1);
906}
907
908static void
909vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority,
910 int empty, int valid, int f)
911{
912 int temp = 0, lifeboat = 0;
913 int this_4 = 2;
914
915 do {
916 temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
917 if (lifeboat++ > 0xbb8) {
918 printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail\n");
919 break;
920 }
921 }
922 while (temp & FIFO_RDONLY);
923
924 if (valid) {
925 if ((temp & FIFO_VALID) == 0) {
926 vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE); // this_4
927#ifdef CHIP_AU8820
928 temp = (this_4 & 0x1f) << 0xb;
929#else
930 temp = (this_4 & 0x3f) << 0xc;
931#endif
932 temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1);
933 temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
934 temp = (temp & 0xffffffef) | ((valid & 1) << 4);
935 temp |= FIFO_U1;
936 temp = (temp & 0xffffffdf) | ((empty & 1) << 5);
937#ifdef CHIP_AU8820
938 temp = (temp & 0xfffbffff) | ((f & 1) << 0x12);
939#endif
940#ifdef CHIP_AU8830
941 temp = (temp & 0xf7ffffff) | ((f & 1) << 0x1b);
942 temp = (temp & 0xefffffff) | ((f & 1) << 0x1c);
943#endif
944#ifdef CHIP_AU8810
945 temp = (temp & 0xfeffffff) | ((f & 1) << 0x18);
946 temp = (temp & 0xfdffffff) | ((f & 1) << 0x19);
947#endif
948 }
949 } else {
950 if (temp & FIFO_VALID) {
951#ifdef CHIP_AU8820
952 temp = ((f & 1) << 0x12) | (temp & 0xfffbffef);
953#endif
954#ifdef CHIP_AU8830
955 temp =
956 ((f & 1) << 0x1b) | (temp & 0xe7ffffef) | FIFO_BITS;
957#endif
958#ifdef CHIP_AU8810
959 temp =
960 ((f & 1) << 0x18) | (temp & 0xfcffffef) | FIFO_BITS;
961#endif
962 } else
963 /*if (this_8[fifo]) */
964 vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);
965 }
966 hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
967 hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
968
969/*
970 do {
971 temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
972 if (lifeboat++ > 0xbb8) {
973 printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail (hanging)\n");
974 break;
975 }
976 } while ((temp & FIFO_RDONLY)&&(temp & FIFO_VALID)&&(temp != 0xFFFFFFFF));
977
978
979 if (valid) {
980 if (temp & FIFO_VALID) {
981 temp = 0x40000;
982 //temp |= 0x08000000;
983 //temp |= 0x10000000;
984 //temp |= 0x04000000;
985 //temp |= 0x00400000;
986 temp |= 0x1c400000;
987 temp &= 0xFFFFFFF3;
988 temp &= 0xFFFFFFEF;
989 temp |= (valid & 1) << 4;
990 hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
991 return;
992 } else {
993 vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);
994 return;
995 }
996 } else {
997 temp &= 0xffffffef;
998 temp |= 0x08000000;
999 temp |= 0x10000000;
1000 temp |= 0x04000000;
1001 temp |= 0x00400000;
1002 hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
1003 temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
1004 //((temp >> 6) & 0x3f)
1005
1006 priority = 0;
1007 if (((temp & 0x0fc0) ^ ((temp >> 6) & 0x0fc0)) & 0FFFFFFC0)
1008 vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE);
1009 valid = 0xfb;
1010 temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1);
1011 temp = (temp & 0xfffdffff) | ((f & 1) << 0x11);
1012 temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
1013 temp = (temp & 0xffffffef) | ((valid & 1) << 4);
1014 temp = (temp & 0xffffffdf) | ((empty & 1) << 5);
1015 hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
1016 }
1017
1018 */
1019
1020 /*
1021 temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1);
1022 temp = (temp & 0xfffdffff) | ((f & 1) << 0x11);
1023 temp = (temp & 0xfffffff3) | ((priority & 3) << 2);
1024 temp = (temp & 0xffffffef) | ((valid & 1) << 4);
1025 temp = (temp & 0xffffffdf) | ((empty & 1) << 5);
1026 #ifdef FIFO_BITS
1027 temp = temp | FIFO_BITS | 40000;
1028 #endif
1029 // 0x1c440010, 0x1c400000
1030 hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp);
1031 */
1032}
1033
1034#endif
1035static void vortex_fifo_init(vortex_t * vortex)
1036{
1037 int x;
1038 unsigned long addr;
1039
1040 /* ADB DMA channels fifos. */
1041 addr = VORTEX_FIFO_ADBCTRL + ((NR_ADB - 1) * 4);
1042 for (x = NR_ADB - 1; x >= 0; x--) {
1043 hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1));
1044 if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1))
1045 printk(KERN_ERR "bad adb fifo reset!");
1046 vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE);
1047 addr -= 4;
1048 }
1049
1050#ifndef CHIP_AU8810
1051 /* WT DMA channels fifos. */
1052 addr = VORTEX_FIFO_WTCTRL + ((NR_WT - 1) * 4);
1053 for (x = NR_WT - 1; x >= 0; x--) {
1054 hwwrite(vortex->mmio, addr, FIFO_U0);
1055 if (hwread(vortex->mmio, addr) != FIFO_U0)
1056 printk(KERN_ERR
1057 "bad wt fifo reset (0x%08lx, 0x%08x)!\n",
1058 addr, hwread(vortex->mmio, addr));
1059 vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE);
1060 addr -= 4;
1061 }
1062#endif
1063 /* trigger... */
1064#ifdef CHIP_AU8820
1065 hwwrite(vortex->mmio, 0xf8c0, 0xd03); //0x0843 0xd6b
1066#else
1067#ifdef CHIP_AU8830
1068 hwwrite(vortex->mmio, 0x17000, 0x61); /* wt a */
1069 hwwrite(vortex->mmio, 0x17004, 0x61); /* wt b */
1070#endif
1071 hwwrite(vortex->mmio, 0x17008, 0x61); /* adb */
1072#endif
1073}
1074
1075/* ADBDMA */
1076
1077static void vortex_adbdma_init(vortex_t * vortex)
1078{
1079}
1080
1081static void vortex_adbdma_setfirstbuffer(vortex_t * vortex, int adbdma)
1082{
1083 stream_t *dma = &vortex->dma_adb[adbdma];
1084
1085 hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
1086 dma->dma_ctrl);
1087}
1088
1089static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb)
1090{
1091 stream_t *dma = &vortex->dma_adb[adbdma];
1092 //hwwrite(vortex->mmio, VORTEX_ADBDMA_START + (adbdma << 2), sb << (((NR_ADB-1)-((adbdma&0xf)*2))));
1093 hwwrite(vortex->mmio, VORTEX_ADBDMA_START + (adbdma << 2),
1094 sb << ((0xf - (adbdma & 0xf)) * 2));
1095 dma->period_real = dma->period_virt = sb;
1096}
1097
1098static void
1099vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
1100 snd_pcm_sgbuf_t * sgbuf, int psize, int count)
1101{
1102 stream_t *dma = &vortex->dma_adb[adbdma];
1103
1104 if (sgbuf == NULL) {
1105 printk(KERN_INFO "vortex: FATAL: sgbuf is NULL!\n");
1106 return;
1107 }
1108 //printk(KERN_INFO "vortex: page count = %d, tblcount = %d\n", count, sgbuf->tblsize);
1109
1110 dma->period_bytes = psize;
1111 dma->nr_periods = count;
1112 dma->sgbuf = sgbuf;
1113
1114 dma->cfg0 = 0;
1115 dma->cfg1 = 0;
1116 switch (count) {
1117 /* Four or more pages */
1118 default:
1119 case 4:
1120 dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize - 1);
1121 hwwrite(vortex->mmio,
1122 VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
1123 snd_sgbuf_get_addr(sgbuf, psize * 3));
1124 /* 3 pages */
1125 case 3:
1126 dma->cfg0 |= 0x12000000;
1127 dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
1128 hwwrite(vortex->mmio,
1129 VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
1130 snd_sgbuf_get_addr(sgbuf, psize * 2));
1131 /* 2 pages */
1132 case 2:
1133 dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
1134 hwwrite(vortex->mmio,
1135 VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
1136 snd_sgbuf_get_addr(sgbuf, psize));
1137 /* 1 page */
1138 case 1:
1139 dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
1140 hwwrite(vortex->mmio,
1141 VORTEX_ADBDMA_BUFBASE + (adbdma << 4),
1142 snd_sgbuf_get_addr(sgbuf, 0));
1143 break;
1144 }
1145 //printk("vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", dma->cfg0, dma->cfg1);
1146 hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG0 + (adbdma << 3), dma->cfg0);
1147 hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG1 + (adbdma << 3), dma->cfg1);
1148
1149 vortex_adbdma_setfirstbuffer(vortex, adbdma);
1150 vortex_adbdma_setstartbuffer(vortex, adbdma, 0);
1151}
1152
1153static void
1154vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, int dir,
1155 int fmt, int d, unsigned long offset)
1156{
1157 stream_t *dma = &vortex->dma_adb[adbdma];
1158
1159 dma->dma_unknown = d;
1160 dma->dma_ctrl =
1161 ((offset & OFFSET_MASK) | (dma->dma_ctrl & ~OFFSET_MASK));
1162 /* Enable PCMOUT interrupts. */
1163 dma->dma_ctrl =
1164 (dma->dma_ctrl & ~IE_MASK) | ((ie << IE_SHIFT) & IE_MASK);
1165
1166 dma->dma_ctrl =
1167 (dma->dma_ctrl & ~DIR_MASK) | ((dir << DIR_SHIFT) & DIR_MASK);
1168 dma->dma_ctrl =
1169 (dma->dma_ctrl & ~FMT_MASK) | ((fmt << FMT_SHIFT) & FMT_MASK);
1170
1171 hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
1172 dma->dma_ctrl);
1173 hwread(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2));
1174}
1175
1176static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma)
1177{
1178 stream_t *dma = &vortex->dma_adb[adbdma];
1179 int page, p, pp, delta, i;
1180
1181 page =
1182 (hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)) &
1183 ADB_SUBBUF_MASK) >> ADB_SUBBUF_SHIFT;
1184 if (dma->nr_periods >= 4)
1185 delta = (page - dma->period_real) & 3;
1186 else {
1187 delta = (page - dma->period_real);
1188 if (delta < 0)
1189 delta += dma->nr_periods;
1190 }
1191 if (delta == 0)
1192 return 0;
1193
1194 /* refresh hw page table */
1195 if (dma->nr_periods > 4) {
1196 for (i = 0; i < delta; i++) {
1197 /* p: audio buffer page index */
1198 p = dma->period_virt + i + 4;
1199 if (p >= dma->nr_periods)
1200 p -= dma->nr_periods;
1201 /* pp: hardware DMA page index. */
1202 pp = dma->period_real + i;
1203 if (pp >= 4)
1204 pp -= 4;
1205 //hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), dma->table[p].addr);
1206 hwwrite(vortex->mmio,
1207 VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2),
1208 snd_sgbuf_get_addr(dma->sgbuf,
1209 dma->period_bytes * p));
1210 /* Force write thru cache. */
1211 hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE +
1212 (((adbdma << 2) + pp) << 2));
1213 }
1214 }
1215 dma->period_virt += delta;
1216 dma->period_real = page;
1217 if (dma->period_virt >= dma->nr_periods)
1218 dma->period_virt -= dma->nr_periods;
1219 if (delta != 1)
1220 printk(KERN_INFO "vortex: %d virt=%d, real=%d, delta=%d\n",
1221 adbdma, dma->period_virt, dma->period_real, delta);
1222
1223 return delta;
1224}
1225
1226
1227static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma) {
1228 stream_t *dma = &vortex->dma_adb[adbdma];
1229 int p, pp, i;
1230
1231 /* refresh hw page table */
1232 for (i=0 ; i < 4 && i < dma->nr_periods; i++) {
1233 /* p: audio buffer page index */
1234 p = dma->period_virt + i;
1235 if (p >= dma->nr_periods)
1236 p -= dma->nr_periods;
1237 /* pp: hardware DMA page index. */
1238 pp = dma->period_real + i;
1239 if (dma->nr_periods < 4) {
1240 if (pp >= dma->nr_periods)
1241 pp -= dma->nr_periods;
1242 }
1243 else {
1244 if (pp >= 4)
1245 pp -= 4;
1246 }
1247 hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p));
1248 /* Force write thru cache. */
1249 hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE + (((adbdma << 2)+pp) << 2));
1250 }
1251}
1252
1253static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma)
1254{
1255 stream_t *dma = &vortex->dma_adb[adbdma];
1256 int temp;
1257
1258 temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2));
1259 temp = (dma->period_virt * dma->period_bytes) + (temp & POS_MASK);
1260 return (temp);
1261}
1262
1263static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma)
1264{
1265 int this_8 = 0 /*empty */ , this_4 = 0 /*priority */ ;
1266 stream_t *dma = &vortex->dma_adb[adbdma];
1267
1268 switch (dma->fifo_status) {
1269 case FIFO_START:
1270 vortex_fifo_setadbvalid(vortex, adbdma,
1271 dma->fifo_enabled ? 1 : 0);
1272 break;
1273 case FIFO_STOP:
1274 this_8 = 1;
1275 hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
1276 dma->dma_ctrl);
1277 vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
1278 this_4, this_8,
1279 dma->fifo_enabled ? 1 : 0, 0);
1280 break;
1281 case FIFO_PAUSE:
1282 vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
1283 this_4, this_8,
1284 dma->fifo_enabled ? 1 : 0, 0);
1285 break;
1286 }
1287 dma->fifo_status = FIFO_START;
1288}
1289
1290static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma)
1291{
1292 stream_t *dma = &vortex->dma_adb[adbdma];
1293
1294 int this_8 = 1, this_4 = 0;
1295 switch (dma->fifo_status) {
1296 case FIFO_STOP:
1297 hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
1298 dma->dma_ctrl);
1299 vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
1300 this_4, this_8,
1301 dma->fifo_enabled ? 1 : 0, 0);
1302 break;
1303 case FIFO_PAUSE:
1304 vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
1305 this_4, this_8,
1306 dma->fifo_enabled ? 1 : 0, 0);
1307 break;
1308 }
1309 dma->fifo_status = FIFO_START;
1310}
1311
1312static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma)
1313{
1314 stream_t *dma = &vortex->dma_adb[adbdma];
1315
1316 int this_8 = 0, this_4 = 0;
1317 switch (dma->fifo_status) {
1318 case FIFO_START:
1319 vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
1320 this_4, this_8, 0, 0);
1321 break;
1322 case FIFO_STOP:
1323 hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2),
1324 dma->dma_ctrl);
1325 vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
1326 this_4, this_8, 0, 0);
1327 break;
1328 }
1329 dma->fifo_status = FIFO_PAUSE;
1330}
1331
1332#if 0 // Using pause instead
1333static void vortex_adbdma_stopfifo(vortex_t * vortex, int adbdma)
1334{
1335 stream_t *dma = &vortex->dma_adb[adbdma];
1336
1337 int this_4 = 0, this_8 = 0;
1338 if (dma->fifo_status == FIFO_START)
1339 vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown,
1340 this_4, this_8, 0, 0);
1341 else if (dma->fifo_status == FIFO_STOP)
1342 return;
1343 dma->fifo_status = FIFO_STOP;
1344 dma->fifo_enabled = 0;
1345}
1346
1347#endif
1348/* WTDMA */
1349
1350#ifndef CHIP_AU8810
1351static void vortex_wtdma_setfirstbuffer(vortex_t * vortex, int wtdma)
1352{
1353 //int this_7c=dma_ctrl;
1354 stream_t *dma = &vortex->dma_wt[wtdma];
1355
1356 hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), dma->dma_ctrl);
1357}
1358
1359static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb)
1360{
1361 stream_t *dma = &vortex->dma_wt[wtdma];
1362 //hwwrite(vortex->mmio, VORTEX_WTDMA_START + (wtdma << 2), sb << ((0x1f-(wtdma&0xf)*2)));
1363 hwwrite(vortex->mmio, VORTEX_WTDMA_START + (wtdma << 2),
1364 sb << ((0xf - (wtdma & 0xf)) * 2));
1365 dma->period_real = dma->period_virt = sb;
1366}
1367
1368static void
1369vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
1370 snd_pcm_sgbuf_t * sgbuf, int psize, int count)
1371{
1372 stream_t *dma = &vortex->dma_wt[wtdma];
1373
1374 dma->period_bytes = psize;
1375 dma->nr_periods = count;
1376 dma->sgbuf = sgbuf;
1377
1378 dma->cfg0 = 0;
1379 dma->cfg1 = 0;
1380 switch (count) {
1381 /* Four or more pages */
1382 default:
1383 case 4:
1384 dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
1385 hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
1386 snd_sgbuf_get_addr(sgbuf, psize * 3));
1387 /* 3 pages */
1388 case 3:
1389 dma->cfg0 |= 0x12000000;
1390 dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
1391 hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x8,
1392 snd_sgbuf_get_addr(sgbuf, psize * 2));
1393 /* 2 pages */
1394 case 2:
1395 dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
1396 hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
1397 snd_sgbuf_get_addr(sgbuf, psize));
1398 /* 1 page */
1399 case 1:
1400 dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
1401 hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4),
1402 snd_sgbuf_get_addr(sgbuf, 0));
1403 break;
1404 }
1405 hwwrite(vortex->mmio, VORTEX_WTDMA_BUFCFG0 + (wtdma << 3), dma->cfg0);
1406 hwwrite(vortex->mmio, VORTEX_WTDMA_BUFCFG1 + (wtdma << 3), dma->cfg1);
1407
1408 vortex_wtdma_setfirstbuffer(vortex, wtdma);
1409 vortex_wtdma_setstartbuffer(vortex, wtdma, 0);
1410}
1411
1412static void
1413vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d,
1414 /*int e, */ unsigned long offset)
1415{
1416 stream_t *dma = &vortex->dma_wt[wtdma];
1417
1418 //dma->this_08 = e;
1419 dma->dma_unknown = d;
1420 dma->dma_ctrl = 0;
1421 dma->dma_ctrl =
1422 ((offset & OFFSET_MASK) | (dma->dma_ctrl & ~OFFSET_MASK));
1423 /* PCMOUT interrupt */
1424 dma->dma_ctrl =
1425 (dma->dma_ctrl & ~IE_MASK) | ((ie << IE_SHIFT) & IE_MASK);
1426 /* Always playback. */
1427 dma->dma_ctrl |= (1 << DIR_SHIFT);
1428 /* Audio Format */
1429 dma->dma_ctrl =
1430 (dma->dma_ctrl & FMT_MASK) | ((fmt << FMT_SHIFT) & FMT_MASK);
1431 /* Write into hardware */
1432 hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), dma->dma_ctrl);
1433}
1434
1435static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma)
1436{
1437 stream_t *dma = &vortex->dma_wt[wtdma];
1438 int page, p, pp, delta, i;
1439
1440 page =
1441 (hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) &
1442 WT_SUBBUF_MASK)
1443 >> WT_SUBBUF_SHIFT;
1444 if (dma->nr_periods >= 4)
1445 delta = (page - dma->period_real) & 3;
1446 else {
1447 delta = (page - dma->period_real);
1448 if (delta < 0)
1449 delta += dma->nr_periods;
1450 }
1451 if (delta == 0)
1452 return 0;
1453
1454 /* refresh hw page table */
1455 if (dma->nr_periods > 4) {
1456 for (i = 0; i < delta; i++) {
1457 /* p: audio buffer page index */
1458 p = dma->period_virt + i + 4;
1459 if (p >= dma->nr_periods)
1460 p -= dma->nr_periods;
1461 /* pp: hardware DMA page index. */
1462 pp = dma->period_real + i;
1463 if (pp >= 4)
1464 pp -= 4;
1465 hwwrite(vortex->mmio,
1466 VORTEX_WTDMA_BUFBASE +
1467 (((wtdma << 2) + pp) << 2),
1468 snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p));
1469 /* Force write thru cache. */
1470 hwread(vortex->mmio, VORTEX_WTDMA_BUFBASE +
1471 (((wtdma << 2) + pp) << 2));
1472 }
1473 }
1474 dma->period_virt += delta;
1475 if (dma->period_virt >= dma->nr_periods)
1476 dma->period_virt -= dma->nr_periods;
1477 dma->period_real = page;
1478
1479 if (delta != 1)
1480 printk(KERN_WARNING "vortex: wt virt = %d, delta = %d\n",
1481 dma->period_virt, delta);
1482
1483 return delta;
1484}
1485
1486#if 0
1487static void
1488vortex_wtdma_getposition(vortex_t * vortex, int wtdma, int *subbuf, int *pos)
1489{
1490 int temp;
1491 temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2));
1492 *subbuf = (temp >> WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK;
1493 *pos = temp & POS_MASK;
1494}
1495
1496static int vortex_wtdma_getcursubuffer(vortex_t * vortex, int wtdma)
1497{
1498 return ((hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) >>
1499 POS_SHIFT) & POS_MASK);
1500}
1501#endif
1502static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma)
1503{
1504 stream_t *dma = &vortex->dma_wt[wtdma];
1505 int temp;
1506
1507 temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2));
1508 //temp = (temp & POS_MASK) + (((temp>>WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK)*(dma->cfg0&POS_MASK));
1509 temp = (temp & POS_MASK) + ((dma->period_virt) * (dma->period_bytes));
1510 return temp;
1511}
1512
1513static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma)
1514{
1515 stream_t *dma = &vortex->dma_wt[wtdma];
1516 int this_8 = 0, this_4 = 0;
1517
1518 switch (dma->fifo_status) {
1519 case FIFO_START:
1520 vortex_fifo_setwtvalid(vortex, wtdma,
1521 dma->fifo_enabled ? 1 : 0);
1522 break;
1523 case FIFO_STOP:
1524 this_8 = 1;
1525 hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2),
1526 dma->dma_ctrl);
1527 vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
1528 this_4, this_8,
1529 dma->fifo_enabled ? 1 : 0, 0);
1530 break;
1531 case FIFO_PAUSE:
1532 vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
1533 this_4, this_8,
1534 dma->fifo_enabled ? 1 : 0, 0);
1535 break;
1536 }
1537 dma->fifo_status = FIFO_START;
1538}
1539
1540static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma)
1541{
1542 stream_t *dma = &vortex->dma_wt[wtdma];
1543
1544 int this_8 = 0, this_4 = 0;
1545 switch (dma->fifo_status) {
1546 case FIFO_STOP:
1547 hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2),
1548 dma->dma_ctrl);
1549 vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
1550 this_4, this_8,
1551 dma->fifo_enabled ? 1 : 0, 0);
1552 break;
1553 case FIFO_PAUSE:
1554 vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
1555 this_4, this_8,
1556 dma->fifo_enabled ? 1 : 0, 0);
1557 break;
1558 }
1559 dma->fifo_status = FIFO_START;
1560}
1561
1562static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma)
1563{
1564 stream_t *dma = &vortex->dma_wt[wtdma];
1565
1566 int this_8 = 0, this_4 = 0;
1567 switch (dma->fifo_status) {
1568 case FIFO_START:
1569 vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
1570 this_4, this_8, 0, 0);
1571 break;
1572 case FIFO_STOP:
1573 hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2),
1574 dma->dma_ctrl);
1575 vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
1576 this_4, this_8, 0, 0);
1577 break;
1578 }
1579 dma->fifo_status = FIFO_PAUSE;
1580}
1581
1582static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma)
1583{
1584 stream_t *dma = &vortex->dma_wt[wtdma];
1585
1586 int this_4 = 0, this_8 = 0;
1587 if (dma->fifo_status == FIFO_START)
1588 vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown,
1589 this_4, this_8, 0, 0);
1590 else if (dma->fifo_status == FIFO_STOP)
1591 return;
1592 dma->fifo_status = FIFO_STOP;
1593 dma->fifo_enabled = 0;
1594}
1595
1596#endif
1597/* ADB Routes */
1598
1599typedef int ADBRamLink;
1600static void vortex_adb_init(vortex_t * vortex)
1601{
1602 int i;
1603 /* it looks like we are writing more than we need to...
1604 * if we write what we are supposed to it breaks things... */
1605 hwwrite(vortex->mmio, VORTEX_ADB_SR, 0);
1606 for (i = 0; i < VORTEX_ADB_RTBASE_COUNT; i++)
1607 hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (i << 2),
1608 hwread(vortex->mmio,
1609 VORTEX_ADB_RTBASE + (i << 2)) | ROUTE_MASK);
1610 for (i = 0; i < VORTEX_ADB_CHNBASE_COUNT; i++) {
1611 hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (i << 2),
1612 hwread(vortex->mmio,
1613 VORTEX_ADB_CHNBASE + (i << 2)) | ROUTE_MASK);
1614 }
1615}
1616
1617static void vortex_adb_en_sr(vortex_t * vortex, int channel)
1618{
1619 hwwrite(vortex->mmio, VORTEX_ADB_SR,
1620 hwread(vortex->mmio, VORTEX_ADB_SR) | (0x1 << channel));
1621}
1622
1623static void vortex_adb_dis_sr(vortex_t * vortex, int channel)
1624{
1625 hwwrite(vortex->mmio, VORTEX_ADB_SR,
1626 hwread(vortex->mmio, VORTEX_ADB_SR) & ~(0x1 << channel));
1627}
1628
1629static void
1630vortex_adb_addroutes(vortex_t * vortex, unsigned char channel,
1631 ADBRamLink * route, int rnum)
1632{
1633 int temp, prev, lifeboat = 0;
1634
1635 if ((rnum <= 0) || (route == NULL))
1636 return;
1637 /* Write last routes. */
1638 rnum--;
1639 hwwrite(vortex->mmio,
1640 VORTEX_ADB_RTBASE + ((route[rnum] & ADB_MASK) << 2),
1641 ROUTE_MASK);
1642 while (rnum > 0) {
1643 hwwrite(vortex->mmio,
1644 VORTEX_ADB_RTBASE +
1645 ((route[rnum - 1] & ADB_MASK) << 2), route[rnum]);
1646 rnum--;
1647 }
1648 /* Write first route. */
1649 temp =
1650 hwread(vortex->mmio,
1651 VORTEX_ADB_CHNBASE + (channel << 2)) & ADB_MASK;
1652 if (temp == ADB_MASK) {
1653 /* First entry on this channel. */
1654 hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (channel << 2),
1655 route[0]);
1656 vortex_adb_en_sr(vortex, channel);
1657 return;
1658 }
1659 /* Not first entry on this channel. Need to link. */
1660 do {
1661 prev = temp;
1662 temp =
1663 hwread(vortex->mmio,
1664 VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK;
1665 if ((lifeboat++) > ADB_MASK) {
1666 printk(KERN_ERR
1667 "vortex_adb_addroutes: unending route! 0x%x\n",
1668 *route);
1669 return;
1670 }
1671 }
1672 while (temp != ADB_MASK);
1673 hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (prev << 2), route[0]);
1674}
1675
1676static void
1677vortex_adb_delroutes(vortex_t * vortex, unsigned char channel,
1678 ADBRamLink route0, ADBRamLink route1)
1679{
1680 int temp, lifeboat = 0, prev;
1681
1682 /* Find route. */
1683 temp =
1684 hwread(vortex->mmio,
1685 VORTEX_ADB_CHNBASE + (channel << 2)) & ADB_MASK;
1686 if (temp == (route0 & ADB_MASK)) {
1687 temp =
1688 hwread(vortex->mmio,
1689 VORTEX_ADB_RTBASE + ((route1 & ADB_MASK) << 2));
1690 if ((temp & ADB_MASK) == ADB_MASK)
1691 vortex_adb_dis_sr(vortex, channel);
1692 hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (channel << 2),
1693 temp);
1694 return;
1695 }
1696 do {
1697 prev = temp;
1698 temp =
1699 hwread(vortex->mmio,
1700 VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK;
1701 if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) {
1702 printk(KERN_ERR
1703 "vortex_adb_delroutes: route not found! 0x%x\n",
1704 route0);
1705 return;
1706 }
1707 }
1708 while (temp != (route0 & ADB_MASK));
1709 temp = hwread(vortex->mmio, VORTEX_ADB_RTBASE + (temp << 2));
1710 if ((temp & ADB_MASK) == route1)
1711 temp = hwread(vortex->mmio, VORTEX_ADB_RTBASE + (temp << 2));
1712 /* Make bridge over deleted route. */
1713 hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (prev << 2), temp);
1714}
1715
1716static void
1717vortex_route(vortex_t * vortex, int en, unsigned char channel,
1718 unsigned char source, unsigned char dest)
1719{
1720 ADBRamLink route;
1721
1722 route = ((source & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK);
1723 if (en) {
1724 vortex_adb_addroutes(vortex, channel, &route, 1);
1725 if ((source < (OFFSET_SRCOUT + NR_SRC))
1726 && (source >= OFFSET_SRCOUT))
1727 vortex_src_addWTD(vortex, (source - OFFSET_SRCOUT),
1728 channel);
1729 else if ((source < (OFFSET_MIXOUT + NR_MIXOUT))
1730 && (source >= OFFSET_MIXOUT))
1731 vortex_mixer_addWTD(vortex,
1732 (source - OFFSET_MIXOUT), channel);
1733 } else {
1734 vortex_adb_delroutes(vortex, channel, route, route);
1735 if ((source < (OFFSET_SRCOUT + NR_SRC))
1736 && (source >= OFFSET_SRCOUT))
1737 vortex_src_delWTD(vortex, (source - OFFSET_SRCOUT),
1738 channel);
1739 else if ((source < (OFFSET_MIXOUT + NR_MIXOUT))
1740 && (source >= OFFSET_MIXOUT))
1741 vortex_mixer_delWTD(vortex,
1742 (source - OFFSET_MIXOUT), channel);
1743 }
1744}
1745
1746#if 0
1747static void
1748vortex_routes(vortex_t * vortex, int en, unsigned char channel,
1749 unsigned char source, unsigned char dest0, unsigned char dest1)
1750{
1751 ADBRamLink route[2];
1752
1753 route[0] = ((source & ADB_MASK) << ADB_SHIFT) | (dest0 & ADB_MASK);
1754 route[1] = ((source & ADB_MASK) << ADB_SHIFT) | (dest1 & ADB_MASK);
1755
1756 if (en) {
1757 vortex_adb_addroutes(vortex, channel, route, 2);
1758 if ((source < (OFFSET_SRCOUT + NR_SRC))
1759 && (source >= (OFFSET_SRCOUT)))
1760 vortex_src_addWTD(vortex, (source - OFFSET_SRCOUT),
1761 channel);
1762 else if ((source < (OFFSET_MIXOUT + NR_MIXOUT))
1763 && (source >= (OFFSET_MIXOUT)))
1764 vortex_mixer_addWTD(vortex,
1765 (source - OFFSET_MIXOUT), channel);
1766 } else {
1767 vortex_adb_delroutes(vortex, channel, route[0], route[1]);
1768 if ((source < (OFFSET_SRCOUT + NR_SRC))
1769 && (source >= (OFFSET_SRCOUT)))
1770 vortex_src_delWTD(vortex, (source - OFFSET_SRCOUT),
1771 channel);
1772 else if ((source < (OFFSET_MIXOUT + NR_MIXOUT))
1773 && (source >= (OFFSET_MIXOUT)))
1774 vortex_mixer_delWTD(vortex,
1775 (source - OFFSET_MIXOUT), channel);
1776 }
1777}
1778
1779#endif
1780/* Route two sources to same target. Sources must be of same class !!! */
1781static void
1782vortex_routeLRT(vortex_t * vortex, int en, unsigned char ch,
1783 unsigned char source0, unsigned char source1,
1784 unsigned char dest)
1785{
1786 ADBRamLink route[2];
1787
1788 route[0] = ((source0 & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK);
1789 route[1] = ((source1 & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK);
1790
1791 if (dest < 0x10)
1792 route[1] = (route[1] & ~ADB_MASK) | (dest + 0x20); /* fifo A */
1793
1794 if (en) {
1795 vortex_adb_addroutes(vortex, ch, route, 2);
1796 if ((source0 < (OFFSET_SRCOUT + NR_SRC))
1797 && (source0 >= OFFSET_SRCOUT)) {
1798 vortex_src_addWTD(vortex,
1799 (source0 - OFFSET_SRCOUT), ch);
1800 vortex_src_addWTD(vortex,
1801 (source1 - OFFSET_SRCOUT), ch);
1802 } else if ((source0 < (OFFSET_MIXOUT + NR_MIXOUT))
1803 && (source0 >= OFFSET_MIXOUT)) {
1804 vortex_mixer_addWTD(vortex,
1805 (source0 - OFFSET_MIXOUT), ch);
1806 vortex_mixer_addWTD(vortex,
1807 (source1 - OFFSET_MIXOUT), ch);
1808 }
1809 } else {
1810 vortex_adb_delroutes(vortex, ch, route[0], route[1]);
1811 if ((source0 < (OFFSET_SRCOUT + NR_SRC))
1812 && (source0 >= OFFSET_SRCOUT)) {
1813 vortex_src_delWTD(vortex,
1814 (source0 - OFFSET_SRCOUT), ch);
1815 vortex_src_delWTD(vortex,
1816 (source1 - OFFSET_SRCOUT), ch);
1817 } else if ((source0 < (OFFSET_MIXOUT + NR_MIXOUT))
1818 && (source0 >= OFFSET_MIXOUT)) {
1819 vortex_mixer_delWTD(vortex,
1820 (source0 - OFFSET_MIXOUT), ch);
1821 vortex_mixer_delWTD(vortex,
1822 (source1 - OFFSET_MIXOUT), ch);
1823 }
1824 }
1825}
1826
1827/* Connection stuff */
1828
1829// Connect adbdma to src('s).
1830static void
1831vortex_connection_adbdma_src(vortex_t * vortex, int en, unsigned char ch,
1832 unsigned char adbdma, unsigned char src)
1833{
1834 vortex_route(vortex, en, ch, ADB_DMA(adbdma), ADB_SRCIN(src));
1835}
1836
1837// Connect SRC to mixin.
1838static void
1839vortex_connection_src_mixin(vortex_t * vortex, int en,
1840 unsigned char channel, unsigned char src,
1841 unsigned char mixin)
1842{
1843 vortex_route(vortex, en, channel, ADB_SRCOUT(src), ADB_MIXIN(mixin));
1844}
1845
1846// Connect mixin with mix output.
1847static void
1848vortex_connection_mixin_mix(vortex_t * vortex, int en, unsigned char mixin,
1849 unsigned char mix, int a)
1850{
1851 if (en) {
1852 vortex_mix_enableinput(vortex, mix, mixin);
1853 vortex_mix_setinputvolumebyte(vortex, mix, mixin, MIX_DEFIGAIN); // added to original code.
1854 } else
1855 vortex_mix_disableinput(vortex, mix, mixin, a);
1856}
1857
1858// Connect absolut address to mixin.
1859static void
1860vortex_connection_adb_mixin(vortex_t * vortex, int en,
1861 unsigned char channel, unsigned char source,
1862 unsigned char mixin)
1863{
1864 vortex_route(vortex, en, channel, source, ADB_MIXIN(mixin));
1865}
1866
1867static void
1868vortex_connection_src_adbdma(vortex_t * vortex, int en, unsigned char ch,
1869 unsigned char src, unsigned char adbdma)
1870{
1871 vortex_route(vortex, en, ch, ADB_SRCOUT(src), ADB_DMA(adbdma));
1872}
1873
1874static void
1875vortex_connection_src_src_adbdma(vortex_t * vortex, int en,
1876 unsigned char ch, unsigned char src0,
1877 unsigned char src1, unsigned char adbdma)
1878{
1879
1880 vortex_routeLRT(vortex, en, ch, ADB_SRCOUT(src0), ADB_SRCOUT(src1),
1881 ADB_DMA(adbdma));
1882}
1883
1884// mix to absolut address.
1885static void
1886vortex_connection_mix_adb(vortex_t * vortex, int en, unsigned char ch,
1887 unsigned char mix, unsigned char dest)
1888{
1889 vortex_route(vortex, en, ch, ADB_MIXOUT(mix), dest);
1890 vortex_mix_setvolumebyte(vortex, mix, MIX_DEFOGAIN); // added to original code.
1891}
1892
1893// mixer to src.
1894static void
1895vortex_connection_mix_src(vortex_t * vortex, int en, unsigned char ch,
1896 unsigned char mix, unsigned char src)
1897{
1898 vortex_route(vortex, en, ch, ADB_MIXOUT(mix), ADB_SRCIN(src));
1899 vortex_mix_setvolumebyte(vortex, mix, MIX_DEFOGAIN); // added to original code.
1900}
1901
1902#if 0
1903static void
1904vortex_connection_adbdma_src_src(vortex_t * vortex, int en,
1905 unsigned char channel,
1906 unsigned char adbdma, unsigned char src0,
1907 unsigned char src1)
1908{
1909 vortex_routes(vortex, en, channel, ADB_DMA(adbdma),
1910 ADB_SRCIN(src0), ADB_SRCIN(src1));
1911}
1912
1913// Connect two mix to AdbDma.
1914static void
1915vortex_connection_mix_mix_adbdma(vortex_t * vortex, int en,
1916 unsigned char ch, unsigned char mix0,
1917 unsigned char mix1, unsigned char adbdma)
1918{
1919
1920 ADBRamLink routes[2];
1921 routes[0] =
1922 (((mix0 +
1923 OFFSET_MIXOUT) & ADB_MASK) << ADB_SHIFT) | (adbdma & ADB_MASK);
1924 routes[1] =
1925 (((mix1 + OFFSET_MIXOUT) & ADB_MASK) << ADB_SHIFT) | ((adbdma +
1926 0x20) &
1927 ADB_MASK);
1928 if (en) {
1929 vortex_adb_addroutes(vortex, ch, routes, 0x2);
1930 vortex_mixer_addWTD(vortex, mix0, ch);
1931 vortex_mixer_addWTD(vortex, mix1, ch);
1932 } else {
1933 vortex_adb_delroutes(vortex, ch, routes[0], routes[1]);
1934 vortex_mixer_delWTD(vortex, mix0, ch);
1935 vortex_mixer_delWTD(vortex, mix1, ch);
1936 }
1937}
1938#endif
1939
1940/* CODEC connect. */
1941
1942static void
1943vortex_connect_codecplay(vortex_t * vortex, int en, unsigned char mixers[])
1944{
1945#ifdef CHIP_AU8820
1946 vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_CODECOUT(0));
1947 vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_CODECOUT(1));
1948#else
1949#if 1
1950 // Connect front channels through EQ.
1951 vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_EQIN(0));
1952 vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_EQIN(1));
1953 /* Lower volume, since EQ has some gain. */
1954 vortex_mix_setvolumebyte(vortex, mixers[0], 0);
1955 vortex_mix_setvolumebyte(vortex, mixers[1], 0);
1956 vortex_route(vortex, en, 0x11, ADB_EQOUT(0), ADB_CODECOUT(0));
1957 vortex_route(vortex, en, 0x11, ADB_EQOUT(1), ADB_CODECOUT(1));
1958
1959 /* Check if reg 0x28 has SDAC bit set. */
1960 if (VORTEX_IS_QUAD(vortex)) {
1961 /* Rear channel. Note: ADB_CODECOUT(0+2) and (1+2) is for AC97 modem */
1962 vortex_connection_mix_adb(vortex, en, 0x11, mixers[2],
1963 ADB_CODECOUT(0 + 4));
1964 vortex_connection_mix_adb(vortex, en, 0x11, mixers[3],
1965 ADB_CODECOUT(1 + 4));
1966 //printk("SDAC detected ");
1967 }
1968#else
1969 // Use plain direct output to codec.
1970 vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_CODECOUT(0));
1971 vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_CODECOUT(1));
1972#endif
1973#endif
1974}
1975
1976static void
1977vortex_connect_codecrec(vortex_t * vortex, int en, unsigned char mixin0,
1978 unsigned char mixin1)
1979{
1980 /*
1981 Enable: 0x1, 0x1
1982 Channel: 0x11, 0x11
1983 ADB Source address: 0x48, 0x49
1984 Destination Asp4Topology_0x9c,0x98
1985 */
1986 vortex_connection_adb_mixin(vortex, en, 0x11, ADB_CODECIN(0), mixin0);
1987 vortex_connection_adb_mixin(vortex, en, 0x11, ADB_CODECIN(1), mixin1);
1988}
1989
1990// Higher level ADB audio path (de)allocator.
1991
1992/* Resource manager */
1993static int resnum[VORTEX_RESOURCE_LAST] =
1994 { NR_ADB, NR_SRC, NR_MIXIN, NR_MIXOUT, NR_A3D };
1995/*
1996 Checkout/Checkin resource of given type.
1997 resmap: resource map to be used. If NULL means that we want to allocate
1998 a DMA resource (root of all other resources of a dma channel).
1999 out: Mean checkout if != 0. Else mean Checkin resource.
2000 restype: Indicates type of resource to be checked in or out.
2001*/
2002static char
2003vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
2004{
2005 int i, qty = resnum[restype], resinuse = 0;
2006
2007 if (out) {
2008 /* Gather used resources by all streams. */
2009 for (i = 0; i < NR_ADB; i++) {
2010 resinuse |= vortex->dma_adb[i].resources[restype];
2011 }
2012 resinuse |= vortex->fixed_res[restype];
2013 /* Find and take free resource. */
2014 for (i = 0; i < qty; i++) {
2015 if ((resinuse & (1 << i)) == 0) {
2016 if (resmap != NULL)
2017 resmap[restype] |= (1 << i);
2018 else
2019 vortex->dma_adb[i].resources[restype] |= (1 << i);
2020 //printk("vortex: ResManager: type %d out %d\n", restype, i);
2021 return i;
2022 }
2023 }
2024 } else {
2025 if (resmap == NULL)
2026 return -EINVAL;
2027 /* Checkin first resource of type restype. */
2028 for (i = 0; i < qty; i++) {
2029 if (resmap[restype] & (1 << i)) {
2030 resmap[restype] &= ~(1 << i);
2031 //printk("vortex: ResManager: type %d in %d\n",restype, i);
2032 return i;
2033 }
2034 }
2035 }
2036 printk("vortex: FATAL: ResManager: resource type %d exhausted.\n", restype);
2037 return -ENOMEM;
2038}
2039
2040/* Default Connections */
2041static int
2042vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type);
2043
2044static void vortex_connect_default(vortex_t * vortex, int en)
2045{
2046 // Connect AC97 codec.
2047 vortex->mixplayb[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
2048 VORTEX_RESOURCE_MIXOUT);
2049 vortex->mixplayb[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
2050 VORTEX_RESOURCE_MIXOUT);
2051 if (VORTEX_IS_QUAD(vortex)) {
2052 vortex->mixplayb[2] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
2053 VORTEX_RESOURCE_MIXOUT);
2054 vortex->mixplayb[3] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
2055 VORTEX_RESOURCE_MIXOUT);
2056 }
2057 vortex_connect_codecplay(vortex, en, vortex->mixplayb);
2058
2059 vortex->mixcapt[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
2060 VORTEX_RESOURCE_MIXIN);
2061 vortex->mixcapt[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
2062 VORTEX_RESOURCE_MIXIN);
2063 vortex_connect_codecrec(vortex, en, MIX_CAPT(0), MIX_CAPT(1));
2064
2065 // Connect SPDIF
2066#ifndef CHIP_AU8820
2067 vortex->mixspdif[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
2068 VORTEX_RESOURCE_MIXOUT);
2069 vortex->mixspdif[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en,
2070 VORTEX_RESOURCE_MIXOUT);
2071 vortex_connection_mix_adb(vortex, en, 0x14, vortex->mixspdif[0],
2072 ADB_SPDIFOUT(0));
2073 vortex_connection_mix_adb(vortex, en, 0x14, vortex->mixspdif[1],
2074 ADB_SPDIFOUT(1));
2075#endif
2076 // Connect WT
2077#ifndef CHIP_AU8810
2078 vortex_wt_connect(vortex, en);
2079#endif
2080 // A3D (crosstalk canceler and A3D slices). AU8810 disabled for now.
2081#ifndef CHIP_AU8820
2082 vortex_Vort3D_connect(vortex, en);
2083#endif
2084 // Connect I2S
2085
2086 // Connect DSP interface for SQ3500 turbo (not here i think...)
2087
2088 // Connect AC98 modem codec
2089
2090}
2091
2092/*
2093 Allocate nr_ch pcm audio routes if dma < 0. If dma >= 0, existing routes
2094 are deallocated.
2095 dma: DMA engine routes to be deallocated when dma >= 0.
2096 nr_ch: Number of channels to be de/allocated.
2097 dir: direction of stream. Uses same values as substream->stream.
2098 type: Type of audio output/source (codec, spdif, i2s, dsp, etc)
2099 Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0.
2100*/
2101static int
2102vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type)
2103{
2104 stream_t *stream;
2105 int i, en;
2106
2107 if ((nr_ch == 3)
2108 || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2)))
2109 return -EBUSY;
2110
2111 if (dma >= 0) {
2112 en = 0;
2113 vortex_adb_checkinout(vortex,
2114 vortex->dma_adb[dma].resources, en,
2115 VORTEX_RESOURCE_DMA);
2116 } else {
2117 en = 1;
2118 if ((dma =
2119 vortex_adb_checkinout(vortex, NULL, en,
2120 VORTEX_RESOURCE_DMA)) < 0)
2121 return -EBUSY;
2122 }
2123
2124 stream = &vortex->dma_adb[dma];
2125 stream->dma = dma;
2126 stream->dir = dir;
2127 stream->type = type;
2128
2129 /* PLAYBACK ROUTES. */
2130 if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
2131 int src[4], mix[4], ch_top;
2132#ifndef CHIP_AU8820
2133 int a3d = 0;
2134#endif
2135 /* Get SRC and MIXER hardware resources. */
2136 if (stream->type != VORTEX_PCM_SPDIF) {
2137 for (i = 0; i < nr_ch; i++) {
2138 if ((src[i] = vortex_adb_checkinout(vortex,
2139 stream->resources, en,
2140 VORTEX_RESOURCE_SRC)) < 0) {
2141 memset(stream->resources, 0,
2142 sizeof(unsigned char) *
2143 VORTEX_RESOURCE_LAST);
2144 return -EBUSY;
2145 }
2146 if (stream->type != VORTEX_PCM_A3D) {
2147 if ((mix[i] = vortex_adb_checkinout(vortex,
2148 stream->resources,
2149 en,
2150 VORTEX_RESOURCE_MIXIN)) < 0) {
2151 memset(stream->resources,
2152 0,
2153 sizeof(unsigned char) * VORTEX_RESOURCE_LAST);
2154 return -EBUSY;
2155 }
2156 }
2157 }
2158 }
2159#ifndef CHIP_AU8820
2160 if (stream->type == VORTEX_PCM_A3D) {
2161 if ((a3d =
2162 vortex_adb_checkinout(vortex,
2163 stream->resources, en,
2164 VORTEX_RESOURCE_A3D)) < 0) {
2165 memset(stream->resources, 0,
2166 sizeof(unsigned char) *
2167 VORTEX_RESOURCE_LAST);
2168 printk("vortex: out of A3D sources. Sorry\n");
2169 return -EBUSY;
2170 }
2171 /* (De)Initialize A3D hardware source. */
2172 vortex_Vort3D_InitializeSource(&(vortex->a3d[a3d]), en);
2173 }
2174 /* Make SPDIF out exclusive to "spdif" device when in use. */
2175 if ((stream->type == VORTEX_PCM_SPDIF) && (en)) {
2176 vortex_route(vortex, 0, 0x14,
2177 ADB_MIXOUT(vortex->mixspdif[0]),
2178 ADB_SPDIFOUT(0));
2179 vortex_route(vortex, 0, 0x14,
2180 ADB_MIXOUT(vortex->mixspdif[1]),
2181 ADB_SPDIFOUT(1));
2182 }
2183#endif
2184 /* Make playback routes. */
2185 for (i = 0; i < nr_ch; i++) {
2186 if (stream->type == VORTEX_PCM_ADB) {
2187 vortex_connection_adbdma_src(vortex, en,
2188 src[nr_ch - 1],
2189 dma,
2190 src[i]);
2191 vortex_connection_src_mixin(vortex, en,
2192 0x11, src[i],
2193 mix[i]);
2194 vortex_connection_mixin_mix(vortex, en,
2195 mix[i],
2196 MIX_PLAYB(i), 0);
2197#ifndef CHIP_AU8820
2198 vortex_connection_mixin_mix(vortex, en,
2199 mix[i],
2200 MIX_SPDIF(i % 2), 0);
2201 vortex_mix_setinputvolumebyte(vortex,
2202 MIX_SPDIF(i % 2),
2203 mix[i],
2204 MIX_DEFIGAIN);
2205#endif
2206 }
2207#ifndef CHIP_AU8820
2208 if (stream->type == VORTEX_PCM_A3D) {
2209 vortex_connection_adbdma_src(vortex, en,
2210 src[nr_ch - 1],
2211 dma,
2212 src[i]);
2213 vortex_route(vortex, en, 0x11, ADB_SRCOUT(src[i]), ADB_A3DIN(a3d));
2214 /* XTalk test. */
2215 //vortex_route(vortex, en, 0x11, dma, ADB_XTALKIN(i?9:4));
2216 //vortex_route(vortex, en, 0x11, ADB_SRCOUT(src[i]), ADB_XTALKIN(i?4:9));
2217 }
2218 if (stream->type == VORTEX_PCM_SPDIF)
2219 vortex_route(vortex, en, 0x14,
2220 ADB_DMA(stream->dma),
2221 ADB_SPDIFOUT(i));
2222#endif
2223 }
2224 if (stream->type != VORTEX_PCM_SPDIF && stream->type != VORTEX_PCM_A3D) {
2225 ch_top = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
2226 for (i = nr_ch; i < ch_top; i++) {
2227 vortex_connection_mixin_mix(vortex, en,
2228 mix[i % nr_ch],
2229 MIX_PLAYB(i), 0);
2230#ifndef CHIP_AU8820
2231 vortex_connection_mixin_mix(vortex, en,
2232 mix[i % nr_ch],
2233 MIX_SPDIF(i % 2),
2234 0);
2235 vortex_mix_setinputvolumebyte(vortex,
2236 MIX_SPDIF(i % 2),
2237 mix[i % nr_ch],
2238 MIX_DEFIGAIN);
2239#endif
2240 }
2241 }
2242#ifndef CHIP_AU8820
2243 else {
2244 if (nr_ch == 1 && stream->type == VORTEX_PCM_SPDIF)
2245 vortex_route(vortex, en, 0x14,
2246 ADB_DMA(stream->dma),
2247 ADB_SPDIFOUT(1));
2248 }
2249 /* Reconnect SPDIF out when "spdif" device is down. */
2250 if ((stream->type == VORTEX_PCM_SPDIF) && (!en)) {
2251 vortex_route(vortex, 1, 0x14,
2252 ADB_MIXOUT(vortex->mixspdif[0]),
2253 ADB_SPDIFOUT(0));
2254 vortex_route(vortex, 1, 0x14,
2255 ADB_MIXOUT(vortex->mixspdif[1]),
2256 ADB_SPDIFOUT(1));
2257 }
2258#endif
2259 /* CAPTURE ROUTES. */
2260 } else {
2261 int src[2], mix[2];
2262
2263 /* Get SRC and MIXER hardware resources. */
2264 for (i = 0; i < nr_ch; i++) {
2265 if ((mix[i] =
2266 vortex_adb_checkinout(vortex,
2267 stream->resources, en,
2268 VORTEX_RESOURCE_MIXOUT))
2269 < 0) {
2270 memset(stream->resources, 0,
2271 sizeof(unsigned char) *
2272 VORTEX_RESOURCE_LAST);
2273 return -EBUSY;
2274 }
2275 if ((src[i] =
2276 vortex_adb_checkinout(vortex,
2277 stream->resources, en,
2278 VORTEX_RESOURCE_SRC)) < 0) {
2279 memset(stream->resources, 0,
2280 sizeof(unsigned char) *
2281 VORTEX_RESOURCE_LAST);
2282 return -EBUSY;
2283 }
2284 }
2285
2286 /* Make capture routes. */
2287 vortex_connection_mixin_mix(vortex, en, MIX_CAPT(0), mix[0], 0);
2288 vortex_connection_mix_src(vortex, en, 0x11, mix[0], src[0]);
2289 if (nr_ch == 1) {
2290 vortex_connection_mixin_mix(vortex, en,
2291 MIX_CAPT(1), mix[0], 0);
2292 vortex_connection_src_adbdma(vortex, en,
2293 src[0],
2294 src[0], dma);
2295 } else {
2296 vortex_connection_mixin_mix(vortex, en,
2297 MIX_CAPT(1), mix[1], 0);
2298 vortex_connection_mix_src(vortex, en, 0x11, mix[1],
2299 src[1]);
2300 vortex_connection_src_src_adbdma(vortex, en,
2301 src[1], src[0],
2302 src[1], dma);
2303 }
2304 }
2305 vortex->dma_adb[dma].nr_ch = nr_ch;
2306
2307#if 0
2308 /* AC97 Codec channel setup. FIXME: this has no effect on some cards !! */
2309 if (nr_ch < 4) {
2310 /* Copy stereo to rear channel (surround) */
2311 snd_ac97_write_cache(vortex->codec,
2312 AC97_SIGMATEL_DAC2INVERT,
2313 snd_ac97_read(vortex->codec,
2314 AC97_SIGMATEL_DAC2INVERT)
2315 | 4);
2316 } else {
2317 /* Allow separate front and rear channels. */
2318 snd_ac97_write_cache(vortex->codec,
2319 AC97_SIGMATEL_DAC2INVERT,
2320 snd_ac97_read(vortex->codec,
2321 AC97_SIGMATEL_DAC2INVERT)
2322 & ~((u32)
2323 4));
2324 }
2325#endif
2326 return dma;
2327}
2328
2329/*
2330 Set the SampleRate of the SRC's attached to the given DMA engine.
2331 */
2332static void
2333vortex_adb_setsrc(vortex_t * vortex, int adbdma, unsigned int rate, int dir)
2334{
2335 stream_t *stream = &(vortex->dma_adb[adbdma]);
2336 int i, cvrt;
2337
2338 /* dir=1:play ; dir=0:rec */
2339 if (dir)
2340 cvrt = SRC_RATIO(rate, 48000);
2341 else
2342 cvrt = SRC_RATIO(48000, rate);
2343
2344 /* Setup SRC's */
2345 for (i = 0; i < NR_SRC; i++) {
2346 if (stream->resources[VORTEX_RESOURCE_SRC] & (1 << i))
2347 vortex_src_setupchannel(vortex, i, cvrt, 0, 0, i, dir, 1, cvrt, dir);
2348 }
2349}
2350
2351// Timer and ISR functions.
2352
2353static void vortex_settimer(vortex_t * vortex, int period)
2354{
2355 //set the timer period to <period> 48000ths of a second.
2356 hwwrite(vortex->mmio, VORTEX_IRQ_STAT, period);
2357}
2358
2359#if 0
2360static void vortex_enable_timer_int(vortex_t * card)
2361{
2362 hwwrite(card->mmio, VORTEX_IRQ_CTRL,
2363 hwread(card->mmio, VORTEX_IRQ_CTRL) | IRQ_TIMER | 0x60);
2364}
2365
2366static void vortex_disable_timer_int(vortex_t * card)
2367{
2368 hwwrite(card->mmio, VORTEX_IRQ_CTRL,
2369 hwread(card->mmio, VORTEX_IRQ_CTRL) & ~IRQ_TIMER);
2370}
2371
2372#endif
2373static void vortex_enable_int(vortex_t * card)
2374{
2375 // CAsp4ISR__EnableVortexInt_void_
2376 hwwrite(card->mmio, VORTEX_CTRL,
2377 hwread(card->mmio, VORTEX_CTRL) | CTRL_IRQ_ENABLE);
2378 hwwrite(card->mmio, VORTEX_IRQ_CTRL,
2379 (hwread(card->mmio, VORTEX_IRQ_CTRL) & 0xffffefc0) | 0x24);
2380}
2381
2382static void vortex_disable_int(vortex_t * card)
2383{
2384 hwwrite(card->mmio, VORTEX_CTRL,
2385 hwread(card->mmio, VORTEX_CTRL) & ~CTRL_IRQ_ENABLE);
2386}
2387
2388static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
2389{
2390 vortex_t *vortex = dev_id;
2391 int i, handled;
2392 u32 source;
2393
2394 //check if the interrupt is ours.
2395 if (!(hwread(vortex->mmio, VORTEX_STAT) & 0x1))
2396 return IRQ_NONE;
2397
2398 // This is the Interrrupt Enable flag we set before (consistency check).
2399 if (!(hwread(vortex->mmio, VORTEX_CTRL) & CTRL_IRQ_ENABLE))
2400 return IRQ_NONE;
2401
2402 source = hwread(vortex->mmio, VORTEX_IRQ_SOURCE);
2403 // Reset IRQ flags.
2404 hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, source);
2405 hwread(vortex->mmio, VORTEX_IRQ_SOURCE);
2406 // Is at least one IRQ flag set?
2407 if (source == 0) {
2408 printk(KERN_ERR "vortex: missing irq source\n");
2409 return IRQ_NONE;
2410 }
2411
2412 handled = 0;
2413 // Attend every interrupt source.
2414 if (unlikely(source & IRQ_ERR_MASK)) {
2415 if (source & IRQ_FATAL) {
2416 printk(KERN_ERR "vortex: IRQ fatal error\n");
2417 }
2418 if (source & IRQ_PARITY) {
2419 printk(KERN_ERR "vortex: IRQ parity error\n");
2420 }
2421 if (source & IRQ_REG) {
2422 printk(KERN_ERR "vortex: IRQ reg error\n");
2423 }
2424 if (source & IRQ_FIFO) {
2425 printk(KERN_ERR "vortex: IRQ fifo error\n");
2426 }
2427 if (source & IRQ_DMA) {
2428 printk(KERN_ERR "vortex: IRQ dma error\n");
2429 }
2430 handled = 1;
2431 }
2432 if (source & IRQ_PCMOUT) {
2433 /* ALSA period acknowledge. */
2434 spin_lock(&vortex->lock);
2435 for (i = 0; i < NR_ADB; i++) {
2436 if (vortex->dma_adb[i].fifo_status == FIFO_START) {
2437 if (vortex_adbdma_bufshift(vortex, i)) ;
2438 spin_unlock(&vortex->lock);
2439 snd_pcm_period_elapsed(vortex->dma_adb[i].
2440 substream);
2441 spin_lock(&vortex->lock);
2442 }
2443 }
2444#ifndef CHIP_AU8810
2445 for (i = 0; i < NR_WT; i++) {
2446 if (vortex->dma_wt[i].fifo_status == FIFO_START) {
2447 if (vortex_wtdma_bufshift(vortex, i)) ;
2448 spin_unlock(&vortex->lock);
2449 snd_pcm_period_elapsed(vortex->dma_wt[i].
2450 substream);
2451 spin_lock(&vortex->lock);
2452 }
2453 }
2454#endif
2455 spin_unlock(&vortex->lock);
2456 handled = 1;
2457 }
2458 //Acknowledge the Timer interrupt
2459 if (source & IRQ_TIMER) {
2460 hwread(vortex->mmio, VORTEX_IRQ_STAT);
2461 handled = 1;
2462 }
2463 if (source & IRQ_MIDI) {
2464 snd_mpu401_uart_interrupt(vortex->irq,
2465 vortex->rmidi->private_data, regs);
2466 handled = 1;
2467 }
2468
2469 if (!handled) {
2470 printk(KERN_ERR "vortex: unknown irq source %x\n", source);
2471 }
2472 return IRQ_RETVAL(handled);
2473}
2474
2475/* Codec */
2476
2477#define POLL_COUNT 1000
2478static void vortex_codec_init(vortex_t * vortex)
2479{
2480 int i;
2481
2482 for (i = 0; i < 32; i++) {
2483 /* the windows driver writes -i, so we write -i */
2484 hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), -i);
2485 msleep(2);
2486 }
2487 if (0) {
2488 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x8068);
2489 msleep(1);
2490 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00e8);
2491 msleep(1);
2492 } else {
2493 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00a8);
2494 msleep(2);
2495 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80a8);
2496 msleep(2);
2497 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80e8);
2498 msleep(2);
2499 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80a8);
2500 msleep(2);
2501 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00a8);
2502 msleep(2);
2503 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00e8);
2504 }
2505 for (i = 0; i < 32; i++) {
2506 hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), -i);
2507 msleep(5);
2508 }
2509 hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0xe8);
2510 msleep(1);
2511 /* Enable codec channels 0 and 1. */
2512 hwwrite(vortex->mmio, VORTEX_CODEC_EN,
2513 hwread(vortex->mmio, VORTEX_CODEC_EN) | EN_CODEC);
2514}
2515
2516static void
2517vortex_codec_write(ac97_t * codec, unsigned short addr, unsigned short data)
2518{
2519
2520 vortex_t *card = (vortex_t *) codec->private_data;
2521 unsigned int lifeboat = 0;
2522
2523 /* wait for transactions to clear */
2524 while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
2525 udelay(100);
2526 if (lifeboat++ > POLL_COUNT) {
2527 printk(KERN_ERR "vortex: ac97 codec stuck busy\n");
2528 return;
2529 }
2530 }
2531 /* write register */
2532 hwwrite(card->mmio, VORTEX_CODEC_IO,
2533 ((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK) |
2534 ((data << VORTEX_CODEC_DATSHIFT) & VORTEX_CODEC_DATMASK) |
2535 VORTEX_CODEC_WRITE);
2536
2537 /* Flush Caches. */
2538 hwread(card->mmio, VORTEX_CODEC_IO);
2539}
2540
2541static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr)
2542{
2543
2544 vortex_t *card = (vortex_t *) codec->private_data;
2545 u32 read_addr, data;
2546 unsigned lifeboat = 0;
2547
2548 /* wait for transactions to clear */
2549 while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
2550 udelay(100);
2551 if (lifeboat++ > POLL_COUNT) {
2552 printk(KERN_ERR "vortex: ac97 codec stuck busy\n");
2553 return 0xffff;
2554 }
2555 }
2556 /* set up read address */
2557 read_addr = ((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK);
2558 hwwrite(card->mmio, VORTEX_CODEC_IO, read_addr);
2559
2560 /* wait for address */
2561 do {
2562 udelay(100);
2563 data = hwread(card->mmio, VORTEX_CODEC_IO);
2564 if (lifeboat++ > POLL_COUNT) {
2565 printk(KERN_ERR "vortex: ac97 address never arrived\n");
2566 return 0xffff;
2567 }
2568 } while ((data & VORTEX_CODEC_ADDMASK) !=
2569 (addr << VORTEX_CODEC_ADDSHIFT));
2570
2571 /* return data. */
2572 return (u16) (data & VORTEX_CODEC_DATMASK);
2573}
2574
2575/* SPDIF support */
2576
2577static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode)
2578{
2579 int i, this_38 = 0, this_04 = 0, this_08 = 0, this_0c = 0;
2580
2581 /* CAsp4Spdif::InitializeSpdifHardware(void) */
2582 hwwrite(vortex->mmio, VORTEX_SPDIF_FLAGS,
2583 hwread(vortex->mmio, VORTEX_SPDIF_FLAGS) & 0xfff3fffd);
2584 //for (i=0x291D4; i<0x29200; i+=4)
2585 for (i = 0; i < 11; i++)
2586 hwwrite(vortex->mmio, VORTEX_SPDIF_CFG1 + (i << 2), 0);
2587 //hwwrite(vortex->mmio, 0x29190, hwread(vortex->mmio, 0x29190) | 0xc0000);
2588 hwwrite(vortex->mmio, VORTEX_CODEC_EN,
2589 hwread(vortex->mmio, VORTEX_CODEC_EN) | EN_SPDIF);
2590
2591 /* CAsp4Spdif::ProgramSRCInHardware(enum SPDIF_SR,enum SPDIFMODE) */
2592 if (this_04 && this_08) {
2593 int edi;
2594
2595 i = (((0x5DC00000 / spdif_sr) + 1) >> 1);
2596 if (i > 0x800) {
2597 if (i < 0x1ffff)
2598 edi = (i >> 1);
2599 else
2600 edi = 0x1ffff;
2601 } else {
2602 i = edi = 0x800;
2603 }
2604 /* this_04 and this_08 are the CASp4Src's (samplerate converters) */
2605 vortex_src_setupchannel(vortex, this_04, edi, 0, 1,
2606 this_0c, 1, 0, edi, 1);
2607 vortex_src_setupchannel(vortex, this_08, edi, 0, 1,
2608 this_0c, 1, 0, edi, 1);
2609 }
2610
2611 i = spdif_sr;
2612 spdif_sr |= 0x8c;
2613 switch (i) {
2614 case 32000:
2615 this_38 &= 0xFFFFFFFE;
2616 this_38 &= 0xFFFFFFFD;
2617 this_38 &= 0xF3FFFFFF;
2618 this_38 |= 0x03000000; /* set 32khz samplerate */
2619 this_38 &= 0xFFFFFF3F;
2620 spdif_sr &= 0xFFFFFFFD;
2621 spdif_sr |= 1;
2622 break;
2623 case 44100:
2624 this_38 &= 0xFFFFFFFE;
2625 this_38 &= 0xFFFFFFFD;
2626 this_38 &= 0xF0FFFFFF;
2627 this_38 |= 0x03000000;
2628 this_38 &= 0xFFFFFF3F;
2629 spdif_sr &= 0xFFFFFFFC;
2630 break;
2631 case 48000:
2632 if (spdif_mode == 1) {
2633 this_38 &= 0xFFFFFFFE;
2634 this_38 &= 0xFFFFFFFD;
2635 this_38 &= 0xF2FFFFFF;
2636 this_38 |= 0x02000000; /* set 48khz samplerate */
2637 this_38 &= 0xFFFFFF3F;
2638 } else {
2639 /* J. Gordon Wolfe: I think this stuff is for AC3 */
2640 this_38 |= 0x00000003;
2641 this_38 &= 0xFFFFFFBF;
2642 this_38 |= 0x80;
2643 }
2644 spdif_sr |= 2;
2645 spdif_sr &= 0xFFFFFFFE;
2646 break;
2647
2648 }
2649 /* looks like the next 2 lines transfer a 16-bit value into 2 8-bit
2650 registers. seems to be for the standard IEC/SPDIF initialization
2651 stuff */
2652 hwwrite(vortex->mmio, VORTEX_SPDIF_CFG0, this_38 & 0xffff);
2653 hwwrite(vortex->mmio, VORTEX_SPDIF_CFG1, this_38 >> 0x10);
2654 hwwrite(vortex->mmio, VORTEX_SPDIF_SMPRATE, spdif_sr);
2655}
2656
2657/* Initialization */
2658
2659static int vortex_core_init(vortex_t * vortex)
2660{
2661
2662 printk(KERN_INFO "Vortex: init.... ");
2663 /* Hardware Init. */
2664 hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff);
2665 msleep(5);
2666 hwwrite(vortex->mmio, VORTEX_CTRL,
2667 hwread(vortex->mmio, VORTEX_CTRL) & 0xffdfffff);
2668 msleep(5);
2669 /* Reset IRQ flags */
2670 hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffffffff);
2671 hwread(vortex->mmio, VORTEX_IRQ_STAT);
2672
2673 vortex_codec_init(vortex);
2674
2675#ifdef CHIP_AU8830
2676 hwwrite(vortex->mmio, VORTEX_CTRL,
2677 hwread(vortex->mmio, VORTEX_CTRL) | 0x1000000);
2678#endif
2679
2680 /* Init audio engine. */
2681 vortex_adbdma_init(vortex);
2682 hwwrite(vortex->mmio, VORTEX_ENGINE_CTRL, 0x0); //, 0xc83c7e58, 0xc5f93e58
2683 vortex_adb_init(vortex);
2684 /* Init processing blocks. */
2685 vortex_fifo_init(vortex);
2686 vortex_mixer_init(vortex);
2687 vortex_srcblock_init(vortex);
2688#ifndef CHIP_AU8820
2689 vortex_eq_init(vortex);
2690 vortex_spdif_init(vortex, 48000, 1);
2691 vortex_Vort3D(vortex, 1);
2692#endif
2693#ifndef CHIP_AU8810
2694 vortex_wt_init(vortex);
2695#endif
2696 // Moved to au88x0.c
2697 //vortex_connect_default(vortex, 1);
2698
2699 vortex_settimer(vortex, 0x90);
2700 // Enable Interrupts.
2701 // vortex_enable_int() must be first !!
2702 // hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, 0);
2703 // vortex_enable_int(vortex);
2704 //vortex_enable_timer_int(vortex);
2705 //vortex_disable_timer_int(vortex);
2706
2707 printk(KERN_INFO "done.\n");
2708 spin_lock_init(&vortex->lock);
2709
2710 return 0;
2711}
2712
2713static int vortex_core_shutdown(vortex_t * vortex)
2714{
2715
2716 printk(KERN_INFO "Vortex: shutdown...");
2717#ifndef CHIP_AU8820
2718 vortex_eq_free(vortex);
2719 vortex_Vort3D(vortex, 0);
2720#endif
2721 //vortex_disable_timer_int(vortex);
2722 vortex_disable_int(vortex);
2723 vortex_connect_default(vortex, 0);
2724 /* Reset all DMA fifos. */
2725 vortex_fifo_init(vortex);
2726 /* Erase all audio routes. */
2727 vortex_adb_init(vortex);
2728
2729 /* Disable MPU401 */
2730 //hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, hwread(vortex->mmio, VORTEX_IRQ_CTRL) & ~IRQ_MIDI);
2731 //hwwrite(vortex->mmio, VORTEX_CTRL, hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_EN);
2732
2733 hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, 0);
2734 hwwrite(vortex->mmio, VORTEX_CTRL, 0);
2735 msleep(5);
2736 hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff);
2737
2738 printk(KERN_INFO "done.\n");
2739 return 0;
2740}
2741
2742/* Alsa support. */
2743
2744static int vortex_alsafmt_aspfmt(int alsafmt)
2745{
2746 int fmt;
2747
2748 switch (alsafmt) {
2749 case SNDRV_PCM_FORMAT_U8:
2750 fmt = 0x1;
2751 break;
2752 case SNDRV_PCM_FORMAT_MU_LAW:
2753 fmt = 0x2;
2754 break;
2755 case SNDRV_PCM_FORMAT_A_LAW:
2756 fmt = 0x3;
2757 break;
2758 case SNDRV_PCM_FORMAT_SPECIAL:
2759 fmt = 0x4; /* guess. */
2760 break;
2761 case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
2762 fmt = 0x5; /* guess. */
2763 break;
2764 case SNDRV_PCM_FORMAT_S16_LE:
2765 fmt = 0x8;
2766 break;
2767 case SNDRV_PCM_FORMAT_S16_BE:
2768 fmt = 0x9; /* check this... */
2769 break;
2770 default:
2771 fmt = 0x8;
2772 printk(KERN_ERR "vortex: format unsupported %d\n", alsafmt);
2773 break;
2774 }
2775 return fmt;
2776}
2777
2778/* Some not yet useful translations. */
2779#if 0
2780typedef enum {
2781 ASPFMTLINEAR16 = 0, /* 0x8 */
2782 ASPFMTLINEAR8, /* 0x1 */
2783 ASPFMTULAW, /* 0x2 */
2784 ASPFMTALAW, /* 0x3 */
2785 ASPFMTSPORT, /* ? */
2786 ASPFMTSPDIF, /* ? */
2787} ASPENCODING;
2788
2789static int
2790vortex_translateformat(vortex_t * vortex, char bits, char nch, int encod)
2791{
2792 int a, this_194;
2793
2794 if ((bits != 8) || (bits != 16))
2795 return -1;
2796
2797 switch (encod) {
2798 case 0:
2799 if (bits == 0x10)
2800 a = 8; // 16 bit
2801 break;
2802 case 1:
2803 if (bits == 8)
2804 a = 1; // 8 bit
2805 break;
2806 case 2:
2807 a = 2; // U_LAW
2808 break;
2809 case 3:
2810 a = 3; // A_LAW
2811 break;
2812 }
2813 switch (nch) {
2814 case 1:
2815 this_194 = 0;
2816 break;
2817 case 2:
2818 this_194 = 1;
2819 break;
2820 case 4:
2821 this_194 = 1;
2822 break;
2823 case 6:
2824 this_194 = 1;
2825 break;
2826 }
2827 return (a);
2828}
2829
2830static void vortex_cdmacore_setformat(vortex_t * vortex, int bits, int nch)
2831{
2832 short int d, this_148;
2833
2834 d = ((bits >> 3) * nch);
2835 this_148 = 0xbb80 / d;
2836}
2837#endif
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
new file mode 100644
index 000000000000..53b47a42c7d8
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -0,0 +1,937 @@
1/***************************************************************************
2 * au88x0_eq.c
3 * Aureal Vortex Hardware EQ control/access.
4 *
5 * Sun Jun 8 18:19:19 2003
6 * 2003 Manuel Jander (mjander@users.sourceforge.net)
7 *
8 * 02 July 2003: First time something works :)
9 * November 2003: A3D Bypass code completed but untested.
10 *
11 * TODO:
12 * - Debug (testing)
13 * - Test peak visualization support.
14 *
15 ****************************************************************************/
16
17/*
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU Library General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 */
32
33/*
34 The Aureal Hardware EQ is found on AU8810 and AU8830 chips only.
35 it has 4 inputs (2 for general mix, 2 for A3D) and 2 outputs (supposed
36 to be routed to the codec).
37*/
38
39#include "au88x0.h"
40#include "au88x0_eq.h"
41#include "au88x0_eqdata.c"
42
43#define VORTEX_EQ_BASE 0x2b000
44#define VORTEX_EQ_DEST (VORTEX_EQ_BASE + 0x410)
45#define VORTEX_EQ_SOURCE (VORTEX_EQ_BASE + 0x430)
46#define VORTEX_EQ_CTRL (VORTEX_EQ_BASE + 0x440)
47
48#define VORTEX_BAND_COEFF_SIZE 0x30
49
50/* CEqHw.s */
51static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 gain, u16 level)
52{
53 hwwrite(vortex->mmio, 0x2b3c4, gain);
54 hwwrite(vortex->mmio, 0x2b3c8, level);
55}
56
57static inline u16 sign_invert(u16 a)
58{
59 /* -(-32768) -> -32768 so we do -(-32768) -> 32767 to make the result positive */
60 if (a == (u16)-32768)
61 return 32767;
62 else
63 return -a;
64}
65
66static void vortex_EqHw_SetLeftCoefs(vortex_t * vortex, u16 coefs[])
67{
68 eqhw_t *eqhw = &(vortex->eq.this04);
69 int i = 0, n /*esp2c */;
70
71 for (n = 0; n < eqhw->this04; n++) {
72 hwwrite(vortex->mmio, 0x2b000 + n * 0x30, coefs[i + 0]);
73 hwwrite(vortex->mmio, 0x2b004 + n * 0x30, coefs[i + 1]);
74
75 if (eqhw->this08 == 0) {
76 hwwrite(vortex->mmio, 0x2b008 + n * 0x30, coefs[i + 2]);
77 hwwrite(vortex->mmio, 0x2b00c + n * 0x30, coefs[i + 3]);
78 hwwrite(vortex->mmio, 0x2b010 + n * 0x30, coefs[i + 4]);
79 } else {
80 hwwrite(vortex->mmio, 0x2b008 + n * 0x30, sign_invert(coefs[2 + i]));
81 hwwrite(vortex->mmio, 0x2b00c + n * 0x30, sign_invert(coefs[3 + i]));
82 hwwrite(vortex->mmio, 0x2b010 + n * 0x30, sign_invert(coefs[4 + i]));
83 }
84 i += 5;
85 }
86}
87
88static void vortex_EqHw_SetRightCoefs(vortex_t * vortex, u16 coefs[])
89{
90 eqhw_t *eqhw = &(vortex->eq.this04);
91 int i = 0, n /*esp2c */;
92
93 for (n = 0; n < eqhw->this04; n++) {
94 hwwrite(vortex->mmio, 0x2b1e0 + n * 0x30, coefs[0 + i]);
95 hwwrite(vortex->mmio, 0x2b1e4 + n * 0x30, coefs[1 + i]);
96
97 if (eqhw->this08 == 0) {
98 hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, coefs[2 + i]);
99 hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, coefs[3 + i]);
100 hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, coefs[4 + i]);
101 } else {
102 hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, sign_invert(coefs[2 + i]));
103 hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, sign_invert(coefs[3 + i]));
104 hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, sign_invert(coefs[4 + i]));
105 }
106 i += 5;
107 }
108
109}
110
111static void vortex_EqHw_SetLeftStates(vortex_t * vortex, u16 a[], u16 b[])
112{
113 eqhw_t *eqhw = &(vortex->eq.this04);
114 int i = 0, ebx;
115
116 hwwrite(vortex->mmio, 0x2b3fc, a[0]);
117 hwwrite(vortex->mmio, 0x2b400, a[1]);
118
119 for (ebx = 0; ebx < eqhw->this04; ebx++) {
120 hwwrite(vortex->mmio, 0x2b014 + (i * 0xc), b[i]);
121 hwwrite(vortex->mmio, 0x2b018 + (i * 0xc), b[1 + i]);
122 hwwrite(vortex->mmio, 0x2b01c + (i * 0xc), b[2 + i]);
123 hwwrite(vortex->mmio, 0x2b020 + (i * 0xc), b[3 + i]);
124 i += 4;
125 }
126}
127
128static void vortex_EqHw_SetRightStates(vortex_t * vortex, u16 a[], u16 b[])
129{
130 eqhw_t *eqhw = &(vortex->eq.this04);
131 int i = 0, ebx;
132
133 hwwrite(vortex->mmio, 0x2b404, a[0]);
134 hwwrite(vortex->mmio, 0x2b408, a[1]);
135
136 for (ebx = 0; ebx < eqhw->this04; ebx++) {
137 hwwrite(vortex->mmio, 0x2b1f4 + (i * 0xc), b[i]);
138 hwwrite(vortex->mmio, 0x2b1f8 + (i * 0xc), b[1 + i]);
139 hwwrite(vortex->mmio, 0x2b1fc + (i * 0xc), b[2 + i]);
140 hwwrite(vortex->mmio, 0x2b200 + (i * 0xc), b[3 + i]);
141 i += 4;
142 }
143}
144
145#if 0
146static void vortex_EqHw_GetTimeConsts(vortex_t * vortex, u16 * a, u16 * b)
147{
148 *a = hwread(vortex->mmio, 0x2b3c4);
149 *b = hwread(vortex->mmio, 0x2b3c8);
150}
151
152static void vortex_EqHw_GetLeftCoefs(vortex_t * vortex, u16 a[])
153{
154
155}
156
157static void vortex_EqHw_GetRightCoefs(vortex_t * vortex, u16 a[])
158{
159
160}
161
162static void vortex_EqHw_GetLeftStates(vortex_t * vortex, u16 * a, u16 b[])
163{
164
165}
166
167static void vortex_EqHw_GetRightStates(vortex_t * vortex, u16 * a, u16 b[])
168{
169
170}
171
172#endif
173/* Mix Gains */
174static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b)
175{
176 eqhw_t *eqhw = &(vortex->eq.this04);
177 if (eqhw->this08 == 0) {
178 hwwrite(vortex->mmio, 0x2b3d4, a);
179 hwwrite(vortex->mmio, 0x2b3ec, b);
180 } else {
181 hwwrite(vortex->mmio, 0x2b3d4, sign_invert(a));
182 hwwrite(vortex->mmio, 0x2b3ec, sign_invert(b));
183 }
184}
185
186static void vortex_EqHw_SetA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
187{
188
189 hwwrite(vortex->mmio, 0x2b3e0, a);
190 hwwrite(vortex->mmio, 0x2b3f8, b);
191}
192
193#if 0
194static void vortex_EqHw_SetCurrBypassGain(vortex_t * vortex, u16 a, u16 b)
195{
196
197 hwwrite(vortex->mmio, 0x2b3d0, a);
198 hwwrite(vortex->mmio, 0x2b3e8, b);
199}
200
201static void vortex_EqHw_SetCurrA3DBypassGain(vortex_t * vortex, u16 a, u16 b)
202{
203
204 hwwrite(vortex->mmio, 0x2b3dc, a);
205 hwwrite(vortex->mmio, 0x2b3f4, b);
206}
207
208#endif
209static void
210vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
211{
212 hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b);
213}
214
215static void
216vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b)
217{
218 hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b);
219}
220
221static void vortex_EqHw_SetLeftGainsTarget(vortex_t * vortex, u16 a[])
222{
223 eqhw_t *eqhw = &(vortex->eq.this04);
224 int ebx;
225
226 for (ebx = 0; ebx < eqhw->this04; ebx++) {
227 hwwrite(vortex->mmio, 0x2b02c + ebx * 0x30, a[ebx]);
228 }
229}
230
231static void vortex_EqHw_SetRightGainsTarget(vortex_t * vortex, u16 a[])
232{
233 eqhw_t *eqhw = &(vortex->eq.this04);
234 int ebx;
235
236 for (ebx = 0; ebx < eqhw->this04; ebx++) {
237 hwwrite(vortex->mmio, 0x2b20c + ebx * 0x30, a[ebx]);
238 }
239}
240
241static void vortex_EqHw_SetLeftGainsCurrent(vortex_t * vortex, u16 a[])
242{
243 eqhw_t *eqhw = &(vortex->eq.this04);
244 int ebx;
245
246 for (ebx = 0; ebx < eqhw->this04; ebx++) {
247 hwwrite(vortex->mmio, 0x2b028 + ebx * 0x30, a[ebx]);
248 }
249}
250
251static void vortex_EqHw_SetRightGainsCurrent(vortex_t * vortex, u16 a[])
252{
253 eqhw_t *eqhw = &(vortex->eq.this04);
254 int ebx;
255
256 for (ebx = 0; ebx < eqhw->this04; ebx++) {
257 hwwrite(vortex->mmio, 0x2b208 + ebx * 0x30, a[ebx]);
258 }
259}
260
261#if 0
262static void vortex_EqHw_GetLeftGainsTarget(vortex_t * vortex, u16 a[])
263{
264 eqhw_t *eqhw = &(vortex->eq.this04);
265 int ebx = 0;
266
267 if (eqhw->this04 < 0)
268 return;
269
270 do {
271 a[ebx] = hwread(vortex->mmio, 0x2b02c + ebx * 0x30);
272 ebx++;
273 }
274 while (ebx < eqhw->this04);
275}
276
277static void vortex_EqHw_GetRightGainsTarget(vortex_t * vortex, u16 a[])
278{
279 eqhw_t *eqhw = &(vortex->eq.this04);
280 int ebx = 0;
281
282 if (eqhw->this04 < 0)
283 return;
284
285 do {
286 a[ebx] = hwread(vortex->mmio, 0x2b20c + ebx * 0x30);
287 ebx++;
288 }
289 while (ebx < eqhw->this04);
290}
291
292static void vortex_EqHw_GetLeftGainsCurrent(vortex_t * vortex, u16 a[])
293{
294 eqhw_t *eqhw = &(vortex->eq.this04);
295 int ebx = 0;
296
297 if (eqhw->this04 < 0)
298 return;
299
300 do {
301 a[ebx] = hwread(vortex->mmio, 0x2b028 + ebx * 0x30);
302 ebx++;
303 }
304 while (ebx < eqhw->this04);
305}
306
307static void vortex_EqHw_GetRightGainsCurrent(vortex_t * vortex, u16 a[])
308{
309 eqhw_t *eqhw = &(vortex->eq.this04);
310 int ebx = 0;
311
312 if (eqhw->this04 < 0)
313 return;
314
315 do {
316 a[ebx] = hwread(vortex->mmio, 0x2b208 + ebx * 0x30);
317 ebx++;
318 }
319 while (ebx < eqhw->this04);
320}
321
322#endif
323/* EQ band levels settings */
324static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 peaks[])
325{
326 eqhw_t *eqhw = &(vortex->eq.this04);
327 int i;
328
329 /* set left peaks */
330 for (i = 0; i < eqhw->this04; i++) {
331 hwwrite(vortex->mmio, 0x2b024 + i * VORTEX_BAND_COEFF_SIZE, peaks[i]);
332 }
333
334 hwwrite(vortex->mmio, 0x2b3cc, peaks[eqhw->this04]);
335 hwwrite(vortex->mmio, 0x2b3d8, peaks[eqhw->this04 + 1]);
336
337 /* set right peaks */
338 for (i = 0; i < eqhw->this04; i++) {
339 hwwrite(vortex->mmio, 0x2b204 + i * VORTEX_BAND_COEFF_SIZE,
340 peaks[i + (eqhw->this04 + 2)]);
341 }
342
343 hwwrite(vortex->mmio, 0x2b3e4, peaks[2 + (eqhw->this04 * 2)]);
344 hwwrite(vortex->mmio, 0x2b3f0, peaks[3 + (eqhw->this04 * 2)]);
345}
346
347#if 0
348static void vortex_EqHw_GetLevels(vortex_t * vortex, u16 a[])
349{
350 eqhw_t *eqhw = &(vortex->eq.this04);
351 int ebx;
352
353 if (eqhw->this04 < 0)
354 return;
355
356 ebx = 0;
357 do {
358 a[ebx] = hwread(vortex->mmio, 0x2b024 + ebx * 0x30);
359 ebx++;
360 }
361 while (ebx < eqhw->this04);
362
363 a[eqhw->this04] = hwread(vortex->mmio, 0x2b3cc);
364 a[eqhw->this04 + 1] = hwread(vortex->mmio, 0x2b3d8);
365
366 ebx = 0;
367 do {
368 a[ebx + (eqhw->this04 + 2)] =
369 hwread(vortex->mmio, 0x2b204 + ebx * 0x30);
370 ebx++;
371 }
372 while (ebx < eqhw->this04);
373
374 a[2 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3e4);
375 a[3 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3f0);
376}
377
378#endif
379/* Global Control */
380static void vortex_EqHw_SetControlReg(vortex_t * vortex, unsigned long reg)
381{
382 hwwrite(vortex->mmio, 0x2b440, reg);
383}
384
385static void vortex_EqHw_SetSampleRate(vortex_t * vortex, int sr)
386{
387 hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800);
388}
389
390#if 0
391static void vortex_EqHw_GetControlReg(vortex_t * vortex, unsigned long *reg)
392{
393 *reg = hwread(vortex->mmio, 0x2b440);
394}
395
396static void vortex_EqHw_GetSampleRate(vortex_t * vortex, int *sr)
397{
398 *sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f;
399}
400
401#endif
402static void vortex_EqHw_Enable(vortex_t * vortex)
403{
404 hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf001);
405}
406
407static void vortex_EqHw_Disable(vortex_t * vortex)
408{
409 hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf000);
410}
411
412/* Reset (zero) buffers */
413static void vortex_EqHw_ZeroIO(vortex_t * vortex)
414{
415 int i;
416 for (i = 0; i < 0x8; i++)
417 hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
418 for (i = 0; i < 0x4; i++)
419 hwwrite(vortex->mmio, VORTEX_EQ_SOURCE + (i << 2), 0x0);
420}
421
422static void vortex_EqHw_ZeroA3DIO(vortex_t * vortex)
423{
424 int i;
425 for (i = 0; i < 0x4; i++)
426 hwwrite(vortex->mmio, VORTEX_EQ_DEST + (i << 2), 0x0);
427}
428
429static void vortex_EqHw_ZeroState(vortex_t * vortex)
430{
431
432 vortex_EqHw_SetControlReg(vortex, 0);
433 vortex_EqHw_ZeroIO(vortex);
434 hwwrite(vortex->mmio, 0x2b3c0, 0);
435
436 vortex_EqHw_SetTimeConsts(vortex, 0, 0);
437
438 vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros);
439 vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros);
440
441 vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero);
442 vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero);
443 vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero);
444 vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero);
445
446 vortex_EqHw_SetBypassGain(vortex, 0, 0);
447 //vortex_EqHw_SetCurrBypassGain(vortex, 0, 0);
448 vortex_EqHw_SetA3DBypassGain(vortex, 0, 0);
449 //vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0);
450 vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros);
451 vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros);
452 vortex_EqHw_SetLevels(vortex, (u16 *) eq_levels);
453}
454
455/* Program coeficients as pass through */
456static void vortex_EqHw_ProgramPipe(vortex_t * vortex)
457{
458 vortex_EqHw_SetTimeConsts(vortex, 0, 0);
459
460 vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes);
461 vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes);
462
463 vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current);
464 vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current);
465 vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current);
466 vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_current);
467}
468
469/* Program EQ block as 10 band Equalizer */
470static void
471vortex_EqHw_Program10Band(vortex_t * vortex, auxxEqCoeffSet_t * coefset)
472{
473
474 vortex_EqHw_SetTimeConsts(vortex, 0xc, 0x7fe0);
475
476 vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs);
477 vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs);
478
479 vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains);
480
481 vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains);
482 vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains);
483
484 vortex_EqHw_SetRightGainsCurrent(vortex, coefset->RightGains);
485}
486
487/* Read all EQ peaks. (think VU meter) */
488static void vortex_EqHw_GetTenBandLevels(vortex_t * vortex, u16 peaks[])
489{
490 eqhw_t *eqhw = &(vortex->eq.this04);
491 int i;
492
493 if (eqhw->this04 <= 0)
494 return;
495
496 for (i = 0; i < eqhw->this04; i++)
497 peaks[i] = hwread(vortex->mmio, 0x2B024 + i * 0x30);
498 for (i = 0; i < eqhw->this04; i++)
499 peaks[i + eqhw->this04] =
500 hwread(vortex->mmio, 0x2B204 + i * 0x30);
501}
502
503/* CEqlzr.s */
504
505static int vortex_Eqlzr_GetLeftGain(vortex_t * vortex, u16 index, u16 * gain)
506{
507 eqlzr_t *eq = &(vortex->eq);
508
509 if (eq->this28) {
510 *gain = eq->this130[index];
511 return 0;
512 }
513 return 1;
514}
515
516static void vortex_Eqlzr_SetLeftGain(vortex_t * vortex, u16 index, u16 gain)
517{
518 eqlzr_t *eq = &(vortex->eq);
519
520 if (eq->this28 == 0)
521 return;
522
523 eq->this130[index] = gain;
524 if (eq->this54)
525 return;
526
527 vortex_EqHw_SetLeftGainsSingleTarget(vortex, index, gain);
528}
529
530static int vortex_Eqlzr_GetRightGain(vortex_t * vortex, u16 index, u16 * gain)
531{
532 eqlzr_t *eq = &(vortex->eq);
533
534 if (eq->this28) {
535 *gain = eq->this130[index + eq->this10];
536 return 0;
537 }
538 return 1;
539}
540
541static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain)
542{
543 eqlzr_t *eq = &(vortex->eq);
544
545 if (eq->this28 == 0)
546 return;
547
548 eq->this130[index + eq->this10] = gain;
549 if (eq->this54)
550 return;
551
552 vortex_EqHw_SetRightGainsSingleTarget(vortex, index, gain);
553}
554
555#if 0
556static int
557vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, unsigned long *cnt)
558{
559 eqlzr_t *eq = &(vortex->eq);
560 int si = 0;
561
562 if (eq->this10 == 0)
563 return 1;
564
565 {
566 if (vortex_Eqlzr_GetLeftGain(vortex, si, &gains[si]))
567 return 1;
568 if (vortex_Eqlzr_GetRightGain
569 (vortex, si, &gains[si + eq->this10]))
570 return 1;
571 si++;
572 }
573 while (eq->this10 > si) ;
574 *cnt = si * 2;
575 return 0;
576}
577#endif
578static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex)
579{
580 eqlzr_t *eq = &(vortex->eq);
581
582 vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130);
583 vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10]));
584
585 return 0;
586}
587
588static int
589vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], unsigned long count)
590{
591 eqlzr_t *eq = &(vortex->eq);
592 int i;
593
594 if (((eq->this10) * 2 != count) || (eq->this28 == 0))
595 return 1;
596
597 for (i = 0; i < count; i++) {
598 eq->this130[i] = gains[i];
599 }
600
601 if (eq->this54)
602 return 0;
603 return vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
604}
605
606static void
607vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, unsigned long a,
608 unsigned long b)
609{
610 eqlzr_t *eq = &(vortex->eq);
611 int eax, ebx;
612
613 eq->this58 = a;
614 eq->this5c = b;
615 if (eq->this54)
616 eax = eq->this0e;
617 else
618 eax = eq->this0a;
619 ebx = (eax * eq->this58) >> 0x10;
620 eax = (eax * eq->this5c) >> 0x10;
621 vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
622}
623
624static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex)
625{
626 eqlzr_t *eq = &(vortex->eq);
627 int eax, ebx;
628
629 if (eq->this54)
630 eax = eq->this0e;
631 else
632 eax = eq->this0a;
633 ebx = (eax * eq->this58) >> 0x10;
634 eax = (eax * eq->this5c) >> 0x10;
635 vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax);
636}
637
638static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex)
639{
640 if (vortex != NULL)
641 vortex_EqHw_ZeroA3DIO(vortex);
642}
643
644static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp)
645{
646 eqlzr_t *eq = &(vortex->eq);
647
648 if ((eq->this28) && (bp == 0)) {
649 /* EQ enabled */
650 vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex);
651 vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
652 } else {
653 /* EQ disabled. */
654 vortex_EqHw_SetLeftGainsTarget(vortex, (u16 *) (eq->this14));
655 vortex_EqHw_SetRightGainsTarget(vortex, (u16 *) (eq->this14));
656 vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
657 }
658 vortex_Eqlzr_ProgramA3dBypassGain(vortex);
659}
660
661static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex)
662{
663 eqlzr_t *eq = &(vortex->eq);
664
665 /* Set EQ BiQuad filter coeficients */
666 memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t));
667 /* Set EQ Band gain levels and dump into hardware registers. */
668 vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2);
669}
670
671static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count)
672{
673 eqlzr_t *eq = &(vortex->eq);
674
675 if (eq->this10 == 0)
676 return 1;
677 *count = eq->this10 * 2;
678 vortex_EqHw_GetTenBandLevels(vortex, peaks);
679 return 0;
680}
681
682#if 0
683static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex)
684{
685 eqlzr_t *eq = &(vortex->eq);
686
687 return (&(eq->coefset));
688}
689#endif
690static void vortex_Eqlzr_init(vortex_t * vortex)
691{
692 eqlzr_t *eq = &(vortex->eq);
693
694 /* Object constructor */
695 //eq->this04 = 0;
696 eq->this08 = 0; /* Bypass gain with EQ in use. */
697 eq->this0a = 0x5999;
698 eq->this0c = 0x5999; /* Bypass gain with EQ disabled. */
699 eq->this0e = 0x5999;
700
701 eq->this10 = 0xa; /* 10 eq frequency bands. */
702 eq->this04.this04 = eq->this10;
703 eq->this28 = 0x1; /* if 1 => Allow read access to this130 (gains) */
704 eq->this54 = 0x0; /* if 1 => Dont Allow access to hardware (gains) */
705 eq->this58 = 0xffff;
706 eq->this5c = 0xffff;
707
708 /* Set gains. */
709 memset(eq->this14, 0, 2 * 10);
710
711 /* Actual init. */
712 vortex_EqHw_ZeroState(vortex);
713 vortex_EqHw_SetSampleRate(vortex, 0x11);
714 vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex);
715
716 vortex_EqHw_Program10Band(vortex, &(eq->coefset));
717 vortex_Eqlzr_SetBypass(vortex, eq->this54);
718 vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0);
719 vortex_EqHw_Enable(vortex);
720}
721
722static void vortex_Eqlzr_shutdown(vortex_t * vortex)
723{
724 vortex_Eqlzr_ShutDownA3d(vortex);
725 vortex_EqHw_ProgramPipe(vortex);
726 vortex_EqHw_Disable(vortex);
727}
728
729/* ALSA interface */
730
731/* Control interface */
732static int
733snd_vortex_eqtoggle_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
734{
735 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
736 uinfo->count = 1;
737 uinfo->value.integer.min = 0;
738 uinfo->value.integer.max = 1;
739 return 0;
740}
741
742static int
743snd_vortex_eqtoggle_get(snd_kcontrol_t * kcontrol,
744 snd_ctl_elem_value_t * ucontrol)
745{
746 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
747 eqlzr_t *eq = &(vortex->eq);
748 //int i = kcontrol->private_value;
749
750 ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1;
751
752 return 0;
753}
754
755static int
756snd_vortex_eqtoggle_put(snd_kcontrol_t * kcontrol,
757 snd_ctl_elem_value_t * ucontrol)
758{
759 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
760 eqlzr_t *eq = &(vortex->eq);
761 //int i = kcontrol->private_value;
762
763 eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1;
764 vortex_Eqlzr_SetBypass(vortex, eq->this54);
765
766 return 1; /* Allways changes */
767}
768
769static snd_kcontrol_new_t vortex_eqtoggle_kcontrol __devinitdata = {
770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
771 .name = "EQ Enable",
772 .index = 0,
773 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
774 .private_value = 0,
775 .info = snd_vortex_eqtoggle_info,
776 .get = snd_vortex_eqtoggle_get,
777 .put = snd_vortex_eqtoggle_put
778};
779
780static int
781snd_vortex_eq_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
782{
783 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
784 uinfo->count = 2;
785 uinfo->value.integer.min = 0x0000;
786 uinfo->value.integer.max = 0x7fff;
787 return 0;
788}
789
790static int
791snd_vortex_eq_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
792{
793 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
794 int i = kcontrol->private_value;
795 u16 gainL, gainR;
796
797 vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
798 vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
799 ucontrol->value.integer.value[0] = gainL;
800 ucontrol->value.integer.value[1] = gainR;
801 return 0;
802}
803
804static int
805snd_vortex_eq_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
806{
807 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
808 int changed = 0, i = kcontrol->private_value;
809 u16 gainL, gainR;
810
811 vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
812 vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
813
814 if (gainL != ucontrol->value.integer.value[0]) {
815 vortex_Eqlzr_SetLeftGain(vortex, i,
816 ucontrol->value.integer.value[0]);
817 changed = 1;
818 }
819 if (gainR != ucontrol->value.integer.value[1]) {
820 vortex_Eqlzr_SetRightGain(vortex, i,
821 ucontrol->value.integer.value[1]);
822 changed = 1;
823 }
824 return changed;
825}
826
827static snd_kcontrol_new_t vortex_eq_kcontrol __devinitdata = {
828 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
829 .name = " .",
830 .index = 0,
831 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
832 .private_value = 0,
833 .info = snd_vortex_eq_info,
834 .get = snd_vortex_eq_get,
835 .put = snd_vortex_eq_put
836};
837
838static int
839snd_vortex_peaks_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
840{
841 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
842 uinfo->count = 20;
843 uinfo->value.integer.min = 0x0000;
844 uinfo->value.integer.max = 0x7fff;
845 return 0;
846}
847
848static int
849snd_vortex_peaks_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
850{
851 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
852 int i, count;
853 u16 peaks[20];
854
855 vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
856 if (count != 20) {
857 printk("vortex: peak count error 20 != %d \n", count);
858 return -1;
859 }
860 for (i = 0; i < 20; i++)
861 ucontrol->value.integer.value[i] = peaks[i];
862
863 return 0;
864}
865
866static snd_kcontrol_new_t vortex_levels_kcontrol __devinitdata = {
867 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
868 .name = "EQ Peaks",
869 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
870 .info = snd_vortex_peaks_info,
871 .get = snd_vortex_peaks_get,
872};
873
874/* EQ band gain labels. */
875static char *EqBandLabels[10] __devinitdata = {
876 "EQ0 31Hz\0",
877 "EQ1 63Hz\0",
878 "EQ2 125Hz\0",
879 "EQ3 250Hz\0",
880 "EQ4 500Hz\0",
881 "EQ5 1KHz\0",
882 "EQ6 2KHz\0",
883 "EQ7 4KHz\0",
884 "EQ8 8KHz\0",
885 "EQ9 16KHz\0",
886};
887
888/* ALSA driver entry points. Init and exit. */
889static int vortex_eq_init(vortex_t * vortex)
890{
891 snd_kcontrol_t *kcontrol;
892 int err, i;
893
894 vortex_Eqlzr_init(vortex);
895
896 if ((kcontrol =
897 snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL)
898 return -ENOMEM;
899 kcontrol->private_value = 0;
900 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
901 return err;
902
903 /* EQ gain controls */
904 for (i = 0; i < 10; i++) {
905 if ((kcontrol =
906 snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL)
907 return -ENOMEM;
908 strcpy(kcontrol->id.name, EqBandLabels[i]);
909 kcontrol->private_value = i;
910 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
911 return err;
912 //vortex->eqctrl[i] = kcontrol;
913 }
914 /* EQ band levels */
915 if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL)
916 return -ENOMEM;
917 if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0)
918 return err;
919
920 return 0;
921}
922
923static int vortex_eq_free(vortex_t * vortex)
924{
925 /*
926 //FIXME: segfault because vortex->eqctrl[i] == 4
927 int i;
928 for (i=0; i<10; i++) {
929 if (vortex->eqctrl[i])
930 snd_ctl_remove(vortex->card, vortex->eqctrl[i]);
931 }
932 */
933 vortex_Eqlzr_shutdown(vortex);
934 return 0;
935}
936
937/* End */
diff --git a/sound/pci/au88x0/au88x0_eq.h b/sound/pci/au88x0/au88x0_eq.h
new file mode 100644
index 000000000000..e49bc625c873
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_eq.h
@@ -0,0 +1,46 @@
1#ifndef AU88X0_EQ_H
2#define AU88X0_EQ_H
3
4/***************************************************************************
5 * au88x0_eq.h
6 *
7 * Definitions and constant data for the Aureal Hardware EQ.
8 *
9 * Sun Jun 8 18:23:38 2003
10 * Author: Manuel Jander (mjander@users.sourceforge.net)
11 ****************************************************************************/
12
13typedef struct {
14 u16 LeftCoefs[50]; //0x4
15 u16 RightCoefs[50]; // 0x68
16 u16 LeftGains[20]; //0xd0
17 u16 RightGains[20]; //0xe4
18} auxxEqCoeffSet_t;
19
20typedef struct {
21 unsigned int *this00; /*CAsp4HwIO */
22 long this04; /* How many filters for each side (default = 10) */
23 long this08; /* inited to cero. Stereo flag? */
24} eqhw_t;
25
26typedef struct {
27 unsigned int *this00; /*CAsp4Core */
28 eqhw_t this04; /* CHwEq */
29 short this08; /* Bad codec flag ? SetBypassGain: bypass gain */
30 short this0a;
31 short this0c; /* SetBypassGain: bypass gain when this28 is not set. */
32 short this0e;
33
34 long this10; /* How many gains are used for each side (right or left). */
35 u16 this14[32]; /* SetLeftGainsTarget: Left (and right?) EQ gains */
36 long this24;
37 long this28; /* flag related to EQ enabled or not. Gang flag ? */
38 long this54; /* SetBypass */
39 long this58;
40 long this5c;
41 /*0x60 */ auxxEqCoeffSet_t coefset;
42 /* 50 u16 word each channel. */
43 u16 this130[20]; /* Left and Right gains */
44} eqlzr_t;
45
46#endif
diff --git a/sound/pci/au88x0/au88x0_eqdata.c b/sound/pci/au88x0/au88x0_eqdata.c
new file mode 100644
index 000000000000..abf8d6ac4c15
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_eqdata.c
@@ -0,0 +1,112 @@
1/* Data structs */
2
3static u16 asEqCoefsZeros[50] = {
4 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
5 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
6 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
7 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
8 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
9 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
10 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
11 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
12 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
13 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
14};
15
16static u16 asEqCoefsPipes[64] = {
17 0x0000, 0x0000,
18 0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
19 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
20 0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
21 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
22 0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
23 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
24 0x0000, 0x0666, 0x0000, 0x0000, 0x0666,
25 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
26 0x0000, 0x0666, 0x0000, 0x0000, 0x066a,
27 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
28
29 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
30 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
31 0x0000, 0x0000
32};
33
34/* More coef sets can be found in the win2k "inf" file. */
35static auxxEqCoeffSet_t asEqCoefsNormal = {
36 .LeftCoefs = {
37 0x7e60, 0xc19e, 0x0001, 0x0002, 0x0001,
38 0x7fa0, 0xc05f, 0x004f, 0x0000, 0xffb1,
39 0x7f3f, 0xc0bc, 0x00c2, 0x0000, 0xff3e,
40 0x7e78, 0xc177, 0x011f, 0x0000, 0xfee1,
41 0x7cd6, 0xc2e5, 0x025c, 0x0000, 0xfda4,
42 0x7949, 0xc5aa, 0x0467, 0x0000, 0xfb99,
43 0x7120, 0xcadf, 0x0864, 0x0000, 0xf79c,
44 0x5d33, 0xd430, 0x0f7e, 0x0000, 0xf082,
45 0x2beb, 0xe3ca, 0x1bd3, 0x0000, 0xe42d,
46 0xd740, 0xf01d, 0x2ac5, 0x0000, 0xd53b},
47
48 .RightCoefs = {
49 0x7e60, 0xc19e, 0x0001, 0x0002, 0x0001,
50 0x7fa0, 0xc05f, 0x004f, 0x0000, 0xffb1,
51 0x7f3f, 0xc0bc, 0x00c2, 0x0000, 0xff3e,
52 0x7e78, 0xc177, 0x011f, 0x0000, 0xfee1,
53 0x7cd6, 0xc2e5, 0x025c, 0x0000, 0xfda4,
54 0x7949, 0xc5aa, 0x0467, 0x0000, 0xfb99,
55 0x7120, 0xcadf, 0x0864, 0x0000, 0xf79c,
56 0x5d33, 0xd430, 0x0f7e, 0x0000, 0xf082,
57 0x2beb, 0xe3ca, 0x1bd3, 0x0000, 0xe42d,
58 0xd740, 0xf01d, 0x2ac5, 0x0000, 0xd53b},
59
60 .LeftGains = {
61 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
62 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96},
63 .RightGains = {
64 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
65 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96}
66};
67
68static u16 eq_gains_normal[20] = {
69 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
70 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
71 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96,
72 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96
73};
74
75/* _rodatab60 */
76static u16 eq_gains_zero[10] = {
77 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
78 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
79};
80
81/* _rodatab7c: ProgramPipe */
82static u16 eq_gains_current[12] = {
83 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
84 0x7fff,
85 0x7fff, 0x7fff, 0x7fff
86};
87
88/* _rodatab78 */
89static u16 eq_states_zero[2] = { 0x0000, 0x0000 };
90
91static u16 asEqOutStateZeros[48] = {
92 0x0000, 0x0000, 0x0000, 0x0000,
93 0x0000, 0x0000, 0x0000, 0x0000,
94 0x0000, 0x0000, 0x0000, 0x0000,
95 0x0000, 0x0000, 0x0000, 0x0000,
96 0x0000, 0x0000, 0x0000, 0x0000,
97 0x0000, 0x0000, 0x0000, 0x0000,
98 0x0000, 0x0000, 0x0000, 0x0000,
99 0x0000, 0x0000, 0x0000, 0x0000,
100 0x0000, 0x0000, 0x0000, 0x0000,
101 0x0000, 0x0000, 0x0000, 0x0000,
102 0x0000, 0x0000, 0x0000, 0x0000,
103 0x0000, 0x0000, 0x0000, 0x0000
104};
105
106/*_rodataba0:*/
107static long eq_levels[32] = {
108 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
109 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
110 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
111 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
112};
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c
new file mode 100644
index 000000000000..a07d1deba322
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_game.c
@@ -0,0 +1,135 @@
1/*
2 * $Id: au88x0_game.c,v 1.9 2003/09/22 03:51:28 mjander Exp $
3 *
4 * Manuel Jander.
5 *
6 * Based on the work of:
7 * Vojtech Pavlik
8 * Raymond Ingles
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Should you need to contact me, the author, you can do so either by
25 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
26 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
27 *
28 * Based 90% on Vojtech Pavlik pcigame driver.
29 * Merged and modified by Manuel Jander, for the OpenVortex
30 * driver. (email: mjander@embedded.cl).
31 */
32
33#include <sound/driver.h>
34#include <linux/time.h>
35#include <linux/delay.h>
36#include <linux/init.h>
37#include <sound/core.h>
38#include "au88x0.h"
39#include <linux/gameport.h>
40
41#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
42
43#define VORTEX_GAME_DWAIT 20 /* 20 ms */
44
45static unsigned char vortex_game_read(struct gameport *gameport)
46{
47 vortex_t *vortex = gameport_get_port_data(gameport);
48 return hwread(vortex->mmio, VORTEX_GAME_LEGACY);
49}
50
51static void vortex_game_trigger(struct gameport *gameport)
52{
53 vortex_t *vortex = gameport_get_port_data(gameport);
54 hwwrite(vortex->mmio, VORTEX_GAME_LEGACY, 0xff);
55}
56
57static int
58vortex_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
59{
60 vortex_t *vortex = gameport_get_port_data(gameport);
61 int i;
62
63 *buttons = (~hwread(vortex->mmio, VORTEX_GAME_LEGACY) >> 4) & 0xf;
64
65 for (i = 0; i < 4; i++) {
66 axes[i] =
67 hwread(vortex->mmio, VORTEX_GAME_AXIS + (i * AXIS_SIZE));
68 if (axes[i] == AXIS_RANGE)
69 axes[i] = -1;
70 }
71 return 0;
72}
73
74static int vortex_game_open(struct gameport *gameport, int mode)
75{
76 vortex_t *vortex = gameport_get_port_data(gameport);
77
78 switch (mode) {
79 case GAMEPORT_MODE_COOKED:
80 hwwrite(vortex->mmio, VORTEX_CTRL2,
81 hwread(vortex->mmio,
82 VORTEX_CTRL2) | CTRL2_GAME_ADCMODE);
83 msleep(VORTEX_GAME_DWAIT);
84 return 0;
85 case GAMEPORT_MODE_RAW:
86 hwwrite(vortex->mmio, VORTEX_CTRL2,
87 hwread(vortex->mmio,
88 VORTEX_CTRL2) & ~CTRL2_GAME_ADCMODE);
89 return 0;
90 default:
91 return -1;
92 }
93
94 return 0;
95}
96
97static int __devinit vortex_gameport_register(vortex_t * vortex)
98{
99 struct gameport *gp;
100
101 vortex->gameport = gp = gameport_allocate_port();
102 if (!gp) {
103 printk(KERN_ERR "vortex: cannot allocate memory for gameport\n");
104 return -ENOMEM;
105 };
106
107 gameport_set_name(gp, "AU88x0 Gameport");
108 gameport_set_phys(gp, "pci%s/gameport0", pci_name(vortex->pci_dev));
109 gameport_set_dev_parent(gp, &vortex->pci_dev->dev);
110
111 gp->read = vortex_game_read;
112 gp->trigger = vortex_game_trigger;
113 gp->cooked_read = vortex_game_cooked_read;
114 gp->open = vortex_game_open;
115
116 gameport_set_port_data(gp, vortex);
117 gp->fuzz = 64;
118
119 gameport_register_port(gp);
120
121 return 0;
122}
123
124static void vortex_gameport_unregister(vortex_t * vortex)
125{
126 if (vortex->gameport) {
127 gameport_unregister_port(vortex->gameport);
128 vortex->gameport = NULL;
129 }
130}
131
132#else
133static inline int vortex_gameport_register(vortex_t * vortex) { return -ENOSYS; }
134static inline void vortex_gameport_unregister(vortex_t * vortex) { }
135#endif
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
new file mode 100644
index 000000000000..86e27d695c37
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_mixer.c
@@ -0,0 +1,33 @@
1/*
2 * Vortex Mixer support.
3 *
4 * There is much more than just the AC97 mixer...
5 *
6 */
7
8#include <sound/driver.h>
9#include <linux/time.h>
10#include <linux/init.h>
11#include <sound/core.h>
12#include "au88x0.h"
13
14static int __devinit snd_vortex_mixer(vortex_t * vortex)
15{
16 ac97_bus_t *pbus;
17 ac97_template_t ac97;
18 int err;
19 static ac97_bus_ops_t ops = {
20 .write = vortex_codec_write,
21 .read = vortex_codec_read,
22 };
23
24 if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
25 return err;
26 memset(&ac97, 0, sizeof(ac97));
27 // Intialize AC97 codec stuff.
28 ac97.private_data = vortex;
29 ac97.scaps = AC97_SCAP_NO_SPDIF;
30 err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
31 vortex->isquad = ((vortex->codec == NULL) ? 0 : (vortex->codec->ext_id&0x80));
32 return err;
33}
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c
new file mode 100644
index 000000000000..c0c23466eb0e
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_mpu401.c
@@ -0,0 +1,112 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for control of MPU-401 in UART mode
4 *
5 * Modified for the Aureal Vortex based Soundcards
6 * by Manuel Jander (mjande@embedded.cl).
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sound/driver.h>
25#include <linux/time.h>
26#include <linux/init.h>
27#include <sound/core.h>
28#include <sound/mpu401.h>
29#include "au88x0.h"
30
31/* Check for mpu401 mmio support. */
32/* MPU401 legacy support is only provided as a emergency fallback *
33 * for older versions of ALSA. Its usage is strongly discouraged. */
34#ifndef MPU401_HW_AUREAL
35#define VORTEX_MPU401_LEGACY
36#endif
37
38/* Vortex MPU401 defines. */
39#define MIDI_CLOCK_DIV 0x61
40/* Standart MPU401 defines. */
41#define MPU401_RESET 0xff
42#define MPU401_ENTER_UART 0x3f
43#define MPU401_ACK 0xfe
44
45static int __devinit snd_vortex_midi(vortex_t * vortex)
46{
47 snd_rawmidi_t *rmidi;
48 int temp, mode;
49 mpu401_t *mpu;
50 int port;
51
52#ifdef VORTEX_MPU401_LEGACY
53 /* EnableHardCodedMPU401Port() */
54 /* Enable Legacy MIDI Interface port. */
55 port = (0x03 << 5); /* FIXME: static address. 0x330 */
56 temp =
57 (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) |
58 CTRL_MIDI_EN | port;
59 hwwrite(vortex->mmio, VORTEX_CTRL, temp);
60#else
61 /* Disable Legacy MIDI Interface port. */
62 temp =
63 (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) &
64 ~CTRL_MIDI_EN;
65 hwwrite(vortex->mmio, VORTEX_CTRL, temp);
66#endif
67 /* Mpu401UartInit() */
68 mode = 1;
69 temp = hwread(vortex->mmio, VORTEX_CTRL2) & 0xffff00cf;
70 temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4;
71 hwwrite(vortex->mmio, VORTEX_CTRL2, temp);
72 hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET);
73 /* Set some kind of mode */
74 if (mode)
75 hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_ENTER_UART);
76
77 /* Check if anything is OK. */
78 temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
79 if (temp != MPU401_ACK /*0xfe */ ) {
80 printk(KERN_ERR "midi port doesn't acknowledge!\n");
81 return -ENODEV;
82 }
83 /* Enable MPU401 interrupts. */
84 hwwrite(vortex->mmio, VORTEX_IRQ_CTRL,
85 hwread(vortex->mmio, VORTEX_IRQ_CTRL) | IRQ_MIDI);
86
87 /* Create MPU401 instance. */
88#ifdef VORTEX_MPU401_LEGACY
89 if ((temp =
90 snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330,
91 0, 0, 0, &rmidi)) != 0) {
92 hwwrite(vortex->mmio, VORTEX_CTRL,
93 (hwread(vortex->mmio, VORTEX_CTRL) &
94 ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
95 return temp;
96 }
97#else
98 port = (unsigned long)(vortex->mmio + (VORTEX_MIDI_DATA >> 2));
99 if ((temp =
100 snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port,
101 1, 0, 0, &rmidi)) != 0) {
102 hwwrite(vortex->mmio, VORTEX_CTRL,
103 (hwread(vortex->mmio, VORTEX_CTRL) &
104 ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN);
105 return temp;
106 }
107 mpu = rmidi->private_data;
108 mpu->cport = (unsigned long)(vortex->mmio + (VORTEX_MIDI_CMD >> 2));
109#endif
110 vortex->rmidi = rmidi;
111 return 0;
112}
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
new file mode 100644
index 000000000000..04dcefd8b8ff
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -0,0 +1,548 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17/*
18 * Vortex PCM ALSA driver.
19 *
20 * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet.
21 * It remains stuck,and DMA transfers do not happen.
22 */
23#include <sound/asoundef.h>
24#include <sound/driver.h>
25#include <linux/time.h>
26#include <sound/core.h>
27#include <sound/pcm.h>
28#include <sound/pcm_params.h>
29#include "au88x0.h"
30
31#define VORTEX_PCM_TYPE(x) (x->name[40])
32
33/* hardware definition */
34static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
35 .info =
36 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
37 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
38 SNDRV_PCM_INFO_MMAP_VALID),
39 .formats =
40 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
41 SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
42 .rates = SNDRV_PCM_RATE_CONTINUOUS,
43 .rate_min = 5000,
44 .rate_max = 48000,
45 .channels_min = 1,
46#ifdef CHIP_AU8830
47 .channels_max = 4,
48#else
49 .channels_max = 2,
50#endif
51 .buffer_bytes_max = 0x10000,
52 .period_bytes_min = 0x1,
53 .period_bytes_max = 0x1000,
54 .periods_min = 2,
55 .periods_max = 32,
56};
57
58#ifndef CHIP_AU8820
59static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
60 .info =
61 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
62 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
63 SNDRV_PCM_INFO_MMAP_VALID),
64 .formats =
65 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
66 SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
67 .rates = SNDRV_PCM_RATE_CONTINUOUS,
68 .rate_min = 5000,
69 .rate_max = 48000,
70 .channels_min = 1,
71 .channels_max = 1,
72 .buffer_bytes_max = 0x10000,
73 .period_bytes_min = 0x100,
74 .period_bytes_max = 0x1000,
75 .periods_min = 2,
76 .periods_max = 64,
77};
78#endif
79static snd_pcm_hardware_t snd_vortex_playback_hw_spdif = {
80 .info =
81 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
82 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
83 SNDRV_PCM_INFO_MMAP_VALID),
84 .formats =
85 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
86 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW |
87 SNDRV_PCM_FMTBIT_A_LAW,
88 .rates =
89 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
90 .rate_min = 32000,
91 .rate_max = 48000,
92 .channels_min = 1,
93 .channels_max = 2,
94 .buffer_bytes_max = 0x10000,
95 .period_bytes_min = 0x100,
96 .period_bytes_max = 0x1000,
97 .periods_min = 2,
98 .periods_max = 64,
99};
100
101#ifndef CHIP_AU8810
102static snd_pcm_hardware_t snd_vortex_playback_hw_wt = {
103 .info = (SNDRV_PCM_INFO_MMAP |
104 SNDRV_PCM_INFO_INTERLEAVED |
105 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
106 .formats = SNDRV_PCM_FMTBIT_S16_LE,
107 .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000,
108 .rate_min = 8000,
109 .rate_max = 48000,
110 .channels_min = 1,
111 .channels_max = 2,
112 .buffer_bytes_max = 0x10000,
113 .period_bytes_min = 0x0400,
114 .period_bytes_max = 0x1000,
115 .periods_min = 2,
116 .periods_max = 64,
117};
118#endif
119/* open callback */
120static int snd_vortex_pcm_open(snd_pcm_substream_t * substream)
121{
122 vortex_t *vortex = snd_pcm_substream_chip(substream);
123 snd_pcm_runtime_t *runtime = substream->runtime;
124 int err;
125
126 /* Force equal size periods */
127 if ((err =
128 snd_pcm_hw_constraint_integer(runtime,
129 SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
130 return err;
131 /* Avoid PAGE_SIZE boundary to fall inside of a period. */
132 if ((err =
133 snd_pcm_hw_constraint_pow2(runtime, 0,
134 SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
135 return err;
136
137 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
138#ifndef CHIP_AU8820
139 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) {
140 runtime->hw = snd_vortex_playback_hw_a3d;
141 }
142#endif
143 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) {
144 runtime->hw = snd_vortex_playback_hw_spdif;
145 switch (vortex->spdif_sr) {
146 case 32000:
147 runtime->hw.rates = SNDRV_PCM_RATE_32000;
148 break;
149 case 44100:
150 runtime->hw.rates = SNDRV_PCM_RATE_44100;
151 break;
152 case 48000:
153 runtime->hw.rates = SNDRV_PCM_RATE_48000;
154 break;
155 }
156 }
157 if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB
158 || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)
159 runtime->hw = snd_vortex_playback_hw_adb;
160 substream->runtime->private_data = NULL;
161 }
162#ifndef CHIP_AU8810
163 else {
164 runtime->hw = snd_vortex_playback_hw_wt;
165 substream->runtime->private_data = NULL;
166 }
167#endif
168 return 0;
169}
170
171/* close callback */
172static int snd_vortex_pcm_close(snd_pcm_substream_t * substream)
173{
174 //vortex_t *chip = snd_pcm_substream_chip(substream);
175 stream_t *stream = (stream_t *) substream->runtime->private_data;
176
177 // the hardware-specific codes will be here
178 if (stream != NULL) {
179 stream->substream = NULL;
180 stream->nr_ch = 0;
181 }
182 substream->runtime->private_data = NULL;
183 return 0;
184}
185
186/* hw_params callback */
187static int
188snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream,
189 snd_pcm_hw_params_t * hw_params)
190{
191 vortex_t *chip = snd_pcm_substream_chip(substream);
192 stream_t *stream = (stream_t *) (substream->runtime->private_data);
193 snd_pcm_sgbuf_t *sgbuf;
194 int err;
195
196 // Alloc buffer memory.
197 err =
198 snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
199 if (err < 0) {
200 printk(KERN_ERR "Vortex: pcm page alloc failed!\n");
201 return err;
202 }
203 //sgbuf = (snd_pcm_sgbuf_t *) substream->runtime->dma_private;
204 sgbuf = snd_pcm_substream_sgbuf(substream);
205 /*
206 printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
207 params_period_bytes(hw_params), params_channels(hw_params));
208 */
209 spin_lock_irq(&chip->lock);
210 // Make audio routes and config buffer DMA.
211 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
212 int dma, type = VORTEX_PCM_TYPE(substream->pcm);
213 /* Dealloc any routes. */
214 if (stream != NULL)
215 vortex_adb_allocroute(chip, stream->dma,
216 stream->nr_ch, stream->dir,
217 stream->type);
218 /* Alloc routes. */
219 dma =
220 vortex_adb_allocroute(chip, -1,
221 params_channels(hw_params),
222 substream->stream, type);
223 if (dma < 0)
224 return dma;
225 stream = substream->runtime->private_data = &chip->dma_adb[dma];
226 stream->substream = substream;
227 /* Setup Buffers. */
228 vortex_adbdma_setbuffers(chip, dma, sgbuf,
229 params_period_bytes(hw_params),
230 params_periods(hw_params));
231 }
232#ifndef CHIP_AU8810
233 else {
234 /* if (stream != NULL)
235 vortex_wt_allocroute(chip, substream->number, 0); */
236 vortex_wt_allocroute(chip, substream->number,
237 params_channels(hw_params));
238 stream = substream->runtime->private_data =
239 &chip->dma_wt[substream->number];
240 stream->dma = substream->number;
241 stream->substream = substream;
242 vortex_wtdma_setbuffers(chip, substream->number, sgbuf,
243 params_period_bytes(hw_params),
244 params_periods(hw_params));
245 }
246#endif
247 spin_unlock_irq(&chip->lock);
248 return 0;
249}
250
251/* hw_free callback */
252static int snd_vortex_pcm_hw_free(snd_pcm_substream_t * substream)
253{
254 vortex_t *chip = snd_pcm_substream_chip(substream);
255 stream_t *stream = (stream_t *) (substream->runtime->private_data);
256
257 spin_lock_irq(&chip->lock);
258 // Delete audio routes.
259 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
260 if (stream != NULL)
261 vortex_adb_allocroute(chip, stream->dma,
262 stream->nr_ch, stream->dir,
263 stream->type);
264 }
265#ifndef CHIP_AU8810
266 else {
267 if (stream != NULL)
268 vortex_wt_allocroute(chip, stream->dma, 0);
269 }
270#endif
271 substream->runtime->private_data = NULL;
272 spin_unlock_irq(&chip->lock);
273
274 return snd_pcm_lib_free_pages(substream);
275}
276
277/* prepare callback */
278static int snd_vortex_pcm_prepare(snd_pcm_substream_t * substream)
279{
280 vortex_t *chip = snd_pcm_substream_chip(substream);
281 snd_pcm_runtime_t *runtime = substream->runtime;
282 stream_t *stream = (stream_t *) substream->runtime->private_data;
283 int dma = stream->dma, fmt, dir;
284
285 // set up the hardware with the current configuration.
286 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
287 dir = 1;
288 else
289 dir = 0;
290 fmt = vortex_alsafmt_aspfmt(runtime->format);
291 spin_lock_irq(&chip->lock);
292 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
293 vortex_adbdma_setmode(chip, dma, 1, dir, fmt, 0 /*? */ ,
294 0);
295 vortex_adbdma_setstartbuffer(chip, dma, 0);
296 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF)
297 vortex_adb_setsrc(chip, dma, runtime->rate, dir);
298 }
299#ifndef CHIP_AU8810
300 else {
301 vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0);
302 // FIXME: Set rate (i guess using vortex_wt_writereg() somehow).
303 vortex_wtdma_setstartbuffer(chip, dma, 0);
304 }
305#endif
306 spin_unlock_irq(&chip->lock);
307 return 0;
308}
309
310/* trigger callback */
311static int snd_vortex_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
312{
313 vortex_t *chip = snd_pcm_substream_chip(substream);
314 stream_t *stream = (stream_t *) substream->runtime->private_data;
315 int dma = stream->dma;
316
317 spin_lock(&chip->lock);
318 switch (cmd) {
319 case SNDRV_PCM_TRIGGER_START:
320 // do something to start the PCM engine
321 //printk(KERN_INFO "vortex: start %d\n", dma);
322 stream->fifo_enabled = 1;
323 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
324 vortex_adbdma_resetup(chip, dma);
325 vortex_adbdma_startfifo(chip, dma);
326 }
327#ifndef CHIP_AU8810
328 else {
329 printk(KERN_INFO "vortex: wt start %d\n", dma);
330 vortex_wtdma_startfifo(chip, dma);
331 }
332#endif
333 break;
334 case SNDRV_PCM_TRIGGER_STOP:
335 // do something to stop the PCM engine
336 //printk(KERN_INFO "vortex: stop %d\n", dma);
337 stream->fifo_enabled = 0;
338 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
339 vortex_adbdma_pausefifo(chip, dma);
340 //vortex_adbdma_stopfifo(chip, dma);
341#ifndef CHIP_AU8810
342 else {
343 printk(KERN_INFO "vortex: wt stop %d\n", dma);
344 vortex_wtdma_stopfifo(chip, dma);
345 }
346#endif
347 break;
348 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
349 //printk(KERN_INFO "vortex: pause %d\n", dma);
350 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
351 vortex_adbdma_pausefifo(chip, dma);
352#ifndef CHIP_AU8810
353 else
354 vortex_wtdma_pausefifo(chip, dma);
355#endif
356 break;
357 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
358 //printk(KERN_INFO "vortex: resume %d\n", dma);
359 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
360 vortex_adbdma_resumefifo(chip, dma);
361#ifndef CHIP_AU8810
362 else
363 vortex_wtdma_resumefifo(chip, dma);
364#endif
365 break;
366 default:
367 spin_unlock(&chip->lock);
368 return -EINVAL;
369 }
370 spin_unlock(&chip->lock);
371 return 0;
372}
373
374/* pointer callback */
375static snd_pcm_uframes_t snd_vortex_pcm_pointer(snd_pcm_substream_t * substream)
376{
377 vortex_t *chip = snd_pcm_substream_chip(substream);
378 stream_t *stream = (stream_t *) substream->runtime->private_data;
379 int dma = stream->dma;
380 snd_pcm_uframes_t current_ptr = 0;
381
382 spin_lock(&chip->lock);
383 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
384 current_ptr = vortex_adbdma_getlinearpos(chip, dma);
385#ifndef CHIP_AU8810
386 else
387 current_ptr = vortex_wtdma_getlinearpos(chip, dma);
388#endif
389 //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);
390 spin_unlock(&chip->lock);
391 return (bytes_to_frames(substream->runtime, current_ptr));
392}
393
394/* Page callback. */
395/*
396static struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) {
397
398
399}
400*/
401/* operators */
402static snd_pcm_ops_t snd_vortex_playback_ops = {
403 .open = snd_vortex_pcm_open,
404 .close = snd_vortex_pcm_close,
405 .ioctl = snd_pcm_lib_ioctl,
406 .hw_params = snd_vortex_pcm_hw_params,
407 .hw_free = snd_vortex_pcm_hw_free,
408 .prepare = snd_vortex_pcm_prepare,
409 .trigger = snd_vortex_pcm_trigger,
410 .pointer = snd_vortex_pcm_pointer,
411 .page = snd_pcm_sgbuf_ops_page,
412};
413
414/*
415* definitions of capture are omitted here...
416*/
417
418static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
419 "AU88x0 ADB",
420 "AU88x0 SPDIF",
421 "AU88x0 A3D",
422 "AU88x0 WT",
423 "AU88x0 I2S",
424};
425static char *vortex_pcm_name[VORTEX_PCM_LAST] = {
426 "adb",
427 "spdif",
428 "a3d",
429 "wt",
430 "i2s",
431};
432
433/* SPDIF kcontrol */
434
435static int snd_vortex_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
436{
437 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
438 uinfo->count = 1;
439 return 0;
440}
441
442static int snd_vortex_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
443{
444 ucontrol->value.iec958.status[0] = 0xff;
445 ucontrol->value.iec958.status[1] = 0xff;
446 ucontrol->value.iec958.status[2] = 0xff;
447 ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
448 return 0;
449}
450
451static int snd_vortex_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
452{
453 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
454 ucontrol->value.iec958.status[0] = 0x00;
455 ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID;
456 ucontrol->value.iec958.status[2] = 0x00;
457 switch (vortex->spdif_sr) {
458 case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break;
459 case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break;
460 case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break;
461 }
462 return 0;
463}
464
465static int snd_vortex_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
466{
467 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
468 int spdif_sr = 48000;
469 switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) {
470 case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break;
471 case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break;
472 case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break;
473 }
474 if (spdif_sr == vortex->spdif_sr)
475 return 0;
476 vortex->spdif_sr = spdif_sr;
477 vortex_spdif_init(vortex, vortex->spdif_sr, 1);
478 return 1;
479}
480
481/* spdif controls */
482static snd_kcontrol_new_t snd_vortex_mixer_spdif[] __devinitdata = {
483 {
484 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
485 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
486 .info = snd_vortex_spdif_info,
487 .get = snd_vortex_spdif_get,
488 .put = snd_vortex_spdif_put,
489 },
490 {
491 .access = SNDRV_CTL_ELEM_ACCESS_READ,
492 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
493 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
494 .info = snd_vortex_spdif_info,
495 .get = snd_vortex_spdif_mask_get
496 },
497};
498
499/* create a pcm device */
500static int __devinit snd_vortex_new_pcm(vortex_t * chip, int idx, int nr)
501{
502 snd_pcm_t *pcm;
503 snd_kcontrol_t *kctl;
504 int i;
505 int err, nr_capt;
506
507 if ((chip == 0) || (idx < 0) || (idx > VORTEX_PCM_LAST))
508 return -ENODEV;
509
510 /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the
511 * same dma engine. WT uses it own separate dma engine whcih cant capture. */
512 if (idx == VORTEX_PCM_ADB)
513 nr_capt = nr;
514 else
515 nr_capt = 0;
516 if ((err =
517 snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,
518 nr_capt, &pcm)) < 0)
519 return err;
520 strcpy(pcm->name, vortex_pcm_name[idx]);
521 chip->pcm[idx] = pcm;
522 // This is an evil hack, but it saves a lot of duplicated code.
523 VORTEX_PCM_TYPE(pcm) = idx;
524 pcm->private_data = chip;
525 /* set operators */
526 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
527 &snd_vortex_playback_ops);
528 if (idx == VORTEX_PCM_ADB)
529 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
530 &snd_vortex_playback_ops);
531
532 /* pre-allocation of Scatter-Gather buffers */
533
534 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
535 snd_dma_pci_data(chip->pci_dev),
536 0x10000, 0x10000);
537
538 if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
539 for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
540 kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);
541 if (!kctl)
542 return -ENOMEM;
543 if ((err = snd_ctl_add(chip->card, kctl)) < 0)
544 return err;
545 }
546 }
547 return 0;
548}
diff --git a/sound/pci/au88x0/au88x0_sb.h b/sound/pci/au88x0/au88x0_sb.h
new file mode 100644
index 000000000000..5a4d8fc2bbfc
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_sb.h
@@ -0,0 +1,40 @@
1/***************************************************************************
2 * au88x0_sb.h
3 *
4 * Wed Oct 29 22:10:42 2003
5 *
6 ****************************************************************************/
7
8#ifdef CHIP_AU8820
9/* AU8820 starting @ 64KiB offset */
10#define SBEMU_BASE 0x10000
11#else
12/* AU8810? and AU8830 starting @ 164KiB offset */
13#define SBEMU_BASE 0x29000
14#endif
15
16#define FM_A_STATUS (SBEMU_BASE + 0x00) /* read */
17#define FM_A_ADDRESS (SBEMU_BASE + 0x00) /* write */
18#define FM_A_DATA (SBEMU_BASE + 0x04)
19#define FM_B_STATUS (SBEMU_BASE + 0x08)
20#define FM_B_ADDRESS (SBEMU_BASE + 0x08)
21#define FM_B_DATA (SBEMU_BASE + 0x0C)
22#define SB_MIXER_ADDR (SBEMU_BASE + 0x10)
23#define SB_MIXER_DATA (SBEMU_BASE + 0x14)
24#define SB_RESET (SBEMU_BASE + 0x18)
25#define SB_RESET_ALIAS (SBEMU_BASE + 0x1C)
26#define FM_STATUS2 (SBEMU_BASE + 0x20)
27#define FM_ADDR2 (SBEMU_BASE + 0x20)
28#define FM_DATA2 (SBEMU_BASE + 0x24)
29#define SB_DSP_READ (SBEMU_BASE + 0x28)
30#define SB_DSP_WRITE (SBEMU_BASE + 0x30)
31#define SB_DSP_WRITE_STATUS (SBEMU_BASE + 0x30) /* bit 7 */
32#define SB_DSP_READ_STATUS (SBEMU_BASE + 0x38) /* bit 7 */
33#define SB_LACR (SBEMU_BASE + 0x40) /* ? */
34#define SB_LADCR (SBEMU_BASE + 0x44) /* ? */
35#define SB_LAMR (SBEMU_BASE + 0x48) /* ? */
36#define SB_LARR (SBEMU_BASE + 0x4C) /* ? */
37#define SB_VERSION (SBEMU_BASE + 0x50)
38#define SB_CTRLSTAT (SBEMU_BASE + 0x54)
39#define SB_TIMERSTAT (SBEMU_BASE + 0x58)
40#define FM_RAM (SBEMU_BASE + 0x100) /* 0x40 ULONG */
diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c
new file mode 100644
index 000000000000..400417d34609
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_synth.c
@@ -0,0 +1,395 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Library General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17/*
18 * Someday its supposed to make use of the WT DMA engine
19 * for a Wavetable synthesizer.
20 */
21
22#include "au88x0.h"
23#include "au88x0_wt.h"
24
25static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en);
26static void vortex_connection_adb_mixin(vortex_t * vortex, int en,
27 unsigned char channel,
28 unsigned char source,
29 unsigned char mixin);
30static void vortex_connection_mixin_mix(vortex_t * vortex, int en,
31 unsigned char mixin,
32 unsigned char mix, int a);
33static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j);
34static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
35 unsigned long val);
36
37/* WT */
38
39/* Put 2 WT channels together for one stereo interlaced channel. */
40static void vortex_wt_setstereo(vortex_t * vortex, u32 wt, u32 stereo)
41{
42 int temp;
43
44 //temp = hwread(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2));
45 temp = hwread(vortex->mmio, WT_STEREO(wt));
46 temp = (temp & 0xfe) | (stereo & 1);
47 //hwwrite(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2), temp);
48 hwwrite(vortex->mmio, WT_STEREO(wt), temp);
49}
50
51/* Join to mixdown route. */
52static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en)
53{
54 int temp;
55
56 /* There is one DSREG register for each bank (32 voices each). */
57 temp = hwread(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0));
58 if (en)
59 temp |= (1 << (wt & 0x1f));
60 else
61 temp &= (1 << ~(wt & 0x1f));
62 hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp);
63}
64
65/* Setup WT route. */
66static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
67{
68 wt_voice_t *voice = &(vortex->wt_voice[wt]);
69 int temp;
70
71 //FIXME: WT audio routing.
72 if (nr_ch) {
73 vortex_fifo_wtinitialize(vortex, wt, 1);
74 vortex_fifo_setwtvalid(vortex, wt, 1);
75 vortex_wt_setstereo(vortex, wt, nr_ch - 1);
76 } else
77 vortex_fifo_setwtvalid(vortex, wt, 0);
78
79 /* Set mixdown mode. */
80 vortex_wt_setdsout(vortex, wt, 1);
81 /* Set other parameter registers. */
82 hwwrite(vortex->mmio, WT_SRAMP(0), 0x880000);
83 //hwwrite(vortex->mmio, WT_GMODE(0), 0xffffffff);
84#ifdef CHIP_AU8830
85 hwwrite(vortex->mmio, WT_SRAMP(1), 0x880000);
86 //hwwrite(vortex->mmio, WT_GMODE(1), 0xffffffff);
87#endif
88 hwwrite(vortex->mmio, WT_PARM(wt, 0), 0);
89 hwwrite(vortex->mmio, WT_PARM(wt, 1), 0);
90 hwwrite(vortex->mmio, WT_PARM(wt, 2), 0);
91
92 temp = hwread(vortex->mmio, WT_PARM(wt, 3));
93 printk("vortex: WT PARM3: %x\n", temp);
94 //hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
95
96 hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
97 hwwrite(vortex->mmio, WT_DELAY(wt, 1), 0);
98 hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0);
99 hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0);
100
101 printk("vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
102
103 hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
104 hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
105
106 voice->parm0 = voice->parm1 = 0xcfb23e2f;
107 hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
108 hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
109 printk("vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
110 return 0;
111}
112
113
114static void vortex_wt_connect(vortex_t * vortex, int en)
115{
116 int i, ii, mix;
117
118#define NR_WTROUTES 6
119#ifdef CHIP_AU8830
120#define NR_WTBLOCKS 2
121#else
122#define NR_WTBLOCKS 1
123#endif
124
125 for (i = 0; i < NR_WTBLOCKS; i++) {
126 for (ii = 0; ii < NR_WTROUTES; ii++) {
127 mix =
128 vortex_adb_checkinout(vortex,
129 vortex->fixed_res, en,
130 VORTEX_RESOURCE_MIXIN);
131 vortex->mixwt[(i * NR_WTROUTES) + ii] = mix;
132
133 vortex_route(vortex, en, 0x11,
134 ADB_WTOUT(i, ii + 0x20), ADB_MIXIN(mix));
135
136 vortex_connection_mixin_mix(vortex, en, mix,
137 vortex->mixplayb[ii % 2], 0);
138 if (VORTEX_IS_QUAD(vortex))
139 vortex_connection_mixin_mix(vortex, en,
140 mix,
141 vortex->mixplayb[2 +
142 (ii % 2)], 0);
143 }
144 }
145 for (i = 0; i < NR_WT; i++) {
146 hwwrite(vortex->mmio, WT_RUN(i), 1);
147 }
148}
149
150/* Read WT Register */
151#if 0
152static int vortex_wt_GetReg(vortex_t * vortex, char reg, int wt)
153{
154 //int eax, esi;
155
156 if (reg == 4) {
157 return hwread(vortex->mmio, WT_PARM(wt, 3));
158 }
159 if (reg == 7) {
160 return hwread(vortex->mmio, WT_GMODE(wt));
161 }
162
163 return 0;
164}
165
166/* WT hardware abstraction layer generic register interface. */
167static int
168vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt,
169 unsigned short val)
170{
171 /*
172 int eax, edx;
173
174 if (wt >= NR_WT) // 0x40 -> NR_WT
175 return 0;
176
177 if ((reg - 0x20) > 0) {
178 if ((reg - 0x21) != 0)
179 return 0;
180 eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x208; // param 2
181 } else {
182 eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x20a; // param 3
183 }
184 hwwrite(vortex->mmio, eax, c);
185 */
186 return 1;
187}
188
189/*public: static void __thiscall CWTHal::SetReg(unsigned char,int,unsigned long) */
190#endif
191static int
192vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
193 unsigned long val)
194{
195 int ecx;
196
197 if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
198 if (wt >= (NR_WT / NR_WT_PB)) {
199 printk
200 ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
201 reg, wt);
202 return 0;
203 }
204 } else {
205 if (wt >= NR_WT) {
206 printk("vortex: WT SetReg: voice out of range\n");
207 return 0;
208 }
209 }
210 if (reg > 0xc)
211 return 0;
212
213 switch (reg) {
214 /* Voice specific parameters */
215 case 0: /* running */
216 //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_RUN(wt), (int)val);
217 hwwrite(vortex->mmio, WT_RUN(wt), val);
218 return 0xc;
219 break;
220 case 1: /* param 0 */
221 //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,0), (int)val);
222 hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
223 return 0xc;
224 break;
225 case 2: /* param 1 */
226 //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,1), (int)val);
227 hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
228 return 0xc;
229 break;
230 case 3: /* param 2 */
231 //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,2), (int)val);
232 hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
233 return 0xc;
234 break;
235 case 4: /* param 3 */
236 //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,3), (int)val);
237 hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
238 return 0xc;
239 break;
240 case 6: /* mute */
241 //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_MUTE(wt), (int)val);
242 hwwrite(vortex->mmio, WT_MUTE(wt), val);
243 return 0xc;
244 break;
245 case 0xb:
246 { /* delay */
247 //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_DELAY(wt,0), (int)val);
248 hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
249 hwwrite(vortex->mmio, WT_DELAY(wt, 2), val);
250 hwwrite(vortex->mmio, WT_DELAY(wt, 1), val);
251 hwwrite(vortex->mmio, WT_DELAY(wt, 0), val);
252 return 0xc;
253 }
254 break;
255 /* Global WT block parameters */
256 case 5: /* sramp */
257 ecx = WT_SRAMP(wt);
258 break;
259 case 8: /* aramp */
260 ecx = WT_ARAMP(wt);
261 break;
262 case 9: /* mramp */
263 ecx = WT_MRAMP(wt);
264 break;
265 case 0xa: /* ctrl */
266 ecx = WT_CTRL(wt);
267 break;
268 case 0xc: /* ds_reg */
269 ecx = WT_DSREG(wt);
270 break;
271 default:
272 return 0;
273 break;
274 }
275 //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
276 hwwrite(vortex->mmio, ecx, val);
277 return 1;
278}
279
280static void vortex_wt_init(vortex_t * vortex)
281{
282 int var4, var8, varc, var10 = 0, edi;
283
284 var10 &= 0xFFFFFFE3;
285 var10 |= 0x22;
286 var10 &= 0xFFFFFEBF;
287 var10 |= 0x80;
288 var10 |= 0x200;
289 var10 &= 0xfffffffe;
290 var10 &= 0xfffffbff;
291 var10 |= 0x1800;
292 // var10 = 0x1AA2
293 var4 = 0x10000000;
294 varc = 0x00830000;
295 var8 = 0x00830000;
296
297 /* Init Bank registers. */
298 for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++) {
299 vortex_wt_SetReg(vortex, 0xc, edi, 0); /* ds_reg */
300 vortex_wt_SetReg(vortex, 0xa, edi, var10); /* ctrl */
301 vortex_wt_SetReg(vortex, 0x9, edi, var4); /* mramp */
302 vortex_wt_SetReg(vortex, 0x8, edi, varc); /* aramp */
303 vortex_wt_SetReg(vortex, 0x5, edi, var8); /* sramp */
304 }
305 /* Init Voice registers. */
306 for (edi = 0; edi < NR_WT; edi++) {
307 vortex_wt_SetReg(vortex, 0x4, edi, 0); /* param 3 0x20c */
308 vortex_wt_SetReg(vortex, 0x3, edi, 0); /* param 2 0x208 */
309 vortex_wt_SetReg(vortex, 0x2, edi, 0); /* param 1 0x204 */
310 vortex_wt_SetReg(vortex, 0x1, edi, 0); /* param 0 0x200 */
311 vortex_wt_SetReg(vortex, 0xb, edi, 0); /* delay 0x400 - 0x40c */
312 }
313 var10 |= 1;
314 for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++)
315 vortex_wt_SetReg(vortex, 0xa, edi, var10); /* ctrl */
316}
317
318/* Extract of CAdbTopology::SetVolume(struct _ASPVOLUME *) */
319#if 0
320static void vortex_wt_SetVolume(vortex_t * vortex, int wt, int vol[])
321{
322 wt_voice_t *voice = &(vortex->wt_voice[wt]);
323 int ecx = vol[1], eax = vol[0];
324
325 /* This is pure guess */
326 voice->parm0 &= 0xff00ffff;
327 voice->parm0 |= (vol[0] & 0xff) << 0x10;
328 voice->parm1 &= 0xff00ffff;
329 voice->parm1 |= (vol[1] & 0xff) << 0x10;
330
331 /* This is real */
332 hwwrite(vortex, WT_PARM(wt, 0), voice->parm0);
333 hwwrite(vortex, WT_PARM(wt, 1), voice->parm0);
334
335 if (voice->this_1D0 & 4) {
336 eax >>= 8;
337 ecx = eax;
338 if (ecx < 0x80)
339 ecx = 0x7f;
340 voice->parm3 &= 0xFFFFC07F;
341 voice->parm3 |= (ecx & 0x7f) << 7;
342 voice->parm3 &= 0xFFFFFF80;
343 voice->parm3 |= (eax & 0x7f);
344 } else {
345 voice->parm3 &= 0xFFE03FFF;
346 voice->parm3 |= (eax & 0xFE00) << 5;
347 }
348
349 hwwrite(vortex, WT_PARM(wt, 3), voice->parm3);
350}
351
352/* Extract of CAdbTopology::SetFrequency(unsigned long arg_0) */
353static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
354{
355 wt_voice_t *voice = &(vortex->wt_voice[wt]);
356 long int eax, edx;
357
358 //FIXME: 64 bit operation.
359 eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff;
360 edx = (((sr << 0xf) * 0x57619F1)) >> 0x20;
361
362 edx >>= 0xa;
363 edx <<= 1;
364 if (edx) {
365 if (edx & 0x0FFF80000)
366 eax = 0x7fff;
367 else {
368 edx <<= 0xd;
369 eax = 7;
370 while ((edx & 0x80000000) == 0) {
371 edx <<= 1;
372 eax--;
373 if (eax == 0) ;
374 break;
375 }
376 if (eax)
377 edx <<= 1;
378 eax <<= 0xc;
379 edx >>= 0x14;
380 eax |= edx;
381 }
382 } else
383 eax = 0;
384 voice->parm0 &= 0xffff0001;
385 voice->parm0 |= (eax & 0x7fff) << 1;
386 voice->parm1 = voice->parm0 | 1;
387 // Wt: this_1D4
388 //AuWt::WriteReg((ulong)(this_1DC<<4)+0x200, (ulong)this_1E4);
389 //AuWt::WriteReg((ulong)(this_1DC<<4)+0x204, (ulong)this_1E8);
390 hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
391 hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
392}
393#endif
394
395/* End of File */
diff --git a/sound/pci/au88x0/au88x0_wt.h b/sound/pci/au88x0/au88x0_wt.h
new file mode 100644
index 000000000000..d536c88b43bf
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_wt.h
@@ -0,0 +1,65 @@
1/***************************************************************************
2 * WT register offsets.
3 *
4 * Wed Oct 22 13:50:20 2003
5 * Copyright 2003 mjander
6 * mjander@users.sourceforge.org
7 ****************************************************************************/
8#ifndef _AU88X0_WT_H
9#define _AU88X0_WT_H
10
11/* WT channels are grouped in banks. Each bank has 0x20 channels. */
12/* Bank register address boundary is 0x8000 */
13
14#define NR_WT_PB 0x20
15
16/* WT bank base register (as dword address). */
17#define WT_BAR(x) (((x)&0xffe0)<<0x8)
18#define WT_BANK(x) (x>>5)
19/* WT Bank registers */
20#define WT_CTRL(bank) (((((bank)&1)<<0xd) + 0x00)<<2) /* 0x0000 */
21#define WT_SRAMP(bank) (((((bank)&1)<<0xd) + 0x01)<<2) /* 0x0004 */
22#define WT_DSREG(bank) (((((bank)&1)<<0xd) + 0x02)<<2) /* 0x0008 */
23#define WT_MRAMP(bank) (((((bank)&1)<<0xd) + 0x03)<<2) /* 0x000c */
24#define WT_GMODE(bank) (((((bank)&1)<<0xd) + 0x04)<<2) /* 0x0010 */
25#define WT_ARAMP(bank) (((((bank)&1)<<0xd) + 0x05)<<2) /* 0x0014 */
26/* WT Voice registers */
27#define WT_STEREO(voice) ((WT_BAR(voice)+ 0x20 +(((voice)&0x1f)>>1))<<2) /* 0x0080 */
28#define WT_MUTE(voice) ((WT_BAR(voice)+ 0x40 +((voice)&0x1f))<<2) /* 0x0100 */
29#define WT_RUN(voice) ((WT_BAR(voice)+ 0x60 +((voice)&0x1f))<<2) /* 0x0180 */
30/* Some kind of parameters. */
31/* PARM0, PARM1 : Filter (0xFF000000), SampleRate (0x0000FFFF) */
32/* PARM2, PARM3 : Still unknown */
33#define WT_PARM(x,y) (((WT_BAR(x))+ 0x80 +(((x)&0x1f)<<2)+(y))<<2) /* 0x0200 */
34#define WT_DELAY(x,y) (((WT_BAR(x))+ 0x100 +(((x)&0x1f)<<2)+(y))<<2) /* 0x0400 */
35
36/* Numeric indexes used by SetReg() and GetReg() */
37#if 0
38enum {
39 run = 0, /* 0 W 1:run 0:stop */
40 parm0, /* 1 W filter, samplerate */
41 parm1, /* 2 W filter, samplerate */
42 parm2, /* 3 W */
43 parm3, /* 4 RW volume. This value is calculated using floating point ops. */
44 sramp, /* 5 W */
45 mute, /* 6 W 1:mute, 0:unmute */
46 gmode, /* 7 RO Looks like only bit0 is used. */
47 aramp, /* 8 W */
48 mramp, /* 9 W */
49 ctrl, /* a W */
50 delay, /* b W All 4 values are written at once with same value. */
51 dsreg, /* c (R)W */
52} wt_reg;
53#endif
54
55typedef struct {
56 unsigned int parm0; /* this_1E4 */
57 unsigned int parm1; /* this_1E8 */
58 unsigned int parm2; /* this_1EC */
59 unsigned int parm3; /* this_1F0 */
60 unsigned int this_1D0;
61} wt_voice_t;
62
63#endif /* _AU88X0_WT_H */
64
65/* End of file */
diff --git a/sound/pci/au88x0/au88x0_xtalk.c b/sound/pci/au88x0/au88x0_xtalk.c
new file mode 100644
index 000000000000..df915fa3f88d
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_xtalk.c
@@ -0,0 +1,787 @@
1/***************************************************************************
2 * au88x0_cxtalk.c
3 *
4 * Wed Nov 19 16:29:47 2003
5 * Copyright 2003 mjander
6 * mjander@users.sourceforge.org
7 ****************************************************************************/
8
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25#include "au88x0_xtalk.h"
26
27/* Data (a whole lot of data.... ) */
28
29static short const sXtalkWideKLeftEq = 0x269C;
30static short const sXtalkWideKRightEq = 0x269C;
31static short const sXtalkWideKLeftXt = 0xF25E;
32static short const sXtalkWideKRightXt = 0xF25E;
33static short const sXtalkWideShiftLeftEq = 1;
34static short const sXtalkWideShiftRightEq = 1;
35static short const sXtalkWideShiftLeftXt = 0;
36static short const sXtalkWideShiftRightXt = 0;
37static unsigned short const wXtalkWideLeftDelay = 0xd;
38static unsigned short const wXtalkWideRightDelay = 0xd;
39static short const sXtalkNarrowKLeftEq = 0x468D;
40static short const sXtalkNarrowKRightEq = 0x468D;
41static short const sXtalkNarrowKLeftXt = 0xF82E;
42static short const sXtalkNarrowKRightXt = 0xF82E;
43static short const sXtalkNarrowShiftLeftEq = 0x3;
44static short const sXtalkNarrowShiftRightEq = 0x3;
45static short const sXtalkNarrowShiftLeftXt = 0;
46static short const sXtalkNarrowShiftRightXt = 0;
47static unsigned short const wXtalkNarrowLeftDelay = 0x7;
48static unsigned short const wXtalkNarrowRightDelay = 0x7;
49
50static xtalk_gains_t const asXtalkGainsDefault = {
51 0x4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000,
52 0x4000
53};
54
55static xtalk_gains_t const asXtalkGainsTest = {
56 0x8000, 0x7FFF, 0, 0xFFFF, 0x0001, 0xC000, 0x4000, 0xFFFE, 0x0002,
57 0
58};
59static xtalk_gains_t const asXtalkGains1Chan = {
60 0x7FFF, 0, 0, 0, 0x7FFF, 0, 0, 0, 0, 0
61};
62
63// Input gain for 4 A3D slices. One possible input pair is left zero.
64static xtalk_gains_t const asXtalkGainsAllChan = {
65 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
66 0
67 //0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff
68};
69static xtalk_gains_t const asXtalkGainsZeros = {
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
71};
72
73static xtalk_dline_t const alXtalkDlineZeros = {
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75 0, 0, 0,
76 0, 0, 0, 0, 0, 0, 0
77};
78static xtalk_dline_t const alXtalkDlineTest = {
79 0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF,
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81 0, 0, 0, 0
82};
83
84static xtalk_instate_t const asXtalkInStateZeros = { 0, 0, 0, 0 };
85static xtalk_instate_t const asXtalkInStateTest =
86 { 0xFF80, 0x0080, 0xFFFF, 0x0001 };
87static xtalk_state_t const asXtalkOutStateZeros = {
88 {0, 0, 0, 0},
89 {0, 0, 0, 0},
90 {0, 0, 0, 0},
91 {0, 0, 0, 0},
92 {0, 0, 0, 0}
93};
94static short const sDiamondKLeftEq = 0x401d;
95static short const sDiamondKRightEq = 0x401d;
96static short const sDiamondKLeftXt = 0xF90E;
97static short const sDiamondKRightXt = 0xF90E;
98static short const sDiamondShiftLeftEq = 1; /* 0xF90E Is this a bug ??? */
99static short const sDiamondShiftRightEq = 1;
100static short const sDiamondShiftLeftXt = 0;
101static short const sDiamondShiftRightXt = 0;
102static unsigned short const wDiamondLeftDelay = 0xb;
103static unsigned short const wDiamondRightDelay = 0xb;
104
105static xtalk_coefs_t const asXtalkWideCoefsLeftEq = {
106 {0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0},
107 {0x5F60, 0xCBCB, 0xFC26, 0x0305, 0},
108 {0x340B, 0xf504, 0x6CE8, 0x0D23, 0x00E4},
109 {0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA},
110 {0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0}
111};
112static xtalk_coefs_t const asXtalkWideCoefsRightEq = {
113 {0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0},
114 {0x5F60, 0xCBCB, 0xFC26, 0x0305, 0},
115 {0x340B, 0xF504, 0x6CE8, 0x0D23, 0x00E4},
116 {0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA},
117 {0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0}
118};
119static xtalk_coefs_t const asXtalkWideCoefsLeftXt = {
120 {0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047},
121 {0x6000, 0x206A, 0xC6CA, 0x40FF, 0},
122 {0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001},
123 {0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0},
124 {0, 0, 0, 0, 0}
125};
126static xtalk_coefs_t const asXtalkWideCoefsRightXt = {
127 {0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047},
128 {0x6000, 0x206A, 0xC6CA, 0x40FF, 0},
129 {0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001},
130 {0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0},
131 {0, 0, 0, 0, 0}
132};
133static xtalk_coefs_t const asXtalkNarrowCoefsLeftEq = {
134 {0x50B5, 0xD07C, 0x026D, 0xFD21, 0},
135 {0x460F, 0xE44F, 0xF75E, 0xEFA6, 0},
136 {0x556D, 0xDCAB, 0x2098, 0xF0F2, 0},
137 {0x7E03, 0xC1F0, 0x007D, 0xFF89, 0},
138 {0x383E, 0xFD9D, 0xB278, 0x4547, 0}
139};
140
141static xtalk_coefs_t const asXtalkNarrowCoefsRightEq = {
142 {0x50B5, 0xD07C, 0x026D, 0xFD21, 0},
143 {0x460F, 0xE44F, 0xF75E, 0xEFA6, 0},
144 {0x556D, 0xDCAB, 0x2098, 0xF0F2, 0},
145 {0x7E03, 0xC1F0, 0x007D, 0xFF89, 0},
146 {0x383E, 0xFD9D, 0xB278, 0x4547, 0}
147};
148
149static xtalk_coefs_t const asXtalkNarrowCoefsLeftXt = {
150 {0x3CB2, 0xDF49, 0xF6EA, 0x095B, 0},
151 {0x6777, 0xC915, 0xFEAF, 0x00B1, 0},
152 {0x7762, 0xC7D9, 0x025B, 0xFDA6, 0},
153 {0x6B7A, 0xD2AA, 0xF2FB, 0x0B64, 0},
154 {0, 0, 0, 0, 0}
155};
156
157static xtalk_coefs_t const asXtalkNarrowCoefsRightXt = {
158 {0x3CB2, 0xDF49, 0xF6EA, 0x095B, 0},
159 {0x6777, 0xC915, 0xFEAF, 0x00B1, 0},
160 {0x7762, 0xC7D9, 0x025B, 0xFDA6, 0},
161 {0x6B7A, 0xD2AA, 0xF2FB, 0x0B64, 0},
162 {0, 0, 0, 0, 0}
163};
164
165static xtalk_coefs_t const asXtalkCoefsZeros = {
166 {0, 0, 0, 0, 0},
167 {0, 0, 0, 0, 0},
168 {0, 0, 0, 0, 0},
169 {0, 0, 0, 0, 0},
170 {0, 0, 0, 0, 0}
171};
172static xtalk_coefs_t const asXtalkCoefsPipe = {
173 {0, 0, 0x0FA0, 0, 0},
174 {0, 0, 0x0FA0, 0, 0},
175 {0, 0, 0x0FA0, 0, 0},
176 {0, 0, 0x0FA0, 0, 0},
177 {0, 0, 0x1180, 0, 0},
178};
179static xtalk_coefs_t const asXtalkCoefsNegPipe = {
180 {0, 0, 0xF380, 0, 0},
181 {0, 0, 0xF380, 0, 0},
182 {0, 0, 0xF380, 0, 0},
183 {0, 0, 0xF380, 0, 0},
184 {0, 0, 0xF200, 0, 0}
185};
186
187static xtalk_coefs_t const asXtalkCoefsNumTest = {
188 {0, 0, 0xF380, 0x8000, 0x6D60},
189 {0, 0, 0, 0, 0},
190 {0, 0, 0, 0, 0},
191 {0, 0, 0, 0, 0},
192 {0, 0, 0, 0, 0}
193};
194
195static xtalk_coefs_t const asXtalkCoefsDenTest = {
196 {0xC000, 0x2000, 0x4000, 0, 0},
197 {0, 0, 0, 0, 0},
198 {0, 0, 0, 0, 0},
199 {0, 0, 0, 0, 0},
200 {0, 0, 0, 0, 0}
201};
202
203static xtalk_state_t const asXtalkOutStateTest = {
204 {0x7FFF, 0x0004, 0xFFFC, 0},
205 {0xFE00, 0x0008, 0xFFF8, 0x4000},
206 {0x200, 0x0010, 0xFFF0, 0xC000},
207 {0x8000, 0x0020, 0xFFE0, 0},
208 {0, 0, 0, 0}
209};
210
211static xtalk_coefs_t const asDiamondCoefsLeftEq = {
212 {0x0F1E, 0x2D05, 0xF8E3, 0x07C8, 0},
213 {0x45E2, 0xCA51, 0x0448, 0xFCE7, 0},
214 {0xA93E, 0xDBD5, 0x022C, 0x028A, 0},
215 {0, 0, 0, 0, 0},
216 {0, 0, 0, 0, 0}
217};
218
219static xtalk_coefs_t const asDiamondCoefsRightEq = {
220 {0x0F1E, 0x2D05, 0xF8E3, 0x07C8, 0},
221 {0x45E2, 0xCA51, 0x0448, 0xFCE7, 0},
222 {0xA93E, 0xDBD5, 0x022C, 0x028A, 0},
223 {0, 0, 0, 0, 0},
224 {0, 0, 0, 0, 0}
225};
226
227static xtalk_coefs_t const asDiamondCoefsLeftXt = {
228 {0x3B50, 0xFE08, 0xF959, 0x0060, 0},
229 {0x9FCB, 0xD8F1, 0x00A2, 0x003A, 0},
230 {0, 0, 0, 0, 0},
231 {0, 0, 0, 0, 0},
232 {0, 0, 0, 0, 0}
233};
234
235static xtalk_coefs_t const asDiamondCoefsRightXt = {
236 {0x3B50, 0xFE08, 0xF959, 0x0060, 0},
237 {0x9FCB, 0xD8F1, 0x00A2, 0x003A, 0},
238 {0, 0, 0, 0, 0},
239 {0, 0, 0, 0, 0},
240 {0, 0, 0, 0, 0}
241};
242
243 /**/
244/* XTalk EQ and XT */
245static void
246vortex_XtalkHw_SetLeftEQ(vortex_t * vortex, short arg_0, short arg_4,
247 xtalk_coefs_t const coefs)
248{
249 int i;
250
251 for (i = 0; i < 5; i++) {
252 hwwrite(vortex->mmio, 0x24200 + i * 0x24, coefs[i][0]);
253 hwwrite(vortex->mmio, 0x24204 + i * 0x24, coefs[i][1]);
254 hwwrite(vortex->mmio, 0x24208 + i * 0x24, coefs[i][2]);
255 hwwrite(vortex->mmio, 0x2420c + i * 0x24, coefs[i][3]);
256 hwwrite(vortex->mmio, 0x24210 + i * 0x24, coefs[i][4]);
257 }
258 hwwrite(vortex->mmio, 0x24538, arg_0 & 0xffff);
259 hwwrite(vortex->mmio, 0x2453C, arg_4 & 0xffff);
260}
261
262static void
263vortex_XtalkHw_SetRightEQ(vortex_t * vortex, short arg_0, short arg_4,
264 xtalk_coefs_t const coefs)
265{
266 int i;
267
268 for (i = 0; i < 5; i++) {
269 hwwrite(vortex->mmio, 0x242b4 + i * 0x24, coefs[i][0]);
270 hwwrite(vortex->mmio, 0x242b8 + i * 0x24, coefs[i][1]);
271 hwwrite(vortex->mmio, 0x242bc + i * 0x24, coefs[i][2]);
272 hwwrite(vortex->mmio, 0x242c0 + i * 0x24, coefs[i][3]);
273 hwwrite(vortex->mmio, 0x242c4 + i * 0x24, coefs[i][4]);
274 }
275 hwwrite(vortex->mmio, 0x24540, arg_0 & 0xffff);
276 hwwrite(vortex->mmio, 0x24544, arg_4 & 0xffff);
277}
278
279static void
280vortex_XtalkHw_SetLeftXT(vortex_t * vortex, short arg_0, short arg_4,
281 xtalk_coefs_t const coefs)
282{
283 int i;
284
285 for (i = 0; i < 5; i++) {
286 hwwrite(vortex->mmio, 0x24368 + i * 0x24, coefs[i][0]);
287 hwwrite(vortex->mmio, 0x2436c + i * 0x24, coefs[i][1]);
288 hwwrite(vortex->mmio, 0x24370 + i * 0x24, coefs[i][2]);
289 hwwrite(vortex->mmio, 0x24374 + i * 0x24, coefs[i][3]);
290 hwwrite(vortex->mmio, 0x24378 + i * 0x24, coefs[i][4]);
291 }
292 hwwrite(vortex->mmio, 0x24548, arg_0 & 0xffff);
293 hwwrite(vortex->mmio, 0x2454C, arg_4 & 0xffff);
294}
295
296static void
297vortex_XtalkHw_SetRightXT(vortex_t * vortex, short arg_0, short arg_4,
298 xtalk_coefs_t const coefs)
299{
300 int i;
301
302 for (i = 0; i < 5; i++) {
303 hwwrite(vortex->mmio, 0x2441C + i * 0x24, coefs[i][0]);
304 hwwrite(vortex->mmio, 0x24420 + i * 0x24, coefs[i][1]);
305 hwwrite(vortex->mmio, 0x24424 + i * 0x24, coefs[i][2]);
306 hwwrite(vortex->mmio, 0x24428 + i * 0x24, coefs[i][3]);
307 hwwrite(vortex->mmio, 0x2442C + i * 0x24, coefs[i][4]);
308 }
309 hwwrite(vortex->mmio, 0x24550, arg_0 & 0xffff);
310 hwwrite(vortex->mmio, 0x24554, arg_4 & 0xffff);
311}
312
313static void
314vortex_XtalkHw_SetLeftEQStates(vortex_t * vortex,
315 xtalk_instate_t const arg_0,
316 xtalk_state_t const coefs)
317{
318 int i;
319
320 for (i = 0; i < 5; i++) {
321 hwwrite(vortex->mmio, 0x24214 + i * 0x24, coefs[i][0]);
322 hwwrite(vortex->mmio, 0x24218 + i * 0x24, coefs[i][1]);
323 hwwrite(vortex->mmio, 0x2421C + i * 0x24, coefs[i][2]);
324 hwwrite(vortex->mmio, 0x24220 + i * 0x24, coefs[i][3]);
325 }
326 hwwrite(vortex->mmio, 0x244F8 + i * 0x24, arg_0[0]);
327 hwwrite(vortex->mmio, 0x244FC + i * 0x24, arg_0[1]);
328 hwwrite(vortex->mmio, 0x24500 + i * 0x24, arg_0[2]);
329 hwwrite(vortex->mmio, 0x24504 + i * 0x24, arg_0[3]);
330}
331
332static void
333vortex_XtalkHw_SetRightEQStates(vortex_t * vortex,
334 xtalk_instate_t const arg_0,
335 xtalk_state_t const coefs)
336{
337 int i;
338
339 for (i = 0; i < 5; i++) {
340 hwwrite(vortex->mmio, 0x242C8 + i * 0x24, coefs[i][0]);
341 hwwrite(vortex->mmio, 0x242CC + i * 0x24, coefs[i][1]);
342 hwwrite(vortex->mmio, 0x242D0 + i * 0x24, coefs[i][2]);
343 hwwrite(vortex->mmio, 0x244D4 + i * 0x24, coefs[i][3]);
344 }
345 hwwrite(vortex->mmio, 0x24508 + i * 0x24, arg_0[0]);
346 hwwrite(vortex->mmio, 0x2450C + i * 0x24, arg_0[1]);
347 hwwrite(vortex->mmio, 0x24510 + i * 0x24, arg_0[2]);
348 hwwrite(vortex->mmio, 0x24514 + i * 0x24, arg_0[3]);
349}
350
351static void
352vortex_XtalkHw_SetLeftXTStates(vortex_t * vortex,
353 xtalk_instate_t const arg_0,
354 xtalk_state_t const coefs)
355{
356 int i;
357
358 for (i = 0; i < 5; i++) {
359 hwwrite(vortex->mmio, 0x2437C + i * 0x24, coefs[i][0]);
360 hwwrite(vortex->mmio, 0x24380 + i * 0x24, coefs[i][1]);
361 hwwrite(vortex->mmio, 0x24384 + i * 0x24, coefs[i][2]);
362 hwwrite(vortex->mmio, 0x24388 + i * 0x24, coefs[i][3]);
363 }
364 hwwrite(vortex->mmio, 0x24518 + i * 0x24, arg_0[0]);
365 hwwrite(vortex->mmio, 0x2451C + i * 0x24, arg_0[1]);
366 hwwrite(vortex->mmio, 0x24520 + i * 0x24, arg_0[2]);
367 hwwrite(vortex->mmio, 0x24524 + i * 0x24, arg_0[3]);
368}
369
370static void
371vortex_XtalkHw_SetRightXTStates(vortex_t * vortex,
372 xtalk_instate_t const arg_0,
373 xtalk_state_t const coefs)
374{
375 int i;
376
377 for (i = 0; i < 5; i++) {
378 hwwrite(vortex->mmio, 0x24430 + i * 0x24, coefs[i][0]);
379 hwwrite(vortex->mmio, 0x24434 + i * 0x24, coefs[i][1]);
380 hwwrite(vortex->mmio, 0x24438 + i * 0x24, coefs[i][2]);
381 hwwrite(vortex->mmio, 0x2443C + i * 0x24, coefs[i][3]);
382 }
383 hwwrite(vortex->mmio, 0x24528 + i * 0x24, arg_0[0]);
384 hwwrite(vortex->mmio, 0x2452C + i * 0x24, arg_0[1]);
385 hwwrite(vortex->mmio, 0x24530 + i * 0x24, arg_0[2]);
386 hwwrite(vortex->mmio, 0x24534 + i * 0x24, arg_0[3]);
387}
388
389#if 0
390static void
391vortex_XtalkHw_GetLeftEQ(vortex_t * vortex, short *arg_0, short *arg_4,
392 xtalk_coefs_t coefs)
393{
394 int i;
395
396 for (i = 0; i < 5; i++) {
397 coefs[i][0] = hwread(vortex->mmio, 0x24200 + i * 0x24);
398 coefs[i][1] = hwread(vortex->mmio, 0x24204 + i * 0x24);
399 coefs[i][2] = hwread(vortex->mmio, 0x24208 + i * 0x24);
400 coefs[i][3] = hwread(vortex->mmio, 0x2420c + i * 0x24);
401 coefs[i][4] = hwread(vortex->mmio, 0x24210 + i * 0x24);
402 }
403 *arg_0 = hwread(vortex->mmio, 0x24538) & 0xffff;
404 *arg_4 = hwread(vortex->mmio, 0x2453c) & 0xffff;
405}
406
407static void
408vortex_XtalkHw_GetRightEQ(vortex_t * vortex, short *arg_0, short *arg_4,
409 xtalk_coefs_t coefs)
410{
411 int i;
412
413 for (i = 0; i < 5; i++) {
414 coefs[i][0] = hwread(vortex->mmio, 0x242b4 + i * 0x24);
415 coefs[i][1] = hwread(vortex->mmio, 0x242b8 + i * 0x24);
416 coefs[i][2] = hwread(vortex->mmio, 0x242bc + i * 0x24);
417 coefs[i][3] = hwread(vortex->mmio, 0x242c0 + i * 0x24);
418 coefs[i][4] = hwread(vortex->mmio, 0x242c4 + i * 0x24);
419 }
420 *arg_0 = hwread(vortex->mmio, 0x24540) & 0xffff;
421 *arg_4 = hwread(vortex->mmio, 0x24544) & 0xffff;
422}
423
424static void
425vortex_XtalkHw_GetLeftXT(vortex_t * vortex, short *arg_0, short *arg_4,
426 xtalk_coefs_t coefs)
427{
428 int i;
429
430 for (i = 0; i < 5; i++) {
431 coefs[i][0] = hwread(vortex->mmio, 0x24368 + i * 0x24);
432 coefs[i][1] = hwread(vortex->mmio, 0x2436C + i * 0x24);
433 coefs[i][2] = hwread(vortex->mmio, 0x24370 + i * 0x24);
434 coefs[i][3] = hwread(vortex->mmio, 0x24374 + i * 0x24);
435 coefs[i][4] = hwread(vortex->mmio, 0x24378 + i * 0x24);
436 }
437 *arg_0 = hwread(vortex->mmio, 0x24548) & 0xffff;
438 *arg_4 = hwread(vortex->mmio, 0x2454C) & 0xffff;
439}
440
441static void
442vortex_XtalkHw_GetRightXT(vortex_t * vortex, short *arg_0, short *arg_4,
443 xtalk_coefs_t coefs)
444{
445 int i;
446
447 for (i = 0; i < 5; i++) {
448 coefs[i][0] = hwread(vortex->mmio, 0x2441C + i * 0x24);
449 coefs[i][1] = hwread(vortex->mmio, 0x24420 + i * 0x24);
450 coefs[i][2] = hwread(vortex->mmio, 0x24424 + i * 0x24);
451 coefs[i][3] = hwread(vortex->mmio, 0x24428 + i * 0x24);
452 coefs[i][4] = hwread(vortex->mmio, 0x2442C + i * 0x24);
453 }
454 *arg_0 = hwread(vortex->mmio, 0x24550) & 0xffff;
455 *arg_4 = hwread(vortex->mmio, 0x24554) & 0xffff;
456}
457
458static void
459vortex_XtalkHw_GetLeftEQStates(vortex_t * vortex, xtalk_instate_t arg_0,
460 xtalk_state_t coefs)
461{
462 int i;
463
464 for (i = 0; i < 5; i++) {
465 coefs[i][0] = hwread(vortex->mmio, 0x24214 + i * 0x24);
466 coefs[i][1] = hwread(vortex->mmio, 0x24218 + i * 0x24);
467 coefs[i][2] = hwread(vortex->mmio, 0x2421C + i * 0x24);
468 coefs[i][3] = hwread(vortex->mmio, 0x24220 + i * 0x24);
469 }
470 arg_0[0] = hwread(vortex->mmio, 0x244F8 + i * 0x24);
471 arg_0[1] = hwread(vortex->mmio, 0x244FC + i * 0x24);
472 arg_0[2] = hwread(vortex->mmio, 0x24500 + i * 0x24);
473 arg_0[3] = hwread(vortex->mmio, 0x24504 + i * 0x24);
474}
475
476static void
477vortex_XtalkHw_GetRightEQStates(vortex_t * vortex, xtalk_instate_t arg_0,
478 xtalk_state_t coefs)
479{
480 int i;
481
482 for (i = 0; i < 5; i++) {
483 coefs[i][0] = hwread(vortex->mmio, 0x242C8 + i * 0x24);
484 coefs[i][1] = hwread(vortex->mmio, 0x242CC + i * 0x24);
485 coefs[i][2] = hwread(vortex->mmio, 0x242D0 + i * 0x24);
486 coefs[i][3] = hwread(vortex->mmio, 0x242D4 + i * 0x24);
487 }
488 arg_0[0] = hwread(vortex->mmio, 0x24508 + i * 0x24);
489 arg_0[1] = hwread(vortex->mmio, 0x2450C + i * 0x24);
490 arg_0[2] = hwread(vortex->mmio, 0x24510 + i * 0x24);
491 arg_0[3] = hwread(vortex->mmio, 0x24514 + i * 0x24);
492}
493
494static void
495vortex_XtalkHw_GetLeftXTStates(vortex_t * vortex, xtalk_instate_t arg_0,
496 xtalk_state_t coefs)
497{
498 int i;
499
500 for (i = 0; i < 5; i++) {
501 coefs[i][0] = hwread(vortex->mmio, 0x2437C + i * 0x24);
502 coefs[i][1] = hwread(vortex->mmio, 0x24380 + i * 0x24);
503 coefs[i][2] = hwread(vortex->mmio, 0x24384 + i * 0x24);
504 coefs[i][3] = hwread(vortex->mmio, 0x24388 + i * 0x24);
505 }
506 arg_0[0] = hwread(vortex->mmio, 0x24518 + i * 0x24);
507 arg_0[1] = hwread(vortex->mmio, 0x2451C + i * 0x24);
508 arg_0[2] = hwread(vortex->mmio, 0x24520 + i * 0x24);
509 arg_0[3] = hwread(vortex->mmio, 0x24524 + i * 0x24);
510}
511
512static void
513vortex_XtalkHw_GetRightXTStates(vortex_t * vortex, xtalk_instate_t arg_0,
514 xtalk_state_t coefs)
515{
516 int i;
517
518 for (i = 0; i < 5; i++) {
519 coefs[i][0] = hwread(vortex->mmio, 0x24430 + i * 0x24);
520 coefs[i][1] = hwread(vortex->mmio, 0x24434 + i * 0x24);
521 coefs[i][2] = hwread(vortex->mmio, 0x24438 + i * 0x24);
522 coefs[i][3] = hwread(vortex->mmio, 0x2443C + i * 0x24);
523 }
524 arg_0[0] = hwread(vortex->mmio, 0x24528 + i * 0x24);
525 arg_0[1] = hwread(vortex->mmio, 0x2452C + i * 0x24);
526 arg_0[2] = hwread(vortex->mmio, 0x24530 + i * 0x24);
527 arg_0[3] = hwread(vortex->mmio, 0x24534 + i * 0x24);
528}
529
530#endif
531/* Gains */
532
533static void
534vortex_XtalkHw_SetGains(vortex_t * vortex, xtalk_gains_t const gains)
535{
536 int i;
537
538 for (i = 0; i < XTGAINS_SZ; i++) {
539 hwwrite(vortex->mmio, 0x244D0 + (i * 4), gains[i]);
540 }
541}
542
543static void
544vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex)
545{
546 vortex_XtalkHw_SetGains(vortex, asXtalkGainsAllChan);
547}
548
549#if 0
550static void vortex_XtalkHw_GetGains(vortex_t * vortex, xtalk_gains_t gains)
551{
552 int i;
553
554 for (i = 0; i < XTGAINS_SZ; i++)
555 gains[i] = hwread(vortex->mmio, 0x244D0 + i * 4);
556}
557
558#endif
559/* Delay parameters */
560
561static void
562vortex_XtalkHw_SetDelay(vortex_t * vortex, unsigned short right,
563 unsigned short left)
564{
565 int esp0 = 0;
566
567 esp0 &= 0x1FFFFFFF;
568 esp0 |= 0xA0000000;
569 esp0 = (esp0 & 0xffffE0ff) | ((right & 0x1F) << 8);
570 esp0 = (esp0 & 0xfffc1fff) | ((left & 0x1F) << 0xd);
571
572 hwwrite(vortex->mmio, 0x24660, esp0);
573}
574
575static void
576vortex_XtalkHw_SetLeftDline(vortex_t * vortex, xtalk_dline_t const dline)
577{
578 int i;
579
580 for (i = 0; i < 0x20; i++) {
581 hwwrite(vortex->mmio, 0x24000 + (i << 2), dline[i] & 0xffff);
582 hwwrite(vortex->mmio, 0x24080 + (i << 2), dline[i] >> 0x10);
583 }
584}
585
586static void
587vortex_XtalkHw_SetRightDline(vortex_t * vortex, xtalk_dline_t const dline)
588{
589 int i;
590
591 for (i = 0; i < 0x20; i++) {
592 hwwrite(vortex->mmio, 0x24100 + (i << 2), dline[i] & 0xffff);
593 hwwrite(vortex->mmio, 0x24180 + (i << 2), dline[i] >> 0x10);
594 }
595}
596
597#if 0
598static void
599vortex_XtalkHw_GetDelay(vortex_t * vortex, unsigned short *right,
600 unsigned short *left)
601{
602 int esp0;
603
604 esp0 = hwread(vortex->mmio, 0x24660);
605 *right = (esp0 >> 8) & 0x1f;
606 *left = (esp0 >> 0xd) & 0x1f;
607}
608
609static void vortex_XtalkHw_GetLeftDline(vortex_t * vortex, xtalk_dline_t dline)
610{
611 int i;
612
613 for (i = 0; i < 0x20; i++) {
614 dline[i] =
615 (hwread(vortex->mmio, 0x24000 + (i << 2)) & 0xffff) |
616 (hwread(vortex->mmio, 0x24080 + (i << 2)) << 0x10);
617 }
618}
619
620static void vortex_XtalkHw_GetRightDline(vortex_t * vortex, xtalk_dline_t dline)
621{
622 int i;
623
624 for (i = 0; i < 0x20; i++) {
625 dline[i] =
626 (hwread(vortex->mmio, 0x24100 + (i << 2)) & 0xffff) |
627 (hwread(vortex->mmio, 0x24180 + (i << 2)) << 0x10);
628 }
629}
630
631#endif
632/* Control/Global stuff */
633
634#if 0
635static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, unsigned long ctrl)
636{
637 hwwrite(vortex->mmio, 0x24660, ctrl);
638}
639static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, unsigned long *ctrl)
640{
641 *ctrl = hwread(vortex->mmio, 0x24660);
642}
643#endif
644static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr)
645{
646 int temp;
647
648 temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
649 temp = (temp & 0xffffff07) | ((sr & 0x1f) << 3);
650 hwwrite(vortex->mmio, 0x24660, temp);
651}
652
653#if 0
654static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, int *sr)
655{
656 *sr = (hwread(vortex->mmio, 0x24660) >> 3) & 0x1f;
657}
658
659#endif
660static void vortex_XtalkHw_Enable(vortex_t * vortex)
661{
662 int temp;
663
664 temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
665 temp |= 1;
666 hwwrite(vortex->mmio, 0x24660, temp);
667
668}
669
670static void vortex_XtalkHw_Disable(vortex_t * vortex)
671{
672 int temp;
673
674 temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
675 temp &= 0xfffffffe;
676 hwwrite(vortex->mmio, 0x24660, temp);
677
678}
679
680static void vortex_XtalkHw_ZeroIO(vortex_t * vortex)
681{
682 int i;
683
684 for (i = 0; i < 20; i++)
685 hwwrite(vortex->mmio, 0x24600 + (i << 2), 0);
686 for (i = 0; i < 4; i++)
687 hwwrite(vortex->mmio, 0x24650 + (i << 2), 0);
688}
689
690static void vortex_XtalkHw_ZeroState(vortex_t * vortex)
691{
692 vortex_XtalkHw_ZeroIO(vortex); // inlined
693
694 vortex_XtalkHw_SetLeftEQ(vortex, 0, 0, asXtalkCoefsZeros);
695 vortex_XtalkHw_SetRightEQ(vortex, 0, 0, asXtalkCoefsZeros);
696
697 vortex_XtalkHw_SetLeftXT(vortex, 0, 0, asXtalkCoefsZeros);
698 vortex_XtalkHw_SetRightXT(vortex, 0, 0, asXtalkCoefsZeros);
699
700 vortex_XtalkHw_SetGains(vortex, asXtalkGainsZeros); // inlined
701
702 vortex_XtalkHw_SetDelay(vortex, 0, 0); // inlined
703
704 vortex_XtalkHw_SetLeftDline(vortex, alXtalkDlineZeros); // inlined
705 vortex_XtalkHw_SetRightDline(vortex, alXtalkDlineZeros); // inlined
706 vortex_XtalkHw_SetLeftDline(vortex, alXtalkDlineZeros); // inlined
707 vortex_XtalkHw_SetRightDline(vortex, alXtalkDlineZeros); // inlined
708
709 vortex_XtalkHw_SetLeftEQStates(vortex, asXtalkInStateZeros,
710 asXtalkOutStateZeros);
711 vortex_XtalkHw_SetRightEQStates(vortex, asXtalkInStateZeros,
712 asXtalkOutStateZeros);
713 vortex_XtalkHw_SetLeftXTStates(vortex, asXtalkInStateZeros,
714 asXtalkOutStateZeros);
715 vortex_XtalkHw_SetRightXTStates(vortex, asXtalkInStateZeros,
716 asXtalkOutStateZeros);
717}
718
719static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex)
720{
721
722 vortex_XtalkHw_SetLeftEQ(vortex, 0, 1, asXtalkCoefsPipe);
723 vortex_XtalkHw_SetRightEQ(vortex, 0, 1, asXtalkCoefsPipe);
724 vortex_XtalkHw_SetLeftXT(vortex, 0, 0, asXtalkCoefsZeros);
725 vortex_XtalkHw_SetRightXT(vortex, 0, 0, asXtalkCoefsZeros);
726
727 vortex_XtalkHw_SetDelay(vortex, 0, 0); // inlined
728}
729
730static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex)
731{
732
733 vortex_XtalkHw_SetLeftEQ(vortex, sXtalkWideKLeftEq,
734 sXtalkWideShiftLeftEq, asXtalkWideCoefsLeftEq);
735 vortex_XtalkHw_SetRightEQ(vortex, sXtalkWideKRightEq,
736 sXtalkWideShiftRightEq,
737 asXtalkWideCoefsRightEq);
738 vortex_XtalkHw_SetLeftXT(vortex, sXtalkWideKLeftXt,
739 sXtalkWideShiftLeftXt, asXtalkWideCoefsLeftXt);
740 vortex_XtalkHw_SetRightXT(vortex, sXtalkWideKLeftXt,
741 sXtalkWideShiftLeftXt,
742 asXtalkWideCoefsLeftXt);
743
744 vortex_XtalkHw_SetDelay(vortex, wXtalkWideRightDelay, wXtalkWideLeftDelay); // inlined
745}
746
747static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex)
748{
749
750 vortex_XtalkHw_SetLeftEQ(vortex, sXtalkNarrowKLeftEq,
751 sXtalkNarrowShiftLeftEq,
752 asXtalkNarrowCoefsLeftEq);
753 vortex_XtalkHw_SetRightEQ(vortex, sXtalkNarrowKRightEq,
754 sXtalkNarrowShiftRightEq,
755 asXtalkNarrowCoefsRightEq);
756 vortex_XtalkHw_SetLeftXT(vortex, sXtalkNarrowKLeftXt,
757 sXtalkNarrowShiftLeftXt,
758 asXtalkNarrowCoefsLeftXt);
759 vortex_XtalkHw_SetRightXT(vortex, sXtalkNarrowKLeftXt,
760 sXtalkNarrowShiftLeftXt,
761 asXtalkNarrowCoefsLeftXt);
762
763 vortex_XtalkHw_SetDelay(vortex, wXtalkNarrowRightDelay, wXtalkNarrowLeftDelay); // inlined
764}
765
766static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex)
767{
768
769 //sDiamondKLeftEq,sDiamondKRightXt,asDiamondCoefsLeftEq
770 vortex_XtalkHw_SetLeftEQ(vortex, sDiamondKLeftEq,
771 sDiamondShiftLeftEq, asDiamondCoefsLeftEq);
772 vortex_XtalkHw_SetRightEQ(vortex, sDiamondKRightEq,
773 sDiamondShiftRightEq, asDiamondCoefsRightEq);
774 vortex_XtalkHw_SetLeftXT(vortex, sDiamondKLeftXt,
775 sDiamondShiftLeftXt, asDiamondCoefsLeftXt);
776 vortex_XtalkHw_SetRightXT(vortex, sDiamondKLeftXt,
777 sDiamondShiftLeftXt, asDiamondCoefsLeftXt);
778
779 vortex_XtalkHw_SetDelay(vortex, wDiamondRightDelay, wDiamondLeftDelay); // inlined
780}
781
782static void vortex_XtalkHw_init(vortex_t * vortex)
783{
784 vortex_XtalkHw_ZeroState(vortex);
785}
786
787/* End of file */
diff --git a/sound/pci/au88x0/au88x0_xtalk.h b/sound/pci/au88x0/au88x0_xtalk.h
new file mode 100644
index 000000000000..0b8d7b64012d
--- /dev/null
+++ b/sound/pci/au88x0/au88x0_xtalk.h
@@ -0,0 +1,61 @@
1/***************************************************************************
2 * au88x0_cxtalk.h
3 *
4 * Wed Nov 19 19:07:17 2003
5 * Copyright 2003 mjander
6 * mjander@users.sourceforge.org
7 ****************************************************************************/
8
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25/* The crosstalk canceler supports 5 stereo input channels. The result is
26 available at one single output route pair (stereo). */
27
28#ifndef _AU88X0_CXTALK_H
29#define _AU88X0_CXTALK_H
30
31#include "au88x0.h"
32
33#define XTDLINE_SZ 32
34#define XTGAINS_SZ 10
35#define XTINST_SZ 4
36
37#define XT_HEADPHONE 1
38#define XT_SPEAKER0 2
39#define XT_SPEAKER1 3
40#define XT_DIAMOND 4
41
42typedef long xtalk_dline_t[XTDLINE_SZ];
43typedef short xtalk_gains_t[XTGAINS_SZ];
44typedef short xtalk_instate_t[XTINST_SZ];
45typedef short xtalk_coefs_t[5][5];
46typedef short xtalk_state_t[5][4];
47
48static void vortex_XtalkHw_SetGains(vortex_t * vortex,
49 xtalk_gains_t const gains);
50static void vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex);
51static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr);
52static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
53static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
54static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex);
55static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex);
56static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex);
57static void vortex_XtalkHw_Enable(vortex_t * vortex);
58static void vortex_XtalkHw_Disable(vortex_t * vortex);
59static void vortex_XtalkHw_init(vortex_t * vortex);
60
61#endif /* _AU88X0_CXTALK_H */