📄 devices.c
字号:
/*
*
* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -