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