1 |
1626 |
jcastillo |
/*
|
2 |
|
|
sound/aedsp16.c
|
3 |
|
|
|
4 |
|
|
Audio Excel DSP 16 software configuration routines
|
5 |
|
|
|
6 |
|
|
Copyright (C) 1995 Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it)
|
7 |
|
|
|
8 |
|
|
Redistribution and use in source and binary forms, with or without
|
9 |
|
|
modification, are permitted provided that the following conditions are
|
10 |
|
|
met: 1. Redistributions of source code must retain the above copyright
|
11 |
|
|
notice, this list of conditions and the following disclaimer. 2.
|
12 |
|
|
Redistributions in binary form must reproduce the above copyright notice,
|
13 |
|
|
this list of conditions and the following disclaimer in the documentation
|
14 |
|
|
and/or other materials provided with the distribution.
|
15 |
|
|
|
16 |
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
17 |
|
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 |
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19 |
|
|
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
20 |
|
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
21 |
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
22 |
|
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
23 |
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
24 |
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
25 |
|
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
26 |
|
|
SUCH DAMAGE.
|
27 |
|
|
*/
|
28 |
|
|
/*
|
29 |
|
|
* Include the main voxware header file. It include all the os/voxware/etc
|
30 |
|
|
* headers needed by this source.
|
31 |
|
|
*/
|
32 |
|
|
#include <linux/config.h>
|
33 |
|
|
#include "sound_config.h"
|
34 |
|
|
|
35 |
|
|
#ifndef AEDSP16_BASE
|
36 |
|
|
#undef CONFIG_AEDSP16
|
37 |
|
|
#endif
|
38 |
|
|
|
39 |
|
|
#if defined(CONFIG_AEDSP16)
|
40 |
|
|
/*
|
41 |
|
|
|
42 |
|
|
READ THIS
|
43 |
|
|
|
44 |
|
|
This module is intended for Audio Excel DSP 16 Sound Card.
|
45 |
|
|
|
46 |
|
|
Audio Excel DSP 16 is an SB pro II, Microsoft Sound System
|
47 |
|
|
and MPU-401 compatible card.
|
48 |
|
|
It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq),
|
49 |
|
|
so before this module, the only way to configure the DSP under linux was
|
50 |
|
|
boot the MS-BAU loading the sound.sys device driver (this driver soft-
|
51 |
|
|
configure the sound board hardware by massaging someone of its registers),
|
52 |
|
|
and then ctrl-alt-del to boot linux with the DSP configured by the DOG
|
53 |
|
|
driver.
|
54 |
|
|
|
55 |
|
|
This module works configuring your Audio Excel DSP 16's
|
56 |
|
|
irq, dma and mpu-401-irq. The voxware probe routines rely on the
|
57 |
|
|
fact that if the hardware is there, they can detect it. The problem
|
58 |
|
|
with AEDSP16 is that no hardware can be found by the probe routines
|
59 |
|
|
if the sound card is not well configured. Sometimes the kernel probe
|
60 |
|
|
routines can find an SBPRO even when the card is not configured (this
|
61 |
|
|
is the standard setup of the card), but the SBPRO emulation don't work
|
62 |
|
|
well if the card is not properly initialized. For this reason
|
63 |
|
|
|
64 |
|
|
InitAEDSP16_...()
|
65 |
|
|
|
66 |
|
|
routines are called before the voxware probe routines try to detect the
|
67 |
|
|
hardware.
|
68 |
|
|
|
69 |
|
|
NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS)
|
70 |
|
|
|
71 |
|
|
The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS;
|
72 |
|
|
the voxware sound driver can be configured for SBPRO and MSS cards
|
73 |
|
|
at the same time, but the AEDSP16 can't be two cards!!
|
74 |
|
|
When we configure it, we have to choose the SBPRO or the MSS emulation
|
75 |
|
|
for AEDSP16. We also can install a *REAL* card of the other type
|
76 |
|
|
(see [1], not tested but I can't see any reason for it to fail).
|
77 |
|
|
|
78 |
|
|
NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO
|
79 |
|
|
please let me know if it works.
|
80 |
|
|
|
81 |
|
|
The MPU-401 support can be compiled in together with one of the other
|
82 |
|
|
two operating modes.
|
83 |
|
|
|
84 |
|
|
The board configuration calls, are in the probe_...() routines because
|
85 |
|
|
we have to configure the board before probing it for a particular
|
86 |
|
|
hardware. After card configuration, we can probe the hardware.
|
87 |
|
|
|
88 |
|
|
NOTE: This is something like plug-and-play: we have only to plug
|
89 |
|
|
the AEDSP16 board in the socket, and then configure and compile
|
90 |
|
|
a kernel that uses the AEDSP16 software configuration capability.
|
91 |
|
|
No jumper setting is needed!
|
92 |
|
|
|
93 |
|
|
For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3
|
94 |
|
|
you have just to make config the voxware package, configuring
|
95 |
|
|
the SBPro sound card with that parameters, then when configure
|
96 |
|
|
asks if you have an AEDSP16, answer yes. That's it.
|
97 |
|
|
Compile the kernel and run it.
|
98 |
|
|
|
99 |
|
|
NOTE: This means that you can choose irq and dma, but not the
|
100 |
|
|
I/O addresses. To change I/O addresses you have to set them
|
101 |
|
|
with jumpers.
|
102 |
|
|
|
103 |
|
|
NOTE: InitAEDSP16_...() routines get as parameter the hw_config,
|
104 |
|
|
the hardware configuration of the - to be configured - board.
|
105 |
|
|
The InitAEDSP16() routine, configure the board following our
|
106 |
|
|
wishes, that are in the hw_config structure.
|
107 |
|
|
|
108 |
|
|
You can change the irq/dma/mirq settings WITHOUT THE NEED to open
|
109 |
|
|
your computer and massage the jumpers (there are no irq/dma/mirq
|
110 |
|
|
jumpers to be configured anyway, only I/O port ones have to be
|
111 |
|
|
configured with jumpers)
|
112 |
|
|
|
113 |
|
|
For some ununderstandable reason, the card default of irq 7, dma 1,
|
114 |
|
|
don't work for me. Seems to be an IRQ or DMA conflict. Under heavy
|
115 |
|
|
HDD work, the kernel start to erupt out a lot of messages like:
|
116 |
|
|
|
117 |
|
|
'Sound: DMA timed out - IRQ/DRQ config error?'
|
118 |
|
|
|
119 |
|
|
For what I can say, I have NOT any conflict at irq 7 (under linux I'm
|
120 |
|
|
using the lp polling driver), and dma line 1 is unused as stated by
|
121 |
|
|
/proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so
|
122 |
|
|
I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows!
|
123 |
|
|
Anyway a setting of irq 10, dma 3 works really fine.
|
124 |
|
|
|
125 |
|
|
NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know
|
126 |
|
|
the emulation mode, all the installed hardware and the hardware
|
127 |
|
|
configuration (irq and dma settings of all the hardware).
|
128 |
|
|
|
129 |
|
|
This init module should work with SBPRO+MSS, when one of the two is
|
130 |
|
|
the AEDSP16 emulation and the other the real card. (see [1])
|
131 |
|
|
For example:
|
132 |
|
|
|
133 |
|
|
AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other
|
134 |
|
|
AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other
|
135 |
|
|
|
136 |
|
|
MPU401 should work. (see [1])
|
137 |
|
|
|
138 |
|
|
[1] Not tested by me for lack of hardware.
|
139 |
|
|
|
140 |
|
|
TODO, WISHES AND TECH
|
141 |
|
|
|
142 |
|
|
May be there's lot of redundant delays, but for now I want to leave it
|
143 |
|
|
this way.
|
144 |
|
|
|
145 |
|
|
Should be interesting eventually write down a new ioctl for the
|
146 |
|
|
AEDSP16, to let the suser() change the irq/dma/mirq on the fly.
|
147 |
|
|
The thing is not trivial.
|
148 |
|
|
In the real world, there's no need to have such an ioctl because
|
149 |
|
|
when we configure the kernel for compile, we can choose the config
|
150 |
|
|
parameters. If we change our mind, we can easily re-config the kernel
|
151 |
|
|
and re-compile.
|
152 |
|
|
Why let the suser() change the config parameters on the fly ?
|
153 |
|
|
If anyone have a reasonable answer to this question, I will write down
|
154 |
|
|
the code to do it.
|
155 |
|
|
|
156 |
|
|
More integration with voxware, using voxware low level routines to
|
157 |
|
|
read-write DSP is not possible because you may want to have MSS
|
158 |
|
|
support and in that case we can not rely on the functions included
|
159 |
|
|
in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my
|
160 |
|
|
own I/O functions.
|
161 |
|
|
|
162 |
|
|
- About I/O ports allocation -
|
163 |
|
|
|
164 |
|
|
The request_region should be done at device probe in every sound card
|
165 |
|
|
module. This module is not the best site for requesting regions.
|
166 |
|
|
When the request_region code will be added to the main modules such as
|
167 |
|
|
sb, adlib, gus, ad1848, etc, the requesting code in this module should
|
168 |
|
|
go away.
|
169 |
|
|
|
170 |
|
|
I think the request regions should be done this way:
|
171 |
|
|
|
172 |
|
|
if (check_region(...))
|
173 |
|
|
return ERR; // I/O region already reserved
|
174 |
|
|
device_probe(...);
|
175 |
|
|
device_attach(...);
|
176 |
|
|
request_region(...); // reserve only when we are sure all is okay
|
177 |
|
|
|
178 |
|
|
Request the 2x0h region in any case if we are using this card.
|
179 |
|
|
|
180 |
|
|
NOTE: the "(SBPro)" string with which we are requesting the AEDSP16 region
|
181 |
|
|
(see code) does not mean necessarily that we are emulating SBPro.
|
182 |
|
|
It mean that the region is the SBPro I/O ports region. We use this
|
183 |
|
|
region to access the control registers of the card, and if emulating
|
184 |
|
|
SBPro, I/O SBPro registers too. If we are emulating MSS, the SBPro
|
185 |
|
|
registers are not used, in no way, to emulate an SBPro: they are
|
186 |
|
|
used only for configuration purposes.
|
187 |
|
|
|
188 |
|
|
Someone pointed out that should be possible use both the SBPRO and MSS
|
189 |
|
|
modes because the sound card have all the two chipsets, supposing that
|
190 |
|
|
the card is really two cards. I have tried something to have the two
|
191 |
|
|
modes work together, but, for some reason unknown to me, without success.
|
192 |
|
|
|
193 |
|
|
I think all the soft-config only cards have an init sequence similar to
|
194 |
|
|
this. If you have a card that is not an AEDSP16, you can try to start
|
195 |
|
|
with this module changing it (mainly in the CMD? I think) to fit your
|
196 |
|
|
needs.
|
197 |
|
|
|
198 |
|
|
Started Fri Mar 17 16:13:18 MET 1995
|
199 |
|
|
|
200 |
|
|
v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c)
|
201 |
|
|
- Initial code.
|
202 |
|
|
v0.2 (ALPHA)
|
203 |
|
|
- Cleanups.
|
204 |
|
|
- Integrated with Linux voxware v 2.90-2 kernel sound driver.
|
205 |
|
|
- Sound Blaster Pro mode configuration.
|
206 |
|
|
- Microsoft Sound System mode configuration.
|
207 |
|
|
- MPU-401 mode configuration.
|
208 |
|
|
v0.3 (ALPHA)
|
209 |
|
|
- Cleanups.
|
210 |
|
|
- Rearranged the code to let InitAEDSP16 be more general.
|
211 |
|
|
- Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h
|
212 |
|
|
inclusion too. We rely on os.h
|
213 |
|
|
- Used the to get a variable
|
214 |
|
|
len string (we are not sure about the len of Copyright string).
|
215 |
|
|
This works with any SB and compatible.
|
216 |
|
|
- Added the code to request_region at device init (should go in
|
217 |
|
|
the main body of voxware).
|
218 |
|
|
v0.4 (BETA)
|
219 |
|
|
- Better configure.c patch for AEDSP16 configuration (better
|
220 |
|
|
logic of inclusion of AEDSP16 support)
|
221 |
|
|
- Modified the conditional compilation to better support more than
|
222 |
|
|
one sound card of the emulated type (read the NOTES above)
|
223 |
|
|
- Moved the sb init routine from the attach to the very first
|
224 |
|
|
probe in sb_card.c
|
225 |
|
|
- Rearrangements and cleanups
|
226 |
|
|
- Wiped out some unnecessary code and variables: this is kernel
|
227 |
|
|
code so it is better save some TEXT and DATA
|
228 |
|
|
- Fixed the request_region code. We must allocate the AEDSP16 (SBPro)
|
229 |
|
|
I/O ports in any case because they are used to access the DSP
|
230 |
|
|
configuration registers and we can not allow anyone to get them.
|
231 |
|
|
v0.5
|
232 |
|
|
- cleanups on comments
|
233 |
|
|
- prep for diffs against v3.0-proto-950402
|
234 |
|
|
v0.6
|
235 |
|
|
- removed the request_region()s when compiling the MODULE sound.o
|
236 |
|
|
because we are not allowed (by the actual voxware structure) to
|
237 |
|
|
release_region()
|
238 |
|
|
|
239 |
|
|
*/
|
240 |
|
|
|
241 |
|
|
|
242 |
|
|
#define VERSION "0.6" /* Version of Audio Excel DSP 16 driver */
|
243 |
|
|
|
244 |
|
|
#undef AEDSP16_DEBUG /* Define this to enable debug code */
|
245 |
|
|
/* Actually no debug code is activated */
|
246 |
|
|
|
247 |
|
|
/*
|
248 |
|
|
* Hardware related defaults
|
249 |
|
|
*/
|
250 |
|
|
#define IRQ 7 /* 5 7(default) 9 10 11 */
|
251 |
|
|
#define MIRQ 0 /* 5 7 9 10 0(default), 0 means disable */
|
252 |
|
|
#define DMA 1 /* 0 1(default) 3 */
|
253 |
|
|
|
254 |
|
|
/*
|
255 |
|
|
* Commands of AEDSP16's DSP (SBPRO+special).
|
256 |
|
|
* For now they are CMDn, in the future they may change.
|
257 |
|
|
*/
|
258 |
|
|
#define CMD1 0xe3 /* Get DSP Copyright */
|
259 |
|
|
#define CMD2 0xe1 /* Get DSP Version */
|
260 |
|
|
#define CMD3 0x88 /* */
|
261 |
|
|
#define CMD4 0x5c /* */
|
262 |
|
|
#define CMD5 0x50 /* Set M&I&DRQ mask (the real config) */
|
263 |
|
|
#define CMD6 0x8c /* Enable Microsoft Sound System mode */
|
264 |
|
|
|
265 |
|
|
/*
|
266 |
|
|
* Offsets of AEDSP16 DSP I/O ports. The offset is added to portbase
|
267 |
|
|
* to have the actual I/O port.
|
268 |
|
|
* Register permissions are:
|
269 |
|
|
* (wo) == Write Only
|
270 |
|
|
* (ro) == Read Only
|
271 |
|
|
* (w-) == Write
|
272 |
|
|
* (r-) == Read
|
273 |
|
|
*/
|
274 |
|
|
#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */
|
275 |
|
|
#define DSP_READ 0x0a /* offset of DSP READ (ro) */
|
276 |
|
|
#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */
|
277 |
|
|
#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */
|
278 |
|
|
#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */
|
279 |
|
|
#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */
|
280 |
|
|
|
281 |
|
|
|
282 |
|
|
#define RETRY 10 /* Various retry values on I/O opera- */
|
283 |
|
|
#define STATUSRETRY 1000 /* tions. Sometimes we have to */
|
284 |
|
|
#define HARDRETRY 500000 /* wait for previous cmd to complete */
|
285 |
|
|
|
286 |
|
|
/*
|
287 |
|
|
* Size of character arrays that store name and version of sound card
|
288 |
|
|
*/
|
289 |
|
|
#define CARDNAMELEN 15 /* Size of the card's name in chars */
|
290 |
|
|
#define CARDVERLEN 2 /* Size of the card's version in chars */
|
291 |
|
|
|
292 |
|
|
/*
|
293 |
|
|
* Bit mapped flags for calling InitAEDSP16(), and saving the current
|
294 |
|
|
* emulation mode.
|
295 |
|
|
*/
|
296 |
|
|
#define INIT_NONE (0 )
|
297 |
|
|
#define INIT_SBPRO (1<<0)
|
298 |
|
|
#define INIT_MSS (1<<1)
|
299 |
|
|
#define INIT_MPU401 (1<<2)
|
300 |
|
|
#define RESET_DSP16 (1<<3)
|
301 |
|
|
|
302 |
|
|
/* Base HW Port for Audio Card */
|
303 |
|
|
static int portbase = AEDSP16_BASE;
|
304 |
|
|
static int irq = IRQ; /* irq for DSP I/O */
|
305 |
|
|
static int mirq = MIRQ; /* irq for MPU-401 I/O */
|
306 |
|
|
static int dma = DMA; /* dma for DSP I/O */
|
307 |
|
|
|
308 |
|
|
/* Init status of the card */
|
309 |
|
|
static int ae_init = INIT_NONE; /* (bitmapped variable) */
|
310 |
|
|
static int oredparams = 0; /* Will contain or'ed values of params */
|
311 |
|
|
static int gc = 0; /* generic counter (utility counter) */
|
312 |
|
|
struct orVals
|
313 |
|
|
{ /* Contain the values to be or'ed */
|
314 |
|
|
int val; /* irq|mirq|dma */
|
315 |
|
|
int or; /* oredparams |= TheStruct.or */
|
316 |
|
|
};
|
317 |
|
|
|
318 |
|
|
/*
|
319 |
|
|
* Magic values that the DSP will eat when configuring irq/mirq/dma
|
320 |
|
|
*/
|
321 |
|
|
/* DSP IRQ conversion array */
|
322 |
|
|
static struct orVals orIRQ[] =
|
323 |
|
|
{
|
324 |
|
|
{0x05, 0x28},
|
325 |
|
|
{0x07, 0x08},
|
326 |
|
|
{0x09, 0x10},
|
327 |
|
|
{0x0a, 0x18},
|
328 |
|
|
{0x0b, 0x20},
|
329 |
|
|
{0x00, 0x00}
|
330 |
|
|
};
|
331 |
|
|
|
332 |
|
|
/* MPU-401 IRQ conversion array */
|
333 |
|
|
static struct orVals orMIRQ[] =
|
334 |
|
|
{
|
335 |
|
|
{0x05, 0x04},
|
336 |
|
|
{0x07, 0x44},
|
337 |
|
|
{0x09, 0x84},
|
338 |
|
|
{0x0a, 0xc4},
|
339 |
|
|
{0x00, 0x00}
|
340 |
|
|
};
|
341 |
|
|
|
342 |
|
|
/* DMA Channels conversion array */
|
343 |
|
|
static struct orVals orDMA[] =
|
344 |
|
|
{
|
345 |
|
|
{0x00, 0x01},
|
346 |
|
|
{0x01, 0x02},
|
347 |
|
|
{0x03, 0x03},
|
348 |
|
|
{0x00, 0x00}
|
349 |
|
|
};
|
350 |
|
|
|
351 |
|
|
/*
|
352 |
|
|
* Buffers to store audio card information
|
353 |
|
|
*/
|
354 |
|
|
static char AudioExcelName[CARDNAMELEN + 1];
|
355 |
|
|
static char AudioExcelVersion[CARDVERLEN + 1];
|
356 |
|
|
|
357 |
|
|
static void
|
358 |
|
|
tenmillisec (void)
|
359 |
|
|
{
|
360 |
|
|
|
361 |
|
|
for (gc = 0; gc < 1000; gc++)
|
362 |
|
|
tenmicrosec ();
|
363 |
|
|
}
|
364 |
|
|
|
365 |
|
|
static int
|
366 |
|
|
WaitForDataAvail (int port)
|
367 |
|
|
{
|
368 |
|
|
int loop = STATUSRETRY;
|
369 |
|
|
unsigned char ret = 0;
|
370 |
|
|
|
371 |
|
|
do
|
372 |
|
|
{
|
373 |
|
|
ret = inb (port + DSP_DATAVAIL);
|
374 |
|
|
/*
|
375 |
|
|
* Wait for data available (bit 7 of ret == 1)
|
376 |
|
|
*/
|
377 |
|
|
}
|
378 |
|
|
while (!(ret & 0x80) && loop--);
|
379 |
|
|
|
380 |
|
|
if (ret & 0x80)
|
381 |
|
|
return 0;
|
382 |
|
|
|
383 |
|
|
return -1;
|
384 |
|
|
}
|
385 |
|
|
|
386 |
|
|
static int
|
387 |
|
|
ReadData (int port)
|
388 |
|
|
{
|
389 |
|
|
if (WaitForDataAvail (port))
|
390 |
|
|
return -1;
|
391 |
|
|
return inb (port + DSP_READ);
|
392 |
|
|
}
|
393 |
|
|
|
394 |
|
|
static int
|
395 |
|
|
CheckDSPOkay (int port)
|
396 |
|
|
{
|
397 |
|
|
return ((ReadData (port) == 0xaa) ? 0 : -1);
|
398 |
|
|
}
|
399 |
|
|
|
400 |
|
|
static int
|
401 |
|
|
ResetBoard (int port)
|
402 |
|
|
{
|
403 |
|
|
/*
|
404 |
|
|
* Reset DSP
|
405 |
|
|
*/
|
406 |
|
|
outb (1, (port + DSP_RESET));
|
407 |
|
|
tenmicrosec ();
|
408 |
|
|
outb (0, (port + DSP_RESET));
|
409 |
|
|
tenmicrosec ();
|
410 |
|
|
tenmicrosec ();
|
411 |
|
|
return CheckDSPOkay (port);
|
412 |
|
|
}
|
413 |
|
|
|
414 |
|
|
static int
|
415 |
|
|
WriteDSPCommand (int port, int cmd)
|
416 |
|
|
{
|
417 |
|
|
unsigned char ret;
|
418 |
|
|
int loop = HARDRETRY;
|
419 |
|
|
|
420 |
|
|
do
|
421 |
|
|
{
|
422 |
|
|
ret = inb (port + DSP_STATUS);
|
423 |
|
|
/*
|
424 |
|
|
* DSP ready to receive data if bit 7 of ret == 0
|
425 |
|
|
*/
|
426 |
|
|
if (!(ret & 0x80))
|
427 |
|
|
{
|
428 |
|
|
outb (cmd, port + DSP_COMMAND);
|
429 |
|
|
return 0;
|
430 |
|
|
}
|
431 |
|
|
}
|
432 |
|
|
while (loop--);
|
433 |
|
|
|
434 |
|
|
printk ("[AEDSP16] DSP Command (0x%x) timeout.\n", cmd);
|
435 |
|
|
return -1;
|
436 |
|
|
}
|
437 |
|
|
|
438 |
|
|
int
|
439 |
|
|
InitMSS (int port)
|
440 |
|
|
{
|
441 |
|
|
|
442 |
|
|
tenmillisec ();
|
443 |
|
|
|
444 |
|
|
if (WriteDSPCommand (port, CMD6))
|
445 |
|
|
{
|
446 |
|
|
printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD6);
|
447 |
|
|
return -1;
|
448 |
|
|
}
|
449 |
|
|
|
450 |
|
|
tenmillisec ();
|
451 |
|
|
|
452 |
|
|
return 0;
|
453 |
|
|
}
|
454 |
|
|
|
455 |
|
|
static int
|
456 |
|
|
SetUpBoard (int port)
|
457 |
|
|
{
|
458 |
|
|
int loop = RETRY;
|
459 |
|
|
|
460 |
|
|
do
|
461 |
|
|
{
|
462 |
|
|
if (WriteDSPCommand (portbase, CMD3))
|
463 |
|
|
{
|
464 |
|
|
printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD3);
|
465 |
|
|
return -1;
|
466 |
|
|
}
|
467 |
|
|
|
468 |
|
|
tenmillisec ();
|
469 |
|
|
|
470 |
|
|
}
|
471 |
|
|
while (WaitForDataAvail (port) && loop--);
|
472 |
|
|
|
473 |
|
|
#if defined(THIS_SHOULD_GO_AWAY)
|
474 |
|
|
if (CheckDSPOkay (port))
|
475 |
|
|
{
|
476 |
|
|
printk ("[AEDSP16] CheckDSPOkay: failed\n");
|
477 |
|
|
return -1;
|
478 |
|
|
}
|
479 |
|
|
#else
|
480 |
|
|
if (ReadData (port) == -1)
|
481 |
|
|
{
|
482 |
|
|
printk ("[AEDSP16] ReadData after CMD 0x%x: failed\n", CMD3);
|
483 |
|
|
return -1;
|
484 |
|
|
}
|
485 |
|
|
#endif
|
486 |
|
|
|
487 |
|
|
if (WriteDSPCommand (portbase, CMD4))
|
488 |
|
|
{
|
489 |
|
|
printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD4);
|
490 |
|
|
return -1;
|
491 |
|
|
}
|
492 |
|
|
|
493 |
|
|
if (WriteDSPCommand (portbase, CMD5))
|
494 |
|
|
{
|
495 |
|
|
printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD5);
|
496 |
|
|
return -1;
|
497 |
|
|
}
|
498 |
|
|
|
499 |
|
|
if (WriteDSPCommand (portbase, oredparams))
|
500 |
|
|
{
|
501 |
|
|
printk ("[AEDSP16] Initialization of (M)IRQ and DMA: failed!\n");
|
502 |
|
|
return -1;
|
503 |
|
|
}
|
504 |
|
|
return 0;
|
505 |
|
|
}
|
506 |
|
|
|
507 |
|
|
static int
|
508 |
|
|
GetCardVersion (int port)
|
509 |
|
|
{
|
510 |
|
|
int len = 0;
|
511 |
|
|
int ret;
|
512 |
|
|
int ver[3];
|
513 |
|
|
|
514 |
|
|
do
|
515 |
|
|
{
|
516 |
|
|
if ((ret = ReadData (port)) == -1)
|
517 |
|
|
return -1;
|
518 |
|
|
/*
|
519 |
|
|
* We already know how many int are stored (2), so we know when the
|
520 |
|
|
* string is finished.
|
521 |
|
|
*/
|
522 |
|
|
ver[len++] = ret;
|
523 |
|
|
}
|
524 |
|
|
while (len < CARDVERLEN);
|
525 |
|
|
sprintf (AudioExcelVersion, "%d.%d", ver[0], ver[1]);
|
526 |
|
|
return 0;
|
527 |
|
|
}
|
528 |
|
|
|
529 |
|
|
static int
|
530 |
|
|
GetCardName (int port)
|
531 |
|
|
{
|
532 |
|
|
int len = 0;
|
533 |
|
|
int ret;
|
534 |
|
|
|
535 |
|
|
do
|
536 |
|
|
{
|
537 |
|
|
if ((ret = ReadData (port)) == -1)
|
538 |
|
|
/*
|
539 |
|
|
* If no more data available, return to the caller, no error if len>0.
|
540 |
|
|
* We have no other way to know when the string is finished.
|
541 |
|
|
*/
|
542 |
|
|
return (len ? 0 : -1);
|
543 |
|
|
|
544 |
|
|
AudioExcelName[len++] = ret;
|
545 |
|
|
|
546 |
|
|
}
|
547 |
|
|
while (len < CARDNAMELEN);
|
548 |
|
|
return 0;
|
549 |
|
|
}
|
550 |
|
|
|
551 |
|
|
static void
|
552 |
|
|
InitializeHardParams (void)
|
553 |
|
|
{
|
554 |
|
|
|
555 |
|
|
memset (AudioExcelName, 0, CARDNAMELEN + 1);
|
556 |
|
|
memset (AudioExcelVersion, 0, CARDVERLEN + 1);
|
557 |
|
|
|
558 |
|
|
for (gc = 0; orIRQ[gc].or; gc++)
|
559 |
|
|
if (orIRQ[gc].val == irq)
|
560 |
|
|
oredparams |= orIRQ[gc].or;
|
561 |
|
|
|
562 |
|
|
for (gc = 0; orMIRQ[gc].or; gc++)
|
563 |
|
|
if (orMIRQ[gc].or == mirq)
|
564 |
|
|
oredparams |= orMIRQ[gc].or;
|
565 |
|
|
|
566 |
|
|
for (gc = 0; orDMA[gc].or; gc++)
|
567 |
|
|
if (orDMA[gc].val == dma)
|
568 |
|
|
oredparams |= orDMA[gc].or;
|
569 |
|
|
}
|
570 |
|
|
|
571 |
|
|
static int
|
572 |
|
|
InitAEDSP16 (int which)
|
573 |
|
|
{
|
574 |
|
|
static char *InitName = NULL;
|
575 |
|
|
|
576 |
|
|
InitializeHardParams ();
|
577 |
|
|
|
578 |
|
|
if (ResetBoard (portbase))
|
579 |
|
|
{
|
580 |
|
|
printk ("[AEDSP16] ResetBoard: failed!\n");
|
581 |
|
|
return -1;
|
582 |
|
|
}
|
583 |
|
|
|
584 |
|
|
#if defined(THIS_SHOULD_GO_AWAY)
|
585 |
|
|
if (CheckDSPOkay (portbase))
|
586 |
|
|
{
|
587 |
|
|
printk ("[AEDSP16] CheckDSPOkay: failed!\n");
|
588 |
|
|
return -1;
|
589 |
|
|
}
|
590 |
|
|
#endif
|
591 |
|
|
|
592 |
|
|
if (WriteDSPCommand (portbase, CMD1))
|
593 |
|
|
{
|
594 |
|
|
printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD1);
|
595 |
|
|
return -1;
|
596 |
|
|
}
|
597 |
|
|
|
598 |
|
|
if (GetCardName (portbase))
|
599 |
|
|
{
|
600 |
|
|
printk ("[AEDSP16] GetCardName: failed!\n");
|
601 |
|
|
return -1;
|
602 |
|
|
}
|
603 |
|
|
|
604 |
|
|
/*
|
605 |
|
|
* My AEDSP16 card return SC-6000 in AudioExcelName, so
|
606 |
|
|
* if we have something different, we have to be warned.
|
607 |
|
|
*/
|
608 |
|
|
if (strcmp ("SC-6000", AudioExcelName))
|
609 |
|
|
printk ("[AEDSP16] Warning: non SC-6000 audio card!\n");
|
610 |
|
|
|
611 |
|
|
if (WriteDSPCommand (portbase, CMD2))
|
612 |
|
|
{
|
613 |
|
|
printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD2);
|
614 |
|
|
return -1;
|
615 |
|
|
}
|
616 |
|
|
|
617 |
|
|
if (GetCardVersion (portbase))
|
618 |
|
|
{
|
619 |
|
|
printk ("[AEDSP16] GetCardVersion: failed!\n");
|
620 |
|
|
return -1;
|
621 |
|
|
}
|
622 |
|
|
|
623 |
|
|
if (SetUpBoard (portbase))
|
624 |
|
|
{
|
625 |
|
|
printk ("[AEDSP16] SetUpBoard: failed!\n");
|
626 |
|
|
return -1;
|
627 |
|
|
}
|
628 |
|
|
|
629 |
|
|
if (which == INIT_MSS)
|
630 |
|
|
{
|
631 |
|
|
if (InitMSS (portbase))
|
632 |
|
|
{
|
633 |
|
|
printk ("[AEDSP16] Can't initialize Microsoft Sound System mode.\n");
|
634 |
|
|
return -1;
|
635 |
|
|
}
|
636 |
|
|
}
|
637 |
|
|
|
638 |
|
|
/*
|
639 |
|
|
* If we are resetting, do not print any message because we may be
|
640 |
|
|
* in playing and we do not want lost too much time.
|
641 |
|
|
*/
|
642 |
|
|
if (!(which & RESET_DSP16))
|
643 |
|
|
{
|
644 |
|
|
if (which & INIT_MPU401)
|
645 |
|
|
InitName = "MPU401";
|
646 |
|
|
else if (which & INIT_SBPRO)
|
647 |
|
|
InitName = "SBPro";
|
648 |
|
|
else if (which & INIT_MSS)
|
649 |
|
|
InitName = "MSS";
|
650 |
|
|
else
|
651 |
|
|
InitName = "None";
|
652 |
|
|
|
653 |
|
|
printk ("Audio Excel DSP 16 init v%s (%s %s) [%s]\n",
|
654 |
|
|
VERSION, AudioExcelName,
|
655 |
|
|
AudioExcelVersion, InitName);
|
656 |
|
|
}
|
657 |
|
|
|
658 |
|
|
tenmillisec ();
|
659 |
|
|
|
660 |
|
|
return 0;
|
661 |
|
|
}
|
662 |
|
|
|
663 |
|
|
#if defined(AEDSP16_SBPRO)
|
664 |
|
|
|
665 |
|
|
int
|
666 |
|
|
InitAEDSP16_SBPRO (struct address_info *hw_config)
|
667 |
|
|
{
|
668 |
|
|
/*
|
669 |
|
|
* If the card is already init'ed MSS, we can not init it to SBPRO too
|
670 |
|
|
* because the board can not emulate simultaneously MSS and SBPRO.
|
671 |
|
|
*/
|
672 |
|
|
if (ae_init & INIT_MSS)
|
673 |
|
|
return -1;
|
674 |
|
|
if (ae_init & INIT_SBPRO)
|
675 |
|
|
return 0;
|
676 |
|
|
|
677 |
|
|
/*
|
678 |
|
|
* For now we will leave this
|
679 |
|
|
* code included only when INCLUDE_AEDSP16 is configured in, but it should
|
680 |
|
|
* be better include it every time.
|
681 |
|
|
*/
|
682 |
|
|
if (!(ae_init & INIT_MPU401))
|
683 |
|
|
{
|
684 |
|
|
if (check_region (hw_config->io_base, 0x0f))
|
685 |
|
|
{
|
686 |
|
|
printk ("AEDSP16/SBPRO I/O port region is already in use.\n");
|
687 |
|
|
return -1;
|
688 |
|
|
}
|
689 |
|
|
}
|
690 |
|
|
|
691 |
|
|
/*
|
692 |
|
|
* Set up the internal hardware parameters, to let the driver reach
|
693 |
|
|
* the Sound Card.
|
694 |
|
|
*/
|
695 |
|
|
portbase = hw_config->io_base;
|
696 |
|
|
irq = hw_config->irq;
|
697 |
|
|
dma = hw_config->dma;
|
698 |
|
|
|
699 |
|
|
if (InitAEDSP16 (INIT_SBPRO))
|
700 |
|
|
return -1;
|
701 |
|
|
|
702 |
|
|
#if !defined(MODULE)
|
703 |
|
|
/*
|
704 |
|
|
* If we are compiling sound.o (MODULAR version) we can not
|
705 |
|
|
* request any region because there is not a uninit routine that
|
706 |
|
|
* can allow me to release the requested region.
|
707 |
|
|
*/
|
708 |
|
|
if (!(ae_init & INIT_MPU401))
|
709 |
|
|
request_region (hw_config->io_base, 0x0f, "AEDSP16 (SBPro)");
|
710 |
|
|
#endif
|
711 |
|
|
|
712 |
|
|
ae_init |= INIT_SBPRO;
|
713 |
|
|
return 0;
|
714 |
|
|
}
|
715 |
|
|
|
716 |
|
|
#endif /* AEDSP16_SBPRO */
|
717 |
|
|
|
718 |
|
|
#if defined(AEDSP16_MSS)
|
719 |
|
|
|
720 |
|
|
int
|
721 |
|
|
InitAEDSP16_MSS (struct address_info *hw_config)
|
722 |
|
|
{
|
723 |
|
|
/*
|
724 |
|
|
* If the card is already init'ed SBPRO, we can not init it to MSS too
|
725 |
|
|
* because the board can not emulate simultaneously MSS and SBPRO.
|
726 |
|
|
*/
|
727 |
|
|
if (ae_init & INIT_SBPRO)
|
728 |
|
|
return -1;
|
729 |
|
|
if (ae_init & INIT_MSS)
|
730 |
|
|
return 0;
|
731 |
|
|
|
732 |
|
|
/*
|
733 |
|
|
* For now we will leave this
|
734 |
|
|
* code included only when INCLUDE_AEDSP16 is configured in, but it should
|
735 |
|
|
* be better include it every time.
|
736 |
|
|
*/
|
737 |
|
|
if (check_region (hw_config->io_base, 0x08))
|
738 |
|
|
{
|
739 |
|
|
printk ("MSS I/O port region is already in use.\n");
|
740 |
|
|
return -1;
|
741 |
|
|
}
|
742 |
|
|
|
743 |
|
|
/*
|
744 |
|
|
* We must allocate the AEDSP16 region too because these are the I/O ports
|
745 |
|
|
* to access card's control registers.
|
746 |
|
|
*/
|
747 |
|
|
if (!(ae_init & INIT_MPU401))
|
748 |
|
|
{
|
749 |
|
|
if (check_region (AEDSP16_BASE, 0x0f))
|
750 |
|
|
{
|
751 |
|
|
printk ("AEDSP16 I/O port region is already in use.\n");
|
752 |
|
|
return -1;
|
753 |
|
|
}
|
754 |
|
|
}
|
755 |
|
|
|
756 |
|
|
|
757 |
|
|
/*
|
758 |
|
|
* If we are configuring the card for MSS, the portbase for card
|
759 |
|
|
* configuration is the default one (0x220 unless you have changed the
|
760 |
|
|
* factory default with board switches), so no need to modify the
|
761 |
|
|
* portbase variable.
|
762 |
|
|
* The default is AEDSP16_BASE, that is the right value.
|
763 |
|
|
*/
|
764 |
|
|
irq = hw_config->irq;
|
765 |
|
|
dma = hw_config->dma;
|
766 |
|
|
|
767 |
|
|
if (InitAEDSP16 (INIT_MSS))
|
768 |
|
|
return -1;
|
769 |
|
|
|
770 |
|
|
#if !defined(MODULE)
|
771 |
|
|
/*
|
772 |
|
|
* If we are compiling sound.o (MODULAR version) we can not
|
773 |
|
|
* request any region because there is not a uninit routine that
|
774 |
|
|
* can allow me to release the requested region. So when unloading
|
775 |
|
|
* and then reloading it, we are going to have some nice Oops!
|
776 |
|
|
*/
|
777 |
|
|
request_region (hw_config->io_base, 0x08, "AEDSP16 (MSS)");
|
778 |
|
|
#endif
|
779 |
|
|
|
780 |
|
|
if (!(ae_init & INIT_MPU401))
|
781 |
|
|
request_region (AEDSP16_BASE, 0x0f, "AEDSP16 (SBPro)");
|
782 |
|
|
|
783 |
|
|
ae_init |= INIT_MSS;
|
784 |
|
|
return 0;
|
785 |
|
|
}
|
786 |
|
|
|
787 |
|
|
#endif /* AEDSP16_MSS */
|
788 |
|
|
|
789 |
|
|
#if defined(AEDSP16_MPU401)
|
790 |
|
|
|
791 |
|
|
int
|
792 |
|
|
InitAEDSP16_MPU401 (struct address_info *hw_config)
|
793 |
|
|
{
|
794 |
|
|
if (ae_init & INIT_MPU401)
|
795 |
|
|
return 0;
|
796 |
|
|
|
797 |
|
|
/*
|
798 |
|
|
* For now we will leave this
|
799 |
|
|
* code included only when INCLUDE_AEDSP16 is configured in, but it should
|
800 |
|
|
* be better include it every time.
|
801 |
|
|
*/
|
802 |
|
|
if (check_region (hw_config->io_base, 0x02))
|
803 |
|
|
{
|
804 |
|
|
printk ("SB I/O port region is already in use.\n");
|
805 |
|
|
return -1;
|
806 |
|
|
}
|
807 |
|
|
|
808 |
|
|
/*
|
809 |
|
|
* We must allocate the AEDSP16 region too because these are the I/O ports
|
810 |
|
|
* to access card's control registers.
|
811 |
|
|
*/
|
812 |
|
|
if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
|
813 |
|
|
{
|
814 |
|
|
if (check_region (AEDSP16_BASE, 0x0f))
|
815 |
|
|
{
|
816 |
|
|
printk ("AEDSP16 I/O port region is already in use.\n");
|
817 |
|
|
return -1;
|
818 |
|
|
}
|
819 |
|
|
}
|
820 |
|
|
|
821 |
|
|
/*
|
822 |
|
|
* If mpu401, the irq and dma are not important, do not touch it
|
823 |
|
|
* because we may use the default if SBPro is not yet configured,
|
824 |
|
|
* we may use the SBPro ones if configured, and nothing wrong
|
825 |
|
|
* should happen.
|
826 |
|
|
*
|
827 |
|
|
* The mirq default is 0, but once set it to non-0 value, we should
|
828 |
|
|
* not touch it anymore (unless I write an ioctl to do it, of course).
|
829 |
|
|
*/
|
830 |
|
|
mirq = hw_config->irq;
|
831 |
|
|
if (InitAEDSP16 (INIT_MPU401))
|
832 |
|
|
return -1;
|
833 |
|
|
|
834 |
|
|
#if !defined(MODULE)
|
835 |
|
|
/*
|
836 |
|
|
* If we are compiling sound.o (MODULAR version) we can not
|
837 |
|
|
* request any region because there is not a uninit routine that
|
838 |
|
|
* can allow me to release the requested region.
|
839 |
|
|
*/
|
840 |
|
|
request_region (hw_config->io_base, 0x02, "AEDSP16 (mpu401)");
|
841 |
|
|
#endif
|
842 |
|
|
|
843 |
|
|
if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
|
844 |
|
|
request_region (AEDSP16_BASE, 0x0f, "AEDSP16 (SBPro)");
|
845 |
|
|
|
846 |
|
|
ae_init |= INIT_MPU401;
|
847 |
|
|
return 0;
|
848 |
|
|
}
|
849 |
|
|
|
850 |
|
|
#endif /* AEDSP16_MPU401 */
|
851 |
|
|
|
852 |
|
|
#if 0 /* Leave it out for now. We are not using this portion of code. */
|
853 |
|
|
|
854 |
|
|
/*
|
855 |
|
|
* Entry point for a reset function.
|
856 |
|
|
* May be I will write the infamous ioctl :)
|
857 |
|
|
*/
|
858 |
|
|
int
|
859 |
|
|
ResetAEDSP16 (void)
|
860 |
|
|
{
|
861 |
|
|
#if defined(AEDSP16_DEBUG)
|
862 |
|
|
printk ("[AEDSP16] ResetAEDSP16 called.\n");
|
863 |
|
|
#endif
|
864 |
|
|
return InitAEDSP16 (RESET_DSP16);
|
865 |
|
|
}
|
866 |
|
|
|
867 |
|
|
#endif /* 0 */
|
868 |
|
|
|
869 |
|
|
#endif /* CONFIG_AEDSP16 */
|