Partial implementation of WDMAUD.DRV - device capability querying fails

svn path=/trunk/; revision=19530
This commit is contained in:
Andrew Greenwood 2005-11-24 14:36:47 +00:00
parent 1620efc250
commit fc3b932fc8
12 changed files with 2922 additions and 0 deletions

4
reactos/lib/wdmaud/TODO Normal file
View file

@ -0,0 +1,4 @@
To-Do:
- Globally store the heap handle
- Ensure cleanups are... clean...
- Clone device info in OPEN/close?

View file

@ -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)
{
}

View file

@ -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;
}
}

46
reactos/lib/wdmaud/helper.c Executable file
View file

@ -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;
}

358
reactos/lib/wdmaud/kernel.c Normal file
View file

@ -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;
HANDLE heap = NULL;
HDEVINFO dev_info;
/* Set to TRUE right at the end to define cleanup behaviour */
BOOL success = FALSE;
/* Don't want to be called more than once */
ASSERT(kernel_device_handle == NULL);
dev_info = SetupDiGetClassDevs(&KSCATEGORY_WDMAUD,
NULL,
NULL,
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if ( ( ! dev_info ) || ( dev_info == INVALID_HANDLE_VALUE ) )
{
DPRINT1("SetupDiGetClassDevs failed\n");
goto cleanup;
}
interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if ( ! SetupDiEnumDeviceInterfaces(dev_info,
NULL,
&KSCATEGORY_WDMAUD,
0,
&interface_data) )
{
DPRINT1("SetupDiEnumDeviceInterfaces failed\n");
goto cleanup;
}
/*
We need to find out the size of the interface detail, before we can
actually retrieve the detail. This is a bit backwards, as the function
will return a status of success if the interface is invalid, but we
need it to fail with ERROR_INSUFFICIENT_BUFFER so we can be told how
much memory we need to allocate.
*/
if ( SetupDiGetDeviceInterfaceDetail(dev_info,
&interface_data,
NULL,
0,
&detail_size,
NULL) )
{
DPRINT1("SetupDiGetDeviceInterfaceDetail shouldn't succeed!\n");
goto cleanup;
}
/*
Now we make sure the error was the one we expected. If not, bail out.
*/
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
{
DPRINT1("SetupDiGetDeviceInterfaceDetail returned wrong error code\n");
goto cleanup;
}
heap = GetProcessHeap();
if ( ! heap )
{
DPRINT1("Unable to get the process heap (error %d)\n",
(int)GetLastError());
goto cleanup;
}
detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA) HeapAlloc(heap,
HEAP_ZERO_MEMORY,
detail_size);
if ( ! detail )
{
DPRINT1("Unable to allocate memory for the detail buffer (error %d)\n",
(int)GetLastError());
goto cleanup;
}
detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if ( ! SetupDiGetDeviceInterfaceDetail(dev_info,
&interface_data,
detail,
detail_size,
0,
NULL) )
{
DPRINT1("SetupDiGetDeviceInterfaceDetail failed\n");
goto cleanup;
}
DPRINT("Device path: %S\n", detail->DevicePath);
/* FIXME - params! */
kernel_device_handle = CreateFile(detail->DevicePath,
0xC0000000,
0,
0,
3,
0x40000080,
0);
DPRINT("kernel_device_handle == 0x%x\n", (int) kernel_device_handle);
if ( ! kernel_device_handle )
{
DPRINT1("Unable to open kernel device (error %d)\n",
(int) GetLastError());
goto cleanup;
}
/* Now we say hello to wdmaud.sys */
if ( ! ChangeKernelDeviceState(TRUE) )
{
DPRINT1("Couldn't enable the kernel device\n");
goto cleanup;
}
success = TRUE;
cleanup :
{
DPRINT("Cleanup - success == %d\n", (int) success);
if ( ! success )
{
DPRINT("Failing\n");
if ( kernel_device_handle )
CloseHandle(kernel_device_handle);
}
if ( heap )
{
if ( detail )
HeapFree(heap, 0, detail);
}
}
return success;
}
/*
Nothing here should fail, but if it does, we just give up and ASSERT(). If
we don't, we could be left in a limbo-state (eg: device open but disabled.)
*/
BOOL DisableKernelInterface()
{
return ChangeKernelDeviceState(FALSE);
#if 0 /* OLD CODE */
PWDMAUD_DEVICE_INFO device = NULL;
ASSERT(kernel_device_handle);
/* Say goodbyte to wdmaud.sys */
device = CreateDeviceData(WDMAUD_AUX, L"");
ASSERT(device);
DPRINT("Setting device type and disabling critical section\n");
device->type = WDMAUD_AUX;
device->with_critical_section = FALSE;
DPRINT("Calling kernel device\n");
ASSERT( CallKernelDevice(device, IOCTL_WDMAUD_GOODBYE, 0, 0) == MMSYSERR_NOERROR );
ASSERT( CloseHandle(kernel_device_handle) );
DPRINT("Kernel interface now disabled\n");
kernel_device_handle = NULL;
DeleteDeviceData(device);
#endif
}
/*
The use of this should be avoided...
*/
HANDLE GetKernelInterface()
{
return kernel_device_handle;
}

View file

@ -0,0 +1,235 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/threads.c
* PURPOSE: WDM Audio Support - Completion Threads
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*/
#include "wdmaud.h"
DWORD WINAPI WaveCompletionThreadStart(LPVOID data)
{
PWDMAUD_DEVICE_INFO device = (PWDMAUD_DEVICE_INFO) data;
MMRESULT result = MMSYSERR_ERROR;
PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL;
HANDLE overlap_event = NULL;
BOOL quit_loop = FALSE;
DPRINT("WaveCompletionThread started\n");
EnterCriticalSection(device->state->queue_critical_section);
while ( ! quit_loop )
{
result = ValidateDeviceInfoAndState(device);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Invalid device data or state structure!\n");
break;
}
result = ValidateDeviceStateEvents(device->state);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Invalid device state events\n");
break;
}
if ( device->state->open_descriptor )
{
DPRINT("No open descriptor found - running? %d\n", (int) device->state->is_running);
if ( ! device->state->is_running )
{
LeaveCriticalSection(device->state->queue_critical_section);
DPRINT("Waiting for queue_event\n");
WaitForSingleObject(device->state->queue_event, INFINITE);
DPRINT("field 24 == %d\n", (int) device->state->unknown_24);
/* What is the importance of this field */
if ( ! device->state->unknown_24 )
{
/* ?!?! Presumably this dequeues */
continue;
}
DPRINT("We broke out the loop! Yay!\n");
/* TODO! */
return TRUE; /* bleh */
}
else
{
/* TODO: STOP */
DPRINT("TODO: Stop the device\n");
}
}
else
{
PWAVEHDR wave_header = device->state->wave_header;
DPRINT("An open descriptor or wave header was found\n");
result = ValidateWaveHeader(wave_header);
if ( result == MMSYSERR_NOERROR )
{
prep_data = (PWDMAUD_WAVE_PREPARATION_DATA) wave_header->reserved;
result = ValidateWavePreparationData(prep_data);
}
/* If both checks passed, the playback is complete */
if ( result != MMSYSERR_NOERROR )
{
result = MMSYSERR_NOERROR;
DPRINT("Activating the next header\n");
/* Activate the next header */
device->state->wave_header = wave_header->lpNext;
/* Reset this just in case */
prep_data = NULL;
/* continue; */
}
else
{
/* Should have valid prep data... */
overlap_event = prep_data->overlapped->hEvent;
/* Setting this will cause the loop to exit now */
quit_loop = TRUE;
}
}
}
/* We do this here in case there's an error - deadlock = bad! */
LeaveCriticalSection(device->state->queue_critical_section);
if ( result != MMSYSERR_NOERROR)
goto cleanup;
DPRINT("Waiting for object: %d\n", (int) overlap_event);
WaitForSingleObject(overlap_event, INFINITE);
cleanup :
{
DPRINT("Performing thread cleanup\n");
/* Yeah, like what? */
return result;
}
}
DWORD WINAPI MidiCompletionThreadStart(LPVOID data)
{
DPRINT("MidiCompletionThread started\n");
return 0;
}
BOOL CreateCompletionThread(PWDMAUD_DEVICE_INFO device)
{
LPTHREAD_START_ROUTINE thread_start = NULL;
if ( IsWaveDeviceType(device->type) )
thread_start = WaveCompletionThreadStart;
else if ( IsMidiDeviceType(device->type) )
thread_start = MidiCompletionThreadStart;
else
return FALSE; /* What did you just give me?! */
if ( device->state->unknown_30 != 0 )
{
DPRINT1("unknown_30 wasn't zero (it was %d)\n",
(int) device->state->unknown_30);
}
if ( device->state->thread )
{
DPRINT("Thread isn't null\n");
}
else
{
DPRINT("Thread is null\n");
if ( ( (DWORD) device->state->queue_event != 0 ) &&
( (DWORD) device->state->queue_event != MAGIC_42) &&
( (DWORD) device->state->queue_event != MAGIC_43) )
{
/* Not fatal... */
DPRINT("Queue event is being overwritten!\n");
/* return FALSE; */
}
device->state->queue_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! device->state->queue_event )
{
/* TODO - hmm original doesn't seem to care what happens */
}
if ( ( (DWORD) device->state->exit_thread_event != 0x00000000 ) &&
( (DWORD) device->state->exit_thread_event != 0x48484848 ) )
{
/* Not fatal... */
DPRINT("Exit Thread event is being overwritten!\n");
/* return FALSE; */
}
device->state->exit_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! device->state->exit_thread_event )
{
/* TODO - hmm original doesn't seem to care what happens */
}
device->state->thread = NULL;
/* Should this be unknown_04? aka THREAD? */
device->state->thread = CreateThread(NULL, 0, thread_start, device, 0,
&device->state->thread_id);
if ( ! device->state->thread )
{
DPRINT1("Thread creation failed (error %d)\n",
(int) GetLastError());
if ( device->state->queue_event )
{
CloseHandle(device->state->queue_event);
device->state->queue_event = NULL;
}
if ( device->state->exit_thread_event )
{
CloseHandle(device->state->exit_thread_event);
device->state->exit_thread_event = NULL;
}
return FALSE;
}
SetThreadPriority(device->state->thread, 0xf);
DPRINT("Thread created! - %d\n", (int) device->state->thread);
/* TODO: Set priority */
}
return TRUE; /* TODO / FIXME */
}

387
reactos/lib/wdmaud/user.c Normal file
View file

@ -0,0 +1,387 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/user.c
* PURPOSE: WDM Audio Support - User Mode Interface
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*/
/*
* The GETDEVCAPS message parameters have different meaning in our case.
* The second parameter usually indicates the struct size. But this has
* been replaced by a pointer to the device path.
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include "wdmaud.h"
APIENTRY LONG DriverProc(
DWORD DriverID,
HDRVR DriverHandle,
UINT Message,
LONG Param1,
LONG Param2)
{
/*
Only DRV_ENABLE and DRV_DISABLE need special handling - everything else
is just implemented to aid in debugging.
*/
DPRINT("DriverProc %d %d %d %d %d\n", (INT) DriverID, (int) DriverHandle, (int) Message, (int) Param1, (int) Param2);
switch(Message)
{
/*
DRV_LOAD is the first message we receive, to say we've been loaded.
DriverHandle is documented as being unused, but appears to be the
number 3 (on my system, at least.)
*/
case DRV_LOAD :
DPRINT("DRV_LOAD\n");
/* We should initialize the device list */
return DRV_OK; // dont need to do any more
case DRV_FREE :
/* We should stop all wave and MIDI playback */
DPRINT("DRV_FREE\n");
return DRV_OK;
/*
DRV_OPEN is sent when WINMM wishes to open the driver. Param1
can specify configuration information, but we don't need any.
*/
case DRV_OPEN :
return DRV_OK;
case DRV_CLOSE :
DPRINT("DRV_CLOSE\n");
return DRV_OK;
/*
Enabling this driver causes the kernel-mode portion of WDMAUD to
be opened. We send a message to the kernel-mode driver to say that
we want to make use of it.
And, of course, when we are being disabled, we tell the kernel-mode
portion that we don't require its services any more, and close
the handle to it.
*/
case DRV_ENABLE :
{
DPRINT("DRV_ENABLE\n");
return EnableKernelInterface();
}
case DRV_DISABLE :
DPRINT("DRV_DISABLE\n");
DisableKernelInterface();
return DRV_OK;
/*
We don't actually support configuration or installation, so these
could probably be safely pruned.
*/
case DRV_QUERYCONFIGURE :
DPRINT("DRV_QUERYCONFIGURE\n");
return FALSE;
case DRV_CONFIGURE :
DPRINT("DRV_CONFIGURE\n");
return FALSE;
case DRV_INSTALL :
DPRINT("DRV_INSTALL\n");
return FALSE; /* ok? */
/* DRV_REMOVE */
default :
DPRINT("?\n");
return DefDriverProc(DriverID, DriverHandle, Message, Param1, Param2);
};
}
void NotifyClient(
PWDMAUD_DEVICE_INFO device,
DWORD message,
DWORD p1,
DWORD p2
)
{
DPRINT("Calling client\n");
DriverCallback(device->client_callback,
HIWORD(device->flags),
(HDRVR) device->wave_handle,
message,
device->client_instance,
0,
0);
}
APIENTRY DWORD widMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2
)
{
DPRINT("widMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("WIDM_INIT\n");
return AddWaveInDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("WIDM_EXIT\n");
return RemoveWaveInDevice((WCHAR*) p2); /* FIXME */
case WIDM_GETNUMDEVS :
DPRINT("WIDM_GETNUMDEVS\n");
return GetWaveInCount((WCHAR*) p1);
case WIDM_GETDEVCAPS :
DPRINT("WIDM_GETDEVCAPS\n");
return GetWaveInCapabilities(id, (WCHAR*) p2, (LPCOMMONCAPS) p1);
};
return MMSYSERR_NOERROR;
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD wodMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2)
{
DPRINT("wodMessage %d %d %d %d %d\n",
(int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
/*
* DRVM_INIT
* Parameter 1 : Not used
* Parameter 2 : Topology path
*/
case DRVM_INIT :
DPRINT("DRVM_INIT\n");
return AddWaveOutDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("DRVM_EXIT\n");
return RemoveWaveInDevice((WCHAR*) p2); /* FIXME? */
/*
* WODM_GETNUMDEVS
* Parameter 1 : Topology device path
* Parameter 2 : Not used
*/
case WODM_GETNUMDEVS :
DPRINT("WODM_GETNUMDEVS\n");
return GetWaveOutCount((WCHAR*) p1);
/*
* WODM_GETDEVCAPS
* Parameter 1 : Pointer to a WAVEOUTCAPS struct
* Parameter 2 : "Wave" device path? FIXME (NEW!)
*/
case WODM_GETDEVCAPS :
DPRINT("WODM_GETDEVCAPS\n");
return GetWaveOutCapabilities(id, (WCHAR*) p2, (LPCOMMONCAPS) p1);
/*
* WODM_OPEN
* Parameter 1 : Pointer to a WAVEOPENDESC struct (the dnDevNode
* member holds a device path.)
* Parameter 2 : Flags
*/
case WODM_OPEN :
DPRINT("WODM_OPEN\n");
return OpenWaveOut(id, (LPWAVEOPENDESC) p1, p2, user);
case WODM_CLOSE :
DPRINT("WODM_CLOSE\n");
return CloseDevice((PWDMAUD_DEVICE_INFO) user); /* ugh! */
case WODM_PREPARE :
DPRINT("WODM_PREPARE\n");
return PrepareWaveHeader((PWDMAUD_DEVICE_INFO) user,
(PWAVEHDR) p1);
case WODM_UNPREPARE :
DPRINT("WODM_UNPREPARE\n");
return UnprepareWaveHeader((PWAVEHDR) p1);
case WODM_WRITE :
DPRINT("WODM_WRITE\n");
return WriteWaveData((PWDMAUD_DEVICE_INFO) user,
(PWAVEHDR) p1);
}
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD midMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2
)
{
DPRINT("midMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("MIDM_INIT\n");
return AddMidiInDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("MIDM_EXIT\n");
return RemoveMidiInDevice((WCHAR*) p2); /* FIXME */
case MIDM_GETNUMDEVS :
DPRINT("MIDM_GETNUMDEVS\n");
return GetMidiInCount((WCHAR*) p1);
case MIDM_GETDEVCAPS :
DPRINT("MIDM_GETDEVCAPS\n");
return GetMidiInCapabilities(id, (WCHAR*) p2, (LPCOMMONCAPS) p1);
};
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD modMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2
)
{
DPRINT("modMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("MODM_INIT\n");
return AddMidiOutDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("MODM_EXIT\n");
return RemoveMidiOutDevice((WCHAR*) p2); /* FIXME */
case MODM_GETNUMDEVS :
DPRINT("MODM_GETNUMDEVS\n");
return GetMidiOutCount((WCHAR*) p1);
case MODM_GETDEVCAPS :
DPRINT("MODM_GETDEVCAPS\n");
return GetMidiOutCapabilities(id, (WCHAR*) p2, (LPCOMMONCAPS) p1);
};
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD mxdMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2
)
{
DPRINT("mxdMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("MXDM_INIT\n");
return AddMixerDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("MXDM_EXIT\n");
return RemoveMixerDevice((WCHAR*) p2); /* FIXME */
case MXDM_GETNUMDEVS :
DPRINT("MXDM_GETNUMDEVS\n");
return GetMixerCount((WCHAR*) p1);
case MXDM_GETDEVCAPS :
DPRINT("MXDM_GETDEVCAPS\n");
return GetMixerCapabilities(id, (WCHAR*) p2, (LPCOMMONCAPS) p1);
/* ... */
};
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD auxMessage(DWORD id, DWORD message, DWORD user, DWORD p1, DWORD p2)
{
DPRINT("auxMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("AUXDM_INIT\n");
return AddAuxDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("AUXDM_EXIT\n");
return RemoveAuxDevice((WCHAR*) p2); /* FIXME */
case AUXDM_GETNUMDEVS :
DPRINT("AUXDM_GETNUMDEVS\n");
return GetAuxCount((WCHAR*) p1);
case AUXDM_GETDEVCAPS :
DPRINT("AUXDM_GETDEVCAPS\n");
return GetAuxCapabilities(id, (WCHAR*) p2, (LPCOMMONCAPS) p1);
/* ... */
};
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved)
{
DPRINT("DllMain called!\n");
if (Reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hInstance);
}
else if (Reason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
/* EOF */

View file

@ -0,0 +1,601 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/wavehdr.c
* PURPOSE: WDM Audio Support - Wave Header Manipulation
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*/
#include <windows.h>
#include "wdmaud.h"
const char WAVE_PREPARE_DATA_SIG[4] = "WPPD";
/*
ValidateWaveHeaderPreparation Overview :
First, check to see if we can write to the buffer given to us. Fail
if we can't (invalid parameter?)
Make sure the signature matches "WPPD". Fail if not (invalid param?)
Finally, validate the "overlapped" member, by checking to see if
that buffer is writable, and ensuring hEvent is non-NULL.
*/
MMRESULT ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data)
{
return MMSYSERR_NOERROR;
}
/*
ValidateWaveHeader Overview :
Check that the pointer is valid to write to. If not, signal invalid
parameter.
Perform a bitwise AND on the flags & 0xFFFFFFE0. If there are no bits
set, that's good. Otherwise give error and leave.
Check that the "reserved" member contains a valid WAVEPREPAREDATA
structure.
Return MMSYSERR_NOERROR if all's well!
*/
MMRESULT ValidateWaveHeader(PWAVEHDR header)
{
DWORD flag_check;
if ( IsBadWritePtr(header, sizeof(WAVEHDR)) )
{
DPRINT1("Bad write pointer\n");
return MMSYSERR_INVALPARAM;
}
flag_check = header->dwFlags & 0xffffffe0; /* FIXME: Use flag names */
if ( flag_check )
{
DPRINT1("Unknown flags present\n");
return MMSYSERR_INVALPARAM;
}
return ValidateWavePreparationData(
(PWDMAUD_WAVE_PREPARATION_DATA) header->reserved);
}
/*
PrepareWaveHeader Overview :
Validate the parameters.
Allocate and lock 12 bytes of global memory (fixed, zeroed) for the
WAVEPREPAREDATA structure.
If that fails, return immediately.
Otherwise, allocate 20 bytes of memory on the process heap (with no
special flags.) This is for the overlapped member of the WAVEPREPAREDATA
structure.
If the HeapAlloc failed, free the global memory and return.
Create an event with all parameters false, NULL or zero. This is to be
stored as the hEvent member of the OVERLAPPED structure.
If the event creation failed, free all memory used and return.
If it succeeded, set the WAVEPREPAREDATA signature to "WPPD", and set
the reserved member of "header" to the pointer of the WAVEPREPAREDATA
instance.
Return MMSYSERR_NOTSUPPORTED so that winmm does further processing.
*/
MMRESULT PrepareWaveHeader(
PWDMAUD_DEVICE_INFO device,
PWAVEHDR header
)
{
MMRESULT result = MMSYSERR_ERROR;
PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL;
HANDLE heap = NULL;
DPRINT("PrepareWaveHeader called\n");
result = ValidateDeviceInfoAndState(device);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad device info or device state\n");
return result;
}
/* Make sure we were actually given a header to process */
DPRINT("Checking that a header was supplied\n");
if ( ! header )
{
DPRINT1("Bad header\n");
return MMSYSERR_INVALPARAM;
}
DPRINT("Checking flags\n");
/* I don't think Winmm would let this happen, but ya never know */
/*
ASSERT( ! header->dwFlags & WHDR_PREPARED );
ASSERT( header->dwFlags & WHDR_INQUEUE );
*/
header->lpNext = NULL;
header->reserved = 0;
heap = GetProcessHeap();
if ( ! heap )
{
DPRINT1("Couldn't obtain the process heap (error %d)\n",
(int)GetLastError());
result = MMSYSERR_NOMEM;
goto fail;
}
DPRINT("Allocating preparation data\n");
prep_data =
(PWDMAUD_WAVE_PREPARATION_DATA)
HeapAlloc(heap,
HEAP_ZERO_MEMORY,
sizeof(WDMAUD_WAVE_PREPARATION_DATA));
if ( ! prep_data )
{
DPRINT1("Couldn't lock global memory for preparation data (error %d)\n",
(int)GetLastError());
result = MMSYSERR_NOMEM;
goto fail;
}
DPRINT("Allocating overlapped data\n");
prep_data->overlapped = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(OVERLAPPED));
if ( ! prep_data->overlapped )
{
DPRINT1("Couldn't allocate heap memory for overlapped structure (error %d)\n",
(int)GetLastError());
result = MMSYSERR_NOMEM;
goto fail;
}
DPRINT("Creating overlapped event\n");
prep_data->overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! prep_data->overlapped->hEvent )
{
DPRINT1("Creation of overlapped event failed (error %d)\n",
(int)GetLastError());
result = MMSYSERR_NOMEM;
goto fail;
}
/* Copy the signature over and tie the prepare structure to the wave header */
DPRINT("Copying signature\n");
*prep_data->signature = *WAVE_PREPARE_DATA_SIG;
header->reserved = (DWORD) prep_data;
result = MMSYSERR_NOTSUPPORTED;
return result;
fail :
{
if ( heap )
{
if ( prep_data )
{
if ( prep_data->overlapped )
{
if ( prep_data->overlapped->hEvent )
CloseHandle(prep_data->overlapped->hEvent); /* ok? */
HeapFree(heap, 0, prep_data->overlapped);
}
HeapFree(heap, 0, prep_data);
}
}
return result;
}
}
/*
UnprepareWaveHeader
Winmm is intelligent enough to not call this function with a header that
is currently queued for playing!
*/
MMRESULT UnprepareWaveHeader(PWAVEHDR header)
{
HANDLE heap = NULL;
MMRESULT result = MMSYSERR_ERROR;
PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL;
DPRINT("UnprepareHeader called\n");
/* Make sure we were actually given a header to process */
if ( ! header )
{
DPRINT1("Bad header supplied\n");
return MMSYSERR_INVALPARAM;
}
prep_data = (PWDMAUD_WAVE_PREPARATION_DATA) header->reserved;
result = ValidateWavePreparationData(prep_data);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad wave header preparation structure pointer\n");
return result;
}
/*
Overview :
Set "reserved" to NULL.
Close the event handle (overlapped->hEvent) and set that
structure member to NULL (not strictly necessary.)
Obtain the heap pointer and free the heap-allocated and global
memory allocated in PrepareWaveHeader.
*/
/* We're about to free the preparation structure, so this needs to go */
header->reserved = 0;
CloseHandle(prep_data->overlapped->hEvent);
heap = GetProcessHeap();
if ( ! heap )
{
/* Not quite sure how we handle this */
DPRINT1("Couldn't obtain the process heap (error %d)\n",
(int)GetLastError());
result = MMSYSERR_ERROR;
goto cleanup;
}
if ( ! HeapFree(heap, 0, prep_data->overlapped) )
{
DPRINT1("Unable to free the OVERLAPPED memory (error %d)\n",
(int)GetLastError());
/* This shouldn't happen! */
ASSERT(FALSE);
}
/* Overwrite the signature (structure will be invalid from now on) */
ZeroMemory(prep_data->signature, 4);
if ( ! HeapFree(heap, 0, prep_data) )
{
DPRINT1("Unable to free the preparation structure memory (error %d)\n",
(int)GetLastError());
/* This shouldn't happen! */
ASSERT(FALSE);
}
/* Always return like this so winmm thinks we didn't do anything */
DPRINT("Header now unprepared.\n");
result = MMSYSERR_NOTSUPPORTED;
cleanup :
return result;
}
/* Not sure about this */
MMRESULT CompleteWaveHeader(PWAVEHDR header)
{
return MMSYSERR_NOTSUPPORTED;
}
/*
SubmitWaveHeader Overview :
This may span 2 functions (this one and and another "SubmitHeader")
First, validate the device info, then the state.
Validate the header, followed by the reserved member.
Fail if INQUEUE flag is set in header, or if PREPARED is not set in
header.
AND the flags with PREPARED, BEGINLOOP, ENDLOOP and INQUEUE. OR the
result with INQUEUE.
Enter the csQueue critical section.
Check if the device state's "open descriptor" member is NULL or not.
If we're adding an extra buffer, it will already have been allocated.
If the open descriptor is NULL:
If it's NULL, set "opendesc" to point to the wave header (?!)
If the state structure's "hevtQueue" member isn't NULL, compare it's
value to 0x43434343h and 0x42424242h. If it's not NULL or one of
those values, set the event.
If the open descriptor is NOT NULL:
Check the header's lpNext member. If it's not NULL, check that
structure's lpNext member, and so on, until a NULL entry is
found.
Set the NULL entry to point to our header.
Leave the csQueue critical section.
** SUBMIT THE HEADER ** TODO **
If submission failed:
AND the flags with 0xFFFFFFEFh. If csQueue is set in the target
(the header who's lpNext was NULL), set it to NULL. Set the open
descriptor of state to NULL, too. And fail, of course.
If the device state is PAUSED or RUNNING, we must fail.
Otherwise, reset the device and set it as RUNNING. This may be done by
our caller (wodMessage, etc.)
0x1d8104 is used for wave in
0x1d8148 is used for wave out?
SetDeviceState should now be called with the above IOCTL code and the
device info structure.
*/
static MMRESULT ValidateWriteWaveDataParams(
PWDMAUD_DEVICE_INFO device,
PWAVEHDR header
)
{
MMRESULT result;
result = ValidateWaveHeader(header);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad wave header supplied\n");
return result;
}
/*
We don't want to queue something already queued, and we don't want
to queue something that hasn't been prepared. Who knows what garbage
might be sent to us?!
*/
if ( header->dwFlags & WHDR_INQUEUE )
{
DPRINT1("This header is already queued!\n");
return MMSYSERR_INVALFLAG;
}
if ( ! header->dwFlags & WHDR_PREPARED )
{
DPRINT1("This header isn't prepared!\n");
return WAVERR_UNPREPARED;
}
result = ValidateDeviceInfoAndState(device);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad device info or device state supplied\n");
return result;
}
return result;
}
MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header)
{
MMRESULT result = MMSYSERR_ERROR;
DWORD io_result = 0;
PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL;
PWDMAUD_DEVICE_INFO clone;
/* For the DeviceIoControl later */
DWORD ioctl_code;
DWORD bytes_returned;
DPRINT("SubmitWaveHeader called\n");
result = ValidateWriteWaveDataParams(device, header);
if ( result != MMSYSERR_NOERROR )
return result;
/*
TODO: Check to see if we actually get called with bad flags!
*/
/* Retrieve our precious data from the reserved member */
prep_data = (PWDMAUD_WAVE_PREPARATION_DATA) header->reserved;
result = ValidateWavePreparationData(prep_data);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad wave preparation structure supplied\n");
return result;
}
DPRINT("Flags == 0x%x\n", (int) header->dwFlags);
/* Mask the "done" flag */
CLEAR_WAVEHDR_FLAG(header, WHDR_DONE);
/* header->dwFlags &= ~WHDR_DONE; */
/* ...and set the queue flag! */
SET_WAVEHDR_FLAG(header, WHDR_INQUEUE);
/* header->dwFlags |= WHDR_INQUEUE; */
DPRINT("Flags == 0x%x\n", (int) header->dwFlags);
EnterCriticalSection(device->state->queue_critical_section);
if ( ! device->state->wave_header )
{
DPRINT("Device state wave_header is NULL\n");
device->state->wave_header = header;
/* My, what pretty symmetry you have... */
DPRINT("Queue event == %d\n", (int) device->state->queue_event);
if ( ( (DWORD) device->state->queue_event != 0 ) &&
( (DWORD) device->state->queue_event != MAGIC_42 ) &&
( (DWORD) device->state->queue_event != MAGIC_43 ) )
{
DPRINT("Setting queue event\n");
SetEvent(device->state->queue_event);
}
}
else
{
DPRINT("Device state open_descriptor is NOT NULL\n");
/* TODO */
ASSERT(FALSE);
}
LeaveCriticalSection(device->state->queue_critical_section);
/* CODE FROM SUBMITWAVEHEADER */
DPRINT("Now we actually perform header submission\n");
clone = CloneDeviceData(device);
if ( ! clone )
{
/* Safe to do this? */
DPRINT1("Clone creation failed\n");
return MMSYSERR_NOMEM;
}
if ( ! IsHeaderPrepared(header) )
{
DPRINT1("Unprepared header!\n");
DeleteDeviceData(clone);
return MMSYSERR_INVALPARAM;
}
/* Not sure what this is for */
prep_data->offspring = clone;
/* The modern version of WODM_WRITE, I guess ;) */
clone->ioctl_param1 = sizeof(WAVEHDR);
clone->ioctl_param2 = (DWORD) header;
ioctl_code = clone->type == WDMAUD_WAVE_IN
? 0x1d8150 /* FIXME */
: IOCTL_WDMAUD_SUBMIT_WAVE_HDR;
DPRINT("Overlapped == 0x%x\n", (int) prep_data->overlapped);
/*
FIXME:
For wave input to work, we may need to pass different parameters.
*/
/* We now send the header to the driver */
io_result =
DeviceIoControl(GetKernelInterface(),
ioctl_code,
clone,
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(clone->path) * 2),
clone,
sizeof(WDMAUD_DEVICE_INFO),
&bytes_returned, /* ... */
prep_data->overlapped);
DPRINT("Wave header submission result : %d\n", (int) io_result);
if ( io_result != STATUS_SUCCESS )
{
DPRINT1("Wave header submission FAILED! (error %d)\n", (int) io_result);
CLEAR_WAVEHDR_FLAG(header, WHDR_INQUEUE);
device->state->queue_critical_section = NULL;
device->state->wave_header = NULL;
return TranslateWinError(io_result);
}
/* CallKernelDevice(clone, ioctl_code, 0x20, (DWORD) header); */
DPRINT("Creating completion thread\n");
if ( ! CreateCompletionThread(device) )
{
DPRINT1("Couldn't create completion thread\n");
CLEAR_WAVEHDR_FLAG(header, WHDR_INQUEUE);
device->state->queue_critical_section = NULL;
device->state->wave_header = NULL;
return MMSYSERR_ERROR; /* Care to be more specific? */
}
/* TODO */
DPRINT("applying hacks\n");
DPRINT("Running %d paused %d\n", (int)device->state->is_running, (int)device->state->is_paused);
#if 1
/* HACK */
DPRINT("%d\n", (int)
DeviceIoControl(GetKernelInterface(),
0x1d8104,
device,
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2),
device,
sizeof(WDMAUD_DEVICE_INFO),
&bytes_returned, /* ... */
prep_data->overlapped) );
DPRINT("Running %d paused %d\n", (int)device->state->is_running, (int)device->state->is_paused);
#if 0 /* on error */
DPRINT("%d\n", (int)
DeviceIoControl(GetKernelInterface(),
0x1d8148,
device,
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2),
device,
sizeof(WDMAUD_DEVICE_INFO),
&bytes_returned, /* ... */
prep_data->overlapped) );
#endif
#endif
result = MMSYSERR_NOERROR;
return result;
}

15
reactos/lib/wdmaud/wdmaud.def Executable file
View file

@ -0,0 +1,15 @@
; $Id: wdmaud.def 12852 2005-01-06 13:58:04Z mf $
;
; wdmaud.def
;
; ReactOS Operating System
;
LIBRARY wdmaud.drv
EXPORTS
DriverProc@20
;widMessage@20
wodMessage@20
;midMessage@20
;modMessage@20
;mxdMessage@20
;auxMessage@20

507
reactos/lib/wdmaud/wdmaud.h Executable file
View file

@ -0,0 +1,507 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/wdmaud.h
* PURPOSE: WDM Audio Support - Common header
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 12, 2005: Declarations for debugging + interface
*/
#ifndef __WDMAUD_PRIVATE_H__
#define __WDMAUD_PRIVATE_H__
/* Debugging */
/*
Some of this stuff belongs in ksmedia.h or other such global includes.
*/
#include <stdio.h>
#include <debug.h>
#include <ddk/ntddk.h>
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
/* HACK! */
#define DbgPrint printf
/* TODO: Put elsewhere */
#if 0
typedef struct tagWAVEOUTCAPS2A {
WORD wMid; /* manufacturer ID */
WORD wPid; /* product ID */
MMVERSION vDriverVersion; /* version of the driver */
CHAR szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
DWORD dwFormats; /* formats supported */
WORD wChannels; /* number of sources supported */
WORD wReserved1; /* packing */
DWORD dwSupport; /* functionality supported by driver */
GUID ManufacturerGuid; /* for extensible MID mapping */
GUID ProductGuid; /* for extensible PID mapping */
GUID NameGuid; /* for name lookup in registry */
} WAVEOUTCAPS2A, *PWAVEOUTCAPS2A, *NPWAVEOUTCAPS2A, *LPWAVEOUTCAPS2A;
typedef struct tagWAVEOUTCAPS2W {
WORD wMid; /* manufacturer ID */
WORD wPid; /* product ID */
MMVERSION vDriverVersion; /* version of the driver */
WCHAR szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
DWORD dwFormats; /* formats supported */
WORD wChannels; /* number of sources supported */
WORD wReserved1; /* packing */
DWORD dwSupport; /* functionality supported by driver */
GUID ManufacturerGuid; /* for extensible MID mapping */
GUID ProductGuid; /* for extensible PID mapping */
GUID NameGuid; /* for name lookup in registry */
} WAVEOUTCAPS2W, *PWAVEOUTCAPS2W, *NPWAVEOUTCAPS2W, *LPWAVEOUTCAPS2W;
#ifdef UNICODE
typedef WAVEOUTCAPS2W WAVEOUTCAPS2;
typedef PWAVEOUTCAPS2W PWAVEOUTCAPS2;
typedef NPWAVEOUTCAPS2W NPWAVEOUTCAPS2;
typedef LPWAVEOUTCAPS2W LPWAVEOUTCAPS2;
#else
typedef WAVEOUTCAPS2A WAVEOUTCAPS2;
typedef PWAVEOUTCAPS2A PWAVEOUTCAPS2;
typedef NPWAVEOUTCAPS2A NPWAVEOUTCAPS2;
typedef LPWAVEOUTCAPS2A LPWAVEOUTCAPS2;
#endif // UNICODE
#endif
/*
Handy macros
*/
#define REPORT_MM_RESULT(message, success) \
DPRINT("%s %s\n", message, success == MMSYSERR_NOERROR ? "succeeded" : "failed")
/*
Private IOCTLs shared between wdmaud.sys and wdmaud.drv
TO ADD/MODIFY:
IOCTL_WDMAUD_OPEN_PIN
IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN
IOCTL_WDMAUD_WAVE_IN_READ_PIN
IOCTL_WDMAUD_MIXER_CLOSE
IOCTL_WDMAUD_MIXER_OPEN
IOCTL_WDMAUD_MIDI_IN_READ_PIN
IOCTL_WDMAUD_MIXER_GETLINEINFO
IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA
IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS
IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS
IOCTL_WDMAUD_MIXER_GETLINECONTROLS
*/
/* 0x1d8000 */
#define IOCTL_WDMAUD_HELLO \
CTL_CODE(FILE_DEVICE_SOUND, 0x0000, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WDMAUD_ADD_DEVICE 0x1d8004
#define IOCTL_WDMAUD_REMOVE_DEVICE 0x1d8008
#define IOCTL_WDMAUD_GET_CAPABILITIES 0x1d800c
#define IOCTL_WDMAUD_GET_DEVICE_COUNT 0x1d8010
#define IOCTL_WDMAUD_OPEN_DEVICE 0x1d8014
#define IOCTL_WDMAUD_CLOSE_DEVICE 0x1d8018
#define IOCTL_WDMAUD_AUX_GET_VOLUME 0x1d801c
#define IOCTL_WDMAUD_AUX_SET_VOLUME 0x1d8020
/* 0x1d8024 */
#define IOCTL_WDMAUD_GOODBYE \
CTL_CODE(FILE_DEVICE_SOUND, 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WDMAUD_SET_PREFERRED 0x1d8028
#define IOCTL_WDMAUD_SET_STATE_UNKNOWN1 0x1d8100
#define IOCTL_WDMAUD_WAVE_OUT_START 0x1d8104 /* Reset wave in? */
#define IOCTL_WDMAUD_SET_STATE_UNKNOWN3 0x1d8108 /* Start wave in? */
#define IOCTL_WDMAUD_BREAK_LOOP 0x1d810c
#define IOCTL_WDMAUD_GET_WAVE_OUT_POS 0x1d8110 /* Does something funky */
#define IOCTL_WDMAUD_SET_VOLUME 0x1d8114 /* Hasn't this already been covered? */
#define IOCTL_WDMAUD_UNKNOWN1 0x1d8018 /* Not used by wdmaud.drv */
#define IOCTL_WDMAUD_SUBMIT_WAVE_HDR 0x1d811c
#define IOCTL_WDMAUD_SET_STATE_UNKNOWN4 0x1d8140
#define IOCTL_WDMAUD_WAVE_IN_START 0x1d8144 /* Reset wave out? */
#define IOCTL_WDMAUD_SET_STATE_UNKNOWN6 0x1d8148 /* Start wave out? */
#define IOCTL_WDMAUD_MIDI_OUT_SHORT_MESSAGE \
0x1d8204 /* Wrong description? */
#define IOCTL_WDMAUD_UNKNOWN2 0x1d8208
#define IOCTL_WDMAUD_MIDI_OUT_LONG_MESSAGE \
0x1d820c
#define IOCTL_WDMAUD_SUBMIT_MIDI_HDR 0x1d8210
#define IOCTL_WDMAUD_SET_STATE_UNKNOWN7 0x1d8240
#define IOCTL_WDMAUD_SET_STATE_UNKNOWN8 0x1d8244
#define IOCTL_WDMAUD_SET_STATE_UNKNOWN9 0x1d8248
#define IOCTL_WDMAUD_READ_MIDI_DATA 0x1d824c
#define IOCTL_WDMAUD_MIDI_MESSAGE 0x1d8300 /* Wrong description? */
#define IOCTL_WDMAUD_MIXER_UNKNOWN1 0x1d8310
#define IOCTL_WDMAUD_MIXER_UNKNOWN2 0x1d8314
#define IOCTL_WDMAUD_MIXER_UNKNOWN3 0x1d8318
/*
Device Types
*/
enum
{
WDMAUD_WAVE_IN = 0,
WDMAUD_WAVE_OUT,
WDMAUD_MIDI_IN,
WDMAUD_MIDI_OUT,
WDMAUD_MIXER,
WDMAUD_AUX,
/* For range checking */
WDMAUD_MIN_DEVICE_TYPE = WDMAUD_WAVE_IN,
WDMAUD_MAX_DEVICE_TYPE = WDMAUD_AUX
};
/*
Some macros for device type matching and checking
*/
#define IsWaveInDeviceType(device_type) (device_type == WDMAUD_WAVE_IN)
#define IsWaveOutDeviceType(device_type) (device_type == WDMAUD_WAVE_OUT)
#define IsMidiInDeviceType(device_type) (device_type == WDMAUD_MIDI_IN)
#define IsMidiOutDeviceType(device_type) (device_type == WDMAUD_MIDI_OUT)
#define IsMixerDeviceType(device_type) (device_type == WDMAUD_MIXER)
#define IsAuxDeviceType(device_type) (device_type == WDMAUD_AUX)
#define IsWaveDeviceType(device_type) \
(IsWaveInDeviceType(device_type) || IsWaveOutDeviceType(device_type))
#define IsMidiDeviceType(device_type) \
(IsMidiInDeviceType(device_type) || IsMidiOutDeviceType(device_type))
#define IsValidDeviceType(device_type) \
(device_type >= WDMAUD_MIN_DEVICE_TYPE && \
device_type <= WDMAUD_MAX_DEVICE_TYPE)
/*
The various "caps" (capabilities) structures begin with the same members,
so a generic structure is defined here which can be accessed independently
of a device type.
*/
typedef struct
{
WORD wMid;
WORD wPid;
MMVERSION vDriverVersion;
WCHAR szPname[MAXPNAMELEN];
} COMMONCAPSW, *LPCOMMONCAPSW;
/* Unicode, anyone? */
typedef COMMONCAPSW COMMONCAPS;
typedef LPCOMMONCAPSW LPCOMMONCAPS;
/* More abstraction */
typedef LPVOID PWDMAUD_HEADER;
/*
There are also various "opendesc" structures, but these don't have any
common members. Regardless, this typedef simply serves as a placeholder
to indicate that to access the members, it should be cast accordingly.
*/
typedef struct OPENDESC *LPOPENDESC;
typedef struct
{
DWORD sample_size;
HANDLE thread;
DWORD thread_id;
union
{
LPWAVEOPENDESC open_descriptor;
LPWAVEHDR wave_header;
};
DWORD unknown_10; /* pointer to something */
DWORD unknown_14;
LPCRITICAL_SECTION queue_critical_section;
HANDLE queue_event;
HANDLE exit_thread_event;
DWORD unknown_24;
DWORD is_paused;
DWORD is_running;
DWORD unknown_30;
DWORD unknown_34;
DWORD unknown_38;
char signature[4];
} WDMAUD_DEVICE_STATE, *PWDMAUD_DEVICE_STATE;
typedef struct
{
DWORD unknown_00;
DWORD id;
DWORD type;
HWAVE wave_handle;
DWORD client_instance;
DWORD client_callback;
DWORD unknown_18;
DWORD flags;
DWORD ioctl_param2;
DWORD ioctl_param1;
DWORD with_critical_section;
DWORD string_2c;
DWORD unknown_30;
DWORD playing_notes;
DWORD unknown_38;
DWORD unknown_3c;
DWORD unknown_40;
DWORD unknown_44;
DWORD unknown_48;
DWORD unknown_4C;
DWORD unknown_50;
DWORD beef;
PWDMAUD_DEVICE_STATE state;
char signature[4];
WCHAR path[1];
} WDMAUD_DEVICE_INFO, *PWDMAUD_DEVICE_INFO;
typedef struct
{
PWDMAUD_DEVICE_INFO offspring; /* not sure about this */
LPOVERLAPPED overlapped;
char signature[4];
} WDMAUD_WAVE_PREPARATION_DATA, *PWDMAUD_WAVE_PREPARATION_DATA;
/* Ugh... */
typedef struct
{
DWORD cbSize; /* Maybe? */
} WDMAUD_CAPS, *PWDMAUD_CAPS;
/*
Not quite sure what these are/do yet
*/
#define MAGIC_42 0x42424242 /* Queue critical section */
#define MAGIC_43 0x43434343 /* Queue critical section */
#define MAGIC_48 0x48484848 /* Exit-thread event */
#define IsQueueMagic(test_value) \
( ( (DWORD)test_value == MAGIC_42 ) || ( (DWORD)test_value == MAGIC_43) )
/*
This should eventually be removed, but is used so we can be nosey and see
what the kernel-mode wdmaud.sys is doing with our structures!
*/
#ifdef DUMP_WDMAUD_STRUCTURES
#define DUMP_MEMBER(struct, member) \
DPRINT("%s : %d [0x%x]\n", #member, (int) struct->member, (int) struct->member);
#define DUMP_WDMAUD_DEVICE_INFO(info) \
{ \
DPRINT("-- %s --\n", #info); \
DUMP_MEMBER(info, unknown_00); \
DUMP_MEMBER(info, id); \
DUMP_MEMBER(info, type); \
DUMP_MEMBER(info, wave_handle); \
DUMP_MEMBER(info, client_instance); \
DUMP_MEMBER(info, client_callback); \
DUMP_MEMBER(info, unknown_18); \
DUMP_MEMBER(info, flags); \
DUMP_MEMBER(info, ioctl_param2); \
DUMP_MEMBER(info, ioctl_param1); \
DUMP_MEMBER(info, with_critical_section); \
DUMP_MEMBER(info, string_2c); \
DUMP_MEMBER(info, unknown_30); \
DUMP_MEMBER(info, playing_notes); \
DUMP_MEMBER(info, unknown_38); \
DUMP_MEMBER(info, unknown_3c); \
DUMP_MEMBER(info, unknown_40); \
DUMP_MEMBER(info, unknown_44); \
DUMP_MEMBER(info, unknown_48); \
DUMP_MEMBER(info, unknown_4C); \
DUMP_MEMBER(info, unknown_50); \
DUMP_MEMBER(info, beef); \
DUMP_MEMBER(info, state); \
DUMP_MEMBER(info, signature); \
}
#else
#define DUMP_MEMBER(struct, member)
#define DUMP_WDMAUD_DEVICE_INFO(info)
#endif
/* Helper (helper.c) funcs */
MMRESULT TranslateWinError(DWORD error);
#define GetLastMmError() TranslateWinError(GetLastError());
/* user.c */
void NotifyClient(
PWDMAUD_DEVICE_INFO device,
DWORD message,
DWORD p1,
DWORD p2);
/* #define NotifyClient(device, message, p1, p2) ? */
/* kernel.c */
BOOL EnableKernelInterface();
BOOL DisableKernelInterface();
HANDLE GetKernelInterface();
MMRESULT CallKernelDevice(
PWDMAUD_DEVICE_INFO device,
DWORD ioctl_code,
DWORD param1,
DWORD param2);
/* devices.c */
BOOL IsValidDevicePath(WCHAR* path);
MMRESULT ValidateDeviceInfo(PWDMAUD_DEVICE_INFO info);
MMRESULT ValidateDeviceState(PWDMAUD_DEVICE_STATE state);
MMRESULT ValidateDeviceStateEvents(PWDMAUD_DEVICE_STATE state);
MMRESULT ValidateDeviceInfoAndState(PWDMAUD_DEVICE_INFO device_info);
PWDMAUD_DEVICE_INFO CreateDeviceData(CHAR device_type, WCHAR* device_path);
PWDMAUD_DEVICE_INFO CloneDeviceData(PWDMAUD_DEVICE_INFO original);
void DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data);
/* mixer ... */
MMRESULT ModifyDevicePresence(
CHAR device_type,
WCHAR* device_path,
BOOL adding);
#define AddDevice(device_type, device_path) \
ModifyDevicePresence(device_type, device_path, TRUE)
#define AddWaveInDevice(device_path) \
AddDevice(WDMAUD_WAVE_IN, device_path)
#define AddWaveOutDevice(device_path) \
AddDevice(WDMAUD_WAVE_OUT, device_path)
#define AddMidiInDevice(device_path) \
AddDevice(WDMAUD_MIDI_IN, device_path)
#define AddMidiOutDevice(device_path) \
AddDevice(WDMAUD_MIDI_OUT, device_path)
#define AddMixerDevice(device_path) \
AddDevice(WDMAUD_MIXER, device_path)
#define AddAuxDevice(device_path) \
AddDevice(WDMAUD_AUX, device_path)
#define RemoveDevice(device_type, device_path) \
ModifyDevicePresence(device_type, device_path, FALSE)
#define RemoveWaveInDevice(device_path) \
RemoveDevice(WDMAUD_WAVE_IN, device_path)
#define RemoveWaveOutDevice(device_path) \
RemoveDevice(WDMAUD_WAVE_OUT, device_path)
#define RemoveMidiInDevice(device_path) \
RemoveDevice(WDMAUD_MIDI_IN, device_path)
#define RemoveMidiOutDevice(device_path) \
RemoveDevice(WDMAUD_MIDI_OUT, device_path)
#define RemoveMixerDevice(device_path) \
RemoveDevice(WDMAUD_MIXER, device_path)
#define RemoveAuxDevice(device_path) \
RemoveDevice(WDMAUD_AUX, device_path)
DWORD GetDeviceCount(CHAR device_type, WCHAR* device_path);
#define GetWaveInCount(device_path) GetDeviceCount(WDMAUD_WAVE_IN, device_path)
#define GetWaveOutCount(device_path) GetDeviceCount(WDMAUD_WAVE_OUT, device_path)
#define GetMidiInCount(device_path) GetDeviceCount(WDMAUD_MIDI_IN, device_path)
#define GetMidiOutCount(device_path) GetDeviceCount(WDMAUD_MIDI_OUT, device_path)
#define GetMixerCount(device_path) GetDeviceCount(WDMAUD_MIXER, device_path)
#define GetAuxCount(device_path) GetDeviceCount(WDMAUD_AUX, device_path)
MMRESULT GetDeviceCapabilities(
CHAR device_type,
DWORD device_id,
WCHAR* device_path,
LPCOMMONCAPS caps);
#define GetWaveInCapabilities(id, device_path, caps) \
GetDeviceCapabilities(id, WDMAUD_WAVE_IN, device_path, caps);
#define GetWaveOutCapabilities(id, device_path, caps) \
GetDeviceCapabilities(id, WDMAUD_WAVE_OUT, device_path, caps);
#define GetMidiInCapabilities(id, device_path, caps) \
GetDeviceCapabilities(id, WDMAUD_MIDI_IN, device_path, caps);
#define GetMidiOutCapabilities(id, device_path, caps) \
GetDeviceCapabilities(id, WDMAUD_MIDI_OUT, device_path, caps);
#define GetMixerCapabilities(id, device_path, caps) \
GetDeviceCapabilities(id, WDMAUD_MIXER, device_path, caps);
#define GetAuxCapabilities(id, device_path, caps) \
GetDeviceCapabilities(id, WDMAUD_AUX, device_path, caps);
MMRESULT OpenWaveDevice(
CHAR device_type,
DWORD device_id,
LPWAVEOPENDESC open_details,
DWORD flags,
DWORD user_data);
#define OpenWaveOut(id, open_details, flags, user_data) \
OpenWaveDevice(WDMAUD_WAVE_OUT, id, open_details, flags, user_data);
MMRESULT CloseDevice(
PWDMAUD_DEVICE_INFO device
);
/* wavehdr.h */
#define SET_WAVEHDR_FLAG(header, flag) \
header->dwFlags |= flag
#define CLEAR_WAVEHDR_FLAG(header, flag) \
header->dwFlags &= ~flag
MMRESULT ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data);
MMRESULT ValidateWaveHeader(PWAVEHDR header);
MMRESULT PrepareWaveHeader(
PWDMAUD_DEVICE_INFO device,
PWAVEHDR header
);
MMRESULT UnprepareWaveHeader(PWAVEHDR header);
#define IsHeaderPrepared(header) \
( header->reserved != 0 )
MMRESULT CompleteWaveHeader(PWAVEHDR header);
MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header);
/* threads.c */
BOOL CreateCompletionThread(PWDMAUD_DEVICE_INFO device);
/* MORE... */
#endif

5
reactos/lib/wdmaud/wdmaud.rc Executable file
View file

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "WDM Audio System (Legacy Support)\0"
#define REACTOS_STR_INTERNAL_NAME "wdmaud\0"
#define REACTOS_STR_ORIGINAL_FILENAME "wdmaud.drv\0"
#include <reactos/version.rc>

20
reactos/lib/wdmaud/wdmaud.xml Executable file
View file

@ -0,0 +1,20 @@
<module name="wdmaud" type="win32dll" extension=".drv" baseaddress="${BASEADDRESS_WDMAUD}" installbase="system32" installname="wdmaud.drv">
<importlibrary definition="wdmaud.def" />
<include base="wdmaud">.</include>
<define name="__USE_W32API" />
<define name="_DISABLE_TIDENTS" />
<define name="UNICODE" />
<define name="_UNICODE" />
<define name="__REACTOS__" />
<library>ntdll</library>
<library>kernel32</library>
<library>winmm</library>
<library>setupapi</library>
<file>user.c</file>
<file>kernel.c</file>
<file>devices.c</file>
<file>wavehdr.c</file>
<file>threads.c</file>
<file>helper.c</file>
<file>wdmaud.rc</file>
</module>