blob: 94c411299e5a0d75b91abeb598eb53dcdb002b19 [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>
Paul Gortmakerd81a6d72011-09-22 09:34:58 -040027#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/delay.h>
Takashi Iwai6cbbfe12015-01-28 16:49:33 +010029#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <sound/core.h>
31#include <sound/emu8000.h>
32#include <sound/emu8000_reg.h>
Takashi Iwai976412f2015-01-28 17:24:43 +010033#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#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 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500134static void
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 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500146static void
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 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500159static int
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 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500185static void
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 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500226static void
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 */
Takashi Iwai6a0f56a2012-12-07 07:41:56 +0100238static unsigned short init1[128] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 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
Takashi Iwai6a0f56a2012-12-07 07:41:56 +0100260static unsigned short init2[128] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 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
Takashi Iwai6a0f56a2012-12-07 07:41:56 +0100282static unsigned short init3[128] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 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
Takashi Iwai6a0f56a2012-12-07 07:41:56 +0100304static unsigned short init4[128] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 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 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500330static void
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 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500352static void
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.
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300374 * This is written so as not to need arbitrary delays after the write. It
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 * seems that the only way to do this is to use the one channel and keep
376 * reallocating between read and write.
377 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500378static void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100379size_dram(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
David Flater1730fd92015-01-11 16:08:58 -0500381 int i, size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
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 */
David Flater1730fd92015-01-11 16:08:58 -0500394 snd_emu8000_write_wait(emu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
David Flater1730fd92015-01-11 16:08:58 -0500396 /*
397 * Detect first 512 KiB. If a write succeeds at the beginning of a
398 * 512 KiB page we assume that the whole page is there.
399 */
400 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
401 EMU8000_SMLD_READ(emu); /* discard stale data */
402 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
403 goto skip_detect; /* No RAM */
404 snd_emu8000_read_wait(emu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
David Flater1730fd92015-01-11 16:08:58 -0500406 for (size = 512 * 1024; size < EMU8000_MAX_DRAM; size += 512 * 1024) {
Krzysztof Heltedf12b42010-01-04 22:23:34 +0100407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 /* Write a unique data on the test address.
409 * if the address is out of range, the data is written on
410 * 0x200000(=EMU8000_DRAM_OFFSET). Then the id word is
411 * changed by this data.
412 */
413 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);*/
414 EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
415 EMU8000_SMLD_WRITE(emu, UNIQUE_ID2);
416 snd_emu8000_write_wait(emu);
417
418 /*
419 * read the data on the just written DRAM address
420 * if not the same then we have reached the end of ram.
421 */
422 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_READ);*/
423 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
424 /*snd_emu8000_read_wait(emu);*/
425 EMU8000_SMLD_READ(emu); /* discard stale data */
426 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
Krzysztof Heltdb8cf332009-12-20 20:15:19 +0100427 break; /* no memory at this address */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 snd_emu8000_read_wait(emu);
429
430 /*
431 * If it is the same it could be that the address just
432 * wraps back to the beginning; so check to see if the
433 * initial value has been overwritten.
434 */
435 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
436 EMU8000_SMLD_READ(emu); /* discard stale data */
437 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
438 break; /* we must have wrapped around */
439 snd_emu8000_read_wait(emu);
David Flater1338fc92012-08-27 22:25:21 -0400440
441 /* Otherwise, it's valid memory. */
David Flater1338fc92012-08-27 22:25:21 -0400442 }
443
David Flater1730fd92015-01-11 16:08:58 -0500444skip_detect:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 /* wait until FULL bit in SMAxW register is false */
446 for (i = 0; i < 10000; i++) {
447 if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
448 break;
Nishanth Aravamudan8433a502005-10-24 15:02:37 +0200449 schedule_timeout_interruptible(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (signal_pending(current))
451 break;
452 }
453 snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
454 snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
455
David Flaterd2866402015-01-11 16:10:07 -0500456 pr_info("EMU8000 [0x%lx]: %d KiB on-board DRAM detected\n",
David Flater1730fd92015-01-11 16:08:58 -0500457 emu->port1, size/1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
David Flater1730fd92015-01-11 16:08:58 -0500459 emu->mem_size = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 emu->dram_checked = 1;
461}
462
463
464/*
465 * Initiailise the FM section. You have to do this to use sample RAM
466 * and therefore lose 2 voices.
467 */
468/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100469snd_emu8000_init_fm(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
471 unsigned long flags;
472
473 /* Initialize the last two channels for DRAM refresh and producing
474 the reverb and chorus effects for Yamaha OPL-3 synthesizer */
475
476 /* 31: FM left channel, 0xffffe0-0xffffe8 */
477 EMU8000_DCYSUSV_WRITE(emu, 30, 0x80);
478 EMU8000_PSST_WRITE(emu, 30, 0xFFFFFFE0); /* full left */
479 EMU8000_CSL_WRITE(emu, 30, 0x00FFFFE8 | (emu->fm_chorus_depth << 24));
480 EMU8000_PTRX_WRITE(emu, 30, (emu->fm_reverb_depth << 8));
481 EMU8000_CPF_WRITE(emu, 30, 0);
482 EMU8000_CCCA_WRITE(emu, 30, 0x00FFFFE3);
483
484 /* 32: FM right channel, 0xfffff0-0xfffff8 */
485 EMU8000_DCYSUSV_WRITE(emu, 31, 0x80);
486 EMU8000_PSST_WRITE(emu, 31, 0x00FFFFF0); /* full right */
487 EMU8000_CSL_WRITE(emu, 31, 0x00FFFFF8 | (emu->fm_chorus_depth << 24));
488 EMU8000_PTRX_WRITE(emu, 31, (emu->fm_reverb_depth << 8));
489 EMU8000_CPF_WRITE(emu, 31, 0x8000);
490 EMU8000_CCCA_WRITE(emu, 31, 0x00FFFFF3);
491
492 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0);
493
494 spin_lock_irqsave(&emu->reg_lock, flags);
495 while (!(inw(EMU8000_PTR(emu)) & 0x1000))
496 ;
497 while ((inw(EMU8000_PTR(emu)) & 0x1000))
498 ;
499 spin_unlock_irqrestore(&emu->reg_lock, flags);
500 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828);
501 /* this is really odd part.. */
502 outb(0x3C, EMU8000_PTR(emu));
503 outb(0, EMU8000_DATA1(emu));
504
505 /* skew volume & cutoff */
506 EMU8000_VTFT_WRITE(emu, 30, 0x8000FFFF);
507 EMU8000_VTFT_WRITE(emu, 31, 0x8000FFFF);
508}
509
510
511/*
512 * The main initialization routine.
513 */
Bill Pemberton1bff2922012-12-06 12:35:21 -0500514static void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100515snd_emu8000_init_hw(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
517 int i;
518
519 emu->last_reg = 0xffff; /* reset the last register index */
520
521 /* initialize hardware configuration */
522 EMU8000_HWCF1_WRITE(emu, 0x0059);
523 EMU8000_HWCF2_WRITE(emu, 0x0020);
524
525 /* disable audio; this seems to reduce a clicking noise a bit.. */
526 EMU8000_HWCF3_WRITE(emu, 0);
527
528 /* initialize audio channels */
529 init_audio(emu);
530
531 /* initialize DMA */
532 init_dma(emu);
533
534 /* initialize init arrays */
535 init_arrays(emu);
536
537 /*
538 * Initialize the FM section of the AWE32, this is needed
539 * for DRAM refresh as well
540 */
541 snd_emu8000_init_fm(emu);
542
543 /* terminate all voices */
544 for (i = 0; i < EMU8000_DRAM_VOICES; i++)
545 EMU8000_DCYSUSV_WRITE(emu, 0, 0x807F);
546
547 /* check DRAM memory size */
548 size_dram(emu);
549
550 /* enable audio */
551 EMU8000_HWCF3_WRITE(emu, 0x4);
552
553 /* set equzlier, chorus and reverb modes */
554 snd_emu8000_update_equalizer(emu);
555 snd_emu8000_update_chorus_mode(emu);
556 snd_emu8000_update_reverb_mode(emu);
557}
558
559
560/*----------------------------------------------------------------
561 * Bass/Treble Equalizer
562 *----------------------------------------------------------------*/
563
564static unsigned short bass_parm[12][3] = {
565 {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
566 {0xD25B, 0xD35B, 0x0000}, /* -8 */
567 {0xD24C, 0xD34C, 0x0000}, /* -6 */
568 {0xD23D, 0xD33D, 0x0000}, /* -4 */
569 {0xD21F, 0xD31F, 0x0000}, /* -2 */
570 {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */
571 {0xC219, 0xC319, 0x0001}, /* +2 */
572 {0xC22A, 0xC32A, 0x0001}, /* +4 */
573 {0xC24C, 0xC34C, 0x0001}, /* +6 */
574 {0xC26E, 0xC36E, 0x0001}, /* +8 */
575 {0xC248, 0xC384, 0x0002}, /* +10 */
576 {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
577};
578
579static unsigned short treble_parm[12][9] = {
580 {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
581 {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
582 {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
583 {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
584 {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
585 {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
586 {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
587 {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
588 {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
589 {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
590 {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
591 {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002} /* +12 dB */
592};
593
594
595/*
596 * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
597 */
598/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100599snd_emu8000_update_equalizer(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600{
601 unsigned short w;
602 int bass = emu->bass_level;
603 int treble = emu->treble_level;
604
605 if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
606 return;
607 EMU8000_INIT4_WRITE(emu, 0x01, bass_parm[bass][0]);
608 EMU8000_INIT4_WRITE(emu, 0x11, bass_parm[bass][1]);
609 EMU8000_INIT3_WRITE(emu, 0x11, treble_parm[treble][0]);
610 EMU8000_INIT3_WRITE(emu, 0x13, treble_parm[treble][1]);
611 EMU8000_INIT3_WRITE(emu, 0x1b, treble_parm[treble][2]);
612 EMU8000_INIT4_WRITE(emu, 0x07, treble_parm[treble][3]);
613 EMU8000_INIT4_WRITE(emu, 0x0b, treble_parm[treble][4]);
614 EMU8000_INIT4_WRITE(emu, 0x0d, treble_parm[treble][5]);
615 EMU8000_INIT4_WRITE(emu, 0x17, treble_parm[treble][6]);
616 EMU8000_INIT4_WRITE(emu, 0x19, treble_parm[treble][7]);
617 w = bass_parm[bass][2] + treble_parm[treble][8];
618 EMU8000_INIT4_WRITE(emu, 0x15, (unsigned short)(w + 0x0262));
619 EMU8000_INIT4_WRITE(emu, 0x1d, (unsigned short)(w + 0x8362));
620}
621
622
623/*----------------------------------------------------------------
624 * Chorus mode control
625 *----------------------------------------------------------------*/
626
627/*
628 * chorus mode parameters
629 */
630#define SNDRV_EMU8000_CHORUS_1 0
631#define SNDRV_EMU8000_CHORUS_2 1
632#define SNDRV_EMU8000_CHORUS_3 2
633#define SNDRV_EMU8000_CHORUS_4 3
634#define SNDRV_EMU8000_CHORUS_FEEDBACK 4
635#define SNDRV_EMU8000_CHORUS_FLANGER 5
636#define SNDRV_EMU8000_CHORUS_SHORTDELAY 6
637#define SNDRV_EMU8000_CHORUS_SHORTDELAY2 7
638#define SNDRV_EMU8000_CHORUS_PREDEFINED 8
639/* user can define chorus modes up to 32 */
640#define SNDRV_EMU8000_CHORUS_NUMBERS 32
641
Takashi Iwai029d64b2005-11-17 14:34:36 +0100642struct soundfont_chorus_fx {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 unsigned short feedback; /* feedback level (0xE600-0xE6FF) */
644 unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */
645 unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */
646 unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
647 unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100648};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
651static char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100652static struct soundfont_chorus_fx chorus_parm[SNDRV_EMU8000_CHORUS_NUMBERS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
654 {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
655 {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
656 {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
657 {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
658 {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
659 {0xE600, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay */
660 {0xE6C0, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay + feedback */
661};
662
663/*exported*/ int
Takashi Iwai029d64b2005-11-17 14:34:36 +0100664snd_emu8000_load_chorus_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100666 struct soundfont_chorus_fx rec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) {
668 snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode);
669 return -EINVAL;
670 }
671 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
672 return -EFAULT;
673 chorus_parm[mode] = rec;
674 chorus_defined[mode] = 1;
675 return 0;
676}
677
678/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100679snd_emu8000_update_chorus_mode(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 int effect = emu->chorus_mode;
682 if (effect < 0 || effect >= SNDRV_EMU8000_CHORUS_NUMBERS ||
683 (effect >= SNDRV_EMU8000_CHORUS_PREDEFINED && !chorus_defined[effect]))
684 return;
685 EMU8000_INIT3_WRITE(emu, 0x09, chorus_parm[effect].feedback);
686 EMU8000_INIT3_WRITE(emu, 0x0c, chorus_parm[effect].delay_offset);
687 EMU8000_INIT4_WRITE(emu, 0x03, chorus_parm[effect].lfo_depth);
688 EMU8000_HWCF4_WRITE(emu, chorus_parm[effect].delay);
689 EMU8000_HWCF5_WRITE(emu, chorus_parm[effect].lfo_freq);
690 EMU8000_HWCF6_WRITE(emu, 0x8000);
691 EMU8000_HWCF7_WRITE(emu, 0x0000);
692}
693
694/*----------------------------------------------------------------
695 * Reverb mode control
696 *----------------------------------------------------------------*/
697
698/*
699 * reverb mode parameters
700 */
701#define SNDRV_EMU8000_REVERB_ROOM1 0
702#define SNDRV_EMU8000_REVERB_ROOM2 1
703#define SNDRV_EMU8000_REVERB_ROOM3 2
704#define SNDRV_EMU8000_REVERB_HALL1 3
705#define SNDRV_EMU8000_REVERB_HALL2 4
706#define SNDRV_EMU8000_REVERB_PLATE 5
707#define SNDRV_EMU8000_REVERB_DELAY 6
708#define SNDRV_EMU8000_REVERB_PANNINGDELAY 7
709#define SNDRV_EMU8000_REVERB_PREDEFINED 8
710/* user can define reverb modes up to 32 */
711#define SNDRV_EMU8000_REVERB_NUMBERS 32
712
Takashi Iwai029d64b2005-11-17 14:34:36 +0100713struct soundfont_reverb_fx {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 unsigned short parms[28];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100715};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717/* reverb mode settings; write the following 28 data of 16 bit length
718 * on the corresponding ports in the reverb_cmds array
719 */
720static char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
Takashi Iwai029d64b2005-11-17 14:34:36 +0100721static struct soundfont_reverb_fx reverb_parm[SNDRV_EMU8000_REVERB_NUMBERS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{{ /* room 1 */
723 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
724 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
725 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
726 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
727}},
728{{ /* room 2 */
729 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
730 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
731 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
732 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
733}},
734{{ /* room 3 */
735 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
736 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
737 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
738 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
739}},
740{{ /* hall 1 */
741 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
742 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
743 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
744 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
745}},
746{{ /* hall 2 */
747 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
748 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
749 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
750 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
751}},
752{{ /* plate */
753 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
754 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
755 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
756 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
757}},
758{{ /* delay */
759 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
760 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
761 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
762 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
763}},
764{{ /* panning delay */
765 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
766 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
767 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
768 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
769}},
770};
771
772enum { DATA1, DATA2 };
773#define AWE_INIT1(c) EMU8000_CMD(2,c), DATA1
774#define AWE_INIT2(c) EMU8000_CMD(2,c), DATA2
775#define AWE_INIT3(c) EMU8000_CMD(3,c), DATA1
776#define AWE_INIT4(c) EMU8000_CMD(3,c), DATA2
777
778static struct reverb_cmd_pair {
779 unsigned short cmd, port;
780} reverb_cmds[28] = {
781 {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
782 {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
783 {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
784 {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
785 {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
786 {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
787 {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
788};
789
790/*exported*/ int
Takashi Iwai029d64b2005-11-17 14:34:36 +0100791snd_emu8000_load_reverb_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100793 struct soundfont_reverb_fx rec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 if (mode < SNDRV_EMU8000_REVERB_PREDEFINED || mode >= SNDRV_EMU8000_REVERB_NUMBERS) {
796 snd_printk(KERN_WARNING "invalid reverb mode %d for uploading\n", mode);
797 return -EINVAL;
798 }
799 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
800 return -EFAULT;
801 reverb_parm[mode] = rec;
802 reverb_defined[mode] = 1;
803 return 0;
804}
805
806/*exported*/ void
Takashi Iwai029d64b2005-11-17 14:34:36 +0100807snd_emu8000_update_reverb_mode(struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
809 int effect = emu->reverb_mode;
810 int i;
811
812 if (effect < 0 || effect >= SNDRV_EMU8000_REVERB_NUMBERS ||
813 (effect >= SNDRV_EMU8000_REVERB_PREDEFINED && !reverb_defined[effect]))
814 return;
815 for (i = 0; i < 28; i++) {
816 int port;
817 if (reverb_cmds[i].port == DATA1)
818 port = EMU8000_DATA1(emu);
819 else
820 port = EMU8000_DATA2(emu);
821 snd_emu8000_poke(emu, port, reverb_cmds[i].cmd, reverb_parm[effect].parms[i]);
822 }
823}
824
825
826/*----------------------------------------------------------------
827 * mixer interface
828 *----------------------------------------------------------------*/
829
830/*
831 * bass/treble
832 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100833static int mixer_bass_treble_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
836 uinfo->count = 1;
837 uinfo->value.integer.min = 0;
838 uinfo->value.integer.max = 11;
839 return 0;
840}
841
Takashi Iwai029d64b2005-11-17 14:34:36 +0100842static int mixer_bass_treble_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100844 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->treble_level : emu->bass_level;
847 return 0;
848}
849
Takashi Iwai029d64b2005-11-17 14:34:36 +0100850static int mixer_bass_treble_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100852 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 unsigned long flags;
854 int change;
855 unsigned short val1;
856
857 val1 = ucontrol->value.integer.value[0] % 12;
858 spin_lock_irqsave(&emu->control_lock, flags);
859 if (kcontrol->private_value) {
860 change = val1 != emu->treble_level;
861 emu->treble_level = val1;
862 } else {
863 change = val1 != emu->bass_level;
864 emu->bass_level = val1;
865 }
866 spin_unlock_irqrestore(&emu->control_lock, flags);
867 snd_emu8000_update_equalizer(emu);
868 return change;
869}
870
Takashi Iwai029d64b2005-11-17 14:34:36 +0100871static struct snd_kcontrol_new mixer_bass_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
873 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
874 .name = "Synth Tone Control - Bass",
875 .info = mixer_bass_treble_info,
876 .get = mixer_bass_treble_get,
877 .put = mixer_bass_treble_put,
878 .private_value = 0,
879};
880
Takashi Iwai029d64b2005-11-17 14:34:36 +0100881static struct snd_kcontrol_new mixer_treble_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882{
883 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
884 .name = "Synth Tone Control - Treble",
885 .info = mixer_bass_treble_info,
886 .get = mixer_bass_treble_get,
887 .put = mixer_bass_treble_put,
888 .private_value = 1,
889};
890
891/*
892 * chorus/reverb mode
893 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100894static int mixer_chorus_reverb_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895{
896 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
897 uinfo->count = 1;
898 uinfo->value.integer.min = 0;
899 uinfo->value.integer.max = kcontrol->private_value ? (SNDRV_EMU8000_CHORUS_NUMBERS-1) : (SNDRV_EMU8000_REVERB_NUMBERS-1);
900 return 0;
901}
902
Takashi Iwai029d64b2005-11-17 14:34:36 +0100903static int mixer_chorus_reverb_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100905 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
907 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->chorus_mode : emu->reverb_mode;
908 return 0;
909}
910
Takashi Iwai029d64b2005-11-17 14:34:36 +0100911static int mixer_chorus_reverb_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100913 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 unsigned long flags;
915 int change;
916 unsigned short val1;
917
918 spin_lock_irqsave(&emu->control_lock, flags);
919 if (kcontrol->private_value) {
920 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
921 change = val1 != emu->chorus_mode;
922 emu->chorus_mode = val1;
923 } else {
924 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
925 change = val1 != emu->reverb_mode;
926 emu->reverb_mode = val1;
927 }
928 spin_unlock_irqrestore(&emu->control_lock, flags);
929 if (change) {
930 if (kcontrol->private_value)
931 snd_emu8000_update_chorus_mode(emu);
932 else
933 snd_emu8000_update_reverb_mode(emu);
934 }
935 return change;
936}
937
Takashi Iwai029d64b2005-11-17 14:34:36 +0100938static struct snd_kcontrol_new mixer_chorus_mode_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939{
940 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
941 .name = "Chorus Mode",
942 .info = mixer_chorus_reverb_info,
943 .get = mixer_chorus_reverb_get,
944 .put = mixer_chorus_reverb_put,
945 .private_value = 1,
946};
947
Takashi Iwai029d64b2005-11-17 14:34:36 +0100948static struct snd_kcontrol_new mixer_reverb_mode_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949{
950 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
951 .name = "Reverb Mode",
952 .info = mixer_chorus_reverb_info,
953 .get = mixer_chorus_reverb_get,
954 .put = mixer_chorus_reverb_put,
955 .private_value = 0,
956};
957
958/*
959 * FM OPL3 chorus/reverb depth
960 */
Takashi Iwai029d64b2005-11-17 14:34:36 +0100961static int mixer_fm_depth_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
963 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
964 uinfo->count = 1;
965 uinfo->value.integer.min = 0;
966 uinfo->value.integer.max = 255;
967 return 0;
968}
969
Takashi Iwai029d64b2005-11-17 14:34:36 +0100970static int mixer_fm_depth_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100972 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->fm_chorus_depth : emu->fm_reverb_depth;
975 return 0;
976}
977
Takashi Iwai029d64b2005-11-17 14:34:36 +0100978static int mixer_fm_depth_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
Takashi Iwai029d64b2005-11-17 14:34:36 +0100980 struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 unsigned long flags;
982 int change;
983 unsigned short val1;
984
985 val1 = ucontrol->value.integer.value[0] % 256;
986 spin_lock_irqsave(&emu->control_lock, flags);
987 if (kcontrol->private_value) {
988 change = val1 != emu->fm_chorus_depth;
989 emu->fm_chorus_depth = val1;
990 } else {
991 change = val1 != emu->fm_reverb_depth;
992 emu->fm_reverb_depth = val1;
993 }
994 spin_unlock_irqrestore(&emu->control_lock, flags);
995 if (change)
996 snd_emu8000_init_fm(emu);
997 return change;
998}
999
Takashi Iwai029d64b2005-11-17 14:34:36 +01001000static struct snd_kcontrol_new mixer_fm_chorus_depth_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
1002 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1003 .name = "FM Chorus Depth",
1004 .info = mixer_fm_depth_info,
1005 .get = mixer_fm_depth_get,
1006 .put = mixer_fm_depth_put,
1007 .private_value = 1,
1008};
1009
Takashi Iwai029d64b2005-11-17 14:34:36 +01001010static struct snd_kcontrol_new mixer_fm_reverb_depth_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011{
1012 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1013 .name = "FM Reverb Depth",
1014 .info = mixer_fm_depth_info,
1015 .get = mixer_fm_depth_get,
1016 .put = mixer_fm_depth_put,
1017 .private_value = 0,
1018};
1019
1020
Takashi Iwai029d64b2005-11-17 14:34:36 +01001021static struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 &mixer_bass_control,
1023 &mixer_treble_control,
1024 &mixer_chorus_mode_control,
1025 &mixer_reverb_mode_control,
1026 &mixer_fm_chorus_depth_control,
1027 &mixer_fm_reverb_depth_control,
1028};
1029
1030/*
1031 * create and attach mixer elements for WaveTable treble/bass controls
1032 */
Bill Pemberton1bff2922012-12-06 12:35:21 -05001033static int
Takashi Iwai029d64b2005-11-17 14:34:36 +01001034snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035{
1036 int i, err = 0;
1037
Takashi Iwai622207d2008-08-08 17:11:45 +02001038 if (snd_BUG_ON(!emu || !card))
1039 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041 spin_lock_init(&emu->control_lock);
1042
1043 memset(emu->controls, 0, sizeof(emu->controls));
1044 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1045 if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0)
1046 goto __error;
1047 }
1048 return 0;
1049
1050__error:
1051 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1052 down_write(&card->controls_rwsem);
1053 if (emu->controls[i])
1054 snd_ctl_remove(card, emu->controls[i]);
1055 up_write(&card->controls_rwsem);
1056 }
1057 return err;
1058}
1059
1060
1061/*
1062 * free resources
1063 */
Takashi Iwai029d64b2005-11-17 14:34:36 +01001064static int snd_emu8000_free(struct snd_emu8000 *hw)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065{
Takashi Iwaib1d57762005-10-10 11:56:31 +02001066 release_and_free_resource(hw->res_port1);
1067 release_and_free_resource(hw->res_port2);
1068 release_and_free_resource(hw->res_port3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 kfree(hw);
1070 return 0;
1071}
1072
1073/*
1074 */
Takashi Iwai029d64b2005-11-17 14:34:36 +01001075static int snd_emu8000_dev_free(struct snd_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
Takashi Iwai029d64b2005-11-17 14:34:36 +01001077 struct snd_emu8000 *hw = device->device_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 return snd_emu8000_free(hw);
1079}
1080
1081/*
1082 * initialize and register emu8000 synth device.
1083 */
Bill Pemberton1bff2922012-12-06 12:35:21 -05001084int
Takashi Iwai029d64b2005-11-17 14:34:36 +01001085snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
1086 struct snd_seq_device **awe_ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
Takashi Iwai029d64b2005-11-17 14:34:36 +01001088 struct snd_seq_device *awe;
1089 struct snd_emu8000 *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 int err;
Takashi Iwai029d64b2005-11-17 14:34:36 +01001091 static struct snd_device_ops ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 .dev_free = snd_emu8000_dev_free,
1093 };
1094
1095 if (awe_ret)
1096 *awe_ret = NULL;
1097
1098 if (seq_ports <= 0)
1099 return 0;
1100
Takashi Iwai9e76a762005-09-09 14:21:17 +02001101 hw = kzalloc(sizeof(*hw), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 if (hw == NULL)
1103 return -ENOMEM;
1104 spin_lock_init(&hw->reg_lock);
1105 hw->index = index;
1106 hw->port1 = port;
1107 hw->port2 = port + 0x400;
1108 hw->port3 = port + 0x800;
1109 if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) ||
1110 !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) ||
1111 !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) {
1112 snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3);
1113 snd_emu8000_free(hw);
1114 return -EBUSY;
1115 }
1116 hw->mem_size = 0;
1117 hw->card = card;
1118 hw->seq_ports = seq_ports;
1119 hw->bass_level = 5;
1120 hw->treble_level = 9;
1121 hw->chorus_mode = 2;
1122 hw->reverb_mode = 4;
1123 hw->fm_chorus_depth = 0;
1124 hw->fm_reverb_depth = 0;
1125
1126 if (snd_emu8000_detect(hw) < 0) {
1127 snd_emu8000_free(hw);
1128 return -ENODEV;
1129 }
1130
1131 snd_emu8000_init_hw(hw);
1132 if ((err = snd_emu8000_create_mixer(card, hw)) < 0) {
1133 snd_emu8000_free(hw);
1134 return err;
1135 }
1136
1137 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, hw, &ops)) < 0) {
1138 snd_emu8000_free(hw);
1139 return err;
1140 }
1141#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1142 if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
Takashi Iwai029d64b2005-11-17 14:34:36 +01001143 sizeof(struct snd_emu8000*), &awe) >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 strcpy(awe->name, "EMU-8000");
Takashi Iwai029d64b2005-11-17 14:34:36 +01001145 *(struct snd_emu8000 **)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 }
1147#else
1148 awe = NULL;
1149#endif
1150 if (awe_ret)
1151 *awe_ret = awe;
1152
1153 return 0;
1154}
1155
1156
1157/*
1158 * exported stuff
1159 */
1160
1161EXPORT_SYMBOL(snd_emu8000_poke);
1162EXPORT_SYMBOL(snd_emu8000_peek);
1163EXPORT_SYMBOL(snd_emu8000_poke_dw);
1164EXPORT_SYMBOL(snd_emu8000_peek_dw);
1165EXPORT_SYMBOL(snd_emu8000_dma_chan);
1166EXPORT_SYMBOL(snd_emu8000_init_fm);
1167EXPORT_SYMBOL(snd_emu8000_load_chorus_fx);
1168EXPORT_SYMBOL(snd_emu8000_load_reverb_fx);
1169EXPORT_SYMBOL(snd_emu8000_update_chorus_mode);
1170EXPORT_SYMBOL(snd_emu8000_update_reverb_mode);
1171EXPORT_SYMBOL(snd_emu8000_update_equalizer);