mirror of
https://github.com/reactos/reactos.git
synced 2024-08-21 19:03:01 +00:00
212 lines
4.8 KiB
C
212 lines
4.8 KiB
C
/*
|
|
*
|
|
* 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"
|
|
|
|
#include <winuser.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.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,
|
|
UINT 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,
|
|
UINT 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;
|
|
}
|