1 /*
2  *  Copyright (C) 2002-2018  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (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.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #include "dosbox.h"
20 #include "inout.h"
21 #include "mixer.h"
22 #include "mem.h"
23 #include "hardware.h"
24 #include "setup.h"
25 #include "support.h"
26 #include "pic.h"
27 #include <cstring>
28 #include <math.h>
29 
30 #include "mame/emu.h"
31 #include "mame/saa1099.h"
32 
33 #define MASTER_CLOCK 7159090
34 
35 //My mixer channel
36 static MixerChannel * cms_chan;
37 //Timer to disable the channel after a while
38 static Bit32u lastWriteTicks;
39 static Bit32u cmsBase;
40 static saa1099_device* device[2];
41 
write_cms(Bitu port,Bitu val,Bitu)42 static void write_cms(Bitu port, Bitu val, Bitu /* iolen */) {
43 	if(cms_chan && (!cms_chan->enabled)) cms_chan->Enable(true);
44 	lastWriteTicks = PIC_Ticks;
45 	switch ( port - cmsBase ) {
46 	case 1:
47 		device[0]->control_w(0, 0, val);
48 		break;
49 	case 0:
50 		device[0]->data_w(0, 0, val);
51 		break;
52 	case 3:
53 		device[1]->control_w(0, 0, val);
54 		break;
55 	case 2:
56 		device[1]->data_w(0, 0, val);
57 		break;
58 	}
59 }
60 
CMS_CallBack(Bitu len)61 static void CMS_CallBack(Bitu len) {
62 	enum {
63 		BUFFER_SIZE = 2048
64 	};
65 
66 	if ( len > BUFFER_SIZE )
67 		return;
68 
69 	if ( cms_chan ) {
70 
71 		//Have there been 10 seconds of no commands, disable channel
72 		if ( lastWriteTicks + 10000 < PIC_Ticks ) {
73 			cms_chan->Enable( false );
74 			return;
75 		}
76 		Bit32s result[BUFFER_SIZE][2];
77 		Bit16s work[2][BUFFER_SIZE];
78 		Bit16s* buffers[2] = { work[0], work[1] };
79 		device_sound_interface::sound_stream stream;
80 		device[0]->sound_stream_update(stream, 0, buffers, len);
81 		for (Bitu i = 0; i < len; i++) {
82 			result[i][0] = work[0][i];
83 			result[i][1] = work[1][i];
84 		}
85 		device[1]->sound_stream_update(stream, 0, buffers, len);
86 		for (Bitu i = 0; i < len; i++) {
87 			result[i][0] += work[0][i];
88 			result[i][1] += work[1][i];
89 		}
90 		cms_chan->AddSamples_s32( len, result[0] );
91 	}
92 }
93 
94 // The Gameblaster detection
95 static Bit8u cms_detect_register = 0xff;
96 
write_cms_detect(Bitu port,Bitu val,Bitu)97 static void write_cms_detect(Bitu port, Bitu val, Bitu /* iolen */) {
98 	switch ( port - cmsBase ) {
99 	case 0x6:
100 	case 0x7:
101 		cms_detect_register = val;
102 		break;
103 	}
104 }
105 
read_cms_detect(Bitu port,Bitu)106 static Bitu read_cms_detect(Bitu port, Bitu /* iolen */) {
107 	Bit8u retval = 0xff;
108 	switch ( port - cmsBase ) {
109 	case 0x4:
110 		retval = 0x7f;
111 		break;
112 	case 0xa:
113 	case 0xb:
114 		retval = cms_detect_register;
115 		break;
116 	}
117 	return retval;
118 }
119 
120 
121 class CMS:public Module_base {
122 private:
123 	IO_WriteHandleObject WriteHandler;
124 	IO_WriteHandleObject DetWriteHandler;
125 	IO_ReadHandleObject DetReadHandler;
126 	MixerObject MixerChan;
127 
128 public:
CMS(Section * configuration)129 	CMS(Section* configuration):Module_base(configuration) {
130 		Section_prop * section = static_cast<Section_prop *>(configuration);
131 		Bitu sampleRate = section->Get_int( "oplrate" );
132 		cmsBase = section->Get_hex("sbbase");
133 		WriteHandler.Install( cmsBase, write_cms, IO_MB, 4 );
134 
135 		// A standalone Gameblaster has a magic chip on it which is
136 		// sometimes used for detection.
137 		const char * sbtype=section->Get_string("sbtype");
138 		if (!strcasecmp(sbtype,"gb")) {
139 			DetWriteHandler.Install( cmsBase + 4, write_cms_detect, IO_MB, 12 );
140 			DetReadHandler.Install(cmsBase,read_cms_detect,IO_MB,16);
141 		}
142 
143 		/* Register the Mixer CallBack */
144 		cms_chan = MixerChan.Install(CMS_CallBack,sampleRate,"CMS");
145 
146 		lastWriteTicks = PIC_Ticks;
147 
148 		Bit32u freq = 7159000;		//14318180 isa clock / 2
149 
150 		machine_config config;
151 		device[0] = new saa1099_device(config, "", 0, 7159090);
152 		device[1] = new saa1099_device(config, "", 0, 7159090);
153 
154 		device[0]->device_start();
155 		device[1]->device_start();
156 	}
157 
~CMS()158 	~CMS() {
159 		cms_chan = 0;
160 		delete device[0];
161 		delete device[1];
162 	}
163 };
164 
165 
166 static CMS* test;
167 
CMS_Init(Section * sec)168 void CMS_Init(Section* sec) {
169 	test = new CMS(sec);
170 }
CMS_ShutDown(Section * sec)171 void CMS_ShutDown(Section* sec) {
172 	delete test;
173 }
174