⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devices.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *
 * 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 + -