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

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

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