Merge freeldr from amd64 branch:
[reactos.git] / reactos / lib / drivers / sound / mmebuddy / devicelist.c
1 /*
2 * PROJECT: ReactOS Sound System "MME Buddy" Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/sound/mmebuddy/devicelist.c
5 *
6 * PURPOSE: Manages lists of sound devices.
7 *
8 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
9 */
10
11 #include <windows.h>
12 #include <mmsystem.h>
13 #include <mmddk.h>
14 #include <ntddsnd.h>
15 #include <sndtypes.h>
16 #include <mmebuddy.h>
17
18 ULONG SoundDeviceCounts[SOUND_DEVICE_TYPES];
19 PSOUND_DEVICE SoundDeviceListHeads[SOUND_DEVICE_TYPES];
20 PSOUND_DEVICE SoundDeviceListTails[SOUND_DEVICE_TYPES];
21
22 /*
23 Handles the allocation and initialisation of a SOUND_DEVICE structure.
24 */
25 MMRESULT
26 AllocateSoundDevice(
27 IN MMDEVICE_TYPE DeviceType,
28 OUT PSOUND_DEVICE* SoundDevice)
29 {
30 PSOUND_DEVICE NewDevice;
31
32 SND_ASSERT( IsValidSoundDeviceType(DeviceType) );
33 SND_ASSERT( SoundDevice );
34
35 SND_TRACE(L"Allocating a SOUND_DEVICE structure\n");
36
37 NewDevice = AllocateStruct(SOUND_DEVICE);
38
39 if ( ! NewDevice )
40 return MMSYSERR_NOMEM;
41
42 NewDevice->Type = DeviceType;
43
44 /* Return the new structure to the caller and report success */
45 *SoundDevice = NewDevice;
46
47 return MMSYSERR_NOERROR;
48 }
49
50 /*
51 Handles the cleanup and freeing of a SOUND_DEVICE structure.
52 */
53 VOID
54 FreeSoundDevice(
55 IN PSOUND_DEVICE SoundDevice)
56 {
57 SND_ASSERT( SoundDevice );
58
59 SND_TRACE(L"Freeing a SOUND_DEVICE structure");
60
61 /* For safety the whole struct gets zeroed */
62 ZeroMemory(SoundDevice, sizeof(SOUND_DEVICE));
63 FreeMemory(SoundDevice);
64 }
65
66 /*
67 Returns the number of devices of the specified type which have been added
68 to the device lists. If an invalid device type is specified, the function
69 returns zero.
70 */
71 ULONG
72 GetSoundDeviceCount(
73 IN MMDEVICE_TYPE DeviceType)
74 {
75 ULONG Index = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
76
77 if ( ! IsValidSoundDeviceType(DeviceType) )
78 {
79 return 0;
80 }
81
82 SND_TRACE(L"Returning a count of %d devices\n", SoundDeviceCounts[Index]);
83 return SoundDeviceCounts[Index];
84 }
85
86 /*
87 Determines if a sound device structure pointer is valid, firstly by
88 ensuring that it is not NULL, and then by checking that the device itself
89 exists in one of the device lists.
90 */
91 BOOLEAN
92 IsValidSoundDevice(
93 IN PSOUND_DEVICE SoundDevice)
94 {
95 UCHAR TypeIndex;
96 PSOUND_DEVICE CurrentDevice;
97
98 if ( ! SoundDevice )
99 return FALSE;
100
101 /* Go through all the device lists */
102 for ( TypeIndex = 0; TypeIndex < SOUND_DEVICE_TYPES; ++ TypeIndex )
103 {
104 CurrentDevice = SoundDeviceListHeads[TypeIndex];
105
106 while ( CurrentDevice )
107 {
108 if ( CurrentDevice == SoundDevice )
109 {
110 /* Found the device */
111 return TRUE;
112 }
113
114 CurrentDevice = CurrentDevice->Next;
115 }
116 }
117
118 /* If we get here, nothing was found */
119 return FALSE;
120 }
121
122 /*
123 Informs the MME-Buddy library that it should take ownership of a device.
124 The DevicePath is typically used for storing a device path (for subsequent
125 opening using CreateFile) but it can be a wide-string representing any
126 information that makes sense to your MME driver implementation.
127
128 MME components which operate solely in user-mode (for example, MIDI
129 loopback devices) won't need to communicate with a kernel-mode device,
130 so in these situations DevicePath is likely to be NULL.
131
132 Upon successful addition to the sound device list, the pointer to the new
133 device's SOUND_DEVICE structure is returned via SoundDevice.
134 */
135 MMRESULT
136 ListSoundDevice(
137 IN MMDEVICE_TYPE DeviceType,
138 IN PVOID Identifier OPTIONAL,
139 OUT PSOUND_DEVICE* SoundDevice OPTIONAL)
140 {
141 MMRESULT Result;
142 PSOUND_DEVICE NewDevice;
143 UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
144
145 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
146
147 Result = AllocateSoundDevice(DeviceType, &NewDevice);
148
149 if ( ! MMSUCCESS(Result) )
150 {
151 SND_ERR(L"Failed to allocate SOUND_DEVICE structure\n");
152 return Result;
153 }
154
155 if ( ! SoundDeviceListHeads[TypeIndex] )
156 {
157 SND_TRACE(L"Putting first entry into device list %d\n", DeviceType);
158 SoundDeviceListHeads[TypeIndex] = NewDevice;
159 SoundDeviceListTails[TypeIndex] = NewDevice;
160 }
161 else
162 {
163 SND_TRACE(L"Putting another entry into device list %d\n", DeviceType);
164 SoundDeviceListTails[TypeIndex]->Next = NewDevice;
165 SoundDeviceListTails[TypeIndex] = NewDevice;
166 }
167
168 /* Add to the count */
169 ++ SoundDeviceCounts[TypeIndex];
170
171 /* Set up the default function table */
172 SetSoundDeviceFunctionTable(NewDevice, NULL);
173
174 /* Set up other members of the structure */
175 NewDevice->Identifier = Identifier;
176 NewDevice->HeadInstance = NULL;
177 NewDevice->TailInstance = NULL;
178
179 /* Fill in the caller's PSOUND_DEVICE */
180 if ( SoundDevice )
181 {
182 *SoundDevice = NewDevice;
183 }
184
185 return MMSYSERR_NOERROR;
186 }
187
188 /*
189 Removes a sound device from the list, and frees the memory associated
190 with its description.
191 */
192 MMRESULT
193 UnlistSoundDevice(
194 IN MMDEVICE_TYPE DeviceType,
195 IN PSOUND_DEVICE SoundDevice)
196 {
197 PSOUND_DEVICE CurrentDevice, PreviousDevice;
198
199 UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
200
201 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
202 VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
203
204 PreviousDevice = NULL;
205 CurrentDevice = SoundDeviceListHeads[TypeIndex];
206
207 while ( CurrentDevice )
208 {
209 if ( CurrentDevice == SoundDevice )
210 {
211 if ( ! PreviousDevice )
212 {
213 /* This is the head node */
214 SND_TRACE(L"Removing head node from device list %d\n", DeviceType);
215 SoundDeviceListHeads[TypeIndex] =
216 SoundDeviceListHeads[TypeIndex]->Next;
217 }
218 else
219 {
220 SND_TRACE(L"Removing node from device list %d\n", DeviceType);
221 /* There are nodes before this one - cut our device out */
222 PreviousDevice->Next = CurrentDevice->Next;
223 }
224
225 if ( ! CurrentDevice->Next )
226 {
227 /* This is the tail node */
228 SND_TRACE(L"Removing tail node from device list %d\n", DeviceType);
229 SoundDeviceListTails[TypeIndex] = PreviousDevice;
230 }
231 }
232
233 PreviousDevice = CurrentDevice;
234 CurrentDevice = CurrentDevice->Next;
235 }
236
237 /* Subtract from the count */
238 -- SoundDeviceCounts[TypeIndex];
239
240 /* Finally, free up the deleted entry */
241 FreeSoundDevice(SoundDevice);
242
243 return MMSYSERR_NOERROR;
244 }
245
246 /*
247 Removes all devices from one of the device lists.
248 */
249 MMRESULT
250 UnlistSoundDevices(
251 IN MMDEVICE_TYPE DeviceType)
252 {
253 UCHAR TypeIndex;
254 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
255
256 SND_TRACE(L"Unlisting all sound devices of type %d\n", DeviceType);
257
258 TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
259
260 /* Munch away at the head of the list until it's drained */
261 while ( SoundDeviceCounts[TypeIndex] > 0 )
262 {
263 MMRESULT Result;
264 Result = UnlistSoundDevice(DeviceType, SoundDeviceListHeads[TypeIndex]);
265 SND_ASSERT( Result == MMSYSERR_NOERROR );
266 }
267
268 return MMSYSERR_NOERROR;
269 }
270
271 /*
272 Removes all devices from all lists.
273 */
274 VOID
275 UnlistAllSoundDevices()
276 {
277 MMDEVICE_TYPE Type;
278
279 SND_TRACE(L"Unlisting all sound devices\n");
280
281 for ( Type = MIN_SOUND_DEVICE_TYPE; Type <= MAX_SOUND_DEVICE_TYPE; ++ Type )
282 {
283 MMRESULT Result;
284 Result = UnlistSoundDevices(Type);
285 SND_ASSERT( Result == MMSYSERR_NOERROR );
286 }
287 }
288
289 /*
290 Provides the caller with a pointer to its desired sound device, based on
291 the device type and index.
292 */
293 MMRESULT
294 GetSoundDevice(
295 IN MMDEVICE_TYPE DeviceType,
296 IN DWORD DeviceIndex,
297 OUT PSOUND_DEVICE* SoundDevice)
298 {
299 UCHAR TypeIndex = SOUND_DEVICE_TYPE_TO_INDEX(DeviceType);
300 DWORD CurrentIndex = 0;
301 PSOUND_DEVICE CurrentDevice;
302
303 VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) );
304
305 if ( DeviceIndex >= SoundDeviceCounts[TypeIndex] )
306 {
307 SND_ERR(L"Invalid device ID %d for type %d\n", DeviceIndex, DeviceType);
308 return MMSYSERR_BADDEVICEID;
309 }
310
311 CurrentDevice = SoundDeviceListHeads[TypeIndex];
312
313 /* Following the earlier checks, the index should be valid here. */
314 for ( CurrentIndex = 0; CurrentIndex != DeviceIndex; ++ CurrentIndex )
315 {
316 SND_ASSERT( CurrentDevice );
317 CurrentDevice = CurrentDevice->Next;
318 }
319
320 SND_TRACE(L"Returning sound device %x\n", CurrentDevice);
321
322 *SoundDevice = CurrentDevice;
323
324 return MMSYSERR_NOERROR;
325 }
326
327 /*
328 Provides the caller with the device path of the specified sound device.
329 This will normally be the path to a device provided by a kernel-mode
330 driver.
331 */
332 MMRESULT
333 GetSoundDeviceIdentifier(
334 IN PSOUND_DEVICE SoundDevice,
335 OUT PVOID* Identifier)
336 {
337 VALIDATE_MMSYS_PARAMETER( SoundDevice );
338 VALIDATE_MMSYS_PARAMETER( Identifier );
339
340 /* The caller should not modify this! */
341 *Identifier = SoundDevice->Identifier;
342
343 return MMSYSERR_NOERROR;
344 }
345
346 /*
347 Provides the caller with the device type of the specified sound device.
348 This will be, for example, WAVE_OUT_DEVICE_TYPE, WAVE_IN_DEVICE_TYPE ...
349 */
350 MMRESULT
351 GetSoundDeviceType(
352 IN PSOUND_DEVICE SoundDevice,
353 OUT PMMDEVICE_TYPE DeviceType)
354 {
355 VALIDATE_MMSYS_PARAMETER( SoundDevice );
356 VALIDATE_MMSYS_PARAMETER( DeviceType );
357
358 *DeviceType = SoundDevice->Type;
359
360 return MMSYSERR_NOERROR;
361 }