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