Removing WDMAUD until I figure out how it can be implemented properly

(this will not have any adverse effects as it doesn't actually work 
yet.) Also replacing MMDRV with a rewritten version as it appears to
contain big chunks copied directly from NT4 DDK examples!


svn path=/trunk/; revision=27384
This commit is contained in:
Andrew Greenwood
2007-07-04 10:17:48 +00:00
parent a941582fa2
commit 4d91599bd6
28 changed files with 1706 additions and 4929 deletions
+4
View File
@@ -0,0 +1,4 @@
Jan 2007 TODO list
* Set WHDR_COMPLETE when WriteFileEx APC is called
* Check for WHDR_COMPLETE flag when completing buffers outside APC
+258
View File
@@ -0,0 +1,258 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: dll/win32/mmdrv/common.c
* PURPOSE: Multimedia User Mode Driver (Common functions)
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Jan 14, 2007: Created
*/
#include <mmdrv.h>
/*
Translates errors to MMRESULT codes.
*/
MMRESULT
ErrorToMmResult(UINT error_code)
{
switch ( error_code )
{
case NO_ERROR :
case ERROR_IO_PENDING :
return MMSYSERR_NOERROR;
case ERROR_BUSY :
return MMSYSERR_ALLOCATED;
case ERROR_NOT_SUPPORTED :
case ERROR_INVALID_FUNCTION :
return MMSYSERR_NOTSUPPORTED;
case ERROR_NOT_ENOUGH_MEMORY :
return MMSYSERR_NOMEM;
case ERROR_ACCESS_DENIED :
return MMSYSERR_BADDEVICEID;
case ERROR_INSUFFICIENT_BUFFER :
return MMSYSERR_INVALPARAM;
};
/* If all else fails, it's just a plain old error */
return MMSYSERR_ERROR;
}
/*
Obtains a device count for a specific kind of device.
*/
DWORD
GetDeviceCount(DeviceType device_type)
{
UINT index = 0;
HANDLE handle;
/* Cycle through devices until an error occurs */
while ( OpenKernelDevice(device_type, index, GENERIC_READ, &handle) == MMSYSERR_NOERROR )
{
CloseHandle(handle);
index ++;
}
DPRINT("Found %d devices of type %d\n", index, device_type);
return index;
}
/*
Obtains device capabilities. This could either be done as individual
functions for wave, MIDI and aux, or like this. I chose this method as
it centralizes everything.
*/
DWORD
GetDeviceCapabilities(
DeviceType device_type,
DWORD device_id,
PVOID capabilities,
DWORD capabilities_size)
{
MMRESULT result;
DWORD ioctl;
HANDLE handle;
DWORD bytes_returned;
BOOL device_io_result;
ASSERT(capabilities);
/* Choose the right IOCTL for the job */
if ( IsWaveDevice(device_type) )
ioctl = IOCTL_WAVE_GET_CAPABILITIES;
else if ( IsMidiDevice(device_type) )
ioctl = IOCTL_MIDI_GET_CAPABILITIES;
else if ( IsAuxDevice(device_type) )
return MMSYSERR_NOTSUPPORTED; /* TODO */
else
return MMSYSERR_NOTSUPPORTED;
result = OpenKernelDevice(device_type,
device_id,
GENERIC_READ,
&handle);
if ( result != MMSYSERR_NOERROR )
{
DPRINT("Failed to open kernel device\n");
return result;
}
device_io_result = DeviceIoControl(handle,
ioctl,
NULL,
0,
(LPVOID) capabilities,
capabilities_size,
&bytes_returned,
NULL);
/* Translate result */
if ( device_io_result )
result = MMSYSERR_NOERROR;
else
result = ErrorToMmResult(GetLastError());
/* Clean up and return */
CloseKernelDevice(handle);
return result;
}
/*
A wrapper around OpenKernelDevice that creates a session,
opens the kernel device, initializes session data and notifies
the client (application) that the device has been opened. Again,
this supports any device type and the only real difference is
the open descriptor.
*/
DWORD
OpenDevice(
DeviceType device_type,
DWORD device_id,
PVOID open_descriptor,
DWORD flags,
DWORD private_handle)
{
SessionInfo* session_info;
MMRESULT result;
DWORD message;
/* This will automatically check for duplicate sessions */
result = CreateSession(device_type, device_id, &session_info);
if ( result != MMSYSERR_NOERROR )
{
DPRINT("Couldn't allocate session info\n");
return result;
}
result = OpenKernelDevice(device_type,
device_id,
GENERIC_READ,
&session_info->kernel_device_handle);
if ( result != MMSYSERR_NOERROR )
{
DPRINT("Failed to open kernel device\n");
DestroySession(session_info);
return result;
}
/* Set common session data */
session_info->flags = flags;
/* Set wave/MIDI specific data */
if ( IsWaveDevice(device_type) )
{
LPWAVEOPENDESC wave_open_desc = (LPWAVEOPENDESC) open_descriptor;
session_info->callback = wave_open_desc->dwCallback;
session_info->mme_wave_handle = wave_open_desc->hWave;
session_info->app_user_data = wave_open_desc->dwInstance;
}
else
{
DPRINT("Only wave devices are supported at present!\n");
DestroySession(session_info);
return MMSYSERR_NOTSUPPORTED;
}
/* Start the processing thread */
result = StartSessionThread(session_info);
if ( result != MMSYSERR_NOERROR )
{
DestroySession(session_info);
return result;
}
/* Store the session info */
*((SessionInfo**)private_handle) = session_info;
/* Send the right message */
message = (device_type == WaveOutDevice) ? WOM_OPEN :
(device_type == WaveInDevice) ? WIM_OPEN :
(device_type == MidiOutDevice) ? MOM_OPEN :
(device_type == MidiInDevice) ? MIM_OPEN : 0xFFFFFFFF;
NotifyClient(session_info, message, 0, 0);
return MMSYSERR_NOERROR;
}
/*
Attempts to close a device. This can fail if playback/recording has
not been stopped. We need to make sure it's safe to destroy the
session as well (mainly by killing the session thread.)
*/
DWORD
CloseDevice(
DWORD private_handle)
{
MMRESULT result;
SessionInfo* session_info = (SessionInfo*) private_handle;
/* TODO: Maybe this is best off inside the playback thread? */
ASSERT(session_info);
result = CallSessionThread(session_info, WODM_CLOSE, 0);
if ( result == MMSYSERR_NOERROR )
{
/* TODO: Wait for it to be safe to terminate */
CloseKernelDevice(session_info->kernel_device_handle);
DestroySession(session_info);
}
return result;
}
+31 -85
View File
@@ -2,68 +2,42 @@
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/mmdrv/entry.c
* PURPOSE: Multimedia User Mode Driver
* FILE: dll/win32/mmdrv/entry.c
* PURPOSE: Multimedia User Mode Driver (DriverProc)
* PROGRAMMER: Andrew Greenwood
* Aleksey Bragin
* UPDATE HISTORY:
* Jan 30, 2004: Imported into ReactOS tree (Greenwood)
* Mar 16, 2004: Cleaned up a bit (Bragin)
* Jan 14, 2007: Created
*/
#include <mmdrv.h>
#include "mmdrv.h"
#define NDEBUG
#include <debug.h>
/*
Nothing particularly special happens here.
#define EXPORT __declspec(dllexport)
Back in the days of Windows 3.1, we would do something more useful here,
as this is effectively the old-style equivalent of NT's "DriverEntry",
though far more primitive.
CRITICAL_SECTION DriverSection;
In summary, we just implement to satisfy the MME API (winmm) requirements.
*/
APIENTRY LONG DriverProc(DWORD DriverID, HANDLE DriverHandle, UINT Message,
LONG Param1, LONG Param2)
LONG
DriverProc(
DWORD driver_id,
HANDLE driver_handle,
UINT message,
LONG parameter1,
LONG parameter2)
{
DPRINT("DriverProc\n");
// HINSTANCE Module;
switch(Message)
switch ( message )
{
case DRV_LOAD :
DPRINT("DRV_LOAD\n");
return TRUE; // dont need to do any more
/*
Module = GetDriverModuleHandle(DriverHandle);
// Create our process heap
Heap = GetProcessHeap();
if (Heap == NULL)
return FALSE;
DisableThreadLibraryCalls(Module);
InitializeCriticalSection(&CS);
//
// Load our device list
//
// if (sndFindDevices() != MMSYSERR_NOERROR) {
// DeleteCriticalSection(&mmDrvCritSec);
// return FALSE;
// }
return TRUE;
*/
// return 1L;
return 1L;
case DRV_FREE :
DPRINT("DRV_FREE\n");
// TerminateMidi();
// TerminateWave();
// DeleteCriticalSection(&CS);
return 1L;
case DRV_OPEN :
@@ -82,6 +56,11 @@ APIENTRY LONG DriverProc(DWORD DriverID, HANDLE DriverHandle, UINT Message,
DPRINT("DRV_DISABLE\n");
return 1L;
/*
We don't provide configuration capabilities. This used to be
for things like I/O port, IRQ, DMA settings, etc.
*/
case DRV_QUERYCONFIGURE :
DPRINT("DRV_QUERYCONFIGURE\n");
return 0L;
@@ -93,44 +72,11 @@ APIENTRY LONG DriverProc(DWORD DriverID, HANDLE DriverHandle, UINT Message,
case DRV_INSTALL :
DPRINT("DRV_INSTALL\n");
return DRVCNF_RESTART;
default :
DPRINT("?\n");
return DefDriverProc(DriverID, DriverHandle, Message, Param1, Param2);
};
return DefDriverProc(driver_id,
driver_handle,
message,
parameter1,
parameter2);
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved)
{
DPRINT("DllMain called!\n");
if (Reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hInstance);
// Create our heap
Heap = HeapCreate(0, 800, 0);
if (Heap == NULL)
return FALSE;
InitializeCriticalSection(&CS);
// OK to do this now??
FindDevices();
}
else if (Reason == DLL_PROCESS_DETACH)
{
// We need to do cleanup here...
// TerminateMidi();
// TerminateWave();
DeleteCriticalSection(&CS);
HeapDestroy(Heap);
}
return TRUE;
}
/* EOF */
+206
View File
@@ -0,0 +1,206 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: dll/win32/mmdrv/kernel.c
* PURPOSE: Multimedia User Mode Driver (kernel interface)
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Jan 14, 2007: Created
*/
#include <mmdrv.h>
/*
Devices that we provide access to follow a standard naming convention.
The first wave output, for example, appears as \Device\WaveOut0
I'm not entirely certain how drivers find a free name to use, or why
we need to strip the leading \Device from it when opening, but hey...
*/
MMRESULT
CobbleDeviceName(
DeviceType device_type,
DWORD device_id,
PWCHAR out_device_name)
{
WCHAR base_device_name[MAX_DEVICE_NAME_LENGTH];
/* Work out the base name from the device type */
switch ( device_type )
{
case WaveOutDevice :
wsprintf(base_device_name, L"%ls", WAVE_OUT_DEVICE_NAME);
break;
case WaveInDevice :
wsprintf(base_device_name, L"%ls", WAVE_IN_DEVICE_NAME);
break;
case MidiOutDevice :
wsprintf(base_device_name, L"%ls", MIDI_OUT_DEVICE_NAME);
break;
case MidiInDevice :
wsprintf(base_device_name, L"%ls", MIDI_IN_DEVICE_NAME);
break;
case AuxDevice :
wsprintf(base_device_name, L"%ls", AUX_DEVICE_NAME);
break;
default :
return MMSYSERR_BADDEVICEID;
};
/* Now append the device number, removing the leading \Device */
wsprintf(out_device_name,
L"\\\\.%ls%d",
base_device_name + strlen("\\Device"),
device_id);
return MMSYSERR_NOERROR;
}
/*
Takes a device type (eg: WaveOutDevice), a device ID, desired access and
a pointer to a location that will store the handle of the opened "file" if
the function succeeds.
The device type and ID are converted into a device name using the above
function.
*/
MMRESULT
OpenKernelDevice(
DeviceType device_type,
DWORD device_id,
DWORD access,
HANDLE* handle)
{
MMRESULT result;
WCHAR device_name[MAX_DEVICE_NAME_LENGTH];
DWORD open_flags = 0;
ASSERT(handle);
/* Glue the base device name and the ID together */
result = CobbleDeviceName(device_type, device_id, device_name);
DPRINT("Opening kernel device %ls\n", device_name);
if ( result != MMSYSERR_NOERROR )
return result;
/* We want overlapped I/O when writing */
if ( access != GENERIC_READ )
open_flags = FILE_FLAG_OVERLAPPED;
/* Now try opening... */
*handle = CreateFile(device_name,
access,
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
open_flags,
NULL);
if ( *handle == INVALID_HANDLE_VALUE )
return ErrorToMmResult(GetLastError());
return MMSYSERR_NOERROR;
}
/*
Just an alias for the benefit of having a pair of functions ;)
*/
void
CloseKernelDevice(HANDLE device_handle)
{
CloseHandle(device_handle);
}
MMRESULT
SetDeviceData(
HANDLE device_handle,
DWORD ioctl,
PBYTE input_buffer,
DWORD buffer_size)
{
DPRINT("SetDeviceData\n");
/* TODO */
return 0;
}
MMRESULT
GetDeviceData(
HANDLE device_handle,
DWORD ioctl,
PBYTE output_buffer,
DWORD buffer_size)
{
OVERLAPPED overlap;
DWORD bytes_returned;
BOOL success;
DWORD transfer;
DPRINT("GetDeviceData\n");
memset(&overlap, 0, sizeof(overlap));
overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! overlap.hEvent )
return MMSYSERR_NOMEM;
success = DeviceIoControl(device_handle,
ioctl,
NULL,
0,
output_buffer,
buffer_size,
&bytes_returned,
&overlap);
if ( ! success )
{
if ( GetLastError() == ERROR_IO_PENDING )
{
if ( ! GetOverlappedResult(device_handle, &overlap, &transfer, TRUE) )
{
CloseHandle(overlap.hEvent);
return ErrorToMmResult(GetLastError());
}
}
else
{
CloseHandle(overlap.hEvent);
return ErrorToMmResult(GetLastError());
}
}
while ( TRUE )
{
SetEvent(overlap.hEvent);
if ( WaitForSingleObjectEx(overlap.hEvent, 0, TRUE) != WAIT_IO_COMPLETION )
{
break;
}
}
CloseHandle(overlap.hEvent);
return MMSYSERR_NOERROR;
}
+4 -4
View File
@@ -7,8 +7,8 @@
LIBRARY mmdrv.dll
EXPORTS
DriverProc@20
widMessage@20
;widMessage@20
wodMessage@20
midMessage@20
modMessage@20
auxMessage@20
;midMessage@20
;modMessage@20
;auxMessage@20
+300 -80
View File
@@ -2,117 +2,337 @@
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/mmdrv/mmdrv.h
* FILE: dll/win32/mmdrv/mmdrv.h
* PURPOSE: Multimedia User Mode Driver (header)
* PROGRAMMER: Andrew Greenwood
* Aleksey Bragin
* UPDATE HISTORY:
* Jan 30, 2004: Imported into ReactOS tree
* Jan 10, 2007: Rewritten and tidied up
*/
#ifndef __INCLUDES_MMDRV_H__
#define __INCLUDES_MMDRV_H__
#ifndef MMDRV_H
#define MMDRV_H
//#define UNICODE
#define EXPORT __declspec(dllexport)
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <mmioctl.h>
#include <mmddk.h>
// This needs to be done to get winioctl.h to work:
//typedef unsigned __int64 DWORD64, *PDWORD64;
#include <stdio.h>
#define DPRINT printf
#include <winioctl.h>
//#include "mmddk.h"
#include "mmdef.h"
/* Need to check these */
#define MAX_DEVICES 256
#define MAX_DEVICE_NAME_LENGTH 256
#define MAX_BUFFER_SIZE 1048576
#define MAX_WAVE_BYTES 1048576
/* Custom flag set when overlapped I/O is done */
#define WHDR_COMPLETE 0x80000000
ULONG DbgPrint(PCCH Format, ...);
/*
#define SOUND_MAX_DEVICE_NAME 1024 // GUESSWORK
#define SOUND_MAX_DEVICES 256 // GUESSWORK
The kinds of devices which MMSYSTEM/WINMM may request from us.
*/
// If the root is \Device and the Device type is
// WaveIn and the device number is 2, the full name is \Device\WaveIn2
typedef enum
{
WaveOutDevice,
WaveInDevice,
MidiOutDevice,
MidiInDevice,
AuxDevice
} DeviceType;
#define WAVE_IN_DEVICE_NAME "\\Device\\WaveIn"
#define WAVE_IN_DEVICE_NAME_U L"\\Device\\WaveIn"
#define WAVE_OUT_DEVICE_NAME "\\Device\\WaveOut"
#define WAVE_OUT_DEVICE_NAME_U L"\\Device\\WaveOut"
#define IsWaveDevice(devicetype) \
( ( devicetype == WaveOutDevice ) || ( devicetype == WaveInDevice ) )
#define MIDI_IN_DEVICE_NAME "\\Device\\MidiIn"
#define MIDI_IN_DEVICE_NAME_U L"\\Device\\MidiIn"
#define MIDI_OUT_DEVICE_NAME "\\Device\\MidiOut"
#define MIDI_OUT_DEVICE_NAME_U L"\\Device\\MidiOut"
#define IsMidiDevice(devicetype) \
( ( devicetype == MidiOutDevice ) || ( devicetype == MidiInDevice ) )
#define IsAuxDevice(devicetype) \
( devicetype == AuxDevice )
#define AUX_DEVICE_NAME "\\Device\\MMAux"
#define AUX_DEVICE_NAME_U L"\\Device\\MMAux"
/*
#define IOCTL_SOUND_BASE FILE_DEVICE_SOUND
#define IOCTL_WAVE_BASE 0x0000
#define IOCTL_MIDI_BASE 0x0080
// Wave device driver IOCTLs
#define IOCTL_WAVE_QUERY_FORMAT CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_WAVE_SET_FORMAT CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_CAPABILITIES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_WAVE_SET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0004, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0005, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_POSITION CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_SET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_WAVE_GET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_WAVE_SET_PITCH CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_PITCH CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000A, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_SET_PLAYBACK_RATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000B, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_PLAYBACK_RATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000C, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_PLAY CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000D, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_RECORD CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000E, METHOD_OUT_DIRECT, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_BREAK_LOOP CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000F, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_SET_LOW_PRIORITY CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0010, METHOD_BUFFERED, FILE_WRITE_ACCESS)
// MIDI device driver IOCTLs
#define IOCTL_MIDI_GET_CAPABILITIES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MIDI_SET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_GET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0003, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_SET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MIDI_GET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MIDI_PLAY CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_RECORD CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0007, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_CACHE_PATCHES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0008, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_CACHE_DRUM_PATCHES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
We use these structures to store information regarding open devices. Since
the main structure gets destroyed when a device is closed, I call this a
"session".
*/
typedef struct
{
OVERLAPPED overlap;
LPWAVEHDR header;
} WaveOverlapInfo;
CRITICAL_SECTION CS; // Serialize access to device lists
/*
typedef enum
{
WaveAddBuffer,
WaveClose,
WaveReset,
WaveRestart,
SessionThreadTerminate,
InvalidFunction
} ThreadFunction;
*/
HANDLE Heap;
/* Our own values, used with the session threads */
typedef DWORD ThreadFunction;
#define DRVM_TERMINATE 0xFFFFFFFE
#define DRVM_INVALID 0xFFFFFFFF
enum {
InvalidDevice,
WaveInDevice,
WaveOutDevice,
MidiInDevice,
MidiOutDevice,
AuxDevice
};
typedef enum
{
WavePlaying,
WaveStopped,
WaveReset,
WaveRestart
} WaveState;
MMRESULT OpenDevice(UINT DeviceType, DWORD ID, PHANDLE pDeviceHandle,
DWORD Access);
typedef union
{
PWAVEHDR wave_header;
PMIDIHDR midi_header;
} MediaHeader;
MMRESULT FindDevices();
/*
typedef union
{
MediaHeader header;
} ThreadParameter;
*/
DWORD GetDeviceCount(UINT DeviceType);
typedef struct _ThreadInfo
{
HANDLE handle;
HANDLE ready_event;
HANDLE go_event;
/*ThreadFunction function;*/
DWORD function;
PVOID parameter;
MMRESULT result;
} ThreadInfo;
typedef struct _LoopInfo
{
PWAVEHDR head;
DWORD iterations;
} LoopInfo;
typedef struct _SessionInfo
{
struct _SessionInfo* next;
DeviceType device_type;
DWORD device_id;
HANDLE kernel_device_handle;
/* These are all the same */
union
{
HDRVR mme_handle;
HWAVE mme_wave_handle;
HMIDI mme_midi_handle;
};
/* If playback is paused or not */
BOOL is_paused;
/* Stuff passed to us from winmm */
DWORD app_user_data;
DWORD callback;
DWORD flags;
/* Can only be one or the other */
union
{
PWAVEHDR wave_queue;
PMIDIHDR midi_queue;
};
/* Current playback point */
//PWAVEHDR next_buffer;
/* Where in the current buffer we are */
DWORD buffer_position;
// DWORD remaining_bytes;
LoopInfo loop;
ThreadInfo thread;
} SessionInfo;
#undef ASSERT
#define ASSERT(condition) \
if ( ! (condition) ) \
DPRINT("ASSERT FAILED: %s\n", #condition);
/*
MME interface
*/
BOOL
NotifyClient(
SessionInfo* session_info,
DWORD message,
DWORD parameter1,
DWORD parameter2);
/*
Helpers
*/
MMRESULT
ErrorToMmResult(UINT error_code);
/* Kernel interface */
MMRESULT
CobbleDeviceName(
DeviceType device_type,
DWORD device_id,
PWCHAR out_device_name);
MMRESULT
OpenKernelDevice(
DeviceType device_type,
DWORD device_id,
DWORD access,
HANDLE* handle);
VOID
CloseKernelDevice(HANDLE device_handle);
MMRESULT
SetDeviceData(
HANDLE device_handle,
DWORD ioctl,
PBYTE input_buffer,
DWORD buffer_size);
MMRESULT
GetDeviceData(
HANDLE device_handle,
DWORD ioctl,
PBYTE output_buffer,
DWORD buffer_size);
/* Session management */
MMRESULT
CreateSession(
DeviceType device_type,
DWORD device_id,
SessionInfo** session_info);
VOID
DestroySession(SessionInfo* session);
SessionInfo*
GetSession(
DeviceType device_type,
DWORD device_id);
MMRESULT
StartSessionThread(SessionInfo* session_info);
MMRESULT
CallSessionThread(
SessionInfo* session_info,
ThreadFunction function,
PVOID thread_parameter);
DWORD
HandleBySessionThread(
DWORD private_handle,
DWORD message,
DWORD parameter);
/* General */
DWORD
GetDeviceCount(DeviceType device_type);
DWORD
GetDeviceCapabilities(
DeviceType device_type,
DWORD device_id,
PVOID capabilities,
DWORD capabilities_size);
DWORD
OpenDevice(
DeviceType device_type,
DWORD device_id,
PVOID open_descriptor,
DWORD flags,
DWORD private_handle);
DWORD
CloseDevice(
DWORD private_handle);
DWORD
PauseDevice(
DWORD private_handle);
DWORD
RestartDevice(
DWORD private_handle);
DWORD
ResetDevice(
DWORD private_handle);
DWORD
GetPosition(
DWORD private_handle,
PMMTIME time,
DWORD time_size);
DWORD
BreakLoop(DWORD private_handle);
DWORD
QueryWaveFormat(
DeviceType device_type,
PVOID lpFormat);
DWORD
WriteWaveBuffer(
DWORD private_handle,
PWAVEHDR wave_header,
DWORD wave_header_size);
/* wave thread */
DWORD
WaveThread(LPVOID parameter);
/* Wave I/O */
VOID
PerformWaveIO(SessionInfo* session_info);
CRITICAL_SECTION critical_section;
DWORD TranslateStatus(void);
#endif
+5 -3
View File
@@ -8,9 +8,11 @@
<library>kernel32</library>
<library>user32</library>
<library>winmm</library>
<file>auxil.c</file>
<file>entry.c</file>
<file>midi.c</file>
<file>utils.c</file>
<file>mme.c</file>
<file>kernel.c</file>
<file>session.c</file>
<file>common.c</file>
<file>wave.c</file>
<file>wave_io.c</file>
</module>
+143
View File
@@ -0,0 +1,143 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: dll/win32/mmdrv/mme.c
* PURPOSE: Multimedia User Mode Driver (MME Interface)
* PROGRAMMER: Andrew Greenwood
* Aleksey Bragin
* UPDATE HISTORY:
* Jan 14, 2007: Rewritten and tidied up
*/
#include <mmdrv.h>
/*
Sends a message to the client (application), such as WOM_DONE. This
is just a wrapper around DriverCallback which translates the
parameters appropriately.
*/
BOOL
NotifyClient(
SessionInfo* session_info,
DWORD message,
DWORD parameter1,
DWORD parameter2)
{
return DriverCallback(session_info->callback,
HIWORD(session_info->flags),
session_info->mme_handle,
message,
session_info->app_user_data,
parameter1,
parameter2);
}
/*
MME Driver Entrypoint
Wave Output
*/
APIENTRY DWORD
wodMessage(
DWORD device_id,
DWORD message,
DWORD private_handle,
DWORD parameter1,
DWORD parameter2)
{
switch ( message )
{
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p80.htm */
case WODM_GETNUMDEVS :
DPRINT("WODM_GETNUMDEVS\n");
return GetDeviceCount(WaveOutDevice);
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p6h.htm */
case WODM_GETDEVCAPS :
DPRINT("WODM_GETDEVCAPS\n");
return GetDeviceCapabilities(WaveOutDevice,
device_id,
(PVOID) parameter1,
parameter2);
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p85.htm */
case WODM_OPEN :
{
WAVEOPENDESC* open_desc = (WAVEOPENDESC*) parameter1;
DPRINT("WODM_OPEN\n");
if ( parameter2 && WAVE_FORMAT_QUERY )
return QueryWaveFormat(WaveOutDevice, open_desc->lpFormat);
else
return OpenDevice(WaveOutDevice,
device_id,
open_desc,
parameter2,
private_handle);
}
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p6g.htm */
case WODM_CLOSE :
{
DPRINT("WODM_CLOSE\n");
return CloseDevice(private_handle);
}
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p9w.htm */
case WODM_WRITE :
{
DPRINT("WODM_WRITE\n");
return WriteWaveBuffer(private_handle,
(PWAVEHDR) parameter1,
parameter2);
}
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p86.htm */
case WODM_PAUSE :
{
DPRINT("WODM_PAUSE\n");
return HandleBySessionThread(private_handle, message, 0);
}
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p89.htm */
case WODM_RESTART :
{
DPRINT("WODM_RESTART\n");
return HandleBySessionThread(private_handle, message, 0);
}
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p88.htm */
case WODM_RESET :
{
DPRINT("WODM_RESET\n");
return HandleBySessionThread(private_handle, message, 0);
}
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p83.htm */
#if 0
case WODM_GETPOS :
{
DPRINT("WODM_GETPOS\n");
return GetPosition(private_handle,
(PMMTIME) parameter1,
parameter2);
}
#endif
/* http://www.osronline.com/ddkx/w98ddk/mmedia_4p6f.htm */
case WODM_BREAKLOOP :
{
DPRINT("WODM_BREAKLOOP\n");
return HandleBySessionThread(private_handle, message, 0);
}
/* TODO: Others */
}
DPRINT("Unsupported message\n");
return MMSYSERR_NOTSUPPORTED;
}
+147
View File
@@ -0,0 +1,147 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: dll/win32/mmdrv/mmioctl.h
* PURPOSE: Multimedia system NT4 compatibility
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Jan 13, 2007: Split from mmdrv.h
*/
#ifndef MMDRV_IOCTLS
#define MMDRV_IOCTLS
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include <winioctl.h>
/*
Base names of the supported devices, as provided by drivers running in
kernel mode.
\Device\WaveIn0 etc.
*/
#define WAVE_OUT_DEVICE_NAME L"\\Device\\WaveOut"
#define WAVE_IN_DEVICE_NAME L"\\Device\\WaveIn"
#define MIDI_OUT_DEVICE_NAME L"\\Device\\MidiOut"
#define MIDI_IN_DEVICE_NAME L"\\Device\\MidiIn"
#define AUX_DEVICE_NAME L"\\Device\\MMAux"
/*
Base IOCTL codes
*/
#define IOCTL_SOUND_BASE FILE_DEVICE_SOUND
#define IOCTL_WAVE_BASE 0x0000
#define IOCTL_MIDI_BASE 0x0080
#define IOCTL_AUX_BASE 0x0100
/*
Wave IOCTLs
*/
#define IOCTL_WAVE_QUERY_FORMAT \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_WAVE_SET_FORMAT \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_CAPABILITIES \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_WAVE_SET_STATE \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0004, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_STATE \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0005, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_POSITION \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_SET_VOLUME \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0007, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_WAVE_GET_VOLUME \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0008, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_WAVE_SET_PITCH \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_PITCH \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000A, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_SET_PLAYBACK_RATE \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000B, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_GET_PLAYBACK_RATE \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000C, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_PLAY \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000D, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_RECORD \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000E, METHOD_OUT_DIRECT, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_BREAK_LOOP \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000F, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WAVE_SET_LOW_PRIORITY \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0010, METHOD_BUFFERED, FILE_WRITE_ACCESS)
/*
MIDI IOCTLs
*/
#define IOCTL_MIDI_GET_CAPABILITIES \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MIDI_SET_STATE \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_GET_STATE \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0003, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_SET_VOLUME \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MIDI_GET_VOLUME \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MIDI_PLAY \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_RECORD \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0007, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_CACHE_PATCHES \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0008, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MIDI_CACHE_DRUM_PATCHES \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
/*
Aux IOCTLs
*/
#define IOCTL_AUX_GET_CAPABILITIES \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_AUX_SET_VOLUME \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_AUX_GET_VOLUME \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_SOUND_GET_CHANGED_VOLUME \
CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
#endif
+245
View File
@@ -0,0 +1,245 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: dll/win32/mmdrv/session.c
* PURPOSE: Multimedia User Mode Driver (session management)
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Jan 14, 2007: Created
*/
#include <mmdrv.h>
/* Each session is tracked, but the list must be locked when in use */
SessionInfo* session_list = NULL;
CRITICAL_SECTION session_lock;
/*
Obtains a pointer to the session associated with a device type and ID.
If no session exists, returns NULL. This is mainly used to see if a
session already exists prior to creating a new one.
*/
SessionInfo*
GetSession(
DeviceType device_type,
DWORD device_id)
{
SessionInfo* session_info;
EnterCriticalSection(&session_lock);
session_info = session_list;
while ( session_info )
{
if ( ( session_info->device_type == device_type ) &&
( session_info->device_id == device_id ) )
{
LeaveCriticalSection(&session_lock);
return session_info;
}
session_info = session_info->next;
}
LeaveCriticalSection(&session_lock);
return NULL;
}
/*
Creates a new session, associated with the specified device type and ID.
Whilst the session list is locked, this also checks to see if an existing
session is associated with the device.
*/
MMRESULT
CreateSession(
DeviceType device_type,
DWORD device_id,
SessionInfo** session_info)
{
HANDLE heap = GetProcessHeap();
ASSERT(session_info);
EnterCriticalSection(&session_lock);
/* Ensure we're not creating a duplicate session */
if ( GetSession(device_type, device_id) )
{
DPRINT("Already allocated session\n");
LeaveCriticalSection(&session_lock);
return MMSYSERR_ALLOCATED;
}
*session_info = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(SessionInfo));
if ( ! *session_info )
{
DPRINT("Failed to allocate mem for session info\n");
LeaveCriticalSection(&session_lock);
return MMSYSERR_NOMEM;
}
(*session_info)->device_type = device_type;
(*session_info)->device_id = device_id;
/* Add to the list */
(*session_info)->next = session_list;
session_list = *session_info;
LeaveCriticalSection(&session_lock);
return MMSYSERR_NOERROR;
}
/*
Removes a session from the list and destroys it. This function does NOT
perform any additional cleanup. Think of it as a slightly more advanced
free()
*/
VOID
DestroySession(SessionInfo* session)
{
HANDLE heap = GetProcessHeap();
SessionInfo* session_node;
SessionInfo* session_prev;
/* TODO: More cleanup stuff */
/* Remove from the list */
EnterCriticalSection(&session_lock);
session_node = session_list;
session_prev = NULL;
while ( session_node )
{
if ( session_node == session )
{
/* Bridge the gap for when we go */
session_prev->next = session->next;
break;
}
/* Save the previous node, fetch the next */
session_prev = session_node;
session_node = session_node->next;
}
LeaveCriticalSection(&session_lock);
HeapFree(heap, 0, session);
}
/*
Allocates events and other resources for the session thread, starts it,
and waits for it to announce that it is ready to work for us.
*/
MMRESULT
StartSessionThread(SessionInfo* session_info)
{
LPTASKCALLBACK task;
MMRESULT result;
ASSERT(session_info);
/* This is our "ready" event, sent when the thread is idle */
session_info->thread.ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! session_info->thread.ready_event )
{
DPRINT("Couldn't create thread_ready event\n");
return MMSYSERR_NOMEM;
}
/* This is our "go" event, sent when we want the thread to do something */
session_info->thread.go_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! session_info->thread.go_event )
{
DPRINT("Couldn't create thread_go event\n");
CloseHandle(session_info->thread.ready_event);
return MMSYSERR_NOMEM;
}
/* TODO - other kinds of devices need attention, too */
task = ( session_info->device_type == WaveOutDevice )
? (LPTASKCALLBACK) WaveThread : NULL;
ASSERT(task);
/* Effectively, this is a beefed-up CreateThread */
result = mmTaskCreate(task,
&session_info->thread.handle,
(DWORD) session_info);
if ( result != MMSYSERR_NOERROR )
{
DPRINT("Task creation failed\n");
CloseHandle(session_info->thread.ready_event);
CloseHandle(session_info->thread.go_event);
return result;
}
/* Wait for the thread to be ready before completing */
WaitForSingleObject(session_info->thread.ready_event, INFINITE);
return MMSYSERR_NOERROR;
}
/*
The session thread is pretty simple. Upon creation, it announces that it
is ready to do stuff for us. When we want it to perform an action, we use
CallSessionThread with an appropriate function and parameter, then tell
the thread we want it to do something. When it's finished, it announces
that it is ready once again.
*/
MMRESULT
CallSessionThread(
SessionInfo* session_info,
ThreadFunction function,
PVOID thread_parameter)
{
ASSERT(session_info);
session_info->thread.function = function;
session_info->thread.parameter = thread_parameter;
DPRINT("Calling session thread\n");
SetEvent(session_info->thread.go_event);
DPRINT("Waiting for thread response\n");
WaitForSingleObject(session_info->thread.ready_event, INFINITE);
return session_info->thread.result;
}
DWORD
HandleBySessionThread(
DWORD private_handle,
DWORD message,
DWORD parameter)
{
return CallSessionThread((SessionInfo*) private_handle,
message,
(PVOID) parameter);
}
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
/*
Don't use this.
*/
#include <mmdrv.h>
/*
Complete a partial wave buffer transaction
*/
void
CompleteWaveOverlap(
DWORD error_code,
DWORD bytes_transferred,
LPOVERLAPPED overlapped)
{
DPRINT("Complete partial wave overlap\n");
}
/*
Helper function to set up loops
*/
VOID
UpdateWaveLoop(SessionInfo* session_info)
{
}
/*
The hub of all wave I/O. This ensures a constant stream of buffers are
passed between the land of usermode and kernelmode.
*/
VOID
PerformWaveIO(
SessionInfo* session_info)
{
}
-97
View File
@@ -1,97 +0,0 @@
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
-4
View File
@@ -1,4 +0,0 @@
To-Do:
- Globally store the heap handle
- Ensure cleanups are... clean...
- Clone device info in OPEN/close?
-86
View File
@@ -1,86 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/wdmaud.h
* PURPOSE: WDM Audio Support - Callbacks
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 24, 2005: Started
*/
#include <windows.h>
#include "wdmaud.h"
/*
CheckCallbacks
This appears to just be used by the mixer stuff.
If the global callback file mapping handle isn't set, return FALSE.
Check the first parameter. If the value is below that of the first
DWORD in the mapped view, return FALSE.
TODO: Finish analysis
*/
BOOL CheckCallbacks()
{
return FALSE;
}
/*
CreateWdmaudCallbacks
The original appears to use a security descriptor... We won't bother
with that for now.
Create a file mapping with the name "Global\WDMAUD_Callbacks".
The current process is used as the file handle for the file mapping. The
file mapping attributes should be set to a length of 12 bytes, the
security descriptor we ignore and the handle doesn't need to be
inheritable.
The maximum size should be set to 1028 bytes, and the file view
protection should be set to PAGE_READWRITE.
The result of the file mapping creation is stored in the global callback
handle.
If the creation succeeded, try and map a view of the file, from offset 0
for 1028 bytes, with READ and WRITE access.
If this succeeds, close the created file mapping handle, and set the
global handle to the one returned by the file mapping function.
*/
BOOL CreateWdmaudCallbacks()
{
return FALSE;
}
/*
GetWdmaudCallbacks
If the global callback handle is already set, do nothing.
Open the file mapping to "Global\WDMAUD_Callbacks" with READ and WRITE
access. The handle doesn't need to be inherited.
The handle is stored as the global callback handle.
If the file was opened successfully, map the view of 1028 bytes from
offset 0 with READ and WRITE access.
If this fails, close the global callback handle and set it to NULL.
...and then return
*/
BOOL GetWdmaudCallbacks()
{
return FALSE;
}
-196
View File
@@ -1,196 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/wavehdr.c
* PURPOSE: WDM Audio Support - Device Control (Play/Stop etc.)
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 23, 2005: Created
*/
#include <windows.h>
#include "wdmaud.h"
/*
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)
{
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_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 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)
{
}
-693
View File
@@ -1,693 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/devices.c
* PURPOSE: WDM Audio Support - Device Management
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*
* WARNING! SOME OF THESE FUNCTIONS OUGHT TO COPY THE DEVICE INFO STRUCTURE
* THAT HAS BEEN FED TO THEM!
*/
#include <windows.h>
#include "wdmaud.h"
const char WDMAUD_DEVICE_INFO_SIG[4] = "WADI";
const char WDMAUD_DEVICE_STATE_SIG[4] = "WADS";
/*
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 */
{
DPRINT1("Bad interface\n");
return FALSE;
}
/* Original driver seems to check for strlenW < 0x1000 */
return TRUE;
}
/*
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, 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;
}
/*
ValidateDeviceStateEvents should be used in conjunction with the standard
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 ) &&
( (DWORD) state->exit_thread_event != 0x48484848 ) )
{
DPRINT1("Bad exit thread event\n");
return MMSYSERR_INVALPARAM;
}
if ( ( (DWORD) state->queue_event != 0x00000000 ) &&
( (DWORD) state->queue_event != 0x42424242 ) &&
( (DWORD) state->queue_event != 0x43434343 ) )
{
DPRINT1("Bad queue event\n");
return MMSYSERR_INVALPARAM;
}
return MMSYSERR_NOERROR;
}
*/
/*
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
)
{
BOOL success = FALSE;
PWDMAUD_DEVICE_INFO device = 0;
int path_size = 0;
DPRINT("Creating device data for device type %d\n", (int) device_type);
if ( ! IsValidDevicePath(device_path) )
{
DPRINT1("No valid device interface given!\n");
goto cleanup;
}
/* Take into account this is a unicode string... */
path_size = (lstrlen(device_path) + 1) * sizeof(WCHAR);
/* DPRINT("Size of path is %d\n", (int) path_size); */
DPRINT("Allocating %d bytes for device data\n",
path_size + sizeof(WDMAUD_DEVICE_INFO));
device = (PWDMAUD_DEVICE_INFO)
AllocMem(path_size + sizeof(WDMAUD_DEVICE_INFO));
if ( ! device )
{
DPRINT1("Unable to allocate memory for device data (error %d)\n",
(int) GetLastError());
goto cleanup;
}
/* Copy the signature and device path */
memcpy(device->signature, WDMAUD_DEVICE_INFO_SIG, 4);
lstrcpy(device->path, device_path);
/* Initialize these common members */
device->id = device_id;
device->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 :
{
if ( ! success )
{
if ( device )
{
if ( device->state )
{
ZeroMemory(device->state->signature, 4);
FreeMem(device->state);
}
ZeroMemory(device->signature, 4);
FreeMem(device);
}
}
return (success ? device : NULL);
}
}
/*
DeleteDeviceData
Blanks out the device and device state structures, and frees the memory
associated with the structures.
TODO: Free critical sections / events if set?
*/
void DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data)
{
DPRINT("Deleting device data\n");
ASSERT( device_data );
/* 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,
BOOL adding)
{
DWORD ioctl = 0;
PWDMAUD_DEVICE_INFO device_data = 0;
MMRESULT result = MMSYSERR_ERROR;
MMRESULT kernel_result = MMSYSERR_ERROR;
DPRINT("ModifyDevicePresence - %s a device\n",
adding ? "adding" : "removing");
/* DPRINT("Topology path %S\n", device_path); */
DPRINT("Devtype %d\n", (int) device_type);
ASSERT( IsValidDeviceType(device_type) );
ASSERT( device_path );
device_data = CreateDeviceData(device_type, 0, device_path, FALSE);
if ( ! device_data )
{
DPRINT1("Couldn't allocate memory for device data\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
ioctl = adding ? IOCTL_WDMAUD_ADD_DEVICE : IOCTL_WDMAUD_REMOVE_DEVICE;
kernel_result = CallKernelDevice(device_data,
ioctl,
0,
0);
if ( kernel_result != MMSYSERR_NOERROR )
{
DPRINT1("WdmAudioIoControl FAILED with error %d\n", (int) kernel_result);
switch ( kernel_result )
{
/* TODO: Translate into a real error code */
default :
result = MMSYSERR_ERROR;
}
goto cleanup;
}
DPRINT("ModifyDevicePresence succeeded\n");
result = MMSYSERR_NOERROR;
cleanup :
{
if ( device_data )
DeleteDeviceData(device_data);
return result;
}
}
/*
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;
int device_count = 0;
DPRINT("Topology path %S\n", topology_path);
device_data = CreateDeviceData(device_type, 0, topology_path, FALSE);
if (! device_data)
{
DPRINT1("Couldn't allocate device data\n");
goto cleanup;
}
DPRINT("Getting num devs\n");
device_data->with_critical_section = FALSE;
if ( CallKernelDevice(device_data,
IOCTL_WDMAUD_GET_DEVICE_COUNT,
0,
0) != MMSYSERR_NOERROR )
{
DPRINT1("Failed\n");
goto cleanup;
}
device_count = device_data->id;
DPRINT("There are %d devs\n", device_count);
cleanup :
{
if ( device_data )
DeleteDeviceData(device_data);
return device_count;
}
}
/*
GetDeviceCapabilities
This uses a different structure to the traditional documentation, because
we handle plug and play devices.
Much sleep was lost over implementing this. I got the ID and type
parameters the wrong way round!
*/
MMRESULT GetDeviceCapabilities(
CHAR device_type,
DWORD device_id,
WCHAR* device_path,
LPMDEVICECAPSEX caps
)
{
PWDMAUD_DEVICE_INFO device = NULL;
MMRESULT result = MMSYSERR_ERROR;
DPRINT("Device path %S\n", device_path);
/* Is this right? */
if (caps->cbSize == 0)
{
DPRINT1("We appear to have been given an invalid parameter\n");
return MMSYSERR_INVALPARAM;
}
DPRINT("Going to have to query the kernel-mode part\n");
device = CreateDeviceData(device_type, device_id, device_path, FALSE);
if ( ! device )
{
DPRINT("Unable to allocate device data memory\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
/* These are not needed as they're already initialized */
ASSERT( device_id == device->id );
ASSERT( ! device->with_critical_section );
*(LPWORD)caps->pCaps = (WORD) 0x43;
DPRINT("Calling kernel device\n");
result = CallKernelDevice(device,
IOCTL_WDMAUD_GET_CAPABILITIES,
(DWORD)caps->cbSize,
(DWORD)caps->pCaps);
if ( result != MMSYSERR_NOERROR )
{
DPRINT("IoControl failed\n");
goto cleanup;
}
/* Return code will already be MMSYSERR_NOERROR by now */
cleanup :
{
if ( device )
DeleteDeviceData(device);
return result;
}
}
/*
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
)
{
DWORD format_struct_len = 0;
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;
format_struct_len = 16; /* FIXME */
}
else
{
/* Non-standard format */
return MMSYSERR_NOTSUPPORTED; /* TODO */
}
return CallKernelDevice(device,
IOCTL_WDMAUD_OPEN_DEVICE,
format_struct_len,
(DWORD)format);
}
/* 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,
LPVOID open_descriptor,
DWORD flags,
PWDMAUD_DEVICE_INFO* user_data
)
{
MMRESULT result = MMSYSERR_ERROR;
WCHAR* device_path;
PWDMAUD_DEVICE_INFO device;
LPWAVEFORMATEX format;
/* As we support both types */
LPWAVEOPENDESC wave_opendesc = (LPWAVEOPENDESC) open_descriptor;
LPMIDIOPENDESC midi_opendesc = (LPMIDIOPENDESC) open_descriptor;
/* FIXME: Does this just apply to wave, or MIDI also? */
if ( device_id > 100 )
return MMSYSERR_BADDEVICEID;
/* 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;
device = CreateDeviceData(device_type, device_id, device_path, TRUE);
if ( ! device )
{
DPRINT1("Couldn't allocate memory for device data\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
device->flags = flags;
if ( ( IsWaveDeviceType(device->type) ) &&
( device->flags & WAVE_FORMAT_QUERY ) )
{
result = OpenDeviceViaKernel(device, wave_opendesc->lpFormat);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Format not supported (mmsys error %d)\n", (int) result);
result = WAVERR_BADFORMAT;
}
else
{
DPRINT("Format supported\n");
result = MMSYSERR_NOERROR;
}
goto cleanup;
}
device->state->device_queue_guard = CreateCriticalSection();
if ( ! device->state->device_queue_guard )
{
DPRINT1("Couldn't create queue cs\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
/* Set up the callbacks */
device->client_instance = IsWaveDeviceType(device->type)
? wave_opendesc->dwInstance
: midi_opendesc->dwInstance;
device->client_callback = IsWaveDeviceType(device->type)
? wave_opendesc->dwCallback
: midi_opendesc->dwCallback;
/*
The device state will be stopped and unpaused already, but in some
cases this isn't the desired behaviour.
*/
/* FIXME: What do our friends MIDI in and out need? */
device->state->is_paused = IsWaveOutDeviceType(device->type) ? TRUE : FALSE;
if ( IsMidiOutDeviceType(device->type) )
{
device->state->midi_buffer = AllocMem(2048);
if ( ! device->state->midi_buffer )
{
DPRINT1("Couldn't allocate MIDI buffer\n");
result = MMSYSERR_NOMEM;
goto cleanup;
}
}
/* Format is only for wave devices */
format = IsWaveDeviceType(device->type) ? wave_opendesc->lpFormat : NULL;
result = OpenDeviceViaKernel(device, format);
if ( MM_FAILURE(result) )
{
DPRINT1("FAILED to open device - mm error %d\n", (int) result);
goto cleanup;
}
EnterCriticalSection(device->state->device_queue_guard);
/* TODO */
LeaveCriticalSection(device->state->device_queue_guard);
if ( IsWaveDeviceType(device->type) )
wave_opendesc->hWave = (HWAVE) device;
else
midi_opendesc->hMidi = (HMIDI) device;
/* 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);
}
result = MMSYSERR_NOERROR;
cleanup :
return result;
}
-46
View File
@@ -1,46 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/helper.c
* PURPOSE: Multimedia User Mode Driver - Helper Funcs
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 13, 2005: Created
*/
#include <windows.h>
#include <mmsystem.h>
/*
TranslateWinError converts Win32 error codes (returned by
GetLastError, typically) into MMSYSERR codes.
*/
MMRESULT TranslateWinError(DWORD error)
{
switch(error)
{
case NO_ERROR :
case ERROR_IO_PENDING :
return MMSYSERR_NOERROR;
case ERROR_BUSY :
return MMSYSERR_ALLOCATED;
case ERROR_NOT_SUPPORTED :
case ERROR_INVALID_FUNCTION :
return MMSYSERR_NOTSUPPORTED;
case ERROR_NOT_ENOUGH_MEMORY :
return MMSYSERR_NOMEM;
case ERROR_ACCESS_DENIED :
return MMSYSERR_BADDEVICEID;
case ERROR_INSUFFICIENT_BUFFER :
return MMSYSERR_INVALPARAM;
}
return MMSYSERR_ERROR;
}
-327
View File
@@ -1,327 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/kernel.c
* PURPOSE: WDM Audio Support - Kernel Mode Interface
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*/
#define INITGUID /* FIXME */
#include <windows.h>
#include <setupapi.h>
#include "wdmaud.h"
/* HACK ALERT - This goes in ksmedia.h */
DEFINE_GUID(KSCATEGORY_WDMAUD,
0x3e227e76L, 0x690d, 0x11d2, 0x81, 0x61, 0x00, 0x00, 0xf8, 0x77, 0x5b, 0xf1);
/* This stores the handle of the kernel device */
static HANDLE kernel_device_handle = NULL;
//static WCHAR*
/*
TODO: There's a variant of this that uses critical sections...
*/
MMRESULT CallKernelDevice(
PWDMAUD_DEVICE_INFO device,
DWORD ioctl_code,
DWORD param1,
DWORD param2)
{
OVERLAPPED overlap;
MMRESULT result = MMSYSERR_ERROR;
DWORD name_len = 0;
DWORD bytes_returned = 0;
BOOL using_critical_section = FALSE;
ASSERT(kernel_device_handle);
ASSERT(device);
DPRINT("Creating event\n");
overlap.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if ( ! overlap.hEvent )
{
DPRINT1("CreateEvent failed - error %d\n", (int)GetLastError());
result = MMSYSERR_NOMEM;
goto cleanup;
}
DPRINT("Sizeof wchar == %d\n", (int) sizeof(WCHAR));
name_len = lstrlen(device->path) * sizeof(WCHAR); /* ok ? */
/* These seem to carry optional structures */
device->ioctl_param1 = param1;
device->ioctl_param2 = param2;
/* Enter critical section if wave/midi device, and if required */
if ( ( ! IsMixerDeviceType(device->type) ) &&
( ! IsAuxDeviceType(device->type) ) &&
( device->with_critical_section ) )
{
ASSERT(device->state);
using_critical_section = TRUE;
EnterCriticalSection(device->state->device_queue_guard);
}
DPRINT("Calling DeviceIoControl with IOCTL %x\n", (int) ioctl_code);
if ( ! DeviceIoControl(kernel_device_handle,
ioctl_code,
device,
name_len + sizeof(WDMAUD_DEVICE_INFO),
device,
sizeof(WDMAUD_DEVICE_INFO),
&bytes_returned,
&overlap) )
{
DWORD error = GetLastError();
if (error != ERROR_IO_PENDING)
{
DPRINT1("FAILED in CallKernelDevice (error %d)\n", (int) error);
DUMP_WDMAUD_DEVICE_INFO(device);
result = TranslateWinError(error);
goto cleanup;
}
DPRINT("Waiting for overlap I/O event\n");
/* Wait for the IO to be complete */
WaitForSingleObject(overlap.hEvent, INFINITE);
}
result = MMSYSERR_NOERROR;
DPRINT("CallKernelDevice succeeded :)\n");
DUMP_WDMAUD_DEVICE_INFO(device);
cleanup :
{
/* Leave the critical section */
if ( using_critical_section )
LeaveCriticalSection(device->state->device_queue_guard);
if ( overlap.hEvent )
CloseHandle(overlap.hEvent);
return result;
}
}
static BOOL ChangeKernelDeviceState(BOOL enable)
{
PWDMAUD_DEVICE_INFO device = NULL;
DWORD ioctl_code;
MMRESULT call_result;
ioctl_code = enable ? IOCTL_WDMAUD_HELLO : IOCTL_WDMAUD_GOODBYE;
device = CreateDeviceData(WDMAUD_AUX, 0, L"", FALSE);
if ( ! device )
{
DPRINT1("Couldn't create a new device instance structure\n");
return FALSE;
}
device->with_critical_section = FALSE;
DPRINT("Calling kernel device\n");
call_result = CallKernelDevice(device, ioctl_code, 0, 0);
DeleteDeviceData(device);
if ( call_result != MMSYSERR_NOERROR )
{
DPRINT1("Kernel device doesn't like us! (error %d)\n", (int) GetLastError());
return FALSE;
}
else
{
return TRUE;
}
}
BOOL EnableKernelInterface()
{
/* SetupAPI variables/structures for querying device data */
SP_DEVICE_INTERFACE_DATA interface_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA detail = NULL;
DWORD detail_size = 0;
HANDLE heap = NULL;
HDEVINFO dev_info;
/* Set to TRUE right at the end to define cleanup behaviour */
BOOL success = FALSE;
/* Don't want to be called more than once */
ASSERT(kernel_device_handle == NULL);
dev_info = SetupDiGetClassDevs(&KSCATEGORY_WDMAUD,
NULL,
NULL,
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if ( ( ! dev_info ) || ( dev_info == INVALID_HANDLE_VALUE ) )
{
DPRINT1("SetupDiGetClassDevs failed\n");
goto cleanup;
}
interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if ( ! SetupDiEnumDeviceInterfaces(dev_info,
NULL,
&KSCATEGORY_WDMAUD,
0,
&interface_data) )
{
DPRINT1("SetupDiEnumDeviceInterfaces failed\n");
goto cleanup;
}
/*
We need to find out the size of the interface detail, before we can
actually retrieve the detail. This is a bit backwards, as the function
will return a status of success if the interface is invalid, but we
need it to fail with ERROR_INSUFFICIENT_BUFFER so we can be told how
much memory we need to allocate.
*/
if ( SetupDiGetDeviceInterfaceDetail(dev_info,
&interface_data,
NULL,
0,
&detail_size,
NULL) )
{
DPRINT1("SetupDiGetDeviceInterfaceDetail shouldn't succeed!\n");
goto cleanup;
}
/*
Now we make sure the error was the one we expected. If not, bail out.
*/
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
{
DPRINT1("SetupDiGetDeviceInterfaceDetail returned wrong error code\n");
goto cleanup;
}
heap = GetProcessHeap();
if ( ! heap )
{
DPRINT1("Unable to get the process heap (error %d)\n",
(int)GetLastError());
goto cleanup;
}
detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA) HeapAlloc(heap,
HEAP_ZERO_MEMORY,
detail_size);
if ( ! detail )
{
DPRINT1("Unable to allocate memory for the detail buffer (error %d)\n",
(int)GetLastError());
goto cleanup;
}
detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if ( ! SetupDiGetDeviceInterfaceDetail(dev_info,
&interface_data,
detail,
detail_size,
0,
NULL) )
{
DPRINT1("SetupDiGetDeviceInterfaceDetail failed\n");
goto cleanup;
}
DPRINT("Device path: %S\n", detail->DevicePath);
/* FIXME - params! */
kernel_device_handle = CreateFile(detail->DevicePath,
0xC0000000,
0,
0,
3,
0x40000080,
0);
DPRINT("kernel_device_handle == 0x%x\n", (int) kernel_device_handle);
if ( ! kernel_device_handle )
{
DPRINT1("Unable to open kernel device (error %d)\n",
(int) GetLastError());
goto cleanup;
}
/* Now we say hello to wdmaud.sys */
if ( ! ChangeKernelDeviceState(TRUE) )
{
DPRINT1("Couldn't enable the kernel device\n");
goto cleanup;
}
success = TRUE;
cleanup :
{
DPRINT("Cleanup - success == %d\n", (int) success);
if ( ! success )
{
DPRINT("Failing\n");
if ( kernel_device_handle )
CloseHandle(kernel_device_handle);
}
if ( heap )
{
if ( detail )
HeapFree(heap, 0, detail);
}
}
return success;
}
/*
Nothing here should fail, but if it does, we just give up and ASSERT(). If
we don't, we could be left in a limbo-state (eg: device open but disabled.)
*/
BOOL DisableKernelInterface()
{
return ChangeKernelDeviceState(FALSE);
}
/*
The use of this should be avoided...
*/
HANDLE GetKernelInterface()
{
return kernel_device_handle;
}
-77
View File
@@ -1,77 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/memtrack.c
* PURPOSE: WDM Audio Support - Memory Tracking
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*
*/
#include "wdmaud.h"
static int alloc_count = 0;
LPVOID AllocMem(DWORD size)
{
HANDLE heap;
LPVOID pointer;
heap = GetProcessHeap();
if ( ! heap )
{
DPRINT1("SEVERE ERROR! Couldn't get process heap! (error %d)\n",
(int) GetLastError());
return NULL;
}
pointer = HeapAlloc(heap, HEAP_ZERO_MEMORY, size);
if ( pointer )
alloc_count ++;
ReportMem();
return pointer;
}
VOID FreeMem(LPVOID pointer)
{
HANDLE heap;
if ( ! pointer )
{
DPRINT1("Trying to free a NULL pointer!\n");
return;
}
heap = GetProcessHeap();
if ( ! heap )
{
DPRINT1("SEVERE ERROR! Couldn't get process heap! (error %d)\n",
(int) GetLastError());
return;
}
if ( ! HeapFree(heap, 0, pointer) )
{
DPRINT("Unable to free memory (error %d)\n", (int)GetLastError());
return;
}
alloc_count --;
ReportMem();
}
VOID ReportMem()
{
DPRINT("Memory blocks allocated: %d\n", (int) alloc_count);
if ( alloc_count < 0 )
DPRINT1("FREEMEM HAS BEEN CALLED TOO MANY TIMES!\n");
}
-193
View File
@@ -1,193 +0,0 @@
/*
*
* 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
*/
-236
View File
@@ -1,236 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/threads.c
* PURPOSE: WDM Audio Support - Completion Threads
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*/
#include "wdmaud.h"
DWORD WINAPI WaveCompletionThreadStart(LPVOID data)
{
PWDMAUD_DEVICE_INFO device = (PWDMAUD_DEVICE_INFO) data;
MMRESULT result = MMSYSERR_ERROR;
PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL;
HANDLE overlap_event = NULL;
BOOL quit_loop = FALSE;
DPRINT("WaveCompletionThread started\n");
EnterCriticalSection(device->state->device_queue_guard);
while ( ! quit_loop )
{
result = ValidateDeviceData(device, TRUE);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Invalid device data or state structure!\n");
break;
}
/* TODO: REIMPLEMENT */
/* result = ValidateDeviceStateEvents(device->state); */
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Invalid device state events\n");
break;
}
if ( device->state->current_wave_header )
{
DPRINT("No current header - running? %d\n", (int) device->state->is_running);
if ( ! device->state->is_running )
{
LeaveCriticalSection(device->state->device_queue_guard);
DPRINT("Waiting for queue_event\n");
WaitForSingleObject(device->state->queue_event, INFINITE);
DPRINT("field 24 == %d\n", (int) device->state->unknown_24);
/* What is the importance of this field */
if ( ! device->state->unknown_24 )
{
/* ?!?! Presumably this dequeues */
continue;
}
DPRINT("We broke out the loop! Yay!\n");
/* TODO! */
return TRUE; /* bleh */
}
else
{
/* TODO: STOP */
DPRINT("TODO: Stop the device\n");
}
}
else
{
PWAVEHDR wave_header = device->state->current_wave_header;
DPRINT("An open descriptor or wave header was found\n");
result = ValidateWaveHeader(wave_header);
if ( result == MMSYSERR_NOERROR )
{
prep_data = (PWDMAUD_WAVE_PREPARATION_DATA) wave_header->reserved;
result = ValidateWavePreparationData(prep_data);
}
/* If both checks passed, the playback is complete */
if ( result != MMSYSERR_NOERROR )
{
result = MMSYSERR_NOERROR;
DPRINT("Activating the next header\n");
/* Activate the next header */
device->state->current_wave_header = wave_header->lpNext;
/* Reset this just in case */
prep_data = NULL;
/* continue; */
}
else
{
/* Should have valid prep data... */
overlap_event = prep_data->overlapped->hEvent;
/* Setting this will cause the loop to exit now */
quit_loop = TRUE;
}
}
}
/* We do this here in case there's an error - deadlock = bad! */
LeaveCriticalSection(device->state->device_queue_guard);
if ( result != MMSYSERR_NOERROR)
goto cleanup;
DPRINT("Waiting for object: %d\n", (int) overlap_event);
WaitForSingleObject(overlap_event, INFINITE);
cleanup :
{
DPRINT("Performing thread cleanup\n");
/* Yeah, like what? */
return result;
}
}
DWORD WINAPI MidiCompletionThreadStart(LPVOID data)
{
DPRINT("MidiCompletionThread started\n");
return 0;
}
BOOL CreateCompletionThread(PWDMAUD_DEVICE_INFO device)
{
LPTHREAD_START_ROUTINE thread_start = NULL;
if ( IsWaveDeviceType(device->type) )
thread_start = WaveCompletionThreadStart;
else if ( IsMidiDeviceType(device->type) )
thread_start = MidiCompletionThreadStart;
else
return FALSE; /* What did you just give me?! */
if ( device->state->unknown_30 != 0 )
{
DPRINT1("unknown_30 wasn't zero (it was %d)\n",
(int) device->state->unknown_30);
}
if ( device->state->thread )
{
DPRINT("Thread isn't null\n");
}
else
{
DPRINT("Thread is null\n");
if ( ( (DWORD) device->state->queue_event != 0 ) &&
( (DWORD) device->state->queue_event != MAGIC_42) &&
( (DWORD) device->state->queue_event != MAGIC_43) )
{
/* Not fatal... */
DPRINT("Queue event is being overwritten!\n");
/* return FALSE; */
}
device->state->queue_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! device->state->queue_event )
{
/* TODO - hmm original doesn't seem to care what happens */
}
if ( ( (DWORD) device->state->exit_thread_event != 0x00000000 ) &&
( (DWORD) device->state->exit_thread_event != 0x48484848 ) )
{
/* Not fatal... */
DPRINT("Exit Thread event is being overwritten!\n");
/* return FALSE; */
}
device->state->exit_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! device->state->exit_thread_event )
{
/* TODO - hmm original doesn't seem to care what happens */
}
device->state->thread = NULL;
/* Should this be unknown_04? aka THREAD? */
device->state->thread = CreateThread(NULL, 0, thread_start, device, 0,
&device->state->thread_id);
if ( ! device->state->thread )
{
DPRINT1("Thread creation failed (error %d)\n",
(int) GetLastError());
if ( device->state->queue_event )
{
CloseHandle(device->state->queue_event);
device->state->queue_event = NULL;
}
if ( device->state->exit_thread_event )
{
CloseHandle(device->state->exit_thread_event);
device->state->exit_thread_event = NULL;
}
return FALSE;
}
SetThreadPriority(device->state->thread, 0xf);
DPRINT("Thread created! - %d\n", (int) device->state->thread);
/* TODO: Set priority */
}
return TRUE; /* TODO / FIXME */
}
-434
View File
@@ -1,434 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/user.c
* PURPOSE: WDM Audio Support - User Mode Interface
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*/
/*
* The GETDEVCAPS message parameters have different meaning in our case.
* The second parameter usually indicates the struct size. But this has
* been replaced by a pointer to the device path.
*/
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
#include "wdmaud.h"
APIENTRY LRESULT DriverProc(
DWORD DriverID,
HDRVR DriverHandle,
UINT Message,
LONG Param1,
LONG Param2)
{
/*
Only DRV_ENABLE and DRV_DISABLE need special handling - everything else
is just implemented to aid in debugging.
*/
DPRINT("DriverProc %d %d %d %d %d\n", (INT) DriverID, (int) DriverHandle, (int) Message, (int) Param1, (int) Param2);
switch(Message)
{
/*
DRV_LOAD is the first message we receive, to say we've been loaded.
DriverHandle is documented as being unused, but appears to be the
number 3 (on my system, at least.)
*/
case DRV_LOAD :
DPRINT("DRV_LOAD\n");
/* We should initialize the device list */
return TRUE; // dont need to do any more
case DRV_FREE :
/* We should stop all wave and MIDI playback */
DPRINT("DRV_FREE\n");
return TRUE;
/*
DRV_OPEN is sent when WINMM wishes to open the driver. Param1
can specify configuration information, but we don't need any.
*/
case DRV_OPEN :
DPRINT("DRV_OPEN\n");
return TRUE;
case DRV_CLOSE :
DPRINT("DRV_CLOSE\n");
return TRUE;
/*
Enabling this driver causes the kernel-mode portion of WDMAUD to
be opened. We send a message to the kernel-mode driver to say that
we want to make use of it.
And, of course, when we are being disabled, we tell the kernel-mode
portion that we don't require its services any more, and close
the handle to it.
*/
case DRV_ENABLE :
{
DPRINT("DRV_ENABLE\n");
return EnableKernelInterface();
}
case DRV_DISABLE :
DPRINT("DRV_DISABLE\n");
DisableKernelInterface();
return TRUE;
/*
We don't actually support configuration or installation, so these
could probably be safely pruned.
*/
case DRV_QUERYCONFIGURE :
DPRINT("DRV_QUERYCONFIGURE\n");
return FALSE;
case DRV_CONFIGURE :
DPRINT("DRV_CONFIGURE\n");
return FALSE;
case DRV_INSTALL :
DPRINT("DRV_INSTALL\n");
return TRUE; /* ok? */
case DRV_REMOVE :
DPRINT("DRV_REMOVE\n");
return TRUE;
default :
DPRINT("?\n");
return DefDriverProc(DriverID, DriverHandle, Message, Param1, Param2);
};
}
void NotifyClient(
PWDMAUD_DEVICE_INFO device,
DWORD message,
DWORD p1,
DWORD p2
)
{
DPRINT("Calling client\n");
DriverCallback(device->client_callback,
HIWORD(device->flags),
(HDRVR) device->handle,
message,
device->client_instance,
0,
0);
}
APIENTRY DWORD widMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2
)
{
DPRINT("widMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("WIDM_INIT\n");
return AddWaveInDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("WIDM_EXIT\n");
return RemoveWaveInDevice((WCHAR*) p2); /* FIXME */
case WIDM_GETNUMDEVS :
DPRINT("WIDM_GETNUMDEVS\n");
return GetWaveInCount((WCHAR*) p1);
case WIDM_GETDEVCAPS :
DPRINT("WIDM_GETDEVCAPS\n");
return GetWaveInCapabilities(id, (WCHAR*) p2, (LPMDEVICECAPSEX) p1);
};
return MMSYSERR_NOERROR;
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD wodMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2)
{
DPRINT("wodMessage %d %d %d %d %d\n",
(int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
/*
* DRVM_INIT
* Parameter 1 : Not used
* Parameter 2 : Topology path
*/
case DRVM_INIT :
DPRINT("DRVM_INIT\n");
return AddWaveOutDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("DRVM_EXIT\n");
return RemoveWaveOutDevice((WCHAR*) p2); /* FIXME? */
/*
* WODM_GETNUMDEVS
* Parameter 1 : Topology device path
* Parameter 2 : Not used
*/
case WODM_GETNUMDEVS :
DPRINT("WODM_GETNUMDEVS\n");
return GetWaveOutCount((WCHAR*) p1);
/*
* WODM_GETDEVCAPS
* Parameter 1 : Pointer to a MDEVICECAPS struct
* Parameter 2 : Device path
*/
case WODM_GETDEVCAPS :
DPRINT("WODM_GETDEVCAPS\n");
return GetWaveOutCapabilities(id, (WCHAR*) p2, (LPMDEVICECAPSEX) p1);
/*
* WODM_OPEN
* Parameter 1 : Pointer to a WAVEOPENDESC struct (the dnDevNode
* member holds a device path.)
* Parameter 2 : Flags
*/
case WODM_OPEN :
DPRINT("WODM_OPEN\n");
return OpenWaveOutDevice(id,
(LPWAVEOPENDESC) p1,
p2,
(PWDMAUD_DEVICE_INFO*) user);
case WODM_CLOSE :
DPRINT("WODM_CLOSE\n");
return CloseWaveDevice((PWDMAUD_DEVICE_INFO) user);
case WODM_PREPARE :
DPRINT("WODM_PREPARE\n");
return PrepareWaveHeader((PWDMAUD_DEVICE_INFO) user,
(PWAVEHDR) p1);
case WODM_UNPREPARE :
DPRINT("WODM_UNPREPARE\n");
return UnprepareWaveHeader((PWAVEHDR) p1);
case WODM_WRITE :
DPRINT("WODM_WRITE\n");
return WriteWaveData((PWDMAUD_DEVICE_INFO) user,
(PWAVEHDR) p1);
}
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD midMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2
)
{
DPRINT("midMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("MIDM_INIT\n");
return AddMidiInDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("MIDM_EXIT\n");
return RemoveMidiInDevice((WCHAR*) p2); /* FIXME */
case MIDM_GETNUMDEVS :
DPRINT("MIDM_GETNUMDEVS\n");
return GetMidiInCount((WCHAR*) p1);
case MIDM_GETDEVCAPS :
DPRINT("MIDM_GETDEVCAPS\n");
return GetMidiInCapabilities(id, (WCHAR*) p2, (LPMDEVICECAPSEX) p1);
};
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD modMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2
)
{
DPRINT("modMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("MODM_INIT\n");
return AddMidiOutDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("MODM_EXIT\n");
return RemoveMidiOutDevice((WCHAR*) p2); /* FIXME */
case MODM_GETNUMDEVS :
DPRINT("MODM_GETNUMDEVS\n");
return GetMidiOutCount((WCHAR*) p1);
case MODM_GETDEVCAPS :
DPRINT("MODM_GETDEVCAPS\n");
return GetMidiOutCapabilities(id, (WCHAR*) p2, (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");
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD mxdMessage(
DWORD id,
DWORD message,
DWORD user,
DWORD p1,
DWORD p2
)
{
DPRINT("mxdMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("MXDM_INIT\n");
return AddMixerDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("MXDM_EXIT\n");
return RemoveMixerDevice((WCHAR*) p2); /* FIXME */
case MXDM_GETNUMDEVS :
DPRINT("MXDM_GETNUMDEVS\n");
return GetMixerCount((WCHAR*) p1);
case MXDM_GETDEVCAPS :
DPRINT("MXDM_GETDEVCAPS\n");
return GetMixerCapabilities(id, (WCHAR*) p2, (LPMDEVICECAPSEX) p1);
/* ... */
};
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
APIENTRY DWORD auxMessage(DWORD id, DWORD message, DWORD user, DWORD p1, DWORD p2)
{
DPRINT("auxMessage %d %d %d %d %d\n", (int)id, (int)message, (int)user, (int)p1, (int)p2);
switch(message)
{
case DRVM_INIT :
DPRINT("AUXDM_INIT\n");
return AddAuxDevice((WCHAR*) p2);
case DRVM_EXIT :
DPRINT("AUXDM_EXIT\n");
return RemoveAuxDevice((WCHAR*) p2); /* FIXME */
case AUXDM_GETNUMDEVS :
DPRINT("AUXDM_GETNUMDEVS\n");
return GetAuxCount((WCHAR*) p1);
case AUXDM_GETDEVCAPS :
DPRINT("AUXDM_GETDEVCAPS\n");
return GetAuxCapabilities(id, (WCHAR*) p2, (LPMDEVICECAPSEX) p1);
/* ... */
};
DPRINT("* NOT IMPLEMENTED *\n");
return MMSYSERR_NOTSUPPORTED;
}
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved)
{
DPRINT("DllMain called!\n");
if (Reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hInstance);
}
else if (Reason == DLL_PROCESS_DETACH)
{
DPRINT("*** wdmaud.drv is being closed ***\n");
ReportMem();
}
return TRUE;
}
/* EOF */
-723
View File
@@ -1,723 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/wave.c
* PURPOSE: WDM Audio Support - Wave Device / Header Manipulation
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 18, 2005: Created
*/
#include <windows.h>
#include "wdmaud.h"
const char WAVE_PREPARE_DATA_SIG[4] = "WPPD";
/*
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 :
First, check to see if we can write to the buffer given to us. Fail
if we can't (invalid parameter?)
Make sure the signature matches "WPPD". Fail if not (invalid param?)
Finally, validate the "overlapped" member, by checking to see if
that buffer is writable, and ensuring hEvent is non-NULL.
*/
MMRESULT ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data)
{
/* UNIMPLEMENTED */
return MMSYSERR_NOERROR;
}
/*
ValidateWaveHeader
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.
Returns MMSYSERR_NOERROR if all's well, or MMSYSERR_INVALPARAM if not.
*/
MMRESULT ValidateWaveHeader(PWAVEHDR header)
{
DWORD flag_check;
if ( IsBadWritePtr(header, sizeof(WAVEHDR)) )
{
DPRINT1("Bad write pointer\n");
return MMSYSERR_INVALPARAM;
}
flag_check = header->dwFlags & 0xffffffe0; /* FIXME: Use flag names */
if ( flag_check )
{
DPRINT1("Unknown flags present\n");
return MMSYSERR_INVALPARAM;
}
return ValidateWavePreparationData(
(PWDMAUD_WAVE_PREPARATION_DATA) header->reserved);
}
/*
PrepareWaveHeader
Checks the parameters are sane, allocates memory for a WAVEPREPAREDATA
structure and also memory for an OVERLAPPED structure.
After this, an un-named event is created (as hEvent of the OVERLAPPED)
structure, and the WAVEPREPAREDATA structure has its signature set
accordingly.
Returns MMSYSERR_NOTSUPPORTED so that winmm does further processing.
*/
MMRESULT PrepareWaveHeader(
PWDMAUD_DEVICE_INFO device,
PWAVEHDR header
)
{
MMRESULT result = MMSYSERR_ERROR;
PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL;
DPRINT("PrepareWaveHeader called\n");
/* Check the device data is valid */
result = ValidateDeviceData(device, TRUE);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad device info or device state\n");
return result;
}
/* Make sure we were actually given a header to process */
if ( ! header )
{
DPRINT1("Bad header\n");
return MMSYSERR_INVALPARAM;
}
/* NOTE: At this point, what happens if not prepared or already queued? */
header->lpNext = NULL;
header->reserved = 0;
/* Allocate memory for the wave preparation data */
prep_data =
(PWDMAUD_WAVE_PREPARATION_DATA)
AllocMem(sizeof(WDMAUD_WAVE_PREPARATION_DATA));
if ( ! prep_data )
{
DPRINT1("Couldn't lock global memory for preparation data (error %d)\n",
(int)GetLastError());
result = MMSYSERR_NOMEM;
goto fail;
}
/* Create an event */
prep_data->overlapped = AllocMem(sizeof(OVERLAPPED));
if ( ! prep_data->overlapped )
{
DPRINT1("Couldn't allocate memory for overlapped structure (error %d)\n",
(int)GetLastError());
result = MMSYSERR_NOMEM;
goto fail;
}
prep_data->overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if ( ! prep_data->overlapped->hEvent )
{
DPRINT1("Creation of overlapped event failed (error %d)\n",
(int)GetLastError());
result = MMSYSERR_NOMEM;
goto fail;
}
/* Copy the signature over and tie the prepare structure to the wave header */
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 ( prep_data )
{
if ( prep_data->overlapped )
{
if ( prep_data->overlapped->hEvent )
CloseHandle(prep_data->overlapped->hEvent); /* ok? */
FreeMem(prep_data->overlapped);
}
FreeMem(prep_data);
}
return result;
}
}
/*
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)
{
MMRESULT result = MMSYSERR_ERROR;
PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL;
DPRINT("UnprepareHeader called\n");
/* Make sure we were actually given a header to process */
if ( ! header )
{
DPRINT1("Bad header supplied\n");
return MMSYSERR_INVALPARAM;
}
prep_data = (PWDMAUD_WAVE_PREPARATION_DATA) header->reserved;
result = ValidateWavePreparationData(prep_data);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad wave header preparation structure pointer\n");
return result;
}
/* We're about to free the preparation structure, so this needs to go */
header->reserved = 0;
/* Kill the event */
CloseHandle(prep_data->overlapped->hEvent);
FreeMem(prep_data->overlapped);
/* Overwrite the signature (structure will be invalid from now on) */
ZeroMemory(prep_data->signature, 4);
FreeMem(prep_data);
/* Always return like this so winmm thinks we didn't do anything */
DPRINT("Header now unprepared.\n");
result = MMSYSERR_NOTSUPPORTED;
return result;
}
/* Not sure about this */
MMRESULT CompleteWaveHeader(PWAVEHDR header)
{
return MMSYSERR_NOTSUPPORTED;
}
/*
SubmitWaveHeader Overview :
This may span 2 functions (this one and and another "SubmitHeader")
First, validate the device info, then the state.
Validate the header, followed by the reserved member.
Fail if INQUEUE flag is set in header, or if PREPARED is not set in
header.
AND the flags with PREPARED, BEGINLOOP, ENDLOOP and INQUEUE. OR the
result with INQUEUE.
Enter the csQueue critical section.
Check if the device state's "open descriptor" member is NULL or not.
If we're adding an extra buffer, it will already have been allocated.
If the open descriptor is NULL:
If it's NULL, set "opendesc" to point to the wave header (?!)
If the state structure's "hevtQueue" member isn't NULL, compare it's
value to 0x43434343h and 0x42424242h. If it's not NULL or one of
those values, set the event.
If the open descriptor is NOT NULL:
Check the header's lpNext member. If it's not NULL, check that
structure's lpNext member, and so on, until a NULL entry is
found.
Set the NULL entry to point to our header.
Leave the csQueue critical section.
** SUBMIT THE HEADER ** TODO **
If submission failed:
AND the flags with 0xFFFFFFEFh. If csQueue is set in the target
(the header who's lpNext was NULL), set it to NULL. Set the open
descriptor of state to NULL, too. And fail, of course.
If the device state is PAUSED or RUNNING, we must fail.
Otherwise, reset the device and set it as RUNNING. This may be done by
our caller (wodMessage, etc.)
0x1d8104 is used for wave in
0x1d8148 is used for wave out?
SetDeviceState should now be called with the above IOCTL code and the
device info structure.
*/
/*
ValidateWriteWaveDataParams
This is just a helper function that shrinks WriteWaveData a little
bit.
*/
static MMRESULT ValidateWriteWaveDataParams(
PWDMAUD_DEVICE_INFO device,
PWAVEHDR header
)
{
MMRESULT result;
result = ValidateWaveHeader(header);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad wave header supplied\n");
return result;
}
/*
We don't want to queue something already queued, and we don't want
to queue something that hasn't been prepared. Who knows what garbage
might be sent to us?!
*/
if ( header->dwFlags & WHDR_INQUEUE )
{
DPRINT1("This header is already queued!\n");
return MMSYSERR_INVALFLAG;
}
if ( ! header->dwFlags & WHDR_PREPARED )
{
DPRINT1("This header isn't prepared!\n");
return WAVERR_UNPREPARED;
}
result = ValidateDeviceData(device, TRUE);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad device info or device state supplied\n");
return result;
}
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; */
/* For the DeviceIoControl later */
DWORD ioctl_code;
DWORD bytes_returned;
DPRINT("WriteWaveHeader called\n");
result = ValidateWriteWaveDataParams(device, header);
if ( result != MMSYSERR_NOERROR )
return result;
/* 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;
result = ValidateWavePreparationData(prep_data);
if ( result != MMSYSERR_NOERROR )
{
DPRINT1("Bad wave preparation structure supplied\n");
return result;
}
DPRINT("Flags == 0x%x\n", (int) header->dwFlags);
/* Mask the "done" flag */
CLEAR_WAVEHDR_FLAG(header, WHDR_DONE);
/* header->dwFlags &= ~WHDR_DONE; */
/* ...and set the queue flag! */
SET_WAVEHDR_FLAG(header, WHDR_INQUEUE);
/* header->dwFlags |= WHDR_INQUEUE; */
DPRINT("Flags == 0x%x\n", (int) header->dwFlags);
EnterCriticalSection(device->state->device_queue_guard);
if ( ! device->state->current_wave_header )
{
DPRINT("Device state wave_header is NULL\n");
device->state->current_wave_header = header;
/* My, what pretty symmetry you have... */
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 ) &&
( (DWORD) device->state->queue_event != MAGIC_43 ) )
{
DPRINT("Setting queue event\n");
SetEvent(device->state->queue_event);
}
}
else
{
DPRINT("Device state open_descriptor is NOT NULL\n");
/* TODO */
ASSERT(FALSE);
}
LeaveCriticalSection(device->state->device_queue_guard);
/* Now we send the header to the kernel device */
if ( ! IsHeaderPrepared(header) )
{
DPRINT1("Unprepared header!\n");
result = MMSYSERR_INVALPARAM;
goto cleanup;
}
/*
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 ;) */
device->ioctl_param1 = sizeof(WAVEHDR);
device->ioctl_param2 = (DWORD) header;
ioctl_code = device->type == WDMAUD_WAVE_IN
? IOCTL_WDMAUD_SUBMIT_WAVE_IN_HDR /* FIXME */
: IOCTL_WDMAUD_SUBMIT_WAVE_OUT_HDR;
/*
FIXME:
For wave input to work, we may need to pass different parameters.
*/
/* We now send the header to the driver */
io_result =
DeviceIoControl(GetKernelInterface(),
ioctl_code,
device,
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2),
device,
sizeof(WDMAUD_DEVICE_INFO),
&bytes_returned, /* ... */
prep_data->overlapped);
DPRINT("Wave header submission result : %d\n", (int) io_result);
if ( io_result != STATUS_SUCCESS )
{
DPRINT1("Wave header submission FAILED! (error %d)\n", (int) io_result);
CLEAR_WAVEHDR_FLAG(header, WHDR_INQUEUE);
device->state->device_queue_guard = NULL;
device->state->current_wave_header = NULL;
return TranslateWinError(io_result);
}
/* CallKernelDevice(clone, ioctl_code, 0x20, (DWORD) header); */
if ( ! CreateCompletionThread(device) )
{
DPRINT1("Couldn't create completion thread\n");
CLEAR_WAVEHDR_FLAG(header, WHDR_INQUEUE);
device->state->device_queue_guard = NULL;
device->state->current_wave_header = NULL;
return MMSYSERR_ERROR; /* Care to be more specific? */
}
/* ***** FIXME ****** THIS IS NASTY HACKERY ****** */
DPRINT("applying hacks\n");
DPRINT("Running %d paused %d\n", (int)device->state->is_running, (int)device->state->is_paused);
#if 1
/* HACK */
DPRINT("%d\n", (int)
DeviceIoControl(GetKernelInterface(),
IOCTL_WDMAUD_WAVE_OUT_START,
device,
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2),
device,
sizeof(WDMAUD_DEVICE_INFO),
&bytes_returned, /* ... */
prep_data->overlapped) );
DPRINT("Running %d paused %d\n", (int)device->state->is_running, (int)device->state->is_paused);
#if 0 /* on error */
DPRINT("%d\n", (int)
DeviceIoControl(GetKernelInterface(),
0x1d8148,
device,
sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2),
device,
sizeof(WDMAUD_DEVICE_INFO),
&bytes_returned, /* ... */
prep_data->overlapped) );
#endif
#endif
result = MMSYSERR_NOERROR;
cleanup :
{
/* TODO */
return result;
}
}
-26
View File
@@ -1,26 +0,0 @@
; $Id: wdmaud.def 12852 2005-01-06 13:58:04Z mf $
;
; wdmaud.def
;
; ReactOS Operating System
;
; Each of the "message" functions can be commented out to stop the
; corresponding device type from being supported. This is mainly so we can
; focus on debugging a particular device type.
;
LIBRARY wdmaud.drv
EXPORTS
; DriverProc is needed so the driver can startup and shutdown
DriverProc@20
; Wave input support
;widMessage@20
; Wave output support
wodMessage@20
; Midi input support
;midMessage@20
; Midi output support
;modMessage@20
; Mixer support
;mxdMessage@20
; Auxiliary device support
;auxMessage@20
-602
View File
@@ -1,602 +0,0 @@
/*
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
* FILE: lib/wdmaud/wdmaud.h
* PURPOSE: WDM Audio Support - Common header
* PROGRAMMER: Andrew Greenwood
* UPDATE HISTORY:
* Nov 12, 2005: Declarations for debugging + interface
*/
#ifndef __WDMAUD_PRIVATE_H__
#define __WDMAUD_PRIVATE_H__
/* Debugging */
/*
Some of this stuff belongs in ksmedia.h or other such global includes.
*/
#include <stdio.h>
#include <debug.h>
#include <ntddk.h>
#include <windows.h>
#include <mmsystem.h>
#include <mmddk.h>
/* HACK! */
#define DbgPrint printf
/*
Handy macros
*/
#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"
/*
Private IOCTLs shared between wdmaud.sys and wdmaud.drv
TO ADD/MODIFY:
IOCTL_WDMAUD_OPEN_PIN
IOCTL_WDMAUD_WAVE_OUT_WRITE_PIN
IOCTL_WDMAUD_WAVE_IN_READ_PIN
IOCTL_WDMAUD_MIXER_CLOSE
IOCTL_WDMAUD_MIXER_OPEN
IOCTL_WDMAUD_MIDI_IN_READ_PIN
IOCTL_WDMAUD_MIXER_GETLINEINFO
IOCTL_WDMAUD_MIXER_GETHARDWAREEVENTDATA
IOCTL_WDMAUD_MIXER_SETCONTROLDETAILS
IOCTL_WDMAUD_MIXER_GETCONTROLDETAILS
IOCTL_WDMAUD_MIXER_GETLINECONTROLS
*/
/* 0x1d8000 */
#define IOCTL_WDMAUD_HELLO \
CTL_CODE(FILE_DEVICE_SOUND, 0x0000, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WDMAUD_ADD_DEVICE 0x1d8004
#define IOCTL_WDMAUD_REMOVE_DEVICE 0x1d8008
#define IOCTL_WDMAUD_GET_CAPABILITIES 0x1d800c
#define IOCTL_WDMAUD_GET_DEVICE_COUNT 0x1d8010
#define IOCTL_WDMAUD_OPEN_DEVICE 0x1d8014
#define IOCTL_WDMAUD_CLOSE_DEVICE 0x1d8018
#define IOCTL_WDMAUD_AUX_GET_VOLUME 0x1d801c
#define IOCTL_WDMAUD_AUX_SET_VOLUME 0x1d8020
/* 0x1d8024 */
#define IOCTL_WDMAUD_GOODBYE \
CTL_CODE(FILE_DEVICE_SOUND, 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_WDMAUD_SET_PREFERRED 0x1d8028
#define IOCTL_WDMAUD_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 /* Already been covered? */
#define IOCTL_WDMAUD_UNKNOWN1 0x1d8118 /* Not used by wdmaud.drv */
#define IOCTL_WDMAUD_SUBMIT_WAVE_OUT_HDR 0x1d811c
#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? */
#define IOCTL_WDMAUD_UNKNOWN2 0x1d8208
#define IOCTL_WDMAUD_MIDI_OUT_LONG_MESSAGE \
0x1d820c
#define IOCTL_WDMAUD_SUBMIT_MIDI_HDR 0x1d8210
#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? */
#define IOCTL_WDMAUD_MIXER_UNKNOWN1 0x1d8310
#define IOCTL_WDMAUD_MIXER_UNKNOWN2 0x1d8314
#define IOCTL_WDMAUD_MIXER_UNKNOWN3 0x1d8318
/*
Device Types
*/
enum
{
WDMAUD_WAVE_IN = 0,
WDMAUD_WAVE_OUT,
WDMAUD_MIDI_IN,
WDMAUD_MIDI_OUT,
WDMAUD_MIXER,
WDMAUD_AUX,
/* For range checking */
WDMAUD_MIN_DEVICE_TYPE = WDMAUD_WAVE_IN,
WDMAUD_MAX_DEVICE_TYPE = WDMAUD_AUX
};
/*
Some macros for device type matching and checking
*/
#define IsWaveInDeviceType(device_type) (device_type == WDMAUD_WAVE_IN)
#define IsWaveOutDeviceType(device_type) (device_type == WDMAUD_WAVE_OUT)
#define IsMidiInDeviceType(device_type) (device_type == WDMAUD_MIDI_IN)
#define IsMidiOutDeviceType(device_type) (device_type == WDMAUD_MIDI_OUT)
#define IsMixerDeviceType(device_type) (device_type == WDMAUD_MIXER)
#define IsAuxDeviceType(device_type) (device_type == WDMAUD_AUX)
#define IsWaveDeviceType(device_type) \
(IsWaveInDeviceType(device_type) || IsWaveOutDeviceType(device_type))
#define IsMidiDeviceType(device_type) \
(IsMidiInDeviceType(device_type) || IsMidiOutDeviceType(device_type))
#define IsValidDeviceType(device_type) \
(device_type >= WDMAUD_MIN_DEVICE_TYPE && \
device_type <= WDMAUD_MAX_DEVICE_TYPE)
/*
The various "caps" (capabilities) structures begin with the same members,
so a generic structure is defined here which can be accessed independently
of a device type.
*/
/*
This is used as a general-purpose structure to retrieve capabilities
from the driver.
*/
typedef struct
{
DWORD cbSize;
LPVOID pCaps;
} MDEVICECAPSEX, *LPMDEVICECAPSEX;
/* Abstraction */
typedef LPVOID PWDMAUD_HEADER;
/*
There are also various "opendesc" structures, but these don't have any
common members. Regardless, this typedef simply serves as a placeholder
to indicate that to access the members, it should be cast accordingly.
TODO: Maybe have a generic OPEN routine that uses this?
*/
typedef struct OPENDESC *LPOPENDESC;
typedef struct
{
DWORD sample_size;
HANDLE thread;
DWORD thread_id;
union
{
LPWAVEHDR current_wave_header;
LPMIDIHDR current_midi_header;
};
DWORD unknown_10; /* pointer to something */
DWORD unknown_14;
LPCRITICAL_SECTION device_queue_guard;
HANDLE queue_event;
HANDLE exit_thread_event;
DWORD unknown_24;
DWORD is_paused;
DWORD is_running;
DWORD unknown_30;
LPVOID midi_buffer; /* for output ? */
DWORD running_status;
char signature[4];
} WDMAUD_DEVICE_STATE, *PWDMAUD_DEVICE_STATE;
typedef struct
{
DWORD next_device;
DWORD id;
DWORD type;
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;
DWORD unknown_44;
DWORD unknown_48;
DWORD unknown_4C;
DWORD unknown_50;
DWORD beef;
PWDMAUD_DEVICE_STATE state;
char signature[4];
WCHAR path[1];
} WDMAUD_DEVICE_INFO, *PWDMAUD_DEVICE_INFO;
typedef struct
{
PWDMAUD_DEVICE_INFO offspring; /* not sure about this */
LPOVERLAPPED overlapped;
char signature[4];
} WDMAUD_WAVE_PREPARATION_DATA, *PWDMAUD_WAVE_PREPARATION_DATA;
/* Ugh... */
typedef struct
{
DWORD cbSize; /* Maybe? */
} WDMAUD_CAPS, *PWDMAUD_CAPS;
/*
Not quite sure what these are/do yet
*/
#define MAGIC_42 0x42424242 /* Queue critical section */
#define MAGIC_43 0x43434343 /* Queue critical section */
#define MAGIC_48 0x48484848 /* Exit-thread event */
#define IsQueueMagic(test_value) \
( ( (DWORD)test_value == MAGIC_42 ) || ( (DWORD)test_value == MAGIC_43) )
/*
This should eventually be removed, but is used so we can be nosey and see
what the kernel-mode wdmaud.sys is doing with our structures!
*/
#ifdef DUMP_WDMAUD_STRUCTURES
#define DUMP_MEMBER(struct, member) \
DPRINT("%s : %d [0x%x]\n", #member, (int) struct->member, (int) struct->member);
#define DUMP_WDMAUD_DEVICE_INFO(info) \
{ \
DPRINT("-- %s --\n", #info); \
DUMP_MEMBER(info, unknown_00); \
DUMP_MEMBER(info, id); \
DUMP_MEMBER(info, type); \
DUMP_MEMBER(info, wave_handle); \
DUMP_MEMBER(info, client_instance); \
DUMP_MEMBER(info, client_callback); \
DUMP_MEMBER(info, unknown_18); \
DUMP_MEMBER(info, flags); \
DUMP_MEMBER(info, ioctl_param2); \
DUMP_MEMBER(info, ioctl_param1); \
DUMP_MEMBER(info, with_critical_section); \
DUMP_MEMBER(info, string_2c); \
DUMP_MEMBER(info, unknown_30); \
DUMP_MEMBER(info, playing_notes); \
DUMP_MEMBER(info, unknown_38); \
DUMP_MEMBER(info, unknown_3c); \
DUMP_MEMBER(info, unknown_40); \
DUMP_MEMBER(info, unknown_44); \
DUMP_MEMBER(info, unknown_48); \
DUMP_MEMBER(info, unknown_4C); \
DUMP_MEMBER(info, unknown_50); \
DUMP_MEMBER(info, beef); \
DUMP_MEMBER(info, state); \
DUMP_MEMBER(info, signature); \
}
#else
#define DUMP_MEMBER(struct, member)
#define DUMP_WDMAUD_DEVICE_INFO(info)
#endif
/* Helper (helper.c) funcs */
MMRESULT TranslateWinError(DWORD error);
#define GetLastMmError() TranslateWinError(GetLastError());
/* user.c */
void
NotifyClient(
PWDMAUD_DEVICE_INFO device,
DWORD message,
DWORD p1,
DWORD p2
);
/* kernel.c */
BOOL
EnableKernelInterface();
BOOL
DisableKernelInterface();
HANDLE
GetKernelInterface();
MMRESULT
CallKernelDevice(
PWDMAUD_DEVICE_INFO device,
DWORD ioctl_code,
DWORD param1,
DWORD param2);
/* devices.c */
BOOL
IsValidDevicePath(WCHAR* path);
MMRESULT
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);
/* mixer ... */
MMRESULT ModifyDevicePresence(
CHAR device_type,
WCHAR* device_path,
BOOL adding);
#define AddDevice(device_type, device_path) \
ModifyDevicePresence(device_type, device_path, TRUE)
#define AddWaveInDevice(device_path) \
AddDevice(WDMAUD_WAVE_IN, device_path)
#define AddWaveOutDevice(device_path) \
AddDevice(WDMAUD_WAVE_OUT, device_path)
#define AddMidiInDevice(device_path) \
AddDevice(WDMAUD_MIDI_IN, device_path)
#define AddMidiOutDevice(device_path) \
AddDevice(WDMAUD_MIDI_OUT, device_path)
#define AddMixerDevice(device_path) \
AddDevice(WDMAUD_MIXER, device_path)
#define AddAuxDevice(device_path) \
AddDevice(WDMAUD_AUX, device_path)
#define RemoveDevice(device_type, device_path) \
ModifyDevicePresence(device_type, device_path, FALSE)
#define RemoveWaveInDevice(device_path) \
RemoveDevice(WDMAUD_WAVE_IN, device_path)
#define RemoveWaveOutDevice(device_path) \
RemoveDevice(WDMAUD_WAVE_OUT, device_path)
#define RemoveMidiInDevice(device_path) \
RemoveDevice(WDMAUD_MIDI_IN, device_path)
#define RemoveMidiOutDevice(device_path) \
RemoveDevice(WDMAUD_MIDI_OUT, device_path)
#define RemoveMixerDevice(device_path) \
RemoveDevice(WDMAUD_MIXER, device_path)
#define RemoveAuxDevice(device_path) \
RemoveDevice(WDMAUD_AUX, device_path)
DWORD
GetDeviceCount(CHAR device_type, WCHAR* device_path);
#define GetWaveInCount(device_path) GetDeviceCount(WDMAUD_WAVE_IN, device_path)
#define GetWaveOutCount(device_path) GetDeviceCount(WDMAUD_WAVE_OUT, device_path)
#define GetMidiInCount(device_path) GetDeviceCount(WDMAUD_MIDI_IN, device_path)
#define GetMidiOutCount(device_path) GetDeviceCount(WDMAUD_MIDI_OUT, device_path)
#define GetMixerCount(device_path) GetDeviceCount(WDMAUD_MIXER, device_path)
#define GetAuxCount(device_path) GetDeviceCount(WDMAUD_AUX, device_path)
MMRESULT
GetDeviceCapabilities(
CHAR device_type,
DWORD device_id,
WCHAR* device_path,
LPMDEVICECAPSEX caps
);
#define GetWaveInCapabilities(id, device_path, caps) \
GetDeviceCapabilities(WDMAUD_WAVE_IN, id, device_path, caps);
#define GetWaveOutCapabilities(id, device_path, caps) \
GetDeviceCapabilities(WDMAUD_WAVE_OUT, id, device_path, caps);
#define GetMidiInCapabilities(id, device_path, caps) \
GetDeviceCapabilities(WDMAUD_MIDI_IN, id, device_path, caps);
#define GetMidiOutCapabilities(id, device_path, caps) \
GetDeviceCapabilities(WDMAUD_MIDI_OUT, id, device_path, caps);
#define GetMixerCapabilities(id, device_path, caps) \
GetDeviceCapabilities(WDMAUD_MIXER, id, device_path, caps);
#define GetAuxCapabilities(id, device_path, caps) \
GetDeviceCapabilities(WDMAUD_AUX, id, device_path, caps);
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
);
#endif
#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
CloseWaveDevice(
PWDMAUD_DEVICE_INFO device
);
#define SET_WAVEHDR_FLAG(header, flag) \
header->dwFlags |= flag
#define CLEAR_WAVEHDR_FLAG(header, flag) \
header->dwFlags &= ~flag
#define IS_WAVEHDR_FLAG_SET(header, flag) \
( header->dwFlags & flag )
MMRESULT
ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data);
MMRESULT
ValidateWaveHeader(PWAVEHDR header);
MMRESULT
PrepareWaveHeader(
PWDMAUD_DEVICE_INFO device,
PWAVEHDR header
);
MMRESULT
UnprepareWaveHeader(PWAVEHDR header);
#define IsHeaderPrepared(header) \
( header->reserved != 0 )
MMRESULT
CompleteWaveHeader(PWAVEHDR header);
MMRESULT
WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header);
/* 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);
/* threads.c */
BOOL CreateCompletionThread(PWDMAUD_DEVICE_INFO device);
/* MORE... */
/*
DEBUGGING + RESOURCE TRACKING
*/
LPVOID AllocMem(DWORD size);
VOID FreeMem(LPVOID pointer);
VOID ReportMem();
#define AutoAlloc(type) \
(type*) MemAlloc(sizeof(type));
#endif
-22
View File
@@ -1,22 +0,0 @@
<module name="wdmaud" type="win32dll" extension=".drv" baseaddress="${BASEADDRESS_WDMAUD}" installbase="system32" installname="wdmaud.drv">
<importlibrary definition="wdmaud.def" />
<include base="wdmaud">.</include>
<define name="__USE_W32API" />
<define name="_DISABLE_TIDENTS" />
<define name="UNICODE" />
<define name="_UNICODE" />
<define name="__REACTOS__" />
<library>ntdll</library>
<library>kernel32</library>
<library>winmm</library>
<library>setupapi</library>
<file>user.c</file>
<file>kernel.c</file>
<file>devices.c</file>
<file>midi.c</file>
<file>wave.c</file>
<file>threads.c</file>
<file>helper.c</file>
<file>memtrack.c</file>
<file>wdmaud.rc</file>
</module>
-5
View File
@@ -1,5 +0,0 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "WDM Audio System (Legacy Support)\0"
#define REACTOS_STR_INTERNAL_NAME "wdmaud\0"
#define REACTOS_STR_ORIGINAL_FILENAME "wdmaud.drv\0"
#include <reactos/version.rc>