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
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
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
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
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
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
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
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
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