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