mirror of
https://github.com/reactos/reactos.git
synced 2025-02-25 01:39:30 +00:00
Cleanup of existing code, basic implementation of play/stop/resume states.
svn path=/trunk/; revision=19954
This commit is contained in:
parent
2e8b6ad70c
commit
0638246fcd
11 changed files with 1367 additions and 673 deletions
97
reactos/lib/wdmaud/README.TXT
Executable file
97
reactos/lib/wdmaud/README.TXT
Executable file
|
@ -0,0 +1,97 @@
|
|||
User-mode Multimedia Driver for WDM Audio
|
||||
-----------------------------------------
|
||||
|
||||
USAGE
|
||||
-----
|
||||
This is a "drop-in" replacement for the Windows XP wdmaud.drv component. To
|
||||
make use of it, you'll need to disable system file protection somehow (easy
|
||||
way is to rename all *.cab files in the sub-folders of C:\WINDOWS\DRIVER CACHE
|
||||
to something else, then delete or rename WDMAUD.DRV in both C:\WINDOWS\SYSTEM32
|
||||
and C:\WINDOWS\SYSTEM32\DLLCACHE.)
|
||||
|
||||
Now put the ReactOS wdmaud.drv in C:\WINDOWS\SYSTEM32. At some point, you'll
|
||||
be asked to insert the Windows CD as some files are missing - cancel this and
|
||||
choose "yes" when asked if you're sure. This is due to the system file
|
||||
protection not being able to have its own way.
|
||||
|
||||
That should be all there is to it.
|
||||
|
||||
|
||||
IMPLEMENTATION/DEVELOPMENT NOTES
|
||||
--------------------------------
|
||||
The style of driver used here dates back to the days of Windows 3.1. Not much
|
||||
has changed - the NT 4 Sound Blaster driver exported the same functions and
|
||||
supported the same message codes as the traditional Windows 3.1 user-mode
|
||||
drivers did.
|
||||
|
||||
But in XP, something strange happens with WDMAUD (which is why you can't just
|
||||
put this next to the existing WDMAUD under a different name!)
|
||||
|
||||
It appears that WINMM.DLL treats WDMAUD.DRV differently to other drivers.
|
||||
|
||||
Here's a summary of how things work differently:
|
||||
|
||||
1) It seems DRV_ENABLE and DRV_DISABLE are the only important messages
|
||||
processed by DriverProc. These open and close the kernel-mode
|
||||
driver.
|
||||
|
||||
2) Each message handling function (aside from DriverProc) receives a
|
||||
DRVM_INIT message after the driver has been opened. The second
|
||||
parameter of this is a pointer to a string containing a device
|
||||
path (\\?\... format.) Returning zero seems to be the accepted
|
||||
thing to do, in any case.
|
||||
|
||||
The purpose of this function (in our case) is to allow WDMAUD.DRV
|
||||
to let WDMAUD.SYS know which device we want to play with.
|
||||
|
||||
Presumably, this is called when new devices are added to the system,
|
||||
as well. I don't know if this is called once per hardware device...
|
||||
|
||||
3) xxxx_GETNUMDEVS now has extra data passed to it! The first
|
||||
parameter is a device path string - which will have been passed
|
||||
to DRVM_INIT previously.
|
||||
|
||||
4) xxxx_GETDEVCAPS is a bit hazardous. The old set of parameters were:
|
||||
1 - Pointer to a capabilities structure (eg: WAVEOUTCAPS)
|
||||
2 - Size of the above structure
|
||||
|
||||
But now, the parameters are:
|
||||
1 - Pointer to a MDEVCAPSEX struct (which points to a regular
|
||||
capabilities structure)
|
||||
2 - Device path string
|
||||
|
||||
So anything expecting the second parameter to be a size (for copying
|
||||
memory maybe) is in for a bit of a surprise there!
|
||||
|
||||
The reason for the above changes is Plug and Play. It seems that the extra
|
||||
functionality was added in Windows 98 (possibly 95 as well) to make it
|
||||
possible to hot-swap winmm-supported devices without requiring a restart of
|
||||
whatever applications are using the devices.
|
||||
|
||||
That's the theory, at least.
|
||||
|
||||
|
||||
TODO
|
||||
----
|
||||
Our WINMM.DLL will need hacking to make sure it can take into account the
|
||||
preferential treatment given to WDMAUD.DRV
|
||||
|
||||
I'm not sure if it'll work with it yet as there seems to be some accomodation
|
||||
for the PnP DRVM_INIT and DRVM_EXIT messages, but whether or not winmm will
|
||||
function correctly with this WDMAUD.DRV replacement is something that remains
|
||||
to be seen.
|
||||
|
||||
|
||||
THANKS
|
||||
------
|
||||
Thanks to everyone who has encouraged me to continue developing the audio
|
||||
system for ReactOS.
|
||||
|
||||
In particular, I'd like to thank Alex Ionescu for the many hours of assistance
|
||||
he has given me in figuring out how things are done.
|
||||
|
||||
|
||||
-
|
||||
|
||||
Andrew Greenwood
|
||||
andrew.greenwood AT silverblade DOT co DOT uk
|
|
@ -13,8 +13,13 @@
|
|||
#include "wdmaud.h"
|
||||
|
||||
/*
|
||||
TODO:
|
||||
Make these work for the other device types!
|
||||
StartDevice
|
||||
|
||||
Creates a completion thread for a device, sets the "is_running" member
|
||||
of the device state to "true", and tells the kernel device to start
|
||||
processing audio/MIDI data.
|
||||
|
||||
Wave devices always start paused.
|
||||
*/
|
||||
|
||||
MMRESULT StartDevice(PWDMAUD_DEVICE_INFO device)
|
||||
|
@ -25,21 +30,165 @@ MMRESULT StartDevice(PWDMAUD_DEVICE_INFO device)
|
|||
result = ValidateDeviceInfoAndState(device);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
DPRINT1("Device info/state not valid\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
ioctl_code = device == WDMAUD_WAVE_IN ? IOCTL_WDMAUD_WAVE_IN_START :
|
||||
device == WDMAUD_WAVE_OUT ? IOCTL_WDMAUD_WAVE_OUT_START :
|
||||
ioctl_code =
|
||||
IsWaveInDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_IN_START :
|
||||
IsWaveOutDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_OUT_START :
|
||||
IsMidiInDeviceType(device->type) ? IOCTL_WDMAUD_MIDI_IN_START :
|
||||
0x0000;
|
||||
|
||||
ASSERT( ioctl_code );
|
||||
|
||||
result = CreateCompletionThread(device);
|
||||
|
||||
if ( MM_FAILURE( result ) )
|
||||
{
|
||||
DPRINT1("Failed to create completion thread\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
device->state->is_running = TRUE;
|
||||
|
||||
result = CallKernelDevice(device, ioctl_code, 0, 0);
|
||||
|
||||
if ( MM_FAILURE( result ) )
|
||||
{
|
||||
DPRINT1("Audio could not be started\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
if ( ! IsWaveDeviceType(device->type) )
|
||||
device->state->is_paused = FALSE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MMRESULT StopDevice(PWDMAUD_DEVICE_INFO device)
|
||||
{
|
||||
MMRESULT result;
|
||||
DWORD ioctl_code;
|
||||
|
||||
result = ValidateDeviceInfoAndState(device);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
DPRINT1("Device info/state not valid\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
ioctl_code =
|
||||
IsWaveInDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_IN_STOP :
|
||||
IsWaveOutDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_OUT_STOP :
|
||||
IsMidiInDeviceType(device->type) ? IOCTL_WDMAUD_MIDI_IN_STOP :
|
||||
0x0000;
|
||||
|
||||
ASSERT( ioctl_code );
|
||||
|
||||
if ( IsMidiInDeviceType(device->type) )
|
||||
{
|
||||
EnterCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
if ( ! device->state->is_running )
|
||||
{
|
||||
/* TODO: Free the MIDI data queue */
|
||||
}
|
||||
else
|
||||
{
|
||||
device->state->is_running = FALSE;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
}
|
||||
else /* wave device */
|
||||
{
|
||||
device->state->is_paused = TRUE;
|
||||
}
|
||||
|
||||
result = CallKernelDevice(device, ioctl_code, 0, 0);
|
||||
|
||||
if ( MM_FAILURE( result ) )
|
||||
{
|
||||
DPRINT1("Audio could not be stopped\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
if ( IsWaveDeviceType(device-type) )
|
||||
{
|
||||
device->state->is_paused = TRUE;
|
||||
}
|
||||
else /* MIDI Device */
|
||||
{
|
||||
/* TODO: Destroy completion thread etc. */
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MMRESULT PauseDevice(PWDMAUD_DEVICE_INFO device)
|
||||
MMRESULT ResetDevice(PWDMAUD_DEVICE_INFO device)
|
||||
{
|
||||
MMRESULT result;
|
||||
DWORD ioctl_code;
|
||||
|
||||
result = ValidateDeviceInfoAndState(device);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
DPRINT1("Device info/state not valid\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
ioctl_code =
|
||||
IsWaveInDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_IN_RESET :
|
||||
IsWaveOutDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_OUT_RESET :
|
||||
IsMidiInDeviceType(device->type) ? IOCTL_WDMAUD_MIDI_IN_RESET :
|
||||
0x0000;
|
||||
|
||||
ASSERT( ioctl_code );
|
||||
|
||||
if ( IsMidiInDeviceType(device->type) )
|
||||
{
|
||||
EnterCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
if ( ! device->state->is_running )
|
||||
{
|
||||
/* TODO: Free the MIDI data queue */
|
||||
}
|
||||
else
|
||||
{
|
||||
device->state->is_running = FALSE;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
}
|
||||
|
||||
result = CallKernelDevice(device, ioctl_code, 0, 0);
|
||||
|
||||
if ( MM_FAILURE( result ) )
|
||||
{
|
||||
DPRINT1("Audio could not be reset\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
if ( IsWaveDeviceType(device->type) )
|
||||
{
|
||||
if ( IsWaveInDeviceType(device->type) )
|
||||
device->state->is_paused = TRUE;
|
||||
else if ( IsWaveOutDeviceType(device->type) )
|
||||
device->state->is_paused = FALSE;
|
||||
|
||||
/* TODO: Destroy completion thread + check ret val */
|
||||
}
|
||||
else /* MIDI input device */
|
||||
{
|
||||
/* TODO: Destroy completion thread + check ret val */
|
||||
/* TODO - more stuff */
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MMRESULT StopDeviceLooping(PWDMAUD_DEVICE_INFO device)
|
||||
|
|
|
@ -17,9 +17,15 @@
|
|||
|
||||
const char WDMAUD_DEVICE_INFO_SIG[4] = "WADI";
|
||||
const char WDMAUD_DEVICE_STATE_SIG[4] = "WADS";
|
||||
const char WDMAUD_NULL_SIGNATURE[4] = {0,0,0,0};
|
||||
|
||||
|
||||
/*
|
||||
IsValidDevicePath
|
||||
|
||||
Just checks to see if the string containing the path to the device path
|
||||
(object) is a valid, readable string.
|
||||
*/
|
||||
|
||||
BOOL IsValidDevicePath(WCHAR* path)
|
||||
{
|
||||
if (IsBadReadPtr(path, 1)) /* TODO: Replace with flags */
|
||||
|
@ -33,43 +39,93 @@ BOOL IsValidDevicePath(WCHAR* path)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
MMRESULT ValidateDeviceInfo(PWDMAUD_DEVICE_INFO device_info)
|
||||
{
|
||||
if ( IsBadWritePtr(device_info, sizeof(WDMAUD_DEVICE_INFO)) )
|
||||
return MMSYSERR_INVALPARAM;
|
||||
/*
|
||||
ValidateDeviceData
|
||||
|
||||
if ( *device_info->signature != *WDMAUD_DEVICE_INFO_SIG )
|
||||
Checks that the memory pointed at by the device data pointer is writable,
|
||||
and that it has a valid signature.
|
||||
|
||||
If the "state" member isn't NULL, the state structure is also validated
|
||||
in the same way. If the "require_state" parameter is TRUE and the "state"
|
||||
member is NULL, an error code is returned. Otherwise the "state" member
|
||||
isn't validated and no error occurs.
|
||||
*/
|
||||
|
||||
MMRESULT ValidateDeviceData(
|
||||
PWDMAUD_DEVICE_INFO device,
|
||||
BOOL require_state
|
||||
)
|
||||
{
|
||||
if ( IsBadWritePtr(device, sizeof(WDMAUD_DEVICE_INFO)) )
|
||||
{
|
||||
DPRINT1("Device data structure not writable\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
if ( strncmp(device->signature, WDMAUD_DEVICE_INFO_SIG, 4) != 0 )
|
||||
{
|
||||
DPRINT1("Device signature is invalid\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
if ( ! IsValidDeviceType(device->type) )
|
||||
{
|
||||
DPRINT1("Invalid device type\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
if ( device->id > 100 )
|
||||
{
|
||||
DPRINT1("Device ID is out of range\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
/* Now we validate the device state (if present) */
|
||||
|
||||
if ( device->state )
|
||||
{
|
||||
if ( IsBadWritePtr(device->state, sizeof(WDMAUD_DEVICE_INFO)) )
|
||||
{
|
||||
DPRINT1("Device state structure not writable\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
if ( strncmp(device->state->signature,
|
||||
WDMAUD_DEVICE_STATE_SIG,
|
||||
4) != 0 )
|
||||
{
|
||||
DPRINT1("Device state signature is invalid\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
/* TODO: Validate state events */
|
||||
}
|
||||
else if ( require_state )
|
||||
{
|
||||
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.
|
||||
*/
|
||||
state validation routine (NOT on its own!)
|
||||
|
||||
FIXME: The tests are wrong
|
||||
*/
|
||||
/*
|
||||
MMRESULT ValidateDeviceStateEvents(PWDMAUD_DEVICE_STATE state)
|
||||
{
|
||||
if ( ( (DWORD) state->exit_thread_event == 0x00000000 ) &&
|
||||
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 ) &&
|
||||
if ( ( (DWORD) state->queue_event != 0x00000000 ) &&
|
||||
( (DWORD) state->queue_event != 0x42424242 ) &&
|
||||
( (DWORD) state->queue_event != 0x43434343 ) )
|
||||
{
|
||||
|
@ -79,28 +135,32 @@ MMRESULT ValidateDeviceStateEvents(PWDMAUD_DEVICE_STATE state)
|
|||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
*/
|
||||
|
||||
MMRESULT ValidateDeviceInfoAndState(PWDMAUD_DEVICE_INFO device_info)
|
||||
/*
|
||||
CreateDeviceData
|
||||
|
||||
This is a glorified memory allocation routine, which acts as a primitive
|
||||
constructor for a device data structure.
|
||||
|
||||
It validates the device path given, allocates memory for both the device
|
||||
data and the device state data, copies the signatures over and sets the
|
||||
device type accordingly.
|
||||
|
||||
In some cases, a state structure isn't required, so the creation of one can
|
||||
be avoided by passing FALSE for the "with_state" parameter.
|
||||
*/
|
||||
|
||||
PWDMAUD_DEVICE_INFO
|
||||
CreateDeviceData(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
WCHAR* device_path,
|
||||
BOOL with_state
|
||||
)
|
||||
{
|
||||
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;
|
||||
BOOL success = FALSE;
|
||||
PWDMAUD_DEVICE_INFO device = 0;
|
||||
int path_size = 0;
|
||||
|
||||
DPRINT("Creating device data for device type %d\n", (int) device_type);
|
||||
|
@ -115,121 +175,119 @@ PWDMAUD_DEVICE_INFO CreateDeviceData(CHAR device_type, WCHAR* device_path)
|
|||
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",
|
||||
DPRINT("Allocating %d bytes for device data\n",
|
||||
path_size + sizeof(WDMAUD_DEVICE_INFO));
|
||||
/*
|
||||
device_data = (PWDMAUD_DEVICE_INFO) HeapAlloc(heap,
|
||||
HEAP_ZERO_MEMORY,
|
||||
path_size + sizeof(WDMAUD_DEVICE_INFO));
|
||||
*/
|
||||
|
||||
device_data = (PWDMAUD_DEVICE_INFO)
|
||||
device = (PWDMAUD_DEVICE_INFO)
|
||||
AllocMem(path_size + sizeof(WDMAUD_DEVICE_INFO));
|
||||
|
||||
if ( ! device_data )
|
||||
if ( ! device )
|
||||
{
|
||||
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);
|
||||
/* Copy the signature and device path */
|
||||
memcpy(device->signature, WDMAUD_DEVICE_INFO_SIG, 4);
|
||||
lstrcpy(device->path, device_path);
|
||||
|
||||
DPRINT("Copying path (0x%x)\n", (int)device_path);
|
||||
lstrcpy(device_data->path, device_path);
|
||||
/* Initialize these common members */
|
||||
device->id = device_id;
|
||||
device->type = device_type;
|
||||
|
||||
device_data->type = device_type;
|
||||
if ( with_state )
|
||||
{
|
||||
/* Allocate device state structure */
|
||||
device->state = AllocMem(sizeof(WDMAUD_DEVICE_STATE));
|
||||
|
||||
if ( ! device->state )
|
||||
{
|
||||
DPRINT1("Couldn't allocate memory for device state (error %d)\n",
|
||||
(int) GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Copy the signature */
|
||||
memcpy(device->state->signature, WDMAUD_DEVICE_STATE_SIG, 4);
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
|
||||
cleanup :
|
||||
{
|
||||
/* No cleanup needed (no failures possible after allocation.) */
|
||||
DPRINT("Performing cleanup\n");
|
||||
if ( ! success )
|
||||
{
|
||||
if ( device )
|
||||
{
|
||||
if ( device->state )
|
||||
{
|
||||
ZeroMemory(device->state->signature, 4);
|
||||
FreeMem(device->state);
|
||||
}
|
||||
|
||||
return device_data;
|
||||
ZeroMemory(device->signature, 4);
|
||||
FreeMem(device);
|
||||
}
|
||||
}
|
||||
|
||||
return (success ? device : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
CloneDeviceData
|
||||
DeleteDeviceData
|
||||
|
||||
This isn't all that great... Maybe some macros would be better:
|
||||
BEGIN_CLONING_STRUCT(source, target)
|
||||
CLONE_MEMBER(member)
|
||||
END_CLONING_STRUCT()
|
||||
Blanks out the device and device state structures, and frees the memory
|
||||
associated with the structures.
|
||||
|
||||
The main problem is that sometimes we'll want to copy more than
|
||||
the data presented here. I guess we could blindly copy EVERYTHING
|
||||
but that'd be excessive.
|
||||
TODO: Free critical sections / events if set?
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
HANDLE heap;
|
||||
DPRINT("Deleting device data\n");
|
||||
|
||||
ASSERT( device_data );
|
||||
|
||||
/* Erase the signature to prevent any possible future mishaps */
|
||||
*device_data->signature = *WDMAUD_NULL_SIGNATURE;
|
||||
|
||||
heap = GetProcessHeap();
|
||||
|
||||
if ( ! heap )
|
||||
{
|
||||
DPRINT1("Couldn't get the process heap (error %d)\n",
|
||||
(int) GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
FreeMem(device_data);
|
||||
/*
|
||||
{
|
||||
DPRINT1("Couldn't free device data memory (error %d)\n",
|
||||
(int) GetLastError());
|
||||
}
|
||||
*/
|
||||
|
||||
exit :
|
||||
/* We just return */
|
||||
/* We don't really care if the structure is valid or not */
|
||||
if ( ! device_data )
|
||||
return;
|
||||
|
||||
if ( device_data->state )
|
||||
{
|
||||
/* We DON'T want these to be set - should we clean up? */
|
||||
ASSERT ( ! device_data->state->device_queue_guard );
|
||||
ASSERT ( ! device_data->state->queue_event );
|
||||
ASSERT ( ! device_data->state->exit_thread_event );
|
||||
|
||||
/* Insert a cow (not sure if this is right or not) */
|
||||
device_data->state->sample_size = 0xDEADBEEF;
|
||||
|
||||
/* Overwrite the structure with zeroes and free it */
|
||||
ZeroMemory(device_data->state, sizeof(WDMAUD_DEVICE_STATE));
|
||||
FreeMem(device_data->state);
|
||||
}
|
||||
|
||||
/* Overwrite the structure with zeroes and free it */
|
||||
ZeroMemory(device_data, sizeof(WDMAUD_DEVICE_INFO));
|
||||
FreeMem(device_data);
|
||||
}
|
||||
|
||||
/*
|
||||
ModifyDevicePresence
|
||||
|
||||
Use this to add or remove devices in the kernel-mode driver. If the
|
||||
"adding" parameter is TRUE, the device is added, otherwise it is removed.
|
||||
|
||||
"device_type" is WDMAUD_WAVE_IN, WDMAUD_WAVE_OUT, etc...
|
||||
|
||||
"device_path" specifies the NT object path of the device.
|
||||
|
||||
(I'm not sure what happens to devices that are added but never removed.)
|
||||
*/
|
||||
|
||||
MMRESULT ModifyDevicePresence(
|
||||
CHAR device_type,
|
||||
WCHAR* device_path,
|
||||
|
@ -249,7 +307,7 @@ MMRESULT ModifyDevicePresence(
|
|||
ASSERT( IsValidDeviceType(device_type) );
|
||||
ASSERT( device_path );
|
||||
|
||||
device_data = CreateDeviceData(device_type, device_path);
|
||||
device_data = CreateDeviceData(device_type, 0, device_path, FALSE);
|
||||
|
||||
if ( ! device_data )
|
||||
{
|
||||
|
@ -292,6 +350,16 @@ MMRESULT ModifyDevicePresence(
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
GetDeviceCount
|
||||
|
||||
Pretty straightforward - pass the device type (WDMAUD_WAVE_IN, ...) and
|
||||
a topology device (NT object path) to obtain the number of devices
|
||||
present in that topology of that particular type.
|
||||
|
||||
The topology path is supplied to us by winmm.
|
||||
*/
|
||||
|
||||
DWORD GetDeviceCount(CHAR device_type, WCHAR* topology_path)
|
||||
{
|
||||
PWDMAUD_DEVICE_INFO device_data;
|
||||
|
@ -299,7 +367,7 @@ DWORD GetDeviceCount(CHAR device_type, WCHAR* topology_path)
|
|||
|
||||
DPRINT("Topology path %S\n", topology_path);
|
||||
|
||||
device_data = CreateDeviceData(device_type, topology_path);
|
||||
device_data = CreateDeviceData(device_type, 0, topology_path, FALSE);
|
||||
|
||||
if (! device_data)
|
||||
{
|
||||
|
@ -339,7 +407,8 @@ DWORD GetDeviceCount(CHAR device_type, WCHAR* topology_path)
|
|||
This uses a different structure to the traditional documentation, because
|
||||
we handle plug and play devices.
|
||||
|
||||
Much sleep was lost over implementing this.
|
||||
Much sleep was lost over implementing this. I got the ID and type
|
||||
parameters the wrong way round!
|
||||
*/
|
||||
|
||||
MMRESULT GetDeviceCapabilities(
|
||||
|
@ -363,7 +432,7 @@ MMRESULT GetDeviceCapabilities(
|
|||
|
||||
DPRINT("Going to have to query the kernel-mode part\n");
|
||||
|
||||
device = CreateDeviceData(device_type, device_path);
|
||||
device = CreateDeviceData(device_type, device_id, device_path, FALSE);
|
||||
|
||||
if ( ! device )
|
||||
{
|
||||
|
@ -372,8 +441,9 @@ MMRESULT GetDeviceCapabilities(
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
device->id = device_id;
|
||||
device->with_critical_section = FALSE;
|
||||
/* These are not needed as they're already initialized */
|
||||
ASSERT( device_id == device->id );
|
||||
ASSERT( ! device->with_critical_section );
|
||||
|
||||
*(LPWORD)caps->pCaps = (WORD) 0x43;
|
||||
|
||||
|
@ -400,305 +470,224 @@ MMRESULT GetDeviceCapabilities(
|
|||
}
|
||||
}
|
||||
|
||||
MMRESULT TryOpenDevice(
|
||||
|
||||
/*
|
||||
OpenDeviceViaKernel
|
||||
|
||||
Internal function to rub the kernel mode part of wdmaud the right way
|
||||
so it opens a device on our behalf.
|
||||
*/
|
||||
|
||||
MMRESULT
|
||||
OpenDeviceViaKernel(
|
||||
PWDMAUD_DEVICE_INFO device,
|
||||
LPWAVEFORMATEX format
|
||||
)
|
||||
{
|
||||
if ( device->id > 0x64 ) /* FIXME */
|
||||
{
|
||||
DPRINT1("device->id > 0x64 ! ???\n");
|
||||
return MMSYSERR_BADDEVICEID; /* OK? */
|
||||
}
|
||||
DWORD format_struct_len = 0;
|
||||
|
||||
/* We'll only have a format set for wave devices */
|
||||
if ( format )
|
||||
{
|
||||
if ( format->wFormatTag == 1 )
|
||||
DPRINT("Opening device via kernel\n");
|
||||
|
||||
if ( format->wFormatTag == 1 ) /* FIXME */
|
||||
{
|
||||
/* Standard PCM format */
|
||||
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? */
|
||||
}
|
||||
format_struct_len = 16; /* FIXME */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME */
|
||||
DPRINT("Non-PCM format\n");
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
/* Non-standard format */
|
||||
return MMSYSERR_NOTSUPPORTED; /* TODO */
|
||||
}
|
||||
|
||||
/* If we got this far without error, the format is supported! */
|
||||
return MMSYSERR_NOERROR;
|
||||
return CallKernelDevice(device,
|
||||
IOCTL_WDMAUD_OPEN_DEVICE,
|
||||
format_struct_len,
|
||||
(DWORD)format);
|
||||
}
|
||||
|
||||
MMRESULT OpenWaveDevice(
|
||||
|
||||
/* MOVEME */
|
||||
LPCRITICAL_SECTION CreateCriticalSection()
|
||||
{
|
||||
LPCRITICAL_SECTION cs;
|
||||
|
||||
cs = AllocMem(sizeof(CRITICAL_SECTION));
|
||||
|
||||
if ( ! cs )
|
||||
return NULL;
|
||||
|
||||
InitializeCriticalSection(cs);
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
OpenDevice
|
||||
|
||||
A generic "open device" function, which makes use of the above function
|
||||
once parameters have been checked. This is capable of handling both
|
||||
MIDI and wave devices, which is an improvement over the previous
|
||||
implementation (which had a lot of duplicate functionality.)
|
||||
*/
|
||||
|
||||
MMRESULT
|
||||
OpenDevice(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
LPWAVEOPENDESC open_details,
|
||||
LPVOID open_descriptor,
|
||||
DWORD flags,
|
||||
DWORD user_data
|
||||
PWDMAUD_DEVICE_INFO* user_data
|
||||
)
|
||||
{
|
||||
HANDLE heap = 0;
|
||||
PWDMAUD_DEVICE_INFO device = NULL;
|
||||
WCHAR* device_path = NULL;
|
||||
MMRESULT result = MMSYSERR_ERROR;
|
||||
WCHAR* device_path;
|
||||
PWDMAUD_DEVICE_INFO device;
|
||||
LPWAVEFORMATEX format;
|
||||
|
||||
/* ASSERT(open_details); */
|
||||
/* As we support both types */
|
||||
LPWAVEOPENDESC wave_opendesc = (LPWAVEOPENDESC) open_descriptor;
|
||||
LPMIDIOPENDESC midi_opendesc = (LPMIDIOPENDESC) open_descriptor;
|
||||
|
||||
heap = GetProcessHeap();
|
||||
/* FIXME: Does this just apply to wave, or MIDI also? */
|
||||
if ( device_id > 100 )
|
||||
return MMSYSERR_BADDEVICEID;
|
||||
|
||||
if ( ! heap )
|
||||
{
|
||||
DPRINT1("Couldn't get the process heap (error %d)\n",
|
||||
(int) GetLastError());
|
||||
result = MMSYSERR_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Copy the appropriate dnDevNode value */
|
||||
if ( IsWaveDeviceType(device_type) )
|
||||
device_path = (WCHAR*) wave_opendesc->dnDevNode;
|
||||
else if ( IsMidiDeviceType(device_type) )
|
||||
device_path = (WCHAR*) midi_opendesc->dnDevNode;
|
||||
else
|
||||
return MMSYSERR_INVALPARAM;
|
||||
|
||||
DPRINT("OpenDevice called\n");
|
||||
|
||||
device_path = (WCHAR*) open_details->dnDevNode;
|
||||
device = CreateDeviceData(device_type, device_path);
|
||||
device = CreateDeviceData(device_type, device_id, device_path, TRUE);
|
||||
|
||||
if ( ! device )
|
||||
{
|
||||
DPRINT1("Couldn't create device data\n");
|
||||
DPRINT1("Couldn't allocate memory for 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 )
|
||||
if ( ( IsWaveDeviceType(device->type) ) &&
|
||||
( device->flags & WAVE_FORMAT_QUERY ) )
|
||||
{
|
||||
DPRINT("Do I support this format? Hmm...\n");
|
||||
|
||||
result = TryOpenDevice(device, open_details->lpFormat);
|
||||
result = OpenDeviceViaKernel(device, wave_opendesc->lpFormat);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
DPRINT("Format not supported\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
DPRINT("Yes, I do support this format!\n");
|
||||
DPRINT1("Format not supported (mmsys error %d)\n", (int) result);
|
||||
result = WAVERR_BADFORMAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Format supported\n");
|
||||
result = MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
DPRINT("You actually want me to open the device, huh?\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate memory for the "queue" critical section */
|
||||
device->state->device_queue_guard = CreateCriticalSection();
|
||||
|
||||
device->state->queue_critical_section =
|
||||
HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(CRITICAL_SECTION));
|
||||
|
||||
if ( ! device->state->queue_critical_section )
|
||||
if ( ! device->state->device_queue_guard )
|
||||
{
|
||||
DPRINT1("Couldn't allocate memory for queue critical section (error %d)\n",
|
||||
(int) GetLastError());
|
||||
DPRINT1("Couldn't create queue cs\n");
|
||||
result = MMSYSERR_NOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Initialize the critical section */
|
||||
InitializeCriticalSection(device->state->queue_critical_section);
|
||||
/* Set up the callbacks */
|
||||
device->client_instance = IsWaveDeviceType(device->type)
|
||||
? wave_opendesc->dwInstance
|
||||
: midi_opendesc->dwInstance;
|
||||
|
||||
/* We need these so we can contact the client later */
|
||||
device->client_instance = open_details->dwInstance;
|
||||
device->client_callback = open_details->dwCallback;
|
||||
device->client_callback = IsWaveDeviceType(device->type)
|
||||
? wave_opendesc->dwCallback
|
||||
: midi_opendesc->dwCallback;
|
||||
|
||||
/* Reset state */
|
||||
device->state->open_descriptor = NULL;
|
||||
device->state->unknown_24 = 0;
|
||||
/*
|
||||
The device state will be stopped and unpaused already, but in some
|
||||
cases this isn't the desired behaviour.
|
||||
*/
|
||||
|
||||
device->state->is_running = FALSE;
|
||||
device->state->is_paused =
|
||||
device->type == WDMAUD_WAVE_IN ? TRUE : FALSE;
|
||||
/* FIXME: What do our friends MIDI in and out need? */
|
||||
device->state->is_paused = IsWaveOutDeviceType(device->type) ? 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 )
|
||||
if ( IsMidiOutDeviceType(device->type) )
|
||||
{
|
||||
DPRINT1("Format not supported?\n");
|
||||
goto cleanup; /* no need to set result - already done */
|
||||
device->state->midi_buffer = AllocMem(2048);
|
||||
|
||||
if ( ! device->state->midi_buffer )
|
||||
{
|
||||
DPRINT1("Couldn't allocate MIDI buffer\n");
|
||||
result = MMSYSERR_NOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the critical section while updating the device list */
|
||||
EnterCriticalSection(device->state->queue_critical_section);
|
||||
/* ... */
|
||||
LeaveCriticalSection(device->state->queue_critical_section);
|
||||
/* Format is only for wave devices */
|
||||
format = IsWaveDeviceType(device->type) ? wave_opendesc->lpFormat : NULL;
|
||||
|
||||
/* The wave device handle is actually our structure. Neat, eh? */
|
||||
open_details->hWave = (HWAVE) device;
|
||||
result = OpenDeviceViaKernel(device, format);
|
||||
|
||||
/* We also need to set our "user data" for winmm */
|
||||
LPVOID* ud = (LPVOID*) user_data; /* FIXME */
|
||||
*ud = device;
|
||||
|
||||
if (device->client_callback)
|
||||
if ( MM_FAILURE(result) )
|
||||
{
|
||||
DWORD message;
|
||||
DPRINT1("FAILED to open device - mm error %d\n", (int) result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
message = (device->type == WDMAUD_WAVE_IN ? WIM_OPEN :
|
||||
WDMAUD_WAVE_OUT ? WOM_OPEN : -1);
|
||||
EnterCriticalSection(device->state->device_queue_guard);
|
||||
/* TODO */
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
DPRINT("About to call the client callback\n");
|
||||
if ( IsWaveDeviceType(device->type) )
|
||||
wave_opendesc->hWave = (HWAVE) device;
|
||||
else
|
||||
midi_opendesc->hMidi = (HMIDI) device;
|
||||
|
||||
/* Call the callback */
|
||||
/* Our "user data" is actually the device information */
|
||||
*user_data = device;
|
||||
|
||||
if ( device->client_callback )
|
||||
{
|
||||
DWORD message = IsWaveInDeviceType(device->type) ? WIM_OPEN :
|
||||
IsWaveOutDeviceType(device->type) ? WOM_OPEN :
|
||||
IsMidiInDeviceType(device->type) ? MIM_OPEN :
|
||||
MOM_OPEN;
|
||||
|
||||
DPRINT("Calling client with message %d\n", (int) message);
|
||||
NotifyClient(device, message, 0, 0);
|
||||
|
||||
DPRINT("...it is done!\n");
|
||||
}
|
||||
|
||||
result = MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
This cleanup may need checking for memory leakage. It's not very pretty
|
||||
to look at, either...
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,10 +66,9 @@ MMRESULT CallKernelDevice(
|
|||
( ! 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);
|
||||
EnterCriticalSection(device->state->device_queue_guard);
|
||||
}
|
||||
|
||||
DPRINT("Calling DeviceIoControl with IOCTL %x\n", (int) ioctl_code);
|
||||
|
@ -110,7 +109,7 @@ MMRESULT CallKernelDevice(
|
|||
{
|
||||
/* Leave the critical section */
|
||||
if ( using_critical_section )
|
||||
LeaveCriticalSection(device->state->queue_critical_section);
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
if ( overlap.hEvent )
|
||||
CloseHandle(overlap.hEvent);
|
||||
|
@ -128,7 +127,7 @@ static BOOL ChangeKernelDeviceState(BOOL enable)
|
|||
|
||||
ioctl_code = enable ? IOCTL_WDMAUD_HELLO : IOCTL_WDMAUD_GOODBYE;
|
||||
|
||||
device = CreateDeviceData(WDMAUD_AUX, L"");
|
||||
device = CreateDeviceData(WDMAUD_AUX, 0, L"", FALSE);
|
||||
|
||||
if ( ! device )
|
||||
{
|
||||
|
@ -136,9 +135,6 @@ static BOOL ChangeKernelDeviceState(BOOL enable)
|
|||
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");
|
||||
|
@ -318,33 +314,6 @@ BOOL EnableKernelInterface()
|
|||
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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,6 +58,11 @@ VOID FreeMem(LPVOID pointer)
|
|||
}
|
||||
|
||||
if ( ! HeapFree(heap, 0, pointer) )
|
||||
{
|
||||
DPRINT("Unable to free memory (error %d)\n", (int)GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
alloc_count --;
|
||||
|
||||
ReportMem();
|
||||
|
|
193
reactos/lib/wdmaud/midi.c
Normal file
193
reactos/lib/wdmaud/midi.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Multimedia
|
||||
* FILE: lib/wdmaud/midi.c
|
||||
* PURPOSE: WDM Audio Support - MIDI Device / Header Manipulation
|
||||
* PROGRAMMER: Andrew Greenwood
|
||||
* UPDATE HISTORY:
|
||||
* Nov 29, 2005: Created
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "wdmaud.h"
|
||||
|
||||
/*
|
||||
OpenMidiDevice
|
||||
|
||||
OBSOLETE CODE - REFERENCE ONLY
|
||||
*/
|
||||
|
||||
#if 0
|
||||
MMRESULT
|
||||
OpenMidiDevice(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
LPMIDIOPENDESC open_details,
|
||||
DWORD flags,
|
||||
DWORD user_data
|
||||
)
|
||||
{
|
||||
MMRESULT result = MMSYSERR_ERROR;
|
||||
WCHAR* device_path;
|
||||
PWDMAUD_DEVICE_INFO device;
|
||||
|
||||
ASSERT( open_details );
|
||||
|
||||
/* FIXME? Is this true for MIDI devs too then? */
|
||||
if ( device_id > 100 )
|
||||
return MMSYSERR_BADDEVICEID; /* Not sure about this */
|
||||
|
||||
/* TODO: Case statement for wave/midi selection? */
|
||||
device_path = (WCHAR*) open_details->dnDevNode;
|
||||
device = CreateDeviceData(device_type, device_id, device_path, TRUE);
|
||||
|
||||
if ( ! device )
|
||||
{
|
||||
DPRINT1("Couldn't create device data\n");
|
||||
result = MMSYSERR_NOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
device->type = device_type; /* not necessary */
|
||||
device->id = device_id;
|
||||
device->flags = flags;
|
||||
|
||||
/* Wave devices look for format query flag here... */
|
||||
/* ... Validate Flags ? */
|
||||
|
||||
device->state->device_queue_guard = AllocMem(sizeof(CRITICAL_SECTION));
|
||||
|
||||
if ( ! device->state->device_queue_guard )
|
||||
{
|
||||
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->device_queue_guard);
|
||||
|
||||
/* 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->current_midi_header = NULL;
|
||||
device->state->unknown_24 = 0;
|
||||
|
||||
device->state->is_running = FALSE;
|
||||
device->state->is_paused = FALSE;
|
||||
|
||||
/* MIDI ONLY */
|
||||
device->state->midi_buffer = 0;
|
||||
device->state->running_status = 0x00;
|
||||
|
||||
/* For wave devices, we call the kernel NOW (but we're not handling wave) */
|
||||
/* MIDI devices are a little more complicated... Code follows... */
|
||||
|
||||
/* MIDI OUT */
|
||||
if ( device->type == WDMAUD_MIDI_OUT )
|
||||
{
|
||||
device->state->midi_buffer = AllocMem(2048);
|
||||
|
||||
if ( ! device->state->midi_buffer )
|
||||
{
|
||||
DPRINT1("Couldn't allocate memory for MIDI output buffer\n");
|
||||
result = MMSYSERR_NOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fairly generic code */
|
||||
|
||||
result = OpenDeviceViaKernel(device, NULL);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
DPRINT1("Couldn't open device (mmsys error %d)\n", (int) result);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Enter the critical section while updating the device list */
|
||||
EnterCriticalSection(device->state->device_queue_guard);
|
||||
/* ... update MIDI list ... */
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
/* The MIDI device handle is actually our structure. Neat, eh? */
|
||||
open_details->hMidi = (HMIDI) device;
|
||||
|
||||
/* We also need to set our "user data" for winmm */
|
||||
LPVOID* ud = (LPVOID*) user_data; /* FIXME */
|
||||
*ud = device;
|
||||
|
||||
/* MIDI specific code follows */
|
||||
if ( device->type == WDMAUD_MIDI_IN )
|
||||
{
|
||||
/* TODO: Read MIDI data until none left? */
|
||||
}
|
||||
|
||||
if ( device->client_callback )
|
||||
{
|
||||
DWORD message;
|
||||
|
||||
message = (device->type == WDMAUD_MIDI_IN ? MIM_OPEN : MOM_OPEN);
|
||||
|
||||
DPRINT("About to call the client callback\n");
|
||||
|
||||
/* Call the callback */
|
||||
NotifyClient(device, message, 0, 0);
|
||||
|
||||
DPRINT("...it is done!\n");
|
||||
}
|
||||
|
||||
result = MMSYSERR_NOERROR;
|
||||
|
||||
cleanup :
|
||||
{
|
||||
/* TODO!!!! */
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MMRESULT
|
||||
CloseMidiDevice(PWDMAUD_DEVICE_INFO device)
|
||||
{
|
||||
DPRINT("CloseMidiDevice\n");
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
WriteMidiShort(
|
||||
PWDMAUD_DEVICE_INFO device,
|
||||
DWORD message
|
||||
)
|
||||
{
|
||||
DPRINT("WriteMidiShort\n");
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
WriteMidiBuffer(PWDMAUD_DEVICE_INFO device)
|
||||
{
|
||||
DPRINT("WriteMidiBuffer\n");
|
||||
/* TODO - fix params too! */
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
ResetMidiDevice(PWDMAUD_DEVICE_INFO device)
|
||||
{
|
||||
DPRINT("ResetMidiDevice\n");
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO:
|
||||
SetVolume
|
||||
GetVolume
|
||||
SetPreferred
|
||||
*/
|
||||
|
|
@ -21,11 +21,11 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data)
|
|||
|
||||
DPRINT("WaveCompletionThread started\n");
|
||||
|
||||
EnterCriticalSection(device->state->queue_critical_section);
|
||||
EnterCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
while ( ! quit_loop )
|
||||
{
|
||||
result = ValidateDeviceInfoAndState(device);
|
||||
result = ValidateDeviceData(device, TRUE);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
|
@ -33,7 +33,8 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data)
|
|||
break;
|
||||
}
|
||||
|
||||
result = ValidateDeviceStateEvents(device->state);
|
||||
/* TODO: REIMPLEMENT */
|
||||
/* result = ValidateDeviceStateEvents(device->state); */
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
|
@ -41,13 +42,13 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data)
|
|||
break;
|
||||
}
|
||||
|
||||
if ( device->state->open_descriptor )
|
||||
if ( device->state->current_wave_header )
|
||||
{
|
||||
DPRINT("No open descriptor found - running? %d\n", (int) device->state->is_running);
|
||||
DPRINT("No current header - running? %d\n", (int) device->state->is_running);
|
||||
|
||||
if ( ! device->state->is_running )
|
||||
{
|
||||
LeaveCriticalSection(device->state->queue_critical_section);
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
DPRINT("Waiting for queue_event\n");
|
||||
WaitForSingleObject(device->state->queue_event, INFINITE);
|
||||
|
@ -76,7 +77,7 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data)
|
|||
}
|
||||
else
|
||||
{
|
||||
PWAVEHDR wave_header = device->state->wave_header;
|
||||
PWAVEHDR wave_header = device->state->current_wave_header;
|
||||
|
||||
DPRINT("An open descriptor or wave header was found\n");
|
||||
|
||||
|
@ -98,7 +99,7 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data)
|
|||
DPRINT("Activating the next header\n");
|
||||
|
||||
/* Activate the next header */
|
||||
device->state->wave_header = wave_header->lpNext;
|
||||
device->state->current_wave_header = wave_header->lpNext;
|
||||
|
||||
/* Reset this just in case */
|
||||
prep_data = NULL;
|
||||
|
@ -117,7 +118,7 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data)
|
|||
}
|
||||
|
||||
/* We do this here in case there's an error - deadlock = bad! */
|
||||
LeaveCriticalSection(device->state->queue_critical_section);
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR)
|
||||
goto cleanup;
|
||||
|
@ -229,7 +230,7 @@ BOOL CreateCompletionThread(PWDMAUD_DEVICE_INFO device)
|
|||
DPRINT("Thread created! - %d\n", (int) device->state->thread);
|
||||
|
||||
/* TODO: Set priority */
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE; /* TODO / FIXME */
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "wdmaud.h"
|
||||
|
||||
|
||||
APIENTRY LONG DriverProc(
|
||||
APIENTRY LRESULT DriverProc(
|
||||
DWORD DriverID,
|
||||
HDRVR DriverHandle,
|
||||
UINT Message,
|
||||
|
@ -102,9 +102,11 @@ APIENTRY LONG DriverProc(
|
|||
|
||||
case DRV_INSTALL :
|
||||
DPRINT("DRV_INSTALL\n");
|
||||
return FALSE; /* ok? */
|
||||
return TRUE; /* ok? */
|
||||
|
||||
/* DRV_REMOVE */
|
||||
case DRV_REMOVE :
|
||||
DPRINT("DRV_REMOVE\n");
|
||||
return TRUE;
|
||||
|
||||
default :
|
||||
DPRINT("?\n");
|
||||
|
@ -123,7 +125,7 @@ void NotifyClient(
|
|||
|
||||
DriverCallback(device->client_callback,
|
||||
HIWORD(device->flags),
|
||||
(HDRVR) device->wave_handle,
|
||||
(HDRVR) device->handle,
|
||||
message,
|
||||
device->client_instance,
|
||||
0,
|
||||
|
@ -199,8 +201,8 @@ APIENTRY DWORD wodMessage(
|
|||
|
||||
/*
|
||||
* WODM_GETDEVCAPS
|
||||
* Parameter 1 : Pointer to a WAVEOUTCAPS struct
|
||||
* Parameter 2 : "Wave" device path? FIXME (NEW!)
|
||||
* Parameter 1 : Pointer to a MDEVICECAPS struct
|
||||
* Parameter 2 : Device path
|
||||
*/
|
||||
case WODM_GETDEVCAPS :
|
||||
DPRINT("WODM_GETDEVCAPS\n");
|
||||
|
@ -214,11 +216,14 @@ APIENTRY DWORD wodMessage(
|
|||
*/
|
||||
case WODM_OPEN :
|
||||
DPRINT("WODM_OPEN\n");
|
||||
return OpenWaveOut(id, (LPWAVEOPENDESC) p1, p2, user);
|
||||
return OpenWaveOutDevice(id,
|
||||
(LPWAVEOPENDESC) p1,
|
||||
p2,
|
||||
(PWDMAUD_DEVICE_INFO*) user);
|
||||
|
||||
case WODM_CLOSE :
|
||||
DPRINT("WODM_CLOSE\n");
|
||||
return CloseDevice((PWDMAUD_DEVICE_INFO) user); /* ugh! */
|
||||
return CloseWaveDevice((PWDMAUD_DEVICE_INFO) user);
|
||||
|
||||
case WODM_PREPARE :
|
||||
DPRINT("WODM_PREPARE\n");
|
||||
|
@ -299,6 +304,45 @@ APIENTRY DWORD modMessage(
|
|||
case MODM_GETDEVCAPS :
|
||||
DPRINT("MODM_GETDEVCAPS\n");
|
||||
return GetMidiOutCapabilities(id, (WCHAR*) p2, (LPMDEVICECAPSEX) p1);
|
||||
|
||||
case MODM_OPEN :
|
||||
DPRINT("MODM_OPEN\n");
|
||||
return OpenMidiOutDevice(id,
|
||||
(LPMIDIOPENDESC) p1,
|
||||
p2,
|
||||
(PWDMAUD_DEVICE_INFO*) user);
|
||||
|
||||
case MODM_CLOSE :
|
||||
DPRINT("MODM_CLOSE\n");
|
||||
return CloseMidiDevice((PWDMAUD_DEVICE_INFO) user);
|
||||
|
||||
case MODM_DATA :
|
||||
DPRINT("MODM_DATA\n");
|
||||
return WriteMidiShort((PWDMAUD_DEVICE_INFO) user, p1);
|
||||
|
||||
case MODM_LONGDATA :
|
||||
DPRINT("MODM_LONGDATA\n");
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
case MODM_RESET :
|
||||
DPRINT("MODM_RESET\n");
|
||||
return ResetMidiDevice((PWDMAUD_DEVICE_INFO) user);
|
||||
|
||||
case MODM_SETVOLUME :
|
||||
DPRINT("MODM_SETVOLUME\n");
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
case MODM_GETVOLUME :
|
||||
DPRINT("MODM_GETVOLUME\n");
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
/* TODO: WINE's mmddk.h needs MODM_PREFERRED to be defined (value is ??) */
|
||||
/*
|
||||
case MODM_PREFERRED :
|
||||
DPRINT("MODM_PREFERRED\n");
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
DPRINT("* NOT IMPLEMENTED *\n");
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Multimedia
|
||||
* FILE: lib/wdmaud/wavehdr.c
|
||||
* PURPOSE: WDM Audio Support - Wave Header Manipulation
|
||||
* FILE: lib/wdmaud/wave.c
|
||||
* PURPOSE: WDM Audio Support - Wave Device / Header Manipulation
|
||||
* PROGRAMMER: Andrew Greenwood
|
||||
* UPDATE HISTORY:
|
||||
* Nov 18, 2005: Created
|
||||
|
@ -14,6 +14,194 @@
|
|||
|
||||
const char WAVE_PREPARE_DATA_SIG[4] = "WPPD";
|
||||
|
||||
/*
|
||||
OBSOLETE CODE - FOR REFERENCE ONLY
|
||||
*/
|
||||
#if 0
|
||||
MMRESULT OpenWaveDevice(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
LPWAVEOPENDESC open_details,
|
||||
DWORD flags,
|
||||
DWORD user_data
|
||||
)
|
||||
{
|
||||
MMRESULT result = MMSYSERR_ERROR;
|
||||
WCHAR* device_path;
|
||||
PWDMAUD_DEVICE_INFO device;
|
||||
|
||||
ASSERT( open_details );
|
||||
ASSERT( open_details->lpFormat );
|
||||
|
||||
if ( device_id > 100 )
|
||||
return MMSYSERR_BADDEVICEID; /* Not sure about this */
|
||||
|
||||
device_path = (WCHAR*) open_details->dnDevNode;
|
||||
device = CreateDeviceData(device_type, device_id, device_path, TRUE);
|
||||
|
||||
if ( ! device )
|
||||
{
|
||||
DPRINT1("Couldn't create device data\n");
|
||||
result = MMSYSERR_NOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
device->type = device_type;
|
||||
device->id = device_id;
|
||||
device->flags = flags;
|
||||
|
||||
/* We don't deal with this here */
|
||||
if ( flags & WAVE_FORMAT_QUERY )
|
||||
{
|
||||
result = QueryWaveFormatSupport(device, open_details);
|
||||
DeleteDeviceData( device );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
device->state->device_queue_guard = AllocMem(sizeof(CRITICAL_SECTION));
|
||||
|
||||
if ( ! device->state->device_queue_guard )
|
||||
{
|
||||
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->device_queue_guard);
|
||||
|
||||
/* 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->current_wave_header = NULL;
|
||||
device->state->unknown_24 = 0;
|
||||
|
||||
device->state->is_running = FALSE;
|
||||
device->state->is_paused =
|
||||
device->type == WDMAUD_WAVE_IN ? TRUE : FALSE;
|
||||
|
||||
DPRINT("Opening the device\n");
|
||||
|
||||
result = OpenDeviceViaKernel(device, open_details->lpFormat);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
DPRINT1("Couldn't open! mmsys error %d\n", (int) result);
|
||||
/* TODO: WAVERR_BADFORMAT translation ? */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Enter the critical section while updating the device list */
|
||||
EnterCriticalSection(device->state->device_queue_guard);
|
||||
/* ... */
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
/* 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 : WOM_OPEN);
|
||||
|
||||
DPRINT("About to call the client callback\n");
|
||||
|
||||
/* Call the callback */
|
||||
NotifyClient(device, message, 0, 0);
|
||||
|
||||
DPRINT("...it is done!\n");
|
||||
}
|
||||
|
||||
result = MMSYSERR_NOERROR;
|
||||
|
||||
cleanup :
|
||||
{
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
if ( device )
|
||||
DeleteDeviceData(device);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MMRESULT CloseWaveDevice(
|
||||
PWDMAUD_DEVICE_INFO device
|
||||
)
|
||||
{
|
||||
MMRESULT result = MMSYSERR_ERROR;
|
||||
|
||||
result = ValidateDeviceData(device, TRUE);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
DPRINT1("Device data invalid\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
if ( ! IsWaveDeviceType(device->type) )
|
||||
{
|
||||
DPRINT1("Invalid device type (expected a WAVE device)\n");
|
||||
return MMSYSERR_INVALPARAM;
|
||||
}
|
||||
|
||||
/* TODO: Perform actual close */
|
||||
if ( device->state->current_wave_header )
|
||||
{
|
||||
DPRINT1("Can't close! Device is still playing\n");
|
||||
return WAVERR_STILLPLAYING;
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
/* DestroyCompletionThread(device); - check result */
|
||||
|
||||
result = CallKernelDevice(device, IOCTL_WDMAUD_CLOSE_DEVICE, 0, 0);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
DPRINT1("Close failed! mmsyserr %d\n", (int) result);
|
||||
return result; /* TODO: convert? */
|
||||
}
|
||||
|
||||
if ( device->client_callback )
|
||||
{
|
||||
DWORD message;
|
||||
|
||||
message = (device->type == WDMAUD_WAVE_IN ? WIM_CLOSE : WOM_CLOSE);
|
||||
|
||||
DPRINT("About to call the client callback\n");
|
||||
|
||||
/* Call the callback */
|
||||
NotifyClient(device, message, 0, 0);
|
||||
|
||||
DPRINT("...it is done!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
TODO:
|
||||
Enter critical section
|
||||
Loop through device list until we reach the end or until we find a
|
||||
pointer matching "device".
|
||||
Leave critical section
|
||||
Delete critical section
|
||||
...
|
||||
*/
|
||||
|
||||
DeleteDeviceData(device);
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ValidateWaveHeaderPreparation Overview :
|
||||
|
||||
|
@ -28,22 +216,18 @@ const char WAVE_PREPARE_DATA_SIG[4] = "WPPD";
|
|||
|
||||
MMRESULT ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data)
|
||||
{
|
||||
/* UNIMPLEMENTED */
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
ValidateWaveHeader Overview :
|
||||
ValidateWaveHeader
|
||||
|
||||
Check that the pointer is valid to write to. If not, signal invalid
|
||||
parameter.
|
||||
Checks that the header memory can be written to, that the flags are
|
||||
valid (using the mask 0xFFFFFFE0), and that the wave preparation data
|
||||
is valid.
|
||||
|
||||
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!
|
||||
Returns MMSYSERR_NOERROR if all's well, or MMSYSERR_INVALPARAM if not.
|
||||
*/
|
||||
|
||||
MMRESULT ValidateWaveHeader(PWAVEHDR header)
|
||||
|
@ -70,31 +254,16 @@ MMRESULT ValidateWaveHeader(PWAVEHDR header)
|
|||
|
||||
|
||||
/*
|
||||
PrepareWaveHeader Overview :
|
||||
PrepareWaveHeader
|
||||
|
||||
Validate the parameters.
|
||||
Checks the parameters are sane, allocates memory for a WAVEPREPAREDATA
|
||||
structure and also memory for an OVERLAPPED structure.
|
||||
|
||||
Allocate and lock 12 bytes of global memory (fixed, zeroed) for the
|
||||
WAVEPREPAREDATA structure.
|
||||
After this, an un-named event is created (as hEvent of the OVERLAPPED)
|
||||
structure, and the WAVEPREPAREDATA structure has its signature set
|
||||
accordingly.
|
||||
|
||||
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.
|
||||
Returns MMSYSERR_NOTSUPPORTED so that winmm does further processing.
|
||||
*/
|
||||
|
||||
MMRESULT PrepareWaveHeader(
|
||||
|
@ -104,11 +273,11 @@ MMRESULT PrepareWaveHeader(
|
|||
{
|
||||
MMRESULT result = MMSYSERR_ERROR;
|
||||
PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL;
|
||||
HANDLE heap = NULL;
|
||||
|
||||
DPRINT("PrepareWaveHeader called\n");
|
||||
|
||||
result = ValidateDeviceInfoAndState(device);
|
||||
/* Check the device data is valid */
|
||||
result = ValidateDeviceData(device, TRUE);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
|
@ -117,42 +286,21 @@ MMRESULT PrepareWaveHeader(
|
|||
}
|
||||
|
||||
/* 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 );
|
||||
*/
|
||||
/* NOTE: At this point, what happens if not prepared or already queued? */
|
||||
|
||||
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");
|
||||
|
||||
/* Allocate memory for the wave preparation data */
|
||||
prep_data =
|
||||
(PWDMAUD_WAVE_PREPARATION_DATA)
|
||||
HeapAlloc(heap,
|
||||
HEAP_ZERO_MEMORY,
|
||||
sizeof(WDMAUD_WAVE_PREPARATION_DATA));
|
||||
AllocMem(sizeof(WDMAUD_WAVE_PREPARATION_DATA));
|
||||
|
||||
if ( ! prep_data )
|
||||
{
|
||||
|
@ -162,20 +310,18 @@ MMRESULT PrepareWaveHeader(
|
|||
goto fail;
|
||||
}
|
||||
|
||||
DPRINT("Allocating overlapped data\n");
|
||||
/* Create an event */
|
||||
|
||||
prep_data->overlapped = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(OVERLAPPED));
|
||||
prep_data->overlapped = AllocMem(sizeof(OVERLAPPED));
|
||||
|
||||
if ( ! prep_data->overlapped )
|
||||
{
|
||||
DPRINT1("Couldn't allocate heap memory for overlapped structure (error %d)\n",
|
||||
DPRINT1("Couldn't allocate 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 )
|
||||
|
@ -187,16 +333,14 @@ MMRESULT PrepareWaveHeader(
|
|||
}
|
||||
|
||||
/* Copy the signature over and tie the prepare structure to the wave header */
|
||||
DPRINT("Copying signature\n");
|
||||
*prep_data->signature = *WAVE_PREPARE_DATA_SIG;
|
||||
memcpy(prep_data->signature, WAVE_PREPARE_DATA_SIG, 4);
|
||||
header->reserved = (DWORD) prep_data;
|
||||
|
||||
/* We return this so WINMM can do further processing */
|
||||
result = MMSYSERR_NOTSUPPORTED;
|
||||
return result;
|
||||
|
||||
fail :
|
||||
{
|
||||
if ( heap )
|
||||
{
|
||||
if ( prep_data )
|
||||
{
|
||||
|
@ -205,11 +349,10 @@ MMRESULT PrepareWaveHeader(
|
|||
if ( prep_data->overlapped->hEvent )
|
||||
CloseHandle(prep_data->overlapped->hEvent); /* ok? */
|
||||
|
||||
HeapFree(heap, 0, prep_data->overlapped);
|
||||
FreeMem(prep_data->overlapped);
|
||||
}
|
||||
|
||||
HeapFree(heap, 0, prep_data);
|
||||
}
|
||||
FreeMem(prep_data);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -219,13 +362,15 @@ MMRESULT PrepareWaveHeader(
|
|||
/*
|
||||
UnprepareWaveHeader
|
||||
|
||||
Cleans up after a header has been used, by killing the event we set up
|
||||
above, and freeing the preparation data.
|
||||
|
||||
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;
|
||||
|
||||
|
@ -248,59 +393,22 @@ MMRESULT UnprepareWaveHeader(PWAVEHDR header)
|
|||
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;
|
||||
|
||||
/* Kill the event */
|
||||
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);
|
||||
}
|
||||
FreeMem(prep_data->overlapped);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
FreeMem(prep_data);
|
||||
|
||||
/* Always return like this so winmm thinks we didn't do anything */
|
||||
|
||||
DPRINT("Header now unprepared.\n");
|
||||
result = MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
cleanup :
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -368,6 +476,13 @@ MMRESULT CompleteWaveHeader(PWAVEHDR header)
|
|||
device info structure.
|
||||
*/
|
||||
|
||||
/*
|
||||
ValidateWriteWaveDataParams
|
||||
|
||||
This is just a helper function that shrinks WriteWaveData a little
|
||||
bit.
|
||||
*/
|
||||
|
||||
static MMRESULT ValidateWriteWaveDataParams(
|
||||
PWDMAUD_DEVICE_INFO device,
|
||||
PWAVEHDR header
|
||||
|
@ -401,7 +516,7 @@ static MMRESULT ValidateWriteWaveDataParams(
|
|||
return WAVERR_UNPREPARED;
|
||||
}
|
||||
|
||||
result = ValidateDeviceInfoAndState(device);
|
||||
result = ValidateDeviceData(device, TRUE);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
{
|
||||
|
@ -412,27 +527,41 @@ static MMRESULT ValidateWriteWaveDataParams(
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
WriteWaveData
|
||||
|
||||
This is the exciting (?!) bit where playback actually begins. Various
|
||||
validation takes place, before the header is queued for playback. Playback
|
||||
can then begin. This entails telling the kernel-mode device about the
|
||||
header, then telling the device to start playback.
|
||||
|
||||
It all seems pretty straightforward, but it's not all that easy...
|
||||
*/
|
||||
|
||||
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;
|
||||
/* PWDMAUD_DEVICE_INFO clone; */
|
||||
|
||||
/* For the DeviceIoControl later */
|
||||
DWORD ioctl_code;
|
||||
DWORD bytes_returned;
|
||||
|
||||
DPRINT("SubmitWaveHeader called\n");
|
||||
DPRINT("WriteWaveHeader called\n");
|
||||
|
||||
result = ValidateWriteWaveDataParams(device, header);
|
||||
|
||||
if ( result != MMSYSERR_NOERROR )
|
||||
return result;
|
||||
|
||||
/*
|
||||
TODO: Check to see if we actually get called with bad flags!
|
||||
*/
|
||||
/* Check to see if we actually get called with bad flags! */
|
||||
if ( ! IS_WAVEHDR_FLAG_SET(header, WHDR_PREPARED) )
|
||||
{
|
||||
DPRINT1("Not prepared!\n");
|
||||
return WAVERR_UNPREPARED;
|
||||
}
|
||||
|
||||
/* Retrieve our precious data from the reserved member */
|
||||
prep_data = (PWDMAUD_WAVE_PREPARATION_DATA) header->reserved;
|
||||
|
@ -456,17 +585,17 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header)
|
|||
|
||||
DPRINT("Flags == 0x%x\n", (int) header->dwFlags);
|
||||
|
||||
EnterCriticalSection(device->state->queue_critical_section);
|
||||
EnterCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
if ( ! device->state->wave_header )
|
||||
if ( ! device->state->current_wave_header )
|
||||
{
|
||||
DPRINT("Device state wave_header is NULL\n");
|
||||
|
||||
device->state->wave_header = header;
|
||||
device->state->current_wave_header = header;
|
||||
|
||||
/* My, what pretty symmetry you have... */
|
||||
|
||||
DPRINT("Queue event == %d\n", (int) device->state->queue_event);
|
||||
DPRINT("Queue event == 0x%x\n", (int) device->state->queue_event);
|
||||
|
||||
if ( ( (DWORD) device->state->queue_event != 0 ) &&
|
||||
( (DWORD) device->state->queue_event != MAGIC_42 ) &&
|
||||
|
@ -483,40 +612,30 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header)
|
|||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(device->state->queue_critical_section);
|
||||
LeaveCriticalSection(device->state->device_queue_guard);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/* Now we send the header to the kernel device */
|
||||
|
||||
if ( ! IsHeaderPrepared(header) )
|
||||
{
|
||||
DPRINT1("Unprepared header!\n");
|
||||
DeleteDeviceData(clone);
|
||||
return MMSYSERR_INVALPARAM;
|
||||
result = MMSYSERR_INVALPARAM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Not sure what this is for */
|
||||
prep_data->offspring = clone;
|
||||
/*
|
||||
Not sure what this is for. I *think* it's used for tracking which
|
||||
device a preparation belongs to.
|
||||
*/
|
||||
prep_data->offspring = device;
|
||||
|
||||
/* The modern version of WODM_WRITE, I guess ;) */
|
||||
clone->ioctl_param1 = sizeof(WAVEHDR);
|
||||
clone->ioctl_param2 = (DWORD) header;
|
||||
device->ioctl_param1 = sizeof(WAVEHDR);
|
||||
device->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);
|
||||
ioctl_code = device->type == WDMAUD_WAVE_IN
|
||||
? IOCTL_WDMAUD_SUBMIT_WAVE_IN_HDR /* FIXME */
|
||||
: IOCTL_WDMAUD_SUBMIT_WAVE_OUT_HDR;
|
||||
|
||||
/*
|
||||
FIXME:
|
||||
|
@ -528,9 +647,9 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header)
|
|||
io_result =
|
||||
DeviceIoControl(GetKernelInterface(),
|
||||
ioctl_code,
|
||||
clone,
|
||||
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(clone->path) * 2),
|
||||
clone,
|
||||
device,
|
||||
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2),
|
||||
device,
|
||||
sizeof(WDMAUD_DEVICE_INFO),
|
||||
&bytes_returned, /* ... */
|
||||
prep_data->overlapped);
|
||||
|
@ -542,28 +661,27 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header)
|
|||
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;
|
||||
device->state->device_queue_guard = NULL;
|
||||
device->state->current_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;
|
||||
device->state->device_queue_guard = NULL;
|
||||
device->state->current_wave_header = NULL;
|
||||
|
||||
return MMSYSERR_ERROR; /* Care to be more specific? */
|
||||
}
|
||||
|
||||
|
||||
/* TODO */
|
||||
/* ***** FIXME ****** THIS IS NASTY HACKERY ****** */
|
||||
|
||||
DPRINT("applying hacks\n");
|
||||
|
||||
|
@ -572,7 +690,7 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header)
|
|||
/* HACK */
|
||||
DPRINT("%d\n", (int)
|
||||
DeviceIoControl(GetKernelInterface(),
|
||||
0x1d8104,
|
||||
IOCTL_WDMAUD_WAVE_OUT_START,
|
||||
device,
|
||||
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2),
|
||||
device,
|
||||
|
@ -597,5 +715,9 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header)
|
|||
|
||||
result = MMSYSERR_NOERROR;
|
||||
|
||||
cleanup :
|
||||
{
|
||||
/* TODO */
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -39,6 +39,11 @@
|
|||
#define REPORT_MM_RESULT(message, success) \
|
||||
DPRINT("%s %s\n", message, success == MMSYSERR_NOERROR ? "succeeded" : "failed")
|
||||
|
||||
#define MM_SUCCESS(value) \
|
||||
( value == MMSYSERR_NOERROR )
|
||||
|
||||
#define MM_FAILURE(value) \
|
||||
( value != MMSYSERR_NOERROR )
|
||||
|
||||
|
||||
#define GOBAL_CALLBACKS_PATH L"Global\\WDMAUD_Callbacks"
|
||||
|
@ -80,19 +85,21 @@
|
|||
|
||||
#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_WAVE_OUT_STOP 0x1d8100
|
||||
#define IOCTL_WDMAUD_WAVE_OUT_START 0x1d8104
|
||||
#define IOCTL_WDMAUD_WAVE_OUT_RESET 0x1d8108
|
||||
#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_VOLUME 0x1d8114 /* Already been covered? */
|
||||
#define IOCTL_WDMAUD_UNKNOWN1 0x1d8118 /* Not used by wdmaud.drv */
|
||||
#define IOCTL_WDMAUD_SUBMIT_WAVE_OUT_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_WAVE_IN_STOP 0x1d8140
|
||||
#define IOCTL_WDMAUD_WAVE_IN_START 0x1d8144
|
||||
#define IOCTL_WDMAUD_WAVE_IN_RESET 0x1d8148
|
||||
|
||||
#define IOCTL_WDMAUD_SUBMIT_WAVE_IN_HDR 0x1d8150 /* FIXME: Unsure about this */
|
||||
|
||||
#define IOCTL_WDMAUD_MIDI_OUT_SHORT_MESSAGE \
|
||||
0x1d8204 /* Wrong description? */
|
||||
|
@ -104,9 +111,9 @@
|
|||
|
||||
#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_MIDI_IN_STOP 0x1d8240
|
||||
#define IOCTL_WDMAUD_MIDI_IN_START 0x1d8244
|
||||
#define IOCTL_WDMAUD_MIDI_IN_RESET 0x1d8248
|
||||
|
||||
#define IOCTL_WDMAUD_READ_MIDI_DATA 0x1d824c
|
||||
#define IOCTL_WDMAUD_MIDI_MESSAGE 0x1d8300 /* Wrong description? */
|
||||
|
@ -180,6 +187,8 @@ 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.
|
||||
|
||||
TODO: Maybe have a generic OPEN routine that uses this?
|
||||
*/
|
||||
typedef struct OPENDESC *LPOPENDESC;
|
||||
|
||||
|
@ -188,41 +197,56 @@ typedef struct
|
|||
DWORD sample_size;
|
||||
HANDLE thread;
|
||||
DWORD thread_id;
|
||||
|
||||
union
|
||||
{
|
||||
LPWAVEOPENDESC open_descriptor;
|
||||
LPWAVEHDR wave_header;
|
||||
LPWAVEHDR current_wave_header;
|
||||
LPMIDIHDR current_midi_header;
|
||||
};
|
||||
|
||||
DWORD unknown_10; /* pointer to something */
|
||||
DWORD unknown_14;
|
||||
LPCRITICAL_SECTION queue_critical_section;
|
||||
|
||||
LPCRITICAL_SECTION device_queue_guard;
|
||||
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;
|
||||
LPVOID midi_buffer; /* for output ? */
|
||||
DWORD running_status;
|
||||
|
||||
char signature[4];
|
||||
} WDMAUD_DEVICE_STATE, *PWDMAUD_DEVICE_STATE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD unknown_00;
|
||||
DWORD next_device;
|
||||
|
||||
DWORD id;
|
||||
DWORD type;
|
||||
HWAVE wave_handle;
|
||||
|
||||
HWAVE 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;
|
||||
|
@ -230,6 +254,7 @@ typedef struct
|
|||
DWORD unknown_48;
|
||||
DWORD unknown_4C;
|
||||
DWORD unknown_50;
|
||||
|
||||
DWORD beef;
|
||||
PWDMAUD_DEVICE_STATE state;
|
||||
char signature[4];
|
||||
|
@ -317,37 +342,63 @@ MMRESULT TranslateWinError(DWORD error);
|
|||
|
||||
|
||||
/* user.c */
|
||||
void NotifyClient(
|
||||
|
||||
void
|
||||
NotifyClient(
|
||||
PWDMAUD_DEVICE_INFO device,
|
||||
DWORD message,
|
||||
DWORD p1,
|
||||
DWORD p2);
|
||||
|
||||
/* #define NotifyClient(device, message, p1, p2) ? */
|
||||
DWORD p2
|
||||
);
|
||||
|
||||
|
||||
/* kernel.c */
|
||||
|
||||
BOOL EnableKernelInterface();
|
||||
BOOL DisableKernelInterface();
|
||||
HANDLE GetKernelInterface();
|
||||
BOOL
|
||||
EnableKernelInterface();
|
||||
|
||||
MMRESULT CallKernelDevice(
|
||||
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);
|
||||
|
||||
BOOL
|
||||
IsValidDevicePath(WCHAR* path);
|
||||
|
||||
MMRESULT
|
||||
ValidateDeviceData(
|
||||
PWDMAUD_DEVICE_INFO device_data,
|
||||
BOOL require_state
|
||||
);
|
||||
/*
|
||||
MMRESULT ValidateDeviceState(PWDMAUD_DEVICE_STATE state);
|
||||
MMRESULT ValidateDeviceStateEvents(PWDMAUD_DEVICE_STATE state);
|
||||
MMRESULT ValidateDeviceInfoAndState(PWDMAUD_DEVICE_INFO device_info);
|
||||
*/
|
||||
|
||||
/* TODO: Add ID parameter */
|
||||
|
||||
PWDMAUD_DEVICE_INFO
|
||||
CreateDeviceData(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
WCHAR* device_path,
|
||||
BOOL with_state
|
||||
);
|
||||
|
||||
void
|
||||
DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data);
|
||||
|
||||
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(
|
||||
|
@ -388,7 +439,9 @@ MMRESULT ModifyDevicePresence(
|
|||
RemoveDevice(WDMAUD_AUX, device_path)
|
||||
|
||||
|
||||
DWORD GetDeviceCount(CHAR device_type, WCHAR* 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)
|
||||
|
@ -396,11 +449,13 @@ DWORD GetDeviceCount(CHAR device_type, WCHAR* device_path);
|
|||
#define GetMixerCount(device_path) GetDeviceCount(WDMAUD_MIXER, device_path)
|
||||
#define GetAuxCount(device_path) GetDeviceCount(WDMAUD_AUX, device_path)
|
||||
|
||||
MMRESULT GetDeviceCapabilities(
|
||||
MMRESULT
|
||||
GetDeviceCapabilities(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
WCHAR* device_path,
|
||||
LPMDEVICECAPSEX caps);
|
||||
LPMDEVICECAPSEX caps
|
||||
);
|
||||
|
||||
#define GetWaveInCapabilities(id, device_path, caps) \
|
||||
GetDeviceCapabilities(WDMAUD_WAVE_IN, id, device_path, caps);
|
||||
|
@ -415,46 +470,115 @@ MMRESULT GetDeviceCapabilities(
|
|||
#define GetAuxCapabilities(id, device_path, caps) \
|
||||
GetDeviceCapabilities(WDMAUD_AUX, id, device_path, caps);
|
||||
|
||||
MMRESULT OpenWaveDevice(
|
||||
MMRESULT
|
||||
OpenDeviceViaKernel(
|
||||
PWDMAUD_DEVICE_INFO device,
|
||||
LPWAVEFORMATEX format
|
||||
);
|
||||
|
||||
MMRESULT
|
||||
OpenDevice(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
LPVOID open_descriptor,
|
||||
DWORD flags,
|
||||
PWDMAUD_DEVICE_INFO* user_data
|
||||
);
|
||||
|
||||
|
||||
/* wave.c */
|
||||
#if 0
|
||||
MMRESULT
|
||||
OpenWaveDevice(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
LPWAVEOPENDESC open_details,
|
||||
DWORD flags,
|
||||
DWORD user_data);
|
||||
DWORD user_data
|
||||
);
|
||||
#endif
|
||||
|
||||
#define OpenWaveOut(id, open_details, flags, user_data) \
|
||||
OpenWaveDevice(WDMAUD_WAVE_OUT, id, open_details, flags, user_data);
|
||||
#define OpenWaveInDevice(id, open_details, flags, user_data) \
|
||||
OpenDevice(WDMAUD_WAVE_IN, id, open_details, flags, user_data);
|
||||
#define OpenWaveOutDevice(id, open_details, flags, user_data) \
|
||||
OpenDevice(WDMAUD_WAVE_OUT, id, open_details, flags, user_data);
|
||||
#define OpenMidiInDevice(id, open_details, flags, user_data) \
|
||||
OpenDevice(WDMAUD_MIDI_IN, id, open_details, flags, user_data);
|
||||
#define OpenMidiOutDevice(id, open_details, flags, user_data) \
|
||||
OpenDevice(WDMAUD_MIDI_OUT, id, open_details, flags, user_data);
|
||||
|
||||
MMRESULT CloseDevice(
|
||||
|
||||
MMRESULT
|
||||
CloseWaveDevice(
|
||||
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);
|
||||
#define IS_WAVEHDR_FLAG_SET(header, flag) \
|
||||
( header->dwFlags & flag )
|
||||
|
||||
MMRESULT ValidateWaveHeader(PWAVEHDR header);
|
||||
MMRESULT
|
||||
ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data);
|
||||
|
||||
MMRESULT PrepareWaveHeader(
|
||||
MMRESULT
|
||||
ValidateWaveHeader(PWAVEHDR header);
|
||||
|
||||
MMRESULT
|
||||
PrepareWaveHeader(
|
||||
PWDMAUD_DEVICE_INFO device,
|
||||
PWAVEHDR header
|
||||
);
|
||||
|
||||
MMRESULT UnprepareWaveHeader(PWAVEHDR header);
|
||||
MMRESULT
|
||||
UnprepareWaveHeader(PWAVEHDR header);
|
||||
|
||||
#define IsHeaderPrepared(header) \
|
||||
( header->reserved != 0 )
|
||||
|
||||
MMRESULT CompleteWaveHeader(PWAVEHDR header);
|
||||
MMRESULT
|
||||
CompleteWaveHeader(PWAVEHDR header);
|
||||
|
||||
MMRESULT
|
||||
WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header);
|
||||
|
||||
|
||||
/* midi.c */
|
||||
|
||||
#if 0
|
||||
MMRESULT
|
||||
OpenMidiDevice(
|
||||
CHAR device_type,
|
||||
DWORD device_id,
|
||||
LPMIDIOPENDESC open_details,
|
||||
DWORD flags,
|
||||
DWORD user_data
|
||||
);
|
||||
#endif
|
||||
|
||||
MMRESULT
|
||||
CloseMidiDevice(
|
||||
PWDMAUD_DEVICE_INFO device
|
||||
);
|
||||
|
||||
MMRESULT
|
||||
WriteMidiShort(
|
||||
PWDMAUD_DEVICE_INFO device,
|
||||
DWORD message
|
||||
);
|
||||
|
||||
/* FIXME: Bad params */
|
||||
MMRESULT
|
||||
WriteMidiBuffer(PWDMAUD_DEVICE_INFO device);
|
||||
|
||||
MMRESULT
|
||||
ResetMidiDevice(PWDMAUD_DEVICE_INFO device);
|
||||
|
||||
|
||||
MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header);
|
||||
|
||||
|
||||
/* threads.c */
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
<file>user.c</file>
|
||||
<file>kernel.c</file>
|
||||
<file>devices.c</file>
|
||||
<file>wavehdr.c</file>
|
||||
<file>midi.c</file>
|
||||
<file>wave.c</file>
|
||||
<file>threads.c</file>
|
||||
<file>helper.c</file>
|
||||
<file>memtrack.c</file>
|
||||
|
|
Loading…
Reference in a new issue