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