1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Ensoniq Soundscape driver.
12 *
13 * By Andreas Kluge.
14 *
15 * Based on code by Andrew P. Weir.
16 *
17 * See readme.txt for copyright information.
18 */
19
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "allegro.h"
25 #include "allegro/internal/aintern.h"
26 #include "allegro/platform/aintdos.h"
27
28 #ifndef ALLEGRO_DOS
29 #error something is wrong with the makefile
30 #endif
31
32
33
34 #define ODIE 0 /* ODIE gate array */
35 #define OPUS 1 /* OPUS gate array */
36 #define MMIC 2 /* MiMIC gate array */
37
38 static int soundscape_hw_ver = -1; /* as reported by detection */
39
40 static char *ensoniq_gate_array[] = { "ODIE", "OPUS", "MiMIC" };
41
42
43 #define GA_HOSTCTL_OFF 2 /* host port ctrl/stat reg */
44 #define GA_ADDR_OFF 4 /* indirect address reg */
45 #define GA_DATA_OFF 5 /* indirect data reg */
46 #define GA_CODEC_OFF 8 /* for some boards CoDec is fixed from base */
47
48 #define GA_DMAB_REG 3 /* DMA chan B assign reg */
49 #define GA_INTCFG_REG 4 /* interrupt configuration reg */
50 #define GA_DMACFG_REG 5 /* DMA configuration reg */
51 #define GA_CDCFG_REG 6 /* CD-ROM/CoDec config reg */
52 #define GA_HMCTL_REG 9 /* host master control reg */
53
54 #define CD_ADDR_OFF 0 /* indirect address reg */
55 #define CD_DATA_OFF 1 /* indirect data reg */
56 #define CD_STATUS_OFF 2 /* status register */
57
58
59 #define OUT_TO_ADDR(n) outportb(soundscape_waveport + CD_ADDR_OFF, n)
60
61 #define CODEC_MODE_CHANGE_ON() OUT_TO_ADDR(0x40)
62 #define CODEC_MODE_CHANGE_OFF() OUT_TO_ADDR(0x00)
63
64
65 #define CD_ADCL_REG 0 /* left DAC input control reg */
66 #define CD_ADCR_REG 1 /* right DAC input control reg */
67 #define CD_CDAUXL_REG 2 /* left DAC output control reg */
68 #define CD_CDAUXR_REG 3 /* right DAC output control reg */
69 #define CD_DACL_REG 6 /* left DAC output control reg */
70 #define CD_DACR_REG 7 /* right DAC output control reg */
71 #define CD_FORMAT_REG 8 /* clock and data format reg */
72 #define CD_CONFIG_REG 9 /* interface config register */
73 #define CD_PINCTL_REG 10 /* external pin control reg */
74 #define CD_UCOUNT_REG 14 /* upper count reg */
75 #define CD_LCOUNT_REG 15 /* lower count reg */
76 #define CD_XFORMAT_REG 28 /* extended format reg - 1845 record */
77 #define CD_XUCOUNT_REG 30 /* extended upper count reg - 1845 record */
78 #define CD_XLCOUNT_REG 31 /* extended lower count reg - 1845 record */
79
80
81 #define ENABLE_CODEC_IRQ() cd_write(CD_PINCTL_REG, cd_read(CD_PINCTL_REG) | 0x02)
82 #define DISABLE_CODEC_IRQ() cd_write(CD_PINCTL_REG, cd_read(CD_PINCTL_REG) & 0xFD);
83
84
85 static int soundscape_enabled = FALSE;
86 static int soundscape_mem_allocated = FALSE;
87 static int soundscape_dma_count = 0;
88 static int soundscape_dma;
89 static int soundscape_freq;
90 static int soundscape_baseport; /* gate Array/MPU-401 port */
91 static int soundscape_waveport; /* the AD-1848 base port */
92 static int soundscape_midiirq; /* the MPU-401 IRQ */
93 static int soundscape_waveirq; /* the PCM IRQ */
94
95 static int soundscape_detect(int input);
96 static int soundscape_init(int input, int voices);
97 static void soundscape_exit(int input);
98 static int soundscape_set_mixer_volume(int volume);
99 static int soundscape_buffer_size(void);
100
101 static int soundscape_int = -1; /* interrupt vector */
102 static int soundscape_dma_size = -1; /* size of dma transfer */
103
104 static volatile int soundscape_semaphore = FALSE;
105
106 static int soundscape_sel; /* selector for the DMA buffer */
107 static unsigned long soundscape_buf[2]; /* pointers to the two buffers */
108 static int soundscape_bufnum = 0; /* the one currently in use */
109
110 static void soundscape_lock_mem(void);
111
112 static char soundscape_desc[256] = EMPTY_STRING;
113
114 static int cd_cfg_save; /* gate array register save area */
115 static int dma_cfg_save; /* gate array register save area */
116 static int int_cfg_save; /* gate array register save area */
117
118 static int dac_save_l; /* DAC left volume save */
119 static int dac_save_r; /* DAC right volume save */
120 static int cdx_save_l; /* CD/Aux left volume save */
121 static int cdx_save_r; /* CD/Aux right volume save */
122 static int adc_save_l; /* ADC left volume save */
123 static int adc_save_r; /* ADC right volume save */
124
125 static int ss_irqs[4] = { 9, 5, 7, 10 };
126 static int rs_irqs[4] = { 9, 7, 5, 15 };
127
128 static int *soundscape_irqset; /* pointer to one of the IRQ sets */
129
130 static int soundscape_detected = FALSE;
131
132
133 typedef struct /* DMA controller registers ... */
134 {
135 unsigned char addr; /* address register, lower/upper */
136 unsigned char count; /* address register, lower/upper */
137 unsigned char status; /* status register */
138 unsigned char mask; /* single channel mask register */
139 unsigned char mode; /* mode register */
140 unsigned char clrff; /* clear flip-flop register */
141 unsigned char page; /* fixed page register */
142 } DMAC_REGS;
143
144
145 static DMAC_REGS dmac_regs[4] = /* the DMAC regs for chans 0-3 */
146 {
147 { 0x00, 0x01, 0x08, 0x0A, 0x0B, 0x0C, 0x87 },
148 { 0x02, 0x03, 0x08, 0x0A, 0x0B, 0x0C, 0x83 },
149 { 0x04, 0x05, 0x08, 0x0A, 0x0B, 0x0C, 0x81 },
150 { 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x82 }
151 };
152
153
154 static DMAC_REGS *dmac_reg_p; /* a pointer to a DMAC reg struct */
155
156
157
158 DIGI_DRIVER digi_soundscape =
159 {
160 DIGI_SOUNDSCAPE,
161 empty_string,
162 empty_string,
163 "Soundscape",
164 0, 0, MIXER_MAX_SFX, MIXER_DEF_SFX,
165 soundscape_detect,
166 soundscape_init,
167 soundscape_exit,
168 soundscape_set_mixer_volume,
169 NULL,
170 NULL,
171 NULL,
172 soundscape_buffer_size,
173 _mixer_init_voice,
174 _mixer_release_voice,
175 _mixer_start_voice,
176 _mixer_stop_voice,
177 _mixer_loop_voice,
178 _mixer_get_position,
179 _mixer_set_position,
180 _mixer_get_volume,
181 _mixer_set_volume,
182 _mixer_ramp_volume,
183 _mixer_stop_volume_ramp,
184 _mixer_get_frequency,
185 _mixer_set_frequency,
186 _mixer_sweep_frequency,
187 _mixer_stop_frequency_sweep,
188 _mixer_get_pan,
189 _mixer_set_pan,
190 _mixer_sweep_pan,
191 _mixer_stop_pan_sweep,
192 _mixer_set_echo,
193 _mixer_set_tremolo,
194 _mixer_set_vibrato,
195 0, 0,
196 NULL,
197 NULL,
198 NULL,
199 NULL,
200 NULL,
201 NULL
202 };
203
204
205
206 /* soundscape_buffer_size:
207 * Returns the current DMA buffer size, for use by the audiostream code.
208 */
soundscape_buffer_size(void)209 static int soundscape_buffer_size(void)
210 {
211 return soundscape_dma_size/4; /* convert bytes to stereo 16 bit samples */
212 }
213
214
215
216 /* cd_write:
217 * This function is used to write the indirect addressed registers in the
218 * Ad-1848 or compatible CoDec. It will preserve the special function bits
219 * in the upper-nibble of the indirect address register.
220 */
cd_write(int rnum,int value)221 static void cd_write(int rnum, int value)
222 {
223 OUT_TO_ADDR((inportb(soundscape_waveport + CD_ADDR_OFF) & 0xF0) | rnum);
224 outportb(soundscape_waveport + CD_DATA_OFF, value);
225 }
226
227
228
229 /* cd_read:
230 * This function is used to read the indirect addressed registers in the
231 * AD-1848 or compatible CoDec. It will preserve the special function bits
232 * in the upper-nibble of the indirect address register.
233 */
cd_read(int rnum)234 static int cd_read(int rnum)
235 {
236 OUT_TO_ADDR((inportb(soundscape_waveport + CD_ADDR_OFF) & 0xF0) | rnum);
237 return inportb(soundscape_waveport + CD_DATA_OFF);
238 }
239
240
241
242 /* ga_write:
243 * This function is used to write the indirect addressed registers in the
244 * Ensoniq Soundscape gate array.
245 */
ga_write(int rnum,int value)246 static void ga_write(int rnum, int value)
247 {
248 outportb(soundscape_baseport + GA_ADDR_OFF, rnum);
249 outportb(soundscape_baseport + GA_DATA_OFF, value);
250 }
251
252
253
254 /* ga_read:
255 * This function is used to read the indirect addressed registers in the
256 * Ensoniq Soundscape gate array.
257 */
ga_read(int rnum)258 static int ga_read(int rnum)
259 {
260 outportb(soundscape_baseport + GA_ADDR_OFF, rnum);
261 return inportb(soundscape_baseport + GA_DATA_OFF);
262 }
263
264
265
266 /* set_dac_vol:
267 * This function sets the left and right DAC output level in the CoDec.
268 */
set_dac_vol(int lvol,int rvol)269 static void set_dac_vol(int lvol, int rvol)
270 {
271 cd_write(CD_DACL_REG, ~(lvol >> 2) & 0x3F);
272 cd_write(CD_DACR_REG, ~(rvol >> 2) & 0x3F);
273 }
274
275
276
277 /* resume_codec:
278 * This function will resume the CoDec auto-restart DMA process.
279 */
resume_codec(int direction)280 static void resume_codec(int direction)
281 {
282 cd_write(CD_CONFIG_REG, direction ? 0x02 : 0x01);
283 }
284
285
286
287 /* set_format:
288 * This function sets the CoDec audio data format for record or playback.
289 */
set_format(int srate,int stereo,int size16bit,int direction)290 static int set_format(int srate, int stereo, int size16bit, int direction)
291 {
292 int format = 0;
293 int i;
294
295 /* first, find the sample rate ... */
296 switch (srate) {
297
298 case 5512: format = 0x01; soundscape_dma_size = 512; break;
299 case 6615: format = 0x0F; soundscape_dma_size = 512; break;
300 case 8000: format = 0x00; soundscape_dma_size = 512; break;
301 case 9600: format = 0x0E; soundscape_dma_size = 512; break;
302 case 11025: format = 0x03; soundscape_dma_size = 512; break; /* 11363 */
303 case 16000: format = 0x02; soundscape_dma_size = 512; break; /* 17046 */
304 case 18900: format = 0x05; soundscape_dma_size = 1024; break;
305 case 22050: format = 0x07; soundscape_dma_size = 1024; break; /* 22729 */
306 case 27428: format = 0x04; soundscape_dma_size = 1024; break;
307 case 32000: format = 0x06; soundscape_dma_size = 2048; break;
308 case 33075: format = 0x0D; soundscape_dma_size = 2048; break;
309 case 37800: format = 0x09; soundscape_dma_size = 2048; break;
310 case 44100: format = 0x0B; soundscape_dma_size = 2048; break; /* 44194 */
311 case 48000: format = 0x0C; soundscape_dma_size = 2048; break;
312
313 default:
314 return FALSE;
315 }
316
317 /* set other format bits ... */
318 if (stereo)
319 format |= 0x10;
320
321 if (size16bit) {
322 format |= 0x40;
323 soundscape_dma_size *= 2;
324 }
325
326 soundscape_freq = srate;
327
328 CODEC_MODE_CHANGE_ON();
329
330 /* and write the format register */
331 cd_write(CD_FORMAT_REG, format);
332
333 /* if not using ODIE and recording, setup extended format register */
334 if ((soundscape_hw_ver) != ODIE && (direction))
335 cd_write(CD_XFORMAT_REG, format & 0x70);
336
337 /* delay for internal re-sync */
338 for (i=0; i<200000; i++)
339 inportb(soundscape_baseport + GA_ADDR_OFF);
340
341 CODEC_MODE_CHANGE_OFF();
342
343 return TRUE;
344 }
345
346
347
348 /* stop_codec:
349 * This function will stop the CoDec auto-restart DMA process.
350 */
stop_codec(void)351 static void stop_codec(void)
352 {
353 int i;
354
355 cd_write(CD_CONFIG_REG, cd_read(CD_CONFIG_REG) & 0xFC);
356
357 /* let the CoDec receive its last DACK(s). The DMAC must not be */
358 /* masked while the CoDec has DRQs pending. */
359 for (i=0; i<64; i++) {
360 if (!(inportb(dmac_reg_p->status) & (0x10 << soundscape_dma)))
361 break;
362 }
363 }
364
365
366
367 /* get_ini_config_entry:
368 * This function parses a file (SNDSCAPE.INI) for a left-hand string and,
369 * if found, writes its associated right-hand value to a destination buffer.
370 * This function is case-insensitive.
371 */
get_ini_config_entry(char * entry,char * dest,unsigned int dest_size,FILE * fp)372 static int get_ini_config_entry(char *entry, char *dest, unsigned int dest_size, FILE *fp)
373 {
374 char str[83];
375 char tokstr[33];
376 char *p;
377
378 /* make a local copy of the entry, upper-case it */
379 _al_sane_strncpy(tokstr, entry, sizeof(tokstr));
380 strupr(tokstr);
381
382 /* rewind the file and try to find it... */
383 rewind(fp);
384
385 for (;;) {
386 /* get the next string from the file */
387 fgets(str, 83, fp);
388 if (feof(fp)) {
389 fclose(fp);
390 return -1;
391 }
392
393 /* properly terminate the string */
394 for (p=str; *p; p++) {
395 if (uisspace(*p)) {
396 *p = 0;
397 break;
398 }
399 }
400
401 /* see if it's an 'equate' string; if so, zero the '=' */
402 p = strchr(str, '=');
403 if (!p)
404 continue;
405
406 *p = 0;
407
408 /* upper-case the current string and test it */
409 strupr(str);
410
411 if (strcmp(str, tokstr))
412 continue;
413
414 /* it's our string - copy the right-hand value to buffer */
415 _al_sane_strncpy(dest, str+strlen(str)+1, dest_size);
416 break;
417 }
418
419 return 0;
420 }
421
422
423
424 /* get_init_config:
425 * This function gets all parameters from a file (SNDSCAPE.INI)
426 */
get_init_config(void)427 static int get_init_config(void)
428 {
429 FILE *fp = NULL;
430 char str[78];
431 char *ep;
432
433 /* get the environment var and build the filename, then open it */
434 if (!(ep = getenv("SNDSCAPE")))
435 return FALSE;
436
437 _al_sane_strncpy(str, ep, sizeof(str));
438
439 if (str[strlen(str)-1] == '\\')
440 str[strlen(str)-1] = 0;
441
442 strncat(str, "\\SNDSCAPE.INI", sizeof(str)-1);
443
444 if (!(fp = fopen(str, "r")))
445 return FALSE;
446
447 /* read all of the necessary config info ... */
448 if (get_ini_config_entry("Product", str, sizeof(str), fp)) {
449 fclose(fp);
450 return FALSE;
451 }
452
453 /* if an old product name is read, set the IRQs accordingly */
454 strupr(str);
455 if (strstr(str, "SOUNDFX") || strstr(str, "MEDIA_FX"))
456 soundscape_irqset = rs_irqs;
457 else
458 soundscape_irqset = ss_irqs;
459
460 if (get_ini_config_entry("Port", str, sizeof(str), fp)) {
461 fclose(fp);
462 return FALSE;
463 }
464
465 soundscape_baseport = strtol(str, NULL, 16);
466
467 if (get_ini_config_entry("WavePort", str, sizeof(str), fp)) {
468 fclose(fp);
469 return FALSE;
470 }
471
472 soundscape_waveport = strtol(str, NULL, 16);
473
474 if (get_ini_config_entry("IRQ", str, sizeof(str), fp)) {
475 fclose(fp);
476 return FALSE;
477 }
478
479 soundscape_midiirq = strtol(str, NULL, 10);
480
481 if (soundscape_midiirq == 2)
482 soundscape_midiirq = 9;
483
484 if (get_ini_config_entry("SBIRQ", str, sizeof(str), fp)) {
485 fclose(fp);
486 return FALSE;
487 }
488
489 soundscape_waveirq = strtol(str, NULL, 10);
490
491 if (soundscape_waveirq == 2)
492 soundscape_waveirq = 9;
493
494 if (get_ini_config_entry("DMA", str, sizeof(str), fp)) {
495 fclose(fp);
496 return FALSE;
497 }
498
499 soundscape_dma = strtol(str, NULL, 10);
500
501 fclose(fp);
502 return TRUE;
503 }
504
505
506
507 /* detect_soundscape:
508 * This function is used to detect the presence of a Soundscape card in a
509 * system. It will read the hardware config info from the SNDSCAPE.INI file,
510 * the path to which is indicated by the SNDSCAPE environment variable. This
511 * config info will be stored in global variable space for the other driver
512 * functions to reference. Once the config settings have been determined, a
513 * hardware test will be performed to see if the Soundscape card is actually
514 * present. If this function is not explicitly called by the application, it
515 * it will be called by the OpenSoundscape function.
516 */
detect_soundscape(void)517 static int detect_soundscape(void)
518 {
519 int tmp;
520
521 if (!get_init_config())
522 return FALSE;
523
524 /* see if Soundscape is there by reading HW ... */
525 if ((inportb(soundscape_baseport + GA_HOSTCTL_OFF) & 0x78) != 0x00)
526 return FALSE;
527
528 if ((inportb(soundscape_baseport + GA_ADDR_OFF) & 0xF0) == 0xF0)
529 return FALSE;
530
531 outportb(soundscape_baseport + GA_ADDR_OFF, 0xF5);
532 tmp = inportb(soundscape_baseport + GA_ADDR_OFF);
533
534 if ((tmp & 0xF0) == 0xF0)
535 return FALSE;
536
537 if ((tmp & 0x0F) != 0x05)
538 return FALSE;
539
540 /* formulate the chip ID */
541 if ((tmp & 0x80) != 0x00)
542 soundscape_hw_ver = MMIC;
543 else if ((tmp & 0x70) != 0x00)
544 soundscape_hw_ver = OPUS;
545 else
546 soundscape_hw_ver = ODIE;
547
548 /* now do a quick check to make sure the CoDec is there too */
549 if ((inportb(soundscape_waveport) & 0x80) != 0x00)
550 return FALSE;
551
552 soundscape_detected = TRUE;
553 return TRUE;
554 }
555
556
557
558 /* soundscape_set_mixer_volume:
559 * Sets the Soundscape mixer volume for playing digital samples.
560 */
soundscape_set_mixer_volume(int volume)561 static int soundscape_set_mixer_volume(int volume)
562 {
563 if (volume >= 0)
564 set_dac_vol(volume, volume);
565
566 return 0;
567 }
568
569
570
571 /* soundscape_interrupt:
572 * The Soundscape end-of-buffer interrupt handler.
573 */
soundscape_interrupt(void)574 static int soundscape_interrupt(void)
575 {
576 /* if the CoDec is interrupting ... */
577 if (inportb(soundscape_waveport + CD_STATUS_OFF) & 0x01) {
578
579 /* clear the AD-1848 interrupt */
580 outportb(soundscape_waveport + CD_STATUS_OFF, 0x00);
581
582 soundscape_dma_count++;
583 if (soundscape_dma_count > 16) {
584 soundscape_bufnum = (_dma_todo(soundscape_dma) > (unsigned)soundscape_dma_size) ? 1 : 0;
585 soundscape_dma_count = 0;
586 }
587
588 if (!(soundscape_semaphore)) {
589 soundscape_semaphore = TRUE;
590
591 /* mix some more samples */
592 ENABLE();
593 _mix_some_samples(soundscape_buf[soundscape_bufnum], _dos_ds, TRUE);
594 DISABLE();
595
596 soundscape_semaphore = FALSE;
597 }
598
599 soundscape_bufnum = 1 - soundscape_bufnum;
600 }
601
602 /* acknowledge interrupt */
603 _eoi(soundscape_waveirq);
604 return 0;
605 }
606
607 END_OF_STATIC_FUNCTION(soundscape_interrupt);
608
609
610
611 /* soundscape_detect:
612 * This function is used to detect the presence of a Soundscape card.
613 */
soundscape_detect(int input)614 static int soundscape_detect(int input)
615 {
616 char tmp[64];
617
618 /* input isn't supported yet */
619 if (input)
620 return FALSE;
621
622 if (!detect_soundscape()) {
623 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Soundscape not found"));
624 return FALSE;
625 }
626
627 /* figure out the hardware interrupt number */
628 soundscape_int = _map_irq(soundscape_waveirq);
629
630 /* get desired frequency from _sound variable */
631 soundscape_freq = _sound_freq;
632 if (soundscape_freq == -1)
633 soundscape_freq = 48000;
634
635 /* adjust SB-frequencies for this CoDec */
636 if (soundscape_freq < 12000) /* 11906 -> 11025 */
637 soundscape_freq = 11025;
638 else if (soundscape_freq < 18000) /* 16129 -> 16000 */
639 soundscape_freq = 16000;
640 else if (soundscape_freq < 24000) /* 22727 -> 22050 */
641 soundscape_freq = 22050;
642 else /* 45454 -> 48000 */
643 soundscape_freq = 48000;
644
645 /* set up the card description */
646 uszprintf(soundscape_desc, sizeof(soundscape_desc),
647 get_config_text("Soundscape %s (%d hz) on port %X, using IRQ %d, DMA channel %d and waveport %X"),
648 uconvert_ascii(ensoniq_gate_array[soundscape_hw_ver], tmp),
649 soundscape_freq, soundscape_baseport, soundscape_waveirq, soundscape_dma, soundscape_waveport);
650
651 digi_soundscape.desc = soundscape_desc;
652
653 return TRUE;
654 }
655
656
657
658 /* soundscape_init:
659 * This function opens the Soundscape driver. It will setup the Soundscape
660 * hardware for Native PCM mode.
661 */
soundscape_init(int input,int voices)662 static int soundscape_init(int input, int voices)
663 {
664 int windx, mindx, tmp;
665
666 /* see if we need to detect first */
667 if (!soundscape_detected)
668 if (!soundscape_detect(0))
669 return -1;
670
671 /* set DMA controller register set pointer based on channel */
672 dmac_reg_p = &dmac_regs[soundscape_dma];
673
674 /* in case the CoDec is running, stop it */
675 stop_codec();
676
677 /* clear possible CoDec and SoundBlaster emulation interrupts */
678 outportb(soundscape_waveport + CD_STATUS_OFF, 0x00);
679 inportb(0x22E);
680
681 /* input isn't supported yet, don't init twice without exit */
682 if ((input) || (soundscape_enabled))
683 return -1;
684
685 /* set format, always stereo, 16 bit */
686 set_format(soundscape_freq, 1, 1, 0);
687
688 if (_dma_allocate_mem(soundscape_dma_size * 2, &soundscape_sel, &soundscape_buf[0]) != 0)
689 return -1;
690
691 soundscape_mem_allocated = TRUE;
692
693 soundscape_buf[1] = soundscape_buf[0] + soundscape_dma_size;
694
695 soundscape_lock_mem();
696
697 digi_soundscape.voices = voices;
698
699 if (_mixer_init(soundscape_dma_size/2, soundscape_freq, TRUE, TRUE, &digi_soundscape.voices) != 0) {
700 soundscape_exit(0);
701 return -1;
702 }
703
704 _mix_some_samples(soundscape_buf[0], _dos_ds, TRUE);
705 _mix_some_samples(soundscape_buf[1], _dos_ds, TRUE);
706 soundscape_bufnum = 0;
707
708 _enable_irq(soundscape_waveirq);
709 _install_irq(soundscape_int, soundscape_interrupt);
710
711 if (soundscape_hw_ver != MMIC) {
712 /* derive the MIDI and Wave IRQ indices (0-3) for reg writes */
713 for (mindx=0; mindx<4; mindx++)
714 if (soundscape_midiirq == *(soundscape_irqset + mindx))
715 break;
716
717 for (windx=0; windx<4; windx++)
718 if (soundscape_waveirq == *(soundscape_irqset + windx))
719 break;
720
721 /* setup the CoDec DMA polarity */
722 ga_write(GA_DMACFG_REG, 0x50);
723
724 /* give the CoDec control of the DMA and Wave IRQ resources */
725 cd_cfg_save = ga_read(GA_CDCFG_REG);
726 ga_write(GA_CDCFG_REG, 0x89 | (soundscape_dma << 4) | (windx << 1));
727
728 /* pull the Sound Blaster emulation off of those resources */
729 dma_cfg_save = ga_read(GA_DMAB_REG);
730 ga_write(GA_DMAB_REG, 0x20);
731 int_cfg_save = ga_read(GA_INTCFG_REG);
732 ga_write(GA_INTCFG_REG, 0xF0 | (mindx << 2) | mindx);
733 }
734
735 /* save all volumes that we might use */
736 dac_save_l = cd_read(CD_DACL_REG);
737 dac_save_r = cd_read(CD_DACR_REG);
738 cdx_save_l = cd_read(CD_CDAUXL_REG);
739 cdx_save_r = cd_read(CD_CDAUXL_REG);
740 adc_save_l = cd_read(CD_ADCL_REG);
741 adc_save_r = cd_read(CD_ADCR_REG);
742
743 set_dac_vol(127, 127);
744
745 /* select the mic/line input to the record mux */
746 /* if not ODIE, set the mic gain bit too */
747 cd_write(CD_ADCL_REG, (cd_read(CD_ADCL_REG) & 0x3F) | (soundscape_hw_ver == ODIE ? 0x80 : 0xA0));
748 cd_write(CD_ADCR_REG, (cd_read(CD_ADCR_REG) & 0x3F) | (soundscape_hw_ver == ODIE ? 0x80 : 0xA0));
749
750 /* put the CoDec into mode change state */
751 CODEC_MODE_CHANGE_ON();
752
753 /* setup CoDec mode - single DMA chan, AutoCal on */
754 cd_write(CD_CONFIG_REG, 0x0c);
755
756 ENABLE_CODEC_IRQ();
757
758 _dma_start(soundscape_dma, soundscape_buf[0], soundscape_dma_size * 2, TRUE, FALSE) ;
759
760 /* write the CoDec interrupt count - sample frames per half-buffer. */
761 tmp = soundscape_dma_size / 4 - 1;
762 cd_write(CD_LCOUNT_REG, tmp);
763 cd_write(CD_UCOUNT_REG, tmp >> 8);
764
765 CODEC_MODE_CHANGE_OFF();
766
767 /* start the CoDec for output */
768 resume_codec(0);
769 rest(100);
770
771 soundscape_enabled = TRUE;
772
773 return 0;
774 }
775
776
777
778 /* soundscape_exit:
779 * Soundscape driver cleanup routine, removes ints, stops dma,
780 * frees buffers, etc.
781 */
soundscape_exit(int input)782 static void soundscape_exit(int input)
783 {
784 if (soundscape_enabled) {
785
786 /* in case the CoDec is running, stop it */
787 stop_codec();
788
789 /* stop dma transfer */
790 _dma_stop(soundscape_dma);
791
792 /* disable the CoDec interrupt pin */
793 DISABLE_CODEC_IRQ();
794
795 /* restore all volumes ... */
796 cd_write(CD_DACL_REG, dac_save_l);
797 cd_write(CD_DACR_REG, dac_save_r);
798 cd_write(CD_CDAUXL_REG, cdx_save_l);
799 cd_write(CD_CDAUXL_REG, cdx_save_r);
800 cd_write(CD_ADCL_REG, adc_save_l);
801 cd_write(CD_ADCR_REG, adc_save_r);
802
803 /* if necessary, restore gate array resource registers */
804 if (soundscape_hw_ver != MMIC) {
805 ga_write(GA_INTCFG_REG, int_cfg_save);
806 ga_write(GA_DMAB_REG, dma_cfg_save);
807 ga_write(GA_CDCFG_REG, cd_cfg_save);
808 }
809
810 _remove_irq(soundscape_int); /* restore interrupts */
811 _restore_irq(soundscape_waveirq); /* reset PIC channels */
812 }
813
814 if (soundscape_mem_allocated)
815 __dpmi_free_dos_memory(soundscape_sel); /* free DMA memory buffer */
816
817 _mixer_exit();
818 soundscape_hw_ver = -1;
819 soundscape_detected = FALSE;
820 soundscape_detected = FALSE;
821 soundscape_enabled = FALSE;
822 }
823
824
825
826 /* soundscape_lock_mem:
827 * Locks all the memory touched by parts of the Soundscape code that are
828 * executed in an interrupt context.
829 */
soundscape_lock_mem(void)830 static void soundscape_lock_mem(void)
831 {
832 LOCK_VARIABLE(digi_soundscape);
833 LOCK_VARIABLE(soundscape_freq);
834 LOCK_VARIABLE(soundscape_baseport);
835 LOCK_VARIABLE(soundscape_waveport);
836 LOCK_VARIABLE(soundscape_dma);
837 LOCK_VARIABLE(soundscape_midiirq);
838 LOCK_VARIABLE(soundscape_waveirq);
839 LOCK_VARIABLE(soundscape_int);
840 LOCK_VARIABLE(soundscape_hw_ver);
841 LOCK_VARIABLE(soundscape_dma_size);
842 LOCK_VARIABLE(soundscape_sel);
843 LOCK_VARIABLE(soundscape_buf);
844 LOCK_VARIABLE(soundscape_bufnum);
845 LOCK_VARIABLE(soundscape_dma_count);
846 LOCK_VARIABLE(soundscape_semaphore);
847 LOCK_FUNCTION(soundscape_interrupt);
848
849 _dma_lock_mem();
850 }
851
852