Replace .def file by a .spec file

svn path=/trunk/; revision=35209
This commit is contained in:
Hervé Poussineau 2008-08-09 08:09:40 +00:00
parent ce5c619db0
commit 389c99370d
10 changed files with 1048 additions and 1055 deletions

View file

@ -1,258 +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;
}
/*
*
* 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;
}

View file

@ -22,7 +22,7 @@
In summary, we just implement to satisfy the MME API (winmm) requirements.
*/
LONG
LONG WINAPI
DriverProc(
DWORD driver_id,
HANDLE driver_handle,

View file

@ -1,206 +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;
}
/*
*
* 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;
}

View file

@ -1,14 +0,0 @@
; $Id$
;
; mmdrv.def
;
; ReactOS Operating System
;
LIBRARY mmdrv.dll
EXPORTS
DriverProc@20
;widMessage@20
wodMessage@20
;midMessage@20
;modMessage@20
;auxMessage@20

View file

@ -1,5 +1,5 @@
<module name="mmdrv" type="win32dll" baseaddress="${BASEADDRESS_MMDRV}" installbase="system32" installname="mmdrv.dll" unicode="yes">
<importlibrary definition="mmdrv.def" />
<importlibrary definition="mmdrv.spec.def" />
<include base="mmdrv">.</include>
<define name="NDEBUG" />
<library>ntdll</library>
@ -13,4 +13,5 @@
<file>common.c</file>
<file>wave.c</file>
<file>wave_io.c</file>
<file>mmdrv.spec</file>
</module>

View file

@ -0,0 +1,6 @@
@ stdcall DriverProc(long ptr long long long)
;@ stdcall widMessage(long long long long long)
@ stdcall wodMessage(long long long long long)
;@ stdcall midMessage(long long long long long)
;@ stdcall modMessage(long long long long long)
;@ stdcall auxMessage(long long long long long)

View file

@ -1,143 +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;
}
/*
*
* 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;
}

View file

@ -1,147 +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
/*
*
* 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

View file

@ -1,245 +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);
}
/*
*
* 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);
}

View file

@ -1,40 +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)
{
}
/*
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)
{
}