blob: 658179e86142582a58620d0f5fe4db0ea90605e2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk>
4 * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
5 *
6 * Routines for control of EMU8000 chip
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <sound/driver.h>
24#include <linux/wait.h>
25#include <linux/sched.h>
26#include <linux/slab.h>
27#include <linux/ioport.h>
28#include <linux/delay.h>
29#include <sound/core.h>
30#include <sound/emu8000.h>
31#include <sound/emu8000_reg.h>
32#include <asm/io.h>
33#include <asm/uaccess.h>
34#include <linux/init.h>
35#include <sound/control.h>
36#include <sound/initval.h>
37
38/*
39 * emu8000 register controls
40 */
41
42/*
43 * The following routines read and write registers on the emu8000. They
44 * should always be called via the EMU8000*READ/WRITE macros and never
45 * directly. The macros handle the port number and command word.
46 */
47/* Write a word */
Takashi Iwai029d64b2005-11-17 14:34:36 +010048void snd_emu8000_poke(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
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 */
Takashi Iwai029d64b2005-11-17 14:34:36 +010061unsigned short snd_emu8000_peek(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062{
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 */
Takashi Iwai029d64b2005-11-17 14:34:36 +010076void snd_emu8000_poke_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077{
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 */
Takashi Iwai029d64b2005-11-17 14:34:36 +010090unsigned int snd_emu8000_peek_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070091{
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
Takashi Iwai029d64b2005-11-17 14:34:36 +0100110snd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
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 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200134static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100135snd_emu8000_read_wait(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
137 while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
Nishanth Aravamudan8433a502005-10-24 15:02:37 +0200138 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 if (signal_pending(current))
140 break;
141 }
142}
143
144/*
145 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200146static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100147snd_emu8000_write_wait(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148{
149 while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
Nishanth Aravamudan8433a502005-10-24 15:02:37 +0200150 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 if (signal_pending(current))
152 break;
153 }
154}
155
156/*
157 * detect a card at the given port
158 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200159static int __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100160snd_emu8000_detect(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161{
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 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200185static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100186init_audio(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
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 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200226static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100227init_dma(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
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 */
238static unsigned short init1[128] /*__devinitdata*/ = {
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
260static unsigned short init2[128] /*__devinitdata*/ = {
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
282static unsigned short init3[128] /*__devinitdata*/ = {
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
304static unsigned short init4[128] /*__devinitdata*/ = {
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 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200330static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100331send_array(struct snd_emu8000 *emu, unsigned short *data, int size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
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 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200352static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100353init_arrays(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
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 arbitary 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 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200378static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100379size_dram(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
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
395 while (size < EMU8000_MAX_DRAM) {
396
397 size += 512 * 1024; /* increment 512kbytes */
398
399 /* Write a unique data on the test address.
400 * if the address is out of range, the data is written on
401 * 0x200000(=EMU8000_DRAM_OFFSET). Then the id word is
402 * changed by this data.
403 */
404 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);*/
405 EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
406 EMU8000_SMLD_WRITE(emu, UNIQUE_ID2);
407 snd_emu8000_write_wait(emu);
408
409 /*
410 * read the data on the just written DRAM address
411 * if not the same then we have reached the end of ram.
412 */
413 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_READ);*/
414 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
415 /*snd_emu8000_read_wait(emu);*/
416 EMU8000_SMLD_READ(emu); /* discard stale data */
417 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
418 break; /* we must have wrapped around */
419
420 snd_emu8000_read_wait(emu);
421
422 /*
423 * If it is the same it could be that the address just
424 * wraps back to the beginning; so check to see if the
425 * initial value has been overwritten.
426 */
427 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
428 EMU8000_SMLD_READ(emu); /* discard stale data */
429 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
430 break; /* we must have wrapped around */
431 snd_emu8000_read_wait(emu);
432 }
433
434 /* wait until FULL bit in SMAxW register is false */
435 for (i = 0; i < 10000; i++) {
436 if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
437 break;
Nishanth Aravamudan8433a502005-10-24 15:02:37 +0200438 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 if (signal_pending(current))
440 break;
441 }
442 snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
443 snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
444
445 snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n",
446 emu->port1, size/1024);
447
448 emu->mem_size = size;
449 emu->dram_checked = 1;
450}
451
452
453/*
454 * Initiailise the FM section. You have to do this to use sample RAM
455 * and therefore lose 2 voices.
456 */
457/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100458snd_emu8000_init_fm(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
460 unsigned long flags;
461
462 /* Initialize the last two channels for DRAM refresh and producing
463 the reverb and chorus effects for Yamaha OPL-3 synthesizer */
464
465 /* 31: FM left channel, 0xffffe0-0xffffe8 */
466 EMU8000_DCYSUSV_WRITE(emu, 30, 0x80);
467 EMU8000_PSST_WRITE(emu, 30, 0xFFFFFFE0); /* full left */
468 EMU8000_CSL_WRITE(emu, 30, 0x00FFFFE8 | (emu->fm_chorus_depth << 24));
469 EMU8000_PTRX_WRITE(emu, 30, (emu->fm_reverb_depth << 8));
470 EMU8000_CPF_WRITE(emu, 30, 0);
471 EMU8000_CCCA_WRITE(emu, 30, 0x00FFFFE3);
472
473 /* 32: FM right channel, 0xfffff0-0xfffff8 */
474 EMU8000_DCYSUSV_WRITE(emu, 31, 0x80);
475 EMU8000_PSST_WRITE(emu, 31, 0x00FFFFF0); /* full right */
476 EMU8000_CSL_WRITE(emu, 31, 0x00FFFFF8 | (emu->fm_chorus_depth << 24));
477 EMU8000_PTRX_WRITE(emu, 31, (emu->fm_reverb_depth << 8));
478 EMU8000_CPF_WRITE(emu, 31, 0x8000);
479 EMU8000_CCCA_WRITE(emu, 31, 0x00FFFFF3);
480
481 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0);
482
483 spin_lock_irqsave(&emu->reg_lock, flags);
484 while (!(inw(EMU8000_PTR(emu)) & 0x1000))
485 ;
486 while ((inw(EMU8000_PTR(emu)) & 0x1000))
487 ;
488 spin_unlock_irqrestore(&emu->reg_lock, flags);
489 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828);
490 /* this is really odd part.. */
491 outb(0x3C, EMU8000_PTR(emu));
492 outb(0, EMU8000_DATA1(emu));
493
494 /* skew volume & cutoff */
495 EMU8000_VTFT_WRITE(emu, 30, 0x8000FFFF);
496 EMU8000_VTFT_WRITE(emu, 31, 0x8000FFFF);
497}
498
499
500/*
501 * The main initialization routine.
502 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +0200503static void __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +0100504snd_emu8000_init_hw(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
506 int i;
507
508 emu->last_reg = 0xffff; /* reset the last register index */
509
510 /* initialize hardware configuration */
511 EMU8000_HWCF1_WRITE(emu, 0x0059);
512 EMU8000_HWCF2_WRITE(emu, 0x0020);
513
514 /* disable audio; this seems to reduce a clicking noise a bit.. */
515 EMU8000_HWCF3_WRITE(emu, 0);
516
517 /* initialize audio channels */
518 init_audio(emu);
519
520 /* initialize DMA */
521 init_dma(emu);
522
523 /* initialize init arrays */
524 init_arrays(emu);
525
526 /*
527 * Initialize the FM section of the AWE32, this is needed
528 * for DRAM refresh as well
529 */
530 snd_emu8000_init_fm(emu);
531
532 /* terminate all voices */
533 for (i = 0; i < EMU8000_DRAM_VOICES; i++)
534 EMU8000_DCYSUSV_WRITE(emu, 0, 0x807F);
535
536 /* check DRAM memory size */
537 size_dram(emu);
538
539 /* enable audio */
540 EMU8000_HWCF3_WRITE(emu, 0x4);
541
542 /* set equzlier, chorus and reverb modes */
543 snd_emu8000_update_equalizer(emu);
544 snd_emu8000_update_chorus_mode(emu);
545 snd_emu8000_update_reverb_mode(emu);
546}
547
548
549/*----------------------------------------------------------------
550 * Bass/Treble Equalizer
551 *----------------------------------------------------------------*/
552
553static unsigned short bass_parm[12][3] = {
554 {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
555 {0xD25B, 0xD35B, 0x0000}, /* -8 */
556 {0xD24C, 0xD34C, 0x0000}, /* -6 */
557 {0xD23D, 0xD33D, 0x0000}, /* -4 */
558 {0xD21F, 0xD31F, 0x0000}, /* -2 */
559 {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */
560 {0xC219, 0xC319, 0x0001}, /* +2 */
561 {0xC22A, 0xC32A, 0x0001}, /* +4 */
562 {0xC24C, 0xC34C, 0x0001}, /* +6 */
563 {0xC26E, 0xC36E, 0x0001}, /* +8 */
564 {0xC248, 0xC384, 0x0002}, /* +10 */
565 {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
566};
567
568static unsigned short treble_parm[12][9] = {
569 {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
570 {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
571 {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
572 {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
573 {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
574 {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
575 {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
576 {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
577 {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
578 {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
579 {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
580 {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002} /* +12 dB */
581};
582
583
584/*
585 * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
586 */
587/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100588snd_emu8000_update_equalizer(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
590 unsigned short w;
591 int bass = emu->bass_level;
592 int treble = emu->treble_level;
593
594 if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
595 return;
596 EMU8000_INIT4_WRITE(emu, 0x01, bass_parm[bass][0]);
597 EMU8000_INIT4_WRITE(emu, 0x11, bass_parm[bass][1]);
598 EMU8000_INIT3_WRITE(emu, 0x11, treble_parm[treble][0]);
599 EMU8000_INIT3_WRITE(emu, 0x13, treble_parm[treble][1]);
600 EMU8000_INIT3_WRITE(emu, 0x1b, treble_parm[treble][2]);
601 EMU8000_INIT4_WRITE(emu, 0x07, treble_parm[treble][3]);
602 EMU8000_INIT4_WRITE(emu, 0x0b, treble_parm[treble][4]);
603 EMU8000_INIT4_WRITE(emu, 0x0d, treble_parm[treble][5]);
604 EMU8000_INIT4_WRITE(emu, 0x17, treble_parm[treble][6]);
605 EMU8000_INIT4_WRITE(emu, 0x19, treble_parm[treble][7]);
606 w = bass_parm[bass][2] + treble_parm[treble][8];
607 EMU8000_INIT4_WRITE(emu, 0x15, (unsigned short)(w + 0x0262));
608 EMU8000_INIT4_WRITE(emu, 0x1d, (unsigned short)(w + 0x8362));
609}
610
611
612/*----------------------------------------------------------------
613 * Chorus mode control
614 *----------------------------------------------------------------*/
615
616/*
617 * chorus mode parameters
618 */
619#define SNDRV_EMU8000_CHORUS_1 0
620#define SNDRV_EMU8000_CHORUS_2 1
621#define SNDRV_EMU8000_CHORUS_3 2
622#define SNDRV_EMU8000_CHORUS_4 3
623#define SNDRV_EMU8000_CHORUS_FEEDBACK 4
624#define SNDRV_EMU8000_CHORUS_FLANGER 5
625#define SNDRV_EMU8000_CHORUS_SHORTDELAY 6
626#define SNDRV_EMU8000_CHORUS_SHORTDELAY2 7
627#define SNDRV_EMU8000_CHORUS_PREDEFINED 8
628/* user can define chorus modes up to 32 */
629#define SNDRV_EMU8000_CHORUS_NUMBERS 32
630
Takashi Iwai029d64b2005-11-17 14:34:36 +0100631struct soundfont_chorus_fx {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 unsigned short feedback; /* feedback level (0xE600-0xE6FF) */
633 unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */
634 unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */
635 unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
636 unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100637};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
640static char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100641static struct soundfont_chorus_fx chorus_parm[SNDRV_EMU8000_CHORUS_NUMBERS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
643 {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
644 {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
645 {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
646 {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
647 {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
648 {0xE600, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay */
649 {0xE6C0, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay + feedback */
650};
651
652/*exported*/ int
Takashi Iwai029d64b2005-11-17 14:34:36 +0100653snd_emu8000_load_chorus_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100655 struct soundfont_chorus_fx rec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) {
657 snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode);
658 return -EINVAL;
659 }
660 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
661 return -EFAULT;
662 chorus_parm[mode] = rec;
663 chorus_defined[mode] = 1;
664 return 0;
665}
666
667/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100668snd_emu8000_update_chorus_mode(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669{
670 int effect = emu->chorus_mode;
671 if (effect < 0 || effect >= SNDRV_EMU8000_CHORUS_NUMBERS ||
672 (effect >= SNDRV_EMU8000_CHORUS_PREDEFINED && !chorus_defined[effect]))
673 return;
674 EMU8000_INIT3_WRITE(emu, 0x09, chorus_parm[effect].feedback);
675 EMU8000_INIT3_WRITE(emu, 0x0c, chorus_parm[effect].delay_offset);
676 EMU8000_INIT4_WRITE(emu, 0x03, chorus_parm[effect].lfo_depth);
677 EMU8000_HWCF4_WRITE(emu, chorus_parm[effect].delay);
678 EMU8000_HWCF5_WRITE(emu, chorus_parm[effect].lfo_freq);
679 EMU8000_HWCF6_WRITE(emu, 0x8000);
680 EMU8000_HWCF7_WRITE(emu, 0x0000);
681}
682
683/*----------------------------------------------------------------
684 * Reverb mode control
685 *----------------------------------------------------------------*/
686
687/*
688 * reverb mode parameters
689 */
690#define SNDRV_EMU8000_REVERB_ROOM1 0
691#define SNDRV_EMU8000_REVERB_ROOM2 1
692#define SNDRV_EMU8000_REVERB_ROOM3 2
693#define SNDRV_EMU8000_REVERB_HALL1 3
694#define SNDRV_EMU8000_REVERB_HALL2 4
695#define SNDRV_EMU8000_REVERB_PLATE 5
696#define SNDRV_EMU8000_REVERB_DELAY 6
697#define SNDRV_EMU8000_REVERB_PANNINGDELAY 7
698#define SNDRV_EMU8000_REVERB_PREDEFINED 8
699/* user can define reverb modes up to 32 */
700#define SNDRV_EMU8000_REVERB_NUMBERS 32
701
Takashi Iwai029d64b2005-11-17 14:34:36 +0100702struct soundfont_reverb_fx {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 unsigned short parms[28];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100704};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706/* reverb mode settings; write the following 28 data of 16 bit length
707 * on the corresponding ports in the reverb_cmds array
708 */
709static char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100710static struct soundfont_reverb_fx reverb_parm[SNDRV_EMU8000_REVERB_NUMBERS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{{ /* room 1 */
712 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
713 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
714 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
715 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
716}},
717{{ /* room 2 */
718 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
719 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
720 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
721 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
722}},
723{{ /* room 3 */
724 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
725 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
726 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
727 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
728}},
729{{ /* hall 1 */
730 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
731 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
732 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
733 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
734}},
735{{ /* hall 2 */
736 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
737 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
738 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
739 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
740}},
741{{ /* plate */
742 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
743 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
744 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
745 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
746}},
747{{ /* delay */
748 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
749 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
750 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
751 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
752}},
753{{ /* panning delay */
754 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
755 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
756 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
757 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
758}},
759};
760
761enum { DATA1, DATA2 };
762#define AWE_INIT1(c) EMU8000_CMD(2,c), DATA1
763#define AWE_INIT2(c) EMU8000_CMD(2,c), DATA2
764#define AWE_INIT3(c) EMU8000_CMD(3,c), DATA1
765#define AWE_INIT4(c) EMU8000_CMD(3,c), DATA2
766
767static struct reverb_cmd_pair {
768 unsigned short cmd, port;
769} reverb_cmds[28] = {
770 {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
771 {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
772 {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
773 {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
774 {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
775 {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
776 {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
777};
778
779/*exported*/ int
Takashi Iwai029d64b2005-11-17 14:34:36 +0100780snd_emu8000_load_reverb_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100782 struct soundfont_reverb_fx rec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 if (mode < SNDRV_EMU8000_REVERB_PREDEFINED || mode >= SNDRV_EMU8000_REVERB_NUMBERS) {
785 snd_printk(KERN_WARNING "invalid reverb mode %d for uploading\n", mode);
786 return -EINVAL;
787 }
788 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
789 return -EFAULT;
790 reverb_parm[mode] = rec;
791 reverb_defined[mode] = 1;
792 return 0;
793}
794
795/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100796snd_emu8000_update_reverb_mode(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797{
798 int effect = emu->reverb_mode;
799 int i;
800
801 if (effect < 0 || effect >= SNDRV_EMU8000_REVERB_NUMBERS ||
802 (effect >= SNDRV_EMU8000_REVERB_PREDEFINED && !reverb_defined[effect]))
803 return;
804 for (i = 0; i < 28; i++) {
805 int port;
806 if (reverb_cmds[i].port == DATA1)
807 port = EMU8000_DATA1(emu);
808 else
809 port = EMU8000_DATA2(emu);
810 snd_emu8000_poke(emu, port, reverb_cmds[i].cmd, reverb_parm[effect].parms[i]);
811 }
812}
813
814
815/*----------------------------------------------------------------
816 * mixer interface
817 *----------------------------------------------------------------*/
818
819/*
820 * bass/treble
821 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100822static int mixer_bass_treble_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
824 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
825 uinfo->count = 1;
826 uinfo->value.integer.min = 0;
827 uinfo->value.integer.max = 11;
828 return 0;
829}
830
Takashi Iwai029d64b2005-11-17 14:34:36 +0100831static int mixer_bass_treble_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100833 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->treble_level : emu->bass_level;
836 return 0;
837}
838
Takashi Iwai029d64b2005-11-17 14:34:36 +0100839static int mixer_bass_treble_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100841 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 unsigned long flags;
843 int change;
844 unsigned short val1;
845
846 val1 = ucontrol->value.integer.value[0] % 12;
847 spin_lock_irqsave(&emu->control_lock, flags);
848 if (kcontrol->private_value) {
849 change = val1 != emu->treble_level;
850 emu->treble_level = val1;
851 } else {
852 change = val1 != emu->bass_level;
853 emu->bass_level = val1;
854 }
855 spin_unlock_irqrestore(&emu->control_lock, flags);
856 snd_emu8000_update_equalizer(emu);
857 return change;
858}
859
Takashi Iwai029d64b2005-11-17 14:34:36 +0100860static struct snd_kcontrol_new mixer_bass_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
862 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
863 .name = "Synth Tone Control - Bass",
864 .info = mixer_bass_treble_info,
865 .get = mixer_bass_treble_get,
866 .put = mixer_bass_treble_put,
867 .private_value = 0,
868};
869
Takashi Iwai029d64b2005-11-17 14:34:36 +0100870static struct snd_kcontrol_new mixer_treble_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
872 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
873 .name = "Synth Tone Control - Treble",
874 .info = mixer_bass_treble_info,
875 .get = mixer_bass_treble_get,
876 .put = mixer_bass_treble_put,
877 .private_value = 1,
878};
879
880/*
881 * chorus/reverb mode
882 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100883static int mixer_chorus_reverb_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
886 uinfo->count = 1;
887 uinfo->value.integer.min = 0;
888 uinfo->value.integer.max = kcontrol->private_value ? (SNDRV_EMU8000_CHORUS_NUMBERS-1) : (SNDRV_EMU8000_REVERB_NUMBERS-1);
889 return 0;
890}
891
Takashi Iwai029d64b2005-11-17 14:34:36 +0100892static int mixer_chorus_reverb_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100894 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->chorus_mode : emu->reverb_mode;
897 return 0;
898}
899
Takashi Iwai029d64b2005-11-17 14:34:36 +0100900static int mixer_chorus_reverb_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100902 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 unsigned long flags;
904 int change;
905 unsigned short val1;
906
907 spin_lock_irqsave(&emu->control_lock, flags);
908 if (kcontrol->private_value) {
909 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
910 change = val1 != emu->chorus_mode;
911 emu->chorus_mode = val1;
912 } else {
913 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
914 change = val1 != emu->reverb_mode;
915 emu->reverb_mode = val1;
916 }
917 spin_unlock_irqrestore(&emu->control_lock, flags);
918 if (change) {
919 if (kcontrol->private_value)
920 snd_emu8000_update_chorus_mode(emu);
921 else
922 snd_emu8000_update_reverb_mode(emu);
923 }
924 return change;
925}
926
Takashi Iwai029d64b2005-11-17 14:34:36 +0100927static struct snd_kcontrol_new mixer_chorus_mode_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
929 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
930 .name = "Chorus Mode",
931 .info = mixer_chorus_reverb_info,
932 .get = mixer_chorus_reverb_get,
933 .put = mixer_chorus_reverb_put,
934 .private_value = 1,
935};
936
Takashi Iwai029d64b2005-11-17 14:34:36 +0100937static struct snd_kcontrol_new mixer_reverb_mode_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938{
939 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
940 .name = "Reverb Mode",
941 .info = mixer_chorus_reverb_info,
942 .get = mixer_chorus_reverb_get,
943 .put = mixer_chorus_reverb_put,
944 .private_value = 0,
945};
946
947/*
948 * FM OPL3 chorus/reverb depth
949 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100950static int mixer_fm_depth_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951{
952 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
953 uinfo->count = 1;
954 uinfo->value.integer.min = 0;
955 uinfo->value.integer.max = 255;
956 return 0;
957}
958
Takashi Iwai029d64b2005-11-17 14:34:36 +0100959static int mixer_fm_depth_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100961 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
963 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->fm_chorus_depth : emu->fm_reverb_depth;
964 return 0;
965}
966
Takashi Iwai029d64b2005-11-17 14:34:36 +0100967static int mixer_fm_depth_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100969 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 unsigned long flags;
971 int change;
972 unsigned short val1;
973
974 val1 = ucontrol->value.integer.value[0] % 256;
975 spin_lock_irqsave(&emu->control_lock, flags);
976 if (kcontrol->private_value) {
977 change = val1 != emu->fm_chorus_depth;
978 emu->fm_chorus_depth = val1;
979 } else {
980 change = val1 != emu->fm_reverb_depth;
981 emu->fm_reverb_depth = val1;
982 }
983 spin_unlock_irqrestore(&emu->control_lock, flags);
984 if (change)
985 snd_emu8000_init_fm(emu);
986 return change;
987}
988
Takashi Iwai029d64b2005-11-17 14:34:36 +0100989static struct snd_kcontrol_new mixer_fm_chorus_depth_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
991 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
992 .name = "FM Chorus Depth",
993 .info = mixer_fm_depth_info,
994 .get = mixer_fm_depth_get,
995 .put = mixer_fm_depth_put,
996 .private_value = 1,
997};
998
Takashi Iwai029d64b2005-11-17 14:34:36 +0100999static struct snd_kcontrol_new mixer_fm_reverb_depth_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
1001 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1002 .name = "FM Reverb Depth",
1003 .info = mixer_fm_depth_info,
1004 .get = mixer_fm_depth_get,
1005 .put = mixer_fm_depth_put,
1006 .private_value = 0,
1007};
1008
1009
Takashi Iwai029d64b2005-11-17 14:34:36 +01001010static struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 &mixer_bass_control,
1012 &mixer_treble_control,
1013 &mixer_chorus_mode_control,
1014 &mixer_reverb_mode_control,
1015 &mixer_fm_chorus_depth_control,
1016 &mixer_fm_reverb_depth_control,
1017};
1018
1019/*
1020 * create and attach mixer elements for WaveTable treble/bass controls
1021 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +02001022static int __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +01001023snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 int i, err = 0;
1026
1027 snd_assert(emu != NULL && card != NULL, return -EINVAL);
1028
1029 spin_lock_init(&emu->control_lock);
1030
1031 memset(emu->controls, 0, sizeof(emu->controls));
1032 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1033 if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0)
1034 goto __error;
1035 }
1036 return 0;
1037
1038__error:
1039 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1040 down_write(&card->controls_rwsem);
1041 if (emu->controls[i])
1042 snd_ctl_remove(card, emu->controls[i]);
1043 up_write(&card->controls_rwsem);
1044 }
1045 return err;
1046}
1047
1048
1049/*
1050 * free resources
1051 */
Takashi Iwai029d64b2005-11-17 14:34:36 +01001052static int snd_emu8000_free(struct snd_emu8000 *hw)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053{
Takashi Iwaib1d57762005-10-10 11:56:31 +02001054 release_and_free_resource(hw->res_port1);
1055 release_and_free_resource(hw->res_port2);
1056 release_and_free_resource(hw->res_port3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 kfree(hw);
1058 return 0;
1059}
1060
1061/*
1062 */
Takashi Iwai029d64b2005-11-17 14:34:36 +01001063static int snd_emu8000_dev_free(struct snd_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
Takashi Iwai029d64b2005-11-17 14:34:36 +01001065 struct snd_emu8000 *hw = device->device_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 return snd_emu8000_free(hw);
1067}
1068
1069/*
1070 * initialize and register emu8000 synth device.
1071 */
Takashi Iwai2e74eba2006-06-09 15:28:07 +02001072int __devinit
Takashi Iwai029d64b2005-11-17 14:34:36 +01001073snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
1074 struct snd_seq_device **awe_ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
Takashi Iwai029d64b2005-11-17 14:34:36 +01001076 struct snd_seq_device *awe;
1077 struct snd_emu8000 *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 int err;
Takashi Iwai029d64b2005-11-17 14:34:36 +01001079 static struct snd_device_ops ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 .dev_free = snd_emu8000_dev_free,
1081 };
1082
1083 if (awe_ret)
1084 *awe_ret = NULL;
1085
1086 if (seq_ports <= 0)
1087 return 0;
1088
Takashi Iwai9e76a762005-09-09 14:21:17 +02001089 hw = kzalloc(sizeof(*hw), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 if (hw == NULL)
1091 return -ENOMEM;
1092 spin_lock_init(&hw->reg_lock);
1093 hw->index = index;
1094 hw->port1 = port;
1095 hw->port2 = port + 0x400;
1096 hw->port3 = port + 0x800;
1097 if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) ||
1098 !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) ||
1099 !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) {
1100 snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3);
1101 snd_emu8000_free(hw);
1102 return -EBUSY;
1103 }
1104 hw->mem_size = 0;
1105 hw->card = card;
1106 hw->seq_ports = seq_ports;
1107 hw->bass_level = 5;
1108 hw->treble_level = 9;
1109 hw->chorus_mode = 2;
1110 hw->reverb_mode = 4;
1111 hw->fm_chorus_depth = 0;
1112 hw->fm_reverb_depth = 0;
1113
1114 if (snd_emu8000_detect(hw) < 0) {
1115 snd_emu8000_free(hw);
1116 return -ENODEV;
1117 }
1118
1119 snd_emu8000_init_hw(hw);
1120 if ((err = snd_emu8000_create_mixer(card, hw)) < 0) {
1121 snd_emu8000_free(hw);
1122 return err;
1123 }
1124
1125 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, hw, &ops)) < 0) {
1126 snd_emu8000_free(hw);
1127 return err;
1128 }
1129#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1130 if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
Takashi Iwai029d64b2005-11-17 14:34:36 +01001131 sizeof(struct snd_emu8000*), &awe) >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 strcpy(awe->name, "EMU-8000");
Takashi Iwai029d64b2005-11-17 14:34:36 +01001133 *(struct snd_emu8000 **)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 }
1135#else
1136 awe = NULL;
1137#endif
1138 if (awe_ret)
1139 *awe_ret = awe;
1140
1141 return 0;
1142}
1143
1144
1145/*
1146 * exported stuff
1147 */
1148
1149EXPORT_SYMBOL(snd_emu8000_poke);
1150EXPORT_SYMBOL(snd_emu8000_peek);
1151EXPORT_SYMBOL(snd_emu8000_poke_dw);
1152EXPORT_SYMBOL(snd_emu8000_peek_dw);
1153EXPORT_SYMBOL(snd_emu8000_dma_chan);
1154EXPORT_SYMBOL(snd_emu8000_init_fm);
1155EXPORT_SYMBOL(snd_emu8000_load_chorus_fx);
1156EXPORT_SYMBOL(snd_emu8000_load_reverb_fx);
1157EXPORT_SYMBOL(snd_emu8000_update_chorus_mode);
1158EXPORT_SYMBOL(snd_emu8000_update_reverb_mode);
1159EXPORT_SYMBOL(snd_emu8000_update_equalizer);