3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Multimedia
5 * FILE: lib/wdmaud/kernel.c
6 * PURPOSE: WDM Audio Support - Kernel Mode Interface
7 * PROGRAMMER: Andrew Greenwood
9 * Nov 18, 2005: Created
12 #define INITGUID /* FIXME */
18 /* HACK ALERT - This goes in ksmedia.h */
19 DEFINE_GUID(KSCATEGORY_WDMAUD
,
20 0x3e227e76L
, 0x690d, 0x11d2, 0x81, 0x61, 0x00, 0x00, 0xf8, 0x77, 0x5b, 0xf1);
22 /* This stores the handle of the kernel device */
23 static HANDLE kernel_device_handle
= NULL
;
29 TODO: There's a variant of this that uses critical sections...
32 MMRESULT
CallKernelDevice(
33 PWDMAUD_DEVICE_INFO device
,
39 MMRESULT result
= MMSYSERR_ERROR
;
41 DWORD bytes_returned
= 0;
42 BOOL using_critical_section
= FALSE
;
44 ASSERT(kernel_device_handle
);
47 DPRINT("Creating event\n");
48 overlap
.hEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
50 if ( ! overlap
.hEvent
)
52 DPRINT1("CreateEvent failed - error %d\n", (int)GetLastError());
53 result
= MMSYSERR_NOMEM
;
57 DPRINT("Sizeof wchar == %d\n", (int) sizeof(WCHAR
));
58 name_len
= lstrlen(device
->path
) * sizeof(WCHAR
); /* ok ? */
60 /* These seem to carry optional structures */
61 device
->ioctl_param1
= param1
;
62 device
->ioctl_param2
= param2
;
64 /* Enter critical section if wave/midi device, and if required */
65 if ( ( ! IsMixerDeviceType(device
->type
) ) &&
66 ( ! IsAuxDeviceType(device
->type
) ) &&
67 ( device
->with_critical_section
) )
69 /* this seems to crash under some conditions */
70 ASSERT(device
->state
);
71 using_critical_section
= TRUE
;
72 EnterCriticalSection(device
->state
->queue_critical_section
);
75 DPRINT("Calling DeviceIoControl with IOCTL %x\n", (int) ioctl_code
);
77 if ( ! DeviceIoControl(kernel_device_handle
,
80 name_len
+ sizeof(WDMAUD_DEVICE_INFO
),
82 sizeof(WDMAUD_DEVICE_INFO
),
86 DWORD error
= GetLastError();
88 if (error
!= ERROR_IO_PENDING
)
90 DPRINT1("FAILED in CallKernelDevice (error %d)\n", (int) error
);
92 DUMP_WDMAUD_DEVICE_INFO(device
);
94 result
= TranslateWinError(error
);
98 DPRINT("Waiting for overlap I/O event\n");
100 /* Wait for the IO to be complete */
101 WaitForSingleObject(overlap
.hEvent
, INFINITE
);
104 result
= MMSYSERR_NOERROR
;
105 DPRINT("CallKernelDevice succeeded :)\n");
107 DUMP_WDMAUD_DEVICE_INFO(device
);
111 /* Leave the critical section */
112 if ( using_critical_section
)
113 LeaveCriticalSection(device
->state
->queue_critical_section
);
115 if ( overlap
.hEvent
)
116 CloseHandle(overlap
.hEvent
);
123 static BOOL
ChangeKernelDeviceState(BOOL enable
)
125 PWDMAUD_DEVICE_INFO device
= NULL
;
127 MMRESULT call_result
;
129 ioctl_code
= enable
? IOCTL_WDMAUD_HELLO
: IOCTL_WDMAUD_GOODBYE
;
131 device
= CreateDeviceData(WDMAUD_AUX
, L
"");
135 DPRINT1("Couldn't create a new device instance structure\n");
139 DPRINT("Setting device type and disabling critical section\n");
141 device
->type
= WDMAUD_AUX
;
142 device
->with_critical_section
= FALSE
;
144 DPRINT("Calling kernel device\n");
146 call_result
= CallKernelDevice(device
, ioctl_code
, 0, 0);
148 DeleteDeviceData(device
);
150 if ( call_result
!= MMSYSERR_NOERROR
)
152 DPRINT1("Kernel device doesn't like us! (error %d)\n", (int) GetLastError());
162 BOOL
EnableKernelInterface()
164 /* SetupAPI variables/structures for querying device data */
165 SP_DEVICE_INTERFACE_DATA interface_data
;
166 PSP_DEVICE_INTERFACE_DETAIL_DATA detail
= NULL
;
167 DWORD detail_size
= 0;
171 /* Set to TRUE right at the end to define cleanup behaviour */
172 BOOL success
= FALSE
;
174 /* Don't want to be called more than once */
175 ASSERT(kernel_device_handle
== NULL
);
177 dev_info
= SetupDiGetClassDevs(&KSCATEGORY_WDMAUD
,
180 DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
182 if ( ( ! dev_info
) || ( dev_info
== INVALID_HANDLE_VALUE
) )
184 DPRINT1("SetupDiGetClassDevs failed\n");
188 interface_data
.cbSize
= sizeof(SP_DEVICE_INTERFACE_DATA
);
190 if ( ! SetupDiEnumDeviceInterfaces(dev_info
,
196 DPRINT1("SetupDiEnumDeviceInterfaces failed\n");
201 We need to find out the size of the interface detail, before we can
202 actually retrieve the detail. This is a bit backwards, as the function
203 will return a status of success if the interface is invalid, but we
204 need it to fail with ERROR_INSUFFICIENT_BUFFER so we can be told how
205 much memory we need to allocate.
208 if ( SetupDiGetDeviceInterfaceDetail(dev_info
,
215 DPRINT1("SetupDiGetDeviceInterfaceDetail shouldn't succeed!\n");
220 Now we make sure the error was the one we expected. If not, bail out.
223 if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
225 DPRINT1("SetupDiGetDeviceInterfaceDetail returned wrong error code\n");
229 heap
= GetProcessHeap();
233 DPRINT1("Unable to get the process heap (error %d)\n",
234 (int)GetLastError());
238 detail
= (PSP_DEVICE_INTERFACE_DETAIL_DATA
) HeapAlloc(heap
,
244 DPRINT1("Unable to allocate memory for the detail buffer (error %d)\n",
245 (int)GetLastError());
249 detail
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA
);
251 if ( ! SetupDiGetDeviceInterfaceDetail(dev_info
,
258 DPRINT1("SetupDiGetDeviceInterfaceDetail failed\n");
262 DPRINT("Device path: %S\n", detail
->DevicePath
);
264 /* FIXME - params! */
265 kernel_device_handle
= CreateFile(detail
->DevicePath
,
273 DPRINT("kernel_device_handle == 0x%x\n", (int) kernel_device_handle
);
275 if ( ! kernel_device_handle
)
277 DPRINT1("Unable to open kernel device (error %d)\n",
278 (int) GetLastError());
282 /* Now we say hello to wdmaud.sys */
283 if ( ! ChangeKernelDeviceState(TRUE
) )
285 DPRINT1("Couldn't enable the kernel device\n");
293 DPRINT("Cleanup - success == %d\n", (int) success
);
299 if ( kernel_device_handle
)
300 CloseHandle(kernel_device_handle
);
306 HeapFree(heap
, 0, detail
);
314 Nothing here should fail, but if it does, we just give up and ASSERT(). If
315 we don't, we could be left in a limbo-state (eg: device open but disabled.)
318 BOOL
DisableKernelInterface()
320 return ChangeKernelDeviceState(FALSE
);
323 PWDMAUD_DEVICE_INFO device
= NULL
;
325 ASSERT(kernel_device_handle
);
327 /* Say goodbyte to wdmaud.sys */
328 device
= CreateDeviceData(WDMAUD_AUX
, L
"");
332 DPRINT("Setting device type and disabling critical section\n");
334 device
->type
= WDMAUD_AUX
;
335 device
->with_critical_section
= FALSE
;
337 DPRINT("Calling kernel device\n");
339 ASSERT( CallKernelDevice(device
, IOCTL_WDMAUD_GOODBYE
, 0, 0) == MMSYSERR_NOERROR
);
340 ASSERT( CloseHandle(kernel_device_handle
) );
342 DPRINT("Kernel interface now disabled\n");
344 kernel_device_handle
= NULL
;
346 DeleteDeviceData(device
);
352 The use of this should be avoided...
355 HANDLE
GetKernelInterface()
357 return kernel_device_handle
;