Cleanup of existing code, basic implementation of play/stop/resume
states.
Added: trunk/reactos/lib/wdmaud/README.TXT
Modified: trunk/reactos/lib/wdmaud/control.c
Modified: trunk/reactos/lib/wdmaud/devices.c
Modified: trunk/reactos/lib/wdmaud/kernel.c
Modified: trunk/reactos/lib/wdmaud/memtrack.c
Added: trunk/reactos/lib/wdmaud/midi.c
Modified: trunk/reactos/lib/wdmaud/threads.c
Modified: trunk/reactos/lib/wdmaud/user.c
Added: trunk/reactos/lib/wdmaud/wave.c
Deleted: trunk/reactos/lib/wdmaud/wavehdr.c
Modified: trunk/reactos/lib/wdmaud/wdmaud.h
Modified: trunk/reactos/lib/wdmaud/wdmaud.xml
_____
Added: trunk/reactos/lib/wdmaud/README.TXT
--- trunk/reactos/lib/wdmaud/README.TXT 2005-12-07 18:33:12 UTC (rev
19953)
+++ trunk/reactos/lib/wdmaud/README.TXT 2005-12-07 18:37:49 UTC (rev
19954)
@@ -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
Property changes on: trunk/reactos/lib/wdmaud/README.TXT
___________________________________________________________________
Name: svn:executable
+ *
Name: eol-style
+ native
Property changes on: trunk/reactos/lib/wdmaud/TODO
___________________________________________________________________
Name: eol-style
+ native
Property changes on: trunk/reactos/lib/wdmaud/callbacks.c
___________________________________________________________________
Name: eol-style
+ native
_____
Modified: trunk/reactos/lib/wdmaud/control.c
--- trunk/reactos/lib/wdmaud/control.c 2005-12-07 18:33:12 UTC (rev
19953)
+++ trunk/reactos/lib/wdmaud/control.c 2005-12-07 18:37:49 UTC (rev
19954)
@@ -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 @@
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 :
- 0x0000;
+ 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)
Property changes on: trunk/reactos/lib/wdmaud/control.c
___________________________________________________________________
Name: eol-style
+ native
_____
Modified: trunk/reactos/lib/wdmaud/devices.c
--- trunk/reactos/lib/wdmaud/devices.c 2005-12-07 18:33:12 UTC (rev
19953)
+++ trunk/reactos/lib/wdmaud/devices.c 2005-12-07 18:37:49 UTC (rev
19954)
@@ -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 @@
return TRUE;
}
-MMRESULT ValidateDeviceInfo(PWDMAUD_DEVICE_INFO device_info)
+/*
+ ValidateDeviceData
+
+ 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_info, sizeof(WDMAUD_DEVICE_INFO)) )
+ if ( IsBadWritePtr(device, sizeof(WDMAUD_DEVICE_INFO)) )
+ {
+ DPRINT1("Device data structure not writable\n");
return MMSYSERR_INVALPARAM;
+ }
- if ( *device_info->signature != *WDMAUD_DEVICE_INFO_SIG )
+ if ( strncmp(device->signature, WDMAUD_DEVICE_INFO_SIG, 4) != 0 )
+ {
+ DPRINT1("Device signature is invalid\n");
return MMSYSERR_INVALPARAM;
+ }
- return MMSYSERR_NOERROR;
-}
+ if ( ! IsValidDeviceType(device->type) )
+ {
+ DPRINT1("Invalid device type\n");
+ return MMSYSERR_INVALPARAM;
+ }
-MMRESULT ValidateDeviceState(PWDMAUD_DEVICE_STATE state)
-{
- if ( IsBadWritePtr(state, sizeof(WDMAUD_DEVICE_INFO)) )
+ if ( device->id > 100 )
+ {
+ DPRINT1("Device ID is out of range\n");
return MMSYSERR_INVALPARAM;
+ }
- if ( *state->signature != *WDMAUD_DEVICE_STATE_SIG )
+ /* 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;
}
+
/*
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 @@
return MMSYSERR_NOERROR;
}
+*/
-MMRESULT ValidateDeviceInfoAndState(PWDMAUD_DEVICE_INFO device_info)
-{
- MMRESULT result;
+/*
+ CreateDeviceData
- result = ValidateDeviceInfo(device_info);
+ This is a glorified memory allocation routine, which acts as a
primitive
+ constructor for a device data structure.
- if ( result != MMSYSERR_NOERROR )
- return result;
+ 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.
- result = ValidateDeviceState(device_info->state);
+ 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.
+*/
- if ( result != MMSYSERR_NOERROR )
- return result;
-
- return MMSYSERR_NOERROR;
-}
-
-PWDMAUD_DEVICE_INFO CreateDeviceData(CHAR device_type, WCHAR*
device_path)
+PWDMAUD_DEVICE_INFO
+CreateDeviceData(
+ CHAR device_type,
+ DWORD device_id,
+ WCHAR* device_path,
+ BOOL with_state
+)
{
- 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 @@
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)
+void DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data)
{
- PWDMAUD_DEVICE_INFO clone = NULL;
+ DPRINT("Deleting device data\n");
- if ( ValidateDeviceInfo(original) != MMSYSERR_NOERROR)
- {
- DPRINT1("Original device data was invalid\n");
- return NULL;
- }
+ ASSERT( device_data );
- /* This will set the type and path, so we can forget about those */
- clone = CreateDeviceData(original->type, original->path);
+ /* We don't really care if the structure is valid or not */
+ if ( ! device_data )
+ return;
- if ( ! clone )
+ if ( device_data->state )
{
- DPRINT1("Clone creation failed\n");
- return NULL;
- }
+ /* 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 );
- clone->id = original->id;
- clone->wave_handle = original->wave_handle; /* ok? */
+ /* Insert a cow (not sure if this is right or not) */
+ device_data->state->sample_size = 0xDEADBEEF;
- /* TODO: Maybe we should copy some more? */
+ /* Overwrite the structure with zeroes and free it */
+ ZeroMemory(device_data->state, sizeof(WDMAUD_DEVICE_STATE));
+ FreeMem(device_data->state);
+ }
- return clone;
+ /* Overwrite the structure with zeroes and free it */
+ ZeroMemory(device_data, sizeof(WDMAUD_DEVICE_INFO));
+ FreeMem(device_data);
}
-void DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data)
-{
- HANDLE heap;
+/*
+ ModifyDevicePresence
- ASSERT( device_data );
+ 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.
- /* Erase the signature to prevent any possible future mishaps */
- *device_data->signature = *WDMAUD_NULL_SIGNATURE;
+ "device_type" is WDMAUD_WAVE_IN, WDMAUD_WAVE_OUT, etc...
- heap = GetProcessHeap();
+ "device_path" specifies the NT object path of the device.
- if ( ! heap )
- {
- DPRINT1("Couldn't get the process heap (error %d)\n",
- (int) GetLastError());
- goto exit;
- }
+ (I'm not sure what happens to devices that are added but never
removed.)
+*/
- FreeMem(device_data);
- /*
- {
- DPRINT1("Couldn't free device data memory (error %d)\n",
- (int) GetLastError());
- }
- */
-
- exit :
- /* We just return */
- return;
-}
-
MMRESULT ModifyDevicePresence(
CHAR device_type,
WCHAR* device_path,
@@ -249,7 +307,7 @@
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 @@
}
}
+/*
+ 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 @@
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 @@
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 @@
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 @@
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 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 )
+ DPRINT("Opening device via kernel\n");
+
+ if ( format->wFormatTag == 1 ) /* FIXME */
{
- if ( format->wFormatTag == 1 )
- {
- DWORD sample_size;
+ /* Standard PCM format */
+ DWORD sample_size;
- DPRINT("Standard (PCM) format\n");
- sample_size = format->nChannels * format->wBitsPerSample;
- device->state->sample_size = sample_size;
+ DPRINT("Standard (PCM) format\n");
- 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;
- }
+ sample_size = format->nChannels * format->wBitsPerSample;
+
+ device->state->sample_size = sample_size;
+
+ format_struct_len = 16; /* FIXME */
}
+ else
+ {
+ /* 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 = CreateDeviceData(device_type, device_id, device_path,
TRUE);
- device_path = (WCHAR*) open_details->dnDevNode;
- device = CreateDeviceData(device_type, device_path);
-
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 = OpenDeviceViaKernel(device, wave_opendesc->lpFormat);
- result = TryOpenDevice(device, open_details->lpFormat);
-
if ( result != MMSYSERR_NOERROR )
{
- DPRINT("Format not supported\n");
- goto cleanup;
+ DPRINT1("Format not supported (mmsys error %d)\n", (int)
result);
+ result = WAVERR_BADFORMAT;
}
-
- 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 )
+ else
{
- DPRINT1("Couldn't allocate memory for queue critical
section (error %d)\n",
- (int) GetLastError());
- result = MMSYSERR_NOMEM;
- goto cleanup;
+ DPRINT("Format supported\n");
+ result = MMSYSERR_NOERROR;
}
- /* Initialize the critical section */
-
InitializeCriticalSection(device->state->queue_critical_section);
+ goto cleanup;
+ }
- /* We need these so we can contact the client later */
- device->client_instance = open_details->dwInstance;
- device->client_callback = open_details->dwCallback;
+ device->state->device_queue_guard = CreateCriticalSection();
- /* Reset state */
- device->state->open_descriptor = NULL;
- device->state->unknown_24 = 0;
+ if ( ! device->state->device_queue_guard )
+ {
+ DPRINT1("Couldn't create queue cs\n");
+ result = MMSYSERR_NOMEM;
+ goto cleanup;
+ }
- device->state->is_running = FALSE;
- device->state->is_paused =
- device->type == WDMAUD_WAVE_IN ? TRUE : FALSE;
+ /* Set up the callbacks */
+ device->client_instance = IsWaveDeviceType(device->type)
+ ? wave_opendesc->dwInstance
+ : midi_opendesc->dwInstance;
[truncated at 1000 lines; 2515 more skipped]