1 #include <sndblst.h>
2
3 /*
4 TODO: MmMapIoSpace()
5 */
6
7 /*
8 This checks the read or write status port of the device.
9 */
10
11 BOOLEAN
WaitForReady(PSOUND_BLASTER_PARAMETERS SBDevice,UCHAR Port)12 WaitForReady(
13 PSOUND_BLASTER_PARAMETERS SBDevice,
14 UCHAR Port)
15 {
16 ULONG timeout = SB_TIMEOUT;
17 BOOL ready = FALSE;
18
19 while ( ( ! ready ) && ( timeout > 0 ) )
20 {
21 if ( SbRead(SBDevice, Port) & 0x80 )
22 return TRUE;
23
24 timeout --;
25 }
26
27 return FALSE;
28 }
29
30 BOOLEAN
SbWriteData(PSOUND_BLASTER_PARAMETERS SBDevice,UCHAR Data)31 SbWriteData(
32 PSOUND_BLASTER_PARAMETERS SBDevice,
33 UCHAR Data)
34 {
35 if ( ! WaitToWrite(SBDevice) )
36 return FALSE;
37
38 DPRINT("Writing 0x%x to Sound Blaster card (data)\n", Data);
39 SbWrite(SBDevice, SB_WRITE_DATA_PORT, Data);
40
41 return TRUE;
42 }
43
44 BOOLEAN
SbReadData(PSOUND_BLASTER_PARAMETERS SBDevice,PUCHAR Data)45 SbReadData(
46 PSOUND_BLASTER_PARAMETERS SBDevice,
47 PUCHAR Data)
48 {
49 if ( ! WaitToWrite(SBDevice) )
50 return FALSE;
51
52 *Data = SbRead(SBDevice, SB_READ_DATA_PORT);
53 DPRINT("Read 0x%x from Sound Blaster card (data)\n", *Data);
54
55 return TRUE;
56 }
57
58 BOOLEAN
ResetSoundBlaster(PSOUND_BLASTER_PARAMETERS SBDevice)59 ResetSoundBlaster(
60 PSOUND_BLASTER_PARAMETERS SBDevice)
61 {
62 BOOLEAN acked = FALSE;
63 ULONG timeout;
64
65 SbWriteReset(SBDevice, 0x01);
66 for (timeout = 0; timeout < 30000; timeout ++ );
67 SbWriteReset(SBDevice, 0x00);
68
69 DPRINT("Waiting for SB to acknowledge our reset request\n");
70
71 if ( ! WaitToRead(SBDevice) )
72 {
73 DPRINT("Didn't get an ACK :(\n");
74 return FALSE;
75 }
76
77 timeout = 0;
78
79 while ( ( ! acked ) && ( timeout < SB_TIMEOUT ) )
80 {
81 acked = ( SbReadDataWithoutWait(SBDevice) == SB_DSP_READY );
82 timeout ++;
83 }
84
85 if ( ! acked )
86 {
87 DPRINT("Didn't get an ACK :(\n");
88 return FALSE;
89 }
90
91 return TRUE;
92 }
93
94 ULONG
GetSoundBlasterModel(PSOUND_BLASTER_PARAMETERS SBDevice)95 GetSoundBlasterModel(
96 PSOUND_BLASTER_PARAMETERS SBDevice)
97 {
98 UCHAR MajorVer, MinorVer;
99
100 DPRINT("Querying DSP version\n");
101
102 if ( ! SbWriteData(SBDevice, SbGetDspVersion) )
103 return NotDetected;
104
105 if ( ! WaitToRead(SBDevice) )
106 return NotDetected;
107
108 if ( SbReadData(SBDevice, &MajorVer) )
109 {
110 if ( SbReadData(SBDevice, &MinorVer) )
111 {
112 DPRINT("Version %d.%d\n", MajorVer, MinorVer);
113
114 SBDevice->dsp_version = (MajorVer * 256) + MinorVer;
115
116 if ( SBDevice->dsp_version < 0x0200 )
117 return SoundBlaster;
118 else if ( ( SBDevice->dsp_version & 0xFF00 ) == 0x0200 )
119 return SoundBlaster2;
120 else if ( ( SBDevice->dsp_version & 0xFF00 ) == 0x0300 )
121 return SoundBlasterPro;
122 else if ( SBDevice->dsp_version >= 0x0400 )
123 return SoundBlaster16;
124
125 return NotDetected;
126 }
127 }
128
129 return NotDetected;
130 }
131
132
133 BOOLEAN
IsSampleRateCompatible(PSOUND_BLASTER_PARAMETERS SBDevice,ULONG SampleRate)134 IsSampleRateCompatible(
135 PSOUND_BLASTER_PARAMETERS SBDevice,
136 ULONG SampleRate)
137 {
138 /* TODO */
139 return TRUE;
140 }
141
142 BOOLEAN
SetOutputSampleRate(PSOUND_BLASTER_PARAMETERS SBDevice,ULONG SampleRate)143 SetOutputSampleRate(
144 PSOUND_BLASTER_PARAMETERS SBDevice,
145 ULONG SampleRate)
146 {
147 /* Only works for DSP v4.xx */
148 DPRINT("Setting sample rate\n");
149
150 SbWriteData(SBDevice, SbSetOutputRate);
151 SbWriteData(SBDevice, SampleRate / 256);
152 SbWriteData(SBDevice, SampleRate % 256);
153
154 return TRUE;
155 }
156
157 BOOLEAN
EnableSpeaker(PSOUND_BLASTER_PARAMETERS SBDevice)158 EnableSpeaker(
159 PSOUND_BLASTER_PARAMETERS SBDevice)
160 {
161 DPRINT("Enabling speaker\n");
162
163 return SbWriteData(SBDevice, SbEnableSpeaker);
164 }
165
166 BOOLEAN
DisableSpeaker(PSOUND_BLASTER_PARAMETERS SBDevice)167 DisableSpeaker(
168 PSOUND_BLASTER_PARAMETERS SBDevice)
169 {
170 DPRINT("Disabling speaker\n");
171
172 return SbWriteData(SBDevice, SbDisableSpeaker);
173 }
174
175 BOOLEAN
StartSoundOutput(PSOUND_BLASTER_PARAMETERS SBDevice,ULONG BitDepth,ULONG Channels,ULONG BlockSize)176 StartSoundOutput(
177 PSOUND_BLASTER_PARAMETERS SBDevice,
178 ULONG BitDepth,
179 ULONG Channels,
180 ULONG BlockSize)
181 {
182 DPRINT("Initializing output with %d channels at %d bits/sample\n", Channels, BitDepth);
183
184 UCHAR command = 0xc6, mode = 0x00;
185
186 if ( ( Channels < 1 ) || ( Channels > 2 ) )
187 return FALSE;
188
189 if ( ( BitDepth != 8 ) && ( BitDepth != 16 ) )
190 return FALSE;
191
192 switch ( BitDepth )
193 {
194 case 8 : command = 0xc6; break;
195 case 16 : command = 0xb6; break;
196 };
197
198 switch ( Channels )
199 {
200 case 1 : mode = 0x00; break;
201 case 2 : mode = 0x20; break;
202 }
203 #if 0
204 first_byte = (BitDepth == 16) ? 0xb6 : 0xc6;
205 second_byte = (Channels == 1) ? 0x20 : 0x00;
206 #endif
207
208 if ( SBDevice->dsp_version < 0x0400 )
209 {
210 /* TODO: Additional programming required */
211 }
212
213 /* Send freq */
214 SbWriteData(SBDevice, command);
215 SbWriteData(SBDevice, mode);
216 SbWriteData(SBDevice, BlockSize % 256);
217 SbWriteData(SBDevice, BlockSize / 256);
218
219 DPRINT("Finished programming the DSP\n");
220
221 return TRUE;
222 }
223