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