aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa/sb
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/isa/sb
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'sound/isa/sb')
-rw-r--r--sound/isa/sb/Makefile39
-rw-r--r--sound/isa/sb/emu8000.c1170
-rw-r--r--sound/isa/sb/emu8000_callback.c543
-rw-r--r--sound/isa/sb/emu8000_local.h43
-rw-r--r--sound/isa/sb/emu8000_patch.c303
-rw-r--r--sound/isa/sb/emu8000_pcm.c704
-rw-r--r--sound/isa/sb/emu8000_synth.c134
-rw-r--r--sound/isa/sb/es968.c235
-rw-r--r--sound/isa/sb/sb16.c678
-rw-r--r--sound/isa/sb/sb16_csp.c1175
-rw-r--r--sound/isa/sb/sb16_csp_codecs.h949
-rw-r--r--sound/isa/sb/sb16_main.c916
-rw-r--r--sound/isa/sb/sb8.c223
-rw-r--r--sound/isa/sb/sb8_main.c565
-rw-r--r--sound/isa/sb/sb8_midi.c293
-rw-r--r--sound/isa/sb/sb_common.c313
-rw-r--r--sound/isa/sb/sb_mixer.c844
-rw-r--r--sound/isa/sb/sbawe.c2
18 files changed, 9129 insertions, 0 deletions
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile
new file mode 100644
index 000000000000..fd9d9c5726fc
--- /dev/null
+++ b/sound/isa/sb/Makefile
@@ -0,0 +1,39 @@
1#
2# Makefile for ALSA
3# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-sb-common-objs := sb_common.o sb_mixer.o
7snd-sb8-dsp-objs := sb8_main.o sb8_midi.o
8snd-sb16-dsp-objs := sb16_main.o
9snd-sb16-csp-objs := sb16_csp.o
10snd-sb8-objs := sb8.o
11snd-sb16-objs := sb16.o
12snd-sbawe-objs := sbawe.o emu8000.o
13snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o
14snd-es968-objs := es968.o
15
16#
17# this function returns:
18# "m" - CONFIG_SND_SEQUENCER is m
19# <empty string> - CONFIG_SND_SEQUENCER is undefined
20# otherwise parameter #1 value
21#
22sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
23
24# Toplevel Module Dependency
25obj-$(CONFIG_SND_ALS100) += snd-sb16-dsp.o snd-sb-common.o
26obj-$(CONFIG_SND_CMI8330) += snd-sb16-dsp.o snd-sb-common.o
27obj-$(CONFIG_SND_DT019X) += snd-sb16-dsp.o snd-sb-common.o
28obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
29obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
30obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
31obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
32obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
33ifeq ($(CONFIG_SND_SB16_CSP),y)
34 obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
35 obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
36endif
37obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o
38
39obj-m := $(sort $(obj-m))
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
new file mode 100644
index 000000000000..028af4066595
--- /dev/null
+++ b/sound/isa/sb/emu8000.c
@@ -0,0 +1,1170 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk>
4 * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
5 *
6 * Routines for control of EMU8000 chip
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <sound/driver.h>
24#include <linux/wait.h>
25#include <linux/sched.h>
26#include <linux/slab.h>
27#include <linux/ioport.h>
28#include <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 */
48void snd_emu8000_poke(emu8000_t *emu, unsigned int port, unsigned int reg, unsigned int val)
49{
50 unsigned long flags;
51 spin_lock_irqsave(&emu->reg_lock, flags);
52 if (reg != emu->last_reg) {
53 outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
54 emu->last_reg = reg;
55 }
56 outw((unsigned short)val, port); /* Send data */
57 spin_unlock_irqrestore(&emu->reg_lock, flags);
58}
59
60/* Read a word */
61unsigned short snd_emu8000_peek(emu8000_t *emu, unsigned int port, unsigned int reg)
62{
63 unsigned short res;
64 unsigned long flags;
65 spin_lock_irqsave(&emu->reg_lock, flags);
66 if (reg != emu->last_reg) {
67 outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
68 emu->last_reg = reg;
69 }
70 res = inw(port); /* Read data */
71 spin_unlock_irqrestore(&emu->reg_lock, flags);
72 return res;
73}
74
75/* Write a double word */
76void snd_emu8000_poke_dw(emu8000_t *emu, unsigned int port, unsigned int reg, unsigned int val)
77{
78 unsigned long flags;
79 spin_lock_irqsave(&emu->reg_lock, flags);
80 if (reg != emu->last_reg) {
81 outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
82 emu->last_reg = reg;
83 }
84 outw((unsigned short)val, port); /* Send low word of data */
85 outw((unsigned short)(val>>16), port+2); /* Send high word of data */
86 spin_unlock_irqrestore(&emu->reg_lock, flags);
87}
88
89/* Read a double word */
90unsigned int snd_emu8000_peek_dw(emu8000_t *emu, unsigned int port, unsigned int reg)
91{
92 unsigned short low;
93 unsigned int res;
94 unsigned long flags;
95 spin_lock_irqsave(&emu->reg_lock, flags);
96 if (reg != emu->last_reg) {
97 outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
98 emu->last_reg = reg;
99 }
100 low = inw(port); /* Read low word of data */
101 res = low + (inw(port+2) << 16);
102 spin_unlock_irqrestore(&emu->reg_lock, flags);
103 return res;
104}
105
106/*
107 * Set up / close a channel to be used for DMA.
108 */
109/*exported*/ void
110snd_emu8000_dma_chan(emu8000_t *emu, int ch, int mode)
111{
112 unsigned right_bit = (mode & EMU8000_RAM_RIGHT) ? 0x01000000 : 0;
113 mode &= EMU8000_RAM_MODE_MASK;
114 if (mode == EMU8000_RAM_CLOSE) {
115 EMU8000_CCCA_WRITE(emu, ch, 0);
116 EMU8000_DCYSUSV_WRITE(emu, ch, 0x807F);
117 return;
118 }
119 EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
120 EMU8000_VTFT_WRITE(emu, ch, 0);
121 EMU8000_CVCF_WRITE(emu, ch, 0);
122 EMU8000_PTRX_WRITE(emu, ch, 0x40000000);
123 EMU8000_CPF_WRITE(emu, ch, 0x40000000);
124 EMU8000_PSST_WRITE(emu, ch, 0);
125 EMU8000_CSL_WRITE(emu, ch, 0);
126 if (mode == EMU8000_RAM_WRITE) /* DMA write */
127 EMU8000_CCCA_WRITE(emu, ch, 0x06000000 | right_bit);
128 else /* DMA read */
129 EMU8000_CCCA_WRITE(emu, ch, 0x04000000 | right_bit);
130}
131
132/*
133 */
134static void __init
135snd_emu8000_read_wait(emu8000_t *emu)
136{
137 while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
138 set_current_state(TASK_INTERRUPTIBLE);
139 schedule_timeout(1);
140 if (signal_pending(current))
141 break;
142 }
143}
144
145/*
146 */
147static void __init
148snd_emu8000_write_wait(emu8000_t *emu)
149{
150 while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
151 set_current_state(TASK_INTERRUPTIBLE);
152 schedule_timeout(1);
153 if (signal_pending(current))
154 break;
155 }
156}
157
158/*
159 * detect a card at the given port
160 */
161static int __init
162snd_emu8000_detect(emu8000_t *emu)
163{
164 /* Initialise */
165 EMU8000_HWCF1_WRITE(emu, 0x0059);
166 EMU8000_HWCF2_WRITE(emu, 0x0020);
167 EMU8000_HWCF3_WRITE(emu, 0x0000);
168 /* Check for a recognisable emu8000 */
169 /*
170 if ((EMU8000_U1_READ(emu) & 0x000f) != 0x000c)
171 return -ENODEV;
172 */
173 if ((EMU8000_HWCF1_READ(emu) & 0x007e) != 0x0058)
174 return -ENODEV;
175 if ((EMU8000_HWCF2_READ(emu) & 0x0003) != 0x0003)
176 return -ENODEV;
177
178 snd_printdd("EMU8000 [0x%lx]: Synth chip found\n",
179 emu->port1);
180 return 0;
181}
182
183
184/*
185 * intiailize audio channels
186 */
187static void __init
188init_audio(emu8000_t *emu)
189{
190 int ch;
191
192 /* turn off envelope engines */
193 for (ch = 0; ch < EMU8000_CHANNELS; ch++)
194 EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
195
196 /* reset all other parameters to zero */
197 for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
198 EMU8000_ENVVOL_WRITE(emu, ch, 0);
199 EMU8000_ENVVAL_WRITE(emu, ch, 0);
200 EMU8000_DCYSUS_WRITE(emu, ch, 0);
201 EMU8000_ATKHLDV_WRITE(emu, ch, 0);
202 EMU8000_LFO1VAL_WRITE(emu, ch, 0);
203 EMU8000_ATKHLD_WRITE(emu, ch, 0);
204 EMU8000_LFO2VAL_WRITE(emu, ch, 0);
205 EMU8000_IP_WRITE(emu, ch, 0);
206 EMU8000_IFATN_WRITE(emu, ch, 0);
207 EMU8000_PEFE_WRITE(emu, ch, 0);
208 EMU8000_FMMOD_WRITE(emu, ch, 0);
209 EMU8000_TREMFRQ_WRITE(emu, ch, 0);
210 EMU8000_FM2FRQ2_WRITE(emu, ch, 0);
211 EMU8000_PTRX_WRITE(emu, ch, 0);
212 EMU8000_VTFT_WRITE(emu, ch, 0);
213 EMU8000_PSST_WRITE(emu, ch, 0);
214 EMU8000_CSL_WRITE(emu, ch, 0);
215 EMU8000_CCCA_WRITE(emu, ch, 0);
216 }
217
218 for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
219 EMU8000_CPF_WRITE(emu, ch, 0);
220 EMU8000_CVCF_WRITE(emu, ch, 0);
221 }
222}
223
224
225/*
226 * initialize DMA address
227 */
228static void __init
229init_dma(emu8000_t *emu)
230{
231 EMU8000_SMALR_WRITE(emu, 0);
232 EMU8000_SMARR_WRITE(emu, 0);
233 EMU8000_SMALW_WRITE(emu, 0);
234 EMU8000_SMARW_WRITE(emu, 0);
235}
236
237/*
238 * initialization arrays; from ADIP
239 */
240static unsigned short init1[128] /*__devinitdata*/ = {
241 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330,
242 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730,
243 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30,
244 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30,
245
246 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330,
247 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730,
248 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30,
249 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30,
250
251 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330,
252 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730,
253 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30,
254 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30,
255
256 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330,
257 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730,
258 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30,
259 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30,
260};
261
262static unsigned short init2[128] /*__devinitdata*/ = {
263 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
264 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
265 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
266 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
267
268 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
269 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
270 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
271 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
272
273 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
274 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
275 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
276 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
277
278 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
279 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
280 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
281 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
282};
283
284static unsigned short init3[128] /*__devinitdata*/ = {
285 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
286 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
287 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
288 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
289
290 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
291 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
292 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
293 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
294
295 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
296 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
297 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
298 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
299
300 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
301 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
302 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
303 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
304};
305
306static unsigned short init4[128] /*__devinitdata*/ = {
307 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
308 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
309 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
310 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
311
312 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
313 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
314 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
315 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
316
317 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
318 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
319 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
320 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
321
322 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
323 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
324 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
325 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
326};
327
328/* send an initialization array
329 * Taken from the oss driver, not obvious from the doc how this
330 * is meant to work
331 */
332static void __init
333send_array(emu8000_t *emu, unsigned short *data, int size)
334{
335 int i;
336 unsigned short *p;
337
338 p = data;
339 for (i = 0; i < size; i++, p++)
340 EMU8000_INIT1_WRITE(emu, i, *p);
341 for (i = 0; i < size; i++, p++)
342 EMU8000_INIT2_WRITE(emu, i, *p);
343 for (i = 0; i < size; i++, p++)
344 EMU8000_INIT3_WRITE(emu, i, *p);
345 for (i = 0; i < size; i++, p++)
346 EMU8000_INIT4_WRITE(emu, i, *p);
347}
348
349
350/*
351 * Send initialization arrays to start up, this just follows the
352 * initialisation sequence in the adip.
353 */
354static void __init
355init_arrays(emu8000_t *emu)
356{
357 send_array(emu, init1, ARRAY_SIZE(init1)/4);
358
359 msleep((1024 * 1000) / 44100); /* wait for 1024 clocks */
360 send_array(emu, init2, ARRAY_SIZE(init2)/4);
361 send_array(emu, init3, ARRAY_SIZE(init3)/4);
362
363 EMU8000_HWCF4_WRITE(emu, 0);
364 EMU8000_HWCF5_WRITE(emu, 0x83);
365 EMU8000_HWCF6_WRITE(emu, 0x8000);
366
367 send_array(emu, init4, ARRAY_SIZE(init4)/4);
368}
369
370
371#define UNIQUE_ID1 0xa5b9
372#define UNIQUE_ID2 0x9d53
373
374/*
375 * Size the onboard memory.
376 * This is written so as not to need arbitary delays after the write. It
377 * seems that the only way to do this is to use the one channel and keep
378 * reallocating between read and write.
379 */
380static void __init
381size_dram(emu8000_t *emu)
382{
383 int i, size;
384
385 if (emu->dram_checked)
386 return;
387
388 size = 0;
389
390 /* write out a magic number */
391 snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
392 snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_READ);
393 EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET);
394 EMU8000_SMLD_WRITE(emu, UNIQUE_ID1);
395 snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */
396
397 while (size < EMU8000_MAX_DRAM) {
398
399 size += 512 * 1024; /* increment 512kbytes */
400
401 /* Write a unique data on the test address.
402 * if the address is out of range, the data is written on
403 * 0x200000(=EMU8000_DRAM_OFFSET). Then the id word is
404 * changed by this data.
405 */
406 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);*/
407 EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
408 EMU8000_SMLD_WRITE(emu, UNIQUE_ID2);
409 snd_emu8000_write_wait(emu);
410
411 /*
412 * read the data on the just written DRAM address
413 * if not the same then we have reached the end of ram.
414 */
415 /*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_READ);*/
416 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
417 /*snd_emu8000_read_wait(emu);*/
418 EMU8000_SMLD_READ(emu); /* discard stale data */
419 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
420 break; /* we must have wrapped around */
421
422 snd_emu8000_read_wait(emu);
423
424 /*
425 * If it is the same it could be that the address just
426 * wraps back to the beginning; so check to see if the
427 * initial value has been overwritten.
428 */
429 EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
430 EMU8000_SMLD_READ(emu); /* discard stale data */
431 if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
432 break; /* we must have wrapped around */
433 snd_emu8000_read_wait(emu);
434 }
435
436 /* wait until FULL bit in SMAxW register is false */
437 for (i = 0; i < 10000; i++) {
438 if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
439 break;
440 set_current_state(TASK_INTERRUPTIBLE);
441 schedule_timeout(1);
442 if (signal_pending(current))
443 break;
444 }
445 snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
446 snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
447
448 snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n",
449 emu->port1, size/1024);
450
451 emu->mem_size = size;
452 emu->dram_checked = 1;
453}
454
455
456/*
457 * Initiailise the FM section. You have to do this to use sample RAM
458 * and therefore lose 2 voices.
459 */
460/*exported*/ void
461snd_emu8000_init_fm(emu8000_t *emu)
462{
463 unsigned long flags;
464
465 /* Initialize the last two channels for DRAM refresh and producing
466 the reverb and chorus effects for Yamaha OPL-3 synthesizer */
467
468 /* 31: FM left channel, 0xffffe0-0xffffe8 */
469 EMU8000_DCYSUSV_WRITE(emu, 30, 0x80);
470 EMU8000_PSST_WRITE(emu, 30, 0xFFFFFFE0); /* full left */
471 EMU8000_CSL_WRITE(emu, 30, 0x00FFFFE8 | (emu->fm_chorus_depth << 24));
472 EMU8000_PTRX_WRITE(emu, 30, (emu->fm_reverb_depth << 8));
473 EMU8000_CPF_WRITE(emu, 30, 0);
474 EMU8000_CCCA_WRITE(emu, 30, 0x00FFFFE3);
475
476 /* 32: FM right channel, 0xfffff0-0xfffff8 */
477 EMU8000_DCYSUSV_WRITE(emu, 31, 0x80);
478 EMU8000_PSST_WRITE(emu, 31, 0x00FFFFF0); /* full right */
479 EMU8000_CSL_WRITE(emu, 31, 0x00FFFFF8 | (emu->fm_chorus_depth << 24));
480 EMU8000_PTRX_WRITE(emu, 31, (emu->fm_reverb_depth << 8));
481 EMU8000_CPF_WRITE(emu, 31, 0x8000);
482 EMU8000_CCCA_WRITE(emu, 31, 0x00FFFFF3);
483
484 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0);
485
486 spin_lock_irqsave(&emu->reg_lock, flags);
487 while (!(inw(EMU8000_PTR(emu)) & 0x1000))
488 ;
489 while ((inw(EMU8000_PTR(emu)) & 0x1000))
490 ;
491 spin_unlock_irqrestore(&emu->reg_lock, flags);
492 snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828);
493 /* this is really odd part.. */
494 outb(0x3C, EMU8000_PTR(emu));
495 outb(0, EMU8000_DATA1(emu));
496
497 /* skew volume & cutoff */
498 EMU8000_VTFT_WRITE(emu, 30, 0x8000FFFF);
499 EMU8000_VTFT_WRITE(emu, 31, 0x8000FFFF);
500}
501
502
503/*
504 * The main initialization routine.
505 */
506static void __init
507snd_emu8000_init_hw(emu8000_t *emu)
508{
509 int i;
510
511 emu->last_reg = 0xffff; /* reset the last register index */
512
513 /* initialize hardware configuration */
514 EMU8000_HWCF1_WRITE(emu, 0x0059);
515 EMU8000_HWCF2_WRITE(emu, 0x0020);
516
517 /* disable audio; this seems to reduce a clicking noise a bit.. */
518 EMU8000_HWCF3_WRITE(emu, 0);
519
520 /* initialize audio channels */
521 init_audio(emu);
522
523 /* initialize DMA */
524 init_dma(emu);
525
526 /* initialize init arrays */
527 init_arrays(emu);
528
529 /*
530 * Initialize the FM section of the AWE32, this is needed
531 * for DRAM refresh as well
532 */
533 snd_emu8000_init_fm(emu);
534
535 /* terminate all voices */
536 for (i = 0; i < EMU8000_DRAM_VOICES; i++)
537 EMU8000_DCYSUSV_WRITE(emu, 0, 0x807F);
538
539 /* check DRAM memory size */
540 size_dram(emu);
541
542 /* enable audio */
543 EMU8000_HWCF3_WRITE(emu, 0x4);
544
545 /* set equzlier, chorus and reverb modes */
546 snd_emu8000_update_equalizer(emu);
547 snd_emu8000_update_chorus_mode(emu);
548 snd_emu8000_update_reverb_mode(emu);
549}
550
551
552/*----------------------------------------------------------------
553 * Bass/Treble Equalizer
554 *----------------------------------------------------------------*/
555
556static unsigned short bass_parm[12][3] = {
557 {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
558 {0xD25B, 0xD35B, 0x0000}, /* -8 */
559 {0xD24C, 0xD34C, 0x0000}, /* -6 */
560 {0xD23D, 0xD33D, 0x0000}, /* -4 */
561 {0xD21F, 0xD31F, 0x0000}, /* -2 */
562 {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */
563 {0xC219, 0xC319, 0x0001}, /* +2 */
564 {0xC22A, 0xC32A, 0x0001}, /* +4 */
565 {0xC24C, 0xC34C, 0x0001}, /* +6 */
566 {0xC26E, 0xC36E, 0x0001}, /* +8 */
567 {0xC248, 0xC384, 0x0002}, /* +10 */
568 {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
569};
570
571static unsigned short treble_parm[12][9] = {
572 {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
573 {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
574 {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
575 {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
576 {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
577 {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
578 {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
579 {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
580 {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
581 {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
582 {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
583 {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002} /* +12 dB */
584};
585
586
587/*
588 * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
589 */
590/*exported*/ void
591snd_emu8000_update_equalizer(emu8000_t *emu)
592{
593 unsigned short w;
594 int bass = emu->bass_level;
595 int treble = emu->treble_level;
596
597 if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
598 return;
599 EMU8000_INIT4_WRITE(emu, 0x01, bass_parm[bass][0]);
600 EMU8000_INIT4_WRITE(emu, 0x11, bass_parm[bass][1]);
601 EMU8000_INIT3_WRITE(emu, 0x11, treble_parm[treble][0]);
602 EMU8000_INIT3_WRITE(emu, 0x13, treble_parm[treble][1]);
603 EMU8000_INIT3_WRITE(emu, 0x1b, treble_parm[treble][2]);
604 EMU8000_INIT4_WRITE(emu, 0x07, treble_parm[treble][3]);
605 EMU8000_INIT4_WRITE(emu, 0x0b, treble_parm[treble][4]);
606 EMU8000_INIT4_WRITE(emu, 0x0d, treble_parm[treble][5]);
607 EMU8000_INIT4_WRITE(emu, 0x17, treble_parm[treble][6]);
608 EMU8000_INIT4_WRITE(emu, 0x19, treble_parm[treble][7]);
609 w = bass_parm[bass][2] + treble_parm[treble][8];
610 EMU8000_INIT4_WRITE(emu, 0x15, (unsigned short)(w + 0x0262));
611 EMU8000_INIT4_WRITE(emu, 0x1d, (unsigned short)(w + 0x8362));
612}
613
614
615/*----------------------------------------------------------------
616 * Chorus mode control
617 *----------------------------------------------------------------*/
618
619/*
620 * chorus mode parameters
621 */
622#define SNDRV_EMU8000_CHORUS_1 0
623#define SNDRV_EMU8000_CHORUS_2 1
624#define SNDRV_EMU8000_CHORUS_3 2
625#define SNDRV_EMU8000_CHORUS_4 3
626#define SNDRV_EMU8000_CHORUS_FEEDBACK 4
627#define SNDRV_EMU8000_CHORUS_FLANGER 5
628#define SNDRV_EMU8000_CHORUS_SHORTDELAY 6
629#define SNDRV_EMU8000_CHORUS_SHORTDELAY2 7
630#define SNDRV_EMU8000_CHORUS_PREDEFINED 8
631/* user can define chorus modes up to 32 */
632#define SNDRV_EMU8000_CHORUS_NUMBERS 32
633
634typedef struct soundfont_chorus_fx_t {
635 unsigned short feedback; /* feedback level (0xE600-0xE6FF) */
636 unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */
637 unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */
638 unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
639 unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */
640} soundfont_chorus_fx_t;
641
642/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
643static char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
644static soundfont_chorus_fx_t chorus_parm[SNDRV_EMU8000_CHORUS_NUMBERS] = {
645 {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
646 {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
647 {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
648 {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
649 {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
650 {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
651 {0xE600, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay */
652 {0xE6C0, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay + feedback */
653};
654
655/*exported*/ int
656snd_emu8000_load_chorus_fx(emu8000_t *emu, int mode, const void __user *buf, long len)
657{
658 soundfont_chorus_fx_t rec;
659 if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) {
660 snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode);
661 return -EINVAL;
662 }
663 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
664 return -EFAULT;
665 chorus_parm[mode] = rec;
666 chorus_defined[mode] = 1;
667 return 0;
668}
669
670/*exported*/ void
671snd_emu8000_update_chorus_mode(emu8000_t *emu)
672{
673 int effect = emu->chorus_mode;
674 if (effect < 0 || effect >= SNDRV_EMU8000_CHORUS_NUMBERS ||
675 (effect >= SNDRV_EMU8000_CHORUS_PREDEFINED && !chorus_defined[effect]))
676 return;
677 EMU8000_INIT3_WRITE(emu, 0x09, chorus_parm[effect].feedback);
678 EMU8000_INIT3_WRITE(emu, 0x0c, chorus_parm[effect].delay_offset);
679 EMU8000_INIT4_WRITE(emu, 0x03, chorus_parm[effect].lfo_depth);
680 EMU8000_HWCF4_WRITE(emu, chorus_parm[effect].delay);
681 EMU8000_HWCF5_WRITE(emu, chorus_parm[effect].lfo_freq);
682 EMU8000_HWCF6_WRITE(emu, 0x8000);
683 EMU8000_HWCF7_WRITE(emu, 0x0000);
684}
685
686/*----------------------------------------------------------------
687 * Reverb mode control
688 *----------------------------------------------------------------*/
689
690/*
691 * reverb mode parameters
692 */
693#define SNDRV_EMU8000_REVERB_ROOM1 0
694#define SNDRV_EMU8000_REVERB_ROOM2 1
695#define SNDRV_EMU8000_REVERB_ROOM3 2
696#define SNDRV_EMU8000_REVERB_HALL1 3
697#define SNDRV_EMU8000_REVERB_HALL2 4
698#define SNDRV_EMU8000_REVERB_PLATE 5
699#define SNDRV_EMU8000_REVERB_DELAY 6
700#define SNDRV_EMU8000_REVERB_PANNINGDELAY 7
701#define SNDRV_EMU8000_REVERB_PREDEFINED 8
702/* user can define reverb modes up to 32 */
703#define SNDRV_EMU8000_REVERB_NUMBERS 32
704
705typedef struct soundfont_reverb_fx_t {
706 unsigned short parms[28];
707} soundfont_reverb_fx_t;
708
709/* reverb mode settings; write the following 28 data of 16 bit length
710 * on the corresponding ports in the reverb_cmds array
711 */
712static char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
713static soundfont_reverb_fx_t reverb_parm[SNDRV_EMU8000_REVERB_NUMBERS] = {
714{{ /* room 1 */
715 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
716 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
717 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
718 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
719}},
720{{ /* room 2 */
721 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
722 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
723 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
724 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
725}},
726{{ /* room 3 */
727 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
728 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
729 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
730 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
731}},
732{{ /* hall 1 */
733 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
734 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
735 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
736 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
737}},
738{{ /* hall 2 */
739 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
740 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
741 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
742 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
743}},
744{{ /* plate */
745 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
746 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
747 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
748 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
749}},
750{{ /* delay */
751 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
752 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
753 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
754 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
755}},
756{{ /* panning delay */
757 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
758 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
759 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
760 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
761}},
762};
763
764enum { DATA1, DATA2 };
765#define AWE_INIT1(c) EMU8000_CMD(2,c), DATA1
766#define AWE_INIT2(c) EMU8000_CMD(2,c), DATA2
767#define AWE_INIT3(c) EMU8000_CMD(3,c), DATA1
768#define AWE_INIT4(c) EMU8000_CMD(3,c), DATA2
769
770static struct reverb_cmd_pair {
771 unsigned short cmd, port;
772} reverb_cmds[28] = {
773 {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
774 {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
775 {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
776 {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
777 {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
778 {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
779 {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
780};
781
782/*exported*/ int
783snd_emu8000_load_reverb_fx(emu8000_t *emu, int mode, const void __user *buf, long len)
784{
785 soundfont_reverb_fx_t rec;
786
787 if (mode < SNDRV_EMU8000_REVERB_PREDEFINED || mode >= SNDRV_EMU8000_REVERB_NUMBERS) {
788 snd_printk(KERN_WARNING "invalid reverb mode %d for uploading\n", mode);
789 return -EINVAL;
790 }
791 if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
792 return -EFAULT;
793 reverb_parm[mode] = rec;
794 reverb_defined[mode] = 1;
795 return 0;
796}
797
798/*exported*/ void
799snd_emu8000_update_reverb_mode(emu8000_t *emu)
800{
801 int effect = emu->reverb_mode;
802 int i;
803
804 if (effect < 0 || effect >= SNDRV_EMU8000_REVERB_NUMBERS ||
805 (effect >= SNDRV_EMU8000_REVERB_PREDEFINED && !reverb_defined[effect]))
806 return;
807 for (i = 0; i < 28; i++) {
808 int port;
809 if (reverb_cmds[i].port == DATA1)
810 port = EMU8000_DATA1(emu);
811 else
812 port = EMU8000_DATA2(emu);
813 snd_emu8000_poke(emu, port, reverb_cmds[i].cmd, reverb_parm[effect].parms[i]);
814 }
815}
816
817
818/*----------------------------------------------------------------
819 * mixer interface
820 *----------------------------------------------------------------*/
821
822/*
823 * bass/treble
824 */
825static int mixer_bass_treble_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
826{
827 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
828 uinfo->count = 1;
829 uinfo->value.integer.min = 0;
830 uinfo->value.integer.max = 11;
831 return 0;
832}
833
834static int mixer_bass_treble_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
835{
836 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
837
838 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->treble_level : emu->bass_level;
839 return 0;
840}
841
842static int mixer_bass_treble_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
843{
844 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
845 unsigned long flags;
846 int change;
847 unsigned short val1;
848
849 val1 = ucontrol->value.integer.value[0] % 12;
850 spin_lock_irqsave(&emu->control_lock, flags);
851 if (kcontrol->private_value) {
852 change = val1 != emu->treble_level;
853 emu->treble_level = val1;
854 } else {
855 change = val1 != emu->bass_level;
856 emu->bass_level = val1;
857 }
858 spin_unlock_irqrestore(&emu->control_lock, flags);
859 snd_emu8000_update_equalizer(emu);
860 return change;
861}
862
863static snd_kcontrol_new_t mixer_bass_control =
864{
865 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
866 .name = "Synth Tone Control - Bass",
867 .info = mixer_bass_treble_info,
868 .get = mixer_bass_treble_get,
869 .put = mixer_bass_treble_put,
870 .private_value = 0,
871};
872
873static snd_kcontrol_new_t mixer_treble_control =
874{
875 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
876 .name = "Synth Tone Control - Treble",
877 .info = mixer_bass_treble_info,
878 .get = mixer_bass_treble_get,
879 .put = mixer_bass_treble_put,
880 .private_value = 1,
881};
882
883/*
884 * chorus/reverb mode
885 */
886static int mixer_chorus_reverb_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
887{
888 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
889 uinfo->count = 1;
890 uinfo->value.integer.min = 0;
891 uinfo->value.integer.max = kcontrol->private_value ? (SNDRV_EMU8000_CHORUS_NUMBERS-1) : (SNDRV_EMU8000_REVERB_NUMBERS-1);
892 return 0;
893}
894
895static int mixer_chorus_reverb_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
896{
897 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
898
899 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->chorus_mode : emu->reverb_mode;
900 return 0;
901}
902
903static int mixer_chorus_reverb_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
904{
905 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
906 unsigned long flags;
907 int change;
908 unsigned short val1;
909
910 spin_lock_irqsave(&emu->control_lock, flags);
911 if (kcontrol->private_value) {
912 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
913 change = val1 != emu->chorus_mode;
914 emu->chorus_mode = val1;
915 } else {
916 val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
917 change = val1 != emu->reverb_mode;
918 emu->reverb_mode = val1;
919 }
920 spin_unlock_irqrestore(&emu->control_lock, flags);
921 if (change) {
922 if (kcontrol->private_value)
923 snd_emu8000_update_chorus_mode(emu);
924 else
925 snd_emu8000_update_reverb_mode(emu);
926 }
927 return change;
928}
929
930static snd_kcontrol_new_t mixer_chorus_mode_control =
931{
932 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
933 .name = "Chorus Mode",
934 .info = mixer_chorus_reverb_info,
935 .get = mixer_chorus_reverb_get,
936 .put = mixer_chorus_reverb_put,
937 .private_value = 1,
938};
939
940static snd_kcontrol_new_t mixer_reverb_mode_control =
941{
942 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
943 .name = "Reverb Mode",
944 .info = mixer_chorus_reverb_info,
945 .get = mixer_chorus_reverb_get,
946 .put = mixer_chorus_reverb_put,
947 .private_value = 0,
948};
949
950/*
951 * FM OPL3 chorus/reverb depth
952 */
953static int mixer_fm_depth_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
954{
955 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
956 uinfo->count = 1;
957 uinfo->value.integer.min = 0;
958 uinfo->value.integer.max = 255;
959 return 0;
960}
961
962static int mixer_fm_depth_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
963{
964 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
965
966 ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->fm_chorus_depth : emu->fm_reverb_depth;
967 return 0;
968}
969
970static int mixer_fm_depth_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
971{
972 emu8000_t *emu = snd_kcontrol_chip(kcontrol);
973 unsigned long flags;
974 int change;
975 unsigned short val1;
976
977 val1 = ucontrol->value.integer.value[0] % 256;
978 spin_lock_irqsave(&emu->control_lock, flags);
979 if (kcontrol->private_value) {
980 change = val1 != emu->fm_chorus_depth;
981 emu->fm_chorus_depth = val1;
982 } else {
983 change = val1 != emu->fm_reverb_depth;
984 emu->fm_reverb_depth = val1;
985 }
986 spin_unlock_irqrestore(&emu->control_lock, flags);
987 if (change)
988 snd_emu8000_init_fm(emu);
989 return change;
990}
991
992static snd_kcontrol_new_t mixer_fm_chorus_depth_control =
993{
994 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
995 .name = "FM Chorus Depth",
996 .info = mixer_fm_depth_info,
997 .get = mixer_fm_depth_get,
998 .put = mixer_fm_depth_put,
999 .private_value = 1,
1000};
1001
1002static snd_kcontrol_new_t mixer_fm_reverb_depth_control =
1003{
1004 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1005 .name = "FM Reverb Depth",
1006 .info = mixer_fm_depth_info,
1007 .get = mixer_fm_depth_get,
1008 .put = mixer_fm_depth_put,
1009 .private_value = 0,
1010};
1011
1012
1013static snd_kcontrol_new_t *mixer_defs[EMU8000_NUM_CONTROLS] = {
1014 &mixer_bass_control,
1015 &mixer_treble_control,
1016 &mixer_chorus_mode_control,
1017 &mixer_reverb_mode_control,
1018 &mixer_fm_chorus_depth_control,
1019 &mixer_fm_reverb_depth_control,
1020};
1021
1022/*
1023 * create and attach mixer elements for WaveTable treble/bass controls
1024 */
1025static int __init
1026snd_emu8000_create_mixer(snd_card_t *card, emu8000_t *emu)
1027{
1028 int i, err = 0;
1029
1030 snd_assert(emu != NULL && card != NULL, return -EINVAL);
1031
1032 spin_lock_init(&emu->control_lock);
1033
1034 memset(emu->controls, 0, sizeof(emu->controls));
1035 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1036 if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0)
1037 goto __error;
1038 }
1039 return 0;
1040
1041__error:
1042 for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
1043 down_write(&card->controls_rwsem);
1044 if (emu->controls[i])
1045 snd_ctl_remove(card, emu->controls[i]);
1046 up_write(&card->controls_rwsem);
1047 }
1048 return err;
1049}
1050
1051
1052/*
1053 * free resources
1054 */
1055static int snd_emu8000_free(emu8000_t *hw)
1056{
1057 if (hw->res_port1) {
1058 release_resource(hw->res_port1);
1059 kfree_nocheck(hw->res_port1);
1060 }
1061 if (hw->res_port2) {
1062 release_resource(hw->res_port2);
1063 kfree_nocheck(hw->res_port2);
1064 }
1065 if (hw->res_port3) {
1066 release_resource(hw->res_port3);
1067 kfree_nocheck(hw->res_port3);
1068 }
1069 kfree(hw);
1070 return 0;
1071}
1072
1073/*
1074 */
1075static int snd_emu8000_dev_free(snd_device_t *device)
1076{
1077 emu8000_t *hw = device->device_data;
1078 return snd_emu8000_free(hw);
1079}
1080
1081/*
1082 * initialize and register emu8000 synth device.
1083 */
1084int __init
1085snd_emu8000_new(snd_card_t *card, int index, long port, int seq_ports, snd_seq_device_t **awe_ret)
1086{
1087 snd_seq_device_t *awe;
1088 emu8000_t *hw;
1089 int err;
1090 static snd_device_ops_t ops = {
1091 .dev_free = snd_emu8000_dev_free,
1092 };
1093
1094 if (awe_ret)
1095 *awe_ret = NULL;
1096
1097 if (seq_ports <= 0)
1098 return 0;
1099
1100 hw = kcalloc(1, sizeof(*hw), GFP_KERNEL);
1101 if (hw == NULL)
1102 return -ENOMEM;
1103 spin_lock_init(&hw->reg_lock);
1104 hw->index = index;
1105 hw->port1 = port;
1106 hw->port2 = port + 0x400;
1107 hw->port3 = port + 0x800;
1108 if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) ||
1109 !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) ||
1110 !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) {
1111 snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3);
1112 snd_emu8000_free(hw);
1113 return -EBUSY;
1114 }
1115 hw->mem_size = 0;
1116 hw->card = card;
1117 hw->seq_ports = seq_ports;
1118 hw->bass_level = 5;
1119 hw->treble_level = 9;
1120 hw->chorus_mode = 2;
1121 hw->reverb_mode = 4;
1122 hw->fm_chorus_depth = 0;
1123 hw->fm_reverb_depth = 0;
1124
1125 if (snd_emu8000_detect(hw) < 0) {
1126 snd_emu8000_free(hw);
1127 return -ENODEV;
1128 }
1129
1130 snd_emu8000_init_hw(hw);
1131 if ((err = snd_emu8000_create_mixer(card, hw)) < 0) {
1132 snd_emu8000_free(hw);
1133 return err;
1134 }
1135
1136 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, hw, &ops)) < 0) {
1137 snd_emu8000_free(hw);
1138 return err;
1139 }
1140#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1141 if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
1142 sizeof(emu8000_t*), &awe) >= 0) {
1143 strcpy(awe->name, "EMU-8000");
1144 *(emu8000_t**)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
1145 }
1146#else
1147 awe = NULL;
1148#endif
1149 if (awe_ret)
1150 *awe_ret = awe;
1151
1152 return 0;
1153}
1154
1155
1156/*
1157 * exported stuff
1158 */
1159
1160EXPORT_SYMBOL(snd_emu8000_poke);
1161EXPORT_SYMBOL(snd_emu8000_peek);
1162EXPORT_SYMBOL(snd_emu8000_poke_dw);
1163EXPORT_SYMBOL(snd_emu8000_peek_dw);
1164EXPORT_SYMBOL(snd_emu8000_dma_chan);
1165EXPORT_SYMBOL(snd_emu8000_init_fm);
1166EXPORT_SYMBOL(snd_emu8000_load_chorus_fx);
1167EXPORT_SYMBOL(snd_emu8000_load_reverb_fx);
1168EXPORT_SYMBOL(snd_emu8000_update_chorus_mode);
1169EXPORT_SYMBOL(snd_emu8000_update_reverb_mode);
1170EXPORT_SYMBOL(snd_emu8000_update_equalizer);
diff --git a/sound/isa/sb/emu8000_callback.c b/sound/isa/sb/emu8000_callback.c
new file mode 100644
index 000000000000..1cc4101a17a4
--- /dev/null
+++ b/sound/isa/sb/emu8000_callback.c
@@ -0,0 +1,543 @@
1/*
2 * synth callback routines for the emu8000 (AWE32/64)
3 *
4 * Copyright (C) 1999 Steve Ratcliffe
5 * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include "emu8000_local.h"
23#include <sound/asoundef.h>
24
25/*
26 * prototypes
27 */
28static snd_emux_voice_t *get_voice(snd_emux_t *emu, snd_emux_port_t *port);
29static int start_voice(snd_emux_voice_t *vp);
30static void trigger_voice(snd_emux_voice_t *vp);
31static void release_voice(snd_emux_voice_t *vp);
32static void update_voice(snd_emux_voice_t *vp, int update);
33static void reset_voice(snd_emux_t *emu, int ch);
34static void terminate_voice(snd_emux_voice_t *vp);
35static void sysex(snd_emux_t *emu, char *buf, int len, int parsed, snd_midi_channel_set_t *chset);
36#ifdef CONFIG_SND_SEQUENCER_OSS
37static int oss_ioctl(snd_emux_t *emu, int cmd, int p1, int p2);
38#endif
39static int load_fx(snd_emux_t *emu, int type, int mode, const void __user *buf, long len);
40
41static void set_pitch(emu8000_t *hw, snd_emux_voice_t *vp);
42static void set_volume(emu8000_t *hw, snd_emux_voice_t *vp);
43static void set_pan(emu8000_t *hw, snd_emux_voice_t *vp);
44static void set_fmmod(emu8000_t *hw, snd_emux_voice_t *vp);
45static void set_tremfreq(emu8000_t *hw, snd_emux_voice_t *vp);
46static void set_fm2frq2(emu8000_t *hw, snd_emux_voice_t *vp);
47static void set_filterQ(emu8000_t *hw, snd_emux_voice_t *vp);
48static void snd_emu8000_tweak_voice(emu8000_t *emu, int ch);
49
50/*
51 * Ensure a value is between two points
52 * macro evaluates its args more than once, so changed to upper-case.
53 */
54#define LIMITVALUE(x, a, b) do { if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b); } while (0)
55#define LIMITMAX(x, a) do {if ((x) > (a)) (x) = (a); } while (0)
56
57
58/*
59 * set up operators
60 */
61static snd_emux_operators_t emu8000_ops = {
62 .owner = THIS_MODULE,
63 .get_voice = get_voice,
64 .prepare = start_voice,
65 .trigger = trigger_voice,
66 .release = release_voice,
67 .update = update_voice,
68 .terminate = terminate_voice,
69 .reset = reset_voice,
70 .sample_new = snd_emu8000_sample_new,
71 .sample_free = snd_emu8000_sample_free,
72 .sample_reset = snd_emu8000_sample_reset,
73 .load_fx = load_fx,
74 .sysex = sysex,
75#ifdef CONFIG_SND_SEQUENCER_OSS
76 .oss_ioctl = oss_ioctl,
77#endif
78};
79
80void
81snd_emu8000_ops_setup(emu8000_t *hw)
82{
83 hw->emu->ops = emu8000_ops;
84}
85
86
87
88/*
89 * Terminate a voice
90 */
91static void
92release_voice(snd_emux_voice_t *vp)
93{
94 int dcysusv;
95 emu8000_t *hw;
96
97 hw = vp->hw;
98 dcysusv = 0x8000 | (unsigned char)vp->reg.parm.modrelease;
99 EMU8000_DCYSUS_WRITE(hw, vp->ch, dcysusv);
100 dcysusv = 0x8000 | (unsigned char)vp->reg.parm.volrelease;
101 EMU8000_DCYSUSV_WRITE(hw, vp->ch, dcysusv);
102}
103
104
105/*
106 */
107static void
108terminate_voice(snd_emux_voice_t *vp)
109{
110 emu8000_t *hw;
111
112 hw = vp->hw;
113 EMU8000_DCYSUSV_WRITE(hw, vp->ch, 0x807F);
114}
115
116
117/*
118 */
119static void
120update_voice(snd_emux_voice_t *vp, int update)
121{
122 emu8000_t *hw;
123
124 hw = vp->hw;
125 if (update & SNDRV_EMUX_UPDATE_VOLUME)
126 set_volume(hw, vp);
127 if (update & SNDRV_EMUX_UPDATE_PITCH)
128 set_pitch(hw, vp);
129 if ((update & SNDRV_EMUX_UPDATE_PAN) &&
130 vp->port->ctrls[EMUX_MD_REALTIME_PAN])
131 set_pan(hw, vp);
132 if (update & SNDRV_EMUX_UPDATE_FMMOD)
133 set_fmmod(hw, vp);
134 if (update & SNDRV_EMUX_UPDATE_TREMFREQ)
135 set_tremfreq(hw, vp);
136 if (update & SNDRV_EMUX_UPDATE_FM2FRQ2)
137 set_fm2frq2(hw, vp);
138 if (update & SNDRV_EMUX_UPDATE_Q)
139 set_filterQ(hw, vp);
140}
141
142
143/*
144 * Find a channel (voice) within the EMU that is not in use or at least
145 * less in use than other channels. Always returns a valid pointer
146 * no matter what. If there is a real shortage of voices then one
147 * will be cut. Such is life.
148 *
149 * The channel index (vp->ch) must be initialized in this routine.
150 * In Emu8k, it is identical with the array index.
151 */
152static snd_emux_voice_t *
153get_voice(snd_emux_t *emu, snd_emux_port_t *port)
154{
155 int i;
156 snd_emux_voice_t *vp;
157 emu8000_t *hw;
158
159 /* what we are looking for, in order of preference */
160 enum {
161 OFF=0, RELEASED, PLAYING, END
162 };
163
164 /* Keeps track of what we are finding */
165 struct best {
166 unsigned int time;
167 int voice;
168 } best[END];
169 struct best *bp;
170
171 hw = emu->hw;
172
173 for (i = 0; i < END; i++) {
174 best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */;
175 best[i].voice = -1;
176 }
177
178 /*
179 * Go through them all and get a best one to use.
180 */
181 for (i = 0; i < emu->max_voices; i++) {
182 int state, val;
183
184 vp = &emu->voices[i];
185 state = vp->state;
186
187 if (state == SNDRV_EMUX_ST_OFF)
188 bp = best + OFF;
189 else if (state == SNDRV_EMUX_ST_RELEASED ||
190 state == SNDRV_EMUX_ST_PENDING) {
191 bp = best + RELEASED;
192 val = (EMU8000_CVCF_READ(hw, vp->ch) >> 16) & 0xffff;
193 if (! val)
194 bp = best + OFF;
195 }
196 else if (state & SNDRV_EMUX_ST_ON)
197 bp = best + PLAYING;
198 else
199 continue;
200
201 /* check if sample is finished playing (non-looping only) */
202 if (state != SNDRV_EMUX_ST_OFF &&
203 (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) {
204 val = EMU8000_CCCA_READ(hw, vp->ch) & 0xffffff;
205 if (val >= vp->reg.loopstart)
206 bp = best + OFF;
207 }
208
209 if (vp->time < bp->time) {
210 bp->time = vp->time;
211 bp->voice = i;
212 }
213 }
214
215 for (i = 0; i < END; i++) {
216 if (best[i].voice >= 0) {
217 vp = &emu->voices[best[i].voice];
218 vp->ch = best[i].voice;
219 return vp;
220 }
221 }
222
223 /* not found */
224 return NULL;
225}
226
227/*
228 */
229static int
230start_voice(snd_emux_voice_t *vp)
231{
232 unsigned int temp;
233 int ch;
234 int addr;
235 snd_midi_channel_t *chan;
236 emu8000_t *hw;
237
238 hw = vp->hw;
239 ch = vp->ch;
240 chan = vp->chan;
241
242 /* channel to be silent and idle */
243 EMU8000_DCYSUSV_WRITE(hw, ch, 0x0080);
244 EMU8000_VTFT_WRITE(hw, ch, 0x0000FFFF);
245 EMU8000_CVCF_WRITE(hw, ch, 0x0000FFFF);
246 EMU8000_PTRX_WRITE(hw, ch, 0);
247 EMU8000_CPF_WRITE(hw, ch, 0);
248
249 /* set pitch offset */
250 set_pitch(hw, vp);
251
252 /* set envelope parameters */
253 EMU8000_ENVVAL_WRITE(hw, ch, vp->reg.parm.moddelay);
254 EMU8000_ATKHLD_WRITE(hw, ch, vp->reg.parm.modatkhld);
255 EMU8000_DCYSUS_WRITE(hw, ch, vp->reg.parm.moddcysus);
256 EMU8000_ENVVOL_WRITE(hw, ch, vp->reg.parm.voldelay);
257 EMU8000_ATKHLDV_WRITE(hw, ch, vp->reg.parm.volatkhld);
258 /* decay/sustain parameter for volume envelope is used
259 for triggerg the voice */
260
261 /* cutoff and volume */
262 set_volume(hw, vp);
263
264 /* modulation envelope heights */
265 EMU8000_PEFE_WRITE(hw, ch, vp->reg.parm.pefe);
266
267 /* lfo1/2 delay */
268 EMU8000_LFO1VAL_WRITE(hw, ch, vp->reg.parm.lfo1delay);
269 EMU8000_LFO2VAL_WRITE(hw, ch, vp->reg.parm.lfo2delay);
270
271 /* lfo1 pitch & cutoff shift */
272 set_fmmod(hw, vp);
273 /* lfo1 volume & freq */
274 set_tremfreq(hw, vp);
275 /* lfo2 pitch & freq */
276 set_fm2frq2(hw, vp);
277 /* pan & loop start */
278 set_pan(hw, vp);
279
280 /* chorus & loop end (chorus 8bit, MSB) */
281 addr = vp->reg.loopend - 1;
282 temp = vp->reg.parm.chorus;
283 temp += (int)chan->control[MIDI_CTL_E3_CHORUS_DEPTH] * 9 / 10;
284 LIMITMAX(temp, 255);
285 temp = (temp <<24) | (unsigned int)addr;
286 EMU8000_CSL_WRITE(hw, ch, temp);
287
288 /* Q & current address (Q 4bit value, MSB) */
289 addr = vp->reg.start - 1;
290 temp = vp->reg.parm.filterQ;
291 temp = (temp<<28) | (unsigned int)addr;
292 EMU8000_CCCA_WRITE(hw, ch, temp);
293
294 /* clear unknown registers */
295 EMU8000_00A0_WRITE(hw, ch, 0);
296 EMU8000_0080_WRITE(hw, ch, 0);
297
298 /* reset volume */
299 temp = vp->vtarget << 16;
300 EMU8000_VTFT_WRITE(hw, ch, temp | vp->ftarget);
301 EMU8000_CVCF_WRITE(hw, ch, temp | 0xff00);
302
303 return 0;
304}
305
306/*
307 * Start envelope
308 */
309static void
310trigger_voice(snd_emux_voice_t *vp)
311{
312 int ch = vp->ch;
313 unsigned int temp;
314 emu8000_t *hw;
315
316 hw = vp->hw;
317
318 /* set reverb and pitch target */
319 temp = vp->reg.parm.reverb;
320 temp += (int)vp->chan->control[MIDI_CTL_E1_REVERB_DEPTH] * 9 / 10;
321 LIMITMAX(temp, 255);
322 temp = (temp << 8) | (vp->ptarget << 16) | vp->aaux;
323 EMU8000_PTRX_WRITE(hw, ch, temp);
324 EMU8000_CPF_WRITE(hw, ch, vp->ptarget << 16);
325 EMU8000_DCYSUSV_WRITE(hw, ch, vp->reg.parm.voldcysus);
326}
327
328/*
329 * reset voice parameters
330 */
331static void
332reset_voice(snd_emux_t *emu, int ch)
333{
334 emu8000_t *hw;
335
336 hw = emu->hw;
337 EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F);
338 snd_emu8000_tweak_voice(hw, ch);
339}
340
341/*
342 * Set the pitch of a possibly playing note.
343 */
344static void
345set_pitch(emu8000_t *hw, snd_emux_voice_t *vp)
346{
347 EMU8000_IP_WRITE(hw, vp->ch, vp->apitch);
348}
349
350/*
351 * Set the volume of a possibly already playing note
352 */
353static void
354set_volume(emu8000_t *hw, snd_emux_voice_t *vp)
355{
356 int ifatn;
357
358 ifatn = (unsigned char)vp->acutoff;
359 ifatn = (ifatn << 8);
360 ifatn |= (unsigned char)vp->avol;
361 EMU8000_IFATN_WRITE(hw, vp->ch, ifatn);
362}
363
364/*
365 * Set pan and loop start address.
366 */
367static void
368set_pan(emu8000_t *hw, snd_emux_voice_t *vp)
369{
370 unsigned int temp;
371
372 temp = ((unsigned int)vp->apan<<24) | ((unsigned int)vp->reg.loopstart - 1);
373 EMU8000_PSST_WRITE(hw, vp->ch, temp);
374}
375
376#define MOD_SENSE 18
377
378static void
379set_fmmod(emu8000_t *hw, snd_emux_voice_t *vp)
380{
381 unsigned short fmmod;
382 short pitch;
383 unsigned char cutoff;
384 int modulation;
385
386 pitch = (char)(vp->reg.parm.fmmod>>8);
387 cutoff = (vp->reg.parm.fmmod & 0xff);
388 modulation = vp->chan->gm_modulation + vp->chan->midi_pressure;
389 pitch += (MOD_SENSE * modulation) / 1200;
390 LIMITVALUE(pitch, -128, 127);
391 fmmod = ((unsigned char)pitch<<8) | cutoff;
392 EMU8000_FMMOD_WRITE(hw, vp->ch, fmmod);
393}
394
395/* set tremolo (lfo1) volume & frequency */
396static void
397set_tremfreq(emu8000_t *hw, snd_emux_voice_t *vp)
398{
399 EMU8000_TREMFRQ_WRITE(hw, vp->ch, vp->reg.parm.tremfrq);
400}
401
402/* set lfo2 pitch & frequency */
403static void
404set_fm2frq2(emu8000_t *hw, snd_emux_voice_t *vp)
405{
406 unsigned short fm2frq2;
407 short pitch;
408 unsigned char freq;
409 int modulation;
410
411 pitch = (char)(vp->reg.parm.fm2frq2>>8);
412 freq = vp->reg.parm.fm2frq2 & 0xff;
413 modulation = vp->chan->gm_modulation + vp->chan->midi_pressure;
414 pitch += (MOD_SENSE * modulation) / 1200;
415 LIMITVALUE(pitch, -128, 127);
416 fm2frq2 = ((unsigned char)pitch<<8) | freq;
417 EMU8000_FM2FRQ2_WRITE(hw, vp->ch, fm2frq2);
418}
419
420/* set filterQ */
421static void
422set_filterQ(emu8000_t *hw, snd_emux_voice_t *vp)
423{
424 unsigned int addr;
425 addr = EMU8000_CCCA_READ(hw, vp->ch) & 0xffffff;
426 addr |= (vp->reg.parm.filterQ << 28);
427 EMU8000_CCCA_WRITE(hw, vp->ch, addr);
428}
429
430/*
431 * set the envelope & LFO parameters to the default values
432 */
433static void
434snd_emu8000_tweak_voice(emu8000_t *emu, int i)
435{
436 /* set all mod/vol envelope shape to minimum */
437 EMU8000_ENVVOL_WRITE(emu, i, 0x8000);
438 EMU8000_ENVVAL_WRITE(emu, i, 0x8000);
439 EMU8000_DCYSUS_WRITE(emu, i, 0x7F7F);
440 EMU8000_ATKHLDV_WRITE(emu, i, 0x7F7F);
441 EMU8000_ATKHLD_WRITE(emu, i, 0x7F7F);
442 EMU8000_PEFE_WRITE(emu, i, 0); /* mod envelope height to zero */
443 EMU8000_LFO1VAL_WRITE(emu, i, 0x8000); /* no delay for LFO1 */
444 EMU8000_LFO2VAL_WRITE(emu, i, 0x8000);
445 EMU8000_IP_WRITE(emu, i, 0xE000); /* no pitch shift */
446 EMU8000_IFATN_WRITE(emu, i, 0xFF00); /* volume to minimum */
447 EMU8000_FMMOD_WRITE(emu, i, 0);
448 EMU8000_TREMFRQ_WRITE(emu, i, 0);
449 EMU8000_FM2FRQ2_WRITE(emu, i, 0);
450}
451
452/*
453 * sysex callback
454 */
455static void
456sysex(snd_emux_t *emu, char *buf, int len, int parsed, snd_midi_channel_set_t *chset)
457{
458 emu8000_t *hw;
459
460 hw = emu->hw;
461
462 switch (parsed) {
463 case SNDRV_MIDI_SYSEX_GS_CHORUS_MODE:
464 hw->chorus_mode = chset->gs_chorus_mode;
465 snd_emu8000_update_chorus_mode(hw);
466 break;
467
468 case SNDRV_MIDI_SYSEX_GS_REVERB_MODE:
469 hw->reverb_mode = chset->gs_reverb_mode;
470 snd_emu8000_update_reverb_mode(hw);
471 break;
472 }
473}
474
475
476#ifdef CONFIG_SND_SEQUENCER_OSS
477/*
478 * OSS ioctl callback
479 */
480static int
481oss_ioctl(snd_emux_t *emu, int cmd, int p1, int p2)
482{
483 emu8000_t *hw;
484
485 hw = emu->hw;
486
487 switch (cmd) {
488 case _EMUX_OSS_REVERB_MODE:
489 hw->reverb_mode = p1;
490 snd_emu8000_update_reverb_mode(hw);
491 break;
492
493 case _EMUX_OSS_CHORUS_MODE:
494 hw->chorus_mode = p1;
495 snd_emu8000_update_chorus_mode(hw);
496 break;
497
498 case _EMUX_OSS_INITIALIZE_CHIP:
499 /* snd_emu8000_init(hw); */ /*ignored*/
500 break;
501
502 case _EMUX_OSS_EQUALIZER:
503 hw->bass_level = p1;
504 hw->treble_level = p2;
505 snd_emu8000_update_equalizer(hw);
506 break;
507 }
508 return 0;
509}
510#endif
511
512
513/*
514 * additional patch keys
515 */
516
517#define SNDRV_EMU8000_LOAD_CHORUS_FX 0x10 /* optarg=mode */
518#define SNDRV_EMU8000_LOAD_REVERB_FX 0x11 /* optarg=mode */
519
520
521/*
522 * callback routine
523 */
524
525static int
526load_fx(snd_emux_t *emu, int type, int mode, const void __user *buf, long len)
527{
528 emu8000_t *hw;
529 hw = emu->hw;
530
531 /* skip header */
532 buf += 16;
533 len -= 16;
534
535 switch (type) {
536 case SNDRV_EMU8000_LOAD_CHORUS_FX:
537 return snd_emu8000_load_chorus_fx(hw, mode, buf, len);
538 case SNDRV_EMU8000_LOAD_REVERB_FX:
539 return snd_emu8000_load_reverb_fx(hw, mode, buf, len);
540 }
541 return -EINVAL;
542}
543
diff --git a/sound/isa/sb/emu8000_local.h b/sound/isa/sb/emu8000_local.h
new file mode 100644
index 000000000000..ea4996a895fc
--- /dev/null
+++ b/sound/isa/sb/emu8000_local.h
@@ -0,0 +1,43 @@
1#ifndef __EMU8000_LOCAL_H
2#define __EMU8000_LOCAL_H
3/*
4 * Local defininitons for the emu8000 (AWE32/64)
5 *
6 * Copyright (C) 1999 Steve Ratcliffe
7 * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include <sound/driver.h>
25#include <linux/wait.h>
26#include <linux/sched.h>
27#include <linux/slab.h>
28#include <sound/core.h>
29#include <sound/emu8000.h>
30#include <sound/emu8000_reg.h>
31
32/* emu8000_patch.c */
33int snd_emu8000_sample_new(snd_emux_t *rec, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr, const void __user *data, long count);
34int snd_emu8000_sample_free(snd_emux_t *rec, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr);
35void snd_emu8000_sample_reset(snd_emux_t *rec);
36
37/* emu8000_callback.c */
38void snd_emu8000_ops_setup(emu8000_t *emu);
39
40/* emu8000_pcm.c */
41int snd_emu8000_pcm_new(snd_card_t *card, emu8000_t *emu, int index);
42
43#endif /* __EMU8000_LOCAL_H */
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
new file mode 100644
index 000000000000..4afc4a1bc140
--- /dev/null
+++ b/sound/isa/sb/emu8000_patch.c
@@ -0,0 +1,303 @@
1/*
2 * Patch routines for the emu8000 (AWE32/64)
3 *
4 * Copyright (C) 1999 Steve Ratcliffe
5 * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include "emu8000_local.h"
23#include <asm/uaccess.h>
24#include <linux/moduleparam.h>
25
26static int emu8000_reset_addr = 0;
27module_param(emu8000_reset_addr, int, 0444);
28MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)");
29
30
31/*
32 * Open up channels.
33 */
34static int
35snd_emu8000_open_dma(emu8000_t *emu, int write)
36{
37 int i;
38
39 /* reserve all 30 voices for loading */
40 for (i = 0; i < EMU8000_DRAM_VOICES; i++) {
41 snd_emux_lock_voice(emu->emu, i);
42 snd_emu8000_dma_chan(emu, i, write);
43 }
44
45 /* assign voice 31 and 32 to ROM */
46 EMU8000_VTFT_WRITE(emu, 30, 0);
47 EMU8000_PSST_WRITE(emu, 30, 0x1d8);
48 EMU8000_CSL_WRITE(emu, 30, 0x1e0);
49 EMU8000_CCCA_WRITE(emu, 30, 0x1d8);
50 EMU8000_VTFT_WRITE(emu, 31, 0);
51 EMU8000_PSST_WRITE(emu, 31, 0x1d8);
52 EMU8000_CSL_WRITE(emu, 31, 0x1e0);
53 EMU8000_CCCA_WRITE(emu, 31, 0x1d8);
54
55 return 0;
56}
57
58/*
59 * Close all dram channels.
60 */
61static void
62snd_emu8000_close_dma(emu8000_t *emu)
63{
64 int i;
65
66 for (i = 0; i < EMU8000_DRAM_VOICES; i++) {
67 snd_emu8000_dma_chan(emu, i, EMU8000_RAM_CLOSE);
68 snd_emux_unlock_voice(emu->emu, i);
69 }
70}
71
72/*
73 */
74
75#define BLANK_LOOP_START 4
76#define BLANK_LOOP_END 8
77#define BLANK_LOOP_SIZE 12
78#define BLANK_HEAD_SIZE 48
79
80/*
81 * Read a word from userland, taking care of conversions from
82 * 8bit samples etc.
83 */
84static unsigned short
85read_word(const void __user *buf, int offset, int mode)
86{
87 unsigned short c;
88 if (mode & SNDRV_SFNT_SAMPLE_8BITS) {
89 unsigned char cc;
90 get_user(cc, (unsigned char __user *)buf + offset);
91 c = cc << 8; /* convert 8bit -> 16bit */
92 } else {
93#ifdef SNDRV_LITTLE_ENDIAN
94 get_user(c, (unsigned short __user *)buf + offset);
95#else
96 unsigned short cc;
97 get_user(cc, (unsigned short __user *)buf + offset);
98 c = swab16(cc);
99#endif
100 }
101 if (mode & SNDRV_SFNT_SAMPLE_UNSIGNED)
102 c ^= 0x8000; /* unsigned -> signed */
103 return c;
104}
105
106/*
107 */
108static void
109snd_emu8000_write_wait(emu8000_t *emu)
110{
111 while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
112 set_current_state(TASK_INTERRUPTIBLE);
113 schedule_timeout(1);
114 if (signal_pending(current))
115 break;
116 }
117}
118
119/*
120 * write sample word data
121 *
122 * You should not have to keep resetting the address each time
123 * as the chip is supposed to step on the next address automatically.
124 * It mostly does, but during writes of some samples at random it
125 * completely loses words (every one in 16 roughly but with no
126 * obvious pattern).
127 *
128 * This is therefore much slower than need be, but is at least
129 * working.
130 */
131inline static void
132write_word(emu8000_t *emu, int *offset, unsigned short data)
133{
134 if (emu8000_reset_addr) {
135 if (emu8000_reset_addr > 1)
136 snd_emu8000_write_wait(emu);
137 EMU8000_SMALW_WRITE(emu, *offset);
138 }
139 EMU8000_SMLD_WRITE(emu, data);
140 *offset += 1;
141}
142
143/*
144 * Write the sample to EMU800 memory. This routine is invoked out of
145 * the generic soundfont routines as a callback.
146 */
147int
148snd_emu8000_sample_new(snd_emux_t *rec, snd_sf_sample_t *sp,
149 snd_util_memhdr_t *hdr, const void __user *data, long count)
150{
151 int i;
152 int rc;
153 int offset;
154 int truesize;
155 int dram_offset, dram_start;
156 emu8000_t *emu;
157
158 emu = rec->hw;
159 snd_assert(sp != NULL, return -EINVAL);
160
161 if (sp->v.size == 0)
162 return 0;
163
164 /* be sure loop points start < end */
165 if (sp->v.loopstart > sp->v.loopend) {
166 int tmp = sp->v.loopstart;
167 sp->v.loopstart = sp->v.loopend;
168 sp->v.loopend = tmp;
169 }
170
171 /* compute true data size to be loaded */
172 truesize = sp->v.size;
173 if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
174 truesize += sp->v.loopend - sp->v.loopstart;
175 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
176 truesize += BLANK_LOOP_SIZE;
177
178 sp->block = snd_util_mem_alloc(hdr, truesize * 2);
179 if (sp->block == NULL) {
180 /*snd_printd("EMU8000: out of memory\n");*/
181 /* not ENOMEM (for compatibility) */
182 return -ENOSPC;
183 }
184
185 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {
186 if (!access_ok(VERIFY_READ, data, sp->v.size))
187 return -EFAULT;
188 } else {
189 if (!access_ok(VERIFY_READ, data, sp->v.size * 2))
190 return -EFAULT;
191 }
192
193 /* recalculate address offset */
194 sp->v.end -= sp->v.start;
195 sp->v.loopstart -= sp->v.start;
196 sp->v.loopend -= sp->v.start;
197 sp->v.start = 0;
198
199 /* dram position (in word) -- mem_offset is byte */
200 dram_offset = EMU8000_DRAM_OFFSET + (sp->block->offset >> 1);
201 dram_start = dram_offset;
202
203 /* set the total size (store onto obsolete checksum value) */
204 sp->v.truesize = truesize * 2; /* in bytes */
205
206 snd_emux_terminate_all(emu->emu);
207 if ((rc = snd_emu8000_open_dma(emu, EMU8000_RAM_WRITE)) != 0)
208 return rc;
209
210 /* Set the address to start writing at */
211 snd_emu8000_write_wait(emu);
212 EMU8000_SMALW_WRITE(emu, dram_offset);
213
214 /*snd_emu8000_init_fm(emu);*/
215
216#if 0
217 /* first block - write 48 samples for silence */
218 if (! sp->block->offset) {
219 for (i = 0; i < BLANK_HEAD_SIZE; i++) {
220 write_word(emu, &dram_offset, 0);
221 }
222 }
223#endif
224
225 offset = 0;
226 for (i = 0; i < sp->v.size; i++) {
227 unsigned short s;
228
229 s = read_word(data, offset, sp->v.mode_flags);
230 offset++;
231 write_word(emu, &dram_offset, s);
232
233 /* we may take too long time in this loop.
234 * so give controls back to kernel if needed.
235 */
236 cond_resched();
237
238 if (i == sp->v.loopend &&
239 (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)))
240 {
241 int looplen = sp->v.loopend - sp->v.loopstart;
242 int k;
243
244 /* copy reverse loop */
245 for (k = 1; k <= looplen; k++) {
246 s = read_word(data, offset - k, sp->v.mode_flags);
247 write_word(emu, &dram_offset, s);
248 }
249 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
250 sp->v.loopend += looplen;
251 } else {
252 sp->v.loopstart += looplen;
253 sp->v.loopend += looplen;
254 }
255 sp->v.end += looplen;
256 }
257 }
258
259 /* if no blank loop is attached in the sample, add it */
260 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
261 for (i = 0; i < BLANK_LOOP_SIZE; i++) {
262 write_word(emu, &dram_offset, 0);
263 }
264 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
265 sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
266 sp->v.loopend = sp->v.end + BLANK_LOOP_END;
267 }
268 }
269
270 /* add dram offset */
271 sp->v.start += dram_start;
272 sp->v.end += dram_start;
273 sp->v.loopstart += dram_start;
274 sp->v.loopend += dram_start;
275
276 snd_emu8000_close_dma(emu);
277 snd_emu8000_init_fm(emu);
278
279 return 0;
280}
281
282/*
283 * free a sample block
284 */
285int
286snd_emu8000_sample_free(snd_emux_t *rec, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr)
287{
288 if (sp->block) {
289 snd_util_mem_free(hdr, sp->block);
290 sp->block = NULL;
291 }
292 return 0;
293}
294
295
296/*
297 * sample_reset callback - terminate voices
298 */
299void
300snd_emu8000_sample_reset(snd_emux_t *rec)
301{
302 snd_emux_terminate_all(rec);
303}
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
new file mode 100644
index 000000000000..db5eb8b55058
--- /dev/null
+++ b/sound/isa/sb/emu8000_pcm.c
@@ -0,0 +1,704 @@
1/*
2 * pcm emulation on emu8000 wavetable
3 *
4 * Copyright (C) 2002 Takashi Iwai <tiwai@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "emu8000_local.h"
22#include <linux/init.h>
23#include <sound/initval.h>
24#include <sound/pcm.h>
25
26/*
27 * define the following if you want to use this pcm with non-interleaved mode
28 */
29/* #define USE_NONINTERLEAVE */
30
31/* NOTE: for using the non-interleaved mode with alsa-lib, you have to set
32 * mmap_emulation flag to 1 in your .asoundrc, such like
33 *
34 * pcm.emu8k {
35 * type plug
36 * slave.pcm {
37 * type hw
38 * card 0
39 * device 1
40 * mmap_emulation 1
41 * }
42 * }
43 *
44 * besides, for the time being, the non-interleaved mode doesn't work well on
45 * alsa-lib...
46 */
47
48
49typedef struct snd_emu8k_pcm emu8k_pcm_t;
50
51struct snd_emu8k_pcm {
52 emu8000_t *emu;
53 snd_pcm_substream_t *substream;
54
55 unsigned int allocated_bytes;
56 snd_util_memblk_t *block;
57 unsigned int offset;
58 unsigned int buf_size;
59 unsigned int period_size;
60 unsigned int loop_start[2];
61 unsigned int pitch;
62 int panning[2];
63 int last_ptr;
64 int period_pos;
65 int voices;
66 unsigned int dram_opened: 1;
67 unsigned int running: 1;
68 unsigned int timer_running: 1;
69 struct timer_list timer;
70 spinlock_t timer_lock;
71};
72
73#define LOOP_BLANK_SIZE 8
74
75
76/*
77 * open up channels for the simultaneous data transfer and playback
78 */
79static int
80emu8k_open_dram_for_pcm(emu8000_t *emu, int channels)
81{
82 int i;
83
84 /* reserve up to 2 voices for playback */
85 snd_emux_lock_voice(emu->emu, 0);
86 if (channels > 1)
87 snd_emux_lock_voice(emu->emu, 1);
88
89 /* reserve 28 voices for loading */
90 for (i = channels + 1; i < EMU8000_DRAM_VOICES; i++) {
91 unsigned int mode = EMU8000_RAM_WRITE;
92 snd_emux_lock_voice(emu->emu, i);
93#ifndef USE_NONINTERLEAVE
94 if (channels > 1 && (i & 1) != 0)
95 mode |= EMU8000_RAM_RIGHT;
96#endif
97 snd_emu8000_dma_chan(emu, i, mode);
98 }
99
100 /* assign voice 31 and 32 to ROM */
101 EMU8000_VTFT_WRITE(emu, 30, 0);
102 EMU8000_PSST_WRITE(emu, 30, 0x1d8);
103 EMU8000_CSL_WRITE(emu, 30, 0x1e0);
104 EMU8000_CCCA_WRITE(emu, 30, 0x1d8);
105 EMU8000_VTFT_WRITE(emu, 31, 0);
106 EMU8000_PSST_WRITE(emu, 31, 0x1d8);
107 EMU8000_CSL_WRITE(emu, 31, 0x1e0);
108 EMU8000_CCCA_WRITE(emu, 31, 0x1d8);
109
110 return 0;
111}
112
113/*
114 */
115static void
116snd_emu8000_write_wait(emu8000_t *emu, int can_schedule)
117{
118 while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
119 if (can_schedule) {
120 set_current_state(TASK_INTERRUPTIBLE);
121 schedule_timeout(1);
122 if (signal_pending(current))
123 break;
124 }
125 }
126}
127
128/*
129 * close all channels
130 */
131static void
132emu8k_close_dram(emu8000_t *emu)
133{
134 int i;
135
136 for (i = 0; i < 2; i++)
137 snd_emux_unlock_voice(emu->emu, i);
138 for (; i < EMU8000_DRAM_VOICES; i++) {
139 snd_emu8000_dma_chan(emu, i, EMU8000_RAM_CLOSE);
140 snd_emux_unlock_voice(emu->emu, i);
141 }
142}
143
144/*
145 * convert Hz to AWE32 rate offset (see emux/soundfont.c)
146 */
147
148#define OFFSET_SAMPLERATE 1011119 /* base = 44100 */
149#define SAMPLERATE_RATIO 4096
150
151static int calc_rate_offset(int hz)
152{
153 return snd_sf_linear_to_log(hz, OFFSET_SAMPLERATE, SAMPLERATE_RATIO);
154}
155
156
157/*
158 */
159
160static snd_pcm_hardware_t emu8k_pcm_hw = {
161#ifdef USE_NONINTERLEAVE
162 .info = SNDRV_PCM_INFO_NONINTERLEAVED,
163#else
164 .info = SNDRV_PCM_INFO_INTERLEAVED,
165#endif
166 .formats = SNDRV_PCM_FMTBIT_S16_LE,
167 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
168 .rate_min = 4000,
169 .rate_max = 48000,
170 .channels_min = 1,
171 .channels_max = 2,
172 .buffer_bytes_max = (128*1024),
173 .period_bytes_min = 1024,
174 .period_bytes_max = (128*1024),
175 .periods_min = 2,
176 .periods_max = 1024,
177 .fifo_size = 0,
178
179};
180
181/*
182 * get the current position at the given channel from CCCA register
183 */
184static inline int emu8k_get_curpos(emu8k_pcm_t *rec, int ch)
185{
186 int val = EMU8000_CCCA_READ(rec->emu, ch) & 0xfffffff;
187 val -= rec->loop_start[ch] - 1;
188 return val;
189}
190
191
192/*
193 * timer interrupt handler
194 * check the current position and update the period if necessary.
195 */
196static void emu8k_pcm_timer_func(unsigned long data)
197{
198 emu8k_pcm_t *rec = (emu8k_pcm_t *)data;
199 int ptr, delta;
200
201 spin_lock(&rec->timer_lock);
202 /* update the current pointer */
203 ptr = emu8k_get_curpos(rec, 0);
204 if (ptr < rec->last_ptr)
205 delta = ptr + rec->buf_size - rec->last_ptr;
206 else
207 delta = ptr - rec->last_ptr;
208 rec->period_pos += delta;
209 rec->last_ptr = ptr;
210
211 /* reprogram timer */
212 rec->timer.expires = jiffies + 1;
213 add_timer(&rec->timer);
214
215 /* update period */
216 if (rec->period_pos >= (int)rec->period_size) {
217 rec->period_pos %= rec->period_size;
218 spin_unlock(&rec->timer_lock);
219 snd_pcm_period_elapsed(rec->substream);
220 return;
221 }
222 spin_unlock(&rec->timer_lock);
223}
224
225
226/*
227 * open pcm
228 * creating an instance here
229 */
230static int emu8k_pcm_open(snd_pcm_substream_t *subs)
231{
232 emu8000_t *emu = snd_pcm_substream_chip(subs);
233 emu8k_pcm_t *rec;
234 snd_pcm_runtime_t *runtime = subs->runtime;
235
236 rec = kcalloc(1, sizeof(*rec), GFP_KERNEL);
237 if (! rec)
238 return -ENOMEM;
239
240 rec->emu = emu;
241 rec->substream = subs;
242 runtime->private_data = rec;
243
244 spin_lock_init(&rec->timer_lock);
245 init_timer(&rec->timer);
246 rec->timer.function = emu8k_pcm_timer_func;
247 rec->timer.data = (unsigned long)rec;
248
249 runtime->hw = emu8k_pcm_hw;
250 runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3;
251 runtime->hw.period_bytes_max = runtime->hw.buffer_bytes_max / 2;
252
253 /* use timer to update periods.. (specified in msec) */
254 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
255 (1000000 + HZ - 1) / HZ, UINT_MAX);
256
257 return 0;
258}
259
260static int emu8k_pcm_close(snd_pcm_substream_t *subs)
261{
262 emu8k_pcm_t *rec = subs->runtime->private_data;
263 kfree(rec);
264 subs->runtime->private_data = NULL;
265 return 0;
266}
267
268/*
269 * calculate pitch target
270 */
271static int calc_pitch_target(int pitch)
272{
273 int ptarget = 1 << (pitch >> 12);
274 if (pitch & 0x800) ptarget += (ptarget * 0x102e) / 0x2710;
275 if (pitch & 0x400) ptarget += (ptarget * 0x764) / 0x2710;
276 if (pitch & 0x200) ptarget += (ptarget * 0x389) / 0x2710;
277 ptarget += (ptarget >> 1);
278 if (ptarget > 0xffff) ptarget = 0xffff;
279 return ptarget;
280}
281
282/*
283 * set up the voice
284 */
285static void setup_voice(emu8k_pcm_t *rec, int ch)
286{
287 emu8000_t *hw = rec->emu;
288 unsigned int temp;
289
290 /* channel to be silent and idle */
291 EMU8000_DCYSUSV_WRITE(hw, ch, 0x0080);
292 EMU8000_VTFT_WRITE(hw, ch, 0x0000FFFF);
293 EMU8000_CVCF_WRITE(hw, ch, 0x0000FFFF);
294 EMU8000_PTRX_WRITE(hw, ch, 0);
295 EMU8000_CPF_WRITE(hw, ch, 0);
296
297 /* pitch offset */
298 EMU8000_IP_WRITE(hw, ch, rec->pitch);
299 /* set envelope parameters */
300 EMU8000_ENVVAL_WRITE(hw, ch, 0x8000);
301 EMU8000_ATKHLD_WRITE(hw, ch, 0x7f7f);
302 EMU8000_DCYSUS_WRITE(hw, ch, 0x7f7f);
303 EMU8000_ENVVOL_WRITE(hw, ch, 0x8000);
304 EMU8000_ATKHLDV_WRITE(hw, ch, 0x7f7f);
305 /* decay/sustain parameter for volume envelope is used
306 for triggerg the voice */
307 /* modulation envelope heights */
308 EMU8000_PEFE_WRITE(hw, ch, 0x0);
309 /* lfo1/2 delay */
310 EMU8000_LFO1VAL_WRITE(hw, ch, 0x8000);
311 EMU8000_LFO2VAL_WRITE(hw, ch, 0x8000);
312 /* lfo1 pitch & cutoff shift */
313 EMU8000_FMMOD_WRITE(hw, ch, 0);
314 /* lfo1 volume & freq */
315 EMU8000_TREMFRQ_WRITE(hw, ch, 0);
316 /* lfo2 pitch & freq */
317 EMU8000_FM2FRQ2_WRITE(hw, ch, 0);
318 /* pan & loop start */
319 temp = rec->panning[ch];
320 temp = (temp <<24) | ((unsigned int)rec->loop_start[ch] - 1);
321 EMU8000_PSST_WRITE(hw, ch, temp);
322 /* chorus & loop end (chorus 8bit, MSB) */
323 temp = 0; // chorus
324 temp = (temp << 24) | ((unsigned int)rec->loop_start[ch] + rec->buf_size - 1);
325 EMU8000_CSL_WRITE(hw, ch, temp);
326 /* Q & current address (Q 4bit value, MSB) */
327 temp = 0; // filterQ
328 temp = (temp << 28) | ((unsigned int)rec->loop_start[ch] - 1);
329 EMU8000_CCCA_WRITE(hw, ch, temp);
330 /* clear unknown registers */
331 EMU8000_00A0_WRITE(hw, ch, 0);
332 EMU8000_0080_WRITE(hw, ch, 0);
333}
334
335/*
336 * trigger the voice
337 */
338static void start_voice(emu8k_pcm_t *rec, int ch)
339{
340 unsigned long flags;
341 emu8000_t *hw = rec->emu;
342 unsigned int temp, aux;
343 int pt = calc_pitch_target(rec->pitch);
344
345 /* cutoff and volume */
346 EMU8000_IFATN_WRITE(hw, ch, 0xff00);
347 EMU8000_VTFT_WRITE(hw, ch, 0xffff);
348 EMU8000_CVCF_WRITE(hw, ch, 0xffff);
349 /* trigger envelope */
350 EMU8000_DCYSUSV_WRITE(hw, ch, 0x7f7f);
351 /* set reverb and pitch target */
352 temp = 0; // reverb
353 if (rec->panning[ch] == 0)
354 aux = 0xff;
355 else
356 aux = (-rec->panning[ch]) & 0xff;
357 temp = (temp << 8) | (pt << 16) | aux;
358 EMU8000_PTRX_WRITE(hw, ch, temp);
359 EMU8000_CPF_WRITE(hw, ch, pt << 16);
360
361 /* start timer */
362 spin_lock_irqsave(&rec->timer_lock, flags);
363 if (! rec->timer_running) {
364 rec->timer.expires = jiffies + 1;
365 add_timer(&rec->timer);
366 rec->timer_running = 1;
367 }
368 spin_unlock_irqrestore(&rec->timer_lock, flags);
369}
370
371/*
372 * stop the voice immediately
373 */
374static void stop_voice(emu8k_pcm_t *rec, int ch)
375{
376 unsigned long flags;
377 emu8000_t *hw = rec->emu;
378
379 EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F);
380
381 /* stop timer */
382 spin_lock_irqsave(&rec->timer_lock, flags);
383 if (rec->timer_running) {
384 del_timer(&rec->timer);
385 rec->timer_running = 0;
386 }
387 spin_unlock_irqrestore(&rec->timer_lock, flags);
388}
389
390static int emu8k_pcm_trigger(snd_pcm_substream_t *subs, int cmd)
391{
392 emu8k_pcm_t *rec = subs->runtime->private_data;
393 int ch;
394
395 switch (cmd) {
396 case SNDRV_PCM_TRIGGER_START:
397 for (ch = 0; ch < rec->voices; ch++)
398 start_voice(rec, ch);
399 rec->running = 1;
400 break;
401 case SNDRV_PCM_TRIGGER_STOP:
402 rec->running = 0;
403 for (ch = 0; ch < rec->voices; ch++)
404 stop_voice(rec, ch);
405 break;
406 default:
407 return -EINVAL;
408 }
409 return 0;
410}
411
412
413/*
414 * copy / silence ops
415 */
416
417/*
418 * this macro should be inserted in the copy/silence loops
419 * to reduce the latency. without this, the system will hang up
420 * during the whole loop.
421 */
422#define CHECK_SCHEDULER() \
423do { \
424 cond_resched();\
425 if (signal_pending(current))\
426 return -EAGAIN;\
427} while (0)
428
429
430#ifdef USE_NONINTERLEAVE
431/* copy one channel block */
432static int emu8k_transfer_block(emu8000_t *emu, int offset, unsigned short *buf, int count)
433{
434 EMU8000_SMALW_WRITE(emu, offset);
435 while (count > 0) {
436 unsigned short sval;
437 CHECK_SCHEDULER();
438 get_user(sval, buf);
439 EMU8000_SMLD_WRITE(emu, sval);
440 buf++;
441 count--;
442 }
443 return 0;
444}
445
446static int emu8k_pcm_copy(snd_pcm_substream_t *subs,
447 int voice,
448 snd_pcm_uframes_t pos,
449 void *src,
450 snd_pcm_uframes_t count)
451{
452 emu8k_pcm_t *rec = subs->runtime->private_data;
453 emu8000_t *emu = rec->emu;
454
455 snd_emu8000_write_wait(emu, 1);
456 if (voice == -1) {
457 unsigned short *buf = src;
458 int i, err;
459 count /= rec->voices;
460 for (i = 0; i < rec->voices; i++) {
461 err = emu8k_transfer_block(emu, pos + rec->loop_start[i], buf, count);
462 if (err < 0)
463 return err;
464 buf += count;
465 }
466 return 0;
467 } else {
468 return emu8k_transfer_block(emu, pos + rec->loop_start[voice], src, count);
469 }
470}
471
472/* make a channel block silence */
473static int emu8k_silence_block(emu8000_t *emu, int offset, int count)
474{
475 EMU8000_SMALW_WRITE(emu, offset);
476 while (count > 0) {
477 CHECK_SCHEDULER();
478 EMU8000_SMLD_WRITE(emu, 0);
479 count--;
480 }
481 return 0;
482}
483
484static int emu8k_pcm_silence(snd_pcm_substream_t *subs,
485 int voice,
486 snd_pcm_uframes_t pos,
487 snd_pcm_uframes_t count)
488{
489 emu8k_pcm_t *rec = subs->runtime->private_data;
490 emu8000_t *emu = rec->emu;
491
492 snd_emu8000_write_wait(emu, 1);
493 if (voice == -1 && rec->voices == 1)
494 voice = 0;
495 if (voice == -1) {
496 int err;
497 err = emu8k_silence_block(emu, pos + rec->loop_start[0], count / 2);
498 if (err < 0)
499 return err;
500 return emu8k_silence_block(emu, pos + rec->loop_start[1], count / 2);
501 } else {
502 return emu8k_silence_block(emu, pos + rec->loop_start[voice], count);
503 }
504}
505
506#else /* interleave */
507
508/*
509 * copy the interleaved data can be done easily by using
510 * DMA "left" and "right" channels on emu8k engine.
511 */
512static int emu8k_pcm_copy(snd_pcm_substream_t *subs,
513 int voice,
514 snd_pcm_uframes_t pos,
515 void __user *src,
516 snd_pcm_uframes_t count)
517{
518 emu8k_pcm_t *rec = subs->runtime->private_data;
519 emu8000_t *emu = rec->emu;
520 unsigned short __user *buf = src;
521
522 snd_emu8000_write_wait(emu, 1);
523 EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]);
524 if (rec->voices > 1)
525 EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]);
526
527 while (count-- > 0) {
528 unsigned short sval;
529 CHECK_SCHEDULER();
530 get_user(sval, buf);
531 EMU8000_SMLD_WRITE(emu, sval);
532 buf++;
533 if (rec->voices > 1) {
534 CHECK_SCHEDULER();
535 get_user(sval, buf);
536 EMU8000_SMRD_WRITE(emu, sval);
537 buf++;
538 }
539 }
540 return 0;
541}
542
543static int emu8k_pcm_silence(snd_pcm_substream_t *subs,
544 int voice,
545 snd_pcm_uframes_t pos,
546 snd_pcm_uframes_t count)
547{
548 emu8k_pcm_t *rec = subs->runtime->private_data;
549 emu8000_t *emu = rec->emu;
550
551 snd_emu8000_write_wait(emu, 1);
552 EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos);
553 if (rec->voices > 1)
554 EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos);
555 while (count-- > 0) {
556 CHECK_SCHEDULER();
557 EMU8000_SMLD_WRITE(emu, 0);
558 if (rec->voices > 1) {
559 CHECK_SCHEDULER();
560 EMU8000_SMRD_WRITE(emu, 0);
561 }
562 }
563 return 0;
564}
565#endif
566
567
568/*
569 * allocate a memory block
570 */
571static int emu8k_pcm_hw_params(snd_pcm_substream_t *subs,
572 snd_pcm_hw_params_t *hw_params)
573{
574 emu8k_pcm_t *rec = subs->runtime->private_data;
575
576 if (rec->block) {
577 /* reallocation - release the old block */
578 snd_util_mem_free(rec->emu->memhdr, rec->block);
579 rec->block = NULL;
580 }
581
582 rec->allocated_bytes = params_buffer_bytes(hw_params) + LOOP_BLANK_SIZE * 4;
583 rec->block = snd_util_mem_alloc(rec->emu->memhdr, rec->allocated_bytes);
584 if (! rec->block)
585 return -ENOMEM;
586 rec->offset = EMU8000_DRAM_OFFSET + (rec->block->offset >> 1); /* in word */
587 /* at least dma_bytes must be set for non-interleaved mode */
588 subs->dma_buffer.bytes = params_buffer_bytes(hw_params);
589
590 return 0;
591}
592
593/*
594 * free the memory block
595 */
596static int emu8k_pcm_hw_free(snd_pcm_substream_t *subs)
597{
598 emu8k_pcm_t *rec = subs->runtime->private_data;
599
600 if (rec->block) {
601 int ch;
602 for (ch = 0; ch < rec->voices; ch++)
603 stop_voice(rec, ch); // to be sure
604 if (rec->dram_opened)
605 emu8k_close_dram(rec->emu);
606 snd_util_mem_free(rec->emu->memhdr, rec->block);
607 rec->block = NULL;
608 }
609 return 0;
610}
611
612/*
613 */
614static int emu8k_pcm_prepare(snd_pcm_substream_t *subs)
615{
616 emu8k_pcm_t *rec = subs->runtime->private_data;
617
618 rec->pitch = 0xe000 + calc_rate_offset(subs->runtime->rate);
619 rec->last_ptr = 0;
620 rec->period_pos = 0;
621
622 rec->buf_size = subs->runtime->buffer_size;
623 rec->period_size = subs->runtime->period_size;
624 rec->voices = subs->runtime->channels;
625 rec->loop_start[0] = rec->offset + LOOP_BLANK_SIZE;
626 if (rec->voices > 1)
627 rec->loop_start[1] = rec->loop_start[0] + rec->buf_size + LOOP_BLANK_SIZE;
628 if (rec->voices > 1) {
629 rec->panning[0] = 0xff;
630 rec->panning[1] = 0x00;
631 } else
632 rec->panning[0] = 0x80;
633
634 if (! rec->dram_opened) {
635 int err, i, ch;
636
637 snd_emux_terminate_all(rec->emu->emu);
638 if ((err = emu8k_open_dram_for_pcm(rec->emu, rec->voices)) != 0)
639 return err;
640 rec->dram_opened = 1;
641
642 /* clear loop blanks */
643 snd_emu8000_write_wait(rec->emu, 0);
644 EMU8000_SMALW_WRITE(rec->emu, rec->offset);
645 for (i = 0; i < LOOP_BLANK_SIZE; i++)
646 EMU8000_SMLD_WRITE(rec->emu, 0);
647 for (ch = 0; ch < rec->voices; ch++) {
648 EMU8000_SMALW_WRITE(rec->emu, rec->loop_start[ch] + rec->buf_size);
649 for (i = 0; i < LOOP_BLANK_SIZE; i++)
650 EMU8000_SMLD_WRITE(rec->emu, 0);
651 }
652 }
653
654 setup_voice(rec, 0);
655 if (rec->voices > 1)
656 setup_voice(rec, 1);
657 return 0;
658}
659
660static snd_pcm_uframes_t emu8k_pcm_pointer(snd_pcm_substream_t *subs)
661{
662 emu8k_pcm_t *rec = subs->runtime->private_data;
663 if (rec->running)
664 return emu8k_get_curpos(rec, 0);
665 return 0;
666}
667
668
669static snd_pcm_ops_t emu8k_pcm_ops = {
670 .open = emu8k_pcm_open,
671 .close = emu8k_pcm_close,
672 .ioctl = snd_pcm_lib_ioctl,
673 .hw_params = emu8k_pcm_hw_params,
674 .hw_free = emu8k_pcm_hw_free,
675 .prepare = emu8k_pcm_prepare,
676 .trigger = emu8k_pcm_trigger,
677 .pointer = emu8k_pcm_pointer,
678 .copy = emu8k_pcm_copy,
679 .silence = emu8k_pcm_silence,
680};
681
682
683static void snd_emu8000_pcm_free(snd_pcm_t *pcm)
684{
685 emu8000_t *emu = pcm->private_data;
686 emu->pcm = NULL;
687}
688
689int snd_emu8000_pcm_new(snd_card_t *card, emu8000_t *emu, int index)
690{
691 snd_pcm_t *pcm;
692 int err;
693
694 if ((err = snd_pcm_new(card, "Emu8000 PCM", index, 1, 0, &pcm)) < 0)
695 return err;
696 pcm->private_data = emu;
697 pcm->private_free = snd_emu8000_pcm_free;
698 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &emu8k_pcm_ops);
699 emu->pcm = pcm;
700
701 snd_device_register(card, pcm);
702
703 return 0;
704}
diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c
new file mode 100644
index 000000000000..1f63aa52d596
--- /dev/null
+++ b/sound/isa/sb/emu8000_synth.c
@@ -0,0 +1,134 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk>
4 * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
5 *
6 * Emu8000 synth plug-in routine
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 "emu8000_local.h"
24#include <linux/init.h>
25#include <sound/initval.h>
26
27MODULE_AUTHOR("Takashi Iwai, Steve Ratcliffe");
28MODULE_DESCRIPTION("Emu8000 synth plug-in routine");
29MODULE_LICENSE("GPL");
30
31/*----------------------------------------------------------------*/
32
33/*
34 * create a new hardware dependent device for Emu8000
35 */
36static int snd_emu8000_new_device(snd_seq_device_t *dev)
37{
38 emu8000_t *hw;
39 snd_emux_t *emu;
40
41 hw = *(emu8000_t**)SNDRV_SEQ_DEVICE_ARGPTR(dev);
42 if (hw == NULL)
43 return -EINVAL;
44
45 if (hw->emu)
46 return -EBUSY; /* already exists..? */
47
48 if (snd_emux_new(&emu) < 0)
49 return -ENOMEM;
50
51 hw->emu = emu;
52 snd_emu8000_ops_setup(hw);
53
54 emu->hw = hw;
55 emu->max_voices = EMU8000_DRAM_VOICES;
56 emu->num_ports = hw->seq_ports;
57
58 if (hw->memhdr) {
59 snd_printk("memhdr is already initialized!?\n");
60 snd_util_memhdr_free(hw->memhdr);
61 }
62 hw->memhdr = snd_util_memhdr_new(hw->mem_size);
63 if (hw->memhdr == NULL) {
64 snd_emux_free(emu);
65 hw->emu = NULL;
66 return -ENOMEM;
67 }
68
69 emu->memhdr = hw->memhdr;
70 emu->midi_ports = hw->seq_ports < 2 ? hw->seq_ports : 2; /* number of virmidi ports */
71 emu->midi_devidx = 1;
72 emu->linear_panning = 1;
73 emu->hwdep_idx = 2; /* FIXED */
74
75 if (snd_emux_register(emu, dev->card, hw->index, "Emu8000") < 0) {
76 snd_emux_free(emu);
77 snd_util_memhdr_free(hw->memhdr);
78 hw->emu = NULL;
79 hw->memhdr = NULL;
80 return -ENOMEM;
81 }
82
83 if (hw->mem_size > 0)
84 snd_emu8000_pcm_new(dev->card, hw, 1);
85
86 dev->driver_data = hw;
87
88 return 0;
89}
90
91
92/*
93 * free all resources
94 */
95static int snd_emu8000_delete_device(snd_seq_device_t *dev)
96{
97 emu8000_t *hw;
98
99 if (dev->driver_data == NULL)
100 return 0; /* no synth was allocated actually */
101
102 hw = dev->driver_data;
103 if (hw->pcm)
104 snd_device_free(dev->card, hw->pcm);
105 if (hw->emu)
106 snd_emux_free(hw->emu);
107 if (hw->memhdr)
108 snd_util_memhdr_free(hw->memhdr);
109 hw->emu = NULL;
110 hw->memhdr = NULL;
111 return 0;
112}
113
114/*
115 * INIT part
116 */
117
118static int __init alsa_emu8000_init(void)
119{
120
121 static snd_seq_dev_ops_t ops = {
122 snd_emu8000_new_device,
123 snd_emu8000_delete_device,
124 };
125 return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU8000, &ops, sizeof(emu8000_t*));
126}
127
128static void __exit alsa_emu8000_exit(void)
129{
130 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU8000);
131}
132
133module_init(alsa_emu8000_init)
134module_exit(alsa_emu8000_exit)
diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c
new file mode 100644
index 000000000000..c859917c14db
--- /dev/null
+++ b/sound/isa/sb/es968.c
@@ -0,0 +1,235 @@
1
2/*
3 card-es968.c - driver for ESS AudioDrive ES968 based soundcards.
4 Copyright (C) 1999 by Massimo Piccioni <dafastidio@libero.it>
5
6 Thanks to Pierfrancesco 'qM2' Passerini.
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/init.h>
25#include <linux/time.h>
26#include <linux/pnp.h>
27#include <linux/moduleparam.h>
28#include <sound/core.h>
29#include <sound/initval.h>
30#include <sound/sb.h>
31
32#define PFX "es968: "
33
34MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
35MODULE_DESCRIPTION("ESS AudioDrive ES968");
36MODULE_LICENSE("GPL");
37MODULE_SUPPORTED_DEVICE("{{ESS,AudioDrive ES968}}");
38
39static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
40static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
41static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
42static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
43static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
44static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
45
46module_param_array(index, int, NULL, 0444);
47MODULE_PARM_DESC(index, "Index value for es968 based soundcard.");
48module_param_array(id, charp, NULL, 0444);
49MODULE_PARM_DESC(id, "ID string for es968 based soundcard.");
50module_param_array(enable, bool, NULL, 0444);
51MODULE_PARM_DESC(enable, "Enable es968 based soundcard.");
52module_param_array(port, long, NULL, 0444);
53MODULE_PARM_DESC(port, "Port # for es968 driver.");
54module_param_array(irq, int, NULL, 0444);
55MODULE_PARM_DESC(irq, "IRQ # for es968 driver.");
56module_param_array(dma8, int, NULL, 0444);
57MODULE_PARM_DESC(dma8, "8-bit DMA # for es968 driver.");
58
59struct snd_card_es968 {
60 struct pnp_dev *dev;
61};
62
63static struct pnp_card_device_id snd_es968_pnpids[] = {
64 { .id = "ESS0968", .devs = { { "@@@0968" }, } },
65 { .id = "", } /* end */
66};
67
68MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids);
69
70#define DRIVER_NAME "snd-card-es968"
71
72static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id,
73 struct pt_regs *regs)
74{
75 sb_t *chip = dev_id;
76
77 if (chip->open & SB_OPEN_PCM) {
78 return snd_sb8dsp_interrupt(chip);
79 } else {
80 return snd_sb8dsp_midi_interrupt(chip);
81 }
82}
83
84static int __devinit snd_card_es968_pnp(int dev, struct snd_card_es968 *acard,
85 struct pnp_card_link *card,
86 const struct pnp_card_device_id *id)
87{
88 struct pnp_dev *pdev;
89 struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
90 int err;
91 if (!cfg)
92 return -ENOMEM;
93 acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
94 if (acard->dev == NULL) {
95 kfree(cfg);
96 return -ENODEV;
97 }
98
99 pdev = acard->dev;
100
101 pnp_init_resource_table(cfg);
102
103 /* override resources */
104 if (port[dev] != SNDRV_AUTO_PORT)
105 pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
106 if (dma8[dev] != SNDRV_AUTO_DMA)
107 pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
108 if (irq[dev] != SNDRV_AUTO_IRQ)
109 pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
110 if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
111 snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
112 err = pnp_activate_dev(pdev);
113 if (err < 0) {
114 snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
115 kfree(cfg);
116 return err;
117 }
118 port[dev] = pnp_port_start(pdev, 0);
119 dma8[dev] = pnp_dma(pdev, 1);
120 irq[dev] = pnp_irq(pdev, 0);
121
122 kfree(cfg);
123 return 0;
124}
125
126static int __init snd_card_es968_probe(int dev,
127 struct pnp_card_link *pcard,
128 const struct pnp_card_device_id *pid)
129{
130 int error;
131 sb_t *chip;
132 snd_card_t *card;
133 struct snd_card_es968 *acard;
134
135 if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
136 sizeof(struct snd_card_es968))) == NULL)
137 return -ENOMEM;
138 acard = (struct snd_card_es968 *)card->private_data;
139 if ((error = snd_card_es968_pnp(dev, acard, pcard, pid))) {
140 snd_card_free(card);
141 return error;
142 }
143 snd_card_set_dev(card, &pcard->card->dev);
144
145 if ((error = snd_sbdsp_create(card, port[dev],
146 irq[dev],
147 snd_card_es968_interrupt,
148 dma8[dev],
149 -1,
150 SB_HW_AUTO, &chip)) < 0) {
151 snd_card_free(card);
152 return error;
153 }
154
155 if ((error = snd_sb8dsp_pcm(chip, 0, NULL)) < 0) {
156 snd_card_free(card);
157 return error;
158 }
159
160 if ((error = snd_sbmixer_new(chip)) < 0) {
161 snd_card_free(card);
162 return error;
163 }
164
165 if ((error = snd_sb8dsp_midi(chip, 0, NULL)) < 0) {
166 snd_card_free(card);
167 return error;
168 }
169
170 strcpy(card->driver, "ES968");
171 strcpy(card->shortname, "ESS ES968");
172 sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d",
173 card->shortname, chip->name, chip->port, irq[dev], dma8[dev]);
174
175 if ((error = snd_card_register(card)) < 0) {
176 snd_card_free(card);
177 return error;
178 }
179 pnp_set_card_drvdata(pcard, card);
180 return 0;
181}
182
183static int __devinit snd_es968_pnp_detect(struct pnp_card_link *card,
184 const struct pnp_card_device_id *id)
185{
186 static int dev;
187 int res;
188
189 for ( ; dev < SNDRV_CARDS; dev++) {
190 if (!enable[dev])
191 continue;
192 res = snd_card_es968_probe(dev, card, id);
193 if (res < 0)
194 return res;
195 dev++;
196 return 0;
197 }
198 return -ENODEV;
199}
200
201static void __devexit snd_es968_pnp_remove(struct pnp_card_link * pcard)
202{
203 snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
204
205 snd_card_disconnect(card);
206 snd_card_free_in_thread(card);
207}
208
209static struct pnp_card_driver es968_pnpc_driver = {
210 .flags = PNP_DRIVER_RES_DISABLE,
211 .name = "es968",
212 .id_table = snd_es968_pnpids,
213 .probe = snd_es968_pnp_detect,
214 .remove = __devexit_p(snd_es968_pnp_remove),
215};
216
217static int __init alsa_card_es968_init(void)
218{
219 int cards = pnp_register_card_driver(&es968_pnpc_driver);
220#ifdef MODULE
221 if (cards == 0) {
222 pnp_unregister_card_driver(&es968_pnpc_driver);
223 snd_printk(KERN_ERR "no ES968 based soundcards found\n");
224 }
225#endif
226 return cards ? 0 : -ENODEV;
227}
228
229static void __exit alsa_card_es968_exit(void)
230{
231 pnp_unregister_card_driver(&es968_pnpc_driver);
232}
233
234module_init(alsa_card_es968_init)
235module_exit(alsa_card_es968_exit)
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
new file mode 100644
index 000000000000..60e2c53c49fc
--- /dev/null
+++ b/sound/isa/sb/sb16.c
@@ -0,0 +1,678 @@
1/*
2 * Driver for SoundBlaster 16/AWE32/AWE64 soundcards
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <asm/dma.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/pnp.h>
27#include <linux/moduleparam.h>
28#include <sound/core.h>
29#include <sound/sb.h>
30#include <sound/sb16_csp.h>
31#include <sound/mpu401.h>
32#include <sound/opl3.h>
33#include <sound/emu8000.h>
34#include <sound/seq_device.h>
35#define SNDRV_LEGACY_AUTO_PROBE
36#define SNDRV_LEGACY_FIND_FREE_IRQ
37#define SNDRV_LEGACY_FIND_FREE_DMA
38#include <sound/initval.h>
39
40#ifdef SNDRV_SBAWE
41#define PFX "sbawe: "
42#else
43#define PFX "sb16: "
44#endif
45
46MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
47MODULE_LICENSE("GPL");
48#ifndef SNDRV_SBAWE
49MODULE_DESCRIPTION("Sound Blaster 16");
50MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 16},"
51 "{Creative Labs,SB Vibra16S},"
52 "{Creative Labs,SB Vibra16C},"
53 "{Creative Labs,SB Vibra16CL},"
54 "{Creative Labs,SB Vibra16X}}");
55#else
56MODULE_DESCRIPTION("Sound Blaster AWE");
57MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32},"
58 "{Creative Labs,SB AWE 64},"
59 "{Creative Labs,SB AWE 64 Gold}}");
60#endif
61
62#if 0
63#define SNDRV_DEBUG_IRQ
64#endif
65
66#if defined(SNDRV_SBAWE) && (defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)))
67#define SNDRV_SBAWE_EMU8000
68#endif
69
70static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
71static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
72static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
73#ifdef CONFIG_PNP
74static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
75#endif
76static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */
77static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x330,0x300 */
78static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
79#ifdef SNDRV_SBAWE_EMU8000
80static long awe_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
81#endif
82static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
83static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
84static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 5,6,7 */
85static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
86#ifdef CONFIG_SND_SB16_CSP
87static int csp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
88#endif
89#ifdef SNDRV_SBAWE_EMU8000
90static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
91#endif
92
93module_param_array(index, int, NULL, 0444);
94MODULE_PARM_DESC(index, "Index value for SoundBlaster 16 soundcard.");
95module_param_array(id, charp, NULL, 0444);
96MODULE_PARM_DESC(id, "ID string for SoundBlaster 16 soundcard.");
97module_param_array(enable, bool, NULL, 0444);
98MODULE_PARM_DESC(enable, "Enable SoundBlaster 16 soundcard.");
99#ifdef CONFIG_PNP
100module_param_array(isapnp, bool, NULL, 0444);
101MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
102#endif
103module_param_array(port, long, NULL, 0444);
104MODULE_PARM_DESC(port, "Port # for SB16 driver.");
105module_param_array(mpu_port, long, NULL, 0444);
106MODULE_PARM_DESC(mpu_port, "MPU-401 port # for SB16 driver.");
107module_param_array(fm_port, long, NULL, 0444);
108MODULE_PARM_DESC(fm_port, "FM port # for SB16 PnP driver.");
109#ifdef SNDRV_SBAWE_EMU8000
110module_param_array(awe_port, long, NULL, 0444);
111MODULE_PARM_DESC(awe_port, "AWE port # for SB16 PnP driver.");
112#endif
113module_param_array(irq, int, NULL, 0444);
114MODULE_PARM_DESC(irq, "IRQ # for SB16 driver.");
115module_param_array(dma8, int, NULL, 0444);
116MODULE_PARM_DESC(dma8, "8-bit DMA # for SB16 driver.");
117module_param_array(dma16, int, NULL, 0444);
118MODULE_PARM_DESC(dma16, "16-bit DMA # for SB16 driver.");
119module_param_array(mic_agc, int, NULL, 0444);
120MODULE_PARM_DESC(mic_agc, "Mic Auto-Gain-Control switch.");
121#ifdef CONFIG_SND_SB16_CSP
122module_param_array(csp, int, NULL, 0444);
123MODULE_PARM_DESC(csp, "ASP/CSP chip support.");
124#endif
125#ifdef SNDRV_SBAWE_EMU8000
126module_param_array(seq_ports, int, NULL, 0444);
127MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth.");
128#endif
129
130struct snd_card_sb16 {
131 struct resource *fm_res; /* used to block FM i/o region for legacy cards */
132#ifdef CONFIG_PNP
133 int dev_no;
134 struct pnp_dev *dev;
135#ifdef SNDRV_SBAWE_EMU8000
136 struct pnp_dev *devwt;
137#endif
138#endif
139};
140
141static snd_card_t *snd_sb16_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
142
143#ifdef CONFIG_PNP
144
145static struct pnp_card_device_id snd_sb16_pnpids[] = {
146#ifndef SNDRV_SBAWE
147 /* Sound Blaster 16 PnP */
148 { .id = "CTL0024", .devs = { { "CTL0031" } } },
149 /* Sound Blaster 16 PnP */
150 { .id = "CTL0025", .devs = { { "CTL0031" } } },
151 /* Sound Blaster 16 PnP */
152 { .id = "CTL0026", .devs = { { "CTL0031" } } },
153 /* Sound Blaster 16 PnP */
154 { .id = "CTL0027", .devs = { { "CTL0031" } } },
155 /* Sound Blaster 16 PnP */
156 { .id = "CTL0028", .devs = { { "CTL0031" } } },
157 /* Sound Blaster 16 PnP */
158 { .id = "CTL0029", .devs = { { "CTL0031" } } },
159 /* Sound Blaster 16 PnP */
160 { .id = "CTL002a", .devs = { { "CTL0031" } } },
161 /* Sound Blaster 16 PnP */
162 /* Note: This card has also a CTL0051:StereoEnhance device!!! */
163 { .id = "CTL002b", .devs = { { "CTL0031" } } },
164 /* Sound Blaster 16 PnP */
165 { .id = "CTL002c", .devs = { { "CTL0031" } } },
166 /* Sound Blaster Vibra16S */
167 { .id = "CTL0051", .devs = { { "CTL0001" } } },
168 /* Sound Blaster Vibra16C */
169 { .id = "CTL0070", .devs = { { "CTL0001" } } },
170 /* Sound Blaster Vibra16CL - added by ctm@ardi.com */
171 { .id = "CTL0080", .devs = { { "CTL0041" } } },
172 /* Sound Blaster 16 'value' PnP. It says model ct4130 on the pcb, */
173 /* but ct4131 on a sticker on the board.. */
174 { .id = "CTL0086", .devs = { { "CTL0041" } } },
175 /* Sound Blaster Vibra16X */
176 { .id = "CTL00f0", .devs = { { "CTL0043" } } },
177#else /* SNDRV_SBAWE defined */
178 /* Sound Blaster AWE 32 PnP */
179 { .id = "CTL0035", .devs = { { "CTL0031" }, { "CTL0021" } } },
180 /* Sound Blaster AWE 32 PnP */
181 { .id = "CTL0039", .devs = { { "CTL0031" }, { "CTL0021" } } },
182 /* Sound Blaster AWE 32 PnP */
183 { .id = "CTL0042", .devs = { { "CTL0031" }, { "CTL0021" } } },
184 /* Sound Blaster AWE 32 PnP */
185 { .id = "CTL0043", .devs = { { "CTL0031" }, { "CTL0021" } } },
186 /* Sound Blaster AWE 32 PnP */
187 /* Note: This card has also a CTL0051:StereoEnhance device!!! */
188 { .id = "CTL0044", .devs = { { "CTL0031" }, { "CTL0021" } } },
189 /* Sound Blaster AWE 32 PnP */
190 /* Note: This card has also a CTL0051:StereoEnhance device!!! */
191 { .id = "CTL0045", .devs = { { "CTL0031" }, { "CTL0021" } } },
192 /* Sound Blaster AWE 32 PnP */
193 { .id = "CTL0046", .devs = { { "CTL0031" }, { "CTL0021" } } },
194 /* Sound Blaster AWE 32 PnP */
195 { .id = "CTL0047", .devs = { { "CTL0031" }, { "CTL0021" } } },
196 /* Sound Blaster AWE 32 PnP */
197 { .id = "CTL0048", .devs = { { "CTL0031" }, { "CTL0021" } } },
198 /* Sound Blaster AWE 32 PnP */
199 { .id = "CTL0054", .devs = { { "CTL0031" }, { "CTL0021" } } },
200 /* Sound Blaster AWE 32 PnP */
201 { .id = "CTL009a", .devs = { { "CTL0041" }, { "CTL0021" } } },
202 /* Sound Blaster AWE 32 PnP */
203 { .id = "CTL009c", .devs = { { "CTL0041" }, { "CTL0021" } } },
204 /* Sound Blaster 32 PnP */
205 { .id = "CTL009f", .devs = { { "CTL0041" }, { "CTL0021" } } },
206 /* Sound Blaster AWE 64 PnP */
207 { .id = "CTL009d", .devs = { { "CTL0042" }, { "CTL0022" } } },
208 /* Sound Blaster AWE 64 PnP Gold */
209 { .id = "CTL009e", .devs = { { "CTL0044" }, { "CTL0023" } } },
210 /* Sound Blaster AWE 64 PnP Gold */
211 { .id = "CTL00b2", .devs = { { "CTL0044" }, { "CTL0023" } } },
212 /* Sound Blaster AWE 64 PnP */
213 { .id = "CTL00c1", .devs = { { "CTL0042" }, { "CTL0022" } } },
214 /* Sound Blaster AWE 64 PnP */
215 { .id = "CTL00c3", .devs = { { "CTL0045" }, { "CTL0022" } } },
216 /* Sound Blaster AWE 64 PnP */
217 { .id = "CTL00c5", .devs = { { "CTL0045" }, { "CTL0022" } } },
218 /* Sound Blaster AWE 64 PnP */
219 { .id = "CTL00c7", .devs = { { "CTL0045" }, { "CTL0022" } } },
220 /* Sound Blaster AWE 64 PnP */
221 { .id = "CTL00e4", .devs = { { "CTL0045" }, { "CTL0022" } } },
222 /* Sound Blaster AWE 64 PnP */
223 { .id = "CTL00e9", .devs = { { "CTL0045" }, { "CTL0022" } } },
224 /* Sound Blaster 16 PnP (AWE) */
225 { .id = "CTL00ed", .devs = { { "CTL0041" }, { "CTL0070" } } },
226 /* Generic entries */
227 { .id = "CTLXXXX" , .devs = { { "CTL0031" }, { "CTL0021" } } },
228 { .id = "CTLXXXX" , .devs = { { "CTL0041" }, { "CTL0021" } } },
229 { .id = "CTLXXXX" , .devs = { { "CTL0042" }, { "CTL0022" } } },
230 { .id = "CTLXXXX" , .devs = { { "CTL0044" }, { "CTL0023" } } },
231 { .id = "CTLXXXX" , .devs = { { "CTL0045" }, { "CTL0022" } } },
232#endif /* SNDRV_SBAWE */
233 /* Sound Blaster 16 PnP (Virtual PC 2004)*/
234 { .id = "tBA03b0", .devs = { { "PNPb003" } } },
235 { .id = "", }
236};
237
238MODULE_DEVICE_TABLE(pnp_card, snd_sb16_pnpids);
239
240#endif /* CONFIG_PNP */
241
242#ifdef SNDRV_SBAWE_EMU8000
243#define DRIVER_NAME "snd-card-sbawe"
244#else
245#define DRIVER_NAME "snd-card-sb16"
246#endif
247
248#ifdef CONFIG_PNP
249
250static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
251 struct pnp_card_link *card,
252 const struct pnp_card_device_id *id)
253{
254 struct pnp_dev *pdev;
255 struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
256 int err;
257
258 if (!cfg)
259 return -ENOMEM;
260 acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
261 if (acard->dev == NULL) {
262 kfree(cfg);
263 return -ENODEV;
264 }
265#ifdef SNDRV_SBAWE_EMU8000
266 acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev);
267#endif
268 /* Audio initialization */
269 pdev = acard->dev;
270
271 pnp_init_resource_table(cfg);
272
273 /* override resources */
274
275 if (port[dev] != SNDRV_AUTO_PORT)
276 pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
277 if (mpu_port[dev] != SNDRV_AUTO_PORT)
278 pnp_resource_change(&cfg->port_resource[1], mpu_port[dev], 2);
279 if (fm_port[dev] != SNDRV_AUTO_PORT)
280 pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4);
281 if (dma8[dev] != SNDRV_AUTO_DMA)
282 pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1);
283 if (dma16[dev] != SNDRV_AUTO_DMA)
284 pnp_resource_change(&cfg->dma_resource[1], dma16[dev], 1);
285 if (irq[dev] != SNDRV_AUTO_IRQ)
286 pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
287 if (pnp_manual_config_dev(pdev, cfg, 0) < 0)
288 snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
289 err = pnp_activate_dev(pdev);
290 if (err < 0) {
291 snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
292 kfree(cfg);
293 return err;
294 }
295 port[dev] = pnp_port_start(pdev, 0);
296 mpu_port[dev] = pnp_port_start(pdev, 1);
297 fm_port[dev] = pnp_port_start(pdev, 2);
298 dma8[dev] = pnp_dma(pdev, 0);
299 dma16[dev] = pnp_dma(pdev, 1);
300 irq[dev] = pnp_irq(pdev, 0);
301 snd_printdd("pnp SB16: port=0x%lx, mpu port=0x%lx, fm port=0x%lx\n",
302 port[dev], mpu_port[dev], fm_port[dev]);
303 snd_printdd("pnp SB16: dma1=%i, dma2=%i, irq=%i\n",
304 dma8[dev], dma16[dev], irq[dev]);
305#ifdef SNDRV_SBAWE_EMU8000
306 /* WaveTable initialization */
307 pdev = acard->devwt;
308 if (pdev != NULL) {
309 pnp_init_resource_table(cfg);
310
311 /* override resources */
312
313 if (awe_port[dev] != SNDRV_AUTO_PORT) {
314 pnp_resource_change(&cfg->port_resource[0], awe_port[dev], 4);
315 pnp_resource_change(&cfg->port_resource[1], awe_port[dev] + 0x400, 4);
316 pnp_resource_change(&cfg->port_resource[2], awe_port[dev] + 0x800, 4);
317 }
318 if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
319 snd_printk(KERN_ERR PFX "WaveTable the requested resources are invalid, using auto config\n");
320 err = pnp_activate_dev(pdev);
321 if (err < 0) {
322 goto __wt_error;
323 }
324 awe_port[dev] = pnp_port_start(pdev, 0);
325 snd_printdd("pnp SB16: wavetable port=0x%lx\n", pnp_port_start(pdev, 0));
326 } else {
327__wt_error:
328 if (pdev) {
329 pnp_release_card_device(pdev);
330 snd_printk(KERN_ERR PFX "WaveTable pnp configure failure\n");
331 }
332 acard->devwt = NULL;
333 awe_port[dev] = -1;
334 }
335#endif
336 kfree(cfg);
337 return 0;
338}
339
340#endif /* CONFIG_PNP */
341
342static void snd_sb16_free(snd_card_t *card)
343{
344 struct snd_card_sb16 *acard = (struct snd_card_sb16 *)card->private_data;
345
346 if (acard == NULL)
347 return;
348 if (acard->fm_res) {
349 release_resource(acard->fm_res);
350 kfree_nocheck(acard->fm_res);
351 }
352}
353
354static int __init snd_sb16_probe(int dev,
355 struct pnp_card_link *pcard,
356 const struct pnp_card_device_id *pid)
357{
358 static int possible_irqs[] = {5, 9, 10, 7, -1};
359 static int possible_dmas8[] = {1, 3, 0, -1};
360 static int possible_dmas16[] = {5, 6, 7, -1};
361 int xirq, xdma8, xdma16;
362 sb_t *chip;
363 snd_card_t *card;
364 struct snd_card_sb16 *acard;
365 opl3_t *opl3;
366 snd_hwdep_t *synth = NULL;
367#ifdef CONFIG_SND_SB16_CSP
368 snd_hwdep_t *xcsp = NULL;
369#endif
370 unsigned long flags;
371 int err;
372
373 card = snd_card_new(index[dev], id[dev], THIS_MODULE,
374 sizeof(struct snd_card_sb16));
375 if (card == NULL)
376 return -ENOMEM;
377 acard = (struct snd_card_sb16 *) card->private_data;
378 card->private_free = snd_sb16_free;
379#ifdef CONFIG_PNP
380 if (isapnp[dev]) {
381 if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) {
382 snd_card_free(card);
383 return err;
384 }
385 snd_card_set_dev(card, &pcard->card->dev);
386 }
387#endif
388
389 xirq = irq[dev];
390 xdma8 = dma8[dev];
391 xdma16 = dma16[dev];
392#ifdef CONFIG_PNP
393 if (!isapnp[dev]) {
394#endif
395 if (xirq == SNDRV_AUTO_IRQ) {
396 if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
397 snd_card_free(card);
398 snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
399 return -EBUSY;
400 }
401 }
402 if (xdma8 == SNDRV_AUTO_DMA) {
403 if ((xdma8 = snd_legacy_find_free_dma(possible_dmas8)) < 0) {
404 snd_card_free(card);
405 snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n");
406 return -EBUSY;
407 }
408 }
409 if (xdma16 == SNDRV_AUTO_DMA) {
410 if ((xdma16 = snd_legacy_find_free_dma(possible_dmas16)) < 0) {
411 snd_card_free(card);
412 snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n");
413 return -EBUSY;
414 }
415 }
416 /* non-PnP FM port address is hardwired with base port address */
417 fm_port[dev] = port[dev];
418 /* block the 0x388 port to avoid PnP conflicts */
419 acard->fm_res = request_region(0x388, 4, "SoundBlaster FM");
420#ifdef SNDRV_SBAWE_EMU8000
421 /* non-PnP AWE port address is hardwired with base port address */
422 awe_port[dev] = port[dev] + 0x400;
423#endif
424#ifdef CONFIG_PNP
425 }
426#endif
427
428 if ((err = snd_sbdsp_create(card,
429 port[dev],
430 xirq,
431 snd_sb16dsp_interrupt,
432 xdma8,
433 xdma16,
434 SB_HW_AUTO,
435 &chip)) < 0) {
436 snd_card_free(card);
437 return err;
438 }
439 if (chip->hardware != SB_HW_16) {
440 snd_card_free(card);
441 snd_printdd("SB 16 chip was not detected at 0x%lx\n", port[dev]);
442 return -ENODEV;
443 }
444 chip->mpu_port = mpu_port[dev];
445#ifdef CONFIG_PNP
446 if (!isapnp[dev] && (err = snd_sb16dsp_configure(chip)) < 0) {
447#else
448 if ((err = snd_sb16dsp_configure(chip)) < 0) {
449#endif
450 snd_card_free(card);
451 return -ENXIO;
452 }
453 if ((err = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
454 snd_card_free(card);
455 return -ENXIO;
456 }
457
458 strcpy(card->driver,
459#ifdef SNDRV_SBAWE_EMU8000
460 awe_port[dev] > 0 ? "SB AWE" :
461#endif
462 "SB16");
463 strcpy(card->shortname, chip->name);
464 sprintf(card->longname, "%s at 0x%lx, irq %i, dma ",
465 chip->name,
466 chip->port,
467 xirq);
468 if (xdma8 >= 0)
469 sprintf(card->longname + strlen(card->longname), "%d", xdma8);
470 if (xdma16 >= 0)
471 sprintf(card->longname + strlen(card->longname), "%s%d",
472 xdma8 >= 0 ? "&" : "", xdma16);
473
474 if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
475 if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB,
476 chip->mpu_port, 0,
477 xirq, 0, &chip->rmidi)) < 0) {
478 snd_card_free(card);
479 return -ENXIO;
480 }
481 chip->rmidi_callback = snd_mpu401_uart_interrupt;
482 }
483
484#ifdef SNDRV_SBAWE_EMU8000
485 if (awe_port[dev] == SNDRV_AUTO_PORT)
486 awe_port[dev] = 0; /* disable */
487#endif
488
489 if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
490 if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
491 OPL3_HW_OPL3,
492 acard->fm_res != NULL || fm_port[dev] == port[dev],
493 &opl3) < 0) {
494 snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
495 fm_port[dev], fm_port[dev] + 2);
496 } else {
497#ifdef SNDRV_SBAWE_EMU8000
498 int seqdev = awe_port[dev] > 0 ? 2 : 1;
499#else
500 int seqdev = 1;
501#endif
502 if ((err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth)) < 0) {
503 snd_card_free(card);
504 return -ENXIO;
505 }
506 }
507 }
508
509 if ((err = snd_sbmixer_new(chip)) < 0) {
510 snd_card_free(card);
511 return -ENXIO;
512 }
513
514#ifdef CONFIG_SND_SB16_CSP
515 /* CSP chip on SB16ASP/AWE32 */
516 if ((chip->hardware == SB_HW_16) && csp[dev]) {
517 snd_sb_csp_new(chip, synth != NULL ? 1 : 0, &xcsp);
518 if (xcsp) {
519 chip->csp = xcsp->private_data;
520 chip->hardware = SB_HW_16CSP;
521 } else {
522 snd_printk(KERN_INFO PFX "warning - CSP chip not detected on soundcard #%i\n", dev + 1);
523 }
524 }
525#endif
526#ifdef SNDRV_SBAWE_EMU8000
527 if (awe_port[dev] > 0) {
528 if (snd_emu8000_new(card, 1, awe_port[dev],
529 seq_ports[dev], NULL) < 0) {
530 snd_printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", awe_port[dev]);
531 snd_card_free(card);
532 return -ENXIO;
533 }
534 }
535#endif
536
537 /* setup Mic AGC */
538 spin_lock_irqsave(&chip->mixer_lock, flags);
539 snd_sbmixer_write(chip, SB_DSP4_MIC_AGC,
540 (snd_sbmixer_read(chip, SB_DSP4_MIC_AGC) & 0x01) |
541 (mic_agc[dev] ? 0x00 : 0x01));
542 spin_unlock_irqrestore(&chip->mixer_lock, flags);
543
544 if ((err = snd_card_register(card)) < 0) {
545 snd_card_free(card);
546 return err;
547 }
548 if (pcard)
549 pnp_set_card_drvdata(pcard, card);
550 else
551 snd_sb16_legacy[dev] = card;
552 return 0;
553}
554
555static int __init snd_sb16_probe_legacy_port(unsigned long xport)
556{
557 static int dev;
558 int res;
559
560 for ( ; dev < SNDRV_CARDS; dev++) {
561 if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT)
562 continue;
563#ifdef CONFIG_PNP
564 if (isapnp[dev])
565 continue;
566#endif
567 port[dev] = xport;
568 res = snd_sb16_probe(dev, NULL, NULL);
569 if (res < 0)
570 port[dev] = SNDRV_AUTO_PORT;
571 return res;
572 }
573 return -ENODEV;
574}
575
576#ifdef CONFIG_PNP
577
578static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *card,
579 const struct pnp_card_device_id *id)
580{
581 static int dev;
582 int res;
583
584 for ( ; dev < SNDRV_CARDS; dev++) {
585 if (!enable[dev] || !isapnp[dev])
586 continue;
587 res = snd_sb16_probe(dev, card, id);
588 if (res < 0)
589 return res;
590 dev++;
591 return 0;
592 }
593
594 return -ENODEV;
595}
596
597static void __devexit snd_sb16_pnp_remove(struct pnp_card_link * pcard)
598{
599 snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
600
601 snd_card_disconnect(card);
602 snd_card_free_in_thread(card);
603}
604
605static struct pnp_card_driver sb16_pnpc_driver = {
606 .flags = PNP_DRIVER_RES_DISABLE,
607 .name = "sb16",
608 .id_table = snd_sb16_pnpids,
609 .probe = snd_sb16_pnp_detect,
610 .remove = __devexit_p(snd_sb16_pnp_remove),
611};
612
613#endif /* CONFIG_PNP */
614
615static int __init alsa_card_sb16_init(void)
616{
617 int dev, cards = 0, i;
618 static unsigned long possible_ports[] = {0x220, 0x240, 0x260, 0x280, -1};
619
620 /* legacy non-auto cards at first */
621 for (dev = 0; dev < SNDRV_CARDS; dev++) {
622 if (!enable[dev] || port[dev] == SNDRV_AUTO_PORT)
623 continue;
624#ifdef CONFIG_PNP
625 if (isapnp[dev])
626 continue;
627#endif
628 if (!snd_sb16_probe(dev, NULL, NULL)) {
629 cards++;
630 continue;
631 }
632#ifdef MODULE
633 snd_printk(KERN_ERR "Sound Blaster 16+ soundcard #%i not found at 0x%lx or device busy\n", dev, port[dev]);
634#endif
635 }
636 /* legacy auto configured cards */
637 i = snd_legacy_auto_probe(possible_ports, snd_sb16_probe_legacy_port);
638 if (i > 0)
639 cards += i;
640
641#ifdef CONFIG_PNP
642 /* PnP cards at last */
643 i = pnp_register_card_driver(&sb16_pnpc_driver);
644 if (i >0)
645 cards += i;
646#endif
647
648 if (!cards) {
649#ifdef CONFIG_PNP
650 pnp_unregister_card_driver(&sb16_pnpc_driver);
651#endif
652#ifdef MODULE
653 snd_printk(KERN_ERR "Sound Blaster 16 soundcard not found or device busy\n");
654#ifdef SNDRV_SBAWE_EMU8000
655 snd_printk(KERN_ERR "In case, if you have non-AWE card, try snd-sb16 module\n");
656#else
657 snd_printk(KERN_ERR "In case, if you have AWE card, try snd-sbawe module\n");
658#endif
659#endif
660 return -ENODEV;
661 }
662 return 0;
663}
664
665static void __exit alsa_card_sb16_exit(void)
666{
667 int dev;
668
669#ifdef CONFIG_PNP
670 /* PnP cards first */
671 pnp_unregister_card_driver(&sb16_pnpc_driver);
672#endif
673 for (dev = 0; dev < SNDRV_CARDS; dev++)
674 snd_card_free(snd_sb16_legacy[dev]);
675}
676
677module_init(alsa_card_sb16_init)
678module_exit(alsa_card_sb16_exit)
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
new file mode 100644
index 000000000000..b62920eead3d
--- /dev/null
+++ b/sound/isa/sb/sb16_csp.c
@@ -0,0 +1,1175 @@
1/*
2 * Copyright (c) 1999 by Uros Bizjak <uros@kss-loka.si>
3 * Takashi Iwai <tiwai@suse.de>
4 *
5 * SB16ASP/AWE32 CSP control
6 *
7 * CSP microcode loader:
8 * alsa-tools/sb16_csp/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26#include <sound/driver.h>
27#include <linux/delay.h>
28#include <linux/init.h>
29#include <linux/slab.h>
30#include <sound/core.h>
31#include <sound/control.h>
32#include <sound/info.h>
33#include <sound/sb16_csp.h>
34#include <sound/initval.h>
35
36MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
37MODULE_DESCRIPTION("ALSA driver for SB16 Creative Signal Processor");
38MODULE_LICENSE("GPL");
39
40#ifdef SNDRV_LITTLE_ENDIAN
41#define CSP_HDR_VALUE(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
42#else
43#define CSP_HDR_VALUE(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
44#endif
45#define LE_SHORT(v) le16_to_cpu(v)
46#define LE_INT(v) le32_to_cpu(v)
47
48#define RIFF_HEADER CSP_HDR_VALUE('R', 'I', 'F', 'F')
49#define CSP__HEADER CSP_HDR_VALUE('C', 'S', 'P', ' ')
50#define LIST_HEADER CSP_HDR_VALUE('L', 'I', 'S', 'T')
51#define FUNC_HEADER CSP_HDR_VALUE('f', 'u', 'n', 'c')
52#define CODE_HEADER CSP_HDR_VALUE('c', 'o', 'd', 'e')
53#define INIT_HEADER CSP_HDR_VALUE('i', 'n', 'i', 't')
54#define MAIN_HEADER CSP_HDR_VALUE('m', 'a', 'i', 'n')
55
56/*
57 * RIFF data format
58 */
59typedef struct riff_header {
60 __u32 name;
61 __u32 len;
62} riff_header_t;
63
64typedef struct desc_header {
65 riff_header_t info;
66 __u16 func_nr;
67 __u16 VOC_type;
68 __u16 flags_play_rec;
69 __u16 flags_16bit_8bit;
70 __u16 flags_stereo_mono;
71 __u16 flags_rates;
72} desc_header_t;
73
74/*
75 * prototypes
76 */
77static void snd_sb_csp_free(snd_hwdep_t *hw);
78static int snd_sb_csp_open(snd_hwdep_t * hw, struct file *file);
79static int snd_sb_csp_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg);
80static int snd_sb_csp_release(snd_hwdep_t * hw, struct file *file);
81
82static int csp_detect(sb_t *chip, int *version);
83static int set_codec_parameter(sb_t *chip, unsigned char par, unsigned char val);
84static int set_register(sb_t *chip, unsigned char reg, unsigned char val);
85static int read_register(sb_t *chip, unsigned char reg);
86static int set_mode_register(sb_t *chip, unsigned char mode);
87static int get_version(sb_t *chip);
88
89static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user * code);
90static int snd_sb_csp_unload(snd_sb_csp_t * p);
91static int snd_sb_csp_load_user(snd_sb_csp_t * p, const unsigned char __user *buf, int size, int load_flags);
92static int snd_sb_csp_autoload(snd_sb_csp_t * p, int pcm_sfmt, int play_rec_mode);
93static int snd_sb_csp_check_version(snd_sb_csp_t * p);
94
95static int snd_sb_csp_use(snd_sb_csp_t * p);
96static int snd_sb_csp_unuse(snd_sb_csp_t * p);
97static int snd_sb_csp_start(snd_sb_csp_t * p, int sample_width, int channels);
98static int snd_sb_csp_stop(snd_sb_csp_t * p);
99static int snd_sb_csp_pause(snd_sb_csp_t * p);
100static int snd_sb_csp_restart(snd_sb_csp_t * p);
101
102static int snd_sb_qsound_build(snd_sb_csp_t * p);
103static void snd_sb_qsound_destroy(snd_sb_csp_t * p);
104static int snd_sb_csp_qsound_transfer(snd_sb_csp_t * p);
105
106static int init_proc_entry(snd_sb_csp_t * p, int device);
107static void info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer);
108
109/*
110 * Detect CSP chip and create a new instance
111 */
112int snd_sb_csp_new(sb_t *chip, int device, snd_hwdep_t ** rhwdep)
113{
114 snd_sb_csp_t *p;
115 int version, err;
116 snd_hwdep_t *hw;
117
118 if (rhwdep)
119 *rhwdep = NULL;
120
121 if (csp_detect(chip, &version))
122 return -ENODEV;
123
124 if ((err = snd_hwdep_new(chip->card, "SB16-CSP", device, &hw)) < 0)
125 return err;
126
127 if ((p = kcalloc(1, sizeof(*p), GFP_KERNEL)) == NULL) {
128 snd_device_free(chip->card, hw);
129 return -ENOMEM;
130 }
131 p->chip = chip;
132 p->version = version;
133
134 /* CSP operators */
135 p->ops.csp_use = snd_sb_csp_use;
136 p->ops.csp_unuse = snd_sb_csp_unuse;
137 p->ops.csp_autoload = snd_sb_csp_autoload;
138 p->ops.csp_start = snd_sb_csp_start;
139 p->ops.csp_stop = snd_sb_csp_stop;
140 p->ops.csp_qsound_transfer = snd_sb_csp_qsound_transfer;
141
142 init_MUTEX(&p->access_mutex);
143 sprintf(hw->name, "CSP v%d.%d", (version >> 4), (version & 0x0f));
144 hw->iface = SNDRV_HWDEP_IFACE_SB16CSP;
145 hw->private_data = p;
146 hw->private_free = snd_sb_csp_free;
147
148 /* operators - only write/ioctl */
149 hw->ops.open = snd_sb_csp_open;
150 hw->ops.ioctl = snd_sb_csp_ioctl;
151 hw->ops.release = snd_sb_csp_release;
152
153 /* create a proc entry */
154 init_proc_entry(p, device);
155 if (rhwdep)
156 *rhwdep = hw;
157 return 0;
158}
159
160/*
161 * free_private for hwdep instance
162 */
163static void snd_sb_csp_free(snd_hwdep_t *hwdep)
164{
165 snd_sb_csp_t *p = hwdep->private_data;
166 if (p) {
167 if (p->running & SNDRV_SB_CSP_ST_RUNNING)
168 snd_sb_csp_stop(p);
169 kfree(p);
170 }
171}
172
173/* ------------------------------ */
174
175/*
176 * open the device exclusively
177 */
178static int snd_sb_csp_open(snd_hwdep_t * hw, struct file *file)
179{
180 snd_sb_csp_t *p = hw->private_data;
181 return (snd_sb_csp_use(p));
182}
183
184/*
185 * ioctl for hwdep device:
186 */
187static int snd_sb_csp_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg)
188{
189 snd_sb_csp_t *p = hw->private_data;
190 snd_sb_csp_info_t info;
191 snd_sb_csp_start_t start_info;
192 int err;
193
194 snd_assert(p != NULL, return -EINVAL);
195
196 if (snd_sb_csp_check_version(p))
197 return -ENODEV;
198
199 switch (cmd) {
200 /* get information */
201 case SNDRV_SB_CSP_IOCTL_INFO:
202 *info.codec_name = *p->codec_name;
203 info.func_nr = p->func_nr;
204 info.acc_format = p->acc_format;
205 info.acc_channels = p->acc_channels;
206 info.acc_width = p->acc_width;
207 info.acc_rates = p->acc_rates;
208 info.csp_mode = p->mode;
209 info.run_channels = p->run_channels;
210 info.run_width = p->run_width;
211 info.version = p->version;
212 info.state = p->running;
213 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
214 err = -EFAULT;
215 else
216 err = 0;
217 break;
218
219 /* load CSP microcode */
220 case SNDRV_SB_CSP_IOCTL_LOAD_CODE:
221 err = (p->running & SNDRV_SB_CSP_ST_RUNNING ?
222 -EBUSY : snd_sb_csp_riff_load(p, (snd_sb_csp_microcode_t __user *) arg));
223 break;
224 case SNDRV_SB_CSP_IOCTL_UNLOAD_CODE:
225 err = (p->running & SNDRV_SB_CSP_ST_RUNNING ?
226 -EBUSY : snd_sb_csp_unload(p));
227 break;
228
229 /* change CSP running state */
230 case SNDRV_SB_CSP_IOCTL_START:
231 if (copy_from_user(&start_info, (void __user *) arg, sizeof(start_info)))
232 err = -EFAULT;
233 else
234 err = snd_sb_csp_start(p, start_info.sample_width, start_info.channels);
235 break;
236 case SNDRV_SB_CSP_IOCTL_STOP:
237 err = snd_sb_csp_stop(p);
238 break;
239 case SNDRV_SB_CSP_IOCTL_PAUSE:
240 err = snd_sb_csp_pause(p);
241 break;
242 case SNDRV_SB_CSP_IOCTL_RESTART:
243 err = snd_sb_csp_restart(p);
244 break;
245 default:
246 err = -ENOTTY;
247 break;
248 }
249
250 return err;
251}
252
253/*
254 * close the device
255 */
256static int snd_sb_csp_release(snd_hwdep_t * hw, struct file *file)
257{
258 snd_sb_csp_t *p = hw->private_data;
259 return (snd_sb_csp_unuse(p));
260}
261
262/* ------------------------------ */
263
264/*
265 * acquire device
266 */
267static int snd_sb_csp_use(snd_sb_csp_t * p)
268{
269 down(&p->access_mutex);
270 if (p->used) {
271 up(&p->access_mutex);
272 return -EAGAIN;
273 }
274 p->used++;
275 up(&p->access_mutex);
276
277 return 0;
278
279}
280
281/*
282 * release device
283 */
284static int snd_sb_csp_unuse(snd_sb_csp_t * p)
285{
286 down(&p->access_mutex);
287 p->used--;
288 up(&p->access_mutex);
289
290 return 0;
291}
292
293/*
294 * load microcode via ioctl:
295 * code is user-space pointer
296 */
297static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user * mcode)
298{
299 snd_sb_csp_mc_header_t info;
300
301 unsigned char __user *data_ptr;
302 unsigned char __user *data_end;
303 unsigned short func_nr = 0;
304
305 riff_header_t file_h, item_h, code_h;
306 __u32 item_type;
307 desc_header_t funcdesc_h;
308
309 unsigned long flags;
310 int err;
311
312 if (copy_from_user(&info, mcode, sizeof(info)))
313 return -EFAULT;
314 data_ptr = mcode->data;
315
316 if (copy_from_user(&file_h, data_ptr, sizeof(file_h)))
317 return -EFAULT;
318 if ((file_h.name != RIFF_HEADER) ||
319 (LE_INT(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) {
320 snd_printd("%s: Invalid RIFF header\n", __FUNCTION__);
321 return -EINVAL;
322 }
323 data_ptr += sizeof(file_h);
324 data_end = data_ptr + LE_INT(file_h.len);
325
326 if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
327 return -EFAULT;
328 if (item_type != CSP__HEADER) {
329 snd_printd("%s: Invalid RIFF file type\n", __FUNCTION__);
330 return -EINVAL;
331 }
332 data_ptr += sizeof (item_type);
333
334 for (; data_ptr < data_end; data_ptr += LE_INT(item_h.len)) {
335 if (copy_from_user(&item_h, data_ptr, sizeof(item_h)))
336 return -EFAULT;
337 data_ptr += sizeof(item_h);
338 if (item_h.name != LIST_HEADER)
339 continue;
340
341 if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
342 return -EFAULT;
343 switch (item_type) {
344 case FUNC_HEADER:
345 if (copy_from_user(&funcdesc_h, data_ptr + sizeof(item_type), sizeof(funcdesc_h)))
346 return -EFAULT;
347 func_nr = LE_SHORT(funcdesc_h.func_nr);
348 break;
349 case CODE_HEADER:
350 if (func_nr != info.func_req)
351 break; /* not required function, try next */
352 data_ptr += sizeof(item_type);
353
354 /* destroy QSound mixer element */
355 if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {
356 snd_sb_qsound_destroy(p);
357 }
358 /* Clear all flags */
359 p->running = 0;
360 p->mode = 0;
361
362 /* load microcode blocks */
363 for (;;) {
364 if (data_ptr >= data_end)
365 return -EINVAL;
366 if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))
367 return -EFAULT;
368
369 /* init microcode blocks */
370 if (code_h.name != INIT_HEADER)
371 break;
372 data_ptr += sizeof(code_h);
373 err = snd_sb_csp_load_user(p, data_ptr, LE_INT(code_h.len),
374 SNDRV_SB_CSP_LOAD_INITBLOCK);
375 if (err)
376 return err;
377 data_ptr += LE_INT(code_h.len);
378 }
379 /* main microcode block */
380 if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))
381 return -EFAULT;
382
383 if (code_h.name != MAIN_HEADER) {
384 snd_printd("%s: Missing 'main' microcode\n", __FUNCTION__);
385 return -EINVAL;
386 }
387 data_ptr += sizeof(code_h);
388 err = snd_sb_csp_load_user(p, data_ptr,
389 LE_INT(code_h.len), 0);
390 if (err)
391 return err;
392
393 /* fill in codec header */
394 strlcpy(p->codec_name, info.codec_name, sizeof(p->codec_name));
395 p->func_nr = func_nr;
396 p->mode = LE_SHORT(funcdesc_h.flags_play_rec);
397 switch (LE_SHORT(funcdesc_h.VOC_type)) {
398 case 0x0001: /* QSound decoder */
399 if (LE_SHORT(funcdesc_h.flags_play_rec) == SNDRV_SB_CSP_MODE_DSP_WRITE) {
400 if (snd_sb_qsound_build(p) == 0)
401 /* set QSound flag and clear all other mode flags */
402 p->mode = SNDRV_SB_CSP_MODE_QSOUND;
403 }
404 p->acc_format = 0;
405 break;
406 case 0x0006: /* A Law codec */
407 p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
408 break;
409 case 0x0007: /* Mu Law codec */
410 p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
411 break;
412 case 0x0011: /* what Creative thinks is IMA ADPCM codec */
413 case 0x0200: /* Creative ADPCM codec */
414 p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;
415 break;
416 case 201: /* Text 2 Speech decoder */
417 /* TODO: Text2Speech handling routines */
418 p->acc_format = 0;
419 break;
420 case 0x0202: /* Fast Speech 8 codec */
421 case 0x0203: /* Fast Speech 10 codec */
422 p->acc_format = SNDRV_PCM_FMTBIT_SPECIAL;
423 break;
424 default: /* other codecs are unsupported */
425 p->acc_format = p->acc_width = p->acc_rates = 0;
426 p->mode = 0;
427 snd_printd("%s: Unsupported CSP codec type: 0x%04x\n",
428 __FUNCTION__,
429 LE_SHORT(funcdesc_h.VOC_type));
430 return -EINVAL;
431 }
432 p->acc_channels = LE_SHORT(funcdesc_h.flags_stereo_mono);
433 p->acc_width = LE_SHORT(funcdesc_h.flags_16bit_8bit);
434 p->acc_rates = LE_SHORT(funcdesc_h.flags_rates);
435
436 /* Decouple CSP from IRQ and DMAREQ lines */
437 spin_lock_irqsave(&p->chip->reg_lock, flags);
438 set_mode_register(p->chip, 0xfc);
439 set_mode_register(p->chip, 0x00);
440 spin_unlock_irqrestore(&p->chip->reg_lock, flags);
441
442 /* finished loading successfully */
443 p->running = SNDRV_SB_CSP_ST_LOADED; /* set LOADED flag */
444 return 0;
445 }
446 }
447 snd_printd("%s: Function #%d not found\n", __FUNCTION__, info.func_req);
448 return -EINVAL;
449}
450
451/*
452 * unload CSP microcode
453 */
454static int snd_sb_csp_unload(snd_sb_csp_t * p)
455{
456 if (p->running & SNDRV_SB_CSP_ST_RUNNING)
457 return -EBUSY;
458 if (!(p->running & SNDRV_SB_CSP_ST_LOADED))
459 return -ENXIO;
460
461 /* clear supported formats */
462 p->acc_format = 0;
463 p->acc_channels = p->acc_width = p->acc_rates = 0;
464 /* destroy QSound mixer element */
465 if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {
466 snd_sb_qsound_destroy(p);
467 }
468 /* clear all flags */
469 p->running = 0;
470 p->mode = 0;
471 return 0;
472}
473
474/*
475 * send command sequence to DSP
476 */
477static inline int command_seq(sb_t *chip, const unsigned char *seq, int size)
478{
479 int i;
480 for (i = 0; i < size; i++) {
481 if (!snd_sbdsp_command(chip, seq[i]))
482 return -EIO;
483 }
484 return 0;
485}
486
487/*
488 * set CSP codec parameter
489 */
490static int set_codec_parameter(sb_t *chip, unsigned char par, unsigned char val)
491{
492 unsigned char dsp_cmd[3];
493
494 dsp_cmd[0] = 0x05; /* CSP set codec parameter */
495 dsp_cmd[1] = val; /* Parameter value */
496 dsp_cmd[2] = par; /* Parameter */
497 command_seq(chip, dsp_cmd, 3);
498 snd_sbdsp_command(chip, 0x03); /* DSP read? */
499 if (snd_sbdsp_get_byte(chip) != par)
500 return -EIO;
501 return 0;
502}
503
504/*
505 * set CSP register
506 */
507static int set_register(sb_t *chip, unsigned char reg, unsigned char val)
508{
509 unsigned char dsp_cmd[3];
510
511 dsp_cmd[0] = 0x0e; /* CSP set register */
512 dsp_cmd[1] = reg; /* CSP Register */
513 dsp_cmd[2] = val; /* value */
514 return command_seq(chip, dsp_cmd, 3);
515}
516
517/*
518 * read CSP register
519 * return < 0 -> error
520 */
521static int read_register(sb_t *chip, unsigned char reg)
522{
523 unsigned char dsp_cmd[2];
524
525 dsp_cmd[0] = 0x0f; /* CSP read register */
526 dsp_cmd[1] = reg; /* CSP Register */
527 command_seq(chip, dsp_cmd, 2);
528 return snd_sbdsp_get_byte(chip); /* Read DSP value */
529}
530
531/*
532 * set CSP mode register
533 */
534static int set_mode_register(sb_t *chip, unsigned char mode)
535{
536 unsigned char dsp_cmd[2];
537
538 dsp_cmd[0] = 0x04; /* CSP set mode register */
539 dsp_cmd[1] = mode; /* mode */
540 return command_seq(chip, dsp_cmd, 2);
541}
542
543/*
544 * Detect CSP
545 * return 0 if CSP exists.
546 */
547static int csp_detect(sb_t *chip, int *version)
548{
549 unsigned char csp_test1, csp_test2;
550 unsigned long flags;
551 int result = -ENODEV;
552
553 spin_lock_irqsave(&chip->reg_lock, flags);
554
555 set_codec_parameter(chip, 0x00, 0x00);
556 set_mode_register(chip, 0xfc); /* 0xfc = ?? */
557
558 csp_test1 = read_register(chip, 0x83);
559 set_register(chip, 0x83, ~csp_test1);
560 csp_test2 = read_register(chip, 0x83);
561 if (csp_test2 != (csp_test1 ^ 0xff))
562 goto __fail;
563
564 set_register(chip, 0x83, csp_test1);
565 csp_test2 = read_register(chip, 0x83);
566 if (csp_test2 != csp_test1)
567 goto __fail;
568
569 set_mode_register(chip, 0x00); /* 0x00 = ? */
570
571 *version = get_version(chip);
572 snd_sbdsp_reset(chip); /* reset DSP after getversion! */
573 if (*version >= 0x10 && *version <= 0x1f)
574 result = 0; /* valid version id */
575
576 __fail:
577 spin_unlock_irqrestore(&chip->reg_lock, flags);
578 return result;
579}
580
581/*
582 * get CSP version number
583 */
584static int get_version(sb_t *chip)
585{
586 unsigned char dsp_cmd[2];
587
588 dsp_cmd[0] = 0x08; /* SB_DSP_!something! */
589 dsp_cmd[1] = 0x03; /* get chip version id? */
590 command_seq(chip, dsp_cmd, 2);
591
592 return (snd_sbdsp_get_byte(chip));
593}
594
595/*
596 * check if the CSP version is valid
597 */
598static int snd_sb_csp_check_version(snd_sb_csp_t * p)
599{
600 if (p->version < 0x10 || p->version > 0x1f) {
601 snd_printd("%s: Invalid CSP version: 0x%x\n", __FUNCTION__, p->version);
602 return 1;
603 }
604 return 0;
605}
606
607/*
608 * download microcode to CSP (microcode should have one "main" block).
609 */
610static int snd_sb_csp_load(snd_sb_csp_t * p, const unsigned char *buf, int size, int load_flags)
611{
612 int status, i;
613 int err;
614 int result = -EIO;
615 unsigned long flags;
616
617 spin_lock_irqsave(&p->chip->reg_lock, flags);
618 snd_sbdsp_command(p->chip, 0x01); /* CSP download command */
619 if (snd_sbdsp_get_byte(p->chip)) {
620 snd_printd("%s: Download command failed\n", __FUNCTION__);
621 goto __fail;
622 }
623 /* Send CSP low byte (size - 1) */
624 snd_sbdsp_command(p->chip, (unsigned char)(size - 1));
625 /* Send high byte */
626 snd_sbdsp_command(p->chip, (unsigned char)((size - 1) >> 8));
627 /* send microcode sequence */
628 /* load from kernel space */
629 while (size--) {
630 if (!snd_sbdsp_command(p->chip, *buf++))
631 goto __fail;
632 }
633 if (snd_sbdsp_get_byte(p->chip))
634 goto __fail;
635
636 if (load_flags & SNDRV_SB_CSP_LOAD_INITBLOCK) {
637 i = 0;
638 /* some codecs (FastSpeech) take some time to initialize */
639 while (1) {
640 snd_sbdsp_command(p->chip, 0x03);
641 status = snd_sbdsp_get_byte(p->chip);
642 if (status == 0x55 || ++i >= 10)
643 break;
644 udelay (10);
645 }
646 if (status != 0x55) {
647 snd_printd("%s: Microcode initialization failed\n", __FUNCTION__);
648 goto __fail;
649 }
650 } else {
651 /*
652 * Read mixer register SB_DSP4_DMASETUP after loading 'main' code.
653 * Start CSP chip if no 16bit DMA channel is set - some kind
654 * of autorun or perhaps a bugfix?
655 */
656 spin_lock(&p->chip->mixer_lock);
657 status = snd_sbmixer_read(p->chip, SB_DSP4_DMASETUP);
658 spin_unlock(&p->chip->mixer_lock);
659 if (!(status & (SB_DMASETUP_DMA7 | SB_DMASETUP_DMA6 | SB_DMASETUP_DMA5))) {
660 err = (set_codec_parameter(p->chip, 0xaa, 0x00) ||
661 set_codec_parameter(p->chip, 0xff, 0x00));
662 snd_sbdsp_reset(p->chip); /* really! */
663 if (err)
664 goto __fail;
665 set_mode_register(p->chip, 0xc0); /* c0 = STOP */
666 set_mode_register(p->chip, 0x70); /* 70 = RUN */
667 }
668 }
669 result = 0;
670
671 __fail:
672 spin_unlock_irqrestore(&p->chip->reg_lock, flags);
673 return result;
674}
675
676static int snd_sb_csp_load_user(snd_sb_csp_t * p, const unsigned char __user *buf, int size, int load_flags)
677{
678 int err = -ENOMEM;
679 unsigned char *kbuf = kmalloc(size, GFP_KERNEL);
680 if (kbuf) {
681 if (copy_from_user(kbuf, buf, size))
682 err = -EFAULT;
683 else
684 err = snd_sb_csp_load(p, kbuf, size, load_flags);
685 kfree(kbuf);
686 }
687 return err;
688}
689
690#include "sb16_csp_codecs.h"
691
692/*
693 * autoload hardware codec if necessary
694 * return 0 if CSP is loaded and ready to run (p->running != 0)
695 */
696static int snd_sb_csp_autoload(snd_sb_csp_t * p, int pcm_sfmt, int play_rec_mode)
697{
698 unsigned long flags;
699 int err = 0;
700
701 /* if CSP is running or manually loaded then exit */
702 if (p->running & (SNDRV_SB_CSP_ST_RUNNING | SNDRV_SB_CSP_ST_LOADED))
703 return -EBUSY;
704
705 /* autoload microcode only if requested hardware codec is not already loaded */
706 if (((1 << pcm_sfmt) & p->acc_format) && (play_rec_mode & p->mode)) {
707 p->running = SNDRV_SB_CSP_ST_AUTO;
708 } else {
709 switch (pcm_sfmt) {
710 case SNDRV_PCM_FORMAT_MU_LAW:
711 err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0);
712 p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
713 p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
714 break;
715 case SNDRV_PCM_FORMAT_A_LAW:
716 err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0);
717 p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
718 p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
719 break;
720 case SNDRV_PCM_FORMAT_IMA_ADPCM:
721 err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init),
722 SNDRV_SB_CSP_LOAD_INITBLOCK);
723 if (err)
724 break;
725 if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {
726 err = snd_sb_csp_load(p, &ima_adpcm_playback[0],
727 sizeof(ima_adpcm_playback), 0);
728 p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;
729 } else {
730 err = snd_sb_csp_load(p, &ima_adpcm_capture[0],
731 sizeof(ima_adpcm_capture), 0);
732 p->mode = SNDRV_SB_CSP_MODE_DSP_READ;
733 }
734 p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;
735 break;
736 default:
737 /* Decouple CSP from IRQ and DMAREQ lines */
738 if (p->running & SNDRV_SB_CSP_ST_AUTO) {
739 spin_lock_irqsave(&p->chip->reg_lock, flags);
740 set_mode_register(p->chip, 0xfc);
741 set_mode_register(p->chip, 0x00);
742 spin_unlock_irqrestore(&p->chip->reg_lock, flags);
743 p->running = 0; /* clear autoloaded flag */
744 }
745 return -EINVAL;
746 }
747 if (err) {
748 p->acc_format = 0;
749 p->acc_channels = p->acc_width = p->acc_rates = 0;
750
751 p->running = 0; /* clear autoloaded flag */
752 p->mode = 0;
753 return (err);
754 } else {
755 p->running = SNDRV_SB_CSP_ST_AUTO; /* set autoloaded flag */
756 p->acc_width = SNDRV_SB_CSP_SAMPLE_16BIT; /* only 16 bit data */
757 p->acc_channels = SNDRV_SB_CSP_MONO | SNDRV_SB_CSP_STEREO;
758 p->acc_rates = SNDRV_SB_CSP_RATE_ALL; /* HW codecs accept all rates */
759 }
760
761 }
762 return (p->running & SNDRV_SB_CSP_ST_AUTO) ? 0 : -ENXIO;
763}
764
765/*
766 * start CSP
767 */
768static int snd_sb_csp_start(snd_sb_csp_t * p, int sample_width, int channels)
769{
770 unsigned char s_type; /* sample type */
771 unsigned char mixL, mixR;
772 int result = -EIO;
773 unsigned long flags;
774
775 if (!(p->running & (SNDRV_SB_CSP_ST_LOADED | SNDRV_SB_CSP_ST_AUTO))) {
776 snd_printd("%s: Microcode not loaded\n", __FUNCTION__);
777 return -ENXIO;
778 }
779 if (p->running & SNDRV_SB_CSP_ST_RUNNING) {
780 snd_printd("%s: CSP already running\n", __FUNCTION__);
781 return -EBUSY;
782 }
783 if (!(sample_width & p->acc_width)) {
784 snd_printd("%s: Unsupported PCM sample width\n", __FUNCTION__);
785 return -EINVAL;
786 }
787 if (!(channels & p->acc_channels)) {
788 snd_printd("%s: Invalid number of channels\n", __FUNCTION__);
789 return -EINVAL;
790 }
791
792 /* Mute PCM volume */
793 spin_lock_irqsave(&p->chip->mixer_lock, flags);
794 mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);
795 mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);
796 snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);
797 snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);
798
799 spin_lock(&p->chip->reg_lock);
800 set_mode_register(p->chip, 0xc0); /* c0 = STOP */
801 set_mode_register(p->chip, 0x70); /* 70 = RUN */
802
803 s_type = 0x00;
804 if (channels == SNDRV_SB_CSP_MONO)
805 s_type = 0x11; /* 000n 000n (n = 1 if mono) */
806 if (sample_width == SNDRV_SB_CSP_SAMPLE_8BIT)
807 s_type |= 0x22; /* 00dX 00dX (d = 1 if 8 bit samples) */
808
809 if (set_codec_parameter(p->chip, 0x81, s_type)) {
810 snd_printd("%s: Set sample type command failed\n", __FUNCTION__);
811 goto __fail;
812 }
813 if (set_codec_parameter(p->chip, 0x80, 0x00)) {
814 snd_printd("%s: Codec start command failed\n", __FUNCTION__);
815 goto __fail;
816 }
817 p->run_width = sample_width;
818 p->run_channels = channels;
819
820 p->running |= SNDRV_SB_CSP_ST_RUNNING;
821
822 if (p->mode & SNDRV_SB_CSP_MODE_QSOUND) {
823 set_codec_parameter(p->chip, 0xe0, 0x01);
824 /* enable QSound decoder */
825 set_codec_parameter(p->chip, 0x00, 0xff);
826 set_codec_parameter(p->chip, 0x01, 0xff);
827 p->running |= SNDRV_SB_CSP_ST_QSOUND;
828 /* set QSound startup value */
829 snd_sb_csp_qsound_transfer(p);
830 }
831 result = 0;
832
833 __fail:
834 spin_unlock(&p->chip->reg_lock);
835
836 /* restore PCM volume */
837 snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);
838 snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);
839 spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
840
841 return result;
842}
843
844/*
845 * stop CSP
846 */
847static int snd_sb_csp_stop(snd_sb_csp_t * p)
848{
849 int result;
850 unsigned char mixL, mixR;
851 unsigned long flags;
852
853 if (!(p->running & SNDRV_SB_CSP_ST_RUNNING))
854 return 0;
855
856 /* Mute PCM volume */
857 spin_lock_irqsave(&p->chip->mixer_lock, flags);
858 mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);
859 mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);
860 snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);
861 snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);
862
863 spin_lock(&p->chip->reg_lock);
864 if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
865 set_codec_parameter(p->chip, 0xe0, 0x01);
866 /* disable QSound decoder */
867 set_codec_parameter(p->chip, 0x00, 0x00);
868 set_codec_parameter(p->chip, 0x01, 0x00);
869
870 p->running &= ~SNDRV_SB_CSP_ST_QSOUND;
871 }
872 result = set_mode_register(p->chip, 0xc0); /* c0 = STOP */
873 spin_unlock(&p->chip->reg_lock);
874
875 /* restore PCM volume */
876 snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);
877 snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);
878 spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
879
880 if (!(result))
881 p->running &= ~(SNDRV_SB_CSP_ST_PAUSED | SNDRV_SB_CSP_ST_RUNNING);
882 return result;
883}
884
885/*
886 * pause CSP codec and hold DMA transfer
887 */
888static int snd_sb_csp_pause(snd_sb_csp_t * p)
889{
890 int result;
891 unsigned long flags;
892
893 if (!(p->running & SNDRV_SB_CSP_ST_RUNNING))
894 return -EBUSY;
895
896 spin_lock_irqsave(&p->chip->reg_lock, flags);
897 result = set_codec_parameter(p->chip, 0x80, 0xff);
898 spin_unlock_irqrestore(&p->chip->reg_lock, flags);
899 if (!(result))
900 p->running |= SNDRV_SB_CSP_ST_PAUSED;
901
902 return result;
903}
904
905/*
906 * restart CSP codec and resume DMA transfer
907 */
908static int snd_sb_csp_restart(snd_sb_csp_t * p)
909{
910 int result;
911 unsigned long flags;
912
913 if (!(p->running & SNDRV_SB_CSP_ST_PAUSED))
914 return -EBUSY;
915
916 spin_lock_irqsave(&p->chip->reg_lock, flags);
917 result = set_codec_parameter(p->chip, 0x80, 0x00);
918 spin_unlock_irqrestore(&p->chip->reg_lock, flags);
919 if (!(result))
920 p->running &= ~SNDRV_SB_CSP_ST_PAUSED;
921
922 return result;
923}
924
925/* ------------------------------ */
926
927/*
928 * QSound mixer control for PCM
929 */
930
931static int snd_sb_qsound_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
932{
933 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
934 uinfo->count = 1;
935 uinfo->value.integer.min = 0;
936 uinfo->value.integer.max = 1;
937 return 0;
938}
939
940static int snd_sb_qsound_switch_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
941{
942 snd_sb_csp_t *p = snd_kcontrol_chip(kcontrol);
943
944 ucontrol->value.integer.value[0] = p->q_enabled ? 1 : 0;
945 return 0;
946}
947
948static int snd_sb_qsound_switch_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
949{
950 snd_sb_csp_t *p = snd_kcontrol_chip(kcontrol);
951 unsigned long flags;
952 int change;
953 unsigned char nval;
954
955 nval = ucontrol->value.integer.value[0] & 0x01;
956 spin_lock_irqsave(&p->q_lock, flags);
957 change = p->q_enabled != nval;
958 p->q_enabled = nval;
959 spin_unlock_irqrestore(&p->q_lock, flags);
960 return change;
961}
962
963static int snd_sb_qsound_space_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
964{
965 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
966 uinfo->count = 2;
967 uinfo->value.integer.min = 0;
968 uinfo->value.integer.max = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;
969 return 0;
970}
971
972static int snd_sb_qsound_space_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
973{
974 snd_sb_csp_t *p = snd_kcontrol_chip(kcontrol);
975 unsigned long flags;
976
977 spin_lock_irqsave(&p->q_lock, flags);
978 ucontrol->value.integer.value[0] = p->qpos_left;
979 ucontrol->value.integer.value[1] = p->qpos_right;
980 spin_unlock_irqrestore(&p->q_lock, flags);
981 return 0;
982}
983
984static int snd_sb_qsound_space_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
985{
986 snd_sb_csp_t *p = snd_kcontrol_chip(kcontrol);
987 unsigned long flags;
988 int change;
989 unsigned char nval1, nval2;
990
991 nval1 = ucontrol->value.integer.value[0];
992 if (nval1 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT)
993 nval1 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;
994 nval2 = ucontrol->value.integer.value[1];
995 if (nval2 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT)
996 nval2 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;
997 spin_lock_irqsave(&p->q_lock, flags);
998 change = p->qpos_left != nval1 || p->qpos_right != nval2;
999 p->qpos_left = nval1;
1000 p->qpos_right = nval2;
1001 p->qpos_changed = change;
1002 spin_unlock_irqrestore(&p->q_lock, flags);
1003 return change;
1004}
1005
1006static snd_kcontrol_new_t snd_sb_qsound_switch = {
1007 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1008 .name = "3D Control - Switch",
1009 .info = snd_sb_qsound_switch_info,
1010 .get = snd_sb_qsound_switch_get,
1011 .put = snd_sb_qsound_switch_put
1012};
1013
1014static snd_kcontrol_new_t snd_sb_qsound_space = {
1015 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1016 .name = "3D Control - Space",
1017 .info = snd_sb_qsound_space_info,
1018 .get = snd_sb_qsound_space_get,
1019 .put = snd_sb_qsound_space_put
1020};
1021
1022static int snd_sb_qsound_build(snd_sb_csp_t * p)
1023{
1024 snd_card_t * card;
1025 int err;
1026
1027 snd_assert(p != NULL, return -EINVAL);
1028
1029 card = p->chip->card;
1030 p->qpos_left = p->qpos_right = SNDRV_SB_CSP_QSOUND_MAX_RIGHT / 2;
1031 p->qpos_changed = 0;
1032
1033 spin_lock_init(&p->q_lock);
1034
1035 if ((err = snd_ctl_add(card, p->qsound_switch = snd_ctl_new1(&snd_sb_qsound_switch, p))) < 0)
1036 goto __error;
1037 if ((err = snd_ctl_add(card, p->qsound_space = snd_ctl_new1(&snd_sb_qsound_space, p))) < 0)
1038 goto __error;
1039
1040 return 0;
1041
1042 __error:
1043 snd_sb_qsound_destroy(p);
1044 return err;
1045}
1046
1047static void snd_sb_qsound_destroy(snd_sb_csp_t * p)
1048{
1049 snd_card_t * card;
1050 unsigned long flags;
1051
1052 snd_assert(p != NULL, return);
1053
1054 card = p->chip->card;
1055
1056 down_write(&card->controls_rwsem);
1057 if (p->qsound_switch)
1058 snd_ctl_remove(card, p->qsound_switch);
1059 if (p->qsound_space)
1060 snd_ctl_remove(card, p->qsound_space);
1061 up_write(&card->controls_rwsem);
1062
1063 /* cancel pending transfer of QSound parameters */
1064 spin_lock_irqsave (&p->q_lock, flags);
1065 p->qpos_changed = 0;
1066 spin_unlock_irqrestore (&p->q_lock, flags);
1067}
1068
1069/*
1070 * Transfer qsound parameters to CSP,
1071 * function should be called from interrupt routine
1072 */
1073static int snd_sb_csp_qsound_transfer(snd_sb_csp_t * p)
1074{
1075 int err = -ENXIO;
1076
1077 spin_lock(&p->q_lock);
1078 if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
1079 set_codec_parameter(p->chip, 0xe0, 0x01);
1080 /* left channel */
1081 set_codec_parameter(p->chip, 0x00, p->qpos_left);
1082 set_codec_parameter(p->chip, 0x02, 0x00);
1083 /* right channel */
1084 set_codec_parameter(p->chip, 0x00, p->qpos_right);
1085 set_codec_parameter(p->chip, 0x03, 0x00);
1086 err = 0;
1087 }
1088 p->qpos_changed = 0;
1089 spin_unlock(&p->q_lock);
1090 return err;
1091}
1092
1093/* ------------------------------ */
1094
1095/*
1096 * proc interface
1097 */
1098static int init_proc_entry(snd_sb_csp_t * p, int device)
1099{
1100 char name[16];
1101 snd_info_entry_t *entry;
1102 sprintf(name, "cspD%d", device);
1103 if (! snd_card_proc_new(p->chip->card, name, &entry))
1104 snd_info_set_text_ops(entry, p, 1024, info_read);
1105 return 0;
1106}
1107
1108static void info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
1109{
1110 snd_sb_csp_t *p = entry->private_data;
1111
1112 snd_iprintf(buffer, "Creative Signal Processor [v%d.%d]\n", (p->version >> 4), (p->version & 0x0f));
1113 snd_iprintf(buffer, "State: %cx%c%c%c\n", ((p->running & SNDRV_SB_CSP_ST_QSOUND) ? 'Q' : '-'),
1114 ((p->running & SNDRV_SB_CSP_ST_PAUSED) ? 'P' : '-'),
1115 ((p->running & SNDRV_SB_CSP_ST_RUNNING) ? 'R' : '-'),
1116 ((p->running & SNDRV_SB_CSP_ST_LOADED) ? 'L' : '-'));
1117 if (p->running & SNDRV_SB_CSP_ST_LOADED) {
1118 snd_iprintf(buffer, "Codec: %s [func #%d]\n", p->codec_name, p->func_nr);
1119 snd_iprintf(buffer, "Sample rates: ");
1120 if (p->acc_rates == SNDRV_SB_CSP_RATE_ALL) {
1121 snd_iprintf(buffer, "All\n");
1122 } else {
1123 snd_iprintf(buffer, "%s%s%s%s\n",
1124 ((p->acc_rates & SNDRV_SB_CSP_RATE_8000) ? "8000Hz " : ""),
1125 ((p->acc_rates & SNDRV_SB_CSP_RATE_11025) ? "11025Hz " : ""),
1126 ((p->acc_rates & SNDRV_SB_CSP_RATE_22050) ? "22050Hz " : ""),
1127 ((p->acc_rates & SNDRV_SB_CSP_RATE_44100) ? "44100Hz" : ""));
1128 }
1129 if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {
1130 snd_iprintf(buffer, "QSound decoder %sabled\n",
1131 p->q_enabled ? "en" : "dis");
1132 } else {
1133 snd_iprintf(buffer, "PCM format ID: 0x%x (%s/%s) [%s/%s] [%s/%s]\n",
1134 p->acc_format,
1135 ((p->acc_width & SNDRV_SB_CSP_SAMPLE_16BIT) ? "16bit" : "-"),
1136 ((p->acc_width & SNDRV_SB_CSP_SAMPLE_8BIT) ? "8bit" : "-"),
1137 ((p->acc_channels & SNDRV_SB_CSP_MONO) ? "mono" : "-"),
1138 ((p->acc_channels & SNDRV_SB_CSP_STEREO) ? "stereo" : "-"),
1139 ((p->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) ? "playback" : "-"),
1140 ((p->mode & SNDRV_SB_CSP_MODE_DSP_READ) ? "capture" : "-"));
1141 }
1142 }
1143 if (p->running & SNDRV_SB_CSP_ST_AUTO) {
1144 snd_iprintf(buffer, "Autoloaded Mu-Law, A-Law or Ima-ADPCM hardware codec\n");
1145 }
1146 if (p->running & SNDRV_SB_CSP_ST_RUNNING) {
1147 snd_iprintf(buffer, "Processing %dbit %s PCM samples\n",
1148 ((p->run_width & SNDRV_SB_CSP_SAMPLE_16BIT) ? 16 : 8),
1149 ((p->run_channels & SNDRV_SB_CSP_MONO) ? "mono" : "stereo"));
1150 }
1151 if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
1152 snd_iprintf(buffer, "Qsound position: left = 0x%x, right = 0x%x\n",
1153 p->qpos_left, p->qpos_right);
1154 }
1155}
1156
1157/* */
1158
1159EXPORT_SYMBOL(snd_sb_csp_new);
1160
1161/*
1162 * INIT part
1163 */
1164
1165static int __init alsa_sb_csp_init(void)
1166{
1167 return 0;
1168}
1169
1170static void __exit alsa_sb_csp_exit(void)
1171{
1172}
1173
1174module_init(alsa_sb_csp_init)
1175module_exit(alsa_sb_csp_exit)
diff --git a/sound/isa/sb/sb16_csp_codecs.h b/sound/isa/sb/sb16_csp_codecs.h
new file mode 100644
index 000000000000..f0e8b0dcb572
--- /dev/null
+++ b/sound/isa/sb/sb16_csp_codecs.h
@@ -0,0 +1,949 @@
1/*
2 * Copyright (c) 1994 Creative Technology Ltd.
3 * Microcode files for SB16 Advanced Signal Processor
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21static unsigned char mulaw_main[] = {
22 0x00, 0x10, 0x00, 0x44, 0x08, 0x00, 0x00, 0x44,
23 0x00, 0xb1, 0x00, 0x44, 0x00, 0x61, 0x00, 0x44,
24 0x08, 0x50, 0x00, 0x44, 0x0d, 0xf2, 0x61, 0xa8,
25 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
26 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
27 0x50, 0x05, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
28 0xff, 0x2e, 0x21, 0x49, 0xff, 0x0f, 0xd4, 0x49,
29 0x20, 0x01, 0x09, 0x0e, 0x20, 0x00, 0x71, 0x8b,
30 0xa8, 0x01, 0xa8, 0x80, 0x88, 0x01, 0xa8, 0x80,
31 0xa8, 0x00, 0x00, 0x80, 0xd2, 0x00, 0x71, 0x8b,
32 0x88, 0x00, 0xa8, 0x80, 0xa8, 0x04, 0xb3, 0x80,
33 0x20, 0x07, 0xb3, 0x80, 0x88, 0x03, 0xb1, 0x80,
34 0xc0, 0x00, 0x09, 0x5c, 0xc2, 0x01, 0x00, 0x82,
35 0xa1, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x04, 0x19,
36 0xa2, 0x20, 0x71, 0x8b, 0xcf, 0x00, 0x04, 0x19,
37 0x00, 0x00, 0xb1, 0x80, 0xc2, 0x00, 0x04, 0x19,
38 0x00, 0x40, 0x00, 0x14, 0x08, 0x40, 0x04, 0x24,
39 0x00, 0x00, 0x34, 0x49, 0x0c, 0x40, 0x00, 0x44,
40 0x44, 0x04, 0x04, 0x39, 0x00, 0x00, 0x40, 0x45,
41 0x32, 0x00, 0x09, 0x5c, 0x00, 0x00, 0x0c, 0x39,
42 0x00, 0x00, 0x40, 0x45, 0x40, 0x40, 0x09, 0xef,
43 0xff, 0x20, 0x09, 0xcf, 0x00, 0x04, 0x63, 0xa1,
44 0x50, 0x03, 0x33, 0x80, 0x00, 0x04, 0xa3, 0x80,
45 0x00, 0xff, 0xc2, 0x8b, 0x00, 0xd0, 0x04, 0x54,
46 0x04, 0xe0, 0x00, 0xc4, 0x20, 0x03, 0x80, 0xc0,
47 0x30, 0x00, 0x00, 0x88, 0x00, 0x00, 0x7a, 0x0a,
48 0xd0, 0x01, 0x00, 0x82, 0x00, 0x60, 0x00, 0x44,
49 0xc0, 0x00, 0x00, 0x99, 0x00, 0x60, 0x00, 0x44,
50 0x00, 0xff, 0xc2, 0x8b, 0x20, 0x00, 0x00, 0x80,
51 0x00, 0x0d, 0x42, 0x8b, 0x08, 0x32, 0x00, 0xc4,
52 0x00, 0x0e, 0x42, 0x8b, 0x00, 0xa2, 0x00, 0xc4,
53 0x00, 0x1e, 0x42, 0x8b, 0x0c, 0xb2, 0x00, 0xc4,
54 0x00, 0x8e, 0x42, 0x8b, 0x00, 0x62, 0x00, 0xc4,
55 0x00, 0x9e, 0x42, 0x8b, 0x08, 0x52, 0x00, 0xc4,
56 0x00, 0xbe, 0x42, 0x8b, 0x08, 0x52, 0x00, 0xc4,
57 0x00, 0x04, 0x42, 0x8b, 0x04, 0x72, 0x00, 0xc4,
58 0x00, 0x24, 0x42, 0x8b, 0x00, 0xd2, 0x00, 0xc4,
59 0x00, 0x55, 0x42, 0x8b, 0x00, 0x60, 0x00, 0xc4,
60 0x00, 0x00, 0x40, 0x45, 0x20, 0x01, 0x79, 0x80,
61 0x00, 0x30, 0x42, 0x8b, 0x08, 0x82, 0x00, 0xc4,
62 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x71, 0x8b,
63 0x40, 0x01, 0x00, 0x80, 0x00, 0x60, 0x00, 0x44,
64 0xff, 0x00, 0xe2, 0xab, 0x00, 0xb2, 0x00, 0xc4,
65 0x0f, 0xf2, 0xa8, 0xa8, 0x20, 0x00, 0xb1, 0x88,
66 0x00, 0x00, 0x41, 0x02, 0x4d, 0xf2, 0x00, 0x39,
67 0xc0, 0x01, 0x00, 0x82, 0x00, 0x60, 0x00, 0x44,
68 0x0d, 0xf2, 0xa3, 0xa8, 0x4d, 0xf2, 0x00, 0x39,
69 0x00, 0x60, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
70 0x20, 0x00, 0x00, 0x88, 0x00, 0x00, 0x61, 0x02,
71 0x4d, 0xf2, 0x04, 0x19, 0x00, 0x60, 0x00, 0x44,
72 0xff, 0x00, 0xe2, 0xab, 0xa0, 0x00, 0x00, 0x88,
73 0x00, 0x00, 0x61, 0x10, 0x4d, 0xf2, 0x04, 0x19,
74 0x00, 0x60, 0x00, 0x44, 0xff, 0x20, 0xe2, 0xab,
75 0x60, 0x00, 0x00, 0x88, 0x00, 0x00, 0x71, 0xc0,
76 0x4d, 0xf2, 0x04, 0x19, 0x00, 0x60, 0x00, 0x44,
77 0x00, 0x00, 0x79, 0x80, 0x00, 0xe2, 0x00, 0x84,
78 0x03, 0x03, 0x04, 0x49, 0x08, 0xc2, 0x00, 0x54,
79 0x00, 0x60, 0x04, 0x64, 0x00, 0x60, 0x00, 0x44,
80 0x00, 0x00, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
81 0x03, 0x00, 0x04, 0x49, 0x00, 0x60, 0x00, 0x44,
82 0x20, 0x01, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
83 0x00, 0x20, 0xe2, 0x8b, 0x0c, 0xf2, 0x00, 0x84,
84 0x3e, 0x00, 0x51, 0x8b, 0xc0, 0x20, 0x00, 0x39,
85 0x08, 0x01, 0x00, 0x44, 0x6c, 0x00, 0x51, 0x8b,
86 0xc0, 0x20, 0x00, 0x39, 0x00, 0x02, 0xe2, 0x8b,
87 0x04, 0x21, 0x00, 0x84, 0xfd, 0x00, 0x51, 0x8b,
88 0xc2, 0x20, 0x00, 0x39, 0x00, 0x11, 0x00, 0x44,
89 0xfe, 0x00, 0x51, 0x8b, 0xc2, 0x20, 0x00, 0x39,
90 0xe5, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x00, 0x39,
91 0x00, 0x00, 0xb1, 0x80, 0xc9, 0x20, 0x04, 0x19,
92 0xcb, 0x20, 0x04, 0x19, 0xc1, 0x20, 0x04, 0x19,
93 0xc3, 0x20, 0x04, 0x19, 0x10, 0x00, 0x71, 0x8b,
94 0xc7, 0x20, 0x04, 0x19, 0x5e, 0x00, 0x71, 0x8b,
95 0xcf, 0x00, 0x00, 0x39, 0x00, 0x00, 0xb1, 0x80,
96 0xc4, 0x20, 0x04, 0x19, 0xc6, 0x20, 0x04, 0x19,
97 0xc8, 0x20, 0x04, 0x19, 0xca, 0x20, 0x04, 0x19,
98 0x20, 0x00, 0x71, 0x8b, 0xcc, 0x20, 0x04, 0x19,
99 0x03, 0x00, 0x04, 0x49, 0x00, 0x60, 0x00, 0x44,
100 0x09, 0x04, 0x61, 0xa8, 0xc1, 0x00, 0x04, 0x19,
101 0x0b, 0x04, 0x61, 0xa8, 0xca, 0x00, 0x04, 0x19,
102 0x04, 0x60, 0x00, 0xd4, 0x0d, 0x00, 0x61, 0x0a,
103 0x90, 0x40, 0x09, 0x8f, 0x00, 0x01, 0x00, 0x45,
104 0x0f, 0x00, 0x61, 0x0a, 0x00, 0x40, 0x09, 0x8f,
105 0x00, 0x01, 0x00, 0x45, 0x82, 0x00, 0x09, 0x2e,
106 0x80, 0x40, 0x09, 0xcf, 0x02, 0x00, 0x61, 0x22,
107 0x43, 0x25, 0x61, 0x22, 0x40, 0x33, 0x00, 0x80,
108 0x08, 0xa8, 0x00, 0x44, 0x20, 0x31, 0x49, 0x5c,
109 0x92, 0x00, 0x09, 0x4e, 0x02, 0x03, 0x09, 0x2e,
110 0x00, 0x00, 0xa3, 0x02, 0xc0, 0x00, 0x71, 0xc0,
111 0x20, 0x00, 0xeb, 0x80, 0x00, 0x04, 0xc2, 0x8b,
112 0x20, 0x04, 0x61, 0x80, 0x00, 0x04, 0x7a, 0x02,
113 0xcb, 0x00, 0xa8, 0x58, 0xb0, 0x05, 0xf3, 0x80,
114 0x20, 0x04, 0xa8, 0x10, 0x00, 0x00, 0x10, 0x39,
115 0xb0, 0x00, 0xe0, 0x8b, 0x20, 0x01, 0x00, 0x80,
116 0x00, 0x00, 0x63, 0xcb, 0x00, 0x00, 0x7a, 0x02,
117 0x40, 0x00, 0x01, 0x5b, 0x20, 0x00, 0x00, 0x80,
118 0x00, 0x00, 0x4a, 0xcb, 0x20, 0x00, 0x13, 0x80,
119 0x20, 0x00, 0x7a, 0x80, 0xe0, 0x21, 0x00, 0xc0,
120 0x08, 0x00, 0x08, 0x49, 0x10, 0x41, 0x09, 0x8e,
121 0xff, 0xff, 0x62, 0x8b, 0x00, 0x04, 0x61, 0x22,
122 0x00, 0x03, 0x00, 0x45, 0x22, 0x01, 0x33, 0x80,
123 0x20, 0x01, 0xa3, 0x02, 0x00, 0x00, 0x7a, 0x80,
124 0xc0, 0x00, 0x00, 0x82, 0x07, 0x20, 0x40, 0x0a,
125 0x08, 0x83, 0x00, 0x84, 0x40, 0x21, 0x00, 0x80,
126 0x40, 0x05, 0x93, 0x10, 0xc7, 0x20, 0x00, 0x39,
127 0x00, 0x00, 0x40, 0x45, 0x07, 0x20, 0x40, 0x0a,
128 0x0c, 0xa3, 0x00, 0x84, 0x08, 0x00, 0x00, 0x82,
129 0x0c, 0x24, 0x61, 0x50, 0x40, 0x01, 0x00, 0x80,
130 0xc7, 0x20, 0x00, 0x39, 0x00, 0x00, 0x40, 0x45,
131 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
132 0x42, 0x01, 0x09, 0x0e, 0x02, 0x20, 0x61, 0x0a,
133 0x00, 0x01, 0x00, 0x45, 0x0c, 0x20, 0x60, 0x0a,
134 0x00, 0x73, 0x00, 0x84, 0x00, 0x04, 0xb1, 0x80,
135 0x00, 0x00, 0x06, 0x39, 0x0c, 0x61, 0x04, 0xd4,
136 0x00, 0x24, 0x71, 0xc0, 0x20, 0x33, 0x33, 0xc0,
137 0xe0, 0x01, 0xa3, 0x82, 0x22, 0x03, 0x7a, 0x02,
138 0xc3, 0x01, 0xa3, 0x82, 0x20, 0x01, 0x33, 0x80,
139 0x00, 0x00, 0x7a, 0x80, 0xc2, 0x01, 0xb3, 0x50,
140 0xcc, 0x20, 0x00, 0x39, 0x00, 0x00, 0x71, 0x80,
141 0x00, 0xf3, 0x00, 0x44, 0x0c, 0x20, 0x60, 0x0a,
142 0x00, 0xd3, 0x00, 0x84, 0x00, 0x04, 0xb1, 0x80,
143 0x00, 0x00, 0x06, 0x39, 0x0c, 0x61, 0x04, 0xd4,
144 0x00, 0x00, 0xb3, 0x10, 0xcc, 0x20, 0x00, 0x39,
145 0x00, 0x00, 0x71, 0xc0, 0x00, 0xf3, 0x00, 0x44,
146 0xcc, 0x20, 0x00, 0x39, 0x00, 0x20, 0x71, 0xc0,
147 0x00, 0x30, 0x71, 0xc0, 0x00, 0xf3, 0x00, 0x44,
148 0x20, 0x01, 0x00, 0x80, 0xff, 0xff, 0x62, 0x8b,
149 0x20, 0x01, 0x33, 0x80, 0x00, 0x00, 0x83, 0x80,
150 0x20, 0x00, 0x7a, 0x80, 0x20, 0xe1, 0x09, 0x5c,
151 0x82, 0x00, 0x09, 0x2f, 0x80, 0x4a, 0x09, 0x8e,
152 0xe0, 0x01, 0xb3, 0x82, 0x20, 0x04, 0xa3, 0x80,
153 0x00, 0x00, 0x7a, 0xcb, 0x03, 0x00, 0xa8, 0x18,
154 0x00, 0x00, 0x10, 0x39, 0x08, 0x04, 0xea, 0x10,
155 0x08, 0x04, 0x7a, 0x10, 0x20, 0x00, 0x00, 0x80,
156 0x40, 0x00, 0x21, 0xcb, 0x0c, 0x00, 0xe8, 0x10,
157 0x00, 0x00, 0x41, 0x02, 0x0c, 0x00, 0xeb, 0x10,
158 0xf2, 0x01, 0x00, 0x82, 0x40, 0x21, 0x33, 0x02,
159 0x08, 0x20, 0x61, 0x0a, 0xc4, 0x00, 0x04, 0x19,
160 0xc7, 0x00, 0x00, 0x99, 0x02, 0x00, 0x61, 0x0a,
161 0x0c, 0xe8, 0x04, 0x14, 0x01, 0x00, 0x61, 0x0a,
162 0x03, 0x00, 0x48, 0x0a, 0x00, 0xb8, 0x04, 0x54,
163 0xc3, 0x00, 0x04, 0x19, 0x0c, 0xb8, 0x00, 0x44,
164 0x08, 0x00, 0xc8, 0x0a, 0x0c, 0xb8, 0x04, 0x54,
165 0xc8, 0x00, 0x04, 0x19, 0x0a, 0x00, 0x61, 0x0a,
166 0x09, 0x00, 0x48, 0x0a, 0x00, 0x68, 0x04, 0x54,
167 0xc9, 0x00, 0x04, 0x19, 0x0c, 0x68, 0x00, 0x44,
168 0x0b, 0x00, 0xc8, 0x0a, 0x0c, 0x68, 0x04, 0x54,
169 0xcb, 0x00, 0x04, 0x19, 0x04, 0x00, 0x61, 0x0a,
170 0x06, 0x00, 0x48, 0x0a, 0x00, 0x78, 0x04, 0x54,
171 0xc6, 0x00, 0x04, 0x19, 0x0c, 0x78, 0x00, 0x44,
172 0x05, 0x00, 0xc8, 0x0a, 0x0c, 0x78, 0x04, 0x54,
173 0xc5, 0x00, 0x04, 0x19, 0x07, 0x00, 0x61, 0x0a,
174 0x0c, 0x00, 0x48, 0x0a, 0x00, 0xe8, 0x04, 0x54,
175 0xcc, 0x00, 0x04, 0x19, 0x0c, 0xe8, 0x00, 0x44,
176 0x0e, 0x00, 0xc8, 0x0a, 0x0c, 0xe8, 0x04, 0x54,
177 0xce, 0x00, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
178 0x20, 0x10, 0x71, 0x8b, 0x09, 0x3f, 0x07, 0x00
179};
180
181static unsigned char alaw_main[] = {
182 0x00, 0x10, 0x00, 0x44, 0x08, 0x00, 0x00, 0x44,
183 0x00, 0xb1, 0x00, 0x44, 0x00, 0x61, 0x00, 0x44,
184 0x08, 0x50, 0x00, 0x44, 0x0d, 0xf2, 0x61, 0xa8,
185 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
186 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
187 0x50, 0x05, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
188 0xff, 0x2e, 0x21, 0x49, 0xff, 0x0f, 0xd4, 0x49,
189 0x20, 0x01, 0x09, 0x0e, 0x20, 0x00, 0x71, 0x8b,
190 0xa8, 0x01, 0xa8, 0x80, 0x88, 0x01, 0xa8, 0x80,
191 0xa8, 0x00, 0x00, 0x80, 0xd2, 0x00, 0x71, 0x8b,
192 0x88, 0x00, 0xa8, 0x80, 0xa8, 0x04, 0xb3, 0x80,
193 0x20, 0x07, 0xb3, 0x80, 0x88, 0x03, 0xb1, 0x80,
194 0xc0, 0x00, 0x09, 0x5c, 0xc2, 0x01, 0x00, 0x82,
195 0xa1, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x04, 0x19,
196 0x21, 0x20, 0x71, 0x8b, 0xcf, 0x00, 0x04, 0x19,
197 0x00, 0x00, 0xb1, 0x80, 0xc2, 0x00, 0x04, 0x19,
198 0x00, 0x40, 0x00, 0x14, 0x08, 0x40, 0x04, 0x24,
199 0x00, 0x00, 0x34, 0x49, 0x0c, 0x40, 0x00, 0x44,
200 0x44, 0x04, 0x04, 0x39, 0x00, 0x00, 0x40, 0x45,
201 0x32, 0x00, 0x09, 0x5c, 0x00, 0x00, 0x0c, 0x39,
202 0x00, 0x00, 0x40, 0x45, 0x40, 0x40, 0x09, 0xef,
203 0xff, 0x20, 0x09, 0xcf, 0x00, 0x04, 0x63, 0xa1,
204 0x50, 0x03, 0x33, 0x80, 0x00, 0x04, 0xa3, 0x80,
205 0x00, 0xff, 0xc2, 0x8b, 0x00, 0xd0, 0x04, 0x54,
206 0x04, 0xe0, 0x00, 0xc4, 0x20, 0x03, 0x80, 0xc0,
207 0x30, 0x00, 0x00, 0x88, 0x00, 0x00, 0x7a, 0x0a,
208 0xd0, 0x01, 0x00, 0x82, 0x00, 0x60, 0x00, 0x44,
209 0xc0, 0x00, 0x00, 0x99, 0x00, 0x60, 0x00, 0x44,
210 0x00, 0xff, 0xc2, 0x8b, 0x20, 0x00, 0x00, 0x80,
211 0x00, 0x0d, 0x42, 0x8b, 0x08, 0x32, 0x00, 0xc4,
212 0x00, 0x0e, 0x42, 0x8b, 0x00, 0xa2, 0x00, 0xc4,
213 0x00, 0x1e, 0x42, 0x8b, 0x0c, 0xb2, 0x00, 0xc4,
214 0x00, 0x8e, 0x42, 0x8b, 0x00, 0x62, 0x00, 0xc4,
215 0x00, 0x9e, 0x42, 0x8b, 0x08, 0x52, 0x00, 0xc4,
216 0x00, 0xbe, 0x42, 0x8b, 0x08, 0x52, 0x00, 0xc4,
217 0x00, 0x04, 0x42, 0x8b, 0x04, 0x72, 0x00, 0xc4,
218 0x00, 0x24, 0x42, 0x8b, 0x00, 0xd2, 0x00, 0xc4,
219 0x00, 0x55, 0x42, 0x8b, 0x00, 0x60, 0x00, 0xc4,
220 0x00, 0x00, 0x40, 0x45, 0x20, 0x01, 0x79, 0x80,
221 0x00, 0x30, 0x42, 0x8b, 0x08, 0x82, 0x00, 0xc4,
222 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x71, 0x8b,
223 0x40, 0x01, 0x00, 0x80, 0x00, 0x60, 0x00, 0x44,
224 0xff, 0x00, 0xe2, 0xab, 0x00, 0xb2, 0x00, 0xc4,
225 0x0f, 0xf2, 0xa8, 0xa8, 0x20, 0x00, 0xb1, 0x88,
226 0x00, 0x00, 0x41, 0x02, 0x4d, 0xf2, 0x00, 0x39,
227 0xc0, 0x01, 0x00, 0x82, 0x00, 0x60, 0x00, 0x44,
228 0x0d, 0xf2, 0xa3, 0xa8, 0x4d, 0xf2, 0x00, 0x39,
229 0x00, 0x60, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
230 0x20, 0x00, 0x00, 0x88, 0x00, 0x00, 0x61, 0x02,
231 0x4d, 0xf2, 0x04, 0x19, 0x00, 0x60, 0x00, 0x44,
232 0xff, 0x00, 0xe2, 0xab, 0xa0, 0x00, 0x00, 0x88,
233 0x00, 0x00, 0x61, 0x10, 0x4d, 0xf2, 0x04, 0x19,
234 0x00, 0x60, 0x00, 0x44, 0xff, 0x20, 0xe2, 0xab,
235 0x60, 0x00, 0x00, 0x88, 0x00, 0x00, 0x71, 0xc0,
236 0x4d, 0xf2, 0x04, 0x19, 0x00, 0x60, 0x00, 0x44,
237 0x00, 0x00, 0x79, 0x80, 0x00, 0xe2, 0x00, 0x84,
238 0x03, 0x03, 0x04, 0x49, 0x04, 0xc2, 0x00, 0x54,
239 0x00, 0x60, 0x04, 0x64, 0x00, 0x60, 0x00, 0x44,
240 0x00, 0x00, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
241 0x03, 0x00, 0x04, 0x49, 0x00, 0x60, 0x00, 0x44,
242 0x20, 0x01, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
243 0x00, 0x20, 0xe2, 0x8b, 0x0c, 0xf2, 0x00, 0x84,
244 0xbe, 0x00, 0x51, 0x8b, 0xc0, 0x20, 0x00, 0x39,
245 0x08, 0x01, 0x00, 0x44, 0xec, 0x00, 0x51, 0x8b,
246 0xc0, 0x20, 0x00, 0x39, 0x00, 0x02, 0xe2, 0x8b,
247 0x04, 0x21, 0x00, 0x84, 0x3f, 0x00, 0x51, 0x8b,
248 0xc2, 0x20, 0x00, 0x39, 0x00, 0x11, 0x00, 0x44,
249 0x3d, 0x00, 0x51, 0x8b, 0xc2, 0x20, 0x00, 0x39,
250 0xe5, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x00, 0x39,
251 0x00, 0x00, 0xb1, 0x80, 0xc9, 0x20, 0x04, 0x19,
252 0xcb, 0x20, 0x04, 0x19, 0xc1, 0x20, 0x04, 0x19,
253 0xc3, 0x20, 0x04, 0x19, 0x10, 0x00, 0x71, 0x8b,
254 0xc7, 0x20, 0x04, 0x19, 0xde, 0x00, 0x51, 0x8b,
255 0xcf, 0x00, 0x00, 0x39, 0x00, 0x01, 0xb1, 0x80,
256 0xc4, 0x20, 0x04, 0x19, 0xc6, 0x20, 0x04, 0x19,
257 0xc8, 0x20, 0x04, 0x19, 0xca, 0x20, 0x04, 0x19,
258 0x20, 0x00, 0x71, 0x8b, 0xcc, 0x20, 0x04, 0x19,
259 0x03, 0x00, 0x04, 0x49, 0x00, 0x60, 0x00, 0x44,
260 0x09, 0x04, 0x61, 0xa8, 0xc1, 0x00, 0x04, 0x19,
261 0x0b, 0x04, 0x61, 0xa8, 0xca, 0x00, 0x04, 0x19,
262 0x04, 0x60, 0x00, 0xd4, 0x0d, 0x00, 0x61, 0x0a,
263 0x90, 0x40, 0x09, 0x8f, 0x00, 0x01, 0x00, 0x45,
264 0x0f, 0x00, 0x61, 0x0a, 0x00, 0x40, 0x09, 0x8f,
265 0x00, 0x01, 0x00, 0x45, 0x82, 0x00, 0x09, 0x2e,
266 0x80, 0x40, 0x09, 0xcf, 0x02, 0x00, 0x61, 0x22,
267 0x43, 0x25, 0x61, 0x22, 0x40, 0x33, 0x00, 0x80,
268 0x08, 0x48, 0x00, 0x44, 0x20, 0xb1, 0x49, 0x5c,
269 0x92, 0x00, 0x09, 0x4e, 0x02, 0x03, 0x09, 0x2e,
270 0x00, 0x00, 0xa3, 0x02, 0xc0, 0x00, 0x71, 0xc0,
271 0x20, 0x00, 0xeb, 0x80, 0x00, 0x04, 0xc2, 0x8b,
272 0x20, 0x04, 0x61, 0x80, 0x00, 0x04, 0x7a, 0x02,
273 0xc0, 0x00, 0x00, 0x82, 0x0c, 0xc3, 0x08, 0x49,
274 0xb0, 0x01, 0xf3, 0x80, 0x00, 0x00, 0x10, 0x39,
275 0x20, 0x00, 0x0c, 0x89, 0x0c, 0x88, 0x08, 0x49,
276 0x03, 0x00, 0xa8, 0x18, 0x00, 0x00, 0x10, 0x39,
277 0xbd, 0xff, 0x62, 0x8b, 0x20, 0x01, 0x00, 0x80,
278 0x00, 0x00, 0x63, 0xcb, 0x00, 0x00, 0x7a, 0x02,
279 0x40, 0x00, 0x01, 0x5b, 0x20, 0x00, 0x00, 0x80,
280 0x00, 0x00, 0x4a, 0xcb, 0x20, 0x00, 0x13, 0x80,
281 0x20, 0x00, 0x7a, 0x80, 0xe0, 0x21, 0x00, 0xc0,
282 0x08, 0x00, 0x08, 0x49, 0x10, 0x41, 0x09, 0x8e,
283 0xae, 0xae, 0x62, 0x8b, 0x00, 0x04, 0x61, 0x22,
284 0x00, 0x03, 0x00, 0x45, 0x22, 0x01, 0x33, 0x80,
285 0x20, 0x01, 0xa3, 0x02, 0x00, 0x00, 0x7a, 0x80,
286 0xc0, 0x00, 0x00, 0x82, 0x07, 0x20, 0x40, 0x0a,
287 0x08, 0xa3, 0x00, 0x84, 0x40, 0x21, 0x00, 0x80,
288 0x40, 0x05, 0x93, 0x10, 0xc7, 0x20, 0x00, 0x39,
289 0x00, 0x00, 0x40, 0x45, 0x07, 0x20, 0x40, 0x0a,
290 0x0c, 0x93, 0x00, 0x84, 0x08, 0x00, 0x00, 0x82,
291 0x0c, 0x24, 0x61, 0x50, 0x40, 0x01, 0x00, 0x80,
292 0xc7, 0x20, 0x00, 0x39, 0x00, 0x00, 0x40, 0x45,
293 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
294 0x42, 0x01, 0x09, 0x0e, 0x02, 0x20, 0x61, 0x0a,
295 0x00, 0x01, 0x00, 0x45, 0x0c, 0x20, 0x60, 0x0a,
296 0x00, 0xc3, 0x00, 0x84, 0x00, 0x04, 0xb1, 0x80,
297 0x00, 0x00, 0x06, 0x39, 0x0c, 0x61, 0x04, 0xd4,
298 0x00, 0x24, 0x71, 0xc0, 0x20, 0x33, 0x33, 0xc0,
299 0xe0, 0x01, 0xa3, 0x82, 0x22, 0x03, 0x7a, 0x02,
300 0xc3, 0x01, 0xa3, 0x82, 0x20, 0x01, 0x33, 0x80,
301 0x00, 0x00, 0x7a, 0x80, 0xc2, 0x01, 0xb3, 0x50,
302 0xcc, 0x20, 0x00, 0x39, 0x00, 0x00, 0x71, 0x80,
303 0x00, 0x08, 0x00, 0x44, 0x0c, 0x20, 0x60, 0x0a,
304 0x00, 0xf3, 0x00, 0x84, 0x00, 0x04, 0xb1, 0x80,
305 0x00, 0x00, 0x06, 0x39, 0x0c, 0x61, 0x04, 0xd4,
306 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x93, 0x10,
307 0xcc, 0x20, 0x00, 0x39, 0x00, 0x08, 0x00, 0x44,
308 0xcc, 0x20, 0x00, 0x39, 0x00, 0x20, 0x00, 0xc0,
309 0x00, 0x30, 0x71, 0xc0, 0x00, 0x08, 0x00, 0x44,
310 0x20, 0x01, 0x00, 0x80, 0xae, 0xae, 0x62, 0x8b,
311 0x20, 0x01, 0x33, 0x80, 0x00, 0x00, 0x83, 0x80,
312 0x20, 0x00, 0x7a, 0x80, 0x20, 0xa1, 0x49, 0x5c,
313 0x82, 0x00, 0x09, 0x6e, 0x80, 0x4a, 0x09, 0x8e,
314 0xe0, 0x01, 0xb3, 0x82, 0x20, 0x04, 0xa3, 0x80,
315 0x00, 0x00, 0x7a, 0xcb, 0x28, 0x04, 0xea, 0x10,
316 0x0c, 0x04, 0x7a, 0x10, 0x70, 0x00, 0xc0, 0x8b,
317 0x00, 0x00, 0x10, 0x39, 0x90, 0x03, 0x00, 0x80,
318 0x40, 0x00, 0x21, 0x5b, 0x90, 0x00, 0x61, 0x80,
319 0x0c, 0x8a, 0x08, 0x49, 0x00, 0x00, 0x1c, 0x19,
320 0x40, 0x00, 0x08, 0x5b, 0x08, 0x00, 0x08, 0x49,
321 0x20, 0x02, 0x00, 0x80, 0x03, 0x00, 0xa8, 0x18,
322 0x00, 0x00, 0x14, 0x19, 0x40, 0x00, 0x21, 0xcb,
323 0x00, 0x00, 0x41, 0x02, 0x00, 0x00, 0xeb, 0x80,
324 0xf2, 0x01, 0x00, 0x82, 0x40, 0x21, 0x33, 0x02,
325 0x08, 0x20, 0x61, 0x0a, 0xc4, 0x00, 0x04, 0x19,
326 0xc7, 0x00, 0x00, 0x99, 0x02, 0x00, 0x61, 0x0a,
327 0x0c, 0x0a, 0x04, 0x14, 0x01, 0x00, 0x61, 0x0a,
328 0x03, 0x00, 0x48, 0x0a, 0x00, 0x58, 0x04, 0x54,
329 0xc3, 0x00, 0x04, 0x19, 0x0c, 0x58, 0x00, 0x44,
330 0x08, 0x00, 0xc8, 0x0a, 0x0c, 0x58, 0x04, 0x54,
331 0xc8, 0x00, 0x04, 0x19, 0x0a, 0x00, 0x61, 0x0a,
332 0x09, 0x00, 0x48, 0x0a, 0x00, 0xc8, 0x04, 0x54,
333 0xc9, 0x00, 0x04, 0x19, 0x0c, 0xc8, 0x00, 0x44,
334 0x0b, 0x00, 0xc8, 0x0a, 0x0c, 0xc8, 0x04, 0x54,
335 0xcb, 0x00, 0x04, 0x19, 0x04, 0x00, 0x61, 0x0a,
336 0x06, 0x00, 0x48, 0x0a, 0x00, 0xd8, 0x04, 0x54,
337 0xc6, 0x00, 0x04, 0x19, 0x0c, 0xd8, 0x00, 0x44,
338 0x05, 0x00, 0xc8, 0x0a, 0x0c, 0xd8, 0x04, 0x54,
339 0xc5, 0x00, 0x04, 0x19, 0x07, 0x00, 0x61, 0x0a,
340 0x0c, 0x00, 0x48, 0x0a, 0x00, 0x0a, 0x04, 0x54,
341 0xcc, 0x00, 0x04, 0x19, 0x0c, 0x0a, 0x00, 0x44,
342 0x0e, 0x00, 0xc8, 0x0a, 0x0c, 0x0a, 0x04, 0x54,
343 0xce, 0x00, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
344 0x20, 0x10, 0x71, 0x8b, 0x08, 0x42, 0x06, 0x00
345};
346
347
348static unsigned char ima_adpcm_init[] = {
349 0x00, 0x10, 0x00, 0x44, 0x00, 0x00, 0x40, 0x45,
350 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x40, 0x45,
351 0x00, 0x00, 0x40, 0x45, 0xaa, 0xaa, 0x71, 0x8b,
352 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
353 0xff, 0x6e, 0x21, 0x49, 0xff, 0x0f, 0xd4, 0x49,
354 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
355 0x50, 0x05, 0xb1, 0x80, 0x62, 0x00, 0x19, 0x0e,
356 0x21, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
357 0xb0, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
358 0x40, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
359 0x60, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
360 0x50, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
361 0x70, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
362 0xc0, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
363 0xe0, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
364 0xd0, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
365 0x02, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
366 0x22, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
367 0x32, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
368 0xa2, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
369 0xb2, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
370 0x62, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
371 0xc2, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
372 0xf2, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
373 0x11, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
374 0xa1, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
375 0x61, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
376 0xe1, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
377 0x13, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
378 0xb3, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
379 0xc3, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
380 0x18, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
381 0x68, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
382 0x0a, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
383 0x4a, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
384 0x29, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
385 0x79, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
386 0x9b, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
387 0x14, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
388 0xf4, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
389 0xe6, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
390 0xe5, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
391 0xd7, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
392 0x2e, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
393 0x9d, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
394 0xef, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
395 0xb2, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
396 0x33, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
397 0x2a, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
398 0x3b, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
399 0x46, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
400 0x2c, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
401 0xdd, 0x20, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
402 0x01, 0x10, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
403 0x9a, 0x10, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
404 0x16, 0x10, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
405 0x8e, 0x10, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
406 0xc2, 0x30, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
407 0xc9, 0x30, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
408 0x3c, 0x30, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
409 0x81, 0x80, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
410 0xd4, 0x80, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
411 0x10, 0xa0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
412 0x34, 0xa0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
413 0x02, 0x90, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
414 0x75, 0x90, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
415 0x9a, 0xb0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
416 0x12, 0x40, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
417 0x0d, 0x40, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
418 0x3c, 0x60, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
419 0xe7, 0x50, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
420 0x0e, 0x70, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
421 0xff, 0xc0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
422 0xc8, 0xd0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
423 0x57, 0xf0, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
424 0xc8, 0x22, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
425 0xb0, 0x32, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
426 0xdd, 0x82, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
427 0x90, 0xb2, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
428 0x8a, 0x62, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
429 0xce, 0x72, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
430 0xa5, 0xd2, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
431 0x97, 0x21, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
432 0xa2, 0xa1, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
433 0x5c, 0x41, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
434 0xfe, 0xc1, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
435 0x7a, 0x23, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
436 0x78, 0x93, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
437 0x67, 0x73, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
438 0x17, 0x28, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
439 0x88, 0x48, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
440 0xdb, 0xf8, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
441 0x2b, 0xba, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
442 0xf1, 0x09, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
443 0xdc, 0x69, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
444 0x19, 0x8b, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
445 0xff, 0xfb, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
446 0x20, 0x00, 0x71, 0x8b, 0x88, 0x00, 0x00, 0x80,
447 0x52, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
448 0xff, 0xff, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
449 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x00, 0x00, 0x82,
450 0xc2, 0x00, 0x00, 0x82, 0x10, 0x00, 0x71, 0x8b,
451 0xc2, 0x00, 0x00, 0x82, 0x80, 0x00, 0x71, 0x8b,
452 0xc2, 0x00, 0x00, 0x82, 0x90, 0x00, 0x71, 0x8b,
453 0xc2, 0x00, 0x00, 0x82, 0x40, 0x00, 0x71, 0x8b,
454 0xc2, 0x00, 0x00, 0x82, 0xff, 0xff, 0x71, 0x8b,
455 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x00, 0x00, 0x82,
456 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x00, 0x00, 0x82,
457 0x10, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
458 0x80, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
459 0x90, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
460 0x40, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
461 0xff, 0xfb, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
462 0x00, 0x04, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
463 0x4a, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
464 0x00, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
465 0x00, 0x00, 0x71, 0x8b, 0xc2, 0x00, 0x00, 0x82,
466 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x30, 0x04, 0x19,
467 0x10, 0x00, 0x09, 0x4f, 0xc2, 0x01, 0x00, 0x82,
468 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
469 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
470 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
471 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
472 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
473 0xc2, 0x01, 0x00, 0x82, 0xc2, 0x01, 0x00, 0x82,
474 0x00, 0x10, 0x71, 0x8b, 0xc1, 0x30, 0x04, 0x19,
475 0x93, 0x00, 0x01, 0x4f, 0xcd, 0x30, 0x00, 0x09,
476 0xcf, 0x30, 0x00, 0x09, 0x00, 0x00, 0x34, 0x49,
477 0x00, 0x08, 0x00, 0x44, 0xc8, 0x54, 0x11, 0x00
478};
479
480static unsigned char ima_adpcm_playback[] = {
481 0x00, 0x10, 0x00, 0x44, 0x08, 0x00, 0x00, 0x44,
482 0x0c, 0x50, 0x00, 0x44, 0x00, 0x70, 0x00, 0x44,
483 0x04, 0x70, 0x00, 0x44, 0x0d, 0xf2, 0x61, 0xa8,
484 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
485 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
486 0xff, 0x2e, 0x21, 0x49, 0xff, 0x0d, 0xd4, 0x49,
487 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
488 0x50, 0x01, 0xb1, 0x80, 0x00, 0x01, 0xb1, 0x80,
489 0xc9, 0x20, 0x04, 0x19, 0x51, 0x00, 0x71, 0x8b,
490 0xcd, 0x00, 0x04, 0x19, 0xe4, 0x20, 0x71, 0x8b,
491 0xcf, 0x00, 0x04, 0x19, 0x80, 0x00, 0x71, 0x8b,
492 0xcb, 0x20, 0x04, 0x19, 0x10, 0x00, 0x71, 0x8b,
493 0xc4, 0x20, 0x04, 0x19, 0x65, 0x00, 0x51, 0x8b,
494 0xc2, 0x20, 0x00, 0x39, 0x00, 0x00, 0xb1, 0x80,
495 0xc2, 0x30, 0x04, 0x19, 0x00, 0x00, 0x63, 0x80,
496 0xc1, 0xa0, 0x04, 0x19, 0x93, 0x00, 0x01, 0x4f,
497 0xcd, 0x30, 0x00, 0x09, 0xcf, 0x30, 0x00, 0x09,
498 0x04, 0x40, 0x00, 0x14, 0x0c, 0x40, 0x00, 0x14,
499 0x00, 0x04, 0x61, 0xa8, 0x02, 0x04, 0x61, 0xa8,
500 0x04, 0x60, 0x04, 0x24, 0x00, 0x00, 0x34, 0x49,
501 0x00, 0x50, 0x00, 0x44, 0x44, 0x04, 0x04, 0x39,
502 0x00, 0x00, 0x40, 0x45, 0x00, 0x00, 0x40, 0x45,
503 0x0f, 0x00, 0x61, 0x0a, 0x00, 0x01, 0x00, 0x45,
504 0x40, 0x40, 0x09, 0xef, 0xff, 0x20, 0x09, 0xcf,
505 0x00, 0x04, 0x63, 0xa1, 0x50, 0x03, 0x33, 0x80,
506 0x00, 0x04, 0xa3, 0x80, 0x00, 0xff, 0xc2, 0x8b,
507 0x08, 0xf0, 0x04, 0x54, 0x0c, 0xd0, 0x00, 0xc4,
508 0x20, 0x03, 0x80, 0xc0, 0x30, 0x00, 0x00, 0x88,
509 0x00, 0x00, 0x7a, 0x0a, 0xd0, 0x01, 0x00, 0x82,
510 0x08, 0x50, 0x00, 0x44, 0xc0, 0x00, 0x00, 0x99,
511 0x08, 0x50, 0x00, 0x44, 0x00, 0xff, 0xc2, 0x8b,
512 0x20, 0x00, 0x00, 0x80, 0x00, 0x0d, 0x42, 0x8b,
513 0x00, 0xa2, 0x00, 0xc4, 0x00, 0x0e, 0x42, 0x8b,
514 0x0c, 0x92, 0x00, 0xc4, 0x00, 0x1e, 0x42, 0x8b,
515 0x04, 0x62, 0x00, 0xc4, 0x00, 0x8e, 0x42, 0x8b,
516 0x0c, 0x52, 0x00, 0xc4, 0x00, 0x9e, 0x42, 0x8b,
517 0x00, 0xc2, 0x00, 0xc4, 0x00, 0xbe, 0x42, 0x8b,
518 0x00, 0xc2, 0x00, 0xc4, 0x00, 0x04, 0x42, 0x8b,
519 0x00, 0xf2, 0x00, 0xc4, 0x00, 0x24, 0x42, 0x8b,
520 0x00, 0x91, 0x00, 0xc4, 0x00, 0x55, 0x42, 0x8b,
521 0x08, 0x50, 0x00, 0xc4, 0x00, 0x3f, 0x42, 0x8b,
522 0x08, 0xe2, 0x00, 0xc4, 0x00, 0x00, 0x40, 0x45,
523 0x20, 0x01, 0x79, 0x80, 0x00, 0x30, 0x42, 0x8b,
524 0x00, 0x92, 0x00, 0xc4, 0x00, 0x00, 0x40, 0x45,
525 0x00, 0x00, 0x71, 0x8b, 0x40, 0x01, 0x00, 0x80,
526 0x08, 0x50, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
527 0x0c, 0x42, 0x00, 0xc4, 0x0f, 0xf2, 0xa8, 0xa8,
528 0x20, 0x00, 0xb1, 0x88, 0x00, 0x00, 0x41, 0x02,
529 0x4d, 0xf2, 0x00, 0x39, 0xc0, 0x01, 0x00, 0x82,
530 0x08, 0x50, 0x00, 0x44, 0x0d, 0xf2, 0xa3, 0xa8,
531 0x4d, 0xf2, 0x00, 0x39, 0x08, 0x50, 0x00, 0x44,
532 0xff, 0x00, 0xe2, 0xab, 0x20, 0x00, 0x00, 0x88,
533 0x00, 0x00, 0x61, 0x02, 0x4d, 0xf2, 0x04, 0x19,
534 0x08, 0x50, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
535 0xa0, 0x00, 0x00, 0x88, 0x00, 0x00, 0x61, 0x10,
536 0x4d, 0xf2, 0x04, 0x19, 0x08, 0x50, 0x00, 0x44,
537 0xff, 0x20, 0xe2, 0xab, 0x60, 0x00, 0x00, 0x88,
538 0x00, 0x00, 0x71, 0xc0, 0x4d, 0xf2, 0x04, 0x19,
539 0x08, 0x50, 0x00, 0x44, 0x00, 0x00, 0x7a, 0x0a,
540 0x20, 0x01, 0xf0, 0x80, 0x01, 0xa0, 0x41, 0x0a,
541 0x04, 0xd2, 0x00, 0xc4, 0x20, 0x01, 0xf0, 0x80,
542 0xc1, 0x30, 0x04, 0x19, 0x08, 0x50, 0x00, 0x44,
543 0x00, 0x00, 0x79, 0x80, 0x00, 0xa1, 0x00, 0x84,
544 0xb5, 0x00, 0x51, 0x8b, 0xcf, 0x00, 0x00, 0x39,
545 0x00, 0x01, 0xb1, 0x80, 0x88, 0x00, 0x04, 0x19,
546 0x8a, 0x00, 0x04, 0x19, 0xc8, 0x20, 0x04, 0x19,
547 0xca, 0x20, 0x04, 0x19, 0xc2, 0x30, 0x04, 0x19,
548 0xcd, 0x10, 0x04, 0x19, 0xcf, 0x10, 0x04, 0x19,
549 0xb0, 0x00, 0x71, 0x8b, 0x8c, 0x00, 0x04, 0x19,
550 0x8e, 0x00, 0x04, 0x19, 0x10, 0x00, 0x71, 0x8b,
551 0xc4, 0x20, 0x04, 0x19, 0x93, 0x00, 0x01, 0x4f,
552 0xcd, 0x30, 0x00, 0x09, 0xcf, 0x30, 0x00, 0x09,
553 0x03, 0x03, 0x04, 0x49, 0x04, 0x81, 0x00, 0x54,
554 0x08, 0x50, 0x04, 0x64, 0x08, 0x50, 0x00, 0x44,
555 0x00, 0x00, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
556 0x03, 0x00, 0x04, 0x49, 0x08, 0x50, 0x00, 0x44,
557 0x20, 0x01, 0x63, 0x80, 0x00, 0x00, 0x06, 0x19,
558 0x00, 0x02, 0xe2, 0x8b, 0x08, 0x41, 0x00, 0x84,
559 0x65, 0x00, 0x51, 0x8b, 0xc2, 0x20, 0x00, 0x39,
560 0x00, 0x00, 0x63, 0x80, 0xc1, 0xa0, 0x04, 0x19,
561 0x08, 0x61, 0x00, 0x44, 0x2d, 0x00, 0x51, 0x8b,
562 0xc2, 0x20, 0x00, 0x39, 0x00, 0x00, 0xb1, 0x80,
563 0xc1, 0xa0, 0x04, 0x19, 0x03, 0x00, 0x04, 0x49,
564 0x08, 0x50, 0x00, 0x44, 0x02, 0x20, 0x61, 0x0a,
565 0x00, 0x01, 0x00, 0x45, 0x02, 0x30, 0x61, 0x0a,
566 0x04, 0x03, 0x00, 0xc4, 0x05, 0xb0, 0xc8, 0x18,
567 0x04, 0x71, 0x00, 0xc4, 0x00, 0x13, 0x00, 0x44,
568 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
569 0x00, 0x49, 0x00, 0xc4, 0xca, 0x20, 0x04, 0x19,
570 0x4a, 0x04, 0x04, 0x19, 0xff, 0x00, 0xe2, 0x8b,
571 0x0c, 0xf9, 0x08, 0x44, 0xcf, 0x10, 0x04, 0x19,
572 0x0c, 0x2b, 0x08, 0x44, 0x8e, 0x00, 0x04, 0x19,
573 0x03, 0x30, 0x61, 0x0a, 0xc8, 0x20, 0x00, 0x39,
574 0x48, 0x04, 0x00, 0x39, 0x0a, 0x30, 0x61, 0x0a,
575 0x0c, 0xf9, 0x08, 0x44, 0xcd, 0x10, 0x04, 0x19,
576 0x0c, 0x2b, 0x08, 0x44, 0x8c, 0x00, 0x04, 0x19,
577 0x0c, 0xd9, 0x08, 0x44, 0x0c, 0x5a, 0x00, 0x44,
578 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
579 0x00, 0x49, 0x00, 0xc4, 0xc3, 0x30, 0x04, 0x19,
580 0xca, 0x30, 0x00, 0x99, 0x0c, 0xd9, 0x08, 0x44,
581 0x42, 0x0a, 0x09, 0x0e, 0x00, 0x01, 0x33, 0x11,
582 0x8c, 0x01, 0xa3, 0x80, 0x00, 0x01, 0x7a, 0x10,
583 0x80, 0x05, 0xb1, 0x80, 0x05, 0xb0, 0xe0, 0x18,
584 0x00, 0x93, 0x00, 0x84, 0x00, 0x79, 0x08, 0x44,
585 0x00, 0x04, 0x79, 0x80, 0x00, 0x49, 0x00, 0xc4,
586 0x0c, 0x1b, 0x08, 0x44, 0x88, 0x00, 0x04, 0x19,
587 0x8a, 0x00, 0x00, 0x99, 0x0c, 0xd9, 0x08, 0x44,
588 0x42, 0x0a, 0x09, 0x0e, 0x80, 0x00, 0x71, 0x8b,
589 0xc0, 0x04, 0xb1, 0x82, 0x10, 0x00, 0xe0, 0x0b,
590 0x00, 0x43, 0x00, 0x84, 0x02, 0x30, 0x61, 0x0a,
591 0x01, 0x30, 0xc8, 0x0a, 0x00, 0x43, 0x00, 0x84,
592 0x00, 0x00, 0xb1, 0x80, 0xc2, 0x30, 0x04, 0x19,
593 0x0c, 0xa8, 0x00, 0x44, 0x02, 0x30, 0x61, 0x0a,
594 0x00, 0xd3, 0x00, 0xc4, 0x05, 0xb0, 0xc8, 0x18,
595 0x04, 0x63, 0x00, 0xc4, 0x08, 0xf3, 0x00, 0x44,
596 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
597 0x00, 0x49, 0x00, 0xc4, 0x20, 0x00, 0x04, 0x19,
598 0xff, 0x00, 0xe2, 0x8b, 0x0c, 0xf9, 0x08, 0x44,
599 0xcd, 0x10, 0x04, 0x19, 0xcf, 0x10, 0x04, 0x19,
600 0x0c, 0x2b, 0x08, 0x44, 0x8c, 0x00, 0x04, 0x19,
601 0x8e, 0x00, 0x04, 0x19, 0x03, 0x30, 0x61, 0x0a,
602 0xc8, 0x20, 0x00, 0x39, 0xca, 0x20, 0x00, 0x39,
603 0x48, 0x04, 0x00, 0x39, 0x4a, 0x04, 0x00, 0x39,
604 0x0c, 0xd9, 0x08, 0x44, 0x0c, 0x5a, 0x00, 0x44,
605 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
606 0x00, 0x49, 0x00, 0xc4, 0xc3, 0x30, 0x04, 0x19,
607 0x0c, 0xd9, 0x08, 0x44, 0x42, 0x0a, 0x09, 0x0e,
608 0x05, 0xb0, 0xe0, 0x18, 0x00, 0x18, 0x00, 0x84,
609 0x00, 0x79, 0x08, 0x44, 0x00, 0x04, 0x79, 0x80,
610 0x00, 0x49, 0x00, 0xc4, 0x0c, 0x1b, 0x08, 0x44,
611 0x80, 0x01, 0x00, 0x80, 0x0c, 0xd9, 0x08, 0x44,
612 0x42, 0x0a, 0x09, 0x0e, 0x80, 0x00, 0x71, 0x8b,
613 0xc0, 0x04, 0xb1, 0x82, 0x10, 0x00, 0xe0, 0x0b,
614 0x00, 0x88, 0x00, 0x84, 0x02, 0x30, 0x61, 0x0a,
615 0x01, 0x30, 0xc8, 0x0a, 0x00, 0x88, 0x00, 0x84,
616 0x00, 0x00, 0xb1, 0x80, 0xc2, 0x30, 0x04, 0x19,
617 0x00, 0x01, 0x00, 0x11, 0x00, 0x0f, 0xe2, 0x8b,
618 0x00, 0x00, 0x41, 0xcb, 0x8c, 0x00, 0x00, 0x80,
619 0x00, 0x00, 0x48, 0xcb, 0x20, 0x00, 0x7a, 0x80,
620 0x80, 0x01, 0x00, 0x80, 0x82, 0x0c, 0x09, 0x6e,
621 0x03, 0x08, 0x09, 0x0e, 0x80, 0x40, 0x09, 0xcf,
622 0x00, 0x01, 0x71, 0xc2, 0x00, 0x08, 0xc2, 0x1b,
623 0x04, 0xb8, 0x00, 0xc4, 0x20, 0x05, 0xa8, 0x80,
624 0x20, 0x01, 0xf0, 0x80, 0x00, 0x01, 0xc2, 0x1b,
625 0x04, 0x48, 0x00, 0xc4, 0x20, 0x05, 0xa8, 0x80,
626 0x20, 0x01, 0xf0, 0x80, 0x00, 0x02, 0xc2, 0x1b,
627 0x04, 0x68, 0x00, 0xc4, 0x20, 0x05, 0xa8, 0x80,
628 0x20, 0x01, 0xf0, 0x80, 0x20, 0x03, 0xa8, 0x80,
629 0x00, 0x01, 0x00, 0x11, 0x00, 0x04, 0xc2, 0x8b,
630 0x08, 0x78, 0x00, 0xc4, 0x00, 0x00, 0xe9, 0x80,
631 0x05, 0xb0, 0xa8, 0x18, 0x00, 0x00, 0x4a, 0xcb,
632 0x20, 0x00, 0xa8, 0x22, 0xd0, 0x01, 0x00, 0x82,
633 0x40, 0x01, 0x00, 0x80, 0xc4, 0x00, 0x04, 0x19,
634 0xb0, 0x00, 0xe2, 0x8b, 0x06, 0x20, 0xa8, 0x0a,
635 0x2d, 0x10, 0x61, 0x0a, 0xd1, 0x08, 0x09, 0x2e,
636 0x00, 0x01, 0xa8, 0x02, 0x0c, 0xf9, 0x08, 0x44,
637 0xcd, 0x10, 0x04, 0x19, 0x0c, 0x2b, 0x08, 0x44,
638 0x03, 0x08, 0x09, 0x0e, 0x9a, 0x25, 0xb1, 0x60,
639 0xa2, 0x0e, 0x09, 0x6e, 0x03, 0x00, 0x09, 0x0f,
640 0x00, 0x01, 0x71, 0x82, 0x20, 0x01, 0x00, 0x80,
641 0x00, 0x00, 0x61, 0xcb, 0x80, 0x01, 0x00, 0x80,
642 0x03, 0x00, 0x09, 0x0f, 0x00, 0x01, 0x71, 0xc2,
643 0x00, 0x08, 0xc2, 0x1b, 0x0c, 0x2a, 0x00, 0xc4,
644 0x20, 0x05, 0xa8, 0x80, 0x20, 0x01, 0xf0, 0x80,
645 0x00, 0x01, 0xc2, 0x1b, 0x0c, 0x1a, 0x00, 0xc4,
646 0x20, 0x05, 0xa8, 0x80, 0x20, 0x01, 0xf0, 0x80,
647 0x00, 0x02, 0xc2, 0x1b, 0x0c, 0x3a, 0x00, 0xc4,
648 0x20, 0x05, 0xa8, 0x80, 0x20, 0x01, 0xf0, 0x80,
649 0x20, 0x03, 0xa8, 0x80, 0x00, 0x01, 0x00, 0x11,
650 0x00, 0x04, 0xc2, 0x8b, 0x04, 0xaa, 0x00, 0xc4,
651 0x00, 0x00, 0xe9, 0x80, 0x05, 0xb0, 0xa8, 0x18,
652 0x00, 0x00, 0x4a, 0xcb, 0x20, 0x00, 0xa8, 0x22,
653 0xd0, 0x01, 0x00, 0x82, 0x40, 0x01, 0x00, 0x80,
654 0xc7, 0x00, 0x04, 0x19, 0xb0, 0x00, 0xe2, 0x8b,
655 0x06, 0x20, 0xa8, 0x0a, 0x2f, 0x10, 0x61, 0x0a,
656 0xf1, 0x08, 0x09, 0x2e, 0x00, 0x01, 0xa8, 0x02,
657 0x0c, 0xf9, 0x08, 0x44, 0xcf, 0x10, 0x04, 0x19,
658 0x0c, 0x2b, 0x08, 0x44, 0x9f, 0x35, 0xb1, 0x60,
659 0x03, 0x08, 0x09, 0x0e, 0x00, 0x01, 0x71, 0x82,
660 0x20, 0x01, 0x00, 0x80, 0x00, 0x00, 0x61, 0xcb,
661 0x80, 0x01, 0x00, 0x80, 0xe4, 0x20, 0x71, 0x8b,
662 0x00, 0x01, 0x00, 0x45, 0x90, 0x40, 0x09, 0x8f,
663 0x00, 0x05, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
664 0x08, 0x19, 0x04, 0xd4, 0x93, 0x00, 0x01, 0x4f,
665 0xe7, 0x00, 0x01, 0x6f, 0x0d, 0x30, 0x61, 0x0a,
666 0x20, 0x04, 0x61, 0xa8, 0xc2, 0x00, 0x00, 0x82,
667 0x02, 0x04, 0x61, 0xa8, 0xc2, 0x00, 0x00, 0x82,
668 0xcd, 0x30, 0x00, 0x09, 0x02, 0x00, 0x00, 0x02,
669 0x02, 0x00, 0x00, 0x02, 0xc0, 0x80, 0x00, 0x09,
670 0x20, 0x00, 0x09, 0x49, 0x0f, 0x30, 0x61, 0x0a,
671 0x0d, 0x30, 0xc8, 0x0a, 0x00, 0x29, 0x00, 0xc4,
672 0x00, 0x80, 0xc8, 0x0a, 0x00, 0x29, 0x00, 0xc4,
673 0x00, 0x04, 0xb1, 0x80, 0x00, 0x00, 0x06, 0x39,
674 0xc9, 0x20, 0x04, 0x39, 0x00, 0x39, 0x00, 0x44,
675 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
676 0x00, 0x04, 0xb1, 0x80, 0xc9, 0x20, 0x04, 0x39,
677 0x00, 0x39, 0x00, 0x44, 0x09, 0x20, 0x23, 0x0a,
678 0x00, 0x00, 0x06, 0x19, 0xc9, 0x20, 0x04, 0x19,
679 0x00, 0x00, 0x40, 0x45, 0x02, 0x00, 0x61, 0x0a,
680 0x0c, 0xb9, 0x04, 0x14, 0x04, 0x00, 0x61, 0x0a,
681 0x06, 0x00, 0x48, 0x0a, 0x00, 0xa9, 0x04, 0x54,
682 0xc6, 0x00, 0x04, 0x19, 0x0c, 0xa9, 0x00, 0x44,
683 0x05, 0x00, 0xc8, 0x0a, 0x0c, 0xa9, 0x04, 0x54,
684 0xc5, 0x00, 0x04, 0x19, 0x07, 0x00, 0x61, 0x0a,
685 0x0c, 0x00, 0x48, 0x0a, 0x00, 0xb9, 0x04, 0x54,
686 0xcc, 0x00, 0x04, 0x19, 0x0c, 0xb9, 0x00, 0x44,
687 0x0e, 0x00, 0xc8, 0x0a, 0x0c, 0xb9, 0x04, 0x54,
688 0xce, 0x00, 0x04, 0x19, 0x0c, 0x5a, 0x00, 0x44,
689 0x82, 0x0d, 0x09, 0x2e, 0x80, 0x40, 0x09, 0xcf,
690 0x00, 0xdf, 0x71, 0x8b, 0x80, 0x01, 0x00, 0x80,
691 0x02, 0xc1, 0x00, 0x22, 0x03, 0xc1, 0x00, 0x22,
692 0x00, 0x01, 0x65, 0x80, 0xd2, 0x05, 0x65, 0x82,
693 0x40, 0x21, 0x00, 0x80, 0xd3, 0x03, 0x00, 0x82,
694 0x40, 0x33, 0x00, 0x80, 0x0c, 0x5a, 0x00, 0x44,
695 0x0f, 0x30, 0x61, 0x0a, 0x0d, 0x30, 0xc8, 0x0a,
696 0x08, 0xd9, 0x00, 0xc4, 0x93, 0x00, 0x01, 0x4f,
697 0xe7, 0x00, 0x01, 0x6f, 0x0f, 0x30, 0x61, 0x0a,
698 0x20, 0x00, 0x00, 0x88, 0x02, 0x00, 0x61, 0x02,
699 0x02, 0x00, 0x00, 0x03, 0xcf, 0x30, 0x00, 0x09,
700 0x20, 0x00, 0x09, 0x49, 0x00, 0x04, 0x63, 0x80,
701 0x04, 0xd9, 0x00, 0x44, 0x00, 0x04, 0xb1, 0x80,
702 0x00, 0x00, 0x00, 0x46, 0x02, 0x30, 0x61, 0x0a,
703 0x05, 0xb0, 0xa8, 0x18, 0xc2, 0x30, 0x04, 0x19,
704 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0xc8, 0x0a,
705 0x0c, 0x0b, 0x04, 0x14, 0x0e, 0x10, 0x61, 0x0a,
706 0x04, 0x2b, 0x00, 0x44, 0x0c, 0x10, 0xc8, 0x0a,
707 0x04, 0x2b, 0x04, 0x54, 0x0c, 0x10, 0x61, 0x0a,
708 0x00, 0x00, 0x00, 0x46, 0x00, 0x10, 0xa8, 0x18,
709 0xa0, 0x00, 0x00, 0x88, 0x00, 0x01, 0x71, 0x82,
710 0x00, 0x00, 0x00, 0x46, 0x00, 0x04, 0x33, 0x80,
711 0x00, 0x00, 0x83, 0x80, 0x20, 0x04, 0x7a, 0x80,
712 0x20, 0x01, 0x33, 0x80, 0x00, 0x00, 0x83, 0x80,
713 0x20, 0x00, 0x7a, 0x80, 0x20, 0x03, 0x00, 0x80,
714 0x00, 0x00, 0x00, 0x46, 0x16, 0xce, 0x11, 0x00
715};
716
717static unsigned char ima_adpcm_capture[] = {
718 0x00, 0x10, 0x00, 0x44, 0x08, 0x00, 0x00, 0x44,
719 0x00, 0x70, 0x00, 0x44, 0x08, 0xd0, 0x00, 0x44,
720 0x00, 0xf0, 0x00, 0x44, 0x0d, 0xf2, 0x61, 0xa8,
721 0x44, 0x04, 0x04, 0x19, 0x00, 0x00, 0x40, 0x45,
722 0x00, 0x04, 0x63, 0x80, 0x00, 0x00, 0x06, 0x39,
723 0xff, 0x2e, 0x21, 0x49, 0xff, 0x0c, 0xd4, 0x49,
724 0x40, 0x49, 0x39, 0xac, 0x55, 0x55, 0x71, 0x8b,
725 0x50, 0x01, 0xb1, 0x80, 0x00, 0x00, 0x71, 0x8b,
726 0xc2, 0x30, 0x04, 0x19, 0xc0, 0xa0, 0x04, 0x19,
727 0xc2, 0xa0, 0x04, 0x19, 0x89, 0x00, 0x71, 0x8b,
728 0xc8, 0x30, 0x04, 0x19, 0x71, 0x00, 0x71, 0x8b,
729 0xcd, 0x00, 0x04, 0x19, 0xcf, 0x00, 0x04, 0x19,
730 0x80, 0x00, 0x71, 0x8b, 0xcb, 0x20, 0x04, 0x19,
731 0x20, 0x00, 0x71, 0x8b, 0xc4, 0x20, 0x04, 0x19,
732 0x47, 0x00, 0x51, 0x8b, 0xc0, 0x20, 0x00, 0x39,
733 0x00, 0x00, 0x63, 0x80, 0xc1, 0xa0, 0x04, 0x19,
734 0x93, 0x00, 0x01, 0x4f, 0xcd, 0x30, 0x00, 0x09,
735 0xcf, 0x30, 0x00, 0x09, 0x0c, 0x40, 0x00, 0x14,
736 0x00, 0x60, 0x00, 0x14, 0x00, 0x04, 0x61, 0xa8,
737 0x02, 0x04, 0x61, 0xa8, 0x0c, 0x60, 0x04, 0x24,
738 0x00, 0x00, 0x34, 0x49, 0x08, 0x50, 0x00, 0x44,
739 0x44, 0x04, 0x04, 0x39, 0x00, 0x00, 0x40, 0x45,
740 0x08, 0x30, 0x61, 0x0a, 0x05, 0xb0, 0xe8, 0x18,
741 0x0c, 0xc0, 0x04, 0x54, 0xc8, 0x30, 0x04, 0x19,
742 0x09, 0x04, 0x00, 0xa8, 0x0b, 0x04, 0x00, 0xa8,
743 0x00, 0x00, 0x40, 0x45, 0x09, 0x04, 0x61, 0xa8,
744 0xc1, 0x00, 0x04, 0x19, 0x0b, 0x04, 0x61, 0xa8,
745 0xca, 0x00, 0x04, 0x19, 0x0d, 0x00, 0x61, 0x0a,
746 0x00, 0x01, 0x00, 0x45, 0x0f, 0x00, 0x61, 0x0a,
747 0x00, 0x40, 0x09, 0x8f, 0x00, 0x01, 0x00, 0x45,
748 0x40, 0x40, 0x09, 0xef, 0xff, 0x20, 0x09, 0xcf,
749 0x00, 0x04, 0x63, 0xa1, 0x50, 0x03, 0x33, 0x80,
750 0x00, 0x04, 0xa3, 0x80, 0x00, 0xff, 0xc2, 0x8b,
751 0x0c, 0x12, 0x04, 0x54, 0x08, 0x12, 0x00, 0xc4,
752 0x20, 0x03, 0x80, 0xc0, 0x30, 0x00, 0x00, 0x88,
753 0x00, 0x00, 0x7a, 0x0a, 0xd0, 0x01, 0x00, 0x82,
754 0x04, 0x50, 0x00, 0x44, 0xc0, 0x00, 0x00, 0x99,
755 0x04, 0x50, 0x00, 0x44, 0x00, 0xff, 0xc2, 0x8b,
756 0x20, 0x00, 0x00, 0x80, 0x00, 0x0d, 0x42, 0x8b,
757 0x04, 0x42, 0x00, 0xc4, 0x00, 0x0e, 0x42, 0x8b,
758 0x08, 0x52, 0x00, 0xc4, 0x00, 0x1e, 0x42, 0x8b,
759 0x00, 0xe2, 0x00, 0xc4, 0x00, 0x8e, 0x42, 0x8b,
760 0x08, 0xd2, 0x00, 0xc4, 0x00, 0x9e, 0x42, 0x8b,
761 0x04, 0xf2, 0x00, 0xc4, 0x00, 0xbe, 0x42, 0x8b,
762 0x04, 0xf2, 0x00, 0xc4, 0x00, 0x04, 0x42, 0x8b,
763 0x04, 0x11, 0x00, 0xc4, 0x00, 0x24, 0x42, 0x8b,
764 0x0c, 0x61, 0x00, 0xc4, 0x00, 0x55, 0x42, 0x8b,
765 0x04, 0x50, 0x00, 0xc4, 0x00, 0x3f, 0x42, 0x8b,
766 0x0c, 0x01, 0x00, 0xc4, 0x00, 0x00, 0x40, 0x45,
767 0x20, 0x01, 0x79, 0x80, 0x00, 0x30, 0x42, 0x8b,
768 0x04, 0x62, 0x00, 0xc4, 0x00, 0x00, 0x40, 0x45,
769 0x00, 0x00, 0x71, 0x8b, 0x40, 0x01, 0x00, 0x80,
770 0x04, 0x50, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
771 0x08, 0xc2, 0x00, 0xc4, 0x0f, 0xf2, 0xa8, 0xa8,
772 0x20, 0x00, 0xb1, 0x88, 0x00, 0x00, 0x41, 0x02,
773 0x4d, 0xf2, 0x00, 0x39, 0xc0, 0x01, 0x00, 0x82,
774 0x04, 0x50, 0x00, 0x44, 0x0d, 0xf2, 0xa3, 0xa8,
775 0x4d, 0xf2, 0x00, 0x39, 0x04, 0x50, 0x00, 0x44,
776 0xff, 0x00, 0xe2, 0xab, 0x20, 0x00, 0x00, 0x88,
777 0x00, 0x00, 0x61, 0x02, 0x4d, 0xf2, 0x04, 0x19,
778 0x04, 0x50, 0x00, 0x44, 0xff, 0x00, 0xe2, 0xab,
779 0xa0, 0x00, 0x00, 0x88, 0x00, 0x00, 0x61, 0x10,
780 0x4d, 0xf2, 0x04, 0x19, 0x04, 0x50, 0x00, 0x44,
781 0xff, 0x20, 0xe2, 0xab, 0x60, 0x00, 0x00, 0x88,
782 0x00, 0x00, 0x71, 0xc0, 0x4d, 0xf2, 0x04, 0x19,
783 0x04, 0x50, 0x00, 0x44, 0x00, 0x00, 0x7a, 0x0a,
784 0x20, 0x01, 0xf0, 0x80, 0x01, 0xa0, 0x41, 0x0a,
785 0x00, 0x11, 0x00, 0xc4, 0x20, 0x01, 0xf0, 0x80,
786 0xc1, 0x30, 0x04, 0x19, 0x04, 0x50, 0x00, 0x44,
787 0x00, 0x00, 0x79, 0x80, 0x0c, 0x41, 0x00, 0x84,
788 0x89, 0x00, 0x71, 0x8b, 0xc8, 0x30, 0x04, 0x19,
789 0x97, 0x00, 0x71, 0x8b, 0xcd, 0x00, 0x00, 0x39,
790 0x00, 0x01, 0xb1, 0x80, 0x80, 0x00, 0x04, 0x19,
791 0x82, 0x00, 0x04, 0x19, 0xc1, 0x20, 0x04, 0x19,
792 0xc3, 0x20, 0x04, 0x19, 0xc2, 0x30, 0x04, 0x19,
793 0xcd, 0x10, 0x04, 0x19, 0xcf, 0x10, 0x04, 0x19,
794 0xb0, 0x00, 0x71, 0x8b, 0x84, 0x00, 0x04, 0x19,
795 0x86, 0x00, 0x04, 0x19, 0x80, 0x00, 0x71, 0x8b,
796 0xcb, 0x20, 0x04, 0x19, 0x93, 0x00, 0x01, 0x4f,
797 0xcd, 0x30, 0x00, 0x09, 0xcf, 0x30, 0x00, 0x09,
798 0x03, 0x02, 0x04, 0x49, 0x08, 0x41, 0x00, 0x14,
799 0x04, 0x50, 0x00, 0x44, 0x00, 0x00, 0x63, 0x80,
800 0x00, 0x00, 0x06, 0x19, 0x03, 0x00, 0x04, 0x49,
801 0x04, 0x50, 0x00, 0x44, 0x20, 0x01, 0x63, 0x80,
802 0x00, 0x00, 0x06, 0x19, 0x00, 0x20, 0xe2, 0x8b,
803 0x00, 0xc1, 0x00, 0x84, 0x47, 0x00, 0x51, 0x8b,
804 0xc0, 0x20, 0x00, 0x39, 0x00, 0x00, 0x63, 0x80,
805 0xc1, 0xa0, 0x04, 0x19, 0x00, 0xe1, 0x00, 0x44,
806 0xbd, 0x00, 0x51, 0x8b, 0xc0, 0x20, 0x00, 0x39,
807 0x00, 0x00, 0xb1, 0x80, 0xc1, 0xa0, 0x04, 0x19,
808 0x03, 0x00, 0x04, 0x49, 0x04, 0x50, 0x00, 0x44,
809 0x00, 0x20, 0x61, 0x0a, 0x00, 0x01, 0x00, 0x45,
810 0x02, 0x30, 0x61, 0x0a, 0x0c, 0x83, 0x00, 0xc4,
811 0x0c, 0x78, 0x08, 0x44, 0x04, 0x5a, 0x08, 0x44,
812 0xb2, 0x00, 0x09, 0x4f, 0x10, 0x42, 0x09, 0x8e,
813 0x05, 0xb0, 0xe0, 0x18, 0x04, 0x23, 0x00, 0x84,
814 0x0c, 0x01, 0x00, 0x11, 0x08, 0x05, 0x61, 0x10,
815 0x00, 0x49, 0x08, 0x44, 0x00, 0x48, 0x08, 0x44,
816 0xb2, 0x00, 0x09, 0x4f, 0x80, 0x00, 0x71, 0x8b,
817 0xc0, 0x00, 0x00, 0x82, 0x0c, 0x01, 0x33, 0x10,
818 0x28, 0x01, 0xa3, 0x10, 0x00, 0x01, 0x7a, 0x80,
819 0x8c, 0x01, 0x00, 0x80, 0x02, 0x30, 0x61, 0x0a,
820 0x20, 0x00, 0x04, 0x19, 0x0c, 0x83, 0x00, 0xc4,
821 0x05, 0xb0, 0xc8, 0x18, 0x08, 0x43, 0x00, 0xc4,
822 0x01, 0x30, 0xc8, 0x0a, 0x0c, 0x38, 0x00, 0xc4,
823 0x08, 0x88, 0x00, 0x44, 0x0c, 0x78, 0x08, 0x44,
824 0x04, 0x5a, 0x08, 0x44, 0x00, 0x00, 0xa3, 0x18,
825 0x80, 0x00, 0x04, 0x19, 0x0b, 0x04, 0x61, 0xa8,
826 0xc3, 0x20, 0x00, 0x39, 0xc3, 0x30, 0x04, 0x19,
827 0x0f, 0x10, 0x61, 0x0a, 0xca, 0x30, 0x04, 0x19,
828 0x09, 0x04, 0x41, 0xa8, 0xe1, 0x20, 0x00, 0x39,
829 0xd1, 0x00, 0x09, 0x4f, 0x00, 0x04, 0x61, 0x02,
830 0x08, 0x63, 0x00, 0x44, 0x03, 0x30, 0x41, 0x0a,
831 0x20, 0x00, 0x00, 0x39, 0xa3, 0x00, 0x09, 0x4f,
832 0x00, 0x04, 0x61, 0x02, 0x00, 0x48, 0x08, 0x44,
833 0x08, 0x88, 0x00, 0x44, 0x02, 0x30, 0x61, 0x0a,
834 0x00, 0x08, 0x00, 0xc4, 0x0c, 0x78, 0x08, 0x44,
835 0x04, 0x5a, 0x08, 0x44, 0xb2, 0x00, 0x09, 0x0f,
836 0x10, 0x40, 0x09, 0x8e, 0x00, 0x00, 0x68, 0x5b,
837 0x20, 0x04, 0xb1, 0x80, 0x02, 0x00, 0x61, 0x5b,
838 0x88, 0x03, 0x7a, 0x80, 0xac, 0x01, 0x00, 0x80,
839 0x05, 0xb0, 0xe0, 0x18, 0x00, 0xd3, 0x00, 0x84,
840 0x00, 0x49, 0x08, 0x44, 0x00, 0x48, 0x08, 0x44,
841 0xb2, 0x00, 0x09, 0x0f, 0x80, 0x00, 0x71, 0x8b,
842 0xc0, 0x00, 0x00, 0x82, 0x02, 0x30, 0x61, 0x0a,
843 0x00, 0x08, 0x00, 0xc4, 0x05, 0xb0, 0xc8, 0x18,
844 0x0c, 0x18, 0x00, 0xc4, 0x01, 0x30, 0xc8, 0x0a,
845 0x0c, 0x38, 0x00, 0xc4, 0x08, 0x88, 0x00, 0x44,
846 0x0c, 0x78, 0x08, 0x44, 0x00, 0x00, 0x61, 0x18,
847 0x20, 0x05, 0xb1, 0x80, 0x00, 0x00, 0x68, 0xcb,
848 0x80, 0x00, 0x04, 0x19, 0x0d, 0x10, 0x61, 0x0a,
849 0xc3, 0x30, 0x04, 0x19, 0x0b, 0x04, 0x41, 0xa8,
850 0x09, 0x04, 0x41, 0xa8, 0xe1, 0x20, 0x00, 0x39,
851 0x08, 0x38, 0x00, 0x44, 0x03, 0x30, 0x41, 0x0a,
852 0x20, 0x04, 0xb1, 0x80, 0x00, 0x48, 0x08, 0x44,
853 0x08, 0x88, 0x00, 0x44, 0x00, 0x00, 0xb1, 0x80,
854 0xc2, 0x30, 0x04, 0x19, 0x0c, 0xb8, 0x00, 0xd4,
855 0x0f, 0x30, 0x61, 0x0a, 0x0d, 0x30, 0xc8, 0x0a,
856 0x0c, 0xb8, 0x00, 0xc4, 0x93, 0x00, 0x01, 0x4f,
857 0xe7, 0x00, 0x01, 0x6f, 0x0f, 0x30, 0x61, 0x0a,
858 0x20, 0x00, 0x00, 0x88, 0x02, 0x00, 0x61, 0x02,
859 0x41, 0x04, 0x04, 0x19, 0x02, 0x04, 0x61, 0x02,
860 0x43, 0x04, 0x04, 0x39, 0xcf, 0x30, 0x00, 0x09,
861 0x20, 0x00, 0x09, 0x49, 0x00, 0x59, 0x00, 0x44,
862 0x93, 0x00, 0x01, 0x4f, 0xe7, 0x00, 0x01, 0x6f,
863 0x0d, 0x30, 0x61, 0x0a, 0x20, 0x00, 0x61, 0x88,
864 0xc2, 0x00, 0x00, 0x82, 0xc2, 0x03, 0x00, 0x82,
865 0xcd, 0x30, 0x00, 0x09, 0x20, 0x00, 0x09, 0x49,
866 0x0f, 0x30, 0x61, 0x0a, 0x0d, 0x30, 0xc8, 0x0a,
867 0x0c, 0x58, 0x00, 0x84, 0x02, 0x30, 0x61, 0x0a,
868 0x05, 0xb0, 0xa8, 0x18, 0xc2, 0x30, 0x04, 0x19,
869 0x00, 0x00, 0x00, 0x46, 0x90, 0x40, 0x09, 0x8f,
870 0x12, 0x04, 0x09, 0x6e, 0x03, 0x00, 0x09, 0x0e,
871 0x00, 0x01, 0x71, 0x82, 0x20, 0x01, 0x00, 0x80,
872 0x00, 0x00, 0x61, 0xcb, 0x80, 0x04, 0xb1, 0x80,
873 0x00, 0x01, 0xe0, 0x60, 0x0c, 0xd8, 0x04, 0x14,
874 0x00, 0x01, 0xeb, 0x80, 0x40, 0x00, 0x52, 0x1b,
875 0x80, 0x00, 0x79, 0x80, 0xc0, 0x01, 0x71, 0xc2,
876 0x20, 0x00, 0xc0, 0x80, 0x08, 0x0a, 0x04, 0x54,
877 0xc0, 0x04, 0xa8, 0x82, 0x80, 0x00, 0x72, 0x1b,
878 0x80, 0x00, 0x00, 0x80, 0x00, 0x01, 0xf0, 0x80,
879 0x20, 0x00, 0xc0, 0x80, 0x0c, 0x2a, 0x04, 0x54,
880 0xc0, 0x04, 0xa8, 0x82, 0x10, 0x00, 0x72, 0x1b,
881 0x80, 0x00, 0x00, 0x80, 0x00, 0x01, 0xf0, 0x80,
882 0x20, 0x00, 0xc0, 0x80, 0x08, 0x3a, 0x04, 0x54,
883 0xc0, 0x04, 0xa8, 0x82, 0x20, 0x00, 0x72, 0x1b,
884 0x80, 0x00, 0x00, 0x80, 0xc0, 0x03, 0xf0, 0x82,
885 0x20, 0x00, 0xa0, 0x80, 0x00, 0x01, 0x00, 0x11,
886 0x40, 0x00, 0xc2, 0x8b, 0x00, 0xaa, 0x00, 0xc4,
887 0x00, 0x00, 0xe9, 0x80, 0x05, 0xb0, 0xa8, 0x18,
888 0x00, 0x01, 0xa8, 0x22, 0xd0, 0x01, 0x00, 0x82,
889 0xf0, 0x00, 0xe2, 0x1b, 0x06, 0x20, 0xa8, 0x0a,
890 0x2d, 0x10, 0x61, 0x0a, 0xd1, 0x00, 0x09, 0x2e,
891 0x00, 0x01, 0xa8, 0x02, 0x0e, 0x10, 0xc8, 0x0a,
892 0x0c, 0xba, 0x04, 0x14, 0x0e, 0x10, 0x61, 0x0a,
893 0x04, 0x4a, 0x00, 0x44, 0x0c, 0x10, 0xc8, 0x0a,
894 0x04, 0x4a, 0x04, 0x54, 0x0c, 0x10, 0x61, 0x0a,
895 0xd0, 0x01, 0x00, 0x82, 0x00, 0x10, 0xa8, 0x18,
896 0xa0, 0x00, 0x00, 0x88, 0x00, 0x01, 0x71, 0x82,
897 0x03, 0x00, 0x09, 0x0e, 0x9a, 0x01, 0x00, 0x60,
898 0x32, 0x00, 0x09, 0x2e, 0x00, 0x00, 0x00, 0x46,
899 0x00, 0x01, 0x71, 0x82, 0x20, 0x01, 0x00, 0x80,
900 0x00, 0x00, 0x61, 0xcb, 0x80, 0x24, 0xb1, 0xc0,
901 0x00, 0x31, 0xe0, 0x60, 0x0c, 0xca, 0x04, 0x14,
902 0x00, 0x01, 0xeb, 0x80, 0x40, 0x00, 0x52, 0x1b,
903 0x80, 0x00, 0x79, 0x80, 0xc0, 0x01, 0x71, 0xc2,
904 0x20, 0x00, 0xc0, 0x80, 0x08, 0xda, 0x04, 0x54,
905 0xc0, 0x04, 0xa8, 0x82, 0x80, 0x00, 0x72, 0x1b,
906 0x80, 0x00, 0x00, 0x80, 0x00, 0x01, 0xf0, 0x80,
907 0x20, 0x00, 0xc0, 0x80, 0x0c, 0xfa, 0x04, 0x54,
908 0xc0, 0x04, 0xa8, 0x82, 0x10, 0x00, 0x72, 0x1b,
909 0x80, 0x00, 0x00, 0x80, 0x00, 0x01, 0xf0, 0x80,
910 0x20, 0x00, 0xc0, 0x80, 0x08, 0x29, 0x04, 0x54,
911 0xc0, 0x04, 0xa8, 0x82, 0x20, 0x00, 0x72, 0x1b,
912 0x80, 0x00, 0x00, 0x80, 0xc0, 0x03, 0xf0, 0x82,
913 0x20, 0x00, 0xa0, 0x80, 0x00, 0x01, 0x00, 0x11,
914 0x40, 0x00, 0xc2, 0x8b, 0x00, 0x39, 0x00, 0xc4,
915 0x00, 0x00, 0xe9, 0x80, 0x05, 0xb0, 0xa8, 0x18,
916 0x00, 0x01, 0xa8, 0x22, 0xd0, 0x01, 0x00, 0x82,
917 0xb0, 0x00, 0xe2, 0x1b, 0x06, 0x20, 0xa8, 0x0a,
918 0x2f, 0x10, 0x61, 0x0a, 0xf1, 0x00, 0x09, 0x2e,
919 0x00, 0x01, 0xa8, 0x02, 0x0e, 0x10, 0xc8, 0x0a,
920 0x0c, 0xa9, 0x04, 0x14, 0x0e, 0x10, 0x61, 0x0a,
921 0x04, 0x99, 0x00, 0x44, 0x0c, 0x10, 0xc8, 0x0a,
922 0x04, 0x99, 0x04, 0x54, 0x0c, 0x10, 0x61, 0x0a,
923 0xd0, 0x01, 0x00, 0x82, 0x00, 0x10, 0xa8, 0x18,
924 0xa0, 0x00, 0x00, 0x88, 0x00, 0x01, 0x71, 0x82,
925 0x9f, 0x01, 0x00, 0x60, 0x00, 0x00, 0x00, 0x46,
926 0x00, 0x00, 0x33, 0x80, 0x00, 0x00, 0x83, 0x80,
927 0x20, 0x00, 0x7a, 0x80, 0x20, 0x07, 0x33, 0x80,
928 0x00, 0x00, 0x83, 0x80, 0x20, 0x04, 0x7a, 0x80,
929 0x20, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x46,
930 0x02, 0x00, 0x61, 0x0a, 0x04, 0x1b, 0x04, 0x14,
931 0x01, 0x00, 0x61, 0x0a, 0x03, 0x00, 0x48, 0x0a,
932 0x0c, 0x79, 0x04, 0x54, 0xc3, 0x00, 0x04, 0x19,
933 0x04, 0xc9, 0x00, 0x44, 0x08, 0x00, 0xc8, 0x0a,
934 0x04, 0xc9, 0x04, 0x54, 0xc8, 0x00, 0x04, 0x19,
935 0x0a, 0x00, 0x61, 0x0a, 0x09, 0x00, 0x48, 0x0a,
936 0x0c, 0xe9, 0x04, 0x54, 0xc9, 0x00, 0x04, 0x19,
937 0x04, 0xd9, 0x00, 0x44, 0x0b, 0x00, 0xc8, 0x0a,
938 0x04, 0xd9, 0x04, 0x54, 0xcb, 0x00, 0x04, 0x19,
939 0x04, 0x00, 0x61, 0x0a, 0x06, 0x00, 0x48, 0x0a,
940 0x0c, 0xf9, 0x04, 0x54, 0xc6, 0x00, 0x04, 0x19,
941 0x04, 0x0b, 0x00, 0x44, 0x05, 0x00, 0xc8, 0x0a,
942 0x04, 0x0b, 0x04, 0x54, 0xc5, 0x00, 0x04, 0x19,
943 0x07, 0x00, 0x61, 0x0a, 0x0c, 0x00, 0x48, 0x0a,
944 0x0c, 0x2b, 0x04, 0x54, 0xcc, 0x00, 0x04, 0x19,
945 0x04, 0x1b, 0x00, 0x44, 0x0e, 0x00, 0xc8, 0x0a,
946 0x04, 0x1b, 0x04, 0x54, 0xce, 0x00, 0x04, 0x19,
947 0x00, 0x00, 0x40, 0x45, 0x92, 0x20, 0x71, 0x8b,
948 0xa6, 0xc5, 0x11, 0x00
949};
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
new file mode 100644
index 000000000000..a6a0fa516268
--- /dev/null
+++ b/sound/isa/sb/sb16_main.c
@@ -0,0 +1,916 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for control of 16-bit SoundBlaster cards and clones
4 * Note: This is very ugly hardware which uses one 8-bit DMA channel and
5 * second 16-bit DMA channel. Unfortunately 8-bit DMA channel can't
6 * transfer 16-bit samples and 16-bit DMA channels can't transfer
7 * 8-bit samples. This make full duplex more complicated than
8 * can be... People, don't buy these soundcards for full 16-bit
9 * duplex!!!
10 * Note: 16-bit wide is assigned to first direction which made request.
11 * With full duplex - playback is preferred with abstract layer.
12 *
13 * Note: Some chip revisions have hardware bug. Changing capture
14 * channel from full-duplex 8bit DMA to 16bit DMA will block
15 * 16bit DMA transfers from DSP chip (capture) until 8bit transfer
16 * to DSP chip (playback) starts. This bug can be avoided with
17 * "16bit DMA Allocation" setting set to Playback or Capture.
18 *
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 *
34 */
35
36#include <sound/driver.h>
37#include <asm/io.h>
38#include <asm/dma.h>
39#include <linux/init.h>
40#include <linux/time.h>
41#include <sound/core.h>
42#include <sound/sb.h>
43#include <sound/sb16_csp.h>
44#include <sound/mpu401.h>
45#include <sound/control.h>
46#include <sound/info.h>
47
48MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
49MODULE_DESCRIPTION("Routines for control of 16-bit SoundBlaster cards and clones");
50MODULE_LICENSE("GPL");
51
52#ifdef CONFIG_SND_SB16_CSP
53static void snd_sb16_csp_playback_prepare(sb_t *chip, snd_pcm_runtime_t *runtime)
54{
55 if (chip->hardware == SB_HW_16CSP) {
56 snd_sb_csp_t *csp = chip->csp;
57
58 if (csp->running & SNDRV_SB_CSP_ST_LOADED) {
59 /* manually loaded codec */
60 if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) &&
61 ((1U << runtime->format) == csp->acc_format)) {
62 /* Supported runtime PCM format for playback */
63 if (csp->ops.csp_use(csp) == 0) {
64 /* If CSP was successfully acquired */
65 goto __start_CSP;
66 }
67 } else if ((csp->mode & SNDRV_SB_CSP_MODE_QSOUND) && (csp->q_enabled)) {
68 /* QSound decoder is loaded and enabled */
69 if ((1 << runtime->format) & (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
70 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE)) {
71 /* Only for simple PCM formats */
72 if (csp->ops.csp_use(csp) == 0) {
73 /* If CSP was successfully acquired */
74 goto __start_CSP;
75 }
76 }
77 }
78 } else if (csp->ops.csp_use(csp) == 0) {
79 /* Acquire CSP and try to autoload hardware codec */
80 if (csp->ops.csp_autoload(csp, runtime->format, SNDRV_SB_CSP_MODE_DSP_WRITE)) {
81 /* Unsupported format, release CSP */
82 csp->ops.csp_unuse(csp);
83 } else {
84 __start_CSP:
85 /* Try to start CSP */
86 if (csp->ops.csp_start(csp, (chip->mode & SB_MODE_PLAYBACK_16) ?
87 SNDRV_SB_CSP_SAMPLE_16BIT : SNDRV_SB_CSP_SAMPLE_8BIT,
88 (runtime->channels > 1) ?
89 SNDRV_SB_CSP_STEREO : SNDRV_SB_CSP_MONO)) {
90 /* Failed, release CSP */
91 csp->ops.csp_unuse(csp);
92 } else {
93 /* Success, CSP acquired and running */
94 chip->open = SNDRV_SB_CSP_MODE_DSP_WRITE;
95 }
96 }
97 }
98 }
99}
100
101static void snd_sb16_csp_capture_prepare(sb_t *chip, snd_pcm_runtime_t *runtime)
102{
103 if (chip->hardware == SB_HW_16CSP) {
104 snd_sb_csp_t *csp = chip->csp;
105
106 if (csp->running & SNDRV_SB_CSP_ST_LOADED) {
107 /* manually loaded codec */
108 if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) &&
109 ((1U << runtime->format) == csp->acc_format)) {
110 /* Supported runtime PCM format for capture */
111 if (csp->ops.csp_use(csp) == 0) {
112 /* If CSP was successfully acquired */
113 goto __start_CSP;
114 }
115 }
116 } else if (csp->ops.csp_use(csp) == 0) {
117 /* Acquire CSP and try to autoload hardware codec */
118 if (csp->ops.csp_autoload(csp, runtime->format, SNDRV_SB_CSP_MODE_DSP_READ)) {
119 /* Unsupported format, release CSP */
120 csp->ops.csp_unuse(csp);
121 } else {
122 __start_CSP:
123 /* Try to start CSP */
124 if (csp->ops.csp_start(csp, (chip->mode & SB_MODE_CAPTURE_16) ?
125 SNDRV_SB_CSP_SAMPLE_16BIT : SNDRV_SB_CSP_SAMPLE_8BIT,
126 (runtime->channels > 1) ?
127 SNDRV_SB_CSP_STEREO : SNDRV_SB_CSP_MONO)) {
128 /* Failed, release CSP */
129 csp->ops.csp_unuse(csp);
130 } else {
131 /* Success, CSP acquired and running */
132 chip->open = SNDRV_SB_CSP_MODE_DSP_READ;
133 }
134 }
135 }
136 }
137}
138
139static void snd_sb16_csp_update(sb_t *chip)
140{
141 if (chip->hardware == SB_HW_16CSP) {
142 snd_sb_csp_t *csp = chip->csp;
143
144 if (csp->qpos_changed) {
145 spin_lock(&chip->reg_lock);
146 csp->ops.csp_qsound_transfer (csp);
147 spin_unlock(&chip->reg_lock);
148 }
149 }
150}
151
152static void snd_sb16_csp_playback_open(sb_t *chip, snd_pcm_runtime_t *runtime)
153{
154 /* CSP decoders (QSound excluded) support only 16bit transfers */
155 if (chip->hardware == SB_HW_16CSP) {
156 snd_sb_csp_t *csp = chip->csp;
157
158 if (csp->running & SNDRV_SB_CSP_ST_LOADED) {
159 /* manually loaded codec */
160 if (csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) {
161 runtime->hw.formats |= csp->acc_format;
162 }
163 } else {
164 /* autoloaded codecs */
165 runtime->hw.formats |= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
166 SNDRV_PCM_FMTBIT_IMA_ADPCM;
167 }
168 }
169}
170
171static void snd_sb16_csp_playback_close(sb_t *chip)
172{
173 if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_WRITE)) {
174 snd_sb_csp_t *csp = chip->csp;
175
176 if (csp->ops.csp_stop(csp) == 0) {
177 csp->ops.csp_unuse(csp);
178 chip->open = 0;
179 }
180 }
181}
182
183static void snd_sb16_csp_capture_open(sb_t *chip, snd_pcm_runtime_t *runtime)
184{
185 /* CSP coders support only 16bit transfers */
186 if (chip->hardware == SB_HW_16CSP) {
187 snd_sb_csp_t *csp = chip->csp;
188
189 if (csp->running & SNDRV_SB_CSP_ST_LOADED) {
190 /* manually loaded codec */
191 if (csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) {
192 runtime->hw.formats |= csp->acc_format;
193 }
194 } else {
195 /* autoloaded codecs */
196 runtime->hw.formats |= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
197 SNDRV_PCM_FMTBIT_IMA_ADPCM;
198 }
199 }
200}
201
202static void snd_sb16_csp_capture_close(sb_t *chip)
203{
204 if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_READ)) {
205 snd_sb_csp_t *csp = chip->csp;
206
207 if (csp->ops.csp_stop(csp) == 0) {
208 csp->ops.csp_unuse(csp);
209 chip->open = 0;
210 }
211 }
212}
213#else
214#define snd_sb16_csp_playback_prepare(chip, runtime) /*nop*/
215#define snd_sb16_csp_capture_prepare(chip, runtime) /*nop*/
216#define snd_sb16_csp_update(chip) /*nop*/
217#define snd_sb16_csp_playback_open(chip, runtime) /*nop*/
218#define snd_sb16_csp_playback_close(chip) /*nop*/
219#define snd_sb16_csp_capture_open(chip, runtime) /*nop*/
220#define snd_sb16_csp_capture_close(chip) /*nop*/
221#endif
222
223
224static void snd_sb16_setup_rate(sb_t *chip,
225 unsigned short rate,
226 int channel)
227{
228 unsigned long flags;
229
230 spin_lock_irqsave(&chip->reg_lock, flags);
231 if (chip->mode & (channel == SNDRV_PCM_STREAM_PLAYBACK ? SB_MODE_PLAYBACK_16 : SB_MODE_CAPTURE_16))
232 snd_sb_ack_16bit(chip);
233 else
234 snd_sb_ack_8bit(chip);
235 if (!(chip->mode & SB_RATE_LOCK)) {
236 chip->locked_rate = rate;
237 snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_IN);
238 snd_sbdsp_command(chip, rate >> 8);
239 snd_sbdsp_command(chip, rate & 0xff);
240 snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_OUT);
241 snd_sbdsp_command(chip, rate >> 8);
242 snd_sbdsp_command(chip, rate & 0xff);
243 }
244 spin_unlock_irqrestore(&chip->reg_lock, flags);
245}
246
247static int snd_sb16_hw_params(snd_pcm_substream_t * substream,
248 snd_pcm_hw_params_t * hw_params)
249{
250 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
251}
252
253static int snd_sb16_hw_free(snd_pcm_substream_t * substream)
254{
255 snd_pcm_lib_free_pages(substream);
256 return 0;
257}
258
259static int snd_sb16_playback_prepare(snd_pcm_substream_t * substream)
260{
261 unsigned long flags;
262 sb_t *chip = snd_pcm_substream_chip(substream);
263 snd_pcm_runtime_t *runtime = substream->runtime;
264 unsigned char format;
265 unsigned int size, count, dma;
266
267 snd_sb16_csp_playback_prepare(chip, runtime);
268 if (snd_pcm_format_unsigned(runtime->format) > 0) {
269 format = runtime->channels > 1 ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO;
270 } else {
271 format = runtime->channels > 1 ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO;
272 }
273
274 snd_sb16_setup_rate(chip, runtime->rate, SNDRV_PCM_STREAM_PLAYBACK);
275 size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
276 dma = (chip->mode & SB_MODE_PLAYBACK_8) ? chip->dma8 : chip->dma16;
277 snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT);
278
279 count = snd_pcm_lib_period_bytes(substream);
280 spin_lock_irqsave(&chip->reg_lock, flags);
281 if (chip->mode & SB_MODE_PLAYBACK_16) {
282 count >>= 1;
283 count--;
284 snd_sbdsp_command(chip, SB_DSP4_OUT16_AI);
285 snd_sbdsp_command(chip, format);
286 snd_sbdsp_command(chip, count & 0xff);
287 snd_sbdsp_command(chip, count >> 8);
288 snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);
289 } else {
290 count--;
291 snd_sbdsp_command(chip, SB_DSP4_OUT8_AI);
292 snd_sbdsp_command(chip, format);
293 snd_sbdsp_command(chip, count & 0xff);
294 snd_sbdsp_command(chip, count >> 8);
295 snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
296 }
297 spin_unlock_irqrestore(&chip->reg_lock, flags);
298 return 0;
299}
300
301static int snd_sb16_playback_trigger(snd_pcm_substream_t * substream,
302 int cmd)
303{
304 sb_t *chip = snd_pcm_substream_chip(substream);
305 int result = 0;
306
307 spin_lock(&chip->reg_lock);
308 switch (cmd) {
309 case SNDRV_PCM_TRIGGER_START:
310 chip->mode |= SB_RATE_LOCK_PLAYBACK;
311 snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);
312 break;
313 case SNDRV_PCM_TRIGGER_STOP:
314 snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF);
315 /* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */
316 if (chip->mode & SB_RATE_LOCK_CAPTURE)
317 snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);
318 chip->mode &= ~SB_RATE_LOCK_PLAYBACK;
319 break;
320 default:
321 result = -EINVAL;
322 }
323 spin_unlock(&chip->reg_lock);
324 return result;
325}
326
327static int snd_sb16_capture_prepare(snd_pcm_substream_t * substream)
328{
329 unsigned long flags;
330 sb_t *chip = snd_pcm_substream_chip(substream);
331 snd_pcm_runtime_t *runtime = substream->runtime;
332 unsigned char format;
333 unsigned int size, count, dma;
334
335 snd_sb16_csp_capture_prepare(chip, runtime);
336 if (snd_pcm_format_unsigned(runtime->format) > 0) {
337 format = runtime->channels > 1 ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO;
338 } else {
339 format = runtime->channels > 1 ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO;
340 }
341 snd_sb16_setup_rate(chip, runtime->rate, SNDRV_PCM_STREAM_CAPTURE);
342 size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
343 dma = (chip->mode & SB_MODE_CAPTURE_8) ? chip->dma8 : chip->dma16;
344 snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT);
345
346 count = snd_pcm_lib_period_bytes(substream);
347 spin_lock_irqsave(&chip->reg_lock, flags);
348 if (chip->mode & SB_MODE_CAPTURE_16) {
349 count >>= 1;
350 count--;
351 snd_sbdsp_command(chip, SB_DSP4_IN16_AI);
352 snd_sbdsp_command(chip, format);
353 snd_sbdsp_command(chip, count & 0xff);
354 snd_sbdsp_command(chip, count >> 8);
355 snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);
356 } else {
357 count--;
358 snd_sbdsp_command(chip, SB_DSP4_IN8_AI);
359 snd_sbdsp_command(chip, format);
360 snd_sbdsp_command(chip, count & 0xff);
361 snd_sbdsp_command(chip, count >> 8);
362 snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
363 }
364 spin_unlock_irqrestore(&chip->reg_lock, flags);
365 return 0;
366}
367
368static int snd_sb16_capture_trigger(snd_pcm_substream_t * substream,
369 int cmd)
370{
371 sb_t *chip = snd_pcm_substream_chip(substream);
372 int result = 0;
373
374 spin_lock(&chip->reg_lock);
375 switch (cmd) {
376 case SNDRV_PCM_TRIGGER_START:
377 chip->mode |= SB_RATE_LOCK_CAPTURE;
378 snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);
379 break;
380 case SNDRV_PCM_TRIGGER_STOP:
381 snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF);
382 /* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */
383 if (chip->mode & SB_RATE_LOCK_PLAYBACK)
384 snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);
385 chip->mode &= ~SB_RATE_LOCK_CAPTURE;
386 break;
387 default:
388 result = -EINVAL;
389 }
390 spin_unlock(&chip->reg_lock);
391 return result;
392}
393
394irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
395{
396 sb_t *chip = dev_id;
397 unsigned char status;
398 int ok;
399
400 spin_lock(&chip->mixer_lock);
401 status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
402 spin_unlock(&chip->mixer_lock);
403 if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback)
404 chip->rmidi_callback(irq, chip->rmidi->private_data, regs);
405 if (status & SB_IRQTYPE_8BIT) {
406 ok = 0;
407 if (chip->mode & SB_MODE_PLAYBACK_8) {
408 snd_pcm_period_elapsed(chip->playback_substream);
409 snd_sb16_csp_update(chip);
410 ok++;
411 }
412 if (chip->mode & SB_MODE_CAPTURE_8) {
413 snd_pcm_period_elapsed(chip->capture_substream);
414 ok++;
415 }
416 spin_lock(&chip->reg_lock);
417 if (!ok)
418 snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
419 snd_sb_ack_8bit(chip);
420 spin_unlock(&chip->reg_lock);
421 }
422 if (status & SB_IRQTYPE_16BIT) {
423 ok = 0;
424 if (chip->mode & SB_MODE_PLAYBACK_16) {
425 snd_pcm_period_elapsed(chip->playback_substream);
426 snd_sb16_csp_update(chip);
427 ok++;
428 }
429 if (chip->mode & SB_MODE_CAPTURE_16) {
430 snd_pcm_period_elapsed(chip->capture_substream);
431 ok++;
432 }
433 spin_lock(&chip->reg_lock);
434 if (!ok)
435 snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);
436 snd_sb_ack_16bit(chip);
437 spin_unlock(&chip->reg_lock);
438 }
439 return IRQ_HANDLED;
440}
441
442/*
443
444 */
445
446static snd_pcm_uframes_t snd_sb16_playback_pointer(snd_pcm_substream_t * substream)
447{
448 sb_t *chip = snd_pcm_substream_chip(substream);
449 unsigned int dma;
450 size_t ptr;
451
452 dma = (chip->mode & SB_MODE_PLAYBACK_8) ? chip->dma8 : chip->dma16;
453 ptr = snd_dma_pointer(dma, chip->p_dma_size);
454 return bytes_to_frames(substream->runtime, ptr);
455}
456
457static snd_pcm_uframes_t snd_sb16_capture_pointer(snd_pcm_substream_t * substream)
458{
459 sb_t *chip = snd_pcm_substream_chip(substream);
460 unsigned int dma;
461 size_t ptr;
462
463 dma = (chip->mode & SB_MODE_CAPTURE_8) ? chip->dma8 : chip->dma16;
464 ptr = snd_dma_pointer(dma, chip->c_dma_size);
465 return bytes_to_frames(substream->runtime, ptr);
466}
467
468/*
469
470 */
471
472static snd_pcm_hardware_t snd_sb16_playback =
473{
474 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
475 SNDRV_PCM_INFO_MMAP_VALID),
476 .formats = 0,
477 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100,
478 .rate_min = 4000,
479 .rate_max = 44100,
480 .channels_min = 1,
481 .channels_max = 2,
482 .buffer_bytes_max = (128*1024),
483 .period_bytes_min = 64,
484 .period_bytes_max = (128*1024),
485 .periods_min = 1,
486 .periods_max = 1024,
487 .fifo_size = 0,
488};
489
490static snd_pcm_hardware_t snd_sb16_capture =
491{
492 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
493 SNDRV_PCM_INFO_MMAP_VALID),
494 .formats = 0,
495 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100,
496 .rate_min = 4000,
497 .rate_max = 44100,
498 .channels_min = 1,
499 .channels_max = 2,
500 .buffer_bytes_max = (128*1024),
501 .period_bytes_min = 64,
502 .period_bytes_max = (128*1024),
503 .periods_min = 1,
504 .periods_max = 1024,
505 .fifo_size = 0,
506};
507
508/*
509 * open/close
510 */
511
512static int snd_sb16_playback_open(snd_pcm_substream_t * substream)
513{
514 unsigned long flags;
515 sb_t *chip = snd_pcm_substream_chip(substream);
516 snd_pcm_runtime_t *runtime = substream->runtime;
517
518 spin_lock_irqsave(&chip->open_lock, flags);
519 if (chip->mode & SB_MODE_PLAYBACK) {
520 spin_unlock_irqrestore(&chip->open_lock, flags);
521 return -EAGAIN;
522 }
523 runtime->hw = snd_sb16_playback;
524
525 /* skip if 16 bit DMA was reserved for capture */
526 if (chip->force_mode16 & SB_MODE_CAPTURE_16)
527 goto __skip_16bit;
528
529 if (chip->dma16 >= 0 && !(chip->mode & SB_MODE_CAPTURE_16)) {
530 chip->mode |= SB_MODE_PLAYBACK_16;
531 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE;
532 /* Vibra16X hack */
533 if (chip->dma16 <= 3) {
534 runtime->hw.buffer_bytes_max =
535 runtime->hw.period_bytes_max = 64 * 1024;
536 } else {
537 snd_sb16_csp_playback_open(chip, runtime);
538 }
539 goto __open_ok;
540 }
541
542 __skip_16bit:
543 if (chip->dma8 >= 0 && !(chip->mode & SB_MODE_CAPTURE_8)) {
544 chip->mode |= SB_MODE_PLAYBACK_8;
545 /* DSP v 4.xx can transfer 16bit data through 8bit DMA channel, SBHWPG 2-7 */
546 if (chip->dma16 < 0) {
547 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE;
548 chip->mode |= SB_MODE_PLAYBACK_16;
549 } else {
550 runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8;
551 }
552 runtime->hw.buffer_bytes_max =
553 runtime->hw.period_bytes_max = 64 * 1024;
554 goto __open_ok;
555 }
556 spin_unlock_irqrestore(&chip->open_lock, flags);
557 return -EAGAIN;
558
559 __open_ok:
560 if (chip->hardware == SB_HW_ALS100)
561 runtime->hw.rate_max = 48000;
562 if (chip->mode & SB_RATE_LOCK)
563 runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
564 chip->playback_substream = substream;
565 spin_unlock_irqrestore(&chip->open_lock, flags);
566 return 0;
567}
568
569static int snd_sb16_playback_close(snd_pcm_substream_t * substream)
570{
571 unsigned long flags;
572 sb_t *chip = snd_pcm_substream_chip(substream);
573
574 snd_sb16_csp_playback_close(chip);
575 spin_lock_irqsave(&chip->open_lock, flags);
576 chip->playback_substream = NULL;
577 chip->mode &= ~SB_MODE_PLAYBACK;
578 spin_unlock_irqrestore(&chip->open_lock, flags);
579 return 0;
580}
581
582static int snd_sb16_capture_open(snd_pcm_substream_t * substream)
583{
584 unsigned long flags;
585 sb_t *chip = snd_pcm_substream_chip(substream);
586 snd_pcm_runtime_t *runtime = substream->runtime;
587
588 spin_lock_irqsave(&chip->open_lock, flags);
589 if (chip->mode & SB_MODE_CAPTURE) {
590 spin_unlock_irqrestore(&chip->open_lock, flags);
591 return -EAGAIN;
592 }
593 runtime->hw = snd_sb16_capture;
594
595 /* skip if 16 bit DMA was reserved for playback */
596 if (chip->force_mode16 & SB_MODE_PLAYBACK_16)
597 goto __skip_16bit;
598
599 if (chip->dma16 >= 0 && !(chip->mode & SB_MODE_PLAYBACK_16)) {
600 chip->mode |= SB_MODE_CAPTURE_16;
601 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE;
602 /* Vibra16X hack */
603 if (chip->dma16 <= 3) {
604 runtime->hw.buffer_bytes_max =
605 runtime->hw.period_bytes_max = 64 * 1024;
606 } else {
607 snd_sb16_csp_capture_open(chip, runtime);
608 }
609 goto __open_ok;
610 }
611
612 __skip_16bit:
613 if (chip->dma8 >= 0 && !(chip->mode & SB_MODE_PLAYBACK_8)) {
614 chip->mode |= SB_MODE_CAPTURE_8;
615 /* DSP v 4.xx can transfer 16bit data through 8bit DMA channel, SBHWPG 2-7 */
616 if (chip->dma16 < 0) {
617 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE;
618 chip->mode |= SB_MODE_CAPTURE_16;
619 } else {
620 runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8;
621 }
622 runtime->hw.buffer_bytes_max =
623 runtime->hw.period_bytes_max = 64 * 1024;
624 goto __open_ok;
625 }
626 spin_unlock_irqrestore(&chip->open_lock, flags);
627 return -EAGAIN;
628
629 __open_ok:
630 if (chip->hardware == SB_HW_ALS100)
631 runtime->hw.rate_max = 48000;
632 if (chip->mode & SB_RATE_LOCK)
633 runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
634 chip->capture_substream = substream;
635 spin_unlock_irqrestore(&chip->open_lock, flags);
636 return 0;
637}
638
639static int snd_sb16_capture_close(snd_pcm_substream_t * substream)
640{
641 unsigned long flags;
642 sb_t *chip = snd_pcm_substream_chip(substream);
643
644 snd_sb16_csp_capture_close(chip);
645 spin_lock_irqsave(&chip->open_lock, flags);
646 chip->capture_substream = NULL;
647 chip->mode &= ~SB_MODE_CAPTURE;
648 spin_unlock_irqrestore(&chip->open_lock, flags);
649 return 0;
650}
651
652/*
653 * DMA control interface
654 */
655
656static int snd_sb16_set_dma_mode(sb_t *chip, int what)
657{
658 if (chip->dma8 < 0 || chip->dma16 < 0) {
659 snd_assert(what == 0, return -EINVAL);
660 return 0;
661 }
662 if (what == 0) {
663 chip->force_mode16 = 0;
664 } else if (what == 1) {
665 chip->force_mode16 = SB_MODE_PLAYBACK_16;
666 } else if (what == 2) {
667 chip->force_mode16 = SB_MODE_CAPTURE_16;
668 } else {
669 return -EINVAL;
670 }
671 return 0;
672}
673
674static int snd_sb16_get_dma_mode(sb_t *chip)
675{
676 if (chip->dma8 < 0 || chip->dma16 < 0)
677 return 0;
678 switch (chip->force_mode16) {
679 case SB_MODE_PLAYBACK_16:
680 return 1;
681 case SB_MODE_CAPTURE_16:
682 return 2;
683 default:
684 return 0;
685 }
686}
687
688static int snd_sb16_dma_control_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
689{
690 static char *texts[3] = {
691 "Auto", "Playback", "Capture"
692 };
693
694 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
695 uinfo->count = 1;
696 uinfo->value.enumerated.items = 3;
697 if (uinfo->value.enumerated.item > 2)
698 uinfo->value.enumerated.item = 2;
699 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
700 return 0;
701}
702
703static int snd_sb16_dma_control_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
704{
705 sb_t *chip = snd_kcontrol_chip(kcontrol);
706 unsigned long flags;
707
708 spin_lock_irqsave(&chip->reg_lock, flags);
709 ucontrol->value.enumerated.item[0] = snd_sb16_get_dma_mode(chip);
710 spin_unlock_irqrestore(&chip->reg_lock, flags);
711 return 0;
712}
713
714static int snd_sb16_dma_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
715{
716 sb_t *chip = snd_kcontrol_chip(kcontrol);
717 unsigned long flags;
718 unsigned char nval, oval;
719 int change;
720
721 if ((nval = ucontrol->value.enumerated.item[0]) > 2)
722 return -EINVAL;
723 spin_lock_irqsave(&chip->reg_lock, flags);
724 oval = snd_sb16_get_dma_mode(chip);
725 change = nval != oval;
726 snd_sb16_set_dma_mode(chip, nval);
727 spin_unlock_irqrestore(&chip->reg_lock, flags);
728 return change;
729}
730
731static snd_kcontrol_new_t snd_sb16_dma_control = {
732 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
733 .name = "16-bit DMA Allocation",
734 .info = snd_sb16_dma_control_info,
735 .get = snd_sb16_dma_control_get,
736 .put = snd_sb16_dma_control_put
737};
738
739/*
740 * Initialization part
741 */
742
743int snd_sb16dsp_configure(sb_t * chip)
744{
745 unsigned long flags;
746 unsigned char irqreg = 0, dmareg = 0, mpureg;
747 unsigned char realirq, realdma, realmpureg;
748 /* note: mpu register should be present only on SB16 Vibra soundcards */
749
750 // printk("codec->irq=%i, codec->dma8=%i, codec->dma16=%i\n", chip->irq, chip->dma8, chip->dma16);
751 spin_lock_irqsave(&chip->mixer_lock, flags);
752 mpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP) & ~0x06;
753 spin_unlock_irqrestore(&chip->mixer_lock, flags);
754 switch (chip->irq) {
755 case 2:
756 case 9:
757 irqreg |= SB_IRQSETUP_IRQ9;
758 break;
759 case 5:
760 irqreg |= SB_IRQSETUP_IRQ5;
761 break;
762 case 7:
763 irqreg |= SB_IRQSETUP_IRQ7;
764 break;
765 case 10:
766 irqreg |= SB_IRQSETUP_IRQ10;
767 break;
768 default:
769 return -EINVAL;
770 }
771 if (chip->dma8 >= 0) {
772 switch (chip->dma8) {
773 case 0:
774 dmareg |= SB_DMASETUP_DMA0;
775 break;
776 case 1:
777 dmareg |= SB_DMASETUP_DMA1;
778 break;
779 case 3:
780 dmareg |= SB_DMASETUP_DMA3;
781 break;
782 default:
783 return -EINVAL;
784 }
785 }
786 if (chip->dma16 >= 0 && chip->dma16 != chip->dma8) {
787 switch (chip->dma16) {
788 case 5:
789 dmareg |= SB_DMASETUP_DMA5;
790 break;
791 case 6:
792 dmareg |= SB_DMASETUP_DMA6;
793 break;
794 case 7:
795 dmareg |= SB_DMASETUP_DMA7;
796 break;
797 default:
798 return -EINVAL;
799 }
800 }
801 switch (chip->mpu_port) {
802 case 0x300:
803 mpureg |= 0x04;
804 break;
805 case 0x330:
806 mpureg |= 0x00;
807 break;
808 default:
809 mpureg |= 0x02; /* disable MPU */
810 }
811 spin_lock_irqsave(&chip->mixer_lock, flags);
812
813 snd_sbmixer_write(chip, SB_DSP4_IRQSETUP, irqreg);
814 realirq = snd_sbmixer_read(chip, SB_DSP4_IRQSETUP);
815
816 snd_sbmixer_write(chip, SB_DSP4_DMASETUP, dmareg);
817 realdma = snd_sbmixer_read(chip, SB_DSP4_DMASETUP);
818
819 snd_sbmixer_write(chip, SB_DSP4_MPUSETUP, mpureg);
820 realmpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP);
821
822 spin_unlock_irqrestore(&chip->mixer_lock, flags);
823 if ((~realirq) & irqreg || (~realdma) & dmareg) {
824 snd_printk("SB16 [0x%lx]: unable to set DMA & IRQ (PnP device?)\n", chip->port);
825 snd_printk("SB16 [0x%lx]: wanted: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, realirq, realdma, realmpureg);
826 snd_printk("SB16 [0x%lx]: got: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, irqreg, dmareg, mpureg);
827 return -ENODEV;
828 }
829 return 0;
830}
831
832static snd_pcm_ops_t snd_sb16_playback_ops = {
833 .open = snd_sb16_playback_open,
834 .close = snd_sb16_playback_close,
835 .ioctl = snd_pcm_lib_ioctl,
836 .hw_params = snd_sb16_hw_params,
837 .hw_free = snd_sb16_hw_free,
838 .prepare = snd_sb16_playback_prepare,
839 .trigger = snd_sb16_playback_trigger,
840 .pointer = snd_sb16_playback_pointer,
841};
842
843static snd_pcm_ops_t snd_sb16_capture_ops = {
844 .open = snd_sb16_capture_open,
845 .close = snd_sb16_capture_close,
846 .ioctl = snd_pcm_lib_ioctl,
847 .hw_params = snd_sb16_hw_params,
848 .hw_free = snd_sb16_hw_free,
849 .prepare = snd_sb16_capture_prepare,
850 .trigger = snd_sb16_capture_trigger,
851 .pointer = snd_sb16_capture_pointer,
852};
853
854static void snd_sb16dsp_pcm_free(snd_pcm_t *pcm)
855{
856 snd_pcm_lib_preallocate_free_for_all(pcm);
857}
858
859int snd_sb16dsp_pcm(sb_t * chip, int device, snd_pcm_t ** rpcm)
860{
861 snd_card_t *card = chip->card;
862 snd_pcm_t *pcm;
863 int err;
864
865 if (rpcm)
866 *rpcm = NULL;
867 if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0)
868 return err;
869 sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
870 pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
871 pcm->private_data = chip;
872 pcm->private_free = snd_sb16dsp_pcm_free;
873
874 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops);
875 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops);
876
877 if (chip->dma16 >= 0 && chip->dma8 != chip->dma16)
878 snd_ctl_add(card, snd_ctl_new1(&snd_sb16_dma_control, chip));
879 else
880 pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
881
882 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
883 snd_dma_isa_data(),
884 64*1024, 128*1024);
885
886 if (rpcm)
887 *rpcm = pcm;
888 return 0;
889}
890
891const snd_pcm_ops_t *snd_sb16dsp_get_pcm_ops(int direction)
892{
893 return direction == SNDRV_PCM_STREAM_PLAYBACK ?
894 &snd_sb16_playback_ops : &snd_sb16_capture_ops;
895}
896
897EXPORT_SYMBOL(snd_sb16dsp_pcm);
898EXPORT_SYMBOL(snd_sb16dsp_get_pcm_ops);
899EXPORT_SYMBOL(snd_sb16dsp_configure);
900EXPORT_SYMBOL(snd_sb16dsp_interrupt);
901
902/*
903 * INIT part
904 */
905
906static int __init alsa_sb16_init(void)
907{
908 return 0;
909}
910
911static void __exit alsa_sb16_exit(void)
912{
913}
914
915module_init(alsa_sb16_init)
916module_exit(alsa_sb16_exit)
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
new file mode 100644
index 000000000000..e2cbc4202b3d
--- /dev/null
+++ b/sound/isa/sb/sb8.c
@@ -0,0 +1,223 @@
1/*
2 * Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <linux/init.h>
24#include <linux/slab.h>
25#include <linux/ioport.h>
26#include <linux/moduleparam.h>
27#include <sound/core.h>
28#include <sound/sb.h>
29#include <sound/opl3.h>
30#define SNDRV_LEGACY_AUTO_PROBE
31#include <sound/initval.h>
32
33MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
34MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro");
35MODULE_LICENSE("GPL");
36MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}");
37
38static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
39static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
40static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
41static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
42static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
43static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3 */
44
45module_param_array(index, int, NULL, 0444);
46MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard.");
47module_param_array(id, charp, NULL, 0444);
48MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard.");
49module_param_array(enable, bool, NULL, 0444);
50MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard.");
51module_param_array(port, long, NULL, 0444);
52MODULE_PARM_DESC(port, "Port # for SB8 driver.");
53module_param_array(irq, int, NULL, 0444);
54MODULE_PARM_DESC(irq, "IRQ # for SB8 driver.");
55module_param_array(dma8, int, NULL, 0444);
56MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");
57
58struct snd_sb8 {
59 struct resource *fm_res; /* used to block FM i/o region for legacy cards */
60};
61
62static snd_card_t *snd_sb8_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
63
64static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs)
65{
66 sb_t *chip = dev_id;
67
68 if (chip->open & SB_OPEN_PCM) {
69 return snd_sb8dsp_interrupt(chip);
70 } else {
71 return snd_sb8dsp_midi_interrupt(chip);
72 }
73}
74
75static void snd_sb8_free(snd_card_t *card)
76{
77 struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
78
79 if (acard == NULL)
80 return;
81 if (acard->fm_res) {
82 release_resource(acard->fm_res);
83 kfree_nocheck(acard->fm_res);
84 }
85}
86
87static int __init snd_sb8_probe(int dev)
88{
89 sb_t *chip;
90 snd_card_t *card;
91 struct snd_sb8 *acard;
92 opl3_t *opl3;
93 int err;
94
95 card = snd_card_new(index[dev], id[dev], THIS_MODULE,
96 sizeof(struct snd_sb8));
97 if (card == NULL)
98 return -ENOMEM;
99 acard = (struct snd_sb8 *)card->private_data;
100 card->private_free = snd_sb8_free;
101
102 /* block the 0x388 port to avoid PnP conflicts */
103 acard->fm_res = request_region(0x388, 4, "SoundBlaster FM");
104
105 if ((err = snd_sbdsp_create(card, port[dev], irq[dev],
106 snd_sb8_interrupt,
107 dma8[dev],
108 -1,
109 SB_HW_AUTO,
110 &chip)) < 0) {
111 snd_card_free(card);
112 return err;
113 }
114 if (chip->hardware >= SB_HW_16) {
115 snd_card_free(card);
116 if (chip->hardware == SB_HW_ALS100)
117 snd_printdd("ALS100 chip detected at 0x%lx, try snd-als100 module\n",
118 port[dev]);
119 else
120 snd_printdd("SB 16 chip detected at 0x%lx, try snd-sb16 module\n",
121 port[dev]);
122 return -ENODEV;
123 }
124
125 if ((err = snd_sb8dsp_pcm(chip, 0, NULL)) < 0) {
126 snd_card_free(card);
127 return err;
128 }
129 if ((err = snd_sbmixer_new(chip)) < 0) {
130 snd_card_free(card);
131 return err;
132 }
133 if (chip->hardware == SB_HW_10 || chip->hardware == SB_HW_20) {
134 if ((err = snd_opl3_create(card, chip->port + 8, 0,
135 OPL3_HW_AUTO, 1,
136 &opl3)) < 0) {
137 snd_printk(KERN_ERR "sb8: no OPL device at 0x%lx\n", chip->port + 8);
138 }
139 } else {
140 if ((err = snd_opl3_create(card, chip->port, chip->port + 2,
141 OPL3_HW_AUTO, 1,
142 &opl3)) < 0) {
143 snd_printk(KERN_ERR "sb8: no OPL device at 0x%lx-0x%lx\n",
144 chip->port, chip->port + 2);
145 }
146 }
147 if (err >= 0) {
148 if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
149 snd_card_free(card);
150 return err;
151 }
152 }
153
154 if ((err = snd_sb8dsp_midi(chip, 0, NULL)) < 0) {
155 snd_card_free(card);
156 return err;
157 }
158
159 strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
160 strcpy(card->shortname, chip->name);
161 sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
162 chip->name,
163 chip->port,
164 irq[dev], dma8[dev]);
165 if ((err = snd_card_register(card)) < 0) {
166 snd_card_free(card);
167 return err;
168 }
169 snd_sb8_cards[dev] = card;
170 return 0;
171}
172
173static int __init snd_card_sb8_legacy_auto_probe(unsigned long xport)
174{
175 static int dev;
176 int res;
177
178 for ( ; dev < SNDRV_CARDS; dev++) {
179 if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT)
180 continue;
181 port[dev] = xport;
182 res = snd_sb8_probe(dev);
183 if (res < 0)
184 port[dev] = SNDRV_AUTO_PORT;
185 return res;
186 }
187 return -ENODEV;
188}
189
190static int __init alsa_card_sb8_init(void)
191{
192 static unsigned long possible_ports[] = {0x220, 0x240, 0x260, -1};
193 int dev, cards, i;
194
195 for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
196 if (port[dev] == SNDRV_AUTO_PORT)
197 continue;
198 if (snd_sb8_probe(dev) >= 0)
199 cards++;
200 }
201 i = snd_legacy_auto_probe(possible_ports, snd_card_sb8_legacy_auto_probe);
202 if (i > 0)
203 cards += i;
204
205 if (!cards) {
206#ifdef MODULE
207 snd_printk(KERN_ERR "Sound Blaster soundcard not found or device busy\n");
208#endif
209 return -ENODEV;
210 }
211 return 0;
212}
213
214static void __exit alsa_card_sb8_exit(void)
215{
216 int idx;
217
218 for (idx = 0; idx < SNDRV_CARDS; idx++)
219 snd_card_free(snd_sb8_cards[idx]);
220}
221
222module_init(alsa_card_sb8_init)
223module_exit(alsa_card_sb8_exit)
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c
new file mode 100644
index 000000000000..87c9b1ba06cf
--- /dev/null
+++ b/sound/isa/sb/sb8_main.c
@@ -0,0 +1,565 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Uros Bizjak <uros@kss-loka.si>
4 *
5 * Routines for control of 8-bit SoundBlaster cards and clones
6 * Please note: I don't have access to old SB8 soundcards.
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * --
24 *
25 * Thu Apr 29 20:36:17 BST 1999 George David Morrison <gdm@gedamo.demon.co.uk>
26 * DSP can't respond to commands whilst in "high speed" mode. Caused
27 * glitching during playback. Fixed.
28 *
29 * Wed Jul 12 22:02:55 CEST 2000 Uros Bizjak <uros@kss-loka.si>
30 * Cleaned up and rewrote lowlevel routines.
31 */
32
33#include <sound/driver.h>
34#include <asm/io.h>
35#include <asm/dma.h>
36#include <linux/init.h>
37#include <linux/time.h>
38#include <sound/core.h>
39#include <sound/sb.h>
40
41MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Uros Bizjak <uros@kss-loka.si>");
42MODULE_DESCRIPTION("Routines for control of 8-bit SoundBlaster cards and clones");
43MODULE_LICENSE("GPL");
44
45#define SB8_CLOCK 1000000
46#define SB8_DEN(v) ((SB8_CLOCK + (v) / 2) / (v))
47#define SB8_RATE(v) (SB8_CLOCK / SB8_DEN(v))
48
49static ratnum_t clock = {
50 .num = SB8_CLOCK,
51 .den_min = 1,
52 .den_max = 256,
53 .den_step = 1,
54};
55
56static snd_pcm_hw_constraint_ratnums_t hw_constraints_clock = {
57 .nrats = 1,
58 .rats = &clock,
59};
60
61static ratnum_t stereo_clocks[] = {
62 {
63 .num = SB8_CLOCK,
64 .den_min = SB8_DEN(22050),
65 .den_max = SB8_DEN(22050),
66 .den_step = 1,
67 },
68 {
69 .num = SB8_CLOCK,
70 .den_min = SB8_DEN(11025),
71 .den_max = SB8_DEN(11025),
72 .den_step = 1,
73 }
74};
75
76static int snd_sb8_hw_constraint_rate_channels(snd_pcm_hw_params_t *params,
77 snd_pcm_hw_rule_t *rule)
78{
79 snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
80 if (c->min > 1) {
81 unsigned int num = 0, den = 0;
82 int err = snd_interval_ratnum(hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE),
83 2, stereo_clocks, &num, &den);
84 if (err >= 0 && den) {
85 params->rate_num = num;
86 params->rate_den = den;
87 }
88 return err;
89 }
90 return 0;
91}
92
93static int snd_sb8_hw_constraint_channels_rate(snd_pcm_hw_params_t *params,
94 snd_pcm_hw_rule_t *rule)
95{
96 snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
97 if (r->min > SB8_RATE(22050) || r->max <= SB8_RATE(11025)) {
98 snd_interval_t t = { .min = 1, .max = 1 };
99 return snd_interval_refine(hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS), &t);
100 }
101 return 0;
102}
103
104static int snd_sb8_playback_prepare(snd_pcm_substream_t * substream)
105{
106 unsigned long flags;
107 sb_t *chip = snd_pcm_substream_chip(substream);
108 snd_pcm_runtime_t *runtime = substream->runtime;
109 unsigned int mixreg, rate, size, count;
110
111 rate = runtime->rate;
112 switch (chip->hardware) {
113 case SB_HW_PRO:
114 if (runtime->channels > 1) {
115 snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL);
116 chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
117 break;
118 }
119 /* fallthru */
120 case SB_HW_201:
121 if (rate > 23000) {
122 chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
123 break;
124 }
125 /* fallthru */
126 case SB_HW_20:
127 chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
128 break;
129 case SB_HW_10:
130 chip->playback_format = SB_DSP_OUTPUT;
131 break;
132 default:
133 return -EINVAL;
134 }
135 size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
136 count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
137 spin_lock_irqsave(&chip->reg_lock, flags);
138 snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
139 if (runtime->channels > 1) {
140 /* set playback stereo mode */
141 spin_lock(&chip->mixer_lock);
142 mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
143 snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02);
144 spin_unlock(&chip->mixer_lock);
145
146 /* Soundblaster hardware programming reference guide, 3-23 */
147 snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
148 runtime->dma_area[0] = 0x80;
149 snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE);
150 /* force interrupt */
151 chip->mode = SB_MODE_HALT;
152 snd_sbdsp_command(chip, SB_DSP_OUTPUT);
153 snd_sbdsp_command(chip, 0);
154 snd_sbdsp_command(chip, 0);
155 }
156 snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
157 if (runtime->channels > 1) {
158 snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
159 spin_lock(&chip->mixer_lock);
160 /* save output filter status and turn it off */
161 mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT);
162 snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20);
163 spin_unlock(&chip->mixer_lock);
164 /* just use force_mode16 for temporary storate... */
165 chip->force_mode16 = mixreg;
166 } else {
167 snd_sbdsp_command(chip, 256 - runtime->rate_den);
168 }
169 if (chip->playback_format != SB_DSP_OUTPUT) {
170 count--;
171 snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
172 snd_sbdsp_command(chip, count & 0xff);
173 snd_sbdsp_command(chip, count >> 8);
174 }
175 spin_unlock_irqrestore(&chip->reg_lock, flags);
176 snd_dma_program(chip->dma8, runtime->dma_addr,
177 size, DMA_MODE_WRITE | DMA_AUTOINIT);
178 return 0;
179}
180
181static int snd_sb8_playback_trigger(snd_pcm_substream_t * substream,
182 int cmd)
183{
184 unsigned long flags;
185 sb_t *chip = snd_pcm_substream_chip(substream);
186 unsigned int count;
187
188 spin_lock_irqsave(&chip->reg_lock, flags);
189 switch (cmd) {
190 case SNDRV_PCM_TRIGGER_START:
191 snd_sbdsp_command(chip, chip->playback_format);
192 if (chip->playback_format == SB_DSP_OUTPUT) {
193 count = chip->p_period_size - 1;
194 snd_sbdsp_command(chip, count & 0xff);
195 snd_sbdsp_command(chip, count >> 8);
196 }
197 break;
198 case SNDRV_PCM_TRIGGER_STOP:
199 if (chip->playback_format == SB_DSP_HI_OUTPUT_AUTO) {
200 snd_pcm_runtime_t *runtime = substream->runtime;
201 snd_sbdsp_reset(chip);
202 if (runtime->channels > 1) {
203 spin_lock(&chip->mixer_lock);
204 /* restore output filter and set hardware to mono mode */
205 snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02);
206 spin_unlock(&chip->mixer_lock);
207 }
208 } else {
209 snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
210 }
211 snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
212 }
213 spin_unlock_irqrestore(&chip->reg_lock, flags);
214 chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT;
215 return 0;
216}
217
218static int snd_sb8_hw_params(snd_pcm_substream_t * substream,
219 snd_pcm_hw_params_t * hw_params)
220{
221 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
222}
223
224static int snd_sb8_hw_free(snd_pcm_substream_t * substream)
225{
226 snd_pcm_lib_free_pages(substream);
227 return 0;
228}
229
230static int snd_sb8_capture_prepare(snd_pcm_substream_t * substream)
231{
232 unsigned long flags;
233 sb_t *chip = snd_pcm_substream_chip(substream);
234 snd_pcm_runtime_t *runtime = substream->runtime;
235 unsigned int mixreg, rate, size, count;
236
237 rate = runtime->rate;
238 switch (chip->hardware) {
239 case SB_HW_PRO:
240 if (runtime->channels > 1) {
241 snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL);
242 chip->capture_format = SB_DSP_HI_INPUT_AUTO;
243 break;
244 }
245 chip->capture_format = (rate > 23000) ? SB_DSP_HI_INPUT_AUTO : SB_DSP_LO_INPUT_AUTO;
246 break;
247 case SB_HW_201:
248 if (rate > 13000) {
249 chip->capture_format = SB_DSP_HI_INPUT_AUTO;
250 break;
251 }
252 /* fallthru */
253 case SB_HW_20:
254 chip->capture_format = SB_DSP_LO_INPUT_AUTO;
255 break;
256 case SB_HW_10:
257 chip->capture_format = SB_DSP_INPUT;
258 break;
259 default:
260 return -EINVAL;
261 }
262 size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
263 count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
264 spin_lock_irqsave(&chip->reg_lock, flags);
265 snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
266 if (runtime->channels > 1)
267 snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
268 snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
269 if (runtime->channels > 1) {
270 snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
271 spin_lock(&chip->mixer_lock);
272 /* save input filter status and turn it off */
273 mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT);
274 snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20);
275 spin_unlock(&chip->mixer_lock);
276 /* just use force_mode16 for temporary storate... */
277 chip->force_mode16 = mixreg;
278 } else {
279 snd_sbdsp_command(chip, 256 - runtime->rate_den);
280 }
281 if (chip->capture_format != SB_DSP_OUTPUT) {
282 count--;
283 snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
284 snd_sbdsp_command(chip, count & 0xff);
285 snd_sbdsp_command(chip, count >> 8);
286 }
287 spin_unlock_irqrestore(&chip->reg_lock, flags);
288 snd_dma_program(chip->dma8, runtime->dma_addr,
289 size, DMA_MODE_READ | DMA_AUTOINIT);
290 return 0;
291}
292
293static int snd_sb8_capture_trigger(snd_pcm_substream_t * substream,
294 int cmd)
295{
296 unsigned long flags;
297 sb_t *chip = snd_pcm_substream_chip(substream);
298 unsigned int count;
299
300 spin_lock_irqsave(&chip->reg_lock, flags);
301 switch (cmd) {
302 case SNDRV_PCM_TRIGGER_START:
303 snd_sbdsp_command(chip, chip->capture_format);
304 if (chip->capture_format == SB_DSP_INPUT) {
305 count = chip->c_period_size - 1;
306 snd_sbdsp_command(chip, count & 0xff);
307 snd_sbdsp_command(chip, count >> 8);
308 }
309 break;
310 case SNDRV_PCM_TRIGGER_STOP:
311 if (chip->capture_format == SB_DSP_HI_INPUT_AUTO) {
312 snd_pcm_runtime_t *runtime = substream->runtime;
313 snd_sbdsp_reset(chip);
314 if (runtime->channels > 1) {
315 /* restore input filter status */
316 spin_lock(&chip->mixer_lock);
317 snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16);
318 spin_unlock(&chip->mixer_lock);
319 /* set hardware to mono mode */
320 snd_sbdsp_command(chip, SB_DSP_MONO_8BIT);
321 }
322 } else {
323 snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
324 }
325 snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
326 }
327 spin_unlock_irqrestore(&chip->reg_lock, flags);
328 chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT;
329 return 0;
330}
331
332irqreturn_t snd_sb8dsp_interrupt(sb_t *chip)
333{
334 snd_pcm_substream_t *substream;
335 snd_pcm_runtime_t *runtime;
336
337#if 0
338 snd_printk("sb8: interrupt\n");
339#endif
340 snd_sb_ack_8bit(chip);
341 switch (chip->mode) {
342 case SB_MODE_PLAYBACK_8: /* ok.. playback is active */
343 substream = chip->playback_substream;
344 runtime = substream->runtime;
345 if (chip->playback_format == SB_DSP_OUTPUT)
346 snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
347 snd_pcm_period_elapsed(substream);
348 break;
349 case SB_MODE_CAPTURE_8:
350 substream = chip->capture_substream;
351 runtime = substream->runtime;
352 if (chip->capture_format == SB_DSP_INPUT)
353 snd_sb8_capture_trigger(substream, SNDRV_PCM_TRIGGER_START);
354 snd_pcm_period_elapsed(substream);
355 break;
356 }
357 return IRQ_HANDLED;
358}
359
360static snd_pcm_uframes_t snd_sb8_playback_pointer(snd_pcm_substream_t * substream)
361{
362 sb_t *chip = snd_pcm_substream_chip(substream);
363 size_t ptr;
364
365 if (chip->mode != SB_MODE_PLAYBACK_8)
366 return 0;
367 ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size);
368 return bytes_to_frames(substream->runtime, ptr);
369}
370
371static snd_pcm_uframes_t snd_sb8_capture_pointer(snd_pcm_substream_t * substream)
372{
373 sb_t *chip = snd_pcm_substream_chip(substream);
374 size_t ptr;
375
376 if (chip->mode != SB_MODE_CAPTURE_8)
377 return 0;
378 ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size);
379 return bytes_to_frames(substream->runtime, ptr);
380}
381
382/*
383
384 */
385
386static snd_pcm_hardware_t snd_sb8_playback =
387{
388 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
389 SNDRV_PCM_INFO_MMAP_VALID),
390 .formats = SNDRV_PCM_FMTBIT_U8,
391 .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |
392 SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050),
393 .rate_min = 4000,
394 .rate_max = 23000,
395 .channels_min = 1,
396 .channels_max = 1,
397 .buffer_bytes_max = 65536,
398 .period_bytes_min = 64,
399 .period_bytes_max = 65536,
400 .periods_min = 1,
401 .periods_max = 1024,
402 .fifo_size = 0,
403};
404
405static snd_pcm_hardware_t snd_sb8_capture =
406{
407 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
408 SNDRV_PCM_INFO_MMAP_VALID),
409 .formats = SNDRV_PCM_FMTBIT_U8,
410 .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |
411 SNDRV_PCM_RATE_11025),
412 .rate_min = 4000,
413 .rate_max = 13000,
414 .channels_min = 1,
415 .channels_max = 1,
416 .buffer_bytes_max = 65536,
417 .period_bytes_min = 64,
418 .period_bytes_max = 65536,
419 .periods_min = 1,
420 .periods_max = 1024,
421 .fifo_size = 0,
422};
423
424/*
425 *
426 */
427
428static int snd_sb8_open(snd_pcm_substream_t *substream)
429{
430 sb_t *chip = snd_pcm_substream_chip(substream);
431 snd_pcm_runtime_t *runtime = substream->runtime;
432 unsigned long flags;
433
434 spin_lock_irqsave(&chip->open_lock, flags);
435 if (chip->open) {
436 spin_unlock_irqrestore(&chip->open_lock, flags);
437 return -EAGAIN;
438 }
439 chip->open |= SB_OPEN_PCM;
440 spin_unlock_irqrestore(&chip->open_lock, flags);
441 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
442 chip->playback_substream = substream;
443 runtime->hw = snd_sb8_playback;
444 } else {
445 chip->capture_substream = substream;
446 runtime->hw = snd_sb8_capture;
447 }
448 switch (chip->hardware) {
449 case SB_HW_PRO:
450 runtime->hw.rate_max = 44100;
451 runtime->hw.channels_max = 2;
452 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
453 snd_sb8_hw_constraint_rate_channels, NULL,
454 SNDRV_PCM_HW_PARAM_CHANNELS,
455 SNDRV_PCM_HW_PARAM_RATE, -1);
456 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
457 snd_sb8_hw_constraint_channels_rate, NULL,
458 SNDRV_PCM_HW_PARAM_RATE, -1);
459 break;
460 case SB_HW_201:
461 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
462 runtime->hw.rate_max = 44100;
463 } else {
464 runtime->hw.rate_max = 15000;
465 }
466 default:
467 break;
468 }
469 snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
470 &hw_constraints_clock);
471 return 0;
472}
473
474static int snd_sb8_close(snd_pcm_substream_t *substream)
475{
476 unsigned long flags;
477 sb_t *chip = snd_pcm_substream_chip(substream);
478
479 chip->playback_substream = NULL;
480 chip->capture_substream = NULL;
481 spin_lock_irqsave(&chip->open_lock, flags);
482 chip->open &= ~SB_OPEN_PCM;
483 spin_unlock_irqrestore(&chip->open_lock, flags);
484 return 0;
485}
486
487/*
488 * Initialization part
489 */
490
491static snd_pcm_ops_t snd_sb8_playback_ops = {
492 .open = snd_sb8_open,
493 .close = snd_sb8_close,
494 .ioctl = snd_pcm_lib_ioctl,
495 .hw_params = snd_sb8_hw_params,
496 .hw_free = snd_sb8_hw_free,
497 .prepare = snd_sb8_playback_prepare,
498 .trigger = snd_sb8_playback_trigger,
499 .pointer = snd_sb8_playback_pointer,
500};
501
502static snd_pcm_ops_t snd_sb8_capture_ops = {
503 .open = snd_sb8_open,
504 .close = snd_sb8_close,
505 .ioctl = snd_pcm_lib_ioctl,
506 .hw_params = snd_sb8_hw_params,
507 .hw_free = snd_sb8_hw_free,
508 .prepare = snd_sb8_capture_prepare,
509 .trigger = snd_sb8_capture_trigger,
510 .pointer = snd_sb8_capture_pointer,
511};
512
513static void snd_sb8dsp_pcm_free(snd_pcm_t *pcm)
514{
515 snd_pcm_lib_preallocate_free_for_all(pcm);
516}
517
518int snd_sb8dsp_pcm(sb_t *chip, int device, snd_pcm_t ** rpcm)
519{
520 snd_card_t *card = chip->card;
521 snd_pcm_t *pcm;
522 int err;
523
524 if (rpcm)
525 *rpcm = NULL;
526 if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0)
527 return err;
528 sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
529 pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
530 pcm->private_data = chip;
531 pcm->private_free = snd_sb8dsp_pcm_free;
532
533 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
534 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
535
536 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
537 snd_dma_isa_data(),
538 64*1024, 64*1024);
539
540 if (rpcm)
541 *rpcm = pcm;
542 return 0;
543}
544
545EXPORT_SYMBOL(snd_sb8dsp_pcm);
546EXPORT_SYMBOL(snd_sb8dsp_interrupt);
547 /* sb8_midi.c */
548EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt);
549EXPORT_SYMBOL(snd_sb8dsp_midi);
550
551/*
552 * INIT part
553 */
554
555static int __init alsa_sb8_init(void)
556{
557 return 0;
558}
559
560static void __exit alsa_sb8_exit(void)
561{
562}
563
564module_init(alsa_sb8_init)
565module_exit(alsa_sb8_exit)
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c
new file mode 100644
index 000000000000..d2c633a40e74
--- /dev/null
+++ b/sound/isa/sb/sb8_midi.c
@@ -0,0 +1,293 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for control of SoundBlaster cards - MIDI interface
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * --
20 *
21 * Sun May 9 22:54:38 BST 1999 George David Morrison <gdm@gedamo.demon.co.uk>
22 * Fixed typo in snd_sb8dsp_midi_new_device which prevented midi from
23 * working.
24 *
25 * Sun May 11 12:34:56 UTC 2003 Clemens Ladisch <clemens@ladisch.de>
26 * Added full duplex UART mode for DSP version 2.0 and later.
27 */
28
29#include <sound/driver.h>
30#include <asm/io.h>
31#include <linux/time.h>
32#include <sound/core.h>
33#include <sound/sb.h>
34
35/*
36
37 */
38
39irqreturn_t snd_sb8dsp_midi_interrupt(sb_t * chip)
40{
41 snd_rawmidi_t *rmidi;
42 int max = 64;
43 char byte;
44
45 if (chip == NULL || (rmidi = chip->rmidi) == NULL) {
46 inb(SBP(chip, DATA_AVAIL)); /* ack interrupt */
47 return IRQ_NONE;
48 }
49 spin_lock(&chip->midi_input_lock);
50 while (max-- > 0) {
51 if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
52 byte = inb(SBP(chip, READ));
53 if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) {
54 snd_rawmidi_receive(chip->midi_substream_input, &byte, 1);
55 }
56 }
57 }
58 spin_unlock(&chip->midi_input_lock);
59 return IRQ_HANDLED;
60}
61
62/*
63
64 */
65
66static int snd_sb8dsp_midi_input_open(snd_rawmidi_substream_t * substream)
67{
68 unsigned long flags;
69 sb_t *chip;
70 unsigned int valid_open_flags;
71
72 chip = substream->rmidi->private_data;
73 valid_open_flags = chip->hardware >= SB_HW_20
74 ? SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER : 0;
75 spin_lock_irqsave(&chip->open_lock, flags);
76 if (chip->open & ~valid_open_flags) {
77 spin_unlock_irqrestore(&chip->open_lock, flags);
78 return -EAGAIN;
79 }
80 chip->open |= SB_OPEN_MIDI_INPUT;
81 chip->midi_substream_input = substream;
82 if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) {
83 spin_unlock_irqrestore(&chip->open_lock, flags);
84 snd_sbdsp_reset(chip); /* reset DSP */
85 if (chip->hardware >= SB_HW_20)
86 snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);
87 } else {
88 spin_unlock_irqrestore(&chip->open_lock, flags);
89 }
90 return 0;
91}
92
93static int snd_sb8dsp_midi_output_open(snd_rawmidi_substream_t * substream)
94{
95 unsigned long flags;
96 sb_t *chip;
97 unsigned int valid_open_flags;
98
99 chip = substream->rmidi->private_data;
100 valid_open_flags = chip->hardware >= SB_HW_20
101 ? SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER : 0;
102 spin_lock_irqsave(&chip->open_lock, flags);
103 if (chip->open & ~valid_open_flags) {
104 spin_unlock_irqrestore(&chip->open_lock, flags);
105 return -EAGAIN;
106 }
107 chip->open |= SB_OPEN_MIDI_OUTPUT;
108 chip->midi_substream_output = substream;
109 if (!(chip->open & SB_OPEN_MIDI_INPUT)) {
110 spin_unlock_irqrestore(&chip->open_lock, flags);
111 snd_sbdsp_reset(chip); /* reset DSP */
112 if (chip->hardware >= SB_HW_20)
113 snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ);
114 } else {
115 spin_unlock_irqrestore(&chip->open_lock, flags);
116 }
117 return 0;
118}
119
120static int snd_sb8dsp_midi_input_close(snd_rawmidi_substream_t * substream)
121{
122 unsigned long flags;
123 sb_t *chip;
124
125 chip = substream->rmidi->private_data;
126 spin_lock_irqsave(&chip->open_lock, flags);
127 chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER);
128 chip->midi_substream_input = NULL;
129 if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) {
130 spin_unlock_irqrestore(&chip->open_lock, flags);
131 snd_sbdsp_reset(chip); /* reset DSP */
132 } else {
133 spin_unlock_irqrestore(&chip->open_lock, flags);
134 }
135 return 0;
136}
137
138static int snd_sb8dsp_midi_output_close(snd_rawmidi_substream_t * substream)
139{
140 unsigned long flags;
141 sb_t *chip;
142
143 chip = substream->rmidi->private_data;
144 spin_lock_irqsave(&chip->open_lock, flags);
145 chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER);
146 chip->midi_substream_output = NULL;
147 if (!(chip->open & SB_OPEN_MIDI_INPUT)) {
148 spin_unlock_irqrestore(&chip->open_lock, flags);
149 snd_sbdsp_reset(chip); /* reset DSP */
150 } else {
151 spin_unlock_irqrestore(&chip->open_lock, flags);
152 }
153 return 0;
154}
155
156static void snd_sb8dsp_midi_input_trigger(snd_rawmidi_substream_t * substream, int up)
157{
158 unsigned long flags;
159 sb_t *chip;
160
161 chip = substream->rmidi->private_data;
162 spin_lock_irqsave(&chip->open_lock, flags);
163 if (up) {
164 if (!(chip->open & SB_OPEN_MIDI_INPUT_TRIGGER)) {
165 if (chip->hardware < SB_HW_20)
166 snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ);
167 chip->open |= SB_OPEN_MIDI_INPUT_TRIGGER;
168 }
169 } else {
170 if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) {
171 if (chip->hardware < SB_HW_20)
172 snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ);
173 chip->open &= ~SB_OPEN_MIDI_INPUT_TRIGGER;
174 }
175 }
176 spin_unlock_irqrestore(&chip->open_lock, flags);
177}
178
179static void snd_sb8dsp_midi_output_write(snd_rawmidi_substream_t * substream)
180{
181 unsigned long flags;
182 sb_t *chip;
183 char byte;
184 int max = 32;
185
186 /* how big is Tx FIFO? */
187 chip = substream->rmidi->private_data;
188 while (max-- > 0) {
189 spin_lock_irqsave(&chip->open_lock, flags);
190 if (snd_rawmidi_transmit_peek(substream, &byte, 1) != 1) {
191 chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;
192 del_timer(&chip->midi_timer);
193 spin_unlock_irqrestore(&chip->open_lock, flags);
194 break;
195 }
196 if (chip->hardware >= SB_HW_20) {
197 int timeout = 8;
198 while ((inb(SBP(chip, STATUS)) & 0x80) != 0 && --timeout > 0)
199 ;
200 if (timeout == 0) {
201 /* Tx FIFO full - try again later */
202 spin_unlock_irqrestore(&chip->open_lock, flags);
203 break;
204 }
205 outb(byte, SBP(chip, WRITE));
206 } else {
207 snd_sbdsp_command(chip, SB_DSP_MIDI_OUTPUT);
208 snd_sbdsp_command(chip, byte);
209 }
210 snd_rawmidi_transmit_ack(substream, 1);
211 spin_unlock_irqrestore(&chip->open_lock, flags);
212 }
213}
214
215static void snd_sb8dsp_midi_output_timer(unsigned long data)
216{
217 snd_rawmidi_substream_t * substream = (snd_rawmidi_substream_t *) data;
218 sb_t * chip = substream->rmidi->private_data;
219 unsigned long flags;
220
221 spin_lock_irqsave(&chip->open_lock, flags);
222 chip->midi_timer.expires = 1 + jiffies;
223 add_timer(&chip->midi_timer);
224 spin_unlock_irqrestore(&chip->open_lock, flags);
225 snd_sb8dsp_midi_output_write(substream);
226}
227
228static void snd_sb8dsp_midi_output_trigger(snd_rawmidi_substream_t * substream, int up)
229{
230 unsigned long flags;
231 sb_t *chip;
232
233 chip = substream->rmidi->private_data;
234 spin_lock_irqsave(&chip->open_lock, flags);
235 if (up) {
236 if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) {
237 init_timer(&chip->midi_timer);
238 chip->midi_timer.function = snd_sb8dsp_midi_output_timer;
239 chip->midi_timer.data = (unsigned long) substream;
240 chip->midi_timer.expires = 1 + jiffies;
241 add_timer(&chip->midi_timer);
242 chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER;
243 }
244 } else {
245 if (chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER) {
246 chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER;
247 }
248 }
249 spin_unlock_irqrestore(&chip->open_lock, flags);
250
251 if (up)
252 snd_sb8dsp_midi_output_write(substream);
253}
254
255/*
256
257 */
258
259static snd_rawmidi_ops_t snd_sb8dsp_midi_output =
260{
261 .open = snd_sb8dsp_midi_output_open,
262 .close = snd_sb8dsp_midi_output_close,
263 .trigger = snd_sb8dsp_midi_output_trigger,
264};
265
266static snd_rawmidi_ops_t snd_sb8dsp_midi_input =
267{
268 .open = snd_sb8dsp_midi_input_open,
269 .close = snd_sb8dsp_midi_input_close,
270 .trigger = snd_sb8dsp_midi_input_trigger,
271};
272
273int snd_sb8dsp_midi(sb_t *chip, int device, snd_rawmidi_t ** rrawmidi)
274{
275 snd_rawmidi_t *rmidi;
276 int err;
277
278 if (rrawmidi)
279 *rrawmidi = NULL;
280 if ((err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi)) < 0)
281 return err;
282 strcpy(rmidi->name, "SB8 MIDI");
283 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_sb8dsp_midi_output);
284 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_sb8dsp_midi_input);
285 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT;
286 if (chip->hardware >= SB_HW_20)
287 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
288 rmidi->private_data = chip;
289 chip->rmidi = rmidi;
290 if (rrawmidi)
291 *rrawmidi = rmidi;
292 return 0;
293}
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
new file mode 100644
index 000000000000..5b6bde213ea0
--- /dev/null
+++ b/sound/isa/sb/sb_common.c
@@ -0,0 +1,313 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Uros Bizjak <uros@kss-loka.si>
4 *
5 * Lowlevel routines for control of Sound Blaster cards
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/driver.h>
24#include <linux/delay.h>
25#include <linux/init.h>
26#include <linux/interrupt.h>
27#include <linux/slab.h>
28#include <linux/ioport.h>
29#include <sound/core.h>
30#include <sound/sb.h>
31#include <sound/initval.h>
32
33#include <asm/io.h>
34#include <asm/dma.h>
35
36MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
37MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards");
38MODULE_LICENSE("GPL");
39
40#define BUSY_LOOPS 100000
41
42#undef IO_DEBUG
43
44int snd_sbdsp_command(sb_t *chip, unsigned char val)
45{
46 int i;
47#ifdef IO_DEBUG
48 snd_printk("command 0x%x\n", val);
49#endif
50 for (i = BUSY_LOOPS; i; i--)
51 if ((inb(SBP(chip, STATUS)) & 0x80) == 0) {
52 outb(val, SBP(chip, COMMAND));
53 return 1;
54 }
55 snd_printd("%s [0x%lx]: timeout (0x%x)\n", __FUNCTION__, chip->port, val);
56 return 0;
57}
58
59int snd_sbdsp_get_byte(sb_t *chip)
60{
61 int val;
62 int i;
63 for (i = BUSY_LOOPS; i; i--) {
64 if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
65 val = inb(SBP(chip, READ));
66#ifdef IO_DEBUG
67 snd_printk("get_byte 0x%x\n", val);
68#endif
69 return val;
70 }
71 }
72 snd_printd("%s [0x%lx]: timeout\n", __FUNCTION__, chip->port);
73 return -ENODEV;
74}
75
76int snd_sbdsp_reset(sb_t *chip)
77{
78 int i;
79
80 outb(1, SBP(chip, RESET));
81 udelay(10);
82 outb(0, SBP(chip, RESET));
83 udelay(30);
84 for (i = BUSY_LOOPS; i; i--)
85 if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
86 if (inb(SBP(chip, READ)) == 0xaa)
87 return 0;
88 else
89 break;
90 }
91 snd_printdd("%s [0x%lx] failed...\n", __FUNCTION__, chip->port);
92 return -ENODEV;
93}
94
95static int snd_sbdsp_version(sb_t * chip)
96{
97 unsigned int result = -ENODEV;
98
99 snd_sbdsp_command(chip, SB_DSP_GET_VERSION);
100 result = (short) snd_sbdsp_get_byte(chip) << 8;
101 result |= (short) snd_sbdsp_get_byte(chip);
102 return result;
103}
104
105static int snd_sbdsp_probe(sb_t * chip)
106{
107 int version;
108 int major, minor;
109 char *str;
110 unsigned long flags;
111
112 /*
113 * initialization sequence
114 */
115
116 spin_lock_irqsave(&chip->reg_lock, flags);
117 if (snd_sbdsp_reset(chip) < 0) {
118 spin_unlock_irqrestore(&chip->reg_lock, flags);
119 return -ENODEV;
120 }
121 version = snd_sbdsp_version(chip);
122 if (version < 0) {
123 spin_unlock_irqrestore(&chip->reg_lock, flags);
124 return -ENODEV;
125 }
126 spin_unlock_irqrestore(&chip->reg_lock, flags);
127 major = version >> 8;
128 minor = version & 0xff;
129 snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
130 chip->port, major, minor);
131
132 switch (chip->hardware) {
133 case SB_HW_AUTO:
134 switch (major) {
135 case 1:
136 chip->hardware = SB_HW_10;
137 str = "1.0";
138 break;
139 case 2:
140 if (minor) {
141 chip->hardware = SB_HW_201;
142 str = "2.01+";
143 } else {
144 chip->hardware = SB_HW_20;
145 str = "2.0";
146 }
147 break;
148 case 3:
149 chip->hardware = SB_HW_PRO;
150 str = "Pro";
151 break;
152 case 4:
153 chip->hardware = SB_HW_16;
154 str = "16";
155 break;
156 default:
157 snd_printk("SB [0x%lx]: unknown DSP chip version %i.%i\n",
158 chip->port, major, minor);
159 return -ENODEV;
160 }
161 break;
162 case SB_HW_ALS100:
163 str = "16 (ALS-100)";
164 break;
165 case SB_HW_ALS4000:
166 str = "16 (ALS-4000)";
167 break;
168 case SB_HW_DT019X:
169 str = "(DT019X/ALS007)";
170 break;
171 default:
172 return -ENODEV;
173 }
174 sprintf(chip->name, "Sound Blaster %s", str);
175 chip->version = (major << 8) | minor;
176 return 0;
177}
178
179static int snd_sbdsp_free(sb_t *chip)
180{
181 if (chip->res_port) {
182 release_resource(chip->res_port);
183 kfree_nocheck(chip->res_port);
184 }
185 if (chip->irq >= 0)
186 free_irq(chip->irq, (void *) chip);
187#ifdef CONFIG_ISA
188 if (chip->dma8 >= 0) {
189 disable_dma(chip->dma8);
190 free_dma(chip->dma8);
191 }
192 if (chip->dma16 >= 0 && chip->dma16 != chip->dma8) {
193 disable_dma(chip->dma16);
194 free_dma(chip->dma16);
195 }
196#endif
197 kfree(chip);
198 return 0;
199}
200
201static int snd_sbdsp_dev_free(snd_device_t *device)
202{
203 sb_t *chip = device->device_data;
204 return snd_sbdsp_free(chip);
205}
206
207int snd_sbdsp_create(snd_card_t *card,
208 unsigned long port,
209 int irq,
210 irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
211 int dma8,
212 int dma16,
213 unsigned short hardware,
214 sb_t **r_chip)
215{
216 sb_t *chip;
217 int err;
218 static snd_device_ops_t ops = {
219 .dev_free = snd_sbdsp_dev_free,
220 };
221
222 snd_assert(r_chip != NULL, return -EINVAL);
223 *r_chip = NULL;
224 chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
225 if (chip == NULL)
226 return -ENOMEM;
227 spin_lock_init(&chip->reg_lock);
228 spin_lock_init(&chip->open_lock);
229 spin_lock_init(&chip->midi_input_lock);
230 spin_lock_init(&chip->mixer_lock);
231 chip->irq = -1;
232 chip->dma8 = -1;
233 chip->dma16 = -1;
234 chip->port = port;
235
236 if (request_irq(irq, irq_handler, hardware == SB_HW_ALS4000 ?
237 SA_INTERRUPT | SA_SHIRQ : SA_INTERRUPT,
238 "SoundBlaster", (void *) chip)) {
239 snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq);
240 snd_sbdsp_free(chip);
241 return -EBUSY;
242 }
243 chip->irq = irq;
244
245 if (hardware == SB_HW_ALS4000)
246 goto __skip_allocation;
247
248 if ((chip->res_port = request_region(port, 16, "SoundBlaster")) == NULL) {
249 snd_printk(KERN_ERR "sb: can't grab port 0x%lx\n", port);
250 snd_sbdsp_free(chip);
251 return -EBUSY;
252 }
253
254#ifdef CONFIG_ISA
255 if (dma8 >= 0 && request_dma(dma8, "SoundBlaster - 8bit")) {
256 snd_printk(KERN_ERR "sb: can't grab DMA8 %d\n", dma8);
257 snd_sbdsp_free(chip);
258 return -EBUSY;
259 }
260 chip->dma8 = dma8;
261 if (dma16 >= 0) {
262 if (hardware != SB_HW_ALS100 && (dma16 < 5 || dma16 > 7)) {
263 /* no duplex */
264 dma16 = -1;
265 } else if (request_dma(dma16, "SoundBlaster - 16bit")) {
266 snd_printk(KERN_ERR "sb: can't grab DMA16 %d\n", dma16);
267 snd_sbdsp_free(chip);
268 return -EBUSY;
269 }
270 }
271 chip->dma16 = dma16;
272#endif
273
274 __skip_allocation:
275 chip->card = card;
276 chip->hardware = hardware;
277 if ((err = snd_sbdsp_probe(chip)) < 0) {
278 snd_sbdsp_free(chip);
279 return err;
280 }
281 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
282 snd_sbdsp_free(chip);
283 return err;
284 }
285 *r_chip = chip;
286 return 0;
287}
288
289EXPORT_SYMBOL(snd_sbdsp_command);
290EXPORT_SYMBOL(snd_sbdsp_get_byte);
291EXPORT_SYMBOL(snd_sbdsp_reset);
292EXPORT_SYMBOL(snd_sbdsp_create);
293/* sb_mixer.c */
294EXPORT_SYMBOL(snd_sbmixer_write);
295EXPORT_SYMBOL(snd_sbmixer_read);
296EXPORT_SYMBOL(snd_sbmixer_new);
297EXPORT_SYMBOL(snd_sbmixer_add_ctl);
298
299/*
300 * INIT part
301 */
302
303static int __init alsa_sb_common_init(void)
304{
305 return 0;
306}
307
308static void __exit alsa_sb_common_exit(void)
309{
310}
311
312module_init(alsa_sb_common_init)
313module_exit(alsa_sb_common_exit)
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
new file mode 100644
index 000000000000..cc5a2c6dec16
--- /dev/null
+++ b/sound/isa/sb/sb_mixer.c
@@ -0,0 +1,844 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Routines for Sound Blaster mixer control
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <asm/io.h>
24#include <linux/delay.h>
25#include <linux/time.h>
26#include <sound/core.h>
27#include <sound/sb.h>
28#include <sound/control.h>
29
30#undef IO_DEBUG
31
32void snd_sbmixer_write(sb_t *chip, unsigned char reg, unsigned char data)
33{
34 outb(reg, SBP(chip, MIXER_ADDR));
35 udelay(10);
36 outb(data, SBP(chip, MIXER_DATA));
37 udelay(10);
38#ifdef IO_DEBUG
39 snd_printk("mixer_write 0x%x 0x%x\n", reg, data);
40#endif
41}
42
43unsigned char snd_sbmixer_read(sb_t *chip, unsigned char reg)
44{
45 unsigned char result;
46
47 outb(reg, SBP(chip, MIXER_ADDR));
48 udelay(10);
49 result = inb(SBP(chip, MIXER_DATA));
50 udelay(10);
51#ifdef IO_DEBUG
52 snd_printk("mixer_read 0x%x 0x%x\n", reg, result);
53#endif
54 return result;
55}
56
57/*
58 * Single channel mixer element
59 */
60
61static int snd_sbmixer_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
62{
63 int mask = (kcontrol->private_value >> 24) & 0xff;
64
65 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
66 uinfo->count = 1;
67 uinfo->value.integer.min = 0;
68 uinfo->value.integer.max = mask;
69 return 0;
70}
71
72static int snd_sbmixer_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
73{
74 sb_t *sb = snd_kcontrol_chip(kcontrol);
75 unsigned long flags;
76 int reg = kcontrol->private_value & 0xff;
77 int shift = (kcontrol->private_value >> 16) & 0xff;
78 int mask = (kcontrol->private_value >> 24) & 0xff;
79 unsigned char val;
80
81 spin_lock_irqsave(&sb->mixer_lock, flags);
82 val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
83 spin_unlock_irqrestore(&sb->mixer_lock, flags);
84 ucontrol->value.integer.value[0] = val;
85 return 0;
86}
87
88static int snd_sbmixer_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
89{
90 sb_t *sb = snd_kcontrol_chip(kcontrol);
91 unsigned long flags;
92 int reg = kcontrol->private_value & 0xff;
93 int shift = (kcontrol->private_value >> 16) & 0x07;
94 int mask = (kcontrol->private_value >> 24) & 0xff;
95 int change;
96 unsigned char val, oval;
97
98 val = (ucontrol->value.integer.value[0] & mask) << shift;
99 spin_lock_irqsave(&sb->mixer_lock, flags);
100 oval = snd_sbmixer_read(sb, reg);
101 val = (oval & ~(mask << shift)) | val;
102 change = val != oval;
103 if (change)
104 snd_sbmixer_write(sb, reg, val);
105 spin_unlock_irqrestore(&sb->mixer_lock, flags);
106 return change;
107}
108
109/*
110 * Double channel mixer element
111 */
112
113static int snd_sbmixer_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
114{
115 int mask = (kcontrol->private_value >> 24) & 0xff;
116
117 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
118 uinfo->count = 2;
119 uinfo->value.integer.min = 0;
120 uinfo->value.integer.max = mask;
121 return 0;
122}
123
124static int snd_sbmixer_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
125{
126 sb_t *sb = snd_kcontrol_chip(kcontrol);
127 unsigned long flags;
128 int left_reg = kcontrol->private_value & 0xff;
129 int right_reg = (kcontrol->private_value >> 8) & 0xff;
130 int left_shift = (kcontrol->private_value >> 16) & 0x07;
131 int right_shift = (kcontrol->private_value >> 19) & 0x07;
132 int mask = (kcontrol->private_value >> 24) & 0xff;
133 unsigned char left, right;
134
135 spin_lock_irqsave(&sb->mixer_lock, flags);
136 left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
137 right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
138 spin_unlock_irqrestore(&sb->mixer_lock, flags);
139 ucontrol->value.integer.value[0] = left;
140 ucontrol->value.integer.value[1] = right;
141 return 0;
142}
143
144static int snd_sbmixer_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
145{
146 sb_t *sb = snd_kcontrol_chip(kcontrol);
147 unsigned long flags;
148 int left_reg = kcontrol->private_value & 0xff;
149 int right_reg = (kcontrol->private_value >> 8) & 0xff;
150 int left_shift = (kcontrol->private_value >> 16) & 0x07;
151 int right_shift = (kcontrol->private_value >> 19) & 0x07;
152 int mask = (kcontrol->private_value >> 24) & 0xff;
153 int change;
154 unsigned char left, right, oleft, oright;
155
156 left = (ucontrol->value.integer.value[0] & mask) << left_shift;
157 right = (ucontrol->value.integer.value[1] & mask) << right_shift;
158 spin_lock_irqsave(&sb->mixer_lock, flags);
159 if (left_reg == right_reg) {
160 oleft = snd_sbmixer_read(sb, left_reg);
161 left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
162 change = left != oleft;
163 if (change)
164 snd_sbmixer_write(sb, left_reg, left);
165 } else {
166 oleft = snd_sbmixer_read(sb, left_reg);
167 oright = snd_sbmixer_read(sb, right_reg);
168 left = (oleft & ~(mask << left_shift)) | left;
169 right = (oright & ~(mask << right_shift)) | right;
170 change = left != oleft || right != oright;
171 if (change) {
172 snd_sbmixer_write(sb, left_reg, left);
173 snd_sbmixer_write(sb, right_reg, right);
174 }
175 }
176 spin_unlock_irqrestore(&sb->mixer_lock, flags);
177 return change;
178}
179
180/*
181 * DT-019x / ALS-007 capture/input switch
182 */
183
184static int snd_dt019x_input_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
185{
186 static char *texts[5] = {
187 "CD", "Mic", "Line", "Synth", "Master"
188 };
189
190 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
191 uinfo->count = 1;
192 uinfo->value.enumerated.items = 5;
193 if (uinfo->value.enumerated.item > 4)
194 uinfo->value.enumerated.item = 4;
195 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
196 return 0;
197}
198
199static int snd_dt019x_input_sw_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
200{
201 sb_t *sb = snd_kcontrol_chip(kcontrol);
202 unsigned long flags;
203 unsigned char oval;
204
205 spin_lock_irqsave(&sb->mixer_lock, flags);
206 oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
207 spin_unlock_irqrestore(&sb->mixer_lock, flags);
208 switch (oval & 0x07) {
209 case SB_DT019X_CAP_CD:
210 ucontrol->value.enumerated.item[0] = 0;
211 break;
212 case SB_DT019X_CAP_MIC:
213 ucontrol->value.enumerated.item[0] = 1;
214 break;
215 case SB_DT019X_CAP_LINE:
216 ucontrol->value.enumerated.item[0] = 2;
217 break;
218 case SB_DT019X_CAP_MAIN:
219 ucontrol->value.enumerated.item[0] = 4;
220 break;
221 /* To record the synth on these cards you must record the main. */
222 /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
223 /* duplicate case labels if left uncommented. */
224 /* case SB_DT019X_CAP_SYNTH:
225 * ucontrol->value.enumerated.item[0] = 3;
226 * break;
227 */
228 default:
229 ucontrol->value.enumerated.item[0] = 4;
230 break;
231 }
232 return 0;
233}
234
235static int snd_dt019x_input_sw_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
236{
237 sb_t *sb = snd_kcontrol_chip(kcontrol);
238 unsigned long flags;
239 int change;
240 unsigned char nval, oval;
241
242 if (ucontrol->value.enumerated.item[0] > 4)
243 return -EINVAL;
244 switch (ucontrol->value.enumerated.item[0]) {
245 case 0:
246 nval = SB_DT019X_CAP_CD;
247 break;
248 case 1:
249 nval = SB_DT019X_CAP_MIC;
250 break;
251 case 2:
252 nval = SB_DT019X_CAP_LINE;
253 break;
254 case 3:
255 nval = SB_DT019X_CAP_SYNTH;
256 break;
257 case 4:
258 nval = SB_DT019X_CAP_MAIN;
259 break;
260 default:
261 nval = SB_DT019X_CAP_MAIN;
262 }
263 spin_lock_irqsave(&sb->mixer_lock, flags);
264 oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
265 change = nval != oval;
266 if (change)
267 snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
268 spin_unlock_irqrestore(&sb->mixer_lock, flags);
269 return change;
270}
271
272/*
273 * SBPRO input multiplexer
274 */
275
276static int snd_sb8mixer_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
277{
278 static char *texts[3] = {
279 "Mic", "CD", "Line"
280 };
281
282 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
283 uinfo->count = 1;
284 uinfo->value.enumerated.items = 3;
285 if (uinfo->value.enumerated.item > 2)
286 uinfo->value.enumerated.item = 2;
287 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
288 return 0;
289}
290
291
292static int snd_sb8mixer_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
293{
294 sb_t *sb = snd_kcontrol_chip(kcontrol);
295 unsigned long flags;
296 unsigned char oval;
297
298 spin_lock_irqsave(&sb->mixer_lock, flags);
299 oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
300 spin_unlock_irqrestore(&sb->mixer_lock, flags);
301 switch ((oval >> 0x01) & 0x03) {
302 case SB_DSP_MIXS_CD:
303 ucontrol->value.enumerated.item[0] = 1;
304 break;
305 case SB_DSP_MIXS_LINE:
306 ucontrol->value.enumerated.item[0] = 2;
307 break;
308 default:
309 ucontrol->value.enumerated.item[0] = 0;
310 break;
311 }
312 return 0;
313}
314
315static int snd_sb8mixer_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
316{
317 sb_t *sb = snd_kcontrol_chip(kcontrol);
318 unsigned long flags;
319 int change;
320 unsigned char nval, oval;
321
322 if (ucontrol->value.enumerated.item[0] > 2)
323 return -EINVAL;
324 switch (ucontrol->value.enumerated.item[0]) {
325 case 1:
326 nval = SB_DSP_MIXS_CD;
327 break;
328 case 2:
329 nval = SB_DSP_MIXS_LINE;
330 break;
331 default:
332 nval = SB_DSP_MIXS_MIC;
333 }
334 nval <<= 1;
335 spin_lock_irqsave(&sb->mixer_lock, flags);
336 oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
337 nval |= oval & ~0x06;
338 change = nval != oval;
339 if (change)
340 snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
341 spin_unlock_irqrestore(&sb->mixer_lock, flags);
342 return change;
343}
344
345/*
346 * SB16 input switch
347 */
348
349static int snd_sb16mixer_info_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
350{
351 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
352 uinfo->count = 4;
353 uinfo->value.integer.min = 0;
354 uinfo->value.integer.max = 1;
355 return 0;
356}
357
358static int snd_sb16mixer_get_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
359{
360 sb_t *sb = snd_kcontrol_chip(kcontrol);
361 unsigned long flags;
362 int reg1 = kcontrol->private_value & 0xff;
363 int reg2 = (kcontrol->private_value >> 8) & 0xff;
364 int left_shift = (kcontrol->private_value >> 16) & 0x0f;
365 int right_shift = (kcontrol->private_value >> 24) & 0x0f;
366 unsigned char val1, val2;
367
368 spin_lock_irqsave(&sb->mixer_lock, flags);
369 val1 = snd_sbmixer_read(sb, reg1);
370 val2 = snd_sbmixer_read(sb, reg2);
371 spin_unlock_irqrestore(&sb->mixer_lock, flags);
372 ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
373 ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
374 ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
375 ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
376 return 0;
377}
378
379static int snd_sb16mixer_put_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
380{
381 sb_t *sb = snd_kcontrol_chip(kcontrol);
382 unsigned long flags;
383 int reg1 = kcontrol->private_value & 0xff;
384 int reg2 = (kcontrol->private_value >> 8) & 0xff;
385 int left_shift = (kcontrol->private_value >> 16) & 0x0f;
386 int right_shift = (kcontrol->private_value >> 24) & 0x0f;
387 int change;
388 unsigned char val1, val2, oval1, oval2;
389
390 spin_lock_irqsave(&sb->mixer_lock, flags);
391 oval1 = snd_sbmixer_read(sb, reg1);
392 oval2 = snd_sbmixer_read(sb, reg2);
393 val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
394 val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
395 val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
396 val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
397 val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
398 val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
399 change = val1 != oval1 || val2 != oval2;
400 if (change) {
401 snd_sbmixer_write(sb, reg1, val1);
402 snd_sbmixer_write(sb, reg2, val2);
403 }
404 spin_unlock_irqrestore(&sb->mixer_lock, flags);
405 return change;
406}
407
408
409/*
410 */
411/*
412 */
413int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsigned long value)
414{
415 static snd_kcontrol_new_t newctls[] = {
416 [SB_MIX_SINGLE] = {
417 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
418 .info = snd_sbmixer_info_single,
419 .get = snd_sbmixer_get_single,
420 .put = snd_sbmixer_put_single,
421 },
422 [SB_MIX_DOUBLE] = {
423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
424 .info = snd_sbmixer_info_double,
425 .get = snd_sbmixer_get_double,
426 .put = snd_sbmixer_put_double,
427 },
428 [SB_MIX_INPUT_SW] = {
429 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
430 .info = snd_sb16mixer_info_input_sw,
431 .get = snd_sb16mixer_get_input_sw,
432 .put = snd_sb16mixer_put_input_sw,
433 },
434 [SB_MIX_CAPTURE_PRO] = {
435 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
436 .info = snd_sb8mixer_info_mux,
437 .get = snd_sb8mixer_get_mux,
438 .put = snd_sb8mixer_put_mux,
439 },
440 [SB_MIX_CAPTURE_DT019X] = {
441 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
442 .info = snd_dt019x_input_sw_info,
443 .get = snd_dt019x_input_sw_get,
444 .put = snd_dt019x_input_sw_put,
445 },
446 };
447 snd_kcontrol_t *ctl;
448 int err;
449
450 ctl = snd_ctl_new1(&newctls[type], chip);
451 if (! ctl)
452 return -ENOMEM;
453 strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
454 ctl->id.index = index;
455 ctl->private_value = value;
456 if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
457 snd_ctl_free_one(ctl);
458 return err;
459 }
460 return 0;
461}
462
463/*
464 * SB 2.0 specific mixer elements
465 */
466
467static struct sbmix_elem snd_sb20_ctl_master_play_vol =
468 SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
469static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
470 SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
471static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
472 SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
473static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
474 SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
475
476static struct sbmix_elem *snd_sb20_controls[] = {
477 &snd_sb20_ctl_master_play_vol,
478 &snd_sb20_ctl_pcm_play_vol,
479 &snd_sb20_ctl_synth_play_vol,
480 &snd_sb20_ctl_cd_play_vol
481};
482
483static unsigned char snd_sb20_init_values[][2] = {
484 { SB_DSP20_MASTER_DEV, 0 },
485 { SB_DSP20_FM_DEV, 0 },
486};
487
488/*
489 * SB Pro specific mixer elements
490 */
491static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
492 SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
493static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
494 SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
495static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
496 SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
497static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
498 SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
499static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
500 SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
501static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
502 SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
503static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
504 SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
505static struct sbmix_elem snd_sbpro_ctl_capture_source =
506 {
507 .name = "Capture Source",
508 .type = SB_MIX_CAPTURE_PRO
509 };
510static struct sbmix_elem snd_sbpro_ctl_capture_filter =
511 SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
512static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
513 SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
514
515static struct sbmix_elem *snd_sbpro_controls[] = {
516 &snd_sbpro_ctl_master_play_vol,
517 &snd_sbpro_ctl_pcm_play_vol,
518 &snd_sbpro_ctl_pcm_play_filter,
519 &snd_sbpro_ctl_synth_play_vol,
520 &snd_sbpro_ctl_cd_play_vol,
521 &snd_sbpro_ctl_line_play_vol,
522 &snd_sbpro_ctl_mic_play_vol,
523 &snd_sbpro_ctl_capture_source,
524 &snd_sbpro_ctl_capture_filter,
525 &snd_sbpro_ctl_capture_low_filter
526};
527
528static unsigned char snd_sbpro_init_values[][2] = {
529 { SB_DSP_MASTER_DEV, 0 },
530 { SB_DSP_PCM_DEV, 0 },
531 { SB_DSP_FM_DEV, 0 },
532};
533
534/*
535 * SB16 specific mixer elements
536 */
537static struct sbmix_elem snd_sb16_ctl_master_play_vol =
538 SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
539static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
540 SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
541static struct sbmix_elem snd_sb16_ctl_tone_bass =
542 SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
543static struct sbmix_elem snd_sb16_ctl_tone_treble =
544 SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
545static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
546 SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
547static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
548 SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
549static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
550 SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
551static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
552 SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
553static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
554 SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
555static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
556 SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
557static struct sbmix_elem snd_sb16_ctl_line_capture_route =
558 SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
559static struct sbmix_elem snd_sb16_ctl_line_play_switch =
560 SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
561static struct sbmix_elem snd_sb16_ctl_line_play_vol =
562 SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
563static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
564 SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
565static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
566 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
567static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
568 SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
569static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
570 SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
571static struct sbmix_elem snd_sb16_ctl_capture_vol =
572 SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
573static struct sbmix_elem snd_sb16_ctl_play_vol =
574 SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
575static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
576 SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
577
578static struct sbmix_elem *snd_sb16_controls[] = {
579 &snd_sb16_ctl_master_play_vol,
580 &snd_sb16_ctl_3d_enhance_switch,
581 &snd_sb16_ctl_tone_bass,
582 &snd_sb16_ctl_tone_treble,
583 &snd_sb16_ctl_pcm_play_vol,
584 &snd_sb16_ctl_synth_capture_route,
585 &snd_sb16_ctl_synth_play_vol,
586 &snd_sb16_ctl_cd_capture_route,
587 &snd_sb16_ctl_cd_play_switch,
588 &snd_sb16_ctl_cd_play_vol,
589 &snd_sb16_ctl_line_capture_route,
590 &snd_sb16_ctl_line_play_switch,
591 &snd_sb16_ctl_line_play_vol,
592 &snd_sb16_ctl_mic_capture_route,
593 &snd_sb16_ctl_mic_play_switch,
594 &snd_sb16_ctl_mic_play_vol,
595 &snd_sb16_ctl_pc_speaker_vol,
596 &snd_sb16_ctl_capture_vol,
597 &snd_sb16_ctl_play_vol,
598 &snd_sb16_ctl_auto_mic_gain
599};
600
601static unsigned char snd_sb16_init_values[][2] = {
602 { SB_DSP4_MASTER_DEV + 0, 0 },
603 { SB_DSP4_MASTER_DEV + 1, 0 },
604 { SB_DSP4_PCM_DEV + 0, 0 },
605 { SB_DSP4_PCM_DEV + 1, 0 },
606 { SB_DSP4_SYNTH_DEV + 0, 0 },
607 { SB_DSP4_SYNTH_DEV + 1, 0 },
608 { SB_DSP4_INPUT_LEFT, 0 },
609 { SB_DSP4_INPUT_RIGHT, 0 },
610 { SB_DSP4_OUTPUT_SW, 0 },
611 { SB_DSP4_SPEAKER_DEV, 0 },
612};
613
614/*
615 * DT019x specific mixer elements
616 */
617static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
618 SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
619static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
620 SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
621static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
622 SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
623static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
624 SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
625static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
626 SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
627static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
628 SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7);
629static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
630 SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
631static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
632 SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
633static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
634 SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
635static struct sbmix_elem snd_dt019x_ctl_capture_source =
636 {
637 .name = "Capture Source",
638 .type = SB_MIX_CAPTURE_DT019X
639 };
640
641static struct sbmix_elem *snd_dt019x_controls[] = {
642 &snd_dt019x_ctl_master_play_vol,
643 &snd_dt019x_ctl_pcm_play_vol,
644 &snd_dt019x_ctl_synth_play_vol,
645 &snd_dt019x_ctl_cd_play_vol,
646 &snd_dt019x_ctl_mic_play_vol,
647 &snd_dt019x_ctl_pc_speaker_vol,
648 &snd_dt019x_ctl_line_play_vol,
649 &snd_sb16_ctl_mic_play_switch,
650 &snd_sb16_ctl_cd_play_switch,
651 &snd_sb16_ctl_line_play_switch,
652 &snd_dt019x_ctl_pcm_play_switch,
653 &snd_dt019x_ctl_synth_play_switch,
654 &snd_dt019x_ctl_capture_source
655};
656
657static unsigned char snd_dt019x_init_values[][2] = {
658 { SB_DT019X_MASTER_DEV, 0 },
659 { SB_DT019X_PCM_DEV, 0 },
660 { SB_DT019X_SYNTH_DEV, 0 },
661 { SB_DT019X_CD_DEV, 0 },
662 { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */
663 { SB_DT019X_LINE_DEV, 0 },
664 { SB_DSP4_OUTPUT_SW, 0 },
665 { SB_DT019X_OUTPUT_SW2, 0 },
666 { SB_DT019X_CAPTURE_SW, 0x06 },
667};
668
669/*
670 * ALS4000 specific mixer elements
671 */
672/* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl ! */
673static struct sbmix_elem snd_als4000_ctl_mono_output_switch =
674 SB_SINGLE("Mono Output Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
675/* FIXME: mono input switch also available on DT019X ? */
676static struct sbmix_elem snd_als4000_ctl_mono_input_switch =
677 SB_SINGLE("Mono Input Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
678static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
679 SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
680static struct sbmix_elem snd_als4000_ctl_mixer_out_to_in =
681 SB_SINGLE("Mixer Out To In", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
682/* FIXME: 3D needs much more sophisticated controls, many more features ! */
683static struct sbmix_elem snd_als4000_ctl_3d_output_switch =
684 SB_SINGLE("3D Output Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
685static struct sbmix_elem snd_als4000_ctl_3d_output_ratio =
686 SB_SINGLE("3D Output Ratio", SB_ALS4000_3D_SND_FX, 0, 0x07);
687static struct sbmix_elem snd_als4000_ctl_3d_poweroff_switch =
688 SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
689static struct sbmix_elem snd_als4000_ctl_3d_delay =
690 SB_SINGLE("3D Delay", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
691#if NOT_AVAILABLE
692static struct sbmix_elem snd_als4000_ctl_fmdac =
693 SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
694static struct sbmix_elem snd_als4000_ctl_qsound =
695 SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
696#endif
697
698static struct sbmix_elem *snd_als4000_controls[] = {
699 &snd_sb16_ctl_master_play_vol,
700 &snd_dt019x_ctl_pcm_play_switch,
701 &snd_sb16_ctl_pcm_play_vol,
702 &snd_sb16_ctl_synth_capture_route,
703 &snd_dt019x_ctl_synth_play_switch,
704 &snd_sb16_ctl_synth_play_vol,
705 &snd_sb16_ctl_cd_capture_route,
706 &snd_sb16_ctl_cd_play_switch,
707 &snd_sb16_ctl_cd_play_vol,
708 &snd_sb16_ctl_line_capture_route,
709 &snd_sb16_ctl_line_play_switch,
710 &snd_sb16_ctl_line_play_vol,
711 &snd_sb16_ctl_mic_capture_route,
712 &snd_als4000_ctl_mic_20db_boost,
713 &snd_sb16_ctl_auto_mic_gain,
714 &snd_sb16_ctl_mic_play_switch,
715 &snd_sb16_ctl_mic_play_vol,
716 &snd_sb16_ctl_pc_speaker_vol,
717 &snd_sb16_ctl_capture_vol,
718 &snd_sb16_ctl_play_vol,
719 &snd_als4000_ctl_mono_output_switch,
720 &snd_als4000_ctl_mono_input_switch,
721 &snd_als4000_ctl_mixer_out_to_in,
722 &snd_als4000_ctl_3d_output_switch,
723 &snd_als4000_ctl_3d_output_ratio,
724 &snd_als4000_ctl_3d_delay,
725 &snd_als4000_ctl_3d_poweroff_switch,
726#if NOT_AVAILABLE
727 &snd_als4000_ctl_fmdac,
728 &snd_als4000_ctl_qsound,
729#endif
730};
731
732static unsigned char snd_als4000_init_values[][2] = {
733 { SB_DSP4_MASTER_DEV + 0, 0 },
734 { SB_DSP4_MASTER_DEV + 1, 0 },
735 { SB_DSP4_PCM_DEV + 0, 0 },
736 { SB_DSP4_PCM_DEV + 1, 0 },
737 { SB_DSP4_SYNTH_DEV + 0, 0 },
738 { SB_DSP4_SYNTH_DEV + 1, 0 },
739 { SB_DSP4_SPEAKER_DEV, 0 },
740 { SB_DSP4_OUTPUT_SW, 0 },
741 { SB_DSP4_INPUT_LEFT, 0 },
742 { SB_DSP4_INPUT_RIGHT, 0 },
743 { SB_DT019X_OUTPUT_SW2, 0 },
744 { SB_ALS4000_MIC_IN_GAIN, 0 },
745};
746
747
748/*
749 */
750static int snd_sbmixer_init(sb_t *chip,
751 struct sbmix_elem **controls,
752 int controls_count,
753 unsigned char map[][2],
754 int map_count,
755 char *name)
756{
757 unsigned long flags;
758 snd_card_t *card = chip->card;
759 int idx, err;
760
761 /* mixer reset */
762 spin_lock_irqsave(&chip->mixer_lock, flags);
763 snd_sbmixer_write(chip, 0x00, 0x00);
764 spin_unlock_irqrestore(&chip->mixer_lock, flags);
765
766 /* mute and zero volume channels */
767 for (idx = 0; idx < map_count; idx++) {
768 spin_lock_irqsave(&chip->mixer_lock, flags);
769 snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
770 spin_unlock_irqrestore(&chip->mixer_lock, flags);
771 }
772
773 for (idx = 0; idx < controls_count; idx++) {
774 if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
775 return err;
776 }
777 snd_component_add(card, name);
778 strcpy(card->mixername, name);
779 return 0;
780}
781
782int snd_sbmixer_new(sb_t *chip)
783{
784 snd_card_t * card;
785 int err;
786
787 snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
788
789 card = chip->card;
790
791 switch (chip->hardware) {
792 case SB_HW_10:
793 return 0; /* no mixer chip on SB1.x */
794 case SB_HW_20:
795 case SB_HW_201:
796 if ((err = snd_sbmixer_init(chip,
797 snd_sb20_controls,
798 ARRAY_SIZE(snd_sb20_controls),
799 snd_sb20_init_values,
800 ARRAY_SIZE(snd_sb20_init_values),
801 "CTL1335")) < 0)
802 return err;
803 break;
804 case SB_HW_PRO:
805 if ((err = snd_sbmixer_init(chip,
806 snd_sbpro_controls,
807 ARRAY_SIZE(snd_sbpro_controls),
808 snd_sbpro_init_values,
809 ARRAY_SIZE(snd_sbpro_init_values),
810 "CTL1345")) < 0)
811 return err;
812 break;
813 case SB_HW_16:
814 case SB_HW_ALS100:
815 if ((err = snd_sbmixer_init(chip,
816 snd_sb16_controls,
817 ARRAY_SIZE(snd_sb16_controls),
818 snd_sb16_init_values,
819 ARRAY_SIZE(snd_sb16_init_values),
820 "CTL1745")) < 0)
821 return err;
822 break;
823 case SB_HW_ALS4000:
824 if ((err = snd_sbmixer_init(chip,
825 snd_als4000_controls,
826 ARRAY_SIZE(snd_als4000_controls),
827 snd_als4000_init_values,
828 ARRAY_SIZE(snd_als4000_init_values),
829 "ALS4000")) < 0)
830 return err;
831 break;
832 case SB_HW_DT019X:
833 if ((err = snd_sbmixer_init(chip,
834 snd_dt019x_controls,
835 ARRAY_SIZE(snd_dt019x_controls),
836 snd_dt019x_init_values,
837 ARRAY_SIZE(snd_dt019x_init_values),
838 "DT019X")) < 0)
839 break;
840 default:
841 strcpy(card->mixername, "???");
842 }
843 return 0;
844}
diff --git a/sound/isa/sb/sbawe.c b/sound/isa/sb/sbawe.c
new file mode 100644
index 000000000000..2ec52a3473a2
--- /dev/null
+++ b/sound/isa/sb/sbawe.c
@@ -0,0 +1,2 @@
1#define SNDRV_SBAWE
2#include "sb16.c"