1 /*
2 ReactOS Sound System
3 Sound Blaster DSP support
4 Mixer routines
5
6 Author:
7 Andrew Greenwood (silverblade@reactos.org)
8
9 History:
10 2 July 2008 - Created
11
12 Notes:
13 Functions documented in sbdsp.h
14
15 Currently, input/output switches and PC speaker volume
16 level are not supported.
17
18 The I/O switches are used for muting/unmuting mic, etc.
19 */
20
21 #include "precomp.h"
22
23 VOID
SbMixerReset(IN PUCHAR BasePort)24 SbMixerReset(IN PUCHAR BasePort)
25 {
26 WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_RESET);
27 /* Are we meant to send anything else? */
28 }
29
30 NTSTATUS
SbMixerPackLevelData(IN UCHAR Line,IN UCHAR Level,OUT PUCHAR PackedLevel)31 SbMixerPackLevelData(
32 IN UCHAR Line,
33 IN UCHAR Level,
34 OUT PUCHAR PackedLevel)
35 {
36 if ( ! PackedLevel )
37 return STATUS_INVALID_PARAMETER_3;
38
39 switch ( Line )
40 {
41 case SB_MIX_MASTER_LEFT_LEVEL :
42 case SB_MIX_MASTER_RIGHT_LEVEL :
43 case SB_MIX_VOC_LEFT_LEVEL :
44 case SB_MIX_VOC_RIGHT_LEVEL :
45 case SB_MIX_MIDI_LEFT_LEVEL :
46 case SB_MIX_MIDI_RIGHT_LEVEL :
47 case SB_MIX_CD_LEFT_LEVEL :
48 case SB_MIX_CD_RIGHT_LEVEL :
49 case SB_MIX_LINE_LEFT_LEVEL :
50 case SB_MIX_LINE_RIGHT_LEVEL :
51 case SB_MIX_MIC_LEVEL :
52 case SB_MIX_LEGACY_MIC_LEVEL : /* is this correct? */
53 {
54 if ( Level >= 0x20 )
55 return STATUS_INVALID_PARAMETER_2;
56
57 *PackedLevel = Level << 3;
58 return STATUS_SUCCESS;
59 }
60
61 case SB_MIX_INPUT_LEFT_GAIN :
62 case SB_MIX_INPUT_RIGHT_GAIN :
63 case SB_MIX_OUTPUT_LEFT_GAIN :
64 case SB_MIX_OUTPUT_RIGHT_GAIN :
65 {
66 if ( Level >= 0x04 )
67 return STATUS_INVALID_PARAMETER_2;
68
69 *PackedLevel = Level << 6;
70 return STATUS_SUCCESS;
71 }
72
73 case SB_MIX_VOC_LEVEL : /* legacy */
74 case SB_MIX_MASTER_LEVEL :
75 case SB_MIX_FM_LEVEL :
76 case SB_MIX_CD_LEVEL :
77 case SB_MIX_LINE_LEVEL :
78 case SB_MIX_TREBLE_LEFT_LEVEL : /* bass/treble */
79 case SB_MIX_TREBLE_RIGHT_LEVEL :
80 case SB_MIX_BASS_LEFT_LEVEL :
81 case SB_MIX_BASS_RIGHT_LEVEL :
82 {
83 if ( Level >= 0x10 )
84 return STATUS_INVALID_PARAMETER_2;
85
86 *PackedLevel = Level << 4;
87 return STATUS_SUCCESS;
88 }
89
90 default :
91 return STATUS_INVALID_PARAMETER_1;
92 };
93 }
94
95 NTSTATUS
SbMixerUnpackLevelData(IN UCHAR Line,IN UCHAR PackedLevel,OUT PUCHAR Level)96 SbMixerUnpackLevelData(
97 IN UCHAR Line,
98 IN UCHAR PackedLevel,
99 OUT PUCHAR Level)
100 {
101 if ( ! Level )
102 return STATUS_INVALID_PARAMETER_3;
103
104 switch ( Line )
105 {
106 case SB_MIX_MASTER_LEFT_LEVEL :
107 case SB_MIX_MASTER_RIGHT_LEVEL :
108 case SB_MIX_VOC_LEFT_LEVEL :
109 case SB_MIX_VOC_RIGHT_LEVEL :
110 case SB_MIX_MIDI_LEFT_LEVEL :
111 case SB_MIX_MIDI_RIGHT_LEVEL :
112 case SB_MIX_CD_LEFT_LEVEL :
113 case SB_MIX_CD_RIGHT_LEVEL :
114 case SB_MIX_LINE_LEFT_LEVEL :
115 case SB_MIX_LINE_RIGHT_LEVEL :
116 case SB_MIX_MIC_LEVEL :
117 {
118 *Level = PackedLevel >> 3;
119 return STATUS_SUCCESS;
120 }
121
122 case SB_MIX_INPUT_LEFT_GAIN :
123 case SB_MIX_INPUT_RIGHT_GAIN :
124 case SB_MIX_OUTPUT_LEFT_GAIN :
125 case SB_MIX_OUTPUT_RIGHT_GAIN :
126 {
127 *Level = PackedLevel >> 6;
128 return STATUS_SUCCESS;
129 }
130
131 case SB_MIX_VOC_LEVEL : /* legacy */
132 case SB_MIX_MASTER_LEVEL :
133 case SB_MIX_FM_LEVEL :
134 case SB_MIX_CD_LEVEL :
135 case SB_MIX_LINE_LEVEL :
136 case SB_MIX_TREBLE_LEFT_LEVEL : /* bass/treble */
137 case SB_MIX_TREBLE_RIGHT_LEVEL :
138 case SB_MIX_BASS_LEFT_LEVEL :
139 case SB_MIX_BASS_RIGHT_LEVEL :
140 {
141 *Level = PackedLevel >> 4;
142 return STATUS_SUCCESS;
143 }
144
145 default :
146 return STATUS_INVALID_PARAMETER_1;
147 };
148 }
149
150 NTSTATUS
SbMixerSetLevel(IN PUCHAR BasePort,IN UCHAR Line,IN UCHAR Level)151 SbMixerSetLevel(
152 IN PUCHAR BasePort,
153 IN UCHAR Line,
154 IN UCHAR Level)
155 {
156 UCHAR PackedLevel = 0;
157 NTSTATUS Status;
158
159 Status = SbMixerPackLevelData(Line, Level, &PackedLevel);
160
161 switch ( Status )
162 {
163 case STATUS_SUCCESS :
164 break;
165
166 case STATUS_INVALID_PARAMETER_1 :
167 return STATUS_INVALID_PARAMETER_2;
168
169 case STATUS_INVALID_PARAMETER_2 :
170 return STATUS_INVALID_PARAMETER_3;
171
172 default :
173 return Status;
174 };
175
176 DbgPrint("SbMixerSetLevel: Line 0x%x, raw level 0x%x, packed 0x%x\n", Line, Level, PackedLevel);
177
178 WRITE_SB_MIXER_REGISTER(BasePort, Line);
179 WRITE_SB_MIXER_DATA(BasePort, PackedLevel);
180
181 return STATUS_SUCCESS;
182 }
183
184 NTSTATUS
SbMixerGetLevel(IN PUCHAR BasePort,IN UCHAR Line,OUT PUCHAR Level)185 SbMixerGetLevel(
186 IN PUCHAR BasePort,
187 IN UCHAR Line,
188 OUT PUCHAR Level)
189 {
190 UCHAR PackedLevel = 0;
191 NTSTATUS Status;
192
193 if ( ! Level )
194 return STATUS_INVALID_PARAMETER_3;
195
196 WRITE_SB_MIXER_REGISTER(BasePort, Line);
197 PackedLevel = READ_SB_MIXER_DATA(BasePort);
198
199 Status = SbMixerUnpackLevelData(Line, PackedLevel, Level);
200
201 switch ( Status )
202 {
203 case STATUS_SUCCESS :
204 break;
205
206 case STATUS_INVALID_PARAMETER_1 :
207 return STATUS_INVALID_PARAMETER_2;
208
209 case STATUS_INVALID_PARAMETER_2 :
210 return STATUS_INVALID_PARAMETER_3;
211
212 default :
213 return Status;
214 };
215
216 DbgPrint("SbMixerGetLevel: Line 0x%x, raw level 0x%x, packed 0x%x\n", Line, Level, PackedLevel);
217
218 return STATUS_SUCCESS;
219 }
220
221 VOID
SbMixerEnableAGC(IN PUCHAR BasePort)222 SbMixerEnableAGC(IN PUCHAR BasePort)
223 {
224 /* Untested... */
225 WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
226 WRITE_SB_MIXER_DATA(BasePort, 1);
227 }
228
229 VOID
SbMixerDisableAGC(IN PUCHAR BasePort)230 SbMixerDisableAGC(IN PUCHAR BasePort)
231 {
232 /* Untested... */
233 WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
234 WRITE_SB_MIXER_DATA(BasePort, 0);
235 }
236
237 BOOLEAN
SbMixerIsAGCEnabled(IN PUCHAR BasePort)238 SbMixerIsAGCEnabled(IN PUCHAR BasePort)
239 {
240 /* Untested... */
241 WRITE_SB_MIXER_REGISTER(BasePort, SB_MIX_AGC);
242 return (READ_SB_MIXER_DATA(BasePort) != 0);
243 }
244