aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa/sb/emu8000.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/isa/sb/emu8000.c')
-rw-r--r--sound/isa/sb/emu8000.c1170
1 files changed, 1170 insertions, 0 deletions
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
new file mode 100644
index 000000000000..028af4066595
--- /dev/null
+++ b/sound/isa/sb/emu8000.c
@@ -0,0 +1,1170 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk>
4 * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
5 *
6 * Routines for control of EMU8000 chip
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#include <sound/driver.h>
24#include <linux/wait.h>
25#include <linux/sched.h>
26#include <linux/slab.h>
27#include <linux/ioport.h>
28#include <linux/delay.h>
29#include <sound/core.h>
30#include <sound/emu8000.h>
31#include <sound/emu8000_reg.h>
32#include <asm/io.h>
33#include <asm/uaccess.h>
34#include <linux/init.h>
35#include <sound/control.h>
36#include <sound/initval.h>
37
38/*
39 * emu8000 register controls
40 */
41
42/*
43 * The following routines read and write registers on the emu8000. They
44 * should always be called via the EMU8000*READ/WRITE macros and never
45 * directly. The macros handle the port number and command word.
46 */
47/* Write a word */
48void snd_emu8000_poke(emu8000_t *emu, unsigned int port, unsigned int reg, unsigned int val)
49{
50 unsigned long flags;
51 spin_lock_irqsave(&emu->reg_lock, flags);
52 if (reg != emu->last_reg) {
53 outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
54 emu->last_reg = reg;
55 }
56 outw((unsigned short)val, port); /* Send data */
57 spin_unlock_irqrestore(&emu->reg_lock, flags);
58}
59
60/* Read a word */
61unsigned short snd_emu8000_peek(emu8000_t *emu, unsigned int port, unsigned int reg)
62{
63 unsigned short res;
64 unsigned long flags;
65 spin_lock_irqsave(&emu->reg_lock, flags);
66 if (reg != emu->last_reg) {
67 outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
68 emu->last_reg = reg;
69 }
70 res = inw(port); /* Read data */
71 spin_unlock_irqrestore(&emu->reg_lock, flags);
72 return res;
73}
74
75/* Write a double word */
76void snd_emu8000_poke_dw(emu8000_t *emu, unsigned int port, unsigned int reg, unsigned int val)
77{
78 unsigned long flags;
79 spin_lock_irqsave(&emu->reg_lock, flags);
80 if (reg != emu->last_reg) {
81 outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
82 emu->last_reg = reg;
83 }
84 outw((unsigned short)val, port); /* Send low word of data */
85 outw((unsigned short)(val>>16), port+2); /* Send high word of data */
86 spin_unlock_irqrestore(&emu->reg_lock, flags);
87}
88
89/* Read a double word */
90unsigned int snd_emu8000_peek_dw(emu8000_t *emu, unsigned int port, unsigned int reg)
91{
92 unsigned short low;
93 unsigned int res;
94 unsigned long flags;
95 spin_lock_irqsave(&emu->reg_lock, flags);
96 if (reg != emu->last_reg) {
97 outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
98 emu->last_reg = reg;
99 }
100 low = inw(port); /* Read low word of data */
101 res = low + (inw(port+2) << 16);
102 spin_unlock_irqrestore(&emu->reg_lock, flags);
103 return res;
104}
105
106/*
107 * Set up / close a channel to be used for DMA.
108 */
109/*exported*/ void
110snd_emu8000_dma_chan(emu8000_t *emu, int ch, int mode)
111{
112 unsigned right_bit = (mode & EMU8000_RAM_RIGHT) ? 0x01000000 : 0;
113 mode &= EMU8000_RAM_MODE_MASK;
114 if (mode == EMU8000_RAM_CLOSE) {
115 EMU8000_CCCA_WRITE(emu, ch, 0);
116 EMU8000_DCYSUSV_WRITE(emu, ch, 0x807F);
117 return;
118 }
119 EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
120 EMU8000_VTFT_WRITE(emu, ch, 0);
121 EMU8000_CVCF_WRITE(emu, ch, 0);
122 EMU8000_PTRX_WRITE(emu, ch, 0x40000000);
123 EMU8000_CPF_WRITE(emu, ch, 0x40000000);
124 EMU8000_PSST_WRITE(emu, ch, 0);
125 EMU8000_CSL_WRITE(emu, ch, 0);
126 if (mode == EMU8000_RAM_WRITE) /* DMA write */
127 EMU8000_CCCA_WRITE(emu, ch, 0x06000000 | right_bit);
128 else /* DMA read */
129 EMU8000_CCCA_WRITE(emu, ch, 0x04000000 | right_bit);
130}
131
132/*
133 */
134static void __init
135snd_emu8000_read_wait(emu8000_t *emu)
136{
137 while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
138 set_current_state(TASK_INTERRUPTIBLE);
139 schedule_timeout(1);
140 if (signal_pending(current))
141 break;
142 }
143}
144
145/*
146 */
147static void __init
148snd_emu8000_write_wait(emu8000_t *emu)
149{
150 while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
151 set_current_state(TASK_INTERRUPTIBLE);
152 schedule_timeout(1);
153 if (signal_pending(current))
154 break;
155 }
156}
157
158/*
159 * detect a card at the given port
160 */
161static int __init
162snd_emu8000_detect(emu8000_t *emu)
163{
164 /* Initialise */
165 EMU8000_HWCF1_WRITE(emu, 0x0059);
166 EMU8000_HWCF2_WRITE(emu, 0x0020);
167 EMU8000_HWCF3_WRITE(emu, 0x0000);
168 /* Check for a recognisable emu8000 */
169 /*
170 if ((EMU8000_U1_READ(emu) & 0x000f) != 0x000c)
171 return -ENODEV;
172 */
173 if ((EMU8000_HWCF1_READ(emu) & 0x007e) != 0x0058)
174 return -ENODEV;
175 if ((EMU8000_HWCF2_READ(emu) & 0x0003) != 0x0003)
176 return -ENODEV;
177
178 snd_printdd("EMU8000 [0x%lx]: Synth chip found\n",
179 emu->port1);
180 return 0;
181}
182
183
184/*
185 * intiailize audio channels
186 */
187static void __init
188init_audio(emu8000_t *emu)
189{
190 int ch;
191
192 /* turn off envelope engines */
193 for (ch = 0; ch < EMU8000_CHANNELS; ch++)
194 EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
195
196 /* reset all other parameters to zero */
197 for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
198 EMU8000_ENVVOL_WRITE(emu, ch, 0);
199 EMU8000_ENVVAL_WRITE(emu, ch, 0);
200 EMU8000_DCYSUS_WRITE(emu, ch, 0);
201 EMU8000_ATKHLDV_WRITE(emu, ch, 0);
202 EMU8000_LFO1VAL_WRITE(emu, ch, 0);
203 EMU8000_ATKHLD_WRITE(emu, ch, 0);
204 EMU8000_LFO2VAL_WRITE(emu, ch, 0);
205 EMU8000_IP_WRITE(emu, ch, 0);
206 EMU8000_IFATN_WRITE(emu, ch, 0);
207 EMU8000_PEFE_WRITE(emu, ch, 0);
208 EMU8000_FMMOD_WRITE(emu, ch, 0);
209 EMU8000_TREMFRQ_WRITE(emu, ch, 0);
210 EMU8000_FM2FRQ2_WRITE(emu, ch, 0);
211 EMU8000_PTRX_WRITE(emu, ch, 0);
212 EMU8000_VTFT_WRITE(emu, ch, 0);
213 EMU8000_PSST_WRITE(emu, ch, 0);
214 EMU8000_CSL_WRITE(emu, ch, 0);
215 EMU8000_CCCA_WRITE(emu, ch, 0);
216 }
217
218 for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
219 EMU8000_CPF_WRITE(emu, ch, 0);
220 EMU8000_CVCF_WRITE(emu, ch, 0);
221 }
222}
223
224
225/*
226 * initialize DMA address
227 */
228static void __init
229init_dma(emu8000_t *emu)
230{
231 EMU8000_SMALR_WRITE(emu, 0);
232 EMU8000_SMARR_WRITE(emu, 0);
233 EMU8000_SMALW_WRITE(emu, 0);
234 EMU8000_SMARW_WRITE(emu, 0);
235}
236
237/*
238 * initialization arrays; from ADIP
239 */
240static unsigned short init1[128] /*__devinitdata*/ = {
241 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330,
242 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730,
243 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30,
244 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30,
245
246 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330,
247 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730,
248 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30,
249 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30,
250
251 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330,
252 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730,
253 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30,
254 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30,
255
256 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330,
257 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730,
258 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30,
259 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30,
260};
261
262static unsigned short init2[128] /*__devinitdata*/ = {
263 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
264 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
265 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
266 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
267
268 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
269 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
270 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
271 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
272
273 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
274 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
275 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
276 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
277
278 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
279 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
280 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
281 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
282};
283
284static unsigned short init3[128] /*__devinitdata*/ = {
285 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
286 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
287 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
288 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
289
290 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
291 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
292 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
293 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
294
295 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
296 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
297 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
298 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
299
300 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
301 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
302 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
303 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
304};
305
306static unsigned short init4[128] /*__devinitdata*/ = {
307 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
308 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
309 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
310 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
311
312 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
313 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
314 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
315 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
316
317 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
318 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
319 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
320 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
321
322 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
323 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
324 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
325 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
326};
327
328/* send an initialization array
329 * Taken from the oss driver, not obvious from the doc how this
330 * is meant to work
331 */
332static void __init
333send_array(emu8000_t *emu, unsigned short *data, int size)
334{
335 int i;
336 unsigned short *p;
337
338 p = data;
339 for (i = 0; i < size; i++, p++)
340 EMU8000_INIT1_WRITE(emu, i, *p);
341 for (i = 0; i < size; i++, p++)
342 EMU8000_INIT2_WRITE(emu, i, *p);
343 for (i = 0; i < size; i++, p++)
344 EMU8000_INIT3_WRITE(emu, i, *p);
345 for (i = 0; i < size; i++, p++)
346 EMU8000_INIT4_WRITE(emu, i, *p);
347}
348
349
350/*
351 * Send initialization arrays to start up, this just follows the
352 * initialisation sequence in the adip.
353 */
354static void __init
355init_arrays(emu8000_t *emu)
356{
357 send_array(emu, init1, ARRAY_SIZE(init1)/4);
358
359 msleep((1024 * 1000) / 44100); /* wait for 1024 clocks */
360 send_array(emu, init2, ARRAY_SIZE(init2)/4);
361 send_array(emu, init3, ARRAY_SIZE(init3)/4);
362
363 EMU8000_HWCF4_WRITE(emu, 0);
364 EMU8000_HWCF5_WRITE(emu, 0x83);
365 EMU8000_HWCF6_WRITE(emu, 0x8000);
366
367 send_array(emu, init4, ARRAY_SIZE(init4)/4);
368}
369
370
371#define UNIQUE_ID1 0xa5b9
372#define UNIQUE_ID2 0x9d53
373
374/*
375 * Size the onboard memory.
376 * This is written so as not to need arbitary delays after the write. It
377 * seems that the only way to do this is to use the one channel and keep
378 * reallocating between read and write.
379 */
380static void __init
381size_dram(emu8000_t *emu)
382{
383 int i, size;
384
385 if (emu->dram_checked)
386 return;
387
388 size = 0;
389
390 /* write out a magic number */
391 snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
392 snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_READ);
393 EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET);
394 EMU8000_SMLD_WRITE(emu, UNIQUE_ID1);
395 snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */
396
397 while (size < EMU8000_MAX_DRAM) {
398
399 size += 512 * 1024; /* increment 512kbytes */
400
401 /* Write a unique data on the test address.
402 * if the address is out of range, the data is written on
403 * 0x200000(=EMU8000_DRAM_OFFSET). Then the id word is
404 * changed by this data.
405 */
406 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);*/
407 EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
408 EMU8000_SMLD_WRITE(emu, UNIQUE_ID2);
409 snd_emu8000_write_wait(emu);
410
411 /*
412 * read the data on the just written DRAM address
413 * if not the same then we have reached the end of ram.
414 */
415 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_READ);*/
416 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
417 /*snd_emu8000_read_wait(emu);*/
418 EMU8000_SMLD_READ(emu); /* discard stale data */
419 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
420 break; /* we must have wrapped around */
421
422 snd_emu8000_read_wait(emu);
423
424 /*
425 * If it is the same it could be that the address just
426 * wraps back to the beginning; so check to see if the
427 * initial value has been overwritten.
428 */
429 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
430 EMU8000_SMLD_READ(emu); /* discard stale data */
431 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
432 break; /* we must have wrapped around */
433 snd_emu8000_read_wait(emu);
434 }
435
436 /* wait until FULL bit in SMAxW register is false */
437 for (i = 0; i < 10000; i++) {
438 if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
439 break;
440 set_current_state(TASK_INTERRUPTIBLE);
441 schedule_timeout(1);
442 if (signal_pending(current))
443 break;
444 }
445 snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
446 snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
447
448 snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n",
449 emu->port1, size/1024);
450
451 emu->mem_size = size;
452 emu->dram_checked = 1;
453}
454
455
456/*
457 * Initiailise the FM section. You have to do this to use sample RAM
458 * and therefore lose 2 voices.
459 */
460/*exported*/ void
461snd_emu8000_init_fm(emu8000_t *emu)
462{
463 unsigned long flags;
464
465 /* Initialize the last two channels for DRAM refresh and producing
466 the reverb and chorus effects for Yamaha OPL-3 synthesizer */
467
468 /* 31: FM left channel, 0xffffe0-0xffffe8 */
469 EMU8000_DCYSUSV_WRITE(emu, 30, 0x80);
470 EMU8000_PSST_WRITE(emu, 30, 0xFFFFFFE0); /* full left */
471 EMU8000_CSL_WRITE(emu, 30, 0x00FFFFE8 | (emu->fm_chorus_depth << 24));
472 EMU8000_PTRX_WRITE(emu, 30, (emu->fm_reverb_depth << 8));
473 EMU8000_CPF_WRITE(emu, 30, 0);
474 EMU8000_CCCA_WRITE(emu, 30, 0x00FFFFE3);
475
476 /* 32: FM right channel, 0xfffff0-0xfffff8 */
477 EMU8000_DCYSUSV_WRITE(emu, 31, 0x80);
478 EMU8000_PSST_WRITE(emu, 31, 0x00FFFFF0); /* full right */
479 EMU8000_CSL_WRITE(emu, 31, 0x00FFFFF8 | (emu->fm_chorus_depth << 24));
480 EMU8000_PTRX_WRITE(emu, 31, (emu->fm_reverb_depth << 8));
481 EMU8000_CPF_WRITE(emu, 31, 0x8000);
482 EMU8000_CCCA_WRITE(emu, 31, 0x00FFFFF3);
483
484 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0);
485
486 spin_lock_irqsave(&emu->reg_lock, flags);
487 while (!(inw(EMU8000_PTR(emu)) & 0x1000))
488 ;
489 while ((inw(EMU8000_PTR(emu)) & 0x1000))
490 ;
491 spin_unlock_irqrestore(&emu->reg_lock, flags);
492 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828);
493 /* this is really odd part.. */
494 outb(0x3C, EMU8000_PTR(emu));
495 outb(0, EMU8000_DATA1(emu));
496
497 /* skew volume & cutoff */
498 EMU8000_VTFT_WRITE(emu, 30, 0x8000FFFF);
499 EMU8000_VTFT_WRITE(emu, 31, 0x8000FFFF);
500}
501
502
503/*
504 * The main initialization routine.
505 */
506static void __init
507snd_emu8000_init_hw(emu8000_t *emu)
508{
509 int i;
510
511 emu->last_reg = 0xffff; /* reset the last register index */
512
513 /* initialize hardware configuration */
514 EMU8000_HWCF1_WRITE(emu, 0x0059);
515 EMU8000_HWCF2_WRITE(emu, 0x0020);
516
517 /* disable audio; this seems to reduce a clicking noise a bit.. */
518 EMU8000_HWCF3_WRITE(emu, 0);
519
520 /* initialize audio channels */
521 init_audio(emu);
522
523 /* initialize DMA */
524 init_dma(emu);
525
526 /* initialize init arrays */
527 init_arrays(emu);
528
529 /*
530 * Initialize the FM section of the AWE32, this is needed
531 * for DRAM refresh as well
532 */
533 snd_emu8000_init_fm(emu);
534
535 /* terminate all voices */
536 for (i = 0; i < EMU8000_DRAM_VOICES; i++)
537 EMU8000_DCYSUSV_WRITE(emu, 0, 0x807F);
538
539 /* check DRAM memory size */
540 size_dram(emu);
541
542 /* enable audio */
543 EMU8000_HWCF3_WRITE(emu, 0x4);
544
545 /* set equzlier, chorus and reverb modes */
546 snd_emu8000_update_equalizer(emu);
547 snd_emu8000_update_chorus_mode(emu);
548 snd_emu8000_update_reverb_mode(emu);
549}
550
551
552/*----------------------------------------------------------------
553 * Bass/Treble Equalizer
554 *----------------------------------------------------------------*/
555
556static unsigned short bass_parm[12][3] = {
557 {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
558 {0xD25B, 0xD35B, 0x0000}, /* -8 */
559 {0xD24C, 0xD34C, 0x0000}, /* -6 */
560 {0xD23D, 0xD33D, 0x0000}, /* -4 */
561 {0xD21F, 0xD31F, 0x0000}, /* -2 */
562 {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */
563 {0xC219, 0xC319, 0x0001}, /* +2 */
564 {0xC22A, 0xC32A, 0x0001}, /* +4 */
565 {0xC24C, 0xC34C, 0x0001}, /* +6 */
566 {0xC26E, 0xC36E, 0x0001}, /* +8 */
567 {0xC248, 0xC384, 0x0002}, /* +10 */
568 {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
569};
570
571static unsigned short treble_parm[12][9] = {
572 {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
573 {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
574 {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
575 {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
576 {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
577 {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
578 {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
579 {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
580 {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
581 {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
582 {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
583 {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002} /* +12 dB */
584};
585
586
587/*
588 * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
589 */
590/*exported*/ void
591snd_emu8000_update_equalizer(emu8000_t *emu)
592{
593 unsigned short w;
594 int bass = emu->bass_level;
595 int treble = emu->treble_level;
596
597 if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
598 return;
599 EMU8000_INIT4_WRITE(emu, 0x01, bass_parm[bass][0]);
600 EMU8000_INIT4_WRITE(emu, 0x11, bass_parm[bass][1]);
601 EMU8000_INIT3_WRITE(emu, 0x11, treble_parm[treble][0]);
602 EMU8000_INIT3_WRITE(emu, 0x13, treble_parm[treble][1]);
603 EMU8000_INIT3_WRITE(emu, 0x1b, treble_parm[treble][2]);
604 EMU8000_INIT4_WRITE(emu, 0x07, treble_parm[treble][3]);
605 EMU8000_INIT4_WRITE(emu, 0x0b, treble_parm[treble][4]);
606 EMU8000_INIT4_WRITE(emu, 0x0d, treble_parm[treble][5]);
607 EMU8000_INIT4_WRITE(emu, 0x17, treble_parm[treble][6]);
608 EMU8000_INIT4_WRITE(emu, 0x19, treble_parm[treble][7]);
609 w = bass_parm[bass][2] + treble_parm[treble][8];
610 EMU8000_INIT4_WRITE(emu, 0x15, (unsigned short)(w + 0x0262));
611 EMU8000_INIT4_WRITE(emu, 0x1d, (unsigned short)(w + 0x8362));
612}
613
614
615/*----------------------------------------------------------------
616 * Chorus mode control
617 *----------------------------------------------------------------*/
618
619/*
620 * chorus mode parameters
621 */
622#define SNDRV_EMU8000_CHORUS_1 0
623#define SNDRV_EMU8000_CHORUS_2 1
624#define SNDRV_EMU8000_CHORUS_3 2
625#define SNDRV_EMU8000_CHORUS_4 3
626#define SNDRV_EMU8000_CHORUS_FEEDBACK 4
627#define SNDRV_EMU8000_CHORUS_FLANGER 5
628#define SNDRV_EMU8000_CHORUS_SHORTDELAY 6
629#define SNDRV_EMU8000_CHORUS_SHORTDELAY2 7
630#define SNDRV_EMU8000_CHORUS_PREDEFINED 8
631/* user can define chorus modes up to 32 */
632#define SNDRV_EMU8000_CHORUS_NUMBERS 32
633
634typedef struct soundfont_chorus_fx_t {
635 unsigned short feedback; /* feedback level (0xE600-0xE6FF) */
636 unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */
637 unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */
638 unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
639 unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */
640} soundfont_chorus_fx_t;
641
642/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
643static char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
644static soundfont_chorus_fx_t chorus_parm[SNDRV_EMU8000_CHORUS_NUMBERS] = {
645 {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
646 {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
647 {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
648 {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
649 {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
650 {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
651 {0xE600, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay */
652 {0xE6C0, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay + feedback */
653};
654
655/*exported*/ int
656snd_emu8000_load_chorus_fx(emu8000_t *emu, int mode, const void __user *buf, long len)
657{
658 soundfont_chorus_fx_t rec;
659 if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) {
660 snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode);
661 return -EINVAL;
662 }
663 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
664 return -EFAULT;
665 chorus_parm[mode] = rec;
666 chorus_defined[mode] = 1;
667 return 0;
668}
669
670/*exported*/ void
671snd_emu8000_update_chorus_mode(emu8000_t *emu)
672{
673 int effect = emu->chorus_mode;
674 if (effect < 0 || effect >= SNDRV_EMU8000_CHORUS_NUMBERS ||
675 (effect >= SNDRV_EMU8000_CHORUS_PREDEFINED && !chorus_defined[effect]))
676 return;
677 EMU8000_INIT3_WRITE(emu, 0x09, chorus_parm[effect].feedback);
678 EMU8000_INIT3_WRITE(emu, 0x0c, chorus_parm[effect].delay_offset);
679 EMU8000_INIT4_WRITE(emu, 0x03, chorus_parm[effect].lfo_depth);
680 EMU8000_HWCF4_WRITE(emu, chorus_parm[effect].delay);
681 EMU8000_HWCF5_WRITE(emu, chorus_parm[effect].lfo_freq);
682 EMU8000_HWCF6_WRITE(emu, 0x8000);
683 EMU8000_HWCF7_WRITE(emu, 0x0000);
684}
685
686/*----------------------------------------------------------------
687 * Reverb mode control
688 *----------------------------------------------------------------*/
689
690/*
691 * reverb mode parameters
692 */
693#define SNDRV_EMU8000_REVERB_ROOM1 0
694#define SNDRV_EMU8000_REVERB_ROOM2 1
695#define SNDRV_EMU8000_REVERB_ROOM3 2
696#define SNDRV_EMU8000_REVERB_HALL1 3
697#define SNDRV_EMU8000_REVERB_HALL2 4
698#define SNDRV_EMU8000_REVERB_PLATE 5
699#define SNDRV_EMU8000_REVERB_DELAY 6
700#define SNDRV_EMU8000_REVERB_PANNINGDELAY 7
701#define SNDRV_EMU8000_REVERB_PREDEFINED 8
702/* user can define reverb modes up to 32 */
703#define SNDRV_EMU8000_REVERB_NUMBERS 32
704
705typedef struct soundfont_reverb_fx_t {
706 unsigned short parms[28];
707} soundfont_reverb_fx_t;
708
709/* reverb mode settings; write the following 28 data of 16 bit length
710 * on the corresponding ports in the reverb_cmds array
711 */
712static char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
713static soundfont_reverb_fx_t reverb_parm[SNDRV_EMU8000_REVERB_NUMBERS] = {
714{{ /* room 1 */
715 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
716 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
717 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
718 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
719}},
720{{ /* room 2 */
721 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
722 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
723 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
724 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
725}},
726{{ /* room 3 */
727 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
728 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
729 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
730 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
731}},
732{{ /* hall 1 */
733 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
734 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
735 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
736 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
737}},
738{{ /* hall 2 */
739 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
740 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
741 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
742 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
743}},
744{{ /* plate */
745 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
746 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
747 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
748 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
749}},
750{{ /* delay */
751 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
752 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
753 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
754 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
755}},
756{{ /* panning delay */
757 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
758 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
759 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
760 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
761}},
762};
763
764enum { DATA1, DATA2 };
765#define AWE_INIT1(c) EMU8000_CMD(2,c), DATA1
766#define AWE_INIT2(c) EMU8000_CMD(2,c), DATA2
767#define AWE_INIT3(c) EMU8000_CMD(3,c), DATA1
768#define AWE_INIT4(c) EMU8000_CMD(3,c), DATA2
769
770static struct reverb_cmd_pair {
771 unsigned short cmd, port;
772} reverb_cmds[28] = {
773 {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
774 {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
775 {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
776 {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
777 {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
778 {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
779 {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
780};
781
782/*exported*/ int
783snd_emu8000_load_reverb_fx(emu8000_t *emu, int mode, const void __user *buf, long len)
784{
785 soundfont_reverb_fx_t rec;
786
787 if (mode < SNDRV_EMU8000_REVERB_PREDEFINED || mode >= SNDRV_EMU8000_REVERB_NUMBERS) {
788 snd_printk(KERN_WARNING "invalid reverb mode %d for uploading\n", mode);
789 return -EINVAL;
790 }
791 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
792 return -EFAULT;
793 reverb_parm[mode] = rec;
794 reverb_defined[mode] = 1;
795 return 0;
796}
797
798/*exported*/ void
799snd_emu8000_update_reverb_mode(emu8000_t *emu)
800{
801 int effect = emu->reverb_mode;
802 int i;
803
804 if (effect < 0 || effect >= SNDRV_EMU8000_REVERB_NUMBERS ||
805 (effect >= SNDRV_EMU8000_REVERB_PREDEFINED && !reverb_defined[effect]))
806 return;
807 for (i = 0; i < 28; i++) {
808 int port;
809 if (reverb_cmds[i].port == DATA1)
810 port = EMU8000_DATA1(emu);
811 else
812 port = EMU8000_DATA2(emu);
813 snd_emu8000_poke(emu, port, reverb_cmds[i].cmd, reverb_parm[effect].parms[i]);
814 }
815}
816
817
818/*----------------------------------------------------------------
819 * mixer interface
820 *----------------------------------------------------------------*/
821
822/*
823 * bass/treble
824 */
825static int mixer_bass_treble_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
826{
827 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
828 uinfo->count = 1;
829 uinfo->value.integer.min = 0;
830 uinfo->value.integer.max = 11;
831 return 0;
832}
833
834static int mixer_bass_treble_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
835{
836 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
837
838 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->treble_level : emu->bass_level;
839 return 0;
840}
841
842static int mixer_bass_treble_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
843{
844 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
845 unsigned long flags;
846 int change;
847 unsigned short val1;
848
849 val1 = ucontrol->value.integer.value[0] % 12;
850 spin_lock_irqsave(&emu->control_lock, flags);
851 if (kcontrol->private_value) {
852 change = val1 != emu->treble_level;
853 emu->treble_level = val1;
854 } else {
855 change = val1 != emu->bass_level;
856 emu->bass_level = val1;
857 }
858 spin_unlock_irqrestore(&emu->control_lock, flags);
859 snd_emu8000_update_equalizer(emu);
860 return change;
861}
862
863static snd_kcontrol_new_t mixer_bass_control =
864{
865 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
866 .name = "Synth Tone Control - Bass",
867 .info = mixer_bass_treble_info,
868 .get = mixer_bass_treble_get,
869 .put = mixer_bass_treble_put,
870 .private_value = 0,
871};
872
873static snd_kcontrol_new_t mixer_treble_control =
874{
875 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
876 .name = "Synth Tone Control - Treble",
877 .info = mixer_bass_treble_info,
878 .get = mixer_bass_treble_get,
879 .put = mixer_bass_treble_put,
880 .private_value = 1,
881};
882
883/*
884 * chorus/reverb mode
885 */
886static int mixer_chorus_reverb_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
887{
888 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
889 uinfo->count = 1;
890 uinfo->value.integer.min = 0;
891 uinfo->value.integer.max = kcontrol->private_value ? (SNDRV_EMU8000_CHORUS_NUMBERS-1) : (SNDRV_EMU8000_REVERB_NUMBERS-1);
892 return 0;
893}
894
895static int mixer_chorus_reverb_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
896{
897 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
898
899 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->chorus_mode : emu->reverb_mode;
900 return 0;
901}
902
903static int mixer_chorus_reverb_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
904{
905 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
906 unsigned long flags;
907 int change;
908 unsigned short val1;
909
910 spin_lock_irqsave(&emu->control_lock, flags);
911 if (kcontrol->private_value) {
912 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
913 change = val1 != emu->chorus_mode;
914 emu->chorus_mode = val1;
915 } else {
916 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
917 change = val1 != emu->reverb_mode;
918 emu->reverb_mode = val1;
919 }
920 spin_unlock_irqrestore(&emu->control_lock, flags);
921 if (change) {
922 if (kcontrol->private_value)
923 snd_emu8000_update_chorus_mode(emu);
924 else
925 snd_emu8000_update_reverb_mode(emu);
926 }
927 return change;
928}
929
930static snd_kcontrol_new_t mixer_chorus_mode_control =
931{
932 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
933 .name = "Chorus Mode",
934 .info = mixer_chorus_reverb_info,
935 .get = mixer_chorus_reverb_get,
936 .put = mixer_chorus_reverb_put,
937 .private_value = 1,
938};
939
940static snd_kcontrol_new_t mixer_reverb_mode_control =
941{
942 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
943 .name = "Reverb Mode",
944 .info = mixer_chorus_reverb_info,
945 .get = mixer_chorus_reverb_get,
946 .put = mixer_chorus_reverb_put,
947 .private_value = 0,
948};
949
950/*
951 * FM OPL3 chorus/reverb depth
952 */
953static int mixer_fm_depth_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
954{
955 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
956 uinfo->count = 1;
957 uinfo->value.integer.min = 0;
958 uinfo->value.integer.max = 255;
959 return 0;
960}
961
962static int mixer_fm_depth_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
963{
964 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
965
966 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->fm_chorus_depth : emu->fm_reverb_depth;
967 return 0;
968}
969
970static int mixer_fm_depth_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
971{
972 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
973 unsigned long flags;
974 int change;
975 unsigned short val1;
976
977 val1 = ucontrol->value.integer.value[0] % 256;
978 spin_lock_irqsave(&emu->control_lock, flags);
979 if (kcontrol->private_value) {
980 change = val1 != emu->fm_chorus_depth;
981 emu->fm_chorus_depth = val1;
982 } else {
983 change = val1 != emu->fm_reverb_depth;
984 emu->fm_reverb_depth = val1;
985 }
986 spin_unlock_irqrestore(&emu->control_lock, flags);
987 if (change)
988 snd_emu8000_init_fm(emu);
989 return change;
990}
991
992static snd_kcontrol_new_t mixer_fm_chorus_depth_control =
993{
994 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
995 .name = "FM Chorus Depth",
996 .info = mixer_fm_depth_info,
997 .get = mixer_fm_depth_get,
998 .put = mixer_fm_depth_put,
999 .private_value = 1,
1000};
1001
1002static snd_kcontrol_new_t mixer_fm_reverb_depth_control =
1003{
1004 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1005 .name = "FM Reverb Depth",
1006 .info = mixer_fm_depth_info,
1007 .get = mixer_fm_depth_get,
1008 .put = mixer_fm_depth_put,
1009 .private_value = 0,
1010};
1011
1012
1013static snd_kcontrol_new_t *mixer_defs[EMU8000_NUM_CONTROLS] = {
1014 &mixer_bass_control,
1015 &mixer_treble_control,
1016 &mixer_chorus_mode_control,
1017 &mixer_reverb_mode_control,
1018 &mixer_fm_chorus_depth_control,
1019 &mixer_fm_reverb_depth_control,
1020};
1021
1022/*
1023 * create and attach mixer elements for WaveTable treble/bass controls
1024 */
1025static int __init
1026snd_emu8000_create_mixer(snd_card_t *card, emu8000_t *emu)
1027{
1028 int i, err = 0;
1029
1030 snd_assert(emu != NULL && card != NULL, return -EINVAL);
1031
1032 spin_lock_init(&emu->control_lock);
1033
1034 memset(emu->controls, 0, sizeof(emu->controls));
1035 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1036 if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0)
1037 goto __error;
1038 }
1039 return 0;
1040
1041__error:
1042 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1043 down_write(&card->controls_rwsem);
1044 if (emu->controls[i])
1045 snd_ctl_remove(card, emu->controls[i]);
1046 up_write(&card->controls_rwsem);
1047 }
1048 return err;
1049}
1050
1051
1052/*
1053 * free resources
1054 */
1055static int snd_emu8000_free(emu8000_t *hw)
1056{
1057 if (hw->res_port1) {
1058 release_resource(hw->res_port1);
1059 kfree_nocheck(hw->res_port1);
1060 }
1061 if (hw->res_port2) {
1062 release_resource(hw->res_port2);
1063 kfree_nocheck(hw->res_port2);
1064 }
1065 if (hw->res_port3) {
1066 release_resource(hw->res_port3);
1067 kfree_nocheck(hw->res_port3);
1068 }
1069 kfree(hw);
1070 return 0;
1071}
1072
1073/*
1074 */
1075static int snd_emu8000_dev_free(snd_device_t *device)
1076{
1077 emu8000_t *hw = device->device_data;
1078 return snd_emu8000_free(hw);
1079}
1080
1081/*
1082 * initialize and register emu8000 synth device.
1083 */
1084int __init
1085snd_emu8000_new(snd_card_t *card, int index, long port, int seq_ports, snd_seq_device_t **awe_ret)
1086{
1087 snd_seq_device_t *awe;
1088 emu8000_t *hw;
1089 int err;
1090 static snd_device_ops_t ops = {
1091 .dev_free = snd_emu8000_dev_free,
1092 };
1093
1094 if (awe_ret)
1095 *awe_ret = NULL;
1096
1097 if (seq_ports <= 0)
1098 return 0;
1099
1100 hw = kcalloc(1, sizeof(*hw), GFP_KERNEL);
1101 if (hw == NULL)
1102 return -ENOMEM;
1103 spin_lock_init(&hw->reg_lock);
1104 hw->index = index;
1105 hw->port1 = port;
1106 hw->port2 = port + 0x400;
1107 hw->port3 = port + 0x800;
1108 if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) ||
1109 !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) ||
1110 !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) {
1111 snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3);
1112 snd_emu8000_free(hw);
1113 return -EBUSY;
1114 }
1115 hw->mem_size = 0;
1116 hw->card = card;
1117 hw->seq_ports = seq_ports;
1118 hw->bass_level = 5;
1119 hw->treble_level = 9;
1120 hw->chorus_mode = 2;
1121 hw->reverb_mode = 4;
1122 hw->fm_chorus_depth = 0;
1123 hw->fm_reverb_depth = 0;
1124
1125 if (snd_emu8000_detect(hw) < 0) {
1126 snd_emu8000_free(hw);
1127 return -ENODEV;
1128 }
1129
1130 snd_emu8000_init_hw(hw);
1131 if ((err = snd_emu8000_create_mixer(card, hw)) < 0) {
1132 snd_emu8000_free(hw);
1133 return err;
1134 }
1135
1136 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, hw, &ops)) < 0) {
1137 snd_emu8000_free(hw);
1138 return err;
1139 }
1140#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1141 if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
1142 sizeof(emu8000_t*), &awe) >= 0) {
1143 strcpy(awe->name, "EMU-8000");
1144 *(emu8000_t**)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
1145 }
1146#else
1147 awe = NULL;
1148#endif
1149 if (awe_ret)
1150 *awe_ret = awe;
1151
1152 return 0;
1153}
1154
1155
1156/*
1157 * exported stuff
1158 */
1159
1160EXPORT_SYMBOL(snd_emu8000_poke);
1161EXPORT_SYMBOL(snd_emu8000_peek);
1162EXPORT_SYMBOL(snd_emu8000_poke_dw);
1163EXPORT_SYMBOL(snd_emu8000_peek_dw);
1164EXPORT_SYMBOL(snd_emu8000_dma_chan);
1165EXPORT_SYMBOL(snd_emu8000_init_fm);
1166EXPORT_SYMBOL(snd_emu8000_load_chorus_fx);
1167EXPORT_SYMBOL(snd_emu8000_load_reverb_fx);
1168EXPORT_SYMBOL(snd_emu8000_update_chorus_mode);
1169EXPORT_SYMBOL(snd_emu8000_update_reverb_mode);
1170EXPORT_SYMBOL(snd_emu8000_update_equalizer);