Partial implementation of WDMAUD.DRV - device capability querying fails Added: trunk/reactos/lib/wdmaud/ Added: trunk/reactos/lib/wdmaud/TODO Added: trunk/reactos/lib/wdmaud/control.c Added: trunk/reactos/lib/wdmaud/devices.c Added: trunk/reactos/lib/wdmaud/helper.c Added: trunk/reactos/lib/wdmaud/kernel.c Added: trunk/reactos/lib/wdmaud/threads.c Added: trunk/reactos/lib/wdmaud/user.c Added: trunk/reactos/lib/wdmaud/wavehdr.c Added: trunk/reactos/lib/wdmaud/wdmaud.def Added: trunk/reactos/lib/wdmaud/wdmaud.h Added: trunk/reactos/lib/wdmaud/wdmaud.rc Added: trunk/reactos/lib/wdmaud/wdmaud.xml _____
Added: trunk/reactos/lib/wdmaud/TODO --- trunk/reactos/lib/wdmaud/TODO 2005-11-24 14:34:44 UTC (rev 19529) +++ trunk/reactos/lib/wdmaud/TODO 2005-11-24 14:36:47 UTC (rev 19530) @@ -0,0 +1,4 @@
+To-Do: +- Globally store the heap handle +- Ensure cleanups are... clean... +- Clone device info in OPEN/close? _____
Added: trunk/reactos/lib/wdmaud/control.c --- trunk/reactos/lib/wdmaud/control.c 2005-11-24 14:34:44 UTC (rev 19529) +++ trunk/reactos/lib/wdmaud/control.c 2005-11-24 14:36:47 UTC (rev 19530) @@ -0,0 +1,47 @@
+/* + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Multimedia + * FILE: lib/wdmaud/wavehdr.c + * PURPOSE: WDM Audio Support - Device Control (Play/Stop etc.) + * PROGRAMMER: Andrew Greenwood + * UPDATE HISTORY: + * Nov 23, 2005: Created + */ + +#include <windows.h> +#include "wdmaud.h" + +/* + TODO: + Make these work for the other device types! +*/ + +MMRESULT StartDevice(PWDMAUD_DEVICE_INFO device) +{ + MMRESULT result; + DWORD ioctl_code; + + result = ValidateDeviceInfoAndState(device); + + if ( result != MMSYSERR_NOERROR ) + return result; + + ioctl_code = device == WDMAUD_WAVE_IN ? IOCTL_WDMAUD_WAVE_IN_START : + device == WDMAUD_WAVE_OUT ? IOCTL_WDMAUD_WAVE_OUT_START : + 0x0000; + + ASSERT( ioctl_code ); +} + +MMRESULT StopDevice(PWDMAUD_DEVICE_INFO device) +{ +} + +MMRESULT PauseDevice(PWDMAUD_DEVICE_INFO device) +{ +} + +MMRESULT StopDeviceLooping(PWDMAUD_DEVICE_INFO device) +{ +} Property changes on: trunk/reactos/lib/wdmaud/control.c ___________________________________________________________________ Name: svn:eol-style + native _____
Added: trunk/reactos/lib/wdmaud/devices.c --- trunk/reactos/lib/wdmaud/devices.c 2005-11-24 14:34:44 UTC (rev 19529) +++ trunk/reactos/lib/wdmaud/devices.c 2005-11-24 14:36:47 UTC (rev 19530) @@ -0,0 +1,697 @@
+/* + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Multimedia + * FILE: lib/wdmaud/devices.c + * PURPOSE: WDM Audio Support - Device Management + * PROGRAMMER: Andrew Greenwood + * UPDATE HISTORY: + * Nov 18, 2005: Created + * + * WARNING! SOME OF THESE FUNCTIONS OUGHT TO COPY THE DEVICE INFO STRUCTURE + * THAT HAS BEEN FED TO THEM! +*/ + +#include <windows.h> +#include "wdmaud.h" + +const char WDMAUD_DEVICE_INFO_SIG[4] = "WADI"; +const char WDMAUD_DEVICE_STATE_SIG[4] = "WADS"; + + +BOOL IsValidDevicePath(WCHAR* path) +{ + if (IsBadReadPtr(path, 1)) /* TODO: Replace with flags */ + { + DPRINT1("Bad interface\n"); + return FALSE; + } + + /* Original driver seems to check for strlenW < 0x1000 */ + + return TRUE; +} + +MMRESULT ValidateDeviceInfo(PWDMAUD_DEVICE_INFO device_info) +{ + if ( IsBadWritePtr(device_info, sizeof(WDMAUD_DEVICE_INFO)) ) + return MMSYSERR_INVALPARAM; + + if ( *device_info->signature != *WDMAUD_DEVICE_INFO_SIG ) + return MMSYSERR_INVALPARAM; + + return MMSYSERR_NOERROR; +} + +MMRESULT ValidateDeviceState(PWDMAUD_DEVICE_STATE state) +{ + if ( IsBadWritePtr(state, sizeof(WDMAUD_DEVICE_INFO)) ) + return MMSYSERR_INVALPARAM; + + if ( *state->signature != *WDMAUD_DEVICE_STATE_SIG ) + return MMSYSERR_INVALPARAM; + + return MMSYSERR_NOERROR; +} + +/* + ValidateDeviceStateEvents should be used in conjunction with the standard + state validation routine. +*/ + +MMRESULT ValidateDeviceStateEvents(PWDMAUD_DEVICE_STATE state) +{ + if ( ( (DWORD) state->exit_thread_event == 0x00000000 ) && + ( (DWORD) state->exit_thread_event != 0x48484848 ) ) + { + DPRINT1("Bad exit thread event\n"); + return MMSYSERR_INVALPARAM; + } + + if ( ( (DWORD) state->queue_event == 0x00000000 ) && + ( (DWORD) state->queue_event != 0x42424242 ) && + ( (DWORD) state->queue_event != 0x43434343 ) ) + { + DPRINT1("Bad queue event\n"); + return MMSYSERR_INVALPARAM; + } + + return MMSYSERR_NOERROR; +} + +MMRESULT ValidateDeviceInfoAndState(PWDMAUD_DEVICE_INFO device_info) +{ + MMRESULT result; + + result = ValidateDeviceInfo(device_info); + + if ( result != MMSYSERR_NOERROR ) + return result; + + result = ValidateDeviceState(device_info->state); + + if ( result != MMSYSERR_NOERROR ) + return result; + + return MMSYSERR_NOERROR; +} + +PWDMAUD_DEVICE_INFO CreateDeviceData(CHAR device_type, WCHAR* device_path) +{ + HANDLE heap = 0; + PWDMAUD_DEVICE_INFO device_data = 0; + int path_size = 0; + + if ( ! IsValidDevicePath(device_path) ) + { + DPRINT1("No valid device interface given!\n"); + goto cleanup; + } + + /* Take into account this is a unicode string... */ + path_size = (lstrlen(device_path) + 1) * sizeof(WCHAR); + DPRINT("Size of path is %d\n", (int) path_size); + + heap = GetProcessHeap(); + + if ( ! heap ) + { + DPRINT1("Couldn't get the process heap (error %d)\n", + (int) GetLastError()); + goto cleanup; + } + + DPRINT("Allocating %d bytes\n", + path_size + sizeof(WDMAUD_DEVICE_INFO)); + + device_data = (PWDMAUD_DEVICE_INFO) HeapAlloc(heap, + HEAP_ZERO_MEMORY, + path_size + sizeof(WDMAUD_DEVICE_INFO)); + + if ( ! device_data ) + { + DPRINT1("Unable to allocate memory for device data (error %d)\n", + (int) GetLastError()); + goto cleanup; + } + + DPRINT("Copying signature\n"); + memcpy(device_data->signature, WDMAUD_DEVICE_INFO_SIG, 4); + + DPRINT("Copying path (0x%x)\n", (int)device_path); + lstrcpy(device_data->path, device_path); + + device_data->type = device_type; + + cleanup : + { + /* No cleanup needed (no failures possible after allocation.) */ + DPRINT("Performing cleanup\n"); + + return device_data; + } +} + +PWDMAUD_DEVICE_INFO CloneDeviceData(PWDMAUD_DEVICE_INFO original) +{ + PWDMAUD_DEVICE_INFO clone = NULL; + + if ( ValidateDeviceInfo(original) != MMSYSERR_NOERROR) + { + DPRINT1("Original device data was invalid\n"); + return NULL; + } + + /* This will set the type and path, so we can forget about those */ + clone = CreateDeviceData(original->type, original->path); + + if ( ! clone ) + { + DPRINT1("Clone creation failed\n"); + return NULL; + } + + clone->id = original->id; + clone->wave_handle = original->wave_handle; /* ok? */ + + /* TODO: Maybe we should copy some more? */ + + return clone; +} + +void DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data) +{ + ASSERT( device_data ); + /* TODO */ +} + +MMRESULT ModifyDevicePresence( + CHAR device_type, + WCHAR* device_path, + BOOL adding) +{ + DWORD ioctl = 0; + PWDMAUD_DEVICE_INFO device_data = 0; + MMRESULT result = MMSYSERR_ERROR; + MMRESULT kernel_result = MMSYSERR_ERROR; + + DPRINT("ModifyDevicePresence - %s a device\n", + adding ? "adding" : "removing"); + + DPRINT("Topology path %S\n", device_path); + + /* FIXME: DeviceType! */ + /* TODO: Assert on device type? */ + + ASSERT( IsValidDeviceType(device_type) ); + ASSERT( device_path ); + + device_data = CreateDeviceData(device_type, device_path); + + if ( ! device_data ) + { + DPRINT1("Couldn't allocate memory for device data\n"); + result = MMSYSERR_NOMEM; + goto cleanup; + } + +/* device_data->type = device_type; */ + + ioctl = adding ? IOCTL_WDMAUD_ADD_DEVICE : IOCTL_WDMAUD_REMOVE_DEVICE; + + kernel_result = CallKernelDevice(device_data, + ioctl, + 0, + 0); + + if ( kernel_result != MMSYSERR_NOERROR ) + { + DPRINT1("WdmAudioIoControl FAILED with error %d\n", (int) kernel_result); + + switch ( kernel_result ) + { + /* TODO: Translate into a real error code */ + default : + result = MMSYSERR_ERROR; + } + + goto cleanup; + } + + DPRINT("ModifyDevicePresence succeeded\n"); + + result = MMSYSERR_NOERROR; + + cleanup : + { + if ( device_data ) + DeleteDeviceData(device_data); + + return result; + } +} + +DWORD GetDeviceCount(CHAR device_type, WCHAR* topology_path) +{ + PWDMAUD_DEVICE_INFO device_data; + int device_count = 0; + + DPRINT("Topology path %S\n", topology_path); + + device_data = CreateDeviceData(device_type, topology_path); + + if (! device_data) + { + DPRINT1("Couldn't allocate device data\n"); + goto cleanup; + } + + DPRINT("Getting num devs\n"); + + /*device_data->type = device_type;*/ + device_data->with_critical_section = FALSE; + + if ( CallKernelDevice(device_data, + IOCTL_WDMAUD_GET_DEVICE_COUNT, + 0, + 0) != MMSYSERR_NOERROR ) + { + DPRINT1("Failed\n"); + goto cleanup; + } + + device_count = device_data->id; + + DPRINT("There are %d devs\n", device_count); + + cleanup : + { + if ( device_data ) + DeleteDeviceData(device_data); + + return device_count; + } +} + +/* + This is a bit messed up +*/ + +MMRESULT GetDeviceCapabilities( + CHAR device_type, + DWORD device_id, + WCHAR* device_path, + LPCOMMONCAPS caps +) +{ + PWDMAUD_DEVICE_INFO device = NULL; + MMRESULT result = MMSYSERR_ERROR; + + DPRINT("Device path %S\n", device_path); + + /* Hmm - caps->wMid seems to be 0x54 (84) from XP's winmm.dll */ + if (caps->wMid == 0) + { + return MMSYSERR_NOERROR; + + DPRINT("caps->wMid == 0\n"); + + DPRINT("Manufacturer: 0x%x (%d)\n", caps->wMid, caps->wMid); + DPRINT("Product: 0x%x (%d)\n", caps->wPid, caps->wPid); + DPRINT("Device is: %S\n", caps->szPname); + + if ( IsWaveOutDeviceType(device_type) ) + { + LPWAVEOUTCAPS woc = (LPWAVEOUTCAPS) caps; + DPRINT("Formats: %d\n", (int) woc->dwFormats); + DPRINT("Channels: %d\n", woc->wChannels); + DPRINT("Reserved: %d\n", woc->wReserved1); + DPRINT("Support: %d\n", (int) woc->dwSupport); + } + + return MMSYSERR_NOERROR; + } + +#if 0 + int i; + for (i = 0; i < 64; i ++) + { + DPRINT("0x%x\n", *(((UCHAR*)caps) + i)); + } + + return MMSYSERR_NOERROR; +#endif + + DPRINT("Going to have to query the kernel-mode part\n"); + + device = CreateDeviceData(device_type, device_path); + + if ( ! device ) + { + DPRINT("Unable to allocate device data memory\n"); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + device->id = device_id; + device->with_critical_section = FALSE; + + /* ? */ + DPRINT("Caps wMid is 0x%x\n", (int) caps->wMid); + DPRINT("Driver version is 0x%x\n", (int) caps->vDriverVersion); + + DPRINT("%S\n", (WCHAR*) caps->vDriverVersion); + + LPWORD theword; + theword = (LPWORD) caps->vDriverVersion; + *theword = 0x43; + //caps->vDriverVersion=0x4300; + + + DPRINT("Calling kernel device\n"); + result = CallKernelDevice(device, + IOCTL_WDMAUD_GET_CAPABILITIES, + (DWORD)caps->wMid, + (DWORD)caps->vDriverVersion); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT("IoControl failed\n"); + goto cleanup; + } + + + + /* What do we return? */ + /*return MMSYSERR_NOERROR; */ /* already set by now */ + + cleanup : + { + if ( device ) + DeleteDeviceData(device); + + return result; + } +} + +MMRESULT TryOpenDevice( + PWDMAUD_DEVICE_INFO device, + LPWAVEFORMATEX format +) +{ + if ( device->id > 0x64 ) /* FIXME */ + { + DPRINT1("device->id > 0x64 ! ???\n"); + return MMSYSERR_BADDEVICEID; /* OK? */ + } + + /* We'll only have a format set for wave devices */ + if ( format ) + { + if ( format->wFormatTag == 1 ) + { + DWORD sample_size; + + DPRINT("Standard (PCM) format\n"); + sample_size = format->nChannels * format->wBitsPerSample; + device->state->sample_size = sample_size; + + if ( CallKernelDevice(device, + IOCTL_WDMAUD_OPEN_DEVICE, + 0x10, + (DWORD)format) + != MMSYSERR_NOERROR ) + { + DPRINT("Call failed\n"); + /* FIXME */ + return MMSYSERR_NOTSUPPORTED; /* WAVERR_BADFORMAT? */ + } + } + else + { + /* FIXME */ + DPRINT("Non-PCM format\n"); + return MMSYSERR_NOTSUPPORTED; + } + } + + /* If we got this far without error, the format is supported! */ + return MMSYSERR_NOERROR; +} + +MMRESULT OpenWaveDevice( + CHAR device_type, + DWORD device_id, + LPWAVEOPENDESC open_details, + DWORD flags, + DWORD user_data +) +{ + HANDLE heap = 0; + PWDMAUD_DEVICE_INFO device = NULL; + WCHAR* device_path = NULL; + MMRESULT result = MMSYSERR_ERROR; + + /* ASSERT(open_details); */ + + heap = GetProcessHeap(); + + if ( ! heap ) + { + DPRINT1("Couldn't get the process heap (error %d)\n", + (int) GetLastError()); + result = MMSYSERR_ERROR; + goto cleanup; + } + + DPRINT("OpenDevice called\n"); + + device_path = (WCHAR*) open_details->dnDevNode; + device = CreateDeviceData(device_type, device_path); + + if ( ! device ) + { + DPRINT1("Couldn't create device data\n"); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + DPRINT("Allocated device data, allocating device state\n"); + + device->state = HeapAlloc(heap, + HEAP_ZERO_MEMORY, + sizeof(WDMAUD_DEVICE_STATE)); + + if ( ! device->state ) + { + DPRINT1("Couldn't allocate memory for device state (error %d)\n", + (int) GetLastError()); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + /* FIXME: ok here ? */ + device->type = device_type; + device->id = device_id; + device->flags = flags; + + if ( flags & WAVE_FORMAT_QUERY ) + { + DPRINT("Do I support this format? Hmm...\n"); + + result = TryOpenDevice(device, open_details->lpFormat); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT("Format not supported\n"); + goto cleanup; + } + + DPRINT("Yes, I do support this format!\n"); + } + else + { + + DPRINT("You actually want me to open the device, huh?\n"); + + /* Allocate memory for the "queue" critical section */ + + device->state->queue_critical_section = + HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(CRITICAL_SECTION)); + + if ( ! device->state->queue_critical_section ) + { + DPRINT1("Couldn't allocate memory for queue critical section (error %d)\n", + (int) GetLastError()); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + /* Initialize the critical section */ + InitializeCriticalSection(device->state->queue_critical_section); + + /* We need these so we can contact the client later */ + device->client_instance = open_details->dwInstance; + device->client_callback = open_details->dwCallback; + + /* Reset state */ + device->state->open_descriptor = NULL; + device->state->unknown_24 = 0; + + device->state->is_running = FALSE; + device->state->is_paused = + device->type == WDMAUD_WAVE_IN ? TRUE : FALSE; + + memcpy(device->state->signature, WDMAUD_DEVICE_STATE_SIG, 4); + + DPRINT("All systems are go...\n"); + + result = TryOpenDevice(device, open_details->lpFormat); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Format not supported?\n"); + goto cleanup; /* no need to set result - already done */ + } + + /* Enter the critical section while updating the device list */ + EnterCriticalSection(device->state->queue_critical_section); + /* ... */ + LeaveCriticalSection(device->state->queue_critical_section); + + /* The wave device handle is actually our structure. Neat, eh? */ + open_details->hWave = (HWAVE) device; + + /* We also need to set our "user data" for winmm */ + LPVOID* ud = (LPVOID*) user_data; /* FIXME */ + *ud = device; + + if (device->client_callback) + { + DWORD message; + + message = (device->type == WDMAUD_WAVE_IN ? WIM_OPEN : + WDMAUD_WAVE_OUT ? WOM_OPEN : -1); + + DPRINT("About to call the client callback\n"); + + /* Call the callback */ + NotifyClient(device, message, 0, 0); + + DPRINT("...it is done!\n"); + } + + result = MMSYSERR_NOERROR; + } + + /* + This cleanup may need checking for memory leakage :/ + */ + + cleanup : + { + if ( ( result != MMSYSERR_NOERROR ) && ( heap ) ) + { + if ( device ) + { + if ( device->state ) + { + if ( device->state->queue_critical_section ) + { + DeleteCriticalSection(device->state->queue_critical_section); + HeapFree(heap, 0, device->state->queue_critical_section); + } + + HeapFree(heap, 0, device->state); + } + + DeleteDeviceData(device); + } + } + + DPRINT("Returning %d\n", (int) result); + + return result; + } +} + +MMRESULT CloseDevice( + PWDMAUD_DEVICE_INFO device +) +{ + MMRESULT result = MMSYSERR_ERROR; + + DPRINT("CloseDevice()\n"); + + DUMP_WDMAUD_DEVICE_INFO(device); + + if ( ValidateDeviceInfo(device) != MMSYSERR_NOERROR ) + { + DPRINT1("Invalid device info passed to CloseDevice\n"); + result = MMSYSERR_INVALHANDLE; + goto cleanup; + } + + /* TODO: Check state! */ + + if ( device->id > 0x64 ) /* FIXME ? */ + { + DPRINT1("??\n"); + goto cleanup; + } + + switch(device->type) + { + case WDMAUD_WAVE_OUT : + { + if ( device->state->open_descriptor ) + { + DPRINT1("Device is still playing!\n"); + result = WAVERR_STILLPLAYING; + goto cleanup; + } + + /* TODO: Destroy completion thread */ + + break; + } + + default : + { + DPRINT1("Sorry, device type %d not supported yet!\n", (int) device->type); + goto cleanup; + } + } + + result = CallKernelDevice(device, IOCTL_WDMAUD_CLOSE_DEVICE, 0, 0); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Couldn't close the device!\n"); + goto cleanup; + } + + if (device->client_callback) + { + DWORD message; + + message = (device->type == WDMAUD_WAVE_IN ? WIM_CLOSE : + WDMAUD_WAVE_OUT ? WOM_CLOSE : + WDMAUD_MIDI_IN ? MIM_CLOSE : + WDMAUD_MIDI_OUT ? MOM_CLOSE : -1); + + DPRINT("About to call the client callback\n"); + + /* Call the callback */ + NotifyClient(device, message, 0, 0); + + DPRINT("...it is done!\n"); + } + + /* Result was set earlier by CallKernelDevice */ + + cleanup : + { + return result; + } +} Property changes on: trunk/reactos/lib/wdmaud/devices.c ___________________________________________________________________ Name: svn:eol-style + native _____
Added: trunk/reactos/lib/wdmaud/helper.c --- trunk/reactos/lib/wdmaud/helper.c 2005-11-24 14:34:44 UTC (rev 19529) +++ trunk/reactos/lib/wdmaud/helper.c 2005-11-24 14:36:47 UTC (rev 19530) @@ -0,0 +1,46 @@
+/* + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Multimedia + * FILE: lib/wdmaud/helper.c + * PURPOSE: Multimedia User Mode Driver - Helper Funcs + * PROGRAMMER: Andrew Greenwood + * UPDATE HISTORY: + * Nov 13, 2005: Created + */ + +#include <windows.h> +#include <mmsystem.h> + +/* + TranslateWinError converts Win32 error codes (returned by + GetLastError, typically) into MMSYSERR codes. +*/ + +MMRESULT TranslateWinError(DWORD error) +{ + switch(error) + { + case NO_ERROR : + case ERROR_IO_PENDING : + return MMSYSERR_NOERROR; + + case ERROR_BUSY : + return MMSYSERR_ALLOCATED; + + case ERROR_NOT_SUPPORTED : + case ERROR_INVALID_FUNCTION : + return MMSYSERR_NOTSUPPORTED; + + case ERROR_NOT_ENOUGH_MEMORY : + return MMSYSERR_NOMEM; + + case ERROR_ACCESS_DENIED : + return MMSYSERR_BADDEVICEID; + + case ERROR_INSUFFICIENT_BUFFER : + return MMSYSERR_INVALPARAM; + } + + return MMSYSERR_ERROR; +} Property changes on: trunk/reactos/lib/wdmaud/helper.c ___________________________________________________________________ Name: svn:executable + * Name: svn:eol-style + native _____
Added: trunk/reactos/lib/wdmaud/kernel.c --- trunk/reactos/lib/wdmaud/kernel.c 2005-11-24 14:34:44 UTC (rev 19529) +++ trunk/reactos/lib/wdmaud/kernel.c 2005-11-24 14:36:47 UTC (rev 19530) @@ -0,0 +1,358 @@
+/* + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Multimedia + * FILE: lib/wdmaud/kernel.c + * PURPOSE: WDM Audio Support - Kernel Mode Interface + * PROGRAMMER: Andrew Greenwood + * UPDATE HISTORY: + * Nov 18, 2005: Created + */ + +#define INITGUID /* FIXME */ + +#include <windows.h> +#include <setupapi.h> +#include "wdmaud.h" + +/* HACK ALERT - This goes in ksmedia.h */ +DEFINE_GUID(KSCATEGORY_WDMAUD, + 0x3e227e76L, 0x690d, 0x11d2, 0x81, 0x61, 0x00, 0x00, 0xf8, 0x77, 0x5b, 0xf1); + +/* This stores the handle of the kernel device */ +static HANDLE kernel_device_handle = NULL; + +//static WCHAR* + + +/* + TODO: There's a variant of this that uses critical sections... +*/ + +MMRESULT CallKernelDevice( + PWDMAUD_DEVICE_INFO device, + DWORD ioctl_code, + DWORD param1, + DWORD param2) +{ + OVERLAPPED overlap; + MMRESULT result = MMSYSERR_ERROR; + DWORD name_len = 0; + DWORD bytes_returned = 0; + BOOL using_critical_section = FALSE; + + ASSERT(kernel_device_handle); + ASSERT(device); + + DPRINT("Creating event\n"); + overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if ( ! overlap.hEvent ) + { + DPRINT1("CreateEvent failed - error %d\n", (int)GetLastError()); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + DPRINT("Sizeof wchar == %d\n", (int) sizeof(WCHAR)); + name_len = lstrlen(device->path) * sizeof(WCHAR); /* ok ? */ + + /* These seem to carry optional structures */ + device->ioctl_param1 = param1; + device->ioctl_param2 = param2; + + /* Enter critical section if wave/midi device, and if required */ + if ( ( ! IsMixerDeviceType(device->type) ) && + ( ! IsAuxDeviceType(device->type) ) && + ( device->with_critical_section ) ) + { + /* this seems to crash under some conditions */ + ASSERT(device->state); + using_critical_section = TRUE; + EnterCriticalSection(device->state->queue_critical_section); + } + + DPRINT("Calling DeviceIoControl with IOCTL %x\n", (int) ioctl_code); + + if ( ! DeviceIoControl(kernel_device_handle, + ioctl_code, + device, + name_len + sizeof(WDMAUD_DEVICE_INFO), + device, + sizeof(WDMAUD_DEVICE_INFO), + &bytes_returned, + &overlap) ) + { + DWORD error = GetLastError(); + + if (error != ERROR_IO_PENDING) + { + DPRINT1("FAILED in CallKernelDevice (error %d)\n", (int) error); + + DUMP_WDMAUD_DEVICE_INFO(device); + + result = TranslateWinError(error); + goto cleanup; + } + + DPRINT("Waiting for overlap I/O event\n"); + + /* Wait for the IO to be complete */ + WaitForSingleObject(overlap.hEvent, INFINITE); + } + + result = MMSYSERR_NOERROR; + DPRINT("CallKernelDevice succeeded :)\n"); + + DUMP_WDMAUD_DEVICE_INFO(device); + + cleanup : + { + /* Leave the critical section */ + if ( using_critical_section ) + LeaveCriticalSection(device->state->queue_critical_section); + + if ( overlap.hEvent ) + CloseHandle(overlap.hEvent); + + return result; + } +} + + +static BOOL ChangeKernelDeviceState(BOOL enable) +{ + PWDMAUD_DEVICE_INFO device = NULL; + DWORD ioctl_code; + MMRESULT call_result; + + ioctl_code = enable ? IOCTL_WDMAUD_HELLO : IOCTL_WDMAUD_GOODBYE; + + device = CreateDeviceData(WDMAUD_AUX, L""); + + if ( ! device ) + { + DPRINT1("Couldn't create a new device instance structure\n"); + return FALSE; + } + + DPRINT("Setting device type and disabling critical section\n"); + + device->type = WDMAUD_AUX; + device->with_critical_section = FALSE; + + DPRINT("Calling kernel device\n"); + + call_result = CallKernelDevice(device, ioctl_code, 0, 0); + + DeleteDeviceData(device); + + if ( call_result != MMSYSERR_NOERROR ) + { + DPRINT1("Kernel device doesn't like us! (error %d)\n", (int) GetLastError()); + return FALSE; + } + else + { + return TRUE; + } +} + + +BOOL EnableKernelInterface() +{ + /* SetupAPI variables/structures for querying device data */ + SP_DEVICE_INTERFACE_DATA interface_data; + PSP_DEVICE_INTERFACE_DETAIL_DATA detail = NULL; + DWORD detail_size = 0; [truncated at 1000 lines; 2036 more skipped]