diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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')
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 @@ | |||
1 | snd-au8810-objs := au8810.o | ||
2 | snd-au8820-objs := au8820.o | ||
3 | snd-au8830-objs := au8830.o | ||
4 | |||
5 | obj-$(CONFIG_SND_AU8810) += snd-au8810.o | ||
6 | obj-$(CONFIG_SND_AU8820) += snd-au8820.o | ||
7 | obj-$(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" | ||
3 | static 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" | ||
3 | static 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" | ||
3 | static 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") | ||
26 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
27 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
28 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
29 | static int pcifix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 255 }; | ||
30 | |||
31 | module_param_array(index, int, NULL, 0444); | ||
32 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); | ||
33 | module_param_array(id, charp, NULL, 0444); | ||
34 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | ||
35 | module_param_array(enable, bool, NULL, 0444); | ||
36 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | ||
37 | module_param_array(pcifix, int, NULL, 0444); | ||
38 | MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard."); | ||
39 | |||
40 | MODULE_DESCRIPTION("Aureal vortex"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | MODULE_SUPPORTED_DEVICE("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}"); | ||
43 | |||
44 | MODULE_DEVICE_TABLE(pci, snd_vortex_ids); | ||
45 | |||
46 | static 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 | |||
58 | static 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 | |||
80 | static 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") | ||
115 | static 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") | ||
133 | static int __devinit | ||
134 | snd_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 | ||
226 | static int __devinit | ||
227 | snd_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 | ||
361 | static 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 | ||
368 | static 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 | ||
376 | static int __init alsa_card_vortex_init(void) | ||
377 | { | ||
378 | return pci_module_init(&driver); | ||
379 | } | ||
380 | |||
381 | // clean up the module | ||
382 | static void __exit alsa_card_vortex_exit(void) | ||
383 | { | ||
384 | pci_unregister_driver(&driver); | ||
385 | } | ||
386 | |||
387 | module_init(alsa_card_vortex_init) | ||
388 | module_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 */ | ||
106 | typedef 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 | |||
131 | typedef struct snd_vortex vortex_t; | ||
132 | struct 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 */ | ||
189 | static void vortex_adb_setsrc(vortex_t * vortex, int adbdma, | ||
190 | unsigned int cvrt, int dir); | ||
191 | |||
192 | /* DMA Engines. */ | ||
193 | static void vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, | ||
194 | snd_pcm_sgbuf_t * sgbuf, int size, | ||
195 | int count); | ||
196 | static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, | ||
197 | int dir, int fmt, int d, | ||
198 | unsigned long offset); | ||
199 | static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb); | ||
200 | #ifndef CHIP_AU8810 | ||
201 | static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma, | ||
202 | snd_pcm_sgbuf_t * sgbuf, int size, | ||
203 | int count); | ||
204 | static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d, /*int e, */ | ||
205 | unsigned long offset); | ||
206 | static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb); | ||
207 | #endif | ||
208 | |||
209 | static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma); | ||
210 | //static void vortex_adbdma_stopfifo(vortex_t *vortex, int adbdma); | ||
211 | static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma); | ||
212 | static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma); | ||
213 | static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma); | ||
214 | static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma); | ||
215 | |||
216 | #ifndef CHIP_AU8810 | ||
217 | static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma); | ||
218 | static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma); | ||
219 | static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma); | ||
220 | static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma); | ||
221 | static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma); | ||
222 | #endif | ||
223 | |||
224 | /* global stuff. */ | ||
225 | static void vortex_codec_init(vortex_t * vortex); | ||
226 | static void vortex_codec_write(ac97_t * codec, unsigned short addr, | ||
227 | unsigned short data); | ||
228 | static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr); | ||
229 | static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode); | ||
230 | |||
231 | static int vortex_core_init(vortex_t * card); | ||
232 | static int vortex_core_shutdown(vortex_t * card); | ||
233 | static void vortex_enable_int(vortex_t * card); | ||
234 | static irqreturn_t vortex_interrupt(int irq, void *dev_id, | ||
235 | struct pt_regs *regs); | ||
236 | static int vortex_alsafmt_aspfmt(int alsafmt); | ||
237 | |||
238 | /* Connection stuff. */ | ||
239 | static void vortex_connect_default(vortex_t * vortex, int en); | ||
240 | static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, | ||
241 | int dir, int type); | ||
242 | static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, | ||
243 | int restype); | ||
244 | #ifndef CHIP_AU8810 | ||
245 | static int vortex_wt_allocroute(vortex_t * vortex, int dma, int nr_ch); | ||
246 | static void vortex_wt_connect(vortex_t * vortex, int en); | ||
247 | static void vortex_wt_init(vortex_t * vortex); | ||
248 | #endif | ||
249 | |||
250 | static void vortex_route(vortex_t * vortex, int en, unsigned char channel, | ||
251 | unsigned char source, unsigned char dest); | ||
252 | #if 0 | ||
253 | static void vortex_routes(vortex_t * vortex, int en, unsigned char channel, | ||
254 | unsigned char source, unsigned char dest0, | ||
255 | unsigned char dest1); | ||
256 | #endif | ||
257 | static void vortex_connection_mixin_mix(vortex_t * vortex, int en, | ||
258 | unsigned char mixin, | ||
259 | unsigned char mix, int a); | ||
260 | static void vortex_mix_setinputvolumebyte(vortex_t * vortex, | ||
261 | unsigned char mix, int mixin, | ||
262 | unsigned char vol); | ||
263 | static void vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix, | ||
264 | unsigned char vol); | ||
265 | |||
266 | /* A3D functions. */ | ||
267 | #ifndef CHIP_AU8820 | ||
268 | static void vortex_Vort3D(vortex_t * v, int en); | ||
269 | static void vortex_Vort3D_connect(vortex_t * vortex, int en); | ||
270 | static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en); | ||
271 | #endif | ||
272 | |||
273 | /* Driver stuff. */ | ||
274 | static int __devinit vortex_gameport_register(vortex_t * card); | ||
275 | static void vortex_gameport_unregister(vortex_t * card); | ||
276 | #ifndef CHIP_AU8820 | ||
277 | static int __devinit vortex_eq_init(vortex_t * vortex); | ||
278 | static int __devexit vortex_eq_free(vortex_t * vortex); | ||
279 | #endif | ||
280 | /* ALSA stuff. */ | ||
281 | static int __devinit snd_vortex_new_pcm(vortex_t * vortex, int idx, int nr); | ||
282 | static int __devinit snd_vortex_mixer(vortex_t * vortex); | ||
283 | static 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 | |||
32 | static void | ||
33 | a3dsrc_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 | ||
48 | static void | ||
49 | a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack, | ||
50 | short *GTrack, short *CTrack) | ||
51 | { | ||
52 | // stub! | ||
53 | } | ||
54 | |||
55 | #endif | ||
56 | /* Atmospheric absorbtion. */ | ||
57 | |||
58 | static void | ||
59 | a3dsrc_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 | |||
73 | static void | ||
74 | a3dsrc_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 | |||
88 | static void | ||
89 | a3dsrc_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 | ||
99 | static void | ||
100 | a3dsrc_GetAtmosTarget(a3dsrc_t * a, short *aa, short *b, short *c, | ||
101 | short *d, short *e) | ||
102 | { | ||
103 | } | ||
104 | static void | ||
105 | a3dsrc_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 | |||
126 | static void | ||
127 | a3dsrc_GetAtmosState(a3dsrc_t * a, short *x1, short *x2, short *y1, short *y2) | ||
128 | { | ||
129 | |||
130 | } | ||
131 | |||
132 | #endif | ||
133 | /* HRTF */ | ||
134 | |||
135 | static void | ||
136 | a3dsrc_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 | |||
148 | static void | ||
149 | a3dsrc_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 | |||
161 | static void | ||
162 | a3dsrc_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 | |||
174 | static 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 | ||
184 | static 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 | |||
201 | static 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 | |||
218 | static 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 | |||
235 | static 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.*/ | ||
253 | static 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 | |||
271 | static 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 | |||
289 | static 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 | ||
301 | static 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 | |||
312 | static 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 | |||
324 | static 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 | |||
339 | static 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 | |||
347 | static 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 | ||
356 | static 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 | |||
367 | static 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. */ | ||
379 | static 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 | |||
388 | static 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 | |||
398 | static 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 | |||
406 | static 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 | |||
413 | static 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 | |||
419 | static 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 | ||
426 | static 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 | |||
434 | static 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 | |||
440 | static 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 | ||
447 | static 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. */ | ||
463 | static 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 */ | ||
486 | static 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 */ | ||
510 | static 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 | ||
533 | static 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 | |||
552 | static 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 | |||
565 | static 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 | |||
593 | static int vortex_a3d_register_controls(vortex_t * vortex); | ||
594 | static void vortex_a3d_unregister_controls(vortex_t * vortex); | ||
595 | /* A3D base support init/shudown */ | ||
596 | static 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. */ | ||
617 | static 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. */ | ||
679 | static 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 | |||
704 | static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord) | ||
705 | { | ||
706 | /* FIXME: implement this. */ | ||
707 | |||
708 | } | ||
709 | static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord) | ||
710 | { | ||
711 | /* FIXME: implement this. */ | ||
712 | |||
713 | } | ||
714 | static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right) | ||
715 | { | ||
716 | /* FIXME: implement this. */ | ||
717 | |||
718 | } | ||
719 | static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params) | ||
720 | { | ||
721 | /* FIXME: implement this. */ | ||
722 | |||
723 | } | ||
724 | |||
725 | /* ALSA control interface. */ | ||
726 | |||
727 | static int | ||
728 | snd_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 | } | ||
736 | static int | ||
737 | snd_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 | } | ||
745 | static int | ||
746 | snd_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 | } | ||
754 | static int | ||
755 | snd_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 | |||
765 | static int | ||
766 | snd_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 | |||
774 | static int | ||
775 | snd_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 | |||
791 | static int | ||
792 | snd_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 | |||
810 | static int | ||
811 | snd_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 | |||
827 | static int | ||
828 | snd_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 | |||
848 | static 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. */ | ||
858 | static 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 | |||
909 | static 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 */ | ||
40 | typedef unsigned short int a3d_Hrtf_t[HRTF_SZ]; | ||
41 | typedef unsigned short int a3d_ItdDline_t[DLINE_SZ]; | ||
42 | typedef unsigned short int a3d_atmos_t[5]; | ||
43 | typedef unsigned short int a3d_LRGains_t[2]; | ||
44 | typedef unsigned short int a3d_Itd_t[2]; | ||
45 | typedef unsigned short int a3d_Ild_t[2]; | ||
46 | |||
47 | typedef 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 | |||
27 | static 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 | |||
36 | static 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 | |||
45 | static 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 | |||
62 | static 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 | |||
74 | static 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 | |||
83 | static 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 | |||
88 | static short const GainTCDefault = 0x300; | ||
89 | static short const ItdTCDefault = 0x0C8; | ||
90 | static short const HrtfTCDefault = 0x147; | ||
91 | static 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. | ||
86 | static int mchannels[NR_MIXIN]; | ||
87 | static int rampchs[NR_MIXIN]; | ||
88 | |||
89 | static 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 | } | ||
94 | static 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 | ||
101 | static void | ||
102 | vortex_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 | |||
111 | static 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 | |||
119 | static int | ||
120 | vortex_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 | |||
138 | static unsigned int vortex_mix_boost6db(unsigned char vol) | ||
139 | { | ||
140 | return (vol + 8); /* WOW! what a complex function! */ | ||
141 | } | ||
142 | |||
143 | static 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 | |||
166 | static int | ||
167 | vortex_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 | ||
179 | static void | ||
180 | vortex_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 | |||
193 | static void | ||
194 | vortex_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 | |||
212 | static void | ||
213 | vortex_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 | |||
237 | static void | ||
238 | vortex_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 | |||
246 | static void | ||
247 | vortex_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 | |||
257 | static void | ||
258 | vortex_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 | |||
270 | static int | ||
271 | vortex_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 | |||
298 | static int | ||
299 | vortex_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 | |||
377 | static 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 | |||
443 | static 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 | |||
449 | static 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 | |||
455 | static 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 | |||
466 | static 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 | |||
473 | static void | ||
474 | vortex_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 | |||
486 | static int | ||
487 | vortex_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 | ||
504 | static 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 | |||
516 | static void | ||
517 | vortex_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 | |||
536 | static int | ||
537 | vortex_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 | */ | ||
571 | static 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 | |||
640 | static 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 | |||
666 | static int | ||
667 | vortex_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 | |||
698 | static int | ||
699 | vortex_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 | |||
778 | static void | ||
779 | vortex_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 | ||
788 | static 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 | ||
800 | static 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 | |||
807 | static void | ||
808 | vortex_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 | ||
879 | static 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 | |||
889 | static 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 | |||
901 | static 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 | |||
908 | static void | ||
909 | vortex_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 | ||
1035 | static 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 | |||
1077 | static void vortex_adbdma_init(vortex_t * vortex) | ||
1078 | { | ||
1079 | } | ||
1080 | |||
1081 | static 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 | |||
1089 | static 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 | |||
1098 | static void | ||
1099 | vortex_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 | |||
1153 | static void | ||
1154 | vortex_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 | |||
1176 | static 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 | |||
1227 | static 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 | |||
1253 | static 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 | |||
1263 | static 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 | |||
1290 | static 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 | |||
1312 | static 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 | ||
1333 | static 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 | ||
1351 | static 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 | |||
1359 | static 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 | |||
1368 | static void | ||
1369 | vortex_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 | |||
1412 | static void | ||
1413 | vortex_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 | |||
1435 | static 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 | ||
1487 | static void | ||
1488 | vortex_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 | |||
1496 | static 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 | ||
1502 | static 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 | |||
1513 | static 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 | |||
1540 | static 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 | |||
1562 | static 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 | |||
1582 | static 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 | |||
1599 | typedef int ADBRamLink; | ||
1600 | static 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 | |||
1617 | static 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 | |||
1623 | static 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 | |||
1629 | static void | ||
1630 | vortex_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 | |||
1676 | static void | ||
1677 | vortex_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 | |||
1716 | static void | ||
1717 | vortex_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 | ||
1747 | static void | ||
1748 | vortex_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 !!! */ | ||
1781 | static void | ||
1782 | vortex_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). | ||
1830 | static void | ||
1831 | vortex_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. | ||
1838 | static void | ||
1839 | vortex_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. | ||
1847 | static void | ||
1848 | vortex_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. | ||
1859 | static void | ||
1860 | vortex_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 | |||
1867 | static void | ||
1868 | vortex_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 | |||
1874 | static void | ||
1875 | vortex_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. | ||
1885 | static void | ||
1886 | vortex_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. | ||
1894 | static void | ||
1895 | vortex_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 | ||
1903 | static void | ||
1904 | vortex_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. | ||
1914 | static void | ||
1915 | vortex_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 | |||
1942 | static void | ||
1943 | vortex_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 | |||
1976 | static void | ||
1977 | vortex_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 */ | ||
1993 | static 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 | */ | ||
2002 | static char | ||
2003 | vortex_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 */ | ||
2041 | static int | ||
2042 | vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type); | ||
2043 | |||
2044 | static 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 | */ | ||
2101 | static int | ||
2102 | vortex_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 | */ | ||
2332 | static void | ||
2333 | vortex_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 | |||
2353 | static 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 | ||
2360 | static 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 | |||
2366 | static 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 | ||
2373 | static 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 | |||
2382 | static 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 | |||
2388 | static 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 | ||
2478 | static 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 | |||
2516 | static void | ||
2517 | vortex_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 | |||
2541 | static 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 | |||
2577 | static 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 | |||
2659 | static 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 | |||
2713 | static 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 | |||
2744 | static 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 | ||
2780 | typedef enum { | ||
2781 | ASPFMTLINEAR16 = 0, /* 0x8 */ | ||
2782 | ASPFMTLINEAR8, /* 0x1 */ | ||
2783 | ASPFMTULAW, /* 0x2 */ | ||
2784 | ASPFMTALAW, /* 0x3 */ | ||
2785 | ASPFMTSPORT, /* ? */ | ||
2786 | ASPFMTSPDIF, /* ? */ | ||
2787 | } ASPENCODING; | ||
2788 | |||
2789 | static int | ||
2790 | vortex_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 | |||
2830 | static 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 */ | ||
51 | static 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 | |||
57 | static 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 | |||
66 | static 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 | |||
88 | static 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 | |||
111 | static 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 | |||
128 | static 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 | ||
146 | static 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 | |||
152 | static void vortex_EqHw_GetLeftCoefs(vortex_t * vortex, u16 a[]) | ||
153 | { | ||
154 | |||
155 | } | ||
156 | |||
157 | static void vortex_EqHw_GetRightCoefs(vortex_t * vortex, u16 a[]) | ||
158 | { | ||
159 | |||
160 | } | ||
161 | |||
162 | static void vortex_EqHw_GetLeftStates(vortex_t * vortex, u16 * a, u16 b[]) | ||
163 | { | ||
164 | |||
165 | } | ||
166 | |||
167 | static void vortex_EqHw_GetRightStates(vortex_t * vortex, u16 * a, u16 b[]) | ||
168 | { | ||
169 | |||
170 | } | ||
171 | |||
172 | #endif | ||
173 | /* Mix Gains */ | ||
174 | static 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 | |||
186 | static 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 | ||
194 | static 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 | |||
201 | static 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 | ||
209 | static void | ||
210 | vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b) | ||
211 | { | ||
212 | hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b); | ||
213 | } | ||
214 | |||
215 | static void | ||
216 | vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b) | ||
217 | { | ||
218 | hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b); | ||
219 | } | ||
220 | |||
221 | static 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 | |||
231 | static 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 | |||
241 | static 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 | |||
251 | static 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 | ||
262 | static 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 | |||
277 | static 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 | |||
292 | static 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 | |||
307 | static 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 */ | ||
324 | static 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 | ||
348 | static 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 */ | ||
380 | static void vortex_EqHw_SetControlReg(vortex_t * vortex, unsigned long reg) | ||
381 | { | ||
382 | hwwrite(vortex->mmio, 0x2b440, reg); | ||
383 | } | ||
384 | |||
385 | static void vortex_EqHw_SetSampleRate(vortex_t * vortex, int sr) | ||
386 | { | ||
387 | hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800); | ||
388 | } | ||
389 | |||
390 | #if 0 | ||
391 | static void vortex_EqHw_GetControlReg(vortex_t * vortex, unsigned long *reg) | ||
392 | { | ||
393 | *reg = hwread(vortex->mmio, 0x2b440); | ||
394 | } | ||
395 | |||
396 | static void vortex_EqHw_GetSampleRate(vortex_t * vortex, int *sr) | ||
397 | { | ||
398 | *sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f; | ||
399 | } | ||
400 | |||
401 | #endif | ||
402 | static void vortex_EqHw_Enable(vortex_t * vortex) | ||
403 | { | ||
404 | hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf001); | ||
405 | } | ||
406 | |||
407 | static void vortex_EqHw_Disable(vortex_t * vortex) | ||
408 | { | ||
409 | hwwrite(vortex->mmio, VORTEX_EQ_CTRL, 0xf000); | ||
410 | } | ||
411 | |||
412 | /* Reset (zero) buffers */ | ||
413 | static 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 | |||
422 | static 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 | |||
429 | static 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 */ | ||
456 | static 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 */ | ||
470 | static void | ||
471 | vortex_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) */ | ||
488 | static 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 | |||
505 | static 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 | |||
516 | static 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 | |||
530 | static 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 | |||
541 | static 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 | ||
556 | static int | ||
557 | vortex_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 | ||
578 | static 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 | |||
588 | static int | ||
589 | vortex_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 | |||
606 | static void | ||
607 | vortex_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 | |||
624 | static 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 | |||
638 | static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex) | ||
639 | { | ||
640 | if (vortex != NULL) | ||
641 | vortex_EqHw_ZeroA3DIO(vortex); | ||
642 | } | ||
643 | |||
644 | static 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 | |||
661 | static 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 | |||
671 | static 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 | ||
683 | static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex) | ||
684 | { | ||
685 | eqlzr_t *eq = &(vortex->eq); | ||
686 | |||
687 | return (&(eq->coefset)); | ||
688 | } | ||
689 | #endif | ||
690 | static 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 | |||
722 | static 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 */ | ||
732 | static int | ||
733 | snd_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 | |||
742 | static int | ||
743 | snd_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 | |||
755 | static int | ||
756 | snd_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 | |||
769 | static 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 | |||
780 | static int | ||
781 | snd_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 | |||
790 | static int | ||
791 | snd_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 | |||
804 | static int | ||
805 | snd_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 | |||
827 | static 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 | |||
838 | static int | ||
839 | snd_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 | |||
848 | static int | ||
849 | snd_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 | |||
866 | static 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. */ | ||
875 | static 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. */ | ||
889 | static 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 | |||
923 | static 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 | |||
13 | typedef 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 | |||
20 | typedef 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 | |||
26 | typedef 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 | |||
3 | static 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 | |||
16 | static 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. */ | ||
35 | static 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 | |||
68 | static 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 */ | ||
76 | static u16 eq_gains_zero[10] = { | ||
77 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | ||
78 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 | ||
79 | }; | ||
80 | |||
81 | /* _rodatab7c: ProgramPipe */ | ||
82 | static u16 eq_gains_current[12] = { | ||
83 | 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, | ||
84 | 0x7fff, | ||
85 | 0x7fff, 0x7fff, 0x7fff | ||
86 | }; | ||
87 | |||
88 | /* _rodatab78 */ | ||
89 | static u16 eq_states_zero[2] = { 0x0000, 0x0000 }; | ||
90 | |||
91 | static 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:*/ | ||
107 | static 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 | |||
45 | static 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 | |||
51 | static 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 | |||
57 | static int | ||
58 | vortex_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 | |||
74 | static 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 | |||
97 | static 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 | |||
124 | static 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 | ||
133 | static inline int vortex_gameport_register(vortex_t * vortex) { return -ENOSYS; } | ||
134 | static 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 | |||
14 | static 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 | |||
45 | static 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 */ | ||
34 | static 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 | ||
59 | static 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 | ||
79 | static 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 | ||
102 | static 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 */ | ||
120 | static 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 */ | ||
172 | static 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 */ | ||
187 | static int | ||
188 | snd_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 */ | ||
252 | static 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 */ | ||
278 | static 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 */ | ||
311 | static 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 */ | ||
375 | static 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 | /* | ||
396 | static struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) { | ||
397 | |||
398 | |||
399 | } | ||
400 | */ | ||
401 | /* operators */ | ||
402 | static 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 | |||
418 | static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = { | ||
419 | "AU88x0 ADB", | ||
420 | "AU88x0 SPDIF", | ||
421 | "AU88x0 A3D", | ||
422 | "AU88x0 WT", | ||
423 | "AU88x0 I2S", | ||
424 | }; | ||
425 | static char *vortex_pcm_name[VORTEX_PCM_LAST] = { | ||
426 | "adb", | ||
427 | "spdif", | ||
428 | "a3d", | ||
429 | "wt", | ||
430 | "i2s", | ||
431 | }; | ||
432 | |||
433 | /* SPDIF kcontrol */ | ||
434 | |||
435 | static 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 | |||
442 | static 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 | |||
451 | static 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 | |||
465 | static 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 */ | ||
482 | static 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 */ | ||
500 | static 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 | |||
25 | static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en); | ||
26 | static void vortex_connection_adb_mixin(vortex_t * vortex, int en, | ||
27 | unsigned char channel, | ||
28 | unsigned char source, | ||
29 | unsigned char mixin); | ||
30 | static void vortex_connection_mixin_mix(vortex_t * vortex, int en, | ||
31 | unsigned char mixin, | ||
32 | unsigned char mix, int a); | ||
33 | static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j); | ||
34 | static 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. */ | ||
40 | static 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. */ | ||
52 | static 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. */ | ||
66 | static 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 | |||
114 | static 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 | ||
152 | static 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. */ | ||
167 | static int | ||
168 | vortex_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 | ||
191 | static int | ||
192 | vortex_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 | |||
280 | static 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 | ||
320 | static 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) */ | ||
353 | static 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 | ||
38 | enum { | ||
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 | |||
55 | typedef 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 | |||
29 | static short const sXtalkWideKLeftEq = 0x269C; | ||
30 | static short const sXtalkWideKRightEq = 0x269C; | ||
31 | static short const sXtalkWideKLeftXt = 0xF25E; | ||
32 | static short const sXtalkWideKRightXt = 0xF25E; | ||
33 | static short const sXtalkWideShiftLeftEq = 1; | ||
34 | static short const sXtalkWideShiftRightEq = 1; | ||
35 | static short const sXtalkWideShiftLeftXt = 0; | ||
36 | static short const sXtalkWideShiftRightXt = 0; | ||
37 | static unsigned short const wXtalkWideLeftDelay = 0xd; | ||
38 | static unsigned short const wXtalkWideRightDelay = 0xd; | ||
39 | static short const sXtalkNarrowKLeftEq = 0x468D; | ||
40 | static short const sXtalkNarrowKRightEq = 0x468D; | ||
41 | static short const sXtalkNarrowKLeftXt = 0xF82E; | ||
42 | static short const sXtalkNarrowKRightXt = 0xF82E; | ||
43 | static short const sXtalkNarrowShiftLeftEq = 0x3; | ||
44 | static short const sXtalkNarrowShiftRightEq = 0x3; | ||
45 | static short const sXtalkNarrowShiftLeftXt = 0; | ||
46 | static short const sXtalkNarrowShiftRightXt = 0; | ||
47 | static unsigned short const wXtalkNarrowLeftDelay = 0x7; | ||
48 | static unsigned short const wXtalkNarrowRightDelay = 0x7; | ||
49 | |||
50 | static xtalk_gains_t const asXtalkGainsDefault = { | ||
51 | 0x4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000, | ||
52 | 0x4000 | ||
53 | }; | ||
54 | |||
55 | static xtalk_gains_t const asXtalkGainsTest = { | ||
56 | 0x8000, 0x7FFF, 0, 0xFFFF, 0x0001, 0xC000, 0x4000, 0xFFFE, 0x0002, | ||
57 | 0 | ||
58 | }; | ||
59 | static 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. | ||
64 | static 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 | }; | ||
69 | static xtalk_gains_t const asXtalkGainsZeros = { | ||
70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
71 | }; | ||
72 | |||
73 | static 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 | }; | ||
78 | static 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 | |||
84 | static xtalk_instate_t const asXtalkInStateZeros = { 0, 0, 0, 0 }; | ||
85 | static xtalk_instate_t const asXtalkInStateTest = | ||
86 | { 0xFF80, 0x0080, 0xFFFF, 0x0001 }; | ||
87 | static 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 | }; | ||
94 | static short const sDiamondKLeftEq = 0x401d; | ||
95 | static short const sDiamondKRightEq = 0x401d; | ||
96 | static short const sDiamondKLeftXt = 0xF90E; | ||
97 | static short const sDiamondKRightXt = 0xF90E; | ||
98 | static short const sDiamondShiftLeftEq = 1; /* 0xF90E Is this a bug ??? */ | ||
99 | static short const sDiamondShiftRightEq = 1; | ||
100 | static short const sDiamondShiftLeftXt = 0; | ||
101 | static short const sDiamondShiftRightXt = 0; | ||
102 | static unsigned short const wDiamondLeftDelay = 0xb; | ||
103 | static unsigned short const wDiamondRightDelay = 0xb; | ||
104 | |||
105 | static 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 | }; | ||
112 | static 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 | }; | ||
119 | static 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 | }; | ||
126 | static 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 | }; | ||
133 | static 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 | |||
141 | static 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 | |||
149 | static 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 | |||
157 | static 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 | |||
165 | static 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 | }; | ||
172 | static 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 | }; | ||
179 | static 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 | |||
187 | static 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 | |||
195 | static 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 | |||
203 | static 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 | |||
211 | static 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 | |||
219 | static 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 | |||
227 | static 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 | |||
235 | static 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 */ | ||
245 | static void | ||
246 | vortex_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 | |||
262 | static void | ||
263 | vortex_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 | |||
279 | static void | ||
280 | vortex_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 | |||
296 | static void | ||
297 | vortex_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 | |||
313 | static void | ||
314 | vortex_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 | |||
332 | static void | ||
333 | vortex_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 | |||
351 | static void | ||
352 | vortex_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 | |||
370 | static void | ||
371 | vortex_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 | ||
390 | static void | ||
391 | vortex_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 | |||
407 | static void | ||
408 | vortex_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 | |||
424 | static void | ||
425 | vortex_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 | |||
441 | static void | ||
442 | vortex_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 | |||
458 | static void | ||
459 | vortex_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 | |||
476 | static void | ||
477 | vortex_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 | |||
494 | static void | ||
495 | vortex_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 | |||
512 | static void | ||
513 | vortex_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 | |||
533 | static void | ||
534 | vortex_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 | |||
543 | static void | ||
544 | vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex) | ||
545 | { | ||
546 | vortex_XtalkHw_SetGains(vortex, asXtalkGainsAllChan); | ||
547 | } | ||
548 | |||
549 | #if 0 | ||
550 | static 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 | |||
561 | static void | ||
562 | vortex_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 | |||
575 | static void | ||
576 | vortex_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 | |||
586 | static void | ||
587 | vortex_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 | ||
598 | static void | ||
599 | vortex_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 | |||
609 | static 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 | |||
620 | static 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 | ||
635 | static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, unsigned long ctrl) | ||
636 | { | ||
637 | hwwrite(vortex->mmio, 0x24660, ctrl); | ||
638 | } | ||
639 | static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, unsigned long *ctrl) | ||
640 | { | ||
641 | *ctrl = hwread(vortex->mmio, 0x24660); | ||
642 | } | ||
643 | #endif | ||
644 | static 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 | ||
654 | static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, int *sr) | ||
655 | { | ||
656 | *sr = (hwread(vortex->mmio, 0x24660) >> 3) & 0x1f; | ||
657 | } | ||
658 | |||
659 | #endif | ||
660 | static 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 | |||
670 | static 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 | |||
680 | static 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 | |||
690 | static 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 | |||
719 | static 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 | |||
730 | static 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 | |||
747 | static 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 | |||
766 | static 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 | |||
782 | static 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 | |||
42 | typedef long xtalk_dline_t[XTDLINE_SZ]; | ||
43 | typedef short xtalk_gains_t[XTGAINS_SZ]; | ||
44 | typedef short xtalk_instate_t[XTINST_SZ]; | ||
45 | typedef short xtalk_coefs_t[5][5]; | ||
46 | typedef short xtalk_state_t[5][4]; | ||
47 | |||
48 | static void vortex_XtalkHw_SetGains(vortex_t * vortex, | ||
49 | xtalk_gains_t const gains); | ||
50 | static void vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex); | ||
51 | static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr); | ||
52 | static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex); | ||
53 | static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex); | ||
54 | static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex); | ||
55 | static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex); | ||
56 | static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex); | ||
57 | static void vortex_XtalkHw_Enable(vortex_t * vortex); | ||
58 | static void vortex_XtalkHw_Disable(vortex_t * vortex); | ||
59 | static void vortex_XtalkHw_init(vortex_t * vortex); | ||
60 | |||
61 | #endif /* _AU88X0_CXTALK_H */ | ||