~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/isa/sb/emu8000.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.14 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.57 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.138 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.193 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 *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 *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                 if (emu->controls[i])
1048                         snd_ctl_remove(card, emu->controls[i]);
1049         }
1050         return err;
1051 }
1052 
1053 
1054 /*
1055  * free resources
1056  */
1057 static int snd_emu8000_free(emu8000_t *hw)
1058 {
1059         if (hw->res_port1) {
1060                 release_resource(hw->res_port1);
1061                 kfree_nocheck(hw->res_port1);
1062         }
1063         if (hw->res_port2) {
1064                 release_resource(hw->res_port2);
1065                 kfree_nocheck(hw->res_port2);
1066         }
1067         if (hw->res_port3) {
1068                 release_resource(hw->res_port3);
1069                 kfree_nocheck(hw->res_port3);
1070         }
1071         snd_magic_kfree(hw);
1072         return 0;
1073 }
1074 
1075 /*
1076  */
1077 static int snd_emu8000_dev_free(snd_device_t *device)
1078 {
1079         emu8000_t *hw = snd_magic_cast(emu8000_t, device->device_data, return -ENXIO);
1080         return snd_emu8000_free(hw);
1081 }
1082 
1083 /*
1084  * initialize and register emu8000 synth device.
1085  */
1086 int __init
1087 snd_emu8000_new(snd_card_t *card, int index, long port, int seq_ports, snd_seq_device_t **awe_ret)
1088 {
1089         snd_seq_device_t *awe;
1090         emu8000_t *hw;
1091         int err;
1092         static snd_device_ops_t ops = {
1093                 .dev_free = snd_emu8000_dev_free,
1094         };
1095 
1096         if (awe_ret)
1097                 *awe_ret = NULL;
1098 
1099         if (seq_ports <= 0)
1100                 return 0;
1101 
1102         hw = snd_magic_kcalloc(emu8000_t, 0, GFP_KERNEL);
1103         if (hw == NULL)
1104                 return -ENOMEM;
1105         spin_lock_init(&hw->reg_lock);
1106         hw->index = index;
1107         hw->port1 = port;
1108         hw->port2 = port + 0x400;
1109         hw->port3 = port + 0x800;
1110         if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) ||
1111             !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) ||
1112             !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) {
1113                 snd_emu8000_free(hw);
1114                 return -EBUSY;
1115         }
1116         hw->mem_size = 0;
1117         hw->card = card;
1118         hw->seq_ports = seq_ports;
1119         hw->bass_level = 5;
1120         hw->treble_level = 9;
1121         hw->chorus_mode = 2;
1122         hw->reverb_mode = 4;
1123         hw->fm_chorus_depth = 0;
1124         hw->fm_reverb_depth = 0;
1125 
1126         if (snd_emu8000_detect(hw) < 0) {
1127                 snd_emu8000_free(hw);
1128                 return -ENODEV;
1129         }
1130 
1131         snd_emu8000_init_hw(hw);
1132         if ((err = snd_emu8000_create_mixer(card, hw)) < 0) {
1133                 snd_emu8000_free(hw);
1134                 return err;
1135         }
1136         
1137         if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, hw, &ops)) < 0) {
1138                 snd_emu8000_free(hw);
1139                 return err;
1140         }
1141 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1142         if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
1143                                sizeof(emu8000_t*), &awe) >= 0) {
1144                 strcpy(awe->name, "EMU-8000");
1145                 *(emu8000_t**)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
1146         }
1147 #else
1148         awe = NULL;
1149 #endif
1150         if (awe_ret)
1151                 *awe_ret = awe;
1152 
1153         return 0;
1154 }
1155 
1156 
1157 /*
1158  * exported stuff
1159  */
1160 
1161 EXPORT_SYMBOL(snd_emu8000_poke);
1162 EXPORT_SYMBOL(snd_emu8000_peek);
1163 EXPORT_SYMBOL(snd_emu8000_poke_dw);
1164 EXPORT_SYMBOL(snd_emu8000_peek_dw);
1165 EXPORT_SYMBOL(snd_emu8000_dma_chan);
1166 EXPORT_SYMBOL(snd_emu8000_init_fm);
1167 EXPORT_SYMBOL(snd_emu8000_load_chorus_fx);
1168 EXPORT_SYMBOL(snd_emu8000_load_reverb_fx);
1169 EXPORT_SYMBOL(snd_emu8000_update_chorus_mode);
1170 EXPORT_SYMBOL(snd_emu8000_update_reverb_mode);
1171 EXPORT_SYMBOL(snd_emu8000_update_equalizer);
1172 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp