Merge from amd64-branch:
[reactos.git] / reactos / dll / win32 / wdmaud.drv / wdmaud.c
1 /*
2 * PROJECT: ReactOS Sound System
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/wdmaud.drv/wdmaud.c
5 *
6 * PURPOSE: WDM Audio Driver (User-mode part)
7 * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
8 *
9 * NOTES: Looking for wodMessage & co? You won't find them here. Try
10 * the MME Buddy library, which is where these routines are
11 * actually implemented.
12 *
13 */
14
15 #include <windows.h>
16 #include <ntddsnd.h>
17 #include <sndtypes.h>
18 #include <mmddk.h>
19 #include <mmebuddy.h>
20
21 #include <ks.h>
22 #include <ksmedia.h>
23 #include "interface.h"
24
25 #define KERNEL_DEVICE_NAME L"\\\\.\\wdmaud"
26
27 PWSTR UnknownWaveIn = L"Wave Input";
28 PWSTR UnknownWaveOut = L"Wave Output";
29 PWSTR UnknownMidiIn = L"Midi Input";
30 PWSTR UnknownMidiOut = L"Midi Output";
31
32 HANDLE KernelHandle = INVALID_HANDLE_VALUE;
33 DWORD OpenCount = 0;
34
35
36 MMRESULT
37 GetNumWdmDevs(
38 IN HANDLE Handle,
39 IN MMDEVICE_TYPE DeviceType,
40 OUT DWORD* DeviceCount)
41 {
42 MMRESULT Result;
43 WDMAUD_DEVICE_INFO DeviceInfo;
44
45 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
46 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
47 VALIDATE_MMSYS_PARAMETER( DeviceCount );
48
49 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
50 DeviceInfo.DeviceType = DeviceType;
51
52 Result = SyncOverlappedDeviceIoControl(Handle,
53 IOCTL_GETNUMDEVS_TYPE,
54 (LPVOID) &DeviceInfo,
55 sizeof(WDMAUD_DEVICE_INFO),
56 (LPVOID) &DeviceInfo,
57 sizeof(WDMAUD_DEVICE_INFO),
58 NULL);
59
60 if ( ! MMSUCCESS( Result ) )
61 {
62 SND_ERR(L"Call to IOCTL_GETNUMDEVS_TYPE failed\n");
63 *DeviceCount = 0;
64 return TranslateInternalMmResult(Result);
65 }
66
67 *DeviceCount = DeviceInfo.DeviceCount;
68
69 return MMSYSERR_NOERROR;
70 }
71
72 MMRESULT
73 GetWdmDeviceCapabilities(
74 IN PSOUND_DEVICE SoundDevice,
75 OUT PVOID Capabilities,
76 IN DWORD CapabilitiesSize)
77 {
78 /* NOTE - At this time, WDMAUD does not support this properly */
79
80 MMRESULT Result;
81 MMDEVICE_TYPE DeviceType;
82 WDMAUD_DEVICE_INFO DeviceInfo;
83
84 SND_ASSERT( SoundDevice );
85 SND_ASSERT( Capabilities );
86
87 SND_TRACE(L"WDMAUD - GetWdmDeviceCapabilities\n");
88
89 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
90 SND_ASSERT( Result == MMSYSERR_NOERROR );
91
92 if ( ! MMSUCCESS(Result) )
93 return Result;
94
95
96 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
97 DeviceInfo.DeviceType = DeviceType;
98 DeviceInfo.DeviceIndex = 0; //FIXME
99
100 Result = SyncOverlappedDeviceIoControl(KernelHandle,
101 IOCTL_GETCAPABILITIES,
102 (LPVOID) &DeviceInfo,
103 sizeof(WDMAUD_DEVICE_INFO),
104 (LPVOID) &DeviceInfo,
105 sizeof(WDMAUD_DEVICE_INFO),
106 NULL);
107
108 if ( ! MMSUCCESS(Result) )
109 {
110 return TranslateInternalMmResult(Result);
111 }
112
113
114 /* This is pretty much a big hack right now */
115 switch ( DeviceType )
116 {
117 case WAVE_OUT_DEVICE_TYPE :
118 {
119 LPWAVEOUTCAPS WaveOutCaps = (LPWAVEOUTCAPS) Capabilities;
120 WaveOutCaps->wMid = DeviceInfo.u.WaveOutCaps.wMid;
121 WaveOutCaps->wPid = DeviceInfo.u.WaveOutCaps.wPid;
122
123 WaveOutCaps->vDriverVersion = 0x0001;
124 CopyWideString(WaveOutCaps->szPname, UnknownWaveOut);
125
126 WaveOutCaps->dwFormats = DeviceInfo.u.WaveOutCaps.dwFormats;
127 WaveOutCaps->wChannels = DeviceInfo.u.WaveOutCaps.wChannels;
128 WaveOutCaps->dwSupport = DeviceInfo.u.WaveOutCaps.dwSupport;
129 break;
130 }
131 case WAVE_IN_DEVICE_TYPE :
132 {
133 LPWAVEINCAPS WaveInCaps = (LPWAVEINCAPS) Capabilities;
134 CopyWideString(WaveInCaps->szPname, UnknownWaveIn);
135 /* TODO... other fields */
136 break;
137 }
138 }
139
140 return MMSYSERR_NOERROR;
141 }
142
143
144 MMRESULT
145 OpenWdmSoundDevice(
146 IN struct _SOUND_DEVICE* SoundDevice, /* NOT USED */
147 OUT PVOID* Handle)
148 {
149 /* Only open this if it's not already open */
150 if ( KernelHandle == INVALID_HANDLE_VALUE )
151 {
152 SND_TRACE(L"Opening wdmaud device\n");
153 KernelHandle = CreateFileW(KERNEL_DEVICE_NAME,
154 GENERIC_READ | GENERIC_WRITE,
155 0,
156 NULL,
157 OPEN_EXISTING,
158 FILE_FLAG_OVERLAPPED,
159 NULL);
160 }
161
162 if ( KernelHandle == INVALID_HANDLE_VALUE )
163 return MMSYSERR_ERROR;
164
165 SND_ASSERT( Handle );
166
167 *Handle = KernelHandle;
168 ++ OpenCount;
169
170 return MMSYSERR_NOERROR;
171 }
172
173 MMRESULT
174 CloseWdmSoundDevice(
175 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
176 IN PVOID Handle)
177 {
178 if ( OpenCount == 0 )
179 {
180 return MMSYSERR_NOERROR;
181 }
182
183 SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE );
184
185 if (SoundDeviceInstance->Handle != (PVOID)KernelHandle)
186 {
187 CloseHandle((HANDLE)SoundDeviceInstance->Handle);
188 }
189
190 --OpenCount;
191
192 if ( OpenCount < 1 )
193 {
194 CloseHandle(KernelHandle);
195 KernelHandle = INVALID_HANDLE_VALUE;
196 }
197
198 return MMSYSERR_NOERROR;
199 }
200
201
202 MMRESULT
203 QueryWdmWaveDeviceFormatSupport(
204 IN PSOUND_DEVICE Device,
205 IN PWAVEFORMATEX WaveFormat,
206 IN DWORD WaveFormatSize)
207 {
208 /* Whatever... */
209 return MMSYSERR_NOERROR;
210 }
211
212 MMRESULT
213 SetWdmWaveDeviceFormat(
214 IN PSOUND_DEVICE_INSTANCE Instance,
215 IN PWAVEFORMATEX WaveFormat,
216 IN DWORD WaveFormatSize)
217 {
218 MMRESULT Result;
219 PSOUND_DEVICE SoundDevice;
220 PVOID Identifier;
221 WDMAUD_DEVICE_INFO DeviceInfo;
222 MMDEVICE_TYPE DeviceType;
223
224 Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
225
226 if ( ! MMSUCCESS(Result) )
227 {
228 return TranslateInternalMmResult(Result);
229 }
230
231 Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);
232
233 if ( ! MMSUCCESS(Result) )
234 {
235 return TranslateInternalMmResult(Result);
236 }
237
238 if (Instance->Handle != KernelHandle)
239 {
240 /* device is already open */
241 return MMSYSERR_NOERROR;
242 }
243
244
245 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
246 SND_ASSERT( Result == MMSYSERR_NOERROR );
247
248 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
249 DeviceInfo.DeviceType = DeviceType;
250 DeviceInfo.DeviceIndex = 0; //FIXME
251 DeviceInfo.u.WaveFormatEx.cbSize = WaveFormat->cbSize;
252 DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
253 DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
254 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
255 DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
256 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
257 DeviceInfo.u.WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
258
259 Result = SyncOverlappedDeviceIoControl(KernelHandle,
260 IOCTL_OPEN_WDMAUD,
261 (LPVOID) &DeviceInfo,
262 sizeof(WDMAUD_DEVICE_INFO),
263 (LPVOID) &DeviceInfo,
264 sizeof(WDMAUD_DEVICE_INFO),
265 NULL);
266
267 if ( ! MMSUCCESS(Result) )
268 {
269 return TranslateInternalMmResult(Result);
270 }
271
272 Instance->Handle = (PVOID)DeviceInfo.hDevice;
273
274 return MMSYSERR_NOERROR;
275 }
276
277 MMRESULT
278 WriteFileEx_Committer2(
279 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
280 IN PVOID OffsetPtr,
281 IN DWORD Length,
282 IN PSOUND_OVERLAPPED Overlap,
283 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
284 {
285 HANDLE Handle;
286 WDMAUD_DEVICE_INFO DeviceInfo;
287
288
289 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
290 VALIDATE_MMSYS_PARAMETER( OffsetPtr );
291 VALIDATE_MMSYS_PARAMETER( Overlap );
292 VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
293
294 GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
295
296 SND_ASSERT(Handle);
297
298 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
299 DeviceInfo.hDevice = Handle;
300 DeviceInfo.DeviceType = WAVE_OUT_DEVICE_TYPE; //FIXME
301 DeviceInfo.Buffer = OffsetPtr;
302 DeviceInfo.BufferSize = Length;
303
304 Overlap->Standard.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
305
306 if ( ! WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine))
307 {
308 SND_TRACE(L"WriteFileEx failed with %x\n", GetLastError());
309 }
310 else
311 {
312 WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
313
314 }
315
316 return MMSYSERR_NOERROR;
317 }
318
319
320 MMRESULT
321 PopulateWdmDeviceList(
322 HANDLE Handle,
323 MMDEVICE_TYPE DeviceType)
324 {
325 MMRESULT Result;
326 DWORD DeviceCount = 0;
327 PSOUND_DEVICE SoundDevice = NULL;
328 MMFUNCTION_TABLE FuncTable;
329 DWORD i;
330
331 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
332 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
333
334 Result = GetNumWdmDevs(Handle, DeviceType, &DeviceCount);
335
336 if ( ! MMSUCCESS(Result) )
337 {
338 SND_ERR(L"Error %d while obtaining number of devices\n", Result);
339 return TranslateInternalMmResult(Result);
340 }
341
342 SND_TRACE(L"%d devices of type %d found\n", DeviceCount, DeviceType);
343
344
345 for ( i = 0; i < DeviceCount; ++ i )
346 {
347 Result = ListSoundDevice(DeviceType, (PVOID) i, &SoundDevice);
348
349 if ( ! MMSUCCESS(Result) )
350 {
351 SND_ERR(L"Failed to list sound device - error %d\n", Result);
352 return TranslateInternalMmResult(Result);
353 }
354
355 /* Set up our function table */
356 ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
357 FuncTable.GetCapabilities = GetWdmDeviceCapabilities;
358 FuncTable.QueryWaveFormatSupport = QueryWdmWaveDeviceFormatSupport;
359 FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
360 FuncTable.Open = OpenWdmSoundDevice;
361 FuncTable.Close = CloseWdmSoundDevice;
362 FuncTable.CommitWaveBuffer = WriteFileEx_Committer2;
363
364 SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
365 }
366
367 return MMSYSERR_NOERROR;
368 }
369
370
371
372 APIENTRY LONG
373 DriverProc(
374 DWORD DriverId,
375 HANDLE DriverHandle,
376 UINT Message,
377 LONG Parameter1,
378 LONG Parameter2)
379 {
380 MMRESULT Result;
381
382 switch ( Message )
383 {
384 case DRV_LOAD :
385 {
386 HANDLE Handle;
387 SND_TRACE(L"DRV_LOAD\n");
388
389 Result = InitEntrypointMutexes();
390
391 if ( ! MMSUCCESS(Result) )
392 return 0L;
393
394 OpenWdmSoundDevice(NULL, &Handle);
395
396 if ( Handle == INVALID_HANDLE_VALUE )
397 {
398 SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
399 CleanupEntrypointMutexes();
400
401 //UnlistAllSoundDevices();
402
403 return 0L;
404 }
405
406 /* Populate the device lists */
407 SND_TRACE(L"Populating device lists\n");
408 PopulateWdmDeviceList(KernelHandle, WAVE_OUT_DEVICE_TYPE);
409 PopulateWdmDeviceList(KernelHandle, WAVE_IN_DEVICE_TYPE);
410 PopulateWdmDeviceList(KernelHandle, MIDI_OUT_DEVICE_TYPE);
411 PopulateWdmDeviceList(KernelHandle, MIDI_IN_DEVICE_TYPE);
412 PopulateWdmDeviceList(KernelHandle, AUX_DEVICE_TYPE);
413 PopulateWdmDeviceList(KernelHandle, MIXER_DEVICE_TYPE);
414
415 SND_TRACE(L"Initialisation complete\n");
416
417 return 1L;
418 }
419
420 case DRV_FREE :
421 {
422 SND_TRACE(L"DRV_FREE\n");
423
424 if ( KernelHandle != INVALID_HANDLE_VALUE )
425 {
426 CloseHandle(KernelHandle);
427 KernelHandle = INVALID_HANDLE_VALUE;
428 }
429
430 /* TODO: Clean up the path names! */
431 UnlistAllSoundDevices();
432
433 CleanupEntrypointMutexes();
434
435 SND_TRACE(L"Unfreed memory blocks: %d\n",
436 GetMemoryAllocationCount());
437
438 return 1L;
439 }
440
441 case DRV_ENABLE :
442 case DRV_DISABLE :
443 {
444 SND_TRACE(L"DRV_ENABLE / DRV_DISABLE\n");
445 return 1L;
446 }
447
448 case DRV_OPEN :
449 case DRV_CLOSE :
450 {
451 SND_TRACE(L"DRV_OPEN / DRV_CLOSE\n");
452 return 1L;
453 }
454
455 case DRV_QUERYCONFIGURE :
456 {
457 SND_TRACE(L"DRV_QUERYCONFIGURE\n");
458 return 0L;
459 }
460 case DRV_CONFIGURE :
461 return DRVCNF_OK;
462
463 default :
464 SND_TRACE(L"Unhandled message %d\n", Message);
465 return DefDriverProc(DriverId,
466 DriverHandle,
467 Message,
468 Parameter1,
469 Parameter2);
470 }
471 }
472
473
474 BOOL WINAPI DllMain(
475 HINSTANCE hinstDLL,
476 DWORD fdwReason,
477 LPVOID lpvReserved)
478 {
479 switch ( fdwReason )
480 {
481 case DLL_PROCESS_ATTACH :
482 SND_TRACE(L"WDMAUD.DRV - Process attached\n");
483 break;
484 case DLL_PROCESS_DETACH :
485 SND_TRACE(L"WDMAUD.DRV - Process detached\n");
486 break;
487 case DLL_THREAD_ATTACH :
488 SND_TRACE(L"WDMAUD.DRV - Thread attached\n");
489 break;
490 case DLL_THREAD_DETACH :
491 SND_TRACE(L"WDMAUD.DRV - Thread detached\n");
492 break;
493 }
494
495 return TRUE;
496 }