Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 1
/*
2
Copyright (C) 1996-1997 Id Software, Inc.
3
 
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version 2
7
of the License, or (at your option) any later version.
8
 
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
 
13
See the 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
#include "quakedef.h"
22
#include "dosisms.h"
23
 
24
int BLASTER_GetDMAPos(void);
25
 
26
/*
27
===============================================================================
28
GUS SUPPORT
29
 
30
===============================================================================
31
*/
32
 
33
qboolean GUS_Init (void);
34
int GUS_GetDMAPos (void);
35
void GUS_Shutdown (void);
36
 
37
 
38
/*
39
===============================================================================
40
 
41
BLASTER SUPPORT
42
 
43
===============================================================================
44
*/
45
 
46
short *dma_buffer=0;
47
static int dma_size;
48
static	int dma;
49
 
50
static	int dsp_port;
51
static	int irq;
52
static	int low_dma;
53
static	int high_dma;
54
static	int mixer_port;
55
static	int mpu401_port;
56
 
57
int dsp_version;
58
int dsp_minor_version;
59
 
60
int timeconstant=-1;
61
 
62
 
63
void PrintBits (byte b)
64
{
65
	int	i;
66
	char	str[9];
67
 
68
	for (i=0 ; i<8 ; i++)
69
		str[i] = '0' + ((b & (1<<(7-i))) > 0);
70
 
71
	str[8] = 0;
72
	Con_Printf ("%s (%i)", str, b);
73
}
74
 
75
void SB_Info_f(void)
76
{
77
	Con_Printf ("BLASTER=%s\n", getenv("BLASTER"));
78
	Con_Printf("dsp version=%d.%d\n", dsp_version, dsp_minor_version);
79
	Con_Printf("dma=%d\n", dma);
80
	if (timeconstant != -1)
81
		Con_Printf("timeconstant=%d\n", timeconstant);
82
	Con_Printf("dma position:%i\n", BLASTER_GetDMAPos ());
83
}
84
 
85
// =======================================================================
86
// Interprets BLASTER variable
87
// =======================================================================
88
 
89
int GetBLASTER(void)
90
{
91
	char *BLASTER;
92
	char *param;
93
 
94
	BLASTER = getenv("BLASTER");
95
	if (!BLASTER)
96
		return 0;
97
 
98
	param = strchr(BLASTER, 'A');
99
	if (!param)
100
		param = strchr(BLASTER, 'a');
101
	if (!param)
102
		return 0;
103
	sscanf(param+1, "%x", &dsp_port);
104
 
105
	param = strchr(BLASTER, 'I');
106
	if (!param)
107
		param = strchr(BLASTER, 'i');
108
	if (!param)
109
		return 0;
110
	sscanf(param+1, "%d", &irq);
111
 
112
	param = strchr(BLASTER, 'D');
113
	if (!param)
114
		param = strchr(BLASTER, 'd');
115
	if (!param)
116
		return 0;
117
	sscanf(param+1, "%d", &low_dma);
118
 
119
	param = strchr(BLASTER, 'H');
120
	if (!param)
121
		param = strchr(BLASTER, 'h');
122
	if (param)
123
		sscanf(param+1, "%d", &high_dma);
124
 
125
	param = strchr(BLASTER, 'M');
126
	if (!param)
127
		param = strchr(BLASTER, 'm');
128
	if (param)
129
		sscanf(param+1, "%x", &mixer_port);
130
	else
131
		mixer_port = dsp_port;
132
 
133
	param = strchr(BLASTER, 'P');
134
	if (!param)
135
		param = strchr(BLASTER, 'p');
136
	if (param)
137
		sscanf(param+1, "%x", &mpu401_port);
138
 
139
	return 1;
140
 
141
}
142
 
143
// ==================================================================
144
// Resets DSP.  Returns 0 on success.
145
// ==================================================================
146
 
147
int ResetDSP(void)
148
{
149
	volatile int i;
150
 
151
	dos_outportb(dsp_port + 6, 1);
152
	for (i=65536 ; i ; i--) ;
153
	dos_outportb(dsp_port + 6, 0);
154
	for (i=65536 ; i ; i--)
155
	{
156
		if (!(dos_inportb(dsp_port + 0xe) & 0x80)) continue;
157
		if (dos_inportb(dsp_port + 0xa) == 0xaa) break;
158
	}
159
	if (i) return 0;
160
	else return 1;
161
 
162
}
163
 
164
int ReadDSP(void)
165
{
166
	while (!(dos_inportb(dsp_port+0xe)&0x80)) ;
167
	return dos_inportb(dsp_port+0xa);
168
}
169
 
170
void WriteDSP(int val)
171
{
172
	while ((dos_inportb(dsp_port+0xc)&0x80)) ;
173
	dos_outportb(dsp_port+0xc, val);
174
}
175
 
176
int ReadMixer(int addr)
177
{
178
	dos_outportb(mixer_port+4, addr);
179
	return dos_inportb(mixer_port+5);
180
}
181
 
182
void WriteMixer(int addr, int val)
183
{
184
	dos_outportb(mixer_port+4, addr);
185
	dos_outportb(mixer_port+5, val);
186
}
187
 
188
int		oldmixervalue;
189
 
190
/*
191
================
192
StartSB
193
 
194
================
195
*/
196
void StartSB(void)
197
{
198
	int		i;
199
 
200
// version 4.xx startup code
201
	if (dsp_version >= 4)
202
	{
203
		Con_Printf("Version 4 SB startup\n");
204
		WriteDSP(0xd1); // turn on speaker
205
 
206
		WriteDSP(0x41);
207
 
208
		WriteDSP(shm->speed>>8);
209
		WriteDSP(shm->speed&0xff);
210
 
211
		WriteDSP(0xb6);	// 16-bit output
212
		WriteDSP(0x30);	// stereo
213
		WriteDSP((shm->samples-1) & 0xff);	// # of samples - 1
214
		WriteDSP((shm->samples-1) >> 8);
215
	}
216
// version 3.xx startup code
217
	else if (dsp_version == 3)
218
	{
219
		Con_Printf("Version 3 SB startup\n");
220
		WriteDSP(0xd1); // turn on speaker
221
 
222
		oldmixervalue = ReadMixer (0xe);
223
		WriteMixer (0xe, oldmixervalue | 0x2);// turn on stereo
224
 
225
		WriteDSP(0x14);			// send one byte
226
		WriteDSP(0x0);
227
		WriteDSP(0x0);
228
 
229
		for (i=0 ; i<0x10000 ; i++)
230
			dos_inportb(dsp_port+0xe);		// ack the dsp
231
 
232
		timeconstant = 65536-(256000000/(shm->channels*shm->speed));
233
		WriteDSP(0x40);
234
		WriteDSP(timeconstant>>8);
235
 
236
		WriteMixer (0xe, ReadMixer(0xe) | 0x20);// turn off filter
237
 
238
		WriteDSP(0x48);
239
		WriteDSP((shm->samples-1) & 0xff);	// # of samples - 1
240
		WriteDSP((shm->samples-1) >> 8);
241
 
242
		WriteDSP(0x90); // high speed 8 bit stereo
243
	}
244
// normal speed mono
245
	else
246
	{
247
		Con_Printf("Version 2 SB startup\n");
248
		WriteDSP(0xd1); // turn on speaker
249
 
250
		timeconstant = 65536-(256000000/(shm->channels*shm->speed));
251
		WriteDSP(0x40);
252
		WriteDSP(timeconstant>>8);
253
 
254
		WriteDSP(0x48);
255
		WriteDSP((shm->samples-1) & 0xff);	// # of samples - 1
256
		WriteDSP((shm->samples-1) >> 8);
257
 
258
		WriteDSP(0x1c); // normal speed 8 bit mono
259
	}
260
}
261
 
262
static int page_reg[] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
263
static int addr_reg[] = { 0, 2, 4, 6, 0xc0, 0xc4, 0xc8, 0xcc };
264
static int count_reg[] = { 1, 3, 5, 7, 0xc2, 0xc6, 0xca, 0xce };
265
 
266
static int mode_reg;
267
static int flipflop_reg;
268
static int disable_reg;
269
static int clear_reg;
270
 
271
/*
272
================
273
StartDMA
274
 
275
================
276
*/
277
void StartDMA(void)
278
{
279
	int mode;
280
	int realaddr;
281
 
282
	realaddr = ptr2real(dma_buffer);
283
 
284
// use a high dma channel if specified
285
	if (high_dma && dsp_version >= 4)	// 8 bit snd can never use 16 bit dma
286
		dma = high_dma;
287
	else
288
		dma = low_dma;
289
 
290
	Con_Printf ("Using DMA channel %i\n", dma);
291
 
292
	if (dma > 3)
293
	{
294
		mode_reg = 0xd6;
295
		flipflop_reg = 0xd8;
296
		disable_reg = 0xd4;
297
		clear_reg = 0xdc;
298
	}
299
	else
300
	{
301
		mode_reg = 0xb;
302
		flipflop_reg = 0xc;
303
		disable_reg = 0xa;
304
		clear_reg = 0xe;
305
	}
306
 
307
	dos_outportb(disable_reg, dma|4);	// disable channel
308
	// set mode- see "undocumented pc", p.876
309
	mode =	(1<<6)	// single-cycle
310
		+(0<<5)		// address increment
311
		+(1<<4)		// auto-init dma
312
		+(2<<2)		// read
313
		+(dma&3);	// channel #
314
	dos_outportb(mode_reg, mode);
315
 
316
// set address
317
	// set page
318
	dos_outportb(page_reg[dma], realaddr >> 16);
319
 
320
	if (dma > 3)
321
	{	// address is in words
322
		dos_outportb(flipflop_reg, 0);		// prepare to send 16-bit value
323
		dos_outportb(addr_reg[dma], (realaddr>>1) & 0xff);
324
		dos_outportb(addr_reg[dma], (realaddr>>9) & 0xff);
325
 
326
		dos_outportb(flipflop_reg, 0);		// prepare to send 16-bit value
327
		dos_outportb(count_reg[dma], ((dma_size>>1)-1) & 0xff);
328
		dos_outportb(count_reg[dma], ((dma_size>>1)-1) >> 8);
329
	}
330
	else
331
	{	// address is in bytes
332
		dos_outportb(flipflop_reg, 0);		// prepare to send 16-bit value
333
		dos_outportb(addr_reg[dma], realaddr & 0xff);
334
		dos_outportb(addr_reg[dma], (realaddr>>8) & 0xff);
335
 
336
		dos_outportb(flipflop_reg, 0);		// prepare to send 16-bit value
337
		dos_outportb(count_reg[dma], (dma_size-1) & 0xff);
338
		dos_outportb(count_reg[dma], (dma_size-1) >> 8);
339
	}
340
 
341
	dos_outportb(clear_reg, 0);		// clear write mask
342
	dos_outportb(disable_reg, dma&~4);
343
}
344
 
345
 
346
/*
347
==================
348
BLASTER_Init
349
 
350
Returns false if nothing is found.
351
==================
352
*/
353
qboolean BLASTER_Init(void)
354
{
355
	int 	size;
356
	int 	realaddr;
357
	int 	rc;
358
	int		p;
359
 
360
	shm = 0;
361
	rc = 0;
362
 
363
//
364
// must have a blaster variable set
365
//
366
	if (!GetBLASTER())
367
	{
368
		Con_NotifyBox (
369
		"The BLASTER environment variable\n"
370
		"is not set, sound effects are\n"
371
		"disabled.  See README.TXT for help.\n"
372
		);
373
		return 0;
374
	}
375
 
376
	if (ResetDSP())
377
	{
378
		Con_Printf("Could not reset SB");
379
		return 0;
380
	}
381
 
382
//
383
// get dsp version
384
//
385
	WriteDSP(0xe1);
386
	dsp_version = ReadDSP();
387
	dsp_minor_version = ReadDSP();
388
 
389
// we need at least v2 for auto-init dma
390
	if (dsp_version < 2)
391
	{
392
		Con_Printf ("Sound blaster must be at least v2.0\n");
393
		return 0;
394
	}
395
 
396
// allow command line parm to set quality down
397
	p = COM_CheckParm ("-dsp");
398
	if (p && p < com_argc - 1)
399
	{
400
		p = Q_atoi (com_argv[p+1]);
401
		if (p < 2 || p > 4)
402
			Con_Printf ("-dsp parameter can only be 2, 3, or 4\n");
403
		else if (p > dsp_version)
404
			Con_Printf ("Can't -dsp %i on v%i hardware\n", p, dsp_version);
405
		else
406
			dsp_version = p;
407
	}
408
 
409
 
410
// everyone does 11khz sampling rate unless told otherwise
411
	shm = &sn;
412
	shm->speed = 11025;
413
	rc = COM_CheckParm("-sspeed");
414
	if (rc)
415
		shm->speed = Q_atoi(com_argv[rc+1]);
416
 
417
// version 4 cards (sb 16) do 16 bit stereo
418
	if (dsp_version >= 4)
419
	{
420
		shm->channels = 2;
421
		shm->samplebits = 16;
422
	}
423
// version 3 cards (sb pro) do 8 bit stereo
424
	else if (dsp_version == 3)
425
	{
426
		shm->channels = 2;
427
		shm->samplebits = 8;
428
	}
429
// v2 cards do 8 bit mono
430
	else
431
	{
432
		shm->channels = 1;
433
		shm->samplebits = 8;
434
	}
435
 
436
 
437
	Cmd_AddCommand("sbinfo", SB_Info_f);
438
	size = 4096;
439
 
440
// allocate 8k and get a 4k-aligned buffer from it
441
	dma_buffer = dos_getmemory(size*2);
442
	if (!dma_buffer)
443
	{
444
		Con_Printf("Couldn't allocate sound dma buffer");
445
		return false;
446
	}
447
 
448
	realaddr = ptr2real(dma_buffer);
449
	realaddr = (realaddr + size) & ~(size-1);
450
	dma_buffer = (short *) real2ptr(realaddr);
451
	dma_size = size;
452
 
453
	memset(dma_buffer, 0, dma_size);
454
 
455
	shm->soundalive = true;
456
	shm->splitbuffer = false;
457
 
458
	shm->samples = size/(shm->samplebits/8);
459
	shm->samplepos = 0;
460
	shm->submission_chunk = 1;
461
	shm->buffer = (unsigned char *) dma_buffer;
462
	shm->samples = size/(shm->samplebits/8);
463
 
464
	StartDMA();
465
	StartSB();
466
 
467
	return true;
468
}
469
 
470
 
471
/*
472
==============
473
BLASTER_GetDMAPos
474
 
475
return the current sample position (in mono samples read)
476
inside the recirculating dma buffer, so the mixing code will know
477
how many sample are required to fill it up.
478
===============
479
*/
480
int BLASTER_GetDMAPos(void)
481
{
482
	int count;
483
 
484
// this function is called often.  acknowledge the transfer completions
485
// all the time so that it loops
486
	if (dsp_version >= 4)
487
		dos_inportb(dsp_port+0xf);	// 16 bit audio
488
	else
489
		dos_inportb(dsp_port+0xe);	// 8 bit audio
490
 
491
// clear 16-bit reg flip-flop
492
// load the current dma count register
493
	if (dma < 4)
494
	{
495
		dos_outportb(0xc, 0);
496
		count = dos_inportb(dma*2+1);
497
		count += dos_inportb(dma*2+1) << 8;
498
		if (shm->samplebits == 16)
499
			count /= 2;
500
		count = shm->samples - (count+1);
501
	}
502
	else
503
	{
504
		dos_outportb(0xd8, 0);
505
		count = dos_inportb(0xc0+(dma-4)*4+2);
506
		count += dos_inportb(0xc0+(dma-4)*4+2) << 8;
507
		if (shm->samplebits == 8)
508
			count *= 2;
509
		count = shm->samples - (count+1);
510
	}
511
 
512
//	Con_Printf("DMA pos = 0x%x\n", count);
513
 
514
	shm->samplepos = count & (shm->samples-1);
515
	return shm->samplepos;
516
 
517
}
518
 
519
/*
520
==============
521
BLASTER_Shutdown
522
 
523
Reset the sound device for exiting
524
===============
525
*/
526
void BLASTER_Shutdown(void)
527
{
528
	if (dsp_version >= 4)
529
	{
530
	}
531
	else if (dsp_version == 3)
532
	{
533
		ResetDSP ();			// stop high speed mode
534
		WriteMixer (0xe, oldmixervalue); // turn stereo off and filter on
535
	}
536
	else
537
	{
538
 
539
	}
540
 
541
	WriteDSP(0xd3); // turn off speaker
542
	ResetDSP ();
543
 
544
	dos_outportb(disable_reg, dma|4);	// disable dma channel
545
}
546
 
547
 
548
 
549
/*
550
===============================================================================
551
 
552
INTERFACE
553
 
554
===============================================================================
555
*/
556
 
557
typedef enum
558
{
559
	dma_none,
560
	dma_blaster,
561
	dma_gus
562
} dmacard_t;
563
 
564
dmacard_t	dmacard;
565
 
566
/*
567
==================
568
SNDDM_Init
569
 
570
Try to find a sound device to mix for.
571
Returns false if nothing is found.
572
Returns true and fills in the "shm" structure with information for the mixer.
573
==================
574
*/
575
qboolean SNDDMA_Init(void)
576
{
577
	if (GUS_Init ())
578
	{
579
		dmacard = dma_gus;
580
		return true;
581
	}
582
	if (BLASTER_Init ())
583
	{
584
		dmacard = dma_blaster;
585
		return true;
586
	}
587
 
588
	dmacard = dma_none;
589
 
590
	return false;
591
}
592
 
593
 
594
/*
595
==============
596
SNDDMA_GetDMAPos
597
 
598
return the current sample position (in mono samples, not stereo)
599
inside the recirculating dma buffer, so the mixing code will know
600
how many sample are required to fill it up.
601
===============
602
*/
603
int SNDDMA_GetDMAPos(void)
604
{
605
	switch (dmacard)
606
	{
607
	case dma_blaster:
608
		return BLASTER_GetDMAPos ();
609
	case dma_gus:
610
		return GUS_GetDMAPos ();
611
	case dma_none:
612
		break;
613
	}
614
 
615
	return 0;
616
}
617
 
618
/*
619
==============
620
SNDDMA_Shutdown
621
 
622
Reset the sound device for exiting
623
===============
624
*/
625
void SNDDMA_Shutdown(void)
626
{
627
	switch (dmacard)
628
	{
629
	case dma_blaster:
630
		BLASTER_Shutdown ();
631
		break;
632
	case dma_gus:
633
		GUS_Shutdown ();
634
		break;
635
	case dma_none:
636
		break;
637
	}
638
 
639
	dmacard = dma_none;
640
	return;
641
}
642
 
643
/*
644
==============
645
SNDDMA_Submit
646
 
647
Send sound to device if buffer isn't really the dma buffer
648
===============
649
*/
650
void SNDDMA_Submit(void)
651
{
652
}
653