Sync to trunk head (r42241)
[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 IN DWORD DeviceId,
76 OUT PVOID Capabilities,
77 IN DWORD CapabilitiesSize)
78 {
79 /* NOTE - At this time, WDMAUD does not support this properly */
80
81 MMRESULT Result;
82 MMDEVICE_TYPE DeviceType;
83 WDMAUD_DEVICE_INFO DeviceInfo;
84
85 SND_ASSERT( SoundDevice );
86 SND_ASSERT( Capabilities );
87
88 SND_TRACE(L"WDMAUD - GetWdmDeviceCapabilities\n");
89
90 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
91 SND_ASSERT( Result == MMSYSERR_NOERROR );
92
93 if ( ! MMSUCCESS(Result) )
94 return Result;
95
96
97 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
98 DeviceInfo.DeviceType = DeviceType;
99 DeviceInfo.DeviceIndex = DeviceId;
100
101 Result = SyncOverlappedDeviceIoControl(KernelHandle,
102 IOCTL_GETCAPABILITIES,
103 (LPVOID) &DeviceInfo,
104 sizeof(WDMAUD_DEVICE_INFO),
105 (LPVOID) &DeviceInfo,
106 sizeof(WDMAUD_DEVICE_INFO),
107 NULL);
108
109 if ( ! MMSUCCESS(Result) )
110 {
111 return TranslateInternalMmResult(Result);
112 }
113
114
115 /* This is pretty much a big hack right now */
116 switch ( DeviceType )
117 {
118 case WAVE_OUT_DEVICE_TYPE :
119 {
120 LPWAVEOUTCAPS WaveOutCaps = (LPWAVEOUTCAPS) Capabilities;
121 WaveOutCaps->wMid = DeviceInfo.u.WaveOutCaps.wMid;
122 WaveOutCaps->wPid = DeviceInfo.u.WaveOutCaps.wPid;
123
124 WaveOutCaps->vDriverVersion = 0x0001;
125 CopyWideString(WaveOutCaps->szPname, UnknownWaveOut);
126
127 WaveOutCaps->dwFormats = DeviceInfo.u.WaveOutCaps.dwFormats;
128 WaveOutCaps->wChannels = DeviceInfo.u.WaveOutCaps.wChannels;
129 WaveOutCaps->dwSupport = DeviceInfo.u.WaveOutCaps.dwSupport;
130 break;
131 }
132 case WAVE_IN_DEVICE_TYPE :
133 {
134 LPWAVEINCAPS WaveInCaps = (LPWAVEINCAPS) Capabilities;
135 CopyWideString(WaveInCaps->szPname, UnknownWaveIn);
136 /* TODO... other fields */
137 break;
138 }
139 }
140
141 return MMSYSERR_NOERROR;
142 }
143
144
145 MMRESULT
146 OpenWdmSoundDevice(
147 IN struct _SOUND_DEVICE* SoundDevice, /* NOT USED */
148 OUT PVOID* Handle)
149 {
150 /* Only open this if it's not already open */
151 if ( KernelHandle == INVALID_HANDLE_VALUE )
152 {
153 SND_TRACE(L"Opening wdmaud device\n");
154 KernelHandle = CreateFileW(KERNEL_DEVICE_NAME,
155 GENERIC_READ | GENERIC_WRITE,
156 0,
157 NULL,
158 OPEN_EXISTING,
159 FILE_FLAG_OVERLAPPED,
160 NULL);
161 }
162
163 if ( KernelHandle == INVALID_HANDLE_VALUE )
164 return MMSYSERR_ERROR;
165
166 SND_ASSERT( Handle );
167
168 *Handle = KernelHandle;
169 ++ OpenCount;
170
171 return MMSYSERR_NOERROR;
172 }
173
174 MMRESULT
175 CloseWdmSoundDevice(
176 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
177 IN PVOID Handle)
178 {
179 WDMAUD_DEVICE_INFO DeviceInfo;
180 MMRESULT Result;
181 MMDEVICE_TYPE DeviceType;
182 PSOUND_DEVICE SoundDevice;
183
184 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
185
186 if ( ! MMSUCCESS(Result) )
187 {
188 return TranslateInternalMmResult(Result);
189 }
190
191 if ( OpenCount == 0 )
192 {
193 return MMSYSERR_NOERROR;
194 }
195
196 SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE );
197
198 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
199 SND_ASSERT( Result == MMSYSERR_NOERROR );
200
201 if (SoundDeviceInstance->Handle != (PVOID)KernelHandle)
202 {
203 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
204
205 DeviceInfo.DeviceType = DeviceType;
206 DeviceInfo.hDevice = SoundDeviceInstance->Handle;
207
208 SyncOverlappedDeviceIoControl(KernelHandle,
209 IOCTL_CLOSE_WDMAUD,
210 (LPVOID) &DeviceInfo,
211 sizeof(WDMAUD_DEVICE_INFO),
212 (LPVOID) &DeviceInfo,
213 sizeof(WDMAUD_DEVICE_INFO),
214 NULL);
215 }
216
217 --OpenCount;
218
219 if ( OpenCount < 1 )
220 {
221 CloseHandle(KernelHandle);
222 KernelHandle = INVALID_HANDLE_VALUE;
223 }
224
225 return MMSYSERR_NOERROR;
226 }
227
228
229 MMRESULT
230 QueryWdmWaveDeviceFormatSupport(
231 IN PSOUND_DEVICE Device,
232 IN PWAVEFORMATEX WaveFormat,
233 IN DWORD WaveFormatSize)
234 {
235 /* Whatever... */
236 return MMSYSERR_NOERROR;
237 }
238
239 MMRESULT
240 SetWdmWaveDeviceFormat(
241 IN PSOUND_DEVICE_INSTANCE Instance,
242 IN DWORD DeviceId,
243 IN PWAVEFORMATEX WaveFormat,
244 IN DWORD WaveFormatSize)
245 {
246 MMRESULT Result;
247 PSOUND_DEVICE SoundDevice;
248 PVOID Identifier;
249 WDMAUD_DEVICE_INFO DeviceInfo;
250 MMDEVICE_TYPE DeviceType;
251
252 Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
253
254 if ( ! MMSUCCESS(Result) )
255 {
256 return TranslateInternalMmResult(Result);
257 }
258
259 Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);
260
261 if ( ! MMSUCCESS(Result) )
262 {
263 return TranslateInternalMmResult(Result);
264 }
265
266 if (Instance->Handle != KernelHandle)
267 {
268 /* device is already open */
269 return MMSYSERR_NOERROR;
270 }
271
272
273 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
274 SND_ASSERT( Result == MMSYSERR_NOERROR );
275
276 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
277 DeviceInfo.DeviceType = DeviceType;
278 DeviceInfo.DeviceIndex = DeviceId;
279 DeviceInfo.u.WaveFormatEx.cbSize = WaveFormat->cbSize;
280 DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
281 DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
282 DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
283 DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
284 DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
285 DeviceInfo.u.WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
286
287 Result = SyncOverlappedDeviceIoControl(KernelHandle,
288 IOCTL_OPEN_WDMAUD,
289 (LPVOID) &DeviceInfo,
290 sizeof(WDMAUD_DEVICE_INFO),
291 (LPVOID) &DeviceInfo,
292 sizeof(WDMAUD_DEVICE_INFO),
293 NULL);
294
295 if ( ! MMSUCCESS(Result) )
296 {
297 return TranslateInternalMmResult(Result);
298 }
299
300 Instance->Handle = (PVOID)DeviceInfo.hDevice;
301
302 /* Now determine framing requirements */
303 Result = SyncOverlappedDeviceIoControl(KernelHandle,
304 IOCTL_GETFRAMESIZE,
305 (LPVOID) &DeviceInfo,
306 sizeof(WDMAUD_DEVICE_INFO),
307 (LPVOID) &DeviceInfo,
308 sizeof(WDMAUD_DEVICE_INFO),
309 NULL);
310
311 if ( MMSUCCESS(Result) )
312 {
313 if (DeviceInfo.u.FrameSize)
314 {
315 Instance->FrameSize = DeviceInfo.u.FrameSize;
316 Instance->BufferCount = WaveFormat->nAvgBytesPerSec / Instance->FrameSize;
317 SND_TRACE(L"FrameSize %u BufferCount %u\n", Instance->FrameSize, Instance->BufferCount);
318 }
319 }
320
321
322 return MMSYSERR_NOERROR;
323 }
324
325 MMRESULT
326 WriteFileEx_Committer2(
327 IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
328 IN PVOID OffsetPtr,
329 IN DWORD Length,
330 IN PSOUND_OVERLAPPED Overlap,
331 IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
332 {
333 HANDLE Handle;
334 WDMAUD_DEVICE_INFO DeviceInfo;
335
336
337 VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
338 VALIDATE_MMSYS_PARAMETER( OffsetPtr );
339 VALIDATE_MMSYS_PARAMETER( Overlap );
340 VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
341
342 GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
343
344 SND_ASSERT(Handle);
345
346 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
347 DeviceInfo.hDevice = Handle;
348 DeviceInfo.DeviceType = WAVE_OUT_DEVICE_TYPE; //FIXME
349 DeviceInfo.Buffer = OffsetPtr;
350 DeviceInfo.BufferSize = Length;
351
352 Overlap->Standard.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
353
354 if ( ! WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine))
355 {
356 SND_TRACE(L"WriteFileEx failed with %x\n", GetLastError());
357 }
358 else
359 {
360 WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
361
362 }
363
364 return MMSYSERR_NOERROR;
365 }
366
367 MMRESULT
368 GetWdmPosition(
369 IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
370 IN MMTIME* Time)
371 {
372 MMRESULT Result;
373 PSOUND_DEVICE SoundDevice;
374 WDMAUD_DEVICE_INFO DeviceInfo;
375 MMDEVICE_TYPE DeviceType;
376 HANDLE Handle;
377
378 Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
379
380 if ( ! MMSUCCESS(Result) )
381 {
382 return TranslateInternalMmResult(Result);
383 }
384
385 Result = GetSoundDeviceType(SoundDevice, &DeviceType);
386 SND_ASSERT( Result == MMSYSERR_NOERROR );
387
388 Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
389 SND_ASSERT( Result == MMSYSERR_NOERROR );
390
391 ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
392 DeviceInfo.hDevice = Handle;
393 DeviceInfo.DeviceType = DeviceType;
394
395 Result = SyncOverlappedDeviceIoControl(KernelHandle,
396 IOCTL_OPEN_WDMAUD,
397 (LPVOID) &DeviceInfo,
398 sizeof(WDMAUD_DEVICE_INFO),
399 (LPVOID) &DeviceInfo,
400 sizeof(WDMAUD_DEVICE_INFO),
401 NULL);
402
403 if ( ! MMSUCCESS(Result) )
404 {
405 return TranslateInternalMmResult(Result);
406 }
407
408 Time->wType = TIME_BYTES;
409 Time->u.cb = (DWORD)DeviceInfo.u.Position;
410
411 return MMSYSERR_NOERROR;
412 }
413
414
415 MMRESULT
416 PopulateWdmDeviceList(
417 HANDLE Handle,
418 MMDEVICE_TYPE DeviceType)
419 {
420 MMRESULT Result;
421 DWORD DeviceCount = 0;
422 PSOUND_DEVICE SoundDevice = NULL;
423 MMFUNCTION_TABLE FuncTable;
424 DWORD i;
425
426 VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
427 VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
428
429 Result = GetNumWdmDevs(Handle, DeviceType, &DeviceCount);
430
431 if ( ! MMSUCCESS(Result) )
432 {
433 SND_ERR(L"Error %d while obtaining number of devices\n", Result);
434 return TranslateInternalMmResult(Result);
435 }
436
437 SND_TRACE(L"%d devices of type %d found\n", DeviceCount, DeviceType);
438
439
440 for ( i = 0; i < DeviceCount; ++ i )
441 {
442 Result = ListSoundDevice(DeviceType, UlongToPtr(i), &SoundDevice);
443
444 if ( ! MMSUCCESS(Result) )
445 {
446 SND_ERR(L"Failed to list sound device - error %d\n", Result);
447 return TranslateInternalMmResult(Result);
448 }
449
450 /* Set up our function table */
451 ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
452 FuncTable.GetCapabilities = GetWdmDeviceCapabilities;
453 FuncTable.QueryWaveFormatSupport = QueryWdmWaveDeviceFormatSupport;
454 FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
455 FuncTable.Open = OpenWdmSoundDevice;
456 FuncTable.Close = CloseWdmSoundDevice;
457 FuncTable.CommitWaveBuffer = WriteFileEx_Committer2;
458 FuncTable.GetPos = GetWdmPosition;
459
460 SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
461 }
462
463 return MMSYSERR_NOERROR;
464 }
465
466
467
468 APIENTRY LONG
469 DriverProc(
470 DWORD DriverId,
471 HANDLE DriverHandle,
472 UINT Message,
473 LONG Parameter1,
474 LONG Parameter2)
475 {
476 MMRESULT Result;
477
478 switch ( Message )
479 {
480 case DRV_LOAD :
481 {
482 HANDLE Handle;
483 SND_TRACE(L"DRV_LOAD\n");
484
485 Result = InitEntrypointMutexes();
486
487 if ( ! MMSUCCESS(Result) )
488 return 0L;
489
490 OpenWdmSoundDevice(NULL, &Handle);
491
492 if ( Handle == INVALID_HANDLE_VALUE )
493 {
494 SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
495 CleanupEntrypointMutexes();
496
497 //UnlistAllSoundDevices();
498
499 return 0L;
500 }
501
502 /* Populate the device lists */
503 SND_TRACE(L"Populating device lists\n");
504 PopulateWdmDeviceList(KernelHandle, WAVE_OUT_DEVICE_TYPE);
505 PopulateWdmDeviceList(KernelHandle, WAVE_IN_DEVICE_TYPE);
506 PopulateWdmDeviceList(KernelHandle, MIDI_OUT_DEVICE_TYPE);
507 PopulateWdmDeviceList(KernelHandle, MIDI_IN_DEVICE_TYPE);
508 PopulateWdmDeviceList(KernelHandle, AUX_DEVICE_TYPE);
509 PopulateWdmDeviceList(KernelHandle, MIXER_DEVICE_TYPE);
510
511 SND_TRACE(L"Initialisation complete\n");
512
513 return 1L;
514 }
515
516 case DRV_FREE :
517 {
518 SND_TRACE(L"DRV_FREE\n");
519
520 if ( KernelHandle != INVALID_HANDLE_VALUE )
521 {
522 CloseHandle(KernelHandle);
523 KernelHandle = INVALID_HANDLE_VALUE;
524 }
525
526 /* TODO: Clean up the path names! */
527 UnlistAllSoundDevices();
528
529 CleanupEntrypointMutexes();
530
531 SND_TRACE(L"Unfreed memory blocks: %d\n",
532 GetMemoryAllocationCount());
533
534 return 1L;
535 }
536
537 case DRV_ENABLE :
538 case DRV_DISABLE :
539 {
540 SND_TRACE(L"DRV_ENABLE / DRV_DISABLE\n");
541 return 1L;
542 }
543
544 case DRV_OPEN :
545 case DRV_CLOSE :
546 {
547 SND_TRACE(L"DRV_OPEN / DRV_CLOSE\n");
548 return 1L;
549 }
550
551 case DRV_QUERYCONFIGURE :
552 {
553 SND_TRACE(L"DRV_QUERYCONFIGURE\n");
554 return 0L;
555 }
556 case DRV_CONFIGURE :
557 return DRVCNF_OK;
558
559 default :
560 SND_TRACE(L"Unhandled message %d\n", Message);
561 return DefDriverProc(DriverId,
562 DriverHandle,
563 Message,
564 Parameter1,
565 Parameter2);
566 }
567 }
568
569
570 BOOL WINAPI DllMain(
571 HINSTANCE hinstDLL,
572 DWORD fdwReason,
573 LPVOID lpvReserved)
574 {
575 switch ( fdwReason )
576 {
577 case DLL_PROCESS_ATTACH :
578 SND_TRACE(L"WDMAUD.DRV - Process attached\n");
579 break;
580 case DLL_PROCESS_DETACH :
581 SND_TRACE(L"WDMAUD.DRV - Process detached\n");
582 break;
583 case DLL_THREAD_ATTACH :
584 SND_TRACE(L"WDMAUD.DRV - Thread attached\n");
585 break;
586 case DLL_THREAD_DETACH :
587 SND_TRACE(L"WDMAUD.DRV - Thread detached\n");
588 break;
589 }
590
591 return TRUE;
592 }