diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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/Makefile | 39 | ||||
-rw-r--r-- | sound/isa/sb/emu8000.c | 1170 | ||||
-rw-r--r-- | sound/isa/sb/emu8000_callback.c | 543 | ||||
-rw-r--r-- | sound/isa/sb/emu8000_local.h | 43 | ||||
-rw-r--r-- | sound/isa/sb/emu8000_patch.c | 303 | ||||
-rw-r--r-- | sound/isa/sb/emu8000_pcm.c | 704 | ||||
-rw-r--r-- | sound/isa/sb/emu8000_synth.c | 134 | ||||
-rw-r--r-- | sound/isa/sb/es968.c | 235 | ||||
-rw-r--r-- | sound/isa/sb/sb16.c | 678 | ||||
-rw-r--r-- | sound/isa/sb/sb16_csp.c | 1175 | ||||
-rw-r--r-- | sound/isa/sb/sb16_csp_codecs.h | 949 | ||||
-rw-r--r-- | sound/isa/sb/sb16_main.c | 916 | ||||
-rw-r--r-- | sound/isa/sb/sb8.c | 223 | ||||
-rw-r--r-- | sound/isa/sb/sb8_main.c | 565 | ||||
-rw-r--r-- | sound/isa/sb/sb8_midi.c | 293 | ||||
-rw-r--r-- | sound/isa/sb/sb_common.c | 313 | ||||
-rw-r--r-- | sound/isa/sb/sb_mixer.c | 844 | ||||
-rw-r--r-- | sound/isa/sb/sbawe.c | 2 |
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 | |||
6 | snd-sb-common-objs := sb_common.o sb_mixer.o | ||
7 | snd-sb8-dsp-objs := sb8_main.o sb8_midi.o | ||
8 | snd-sb16-dsp-objs := sb16_main.o | ||
9 | snd-sb16-csp-objs := sb16_csp.o | ||
10 | snd-sb8-objs := sb8.o | ||
11 | snd-sb16-objs := sb16.o | ||
12 | snd-sbawe-objs := sbawe.o emu8000.o | ||
13 | snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o | ||
14 | snd-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 | # | ||
22 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
23 | |||
24 | # Toplevel Module Dependency | ||
25 | obj-$(CONFIG_SND_ALS100) += snd-sb16-dsp.o snd-sb-common.o | ||
26 | obj-$(CONFIG_SND_CMI8330) += snd-sb16-dsp.o snd-sb-common.o | ||
27 | obj-$(CONFIG_SND_DT019X) += snd-sb16-dsp.o snd-sb-common.o | ||
28 | obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o | ||
29 | obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o | ||
30 | obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o | ||
31 | obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o | ||
32 | obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o | ||
33 | ifeq ($(CONFIG_SND_SB16_CSP),y) | ||
34 | obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o | ||
35 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o | ||
36 | endif | ||
37 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-emu8000-synth.o | ||
38 | |||
39 | obj-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 */ | ||
48 | void 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 */ | ||
61 | unsigned 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 */ | ||
76 | void 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 */ | ||
90 | unsigned 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 | ||
110 | snd_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 | */ | ||
134 | static void __init | ||
135 | snd_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 | */ | ||
147 | static void __init | ||
148 | snd_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 | */ | ||
161 | static int __init | ||
162 | snd_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 | */ | ||
187 | static void __init | ||
188 | init_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 | */ | ||
228 | static void __init | ||
229 | init_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 | */ | ||
240 | static 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 | |||
262 | static 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 | |||
284 | static 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 | |||
306 | static 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 | */ | ||
332 | static void __init | ||
333 | send_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 | */ | ||
354 | static void __init | ||
355 | init_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 | */ | ||
380 | static void __init | ||
381 | size_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 | ||
461 | snd_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 | */ | ||
506 | static void __init | ||
507 | snd_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 | |||
556 | static 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 | |||
571 | static 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 | ||
591 | snd_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 | |||
634 | typedef 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 */ | ||
643 | static char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS]; | ||
644 | static 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 | ||
656 | snd_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 | ||
671 | snd_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 | |||
705 | typedef 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 | */ | ||
712 | static char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS]; | ||
713 | static 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 | |||
764 | enum { 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 | |||
770 | static 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 | ||
783 | snd_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 | ||
799 | snd_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 | */ | ||
825 | static 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 | |||
834 | static 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 | |||
842 | static 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 | |||
863 | static 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 | |||
873 | static 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 | */ | ||
886 | static 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 | |||
895 | static 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 | |||
903 | static 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 | |||
930 | static 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 | |||
940 | static 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 | */ | ||
953 | static 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 | |||
962 | static 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 | |||
970 | static 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 | |||
992 | static 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 | |||
1002 | static 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 | |||
1013 | static 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 | */ | ||
1025 | static int __init | ||
1026 | snd_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 | */ | ||
1055 | static 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 | */ | ||
1075 | static 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 | */ | ||
1084 | int __init | ||
1085 | snd_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 | |||
1160 | EXPORT_SYMBOL(snd_emu8000_poke); | ||
1161 | EXPORT_SYMBOL(snd_emu8000_peek); | ||
1162 | EXPORT_SYMBOL(snd_emu8000_poke_dw); | ||
1163 | EXPORT_SYMBOL(snd_emu8000_peek_dw); | ||
1164 | EXPORT_SYMBOL(snd_emu8000_dma_chan); | ||
1165 | EXPORT_SYMBOL(snd_emu8000_init_fm); | ||
1166 | EXPORT_SYMBOL(snd_emu8000_load_chorus_fx); | ||
1167 | EXPORT_SYMBOL(snd_emu8000_load_reverb_fx); | ||
1168 | EXPORT_SYMBOL(snd_emu8000_update_chorus_mode); | ||
1169 | EXPORT_SYMBOL(snd_emu8000_update_reverb_mode); | ||
1170 | EXPORT_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 | */ | ||
28 | static snd_emux_voice_t *get_voice(snd_emux_t *emu, snd_emux_port_t *port); | ||
29 | static int start_voice(snd_emux_voice_t *vp); | ||
30 | static void trigger_voice(snd_emux_voice_t *vp); | ||
31 | static void release_voice(snd_emux_voice_t *vp); | ||
32 | static void update_voice(snd_emux_voice_t *vp, int update); | ||
33 | static void reset_voice(snd_emux_t *emu, int ch); | ||
34 | static void terminate_voice(snd_emux_voice_t *vp); | ||
35 | static void sysex(snd_emux_t *emu, char *buf, int len, int parsed, snd_midi_channel_set_t *chset); | ||
36 | #ifdef CONFIG_SND_SEQUENCER_OSS | ||
37 | static int oss_ioctl(snd_emux_t *emu, int cmd, int p1, int p2); | ||
38 | #endif | ||
39 | static int load_fx(snd_emux_t *emu, int type, int mode, const void __user *buf, long len); | ||
40 | |||
41 | static void set_pitch(emu8000_t *hw, snd_emux_voice_t *vp); | ||
42 | static void set_volume(emu8000_t *hw, snd_emux_voice_t *vp); | ||
43 | static void set_pan(emu8000_t *hw, snd_emux_voice_t *vp); | ||
44 | static void set_fmmod(emu8000_t *hw, snd_emux_voice_t *vp); | ||
45 | static void set_tremfreq(emu8000_t *hw, snd_emux_voice_t *vp); | ||
46 | static void set_fm2frq2(emu8000_t *hw, snd_emux_voice_t *vp); | ||
47 | static void set_filterQ(emu8000_t *hw, snd_emux_voice_t *vp); | ||
48 | static 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 | */ | ||
61 | static 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 | |||
80 | void | ||
81 | snd_emu8000_ops_setup(emu8000_t *hw) | ||
82 | { | ||
83 | hw->emu->ops = emu8000_ops; | ||
84 | } | ||
85 | |||
86 | |||
87 | |||
88 | /* | ||
89 | * Terminate a voice | ||
90 | */ | ||
91 | static void | ||
92 | release_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 | */ | ||
107 | static void | ||
108 | terminate_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 | */ | ||
119 | static void | ||
120 | update_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 | */ | ||
152 | static snd_emux_voice_t * | ||
153 | get_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 | */ | ||
229 | static int | ||
230 | start_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 | */ | ||
309 | static void | ||
310 | trigger_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 | */ | ||
331 | static void | ||
332 | reset_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 | */ | ||
344 | static void | ||
345 | set_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 | */ | ||
353 | static void | ||
354 | set_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 | */ | ||
367 | static void | ||
368 | set_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 | |||
378 | static void | ||
379 | set_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 */ | ||
396 | static void | ||
397 | set_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 */ | ||
403 | static void | ||
404 | set_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 */ | ||
421 | static void | ||
422 | set_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 | */ | ||
433 | static void | ||
434 | snd_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 | */ | ||
455 | static void | ||
456 | sysex(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 | */ | ||
480 | static int | ||
481 | oss_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 | |||
525 | static int | ||
526 | load_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 */ | ||
33 | int snd_emu8000_sample_new(snd_emux_t *rec, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr, const void __user *data, long count); | ||
34 | int snd_emu8000_sample_free(snd_emux_t *rec, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr); | ||
35 | void snd_emu8000_sample_reset(snd_emux_t *rec); | ||
36 | |||
37 | /* emu8000_callback.c */ | ||
38 | void snd_emu8000_ops_setup(emu8000_t *emu); | ||
39 | |||
40 | /* emu8000_pcm.c */ | ||
41 | int 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 | |||
26 | static int emu8000_reset_addr = 0; | ||
27 | module_param(emu8000_reset_addr, int, 0444); | ||
28 | MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)"); | ||
29 | |||
30 | |||
31 | /* | ||
32 | * Open up channels. | ||
33 | */ | ||
34 | static int | ||
35 | snd_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 | */ | ||
61 | static void | ||
62 | snd_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 | */ | ||
84 | static unsigned short | ||
85 | read_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 | */ | ||
108 | static void | ||
109 | snd_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 | */ | ||
131 | inline static void | ||
132 | write_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 | */ | ||
147 | int | ||
148 | snd_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 | */ | ||
285 | int | ||
286 | snd_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 | */ | ||
299 | void | ||
300 | snd_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 | |||
49 | typedef struct snd_emu8k_pcm emu8k_pcm_t; | ||
50 | |||
51 | struct 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 | */ | ||
79 | static int | ||
80 | emu8k_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 | */ | ||
115 | static void | ||
116 | snd_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 | */ | ||
131 | static void | ||
132 | emu8k_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 | |||
151 | static 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 | |||
160 | static 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 | */ | ||
184 | static 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 | */ | ||
196 | static 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 | */ | ||
230 | static 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 | |||
260 | static 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 | */ | ||
271 | static 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 | */ | ||
285 | static 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 | */ | ||
338 | static 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 | */ | ||
374 | static 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 | |||
390 | static 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() \ | ||
423 | do { \ | ||
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 */ | ||
432 | static 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 | |||
446 | static 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 */ | ||
473 | static 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 | |||
484 | static 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 | */ | ||
512 | static 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 | |||
543 | static 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 | */ | ||
571 | static 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 | */ | ||
596 | static 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 | */ | ||
614 | static 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 | |||
660 | static 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 | |||
669 | static 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 | |||
683 | static void snd_emu8000_pcm_free(snd_pcm_t *pcm) | ||
684 | { | ||
685 | emu8000_t *emu = pcm->private_data; | ||
686 | emu->pcm = NULL; | ||
687 | } | ||
688 | |||
689 | int 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 | |||
27 | MODULE_AUTHOR("Takashi Iwai, Steve Ratcliffe"); | ||
28 | MODULE_DESCRIPTION("Emu8000 synth plug-in routine"); | ||
29 | MODULE_LICENSE("GPL"); | ||
30 | |||
31 | /*----------------------------------------------------------------*/ | ||
32 | |||
33 | /* | ||
34 | * create a new hardware dependent device for Emu8000 | ||
35 | */ | ||
36 | static 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 | */ | ||
95 | static 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 | |||
118 | static 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 | |||
128 | static void __exit alsa_emu8000_exit(void) | ||
129 | { | ||
130 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU8000); | ||
131 | } | ||
132 | |||
133 | module_init(alsa_emu8000_init) | ||
134 | module_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 | |||
34 | MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); | ||
35 | MODULE_DESCRIPTION("ESS AudioDrive ES968"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | MODULE_SUPPORTED_DEVICE("{{ESS,AudioDrive ES968}}"); | ||
38 | |||
39 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
40 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
41 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ | ||
42 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
43 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */ | ||
44 | static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ | ||
45 | |||
46 | module_param_array(index, int, NULL, 0444); | ||
47 | MODULE_PARM_DESC(index, "Index value for es968 based soundcard."); | ||
48 | module_param_array(id, charp, NULL, 0444); | ||
49 | MODULE_PARM_DESC(id, "ID string for es968 based soundcard."); | ||
50 | module_param_array(enable, bool, NULL, 0444); | ||
51 | MODULE_PARM_DESC(enable, "Enable es968 based soundcard."); | ||
52 | module_param_array(port, long, NULL, 0444); | ||
53 | MODULE_PARM_DESC(port, "Port # for es968 driver."); | ||
54 | module_param_array(irq, int, NULL, 0444); | ||
55 | MODULE_PARM_DESC(irq, "IRQ # for es968 driver."); | ||
56 | module_param_array(dma8, int, NULL, 0444); | ||
57 | MODULE_PARM_DESC(dma8, "8-bit DMA # for es968 driver."); | ||
58 | |||
59 | struct snd_card_es968 { | ||
60 | struct pnp_dev *dev; | ||
61 | }; | ||
62 | |||
63 | static struct pnp_card_device_id snd_es968_pnpids[] = { | ||
64 | { .id = "ESS0968", .devs = { { "@@@0968" }, } }, | ||
65 | { .id = "", } /* end */ | ||
66 | }; | ||
67 | |||
68 | MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids); | ||
69 | |||
70 | #define DRIVER_NAME "snd-card-es968" | ||
71 | |||
72 | static 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 | |||
84 | static 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 | |||
126 | static 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 | |||
183 | static 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 | |||
201 | static 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 | |||
209 | static 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 | |||
217 | static 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 | |||
229 | static void __exit alsa_card_es968_exit(void) | ||
230 | { | ||
231 | pnp_unregister_card_driver(&es968_pnpc_driver); | ||
232 | } | ||
233 | |||
234 | module_init(alsa_card_es968_init) | ||
235 | module_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 | |||
46 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | #ifndef SNDRV_SBAWE | ||
49 | MODULE_DESCRIPTION("Sound Blaster 16"); | ||
50 | MODULE_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 | ||
56 | MODULE_DESCRIPTION("Sound Blaster AWE"); | ||
57 | MODULE_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 | |||
70 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
71 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
72 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ | ||
73 | #ifdef CONFIG_PNP | ||
74 | static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; | ||
75 | #endif | ||
76 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */ | ||
77 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x330,0x300 */ | ||
78 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
79 | #ifdef SNDRV_SBAWE_EMU8000 | ||
80 | static long awe_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
81 | #endif | ||
82 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */ | ||
83 | static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */ | ||
84 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 5,6,7 */ | ||
85 | static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; | ||
86 | #ifdef CONFIG_SND_SB16_CSP | ||
87 | static int csp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | ||
88 | #endif | ||
89 | #ifdef SNDRV_SBAWE_EMU8000 | ||
90 | static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; | ||
91 | #endif | ||
92 | |||
93 | module_param_array(index, int, NULL, 0444); | ||
94 | MODULE_PARM_DESC(index, "Index value for SoundBlaster 16 soundcard."); | ||
95 | module_param_array(id, charp, NULL, 0444); | ||
96 | MODULE_PARM_DESC(id, "ID string for SoundBlaster 16 soundcard."); | ||
97 | module_param_array(enable, bool, NULL, 0444); | ||
98 | MODULE_PARM_DESC(enable, "Enable SoundBlaster 16 soundcard."); | ||
99 | #ifdef CONFIG_PNP | ||
100 | module_param_array(isapnp, bool, NULL, 0444); | ||
101 | MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); | ||
102 | #endif | ||
103 | module_param_array(port, long, NULL, 0444); | ||
104 | MODULE_PARM_DESC(port, "Port # for SB16 driver."); | ||
105 | module_param_array(mpu_port, long, NULL, 0444); | ||
106 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for SB16 driver."); | ||
107 | module_param_array(fm_port, long, NULL, 0444); | ||
108 | MODULE_PARM_DESC(fm_port, "FM port # for SB16 PnP driver."); | ||
109 | #ifdef SNDRV_SBAWE_EMU8000 | ||
110 | module_param_array(awe_port, long, NULL, 0444); | ||
111 | MODULE_PARM_DESC(awe_port, "AWE port # for SB16 PnP driver."); | ||
112 | #endif | ||
113 | module_param_array(irq, int, NULL, 0444); | ||
114 | MODULE_PARM_DESC(irq, "IRQ # for SB16 driver."); | ||
115 | module_param_array(dma8, int, NULL, 0444); | ||
116 | MODULE_PARM_DESC(dma8, "8-bit DMA # for SB16 driver."); | ||
117 | module_param_array(dma16, int, NULL, 0444); | ||
118 | MODULE_PARM_DESC(dma16, "16-bit DMA # for SB16 driver."); | ||
119 | module_param_array(mic_agc, int, NULL, 0444); | ||
120 | MODULE_PARM_DESC(mic_agc, "Mic Auto-Gain-Control switch."); | ||
121 | #ifdef CONFIG_SND_SB16_CSP | ||
122 | module_param_array(csp, int, NULL, 0444); | ||
123 | MODULE_PARM_DESC(csp, "ASP/CSP chip support."); | ||
124 | #endif | ||
125 | #ifdef SNDRV_SBAWE_EMU8000 | ||
126 | module_param_array(seq_ports, int, NULL, 0444); | ||
127 | MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth."); | ||
128 | #endif | ||
129 | |||
130 | struct 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 | |||
141 | static snd_card_t *snd_sb16_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
142 | |||
143 | #ifdef CONFIG_PNP | ||
144 | |||
145 | static 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 | |||
238 | MODULE_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 | |||
250 | static 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 | |||
342 | static 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 | |||
354 | static 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 | |||
555 | static 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 | |||
578 | static 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 | |||
597 | static 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 | |||
605 | static 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 | |||
615 | static 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 | |||
665 | static 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 | |||
677 | module_init(alsa_card_sb16_init) | ||
678 | module_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 | |||
36 | MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>"); | ||
37 | MODULE_DESCRIPTION("ALSA driver for SB16 Creative Signal Processor"); | ||
38 | MODULE_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 | */ | ||
59 | typedef struct riff_header { | ||
60 | __u32 name; | ||
61 | __u32 len; | ||
62 | } riff_header_t; | ||
63 | |||
64 | typedef 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 | */ | ||
77 | static void snd_sb_csp_free(snd_hwdep_t *hw); | ||
78 | static int snd_sb_csp_open(snd_hwdep_t * hw, struct file *file); | ||
79 | static int snd_sb_csp_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg); | ||
80 | static int snd_sb_csp_release(snd_hwdep_t * hw, struct file *file); | ||
81 | |||
82 | static int csp_detect(sb_t *chip, int *version); | ||
83 | static int set_codec_parameter(sb_t *chip, unsigned char par, unsigned char val); | ||
84 | static int set_register(sb_t *chip, unsigned char reg, unsigned char val); | ||
85 | static int read_register(sb_t *chip, unsigned char reg); | ||
86 | static int set_mode_register(sb_t *chip, unsigned char mode); | ||
87 | static int get_version(sb_t *chip); | ||
88 | |||
89 | static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t __user * code); | ||
90 | static int snd_sb_csp_unload(snd_sb_csp_t * p); | ||
91 | static int snd_sb_csp_load_user(snd_sb_csp_t * p, const unsigned char __user *buf, int size, int load_flags); | ||
92 | static int snd_sb_csp_autoload(snd_sb_csp_t * p, int pcm_sfmt, int play_rec_mode); | ||
93 | static int snd_sb_csp_check_version(snd_sb_csp_t * p); | ||
94 | |||
95 | static int snd_sb_csp_use(snd_sb_csp_t * p); | ||
96 | static int snd_sb_csp_unuse(snd_sb_csp_t * p); | ||
97 | static int snd_sb_csp_start(snd_sb_csp_t * p, int sample_width, int channels); | ||
98 | static int snd_sb_csp_stop(snd_sb_csp_t * p); | ||
99 | static int snd_sb_csp_pause(snd_sb_csp_t * p); | ||
100 | static int snd_sb_csp_restart(snd_sb_csp_t * p); | ||
101 | |||
102 | static int snd_sb_qsound_build(snd_sb_csp_t * p); | ||
103 | static void snd_sb_qsound_destroy(snd_sb_csp_t * p); | ||
104 | static int snd_sb_csp_qsound_transfer(snd_sb_csp_t * p); | ||
105 | |||
106 | static int init_proc_entry(snd_sb_csp_t * p, int device); | ||
107 | static 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 | */ | ||
112 | int 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 | */ | ||
163 | static 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 | */ | ||
178 | static 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 | */ | ||
187 | static 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 | */ | ||
256 | static 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 | */ | ||
267 | static 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 | */ | ||
284 | static 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 | */ | ||
297 | static 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 | */ | ||
454 | static 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 | */ | ||
477 | static 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 | */ | ||
490 | static 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 | */ | ||
507 | static 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 | */ | ||
521 | static 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 | */ | ||
534 | static 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 | */ | ||
547 | static 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 | */ | ||
584 | static 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 | */ | ||
598 | static 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 | */ | ||
610 | static 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 | |||
676 | static 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 | */ | ||
696 | static 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 | */ | ||
768 | static 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 | */ | ||
847 | static 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 | */ | ||
888 | static 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 | */ | ||
908 | static 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 | |||
931 | static 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 | |||
940 | static 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 | |||
948 | static 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 | |||
963 | static 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 | |||
972 | static 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 | |||
984 | static 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 | |||
1006 | static 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 | |||
1014 | static 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 | |||
1022 | static 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 | |||
1047 | static 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 | */ | ||
1073 | static 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 | */ | ||
1098 | static 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 | |||
1108 | static 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 | |||
1159 | EXPORT_SYMBOL(snd_sb_csp_new); | ||
1160 | |||
1161 | /* | ||
1162 | * INIT part | ||
1163 | */ | ||
1164 | |||
1165 | static int __init alsa_sb_csp_init(void) | ||
1166 | { | ||
1167 | return 0; | ||
1168 | } | ||
1169 | |||
1170 | static void __exit alsa_sb_csp_exit(void) | ||
1171 | { | ||
1172 | } | ||
1173 | |||
1174 | module_init(alsa_sb_csp_init) | ||
1175 | module_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 | |||
21 | static 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 | |||
181 | static 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 | |||
348 | static 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 | |||
480 | static 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 | |||
717 | static 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 | |||
48 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | ||
49 | MODULE_DESCRIPTION("Routines for control of 16-bit SoundBlaster cards and clones"); | ||
50 | MODULE_LICENSE("GPL"); | ||
51 | |||
52 | #ifdef CONFIG_SND_SB16_CSP | ||
53 | static 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 | |||
101 | static 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 | |||
139 | static 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 | |||
152 | static 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 | |||
171 | static 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 | |||
183 | static 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 | |||
202 | static 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 | |||
224 | static 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 | |||
247 | static 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 | |||
253 | static int snd_sb16_hw_free(snd_pcm_substream_t * substream) | ||
254 | { | ||
255 | snd_pcm_lib_free_pages(substream); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static 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 | |||
301 | static 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 | |||
327 | static 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 | |||
368 | static 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 | |||
394 | irqreturn_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 | |||
446 | static 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 | |||
457 | static 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 | |||
472 | static 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 | |||
490 | static 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 | |||
512 | static 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 | |||
569 | static 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 | |||
582 | static 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 | |||
639 | static 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 | |||
656 | static 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 | |||
674 | static 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 | |||
688 | static 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 | |||
703 | static 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 | |||
714 | static 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 | |||
731 | static 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 | |||
743 | int 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 | |||
832 | static 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 | |||
843 | static 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 | |||
854 | static void snd_sb16dsp_pcm_free(snd_pcm_t *pcm) | ||
855 | { | ||
856 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
857 | } | ||
858 | |||
859 | int 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 | |||
891 | const 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 | |||
897 | EXPORT_SYMBOL(snd_sb16dsp_pcm); | ||
898 | EXPORT_SYMBOL(snd_sb16dsp_get_pcm_ops); | ||
899 | EXPORT_SYMBOL(snd_sb16dsp_configure); | ||
900 | EXPORT_SYMBOL(snd_sb16dsp_interrupt); | ||
901 | |||
902 | /* | ||
903 | * INIT part | ||
904 | */ | ||
905 | |||
906 | static int __init alsa_sb16_init(void) | ||
907 | { | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static void __exit alsa_sb16_exit(void) | ||
912 | { | ||
913 | } | ||
914 | |||
915 | module_init(alsa_sb16_init) | ||
916 | module_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 | |||
33 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | ||
34 | MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}"); | ||
37 | |||
38 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
39 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
40 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
41 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */ | ||
42 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */ | ||
43 | static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3 */ | ||
44 | |||
45 | module_param_array(index, int, NULL, 0444); | ||
46 | MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard."); | ||
47 | module_param_array(id, charp, NULL, 0444); | ||
48 | MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard."); | ||
49 | module_param_array(enable, bool, NULL, 0444); | ||
50 | MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard."); | ||
51 | module_param_array(port, long, NULL, 0444); | ||
52 | MODULE_PARM_DESC(port, "Port # for SB8 driver."); | ||
53 | module_param_array(irq, int, NULL, 0444); | ||
54 | MODULE_PARM_DESC(irq, "IRQ # for SB8 driver."); | ||
55 | module_param_array(dma8, int, NULL, 0444); | ||
56 | MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver."); | ||
57 | |||
58 | struct snd_sb8 { | ||
59 | struct resource *fm_res; /* used to block FM i/o region for legacy cards */ | ||
60 | }; | ||
61 | |||
62 | static snd_card_t *snd_sb8_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
63 | |||
64 | static 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 | |||
75 | static 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 | |||
87 | static 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 | |||
173 | static 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 | |||
190 | static 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 | |||
214 | static 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 | |||
222 | module_init(alsa_card_sb8_init) | ||
223 | module_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 | |||
41 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Uros Bizjak <uros@kss-loka.si>"); | ||
42 | MODULE_DESCRIPTION("Routines for control of 8-bit SoundBlaster cards and clones"); | ||
43 | MODULE_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 | |||
49 | static ratnum_t clock = { | ||
50 | .num = SB8_CLOCK, | ||
51 | .den_min = 1, | ||
52 | .den_max = 256, | ||
53 | .den_step = 1, | ||
54 | }; | ||
55 | |||
56 | static snd_pcm_hw_constraint_ratnums_t hw_constraints_clock = { | ||
57 | .nrats = 1, | ||
58 | .rats = &clock, | ||
59 | }; | ||
60 | |||
61 | static 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 | |||
76 | static 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 | |||
93 | static 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 | |||
104 | static 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 | |||
181 | static 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 | |||
218 | static 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 | |||
224 | static int snd_sb8_hw_free(snd_pcm_substream_t * substream) | ||
225 | { | ||
226 | snd_pcm_lib_free_pages(substream); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static 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 | |||
293 | static 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 | |||
332 | irqreturn_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 | |||
360 | static 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 | |||
371 | static 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 | |||
386 | static 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 | |||
405 | static 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 | |||
428 | static 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 | |||
474 | static 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 | |||
491 | static 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 | |||
502 | static 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 | |||
513 | static void snd_sb8dsp_pcm_free(snd_pcm_t *pcm) | ||
514 | { | ||
515 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
516 | } | ||
517 | |||
518 | int 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 | |||
545 | EXPORT_SYMBOL(snd_sb8dsp_pcm); | ||
546 | EXPORT_SYMBOL(snd_sb8dsp_interrupt); | ||
547 | /* sb8_midi.c */ | ||
548 | EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt); | ||
549 | EXPORT_SYMBOL(snd_sb8dsp_midi); | ||
550 | |||
551 | /* | ||
552 | * INIT part | ||
553 | */ | ||
554 | |||
555 | static int __init alsa_sb8_init(void) | ||
556 | { | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static void __exit alsa_sb8_exit(void) | ||
561 | { | ||
562 | } | ||
563 | |||
564 | module_init(alsa_sb8_init) | ||
565 | module_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 | |||
39 | irqreturn_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 | |||
66 | static 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 | |||
93 | static 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 | |||
120 | static 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 | |||
138 | static 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 | |||
156 | static 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 | |||
179 | static 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 | |||
215 | static 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 | |||
228 | static 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 | |||
259 | static 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 | |||
266 | static 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 | |||
273 | int 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 | |||
36 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | ||
37 | MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards"); | ||
38 | MODULE_LICENSE("GPL"); | ||
39 | |||
40 | #define BUSY_LOOPS 100000 | ||
41 | |||
42 | #undef IO_DEBUG | ||
43 | |||
44 | int 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 | |||
59 | int 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 | |||
76 | int 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 | |||
95 | static 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 | |||
105 | static 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 | |||
179 | static 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 | |||
201 | static 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 | |||
207 | int 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 | |||
289 | EXPORT_SYMBOL(snd_sbdsp_command); | ||
290 | EXPORT_SYMBOL(snd_sbdsp_get_byte); | ||
291 | EXPORT_SYMBOL(snd_sbdsp_reset); | ||
292 | EXPORT_SYMBOL(snd_sbdsp_create); | ||
293 | /* sb_mixer.c */ | ||
294 | EXPORT_SYMBOL(snd_sbmixer_write); | ||
295 | EXPORT_SYMBOL(snd_sbmixer_read); | ||
296 | EXPORT_SYMBOL(snd_sbmixer_new); | ||
297 | EXPORT_SYMBOL(snd_sbmixer_add_ctl); | ||
298 | |||
299 | /* | ||
300 | * INIT part | ||
301 | */ | ||
302 | |||
303 | static int __init alsa_sb_common_init(void) | ||
304 | { | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static void __exit alsa_sb_common_exit(void) | ||
309 | { | ||
310 | } | ||
311 | |||
312 | module_init(alsa_sb_common_init) | ||
313 | module_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 | |||
32 | void 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 | |||
43 | unsigned 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 | |||
61 | static 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 | |||
72 | static 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 | |||
88 | static 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 | |||
113 | static 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 | |||
124 | static 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 | |||
144 | static 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 | |||
184 | static 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 | |||
199 | static 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 | |||
235 | static 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 | |||
276 | static 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 | |||
292 | static 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 | |||
315 | static 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 | |||
349 | static 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 | |||
358 | static 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 | |||
379 | static 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 | */ | ||
413 | int 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 | |||
467 | static struct sbmix_elem snd_sb20_ctl_master_play_vol = | ||
468 | SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7); | ||
469 | static struct sbmix_elem snd_sb20_ctl_pcm_play_vol = | ||
470 | SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3); | ||
471 | static struct sbmix_elem snd_sb20_ctl_synth_play_vol = | ||
472 | SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7); | ||
473 | static struct sbmix_elem snd_sb20_ctl_cd_play_vol = | ||
474 | SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7); | ||
475 | |||
476 | static 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 | |||
483 | static 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 | */ | ||
491 | static 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); | ||
493 | static 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); | ||
495 | static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter = | ||
496 | SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1); | ||
497 | static 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); | ||
499 | static 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); | ||
501 | static 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); | ||
503 | static struct sbmix_elem snd_sbpro_ctl_mic_play_vol = | ||
504 | SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3); | ||
505 | static struct sbmix_elem snd_sbpro_ctl_capture_source = | ||
506 | { | ||
507 | .name = "Capture Source", | ||
508 | .type = SB_MIX_CAPTURE_PRO | ||
509 | }; | ||
510 | static struct sbmix_elem snd_sbpro_ctl_capture_filter = | ||
511 | SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1); | ||
512 | static struct sbmix_elem snd_sbpro_ctl_capture_low_filter = | ||
513 | SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1); | ||
514 | |||
515 | static 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 | |||
528 | static 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 | */ | ||
537 | static 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); | ||
539 | static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch = | ||
540 | SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1); | ||
541 | static 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); | ||
543 | static 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); | ||
545 | static 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); | ||
547 | static 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); | ||
549 | static 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); | ||
551 | static 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); | ||
553 | static 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); | ||
555 | static 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); | ||
557 | static 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); | ||
559 | static 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); | ||
561 | static 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); | ||
563 | static 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); | ||
565 | static struct sbmix_elem snd_sb16_ctl_mic_play_switch = | ||
566 | SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1); | ||
567 | static struct sbmix_elem snd_sb16_ctl_mic_play_vol = | ||
568 | SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); | ||
569 | static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = | ||
570 | SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3); | ||
571 | static 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); | ||
573 | static 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); | ||
575 | static struct sbmix_elem snd_sb16_ctl_auto_mic_gain = | ||
576 | SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1); | ||
577 | |||
578 | static 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 | |||
601 | static 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 | */ | ||
617 | static 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); | ||
619 | static 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); | ||
621 | static 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); | ||
623 | static 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); | ||
625 | static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = | ||
626 | SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); | ||
627 | static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = | ||
628 | SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7); | ||
629 | static 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); | ||
631 | static 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); | ||
633 | static 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); | ||
635 | static struct sbmix_elem snd_dt019x_ctl_capture_source = | ||
636 | { | ||
637 | .name = "Capture Source", | ||
638 | .type = SB_MIX_CAPTURE_DT019X | ||
639 | }; | ||
640 | |||
641 | static 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 | |||
657 | static 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 ! */ | ||
673 | static 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 ? */ | ||
676 | static struct sbmix_elem snd_als4000_ctl_mono_input_switch = | ||
677 | SB_SINGLE("Mono Input Switch", SB_DT019X_OUTPUT_SW2, 0, 1); | ||
678 | static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = | ||
679 | SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); | ||
680 | static 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 ! */ | ||
683 | static struct sbmix_elem snd_als4000_ctl_3d_output_switch = | ||
684 | SB_SINGLE("3D Output Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); | ||
685 | static struct sbmix_elem snd_als4000_ctl_3d_output_ratio = | ||
686 | SB_SINGLE("3D Output Ratio", SB_ALS4000_3D_SND_FX, 0, 0x07); | ||
687 | static struct sbmix_elem snd_als4000_ctl_3d_poweroff_switch = | ||
688 | SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); | ||
689 | static struct sbmix_elem snd_als4000_ctl_3d_delay = | ||
690 | SB_SINGLE("3D Delay", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); | ||
691 | #if NOT_AVAILABLE | ||
692 | static struct sbmix_elem snd_als4000_ctl_fmdac = | ||
693 | SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); | ||
694 | static struct sbmix_elem snd_als4000_ctl_qsound = | ||
695 | SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); | ||
696 | #endif | ||
697 | |||
698 | static 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 | |||
732 | static 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 | */ | ||
750 | static 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 | |||
782 | int 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" | ||