blob: b35be7d9a9fa8b4a70e1037534c2e8bd0b821d9f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02002 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/wait.h>
24#include <linux/sched.h>
25#include <linux/slab.h>
26#include <linux/ioport.h>
27#include <linux/delay.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 */
Takashi Iwai029d64b2005-11-17 14:34:36 +010047void snd_emu8000_poke(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
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 */
Takashi Iwai029d64b2005-11-17 14:34:36 +010060unsigned short snd_emu8000_peek(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061{
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 */
Takashi Iwai029d64b2005-11-17 14:34:36 +010075void snd_emu8000_poke_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
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 */
Takashi Iwai029d64b2005-11-17 14:34:36 +010089unsigned int snd_emu8000_peek_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070090{
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
Takashi Iwai029d64b2005-11-17 14:34:36 +0100109snd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
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 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200133static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100134snd_emu8000_read_wait(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
136 while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
Nishanth Aravamudan8433a502005-10-24 15:02:37 +0200137 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 if (signal_pending(current))
139 break;
140 }
141}
142
143/*
144 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200145static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100146snd_emu8000_write_wait(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
148 while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
Nishanth Aravamudan8433a502005-10-24 15:02:37 +0200149 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 if (signal_pending(current))
151 break;
152 }
153}
154
155/*
156 * detect a card at the given port
157 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200158static int __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100159snd_emu8000_detect(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160{
161 /* Initialise */
162 EMU8000_HWCF1_WRITE(emu, 0x0059);
163 EMU8000_HWCF2_WRITE(emu, 0x0020);
164 EMU8000_HWCF3_WRITE(emu, 0x0000);
165 /* Check for a recognisable emu8000 */
166 /*
167 if ((EMU8000_U1_READ(emu) & 0x000f) != 0x000c)
168 return -ENODEV;
169 */
170 if ((EMU8000_HWCF1_READ(emu) & 0x007e) != 0x0058)
171 return -ENODEV;
172 if ((EMU8000_HWCF2_READ(emu) & 0x0003) != 0x0003)
173 return -ENODEV;
174
175 snd_printdd("EMU8000 [0x%lx]: Synth chip found\n",
176 emu->port1);
177 return 0;
178}
179
180
181/*
182 * intiailize audio channels
183 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200184static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100185init_audio(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186{
187 int ch;
188
189 /* turn off envelope engines */
190 for (ch = 0; ch < EMU8000_CHANNELS; ch++)
191 EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
192
193 /* reset all other parameters to zero */
194 for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
195 EMU8000_ENVVOL_WRITE(emu, ch, 0);
196 EMU8000_ENVVAL_WRITE(emu, ch, 0);
197 EMU8000_DCYSUS_WRITE(emu, ch, 0);
198 EMU8000_ATKHLDV_WRITE(emu, ch, 0);
199 EMU8000_LFO1VAL_WRITE(emu, ch, 0);
200 EMU8000_ATKHLD_WRITE(emu, ch, 0);
201 EMU8000_LFO2VAL_WRITE(emu, ch, 0);
202 EMU8000_IP_WRITE(emu, ch, 0);
203 EMU8000_IFATN_WRITE(emu, ch, 0);
204 EMU8000_PEFE_WRITE(emu, ch, 0);
205 EMU8000_FMMOD_WRITE(emu, ch, 0);
206 EMU8000_TREMFRQ_WRITE(emu, ch, 0);
207 EMU8000_FM2FRQ2_WRITE(emu, ch, 0);
208 EMU8000_PTRX_WRITE(emu, ch, 0);
209 EMU8000_VTFT_WRITE(emu, ch, 0);
210 EMU8000_PSST_WRITE(emu, ch, 0);
211 EMU8000_CSL_WRITE(emu, ch, 0);
212 EMU8000_CCCA_WRITE(emu, ch, 0);
213 }
214
215 for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
216 EMU8000_CPF_WRITE(emu, ch, 0);
217 EMU8000_CVCF_WRITE(emu, ch, 0);
218 }
219}
220
221
222/*
223 * initialize DMA address
224 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200225static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100226init_dma(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 EMU8000_SMALR_WRITE(emu, 0);
229 EMU8000_SMARR_WRITE(emu, 0);
230 EMU8000_SMALW_WRITE(emu, 0);
231 EMU8000_SMARW_WRITE(emu, 0);
232}
233
234/*
235 * initialization arrays; from ADIP
236 */
237static unsigned short init1[128] /*__devinitdata*/ = {
238 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330,
239 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730,
240 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30,
241 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30,
242
243 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330,
244 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730,
245 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30,
246 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30,
247
248 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330,
249 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730,
250 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30,
251 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30,
252
253 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330,
254 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730,
255 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30,
256 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30,
257};
258
259static unsigned short init2[128] /*__devinitdata*/ = {
260 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
261 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
262 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
263 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
264
265 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
266 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
267 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
268 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
269
270 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
271 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
272 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
273 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
274
275 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
276 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
277 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
278 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
279};
280
281static unsigned short init3[128] /*__devinitdata*/ = {
282 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
283 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
284 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
285 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
286
287 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
288 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
289 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
290 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
291
292 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
293 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
294 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
295 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
296
297 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
298 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
299 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
300 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
301};
302
303static unsigned short init4[128] /*__devinitdata*/ = {
304 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
305 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
306 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
307 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
308
309 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
310 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
311 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
312 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
313
314 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
315 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
316 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
317 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
318
319 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
320 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
321 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
322 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
323};
324
325/* send an initialization array
326 * Taken from the oss driver, not obvious from the doc how this
327 * is meant to work
328 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200329static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100330send_array(struct snd_emu8000 *emu, unsigned short *data, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
332 int i;
333 unsigned short *p;
334
335 p = data;
336 for (i = 0; i < size; i++, p++)
337 EMU8000_INIT1_WRITE(emu, i, *p);
338 for (i = 0; i < size; i++, p++)
339 EMU8000_INIT2_WRITE(emu, i, *p);
340 for (i = 0; i < size; i++, p++)
341 EMU8000_INIT3_WRITE(emu, i, *p);
342 for (i = 0; i < size; i++, p++)
343 EMU8000_INIT4_WRITE(emu, i, *p);
344}
345
346
347/*
348 * Send initialization arrays to start up, this just follows the
349 * initialisation sequence in the adip.
350 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200351static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100352init_arrays(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 send_array(emu, init1, ARRAY_SIZE(init1)/4);
355
356 msleep((1024 * 1000) / 44100); /* wait for 1024 clocks */
357 send_array(emu, init2, ARRAY_SIZE(init2)/4);
358 send_array(emu, init3, ARRAY_SIZE(init3)/4);
359
360 EMU8000_HWCF4_WRITE(emu, 0);
361 EMU8000_HWCF5_WRITE(emu, 0x83);
362 EMU8000_HWCF6_WRITE(emu, 0x8000);
363
364 send_array(emu, init4, ARRAY_SIZE(init4)/4);
365}
366
367
368#define UNIQUE_ID1 0xa5b9
369#define UNIQUE_ID2 0x9d53
370
371/*
372 * Size the onboard memory.
373 * This is written so as not to need arbitary delays after the write. It
374 * seems that the only way to do this is to use the one channel and keep
375 * reallocating between read and write.
376 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200377static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100378size_dram(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 int i, size;
381
382 if (emu->dram_checked)
383 return;
384
385 size = 0;
386
387 /* write out a magic number */
388 snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
389 snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_READ);
390 EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET);
391 EMU8000_SMLD_WRITE(emu, UNIQUE_ID1);
392 snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */
393
394 while (size < EMU8000_MAX_DRAM) {
395
396 size += 512 * 1024; /* increment 512kbytes */
397
398 /* Write a unique data on the test address.
399 * if the address is out of range, the data is written on
400 * 0x200000(=EMU8000_DRAM_OFFSET). Then the id word is
401 * changed by this data.
402 */
403 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);*/
404 EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
405 EMU8000_SMLD_WRITE(emu, UNIQUE_ID2);
406 snd_emu8000_write_wait(emu);
407
408 /*
409 * read the data on the just written DRAM address
410 * if not the same then we have reached the end of ram.
411 */
412 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_READ);*/
413 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
414 /*snd_emu8000_read_wait(emu);*/
415 EMU8000_SMLD_READ(emu); /* discard stale data */
416 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
417 break; /* we must have wrapped around */
418
419 snd_emu8000_read_wait(emu);
420
421 /*
422 * If it is the same it could be that the address just
423 * wraps back to the beginning; so check to see if the
424 * initial value has been overwritten.
425 */
426 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
427 EMU8000_SMLD_READ(emu); /* discard stale data */
428 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
429 break; /* we must have wrapped around */
430 snd_emu8000_read_wait(emu);
431 }
432
433 /* wait until FULL bit in SMAxW register is false */
434 for (i = 0; i < 10000; i++) {
435 if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
436 break;
Nishanth Aravamudan8433a502005-10-24 15:02:37 +0200437 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 if (signal_pending(current))
439 break;
440 }
441 snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
442 snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
443
444 snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n",
445 emu->port1, size/1024);
446
447 emu->mem_size = size;
448 emu->dram_checked = 1;
449}
450
451
452/*
453 * Initiailise the FM section. You have to do this to use sample RAM
454 * and therefore lose 2 voices.
455 */
456/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100457snd_emu8000_init_fm(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 unsigned long flags;
460
461 /* Initialize the last two channels for DRAM refresh and producing
462 the reverb and chorus effects for Yamaha OPL-3 synthesizer */
463
464 /* 31: FM left channel, 0xffffe0-0xffffe8 */
465 EMU8000_DCYSUSV_WRITE(emu, 30, 0x80);
466 EMU8000_PSST_WRITE(emu, 30, 0xFFFFFFE0); /* full left */
467 EMU8000_CSL_WRITE(emu, 30, 0x00FFFFE8 | (emu->fm_chorus_depth << 24));
468 EMU8000_PTRX_WRITE(emu, 30, (emu->fm_reverb_depth << 8));
469 EMU8000_CPF_WRITE(emu, 30, 0);
470 EMU8000_CCCA_WRITE(emu, 30, 0x00FFFFE3);
471
472 /* 32: FM right channel, 0xfffff0-0xfffff8 */
473 EMU8000_DCYSUSV_WRITE(emu, 31, 0x80);
474 EMU8000_PSST_WRITE(emu, 31, 0x00FFFFF0); /* full right */
475 EMU8000_CSL_WRITE(emu, 31, 0x00FFFFF8 | (emu->fm_chorus_depth << 24));
476 EMU8000_PTRX_WRITE(emu, 31, (emu->fm_reverb_depth << 8));
477 EMU8000_CPF_WRITE(emu, 31, 0x8000);
478 EMU8000_CCCA_WRITE(emu, 31, 0x00FFFFF3);
479
480 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0);
481
482 spin_lock_irqsave(&emu->reg_lock, flags);
483 while (!(inw(EMU8000_PTR(emu)) & 0x1000))
484 ;
485 while ((inw(EMU8000_PTR(emu)) & 0x1000))
486 ;
487 spin_unlock_irqrestore(&emu->reg_lock, flags);
488 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828);
489 /* this is really odd part.. */
490 outb(0x3C, EMU8000_PTR(emu));
491 outb(0, EMU8000_DATA1(emu));
492
493 /* skew volume & cutoff */
494 EMU8000_VTFT_WRITE(emu, 30, 0x8000FFFF);
495 EMU8000_VTFT_WRITE(emu, 31, 0x8000FFFF);
496}
497
498
499/*
500 * The main initialization routine.
501 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200502static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100503snd_emu8000_init_hw(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 int i;
506
507 emu->last_reg = 0xffff; /* reset the last register index */
508
509 /* initialize hardware configuration */
510 EMU8000_HWCF1_WRITE(emu, 0x0059);
511 EMU8000_HWCF2_WRITE(emu, 0x0020);
512
513 /* disable audio; this seems to reduce a clicking noise a bit.. */
514 EMU8000_HWCF3_WRITE(emu, 0);
515
516 /* initialize audio channels */
517 init_audio(emu);
518
519 /* initialize DMA */
520 init_dma(emu);
521
522 /* initialize init arrays */
523 init_arrays(emu);
524
525 /*
526 * Initialize the FM section of the AWE32, this is needed
527 * for DRAM refresh as well
528 */
529 snd_emu8000_init_fm(emu);
530
531 /* terminate all voices */
532 for (i = 0; i < EMU8000_DRAM_VOICES; i++)
533 EMU8000_DCYSUSV_WRITE(emu, 0, 0x807F);
534
535 /* check DRAM memory size */
536 size_dram(emu);
537
538 /* enable audio */
539 EMU8000_HWCF3_WRITE(emu, 0x4);
540
541 /* set equzlier, chorus and reverb modes */
542 snd_emu8000_update_equalizer(emu);
543 snd_emu8000_update_chorus_mode(emu);
544 snd_emu8000_update_reverb_mode(emu);
545}
546
547
548/*----------------------------------------------------------------
549 * Bass/Treble Equalizer
550 *----------------------------------------------------------------*/
551
552static unsigned short bass_parm[12][3] = {
553 {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
554 {0xD25B, 0xD35B, 0x0000}, /* -8 */
555 {0xD24C, 0xD34C, 0x0000}, /* -6 */
556 {0xD23D, 0xD33D, 0x0000}, /* -4 */
557 {0xD21F, 0xD31F, 0x0000}, /* -2 */
558 {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */
559 {0xC219, 0xC319, 0x0001}, /* +2 */
560 {0xC22A, 0xC32A, 0x0001}, /* +4 */
561 {0xC24C, 0xC34C, 0x0001}, /* +6 */
562 {0xC26E, 0xC36E, 0x0001}, /* +8 */
563 {0xC248, 0xC384, 0x0002}, /* +10 */
564 {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
565};
566
567static unsigned short treble_parm[12][9] = {
568 {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
569 {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
570 {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
571 {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
572 {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
573 {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
574 {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
575 {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
576 {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
577 {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
578 {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
579 {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002} /* +12 dB */
580};
581
582
583/*
584 * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
585 */
586/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100587snd_emu8000_update_equalizer(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
589 unsigned short w;
590 int bass = emu->bass_level;
591 int treble = emu->treble_level;
592
593 if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
594 return;
595 EMU8000_INIT4_WRITE(emu, 0x01, bass_parm[bass][0]);
596 EMU8000_INIT4_WRITE(emu, 0x11, bass_parm[bass][1]);
597 EMU8000_INIT3_WRITE(emu, 0x11, treble_parm[treble][0]);
598 EMU8000_INIT3_WRITE(emu, 0x13, treble_parm[treble][1]);
599 EMU8000_INIT3_WRITE(emu, 0x1b, treble_parm[treble][2]);
600 EMU8000_INIT4_WRITE(emu, 0x07, treble_parm[treble][3]);
601 EMU8000_INIT4_WRITE(emu, 0x0b, treble_parm[treble][4]);
602 EMU8000_INIT4_WRITE(emu, 0x0d, treble_parm[treble][5]);
603 EMU8000_INIT4_WRITE(emu, 0x17, treble_parm[treble][6]);
604 EMU8000_INIT4_WRITE(emu, 0x19, treble_parm[treble][7]);
605 w = bass_parm[bass][2] + treble_parm[treble][8];
606 EMU8000_INIT4_WRITE(emu, 0x15, (unsigned short)(w + 0x0262));
607 EMU8000_INIT4_WRITE(emu, 0x1d, (unsigned short)(w + 0x8362));
608}
609
610
611/*----------------------------------------------------------------
612 * Chorus mode control
613 *----------------------------------------------------------------*/
614
615/*
616 * chorus mode parameters
617 */
618#define SNDRV_EMU8000_CHORUS_1 0
619#define SNDRV_EMU8000_CHORUS_2 1
620#define SNDRV_EMU8000_CHORUS_3 2
621#define SNDRV_EMU8000_CHORUS_4 3
622#define SNDRV_EMU8000_CHORUS_FEEDBACK 4
623#define SNDRV_EMU8000_CHORUS_FLANGER 5
624#define SNDRV_EMU8000_CHORUS_SHORTDELAY 6
625#define SNDRV_EMU8000_CHORUS_SHORTDELAY2 7
626#define SNDRV_EMU8000_CHORUS_PREDEFINED 8
627/* user can define chorus modes up to 32 */
628#define SNDRV_EMU8000_CHORUS_NUMBERS 32
629
Takashi Iwai029d64b2005-11-17 14:34:36 +0100630struct soundfont_chorus_fx {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 unsigned short feedback; /* feedback level (0xE600-0xE6FF) */
632 unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */
633 unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */
634 unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
635 unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100636};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
639static char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100640static struct soundfont_chorus_fx chorus_parm[SNDRV_EMU8000_CHORUS_NUMBERS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
642 {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
643 {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
644 {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
645 {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
646 {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
647 {0xE600, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay */
648 {0xE6C0, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay + feedback */
649};
650
651/*exported*/ int
Takashi Iwai029d64b2005-11-17 14:34:36 +0100652snd_emu8000_load_chorus_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100654 struct soundfont_chorus_fx rec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) {
656 snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode);
657 return -EINVAL;
658 }
659 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
660 return -EFAULT;
661 chorus_parm[mode] = rec;
662 chorus_defined[mode] = 1;
663 return 0;
664}
665
666/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100667snd_emu8000_update_chorus_mode(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668{
669 int effect = emu->chorus_mode;
670 if (effect < 0 || effect >= SNDRV_EMU8000_CHORUS_NUMBERS ||
671 (effect >= SNDRV_EMU8000_CHORUS_PREDEFINED && !chorus_defined[effect]))
672 return;
673 EMU8000_INIT3_WRITE(emu, 0x09, chorus_parm[effect].feedback);
674 EMU8000_INIT3_WRITE(emu, 0x0c, chorus_parm[effect].delay_offset);
675 EMU8000_INIT4_WRITE(emu, 0x03, chorus_parm[effect].lfo_depth);
676 EMU8000_HWCF4_WRITE(emu, chorus_parm[effect].delay);
677 EMU8000_HWCF5_WRITE(emu, chorus_parm[effect].lfo_freq);
678 EMU8000_HWCF6_WRITE(emu, 0x8000);
679 EMU8000_HWCF7_WRITE(emu, 0x0000);
680}
681
682/*----------------------------------------------------------------
683 * Reverb mode control
684 *----------------------------------------------------------------*/
685
686/*
687 * reverb mode parameters
688 */
689#define SNDRV_EMU8000_REVERB_ROOM1 0
690#define SNDRV_EMU8000_REVERB_ROOM2 1
691#define SNDRV_EMU8000_REVERB_ROOM3 2
692#define SNDRV_EMU8000_REVERB_HALL1 3
693#define SNDRV_EMU8000_REVERB_HALL2 4
694#define SNDRV_EMU8000_REVERB_PLATE 5
695#define SNDRV_EMU8000_REVERB_DELAY 6
696#define SNDRV_EMU8000_REVERB_PANNINGDELAY 7
697#define SNDRV_EMU8000_REVERB_PREDEFINED 8
698/* user can define reverb modes up to 32 */
699#define SNDRV_EMU8000_REVERB_NUMBERS 32
700
Takashi Iwai029d64b2005-11-17 14:34:36 +0100701struct soundfont_reverb_fx {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 unsigned short parms[28];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100703};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705/* reverb mode settings; write the following 28 data of 16 bit length
706 * on the corresponding ports in the reverb_cmds array
707 */
708static char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100709static struct soundfont_reverb_fx reverb_parm[SNDRV_EMU8000_REVERB_NUMBERS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{{ /* room 1 */
711 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
712 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
713 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
714 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
715}},
716{{ /* room 2 */
717 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
718 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
719 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
720 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
721}},
722{{ /* room 3 */
723 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
724 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
725 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
726 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
727}},
728{{ /* hall 1 */
729 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
730 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
731 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
732 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
733}},
734{{ /* hall 2 */
735 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
736 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
737 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
738 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
739}},
740{{ /* plate */
741 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
742 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
743 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
744 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
745}},
746{{ /* delay */
747 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
748 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
749 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
750 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
751}},
752{{ /* panning delay */
753 0xB4FF, 0xA490, 0x9590, 0x8474, 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};
759
760enum { DATA1, DATA2 };
761#define AWE_INIT1(c) EMU8000_CMD(2,c), DATA1
762#define AWE_INIT2(c) EMU8000_CMD(2,c), DATA2
763#define AWE_INIT3(c) EMU8000_CMD(3,c), DATA1
764#define AWE_INIT4(c) EMU8000_CMD(3,c), DATA2
765
766static struct reverb_cmd_pair {
767 unsigned short cmd, port;
768} reverb_cmds[28] = {
769 {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
770 {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
771 {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
772 {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
773 {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
774 {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
775 {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
776};
777
778/*exported*/ int
Takashi Iwai029d64b2005-11-17 14:34:36 +0100779snd_emu8000_load_reverb_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100781 struct soundfont_reverb_fx rec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 if (mode < SNDRV_EMU8000_REVERB_PREDEFINED || mode >= SNDRV_EMU8000_REVERB_NUMBERS) {
784 snd_printk(KERN_WARNING "invalid reverb mode %d for uploading\n", mode);
785 return -EINVAL;
786 }
787 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
788 return -EFAULT;
789 reverb_parm[mode] = rec;
790 reverb_defined[mode] = 1;
791 return 0;
792}
793
794/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100795snd_emu8000_update_reverb_mode(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 int effect = emu->reverb_mode;
798 int i;
799
800 if (effect < 0 || effect >= SNDRV_EMU8000_REVERB_NUMBERS ||
801 (effect >= SNDRV_EMU8000_REVERB_PREDEFINED && !reverb_defined[effect]))
802 return;
803 for (i = 0; i < 28; i++) {
804 int port;
805 if (reverb_cmds[i].port == DATA1)
806 port = EMU8000_DATA1(emu);
807 else
808 port = EMU8000_DATA2(emu);
809 snd_emu8000_poke(emu, port, reverb_cmds[i].cmd, reverb_parm[effect].parms[i]);
810 }
811}
812
813
814/*----------------------------------------------------------------
815 * mixer interface
816 *----------------------------------------------------------------*/
817
818/*
819 * bass/treble
820 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100821static int mixer_bass_treble_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
823 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
824 uinfo->count = 1;
825 uinfo->value.integer.min = 0;
826 uinfo->value.integer.max = 11;
827 return 0;
828}
829
Takashi Iwai029d64b2005-11-17 14:34:36 +0100830static int mixer_bass_treble_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100832 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->treble_level : emu->bass_level;
835 return 0;
836}
837
Takashi Iwai029d64b2005-11-17 14:34:36 +0100838static int mixer_bass_treble_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100840 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 unsigned long flags;
842 int change;
843 unsigned short val1;
844
845 val1 = ucontrol->value.integer.value[0] % 12;
846 spin_lock_irqsave(&emu->control_lock, flags);
847 if (kcontrol->private_value) {
848 change = val1 != emu->treble_level;
849 emu->treble_level = val1;
850 } else {
851 change = val1 != emu->bass_level;
852 emu->bass_level = val1;
853 }
854 spin_unlock_irqrestore(&emu->control_lock, flags);
855 snd_emu8000_update_equalizer(emu);
856 return change;
857}
858
Takashi Iwai029d64b2005-11-17 14:34:36 +0100859static struct snd_kcontrol_new mixer_bass_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
861 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
862 .name = "Synth Tone Control - Bass",
863 .info = mixer_bass_treble_info,
864 .get = mixer_bass_treble_get,
865 .put = mixer_bass_treble_put,
866 .private_value = 0,
867};
868
Takashi Iwai029d64b2005-11-17 14:34:36 +0100869static struct snd_kcontrol_new mixer_treble_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
871 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
872 .name = "Synth Tone Control - Treble",
873 .info = mixer_bass_treble_info,
874 .get = mixer_bass_treble_get,
875 .put = mixer_bass_treble_put,
876 .private_value = 1,
877};
878
879/*
880 * chorus/reverb mode
881 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100882static int mixer_chorus_reverb_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
885 uinfo->count = 1;
886 uinfo->value.integer.min = 0;
887 uinfo->value.integer.max = kcontrol->private_value ? (SNDRV_EMU8000_CHORUS_NUMBERS-1) : (SNDRV_EMU8000_REVERB_NUMBERS-1);
888 return 0;
889}
890
Takashi Iwai029d64b2005-11-17 14:34:36 +0100891static int mixer_chorus_reverb_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100893 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->chorus_mode : emu->reverb_mode;
896 return 0;
897}
898
Takashi Iwai029d64b2005-11-17 14:34:36 +0100899static int mixer_chorus_reverb_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100901 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 unsigned long flags;
903 int change;
904 unsigned short val1;
905
906 spin_lock_irqsave(&emu->control_lock, flags);
907 if (kcontrol->private_value) {
908 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
909 change = val1 != emu->chorus_mode;
910 emu->chorus_mode = val1;
911 } else {
912 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
913 change = val1 != emu->reverb_mode;
914 emu->reverb_mode = val1;
915 }
916 spin_unlock_irqrestore(&emu->control_lock, flags);
917 if (change) {
918 if (kcontrol->private_value)
919 snd_emu8000_update_chorus_mode(emu);
920 else
921 snd_emu8000_update_reverb_mode(emu);
922 }
923 return change;
924}
925
Takashi Iwai029d64b2005-11-17 14:34:36 +0100926static struct snd_kcontrol_new mixer_chorus_mode_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
928 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
929 .name = "Chorus Mode",
930 .info = mixer_chorus_reverb_info,
931 .get = mixer_chorus_reverb_get,
932 .put = mixer_chorus_reverb_put,
933 .private_value = 1,
934};
935
Takashi Iwai029d64b2005-11-17 14:34:36 +0100936static struct snd_kcontrol_new mixer_reverb_mode_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
939 .name = "Reverb Mode",
940 .info = mixer_chorus_reverb_info,
941 .get = mixer_chorus_reverb_get,
942 .put = mixer_chorus_reverb_put,
943 .private_value = 0,
944};
945
946/*
947 * FM OPL3 chorus/reverb depth
948 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100949static int mixer_fm_depth_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950{
951 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
952 uinfo->count = 1;
953 uinfo->value.integer.min = 0;
954 uinfo->value.integer.max = 255;
955 return 0;
956}
957
Takashi Iwai029d64b2005-11-17 14:34:36 +0100958static int mixer_fm_depth_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100960 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->fm_chorus_depth : emu->fm_reverb_depth;
963 return 0;
964}
965
Takashi Iwai029d64b2005-11-17 14:34:36 +0100966static int mixer_fm_depth_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100968 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 unsigned long flags;
970 int change;
971 unsigned short val1;
972
973 val1 = ucontrol->value.integer.value[0] % 256;
974 spin_lock_irqsave(&emu->control_lock, flags);
975 if (kcontrol->private_value) {
976 change = val1 != emu->fm_chorus_depth;
977 emu->fm_chorus_depth = val1;
978 } else {
979 change = val1 != emu->fm_reverb_depth;
980 emu->fm_reverb_depth = val1;
981 }
982 spin_unlock_irqrestore(&emu->control_lock, flags);
983 if (change)
984 snd_emu8000_init_fm(emu);
985 return change;
986}
987
Takashi Iwai029d64b2005-11-17 14:34:36 +0100988static struct snd_kcontrol_new mixer_fm_chorus_depth_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
990 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
991 .name = "FM Chorus Depth",
992 .info = mixer_fm_depth_info,
993 .get = mixer_fm_depth_get,
994 .put = mixer_fm_depth_put,
995 .private_value = 1,
996};
997
Takashi Iwai029d64b2005-11-17 14:34:36 +0100998static struct snd_kcontrol_new mixer_fm_reverb_depth_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{
1000 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1001 .name = "FM Reverb Depth",
1002 .info = mixer_fm_depth_info,
1003 .get = mixer_fm_depth_get,
1004 .put = mixer_fm_depth_put,
1005 .private_value = 0,
1006};
1007
1008
Takashi Iwai029d64b2005-11-17 14:34:36 +01001009static struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 &mixer_bass_control,
1011 &mixer_treble_control,
1012 &mixer_chorus_mode_control,
1013 &mixer_reverb_mode_control,
1014 &mixer_fm_chorus_depth_control,
1015 &mixer_fm_reverb_depth_control,
1016};
1017
1018/*
1019 * create and attach mixer elements for WaveTable treble/bass controls
1020 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +02001021static int __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +01001022snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023{
1024 int i, err = 0;
1025
1026 snd_assert(emu != NULL && card != NULL, return -EINVAL);
1027
1028 spin_lock_init(&emu->control_lock);
1029
1030 memset(emu->controls, 0, sizeof(emu->controls));
1031 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1032 if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0)
1033 goto __error;
1034 }
1035 return 0;
1036
1037__error:
1038 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1039 down_write(&card->controls_rwsem);
1040 if (emu->controls[i])
1041 snd_ctl_remove(card, emu->controls[i]);
1042 up_write(&card->controls_rwsem);
1043 }
1044 return err;
1045}
1046
1047
1048/*
1049 * free resources
1050 */
Takashi Iwai029d64b2005-11-17 14:34:36 +01001051static int snd_emu8000_free(struct snd_emu8000 *hw)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052{
Takashi Iwaib1d57762005-10-10 11:56:31 +02001053 release_and_free_resource(hw->res_port1);
1054 release_and_free_resource(hw->res_port2);
1055 release_and_free_resource(hw->res_port3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 kfree(hw);
1057 return 0;
1058}
1059
1060/*
1061 */
Takashi Iwai029d64b2005-11-17 14:34:36 +01001062static int snd_emu8000_dev_free(struct snd_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063{
Takashi Iwai029d64b2005-11-17 14:34:36 +01001064 struct snd_emu8000 *hw = device->device_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 return snd_emu8000_free(hw);
1066}
1067
1068/*
1069 * initialize and register emu8000 synth device.
1070 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +02001071int __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +01001072snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
1073 struct snd_seq_device **awe_ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074{
Takashi Iwai029d64b2005-11-17 14:34:36 +01001075 struct snd_seq_device *awe;
1076 struct snd_emu8000 *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 int err;
Takashi Iwai029d64b2005-11-17 14:34:36 +01001078 static struct snd_device_ops ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 .dev_free = snd_emu8000_dev_free,
1080 };
1081
1082 if (awe_ret)
1083 *awe_ret = NULL;
1084
1085 if (seq_ports <= 0)
1086 return 0;
1087
Takashi Iwai9e76a762005-09-09 14:21:17 +02001088 hw = kzalloc(sizeof(*hw), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 if (hw == NULL)
1090 return -ENOMEM;
1091 spin_lock_init(&hw->reg_lock);
1092 hw->index = index;
1093 hw->port1 = port;
1094 hw->port2 = port + 0x400;
1095 hw->port3 = port + 0x800;
1096 if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) ||
1097 !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) ||
1098 !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) {
1099 snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3);
1100 snd_emu8000_free(hw);
1101 return -EBUSY;
1102 }
1103 hw->mem_size = 0;
1104 hw->card = card;
1105 hw->seq_ports = seq_ports;
1106 hw->bass_level = 5;
1107 hw->treble_level = 9;
1108 hw->chorus_mode = 2;
1109 hw->reverb_mode = 4;
1110 hw->fm_chorus_depth = 0;
1111 hw->fm_reverb_depth = 0;
1112
1113 if (snd_emu8000_detect(hw) < 0) {
1114 snd_emu8000_free(hw);
1115 return -ENODEV;
1116 }
1117
1118 snd_emu8000_init_hw(hw);
1119 if ((err = snd_emu8000_create_mixer(card, hw)) < 0) {
1120 snd_emu8000_free(hw);
1121 return err;
1122 }
1123
1124 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, hw, &ops)) < 0) {
1125 snd_emu8000_free(hw);
1126 return err;
1127 }
1128#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1129 if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
Takashi Iwai029d64b2005-11-17 14:34:36 +01001130 sizeof(struct snd_emu8000*), &awe) >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 strcpy(awe->name, "EMU-8000");
Takashi Iwai029d64b2005-11-17 14:34:36 +01001132 *(struct snd_emu8000 **)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 }
1134#else
1135 awe = NULL;
1136#endif
1137 if (awe_ret)
1138 *awe_ret = awe;
1139
1140 return 0;
1141}
1142
1143
1144/*
1145 * exported stuff
1146 */
1147
1148EXPORT_SYMBOL(snd_emu8000_poke);
1149EXPORT_SYMBOL(snd_emu8000_peek);
1150EXPORT_SYMBOL(snd_emu8000_poke_dw);
1151EXPORT_SYMBOL(snd_emu8000_peek_dw);
1152EXPORT_SYMBOL(snd_emu8000_dma_chan);
1153EXPORT_SYMBOL(snd_emu8000_init_fm);
1154EXPORT_SYMBOL(snd_emu8000_load_chorus_fx);
1155EXPORT_SYMBOL(snd_emu8000_load_reverb_fx);
1156EXPORT_SYMBOL(snd_emu8000_update_chorus_mode);
1157EXPORT_SYMBOL(snd_emu8000_update_reverb_mode);
1158EXPORT_SYMBOL(snd_emu8000_update_equalizer);