/*++

Copyright (c) Microsoft Corporation

Module Name:

    FxResourceAPI.cpp

Abstract:

    This module implements the resource class.

Author:




Environment:

    Both kernel and user mode

Revision History:

--*/
#include "fxsupportpch.hpp"

extern "C" {
// #include "FxResourceAPI.tmh"
}

//
// Extern "C" the entire file
//
extern "C" {

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfIoResourceRequirementsListSetSlotNumber)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in
    ULONG SlotNumber
    )
/*++

Routine Description:
    Sets the slot number for a given resource requirements list

Arguments:
    RequirementsList - list to be modified

    SlotNumber - slot value to assign

Return Value:
    None

  --*/
{
    FxIoResReqList* pIoResReqList;

    FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
                         RequirementsList,
                         FX_TYPE_IO_RES_REQ_LIST,
                         (PVOID*) &pIoResReqList);

    if (pIoResReqList->m_SlotNumber != SlotNumber) {
        pIoResReqList->MarkChanged();
    }
    pIoResReqList->m_SlotNumber = SlotNumber;
}

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfIoResourceRequirementsListSetInterfaceType)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in
    __drv_strictTypeMatch(__drv_typeCond)
    INTERFACE_TYPE InterfaceType
    )
/*++

Routine Description:
    Sets the InterfaceType for a given resource requirements list

Arguments:
    RequirementsList - list to be modified

    InterfaceType - interface type to assign

Return Value:
    None

  --*/
{
    FxIoResReqList* pIoResReqList;

    FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
                         RequirementsList,
                         FX_TYPE_IO_RES_REQ_LIST,
                         (PVOID*) &pIoResReqList);

    if (pIoResReqList->m_InterfaceType != InterfaceType) {
        pIoResReqList->MarkChanged();
    }

    pIoResReqList->m_InterfaceType = InterfaceType;
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
FxIoResourceRequirementsListInsertIoResList(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in
    WDFIORESLIST IoResList,
    ULONG Index
    )
/*++

Routine Description:
    Inserts a resource list into a requirements list at a particular index.

Arguments:
    RequirementsList - list to be modified

    IoResList - resource list to add

    Index - zero based index to insert at

Return Value:
    NTSTATUS

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxIoResReqList* pIoResReqList;
    FxIoResList* pIoResList;
    NTSTATUS status;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   RequirementsList,
                                   FX_TYPE_IO_RES_REQ_LIST,
                                   (PVOID*) &pIoResReqList,
                                   &pFxDriverGlobals);

    FxObjectHandleGetPtr(pFxDriverGlobals,
                         IoResList,
                         FX_TYPE_IO_RES_LIST,
                         (PVOID*) &pIoResList);

    if (pIoResList->m_OwningList != pIoResReqList) {
        return STATUS_INVALID_DEVICE_REQUEST;
    }

    status = pIoResReqList->AddAt(Index, pIoResList);

    if (NT_SUCCESS(status)) {
        //
        // Mirror the access flags as well.
        //
        pIoResList->m_AccessFlags = pIoResReqList->m_AccessFlags;
        pIoResList->m_OwningList = pIoResReqList;
    }

    return status;
}


_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
STDCALL
WDFEXPORT(WdfIoResourceRequirementsListInsertIoResList)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in
    WDFIORESLIST IoResList,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Inserts a resource list into a requirements list at a particular index.

Arguments:
    RequirementsList - list to be modified

    IoResList - resource list to add

    Index - zero based index to insert at

Return Value:
    NTSTATUS

  --*/
{
    return FxIoResourceRequirementsListInsertIoResList(DriverGlobals,
                                                       RequirementsList,
                                                       IoResList,
                                                       Index);
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
STDCALL
WDFEXPORT(WdfIoResourceRequirementsListAppendIoResList)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in
    WDFIORESLIST IoResList
    )
/*++

Routine Description:
   Appends a resource list to a resource requirements list

Arguments:
    RequirementsList - list to be modified

    IoResList - resource list to append

Return Value:
    NTSTATUS

  --*/

{
    return FxIoResourceRequirementsListInsertIoResList(DriverGlobals,
                                                       RequirementsList,
                                                       IoResList,
                                                       WDF_INSERT_AT_END);
}


__drv_maxIRQL(DISPATCH_LEVEL)
ULONG
STDCALL
WDFEXPORT(WdfIoResourceRequirementsListGetCount)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList
    )
/*++

Routine Description:
    Returns the number of resource lists in the requirements list


Arguments:
    RequirementsList - requirements list whose count will be returned

Return Value:
    number of elements in the list

  --*/

{
    FxIoResReqList* pList;
    ULONG count;
    KIRQL irql;

    FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
                         RequirementsList,
                         FX_TYPE_IO_RES_REQ_LIST,
                         (PVOID*) &pList);

    pList->Lock(&irql);
    count = pList->Count();
    pList->Unlock(irql);

    return count;
}

__drv_maxIRQL(DISPATCH_LEVEL)
WDFIORESLIST
STDCALL
WDFEXPORT(WdfIoResourceRequirementsListGetIoResList)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Retrieves a resource list from the requirements list at a given index.

Arguments:
    RequirementsList - list to retrieve the resource list from

    Index - zero based index from which to retrieve the list

Return Value:
    resource list handle or NULL

  --*/
{
    FxIoResReqList* pIoResReqList;
    FxObject* pObject;
    KIRQL irql;

    FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
                         RequirementsList,
                         FX_TYPE_IO_RES_REQ_LIST,
                         (PVOID*) &pIoResReqList);

    pIoResReqList->Lock(&irql);
    pObject = pIoResReqList->GetItem(Index);
    pIoResReqList->Unlock(irql);

    if (pObject == NULL) {
        return NULL;
    }
    else {
        return (WDFIORESLIST) pObject->GetObjectHandle();
    }
}

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfIoResourceRequirementsListRemove)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Removes a resource list from the requirements list at a given index

Arguments:
    RequirementsList - list of resource requirements which will be modified

    Index - zero based index which indictes location in the list to find the
            resource list

Return Value:
    None

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxIoResReqList* pList;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   RequirementsList,
                                   FX_TYPE_IO_RES_REQ_LIST,
                                   (PVOID*) &pList,
                                   &pFxDriverGlobals);

    if (pList->RemoveAndDelete(Index) == FALSE) {
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
            "WDFIORESLIST %p, could not remove list at index %d (not found), "
            "list item count is %d", RequirementsList, Index, pList->Count());

        FxVerifierDbgBreakPoint(pFxDriverGlobals);
    }
}

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfIoResourceRequirementsListRemoveByIoResList)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in
    WDFIORESLIST IoResList
    )
/*++

Routine Description:
    Removes a resource list from the requirements list based on the resource list's
    handle

Arguments:
    RequirementsList - resource requirements list being modified

    IoResList - resource list to be removed

Return Value:
    None

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxCollectionEntry* cur, *end;
    FxIoResReqList* pList;
    FxIoResList* pResList;
    KIRQL irql;
    BOOLEAN listFound;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   RequirementsList,
                                   FX_TYPE_IO_RES_REQ_LIST,
                                   (PVOID*) &pList,
                                   &pFxDriverGlobals);

    if (pList->IsRemoveAllowed() == FALSE) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
                            "WDFIORESREQLIST %p: Removes not allowed",
                            RequirementsList);

        FxVerifierDbgBreakPoint(pFxDriverGlobals);
        return;
    }

    FxObjectHandleGetPtr(pFxDriverGlobals,
                         IoResList,
                         FX_TYPE_IO_RES_LIST,
                         (PVOID*) &pResList);

    pList->Lock(&irql);

    cur = pList->Start();
    end = pList->End();
    listFound = FALSE;

    while (cur != end) {
        if (cur->m_Object == pResList) {
            pList->MarkChanged();

            pList->RemoveEntry(cur);
            listFound = TRUE;
            break;
        }

        cur = cur->Next();
    }

    pList->Unlock(irql);

    if (listFound) {
        pResList->DeleteObject();
        pResList = NULL;
    }
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
STDCALL
WDFEXPORT(WdfIoResourceListCreate)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESREQLIST RequirementsList,
    __in_opt
    PWDF_OBJECT_ATTRIBUTES Attributes,
    __out
    WDFIORESLIST* ResourceList
    )
/*++

Routine Description:
   Creates a resource list.

Arguments:
    RequirementsList - the resource requirements list that the resource list will
                       be associated with

    Attributes - generic object attributes for the new resource list

    ResourceList - pointer which will receive the new object handle

Return Value:
    NTSTATUS

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxIoResReqList* pIoResReqList;
    FxIoResList* pIoResList;
    NTSTATUS status;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   RequirementsList,
                                   FX_TYPE_IO_RES_REQ_LIST,
                                   (PVOID*) &pIoResReqList,
                                   &pFxDriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, ResourceList);
    *ResourceList = NULL;

    status = FxValidateObjectAttributes(pFxDriverGlobals,
                                        Attributes,
                                        FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED);

    if (!NT_SUCCESS(status)) {
        return status;
    }

    pIoResList = new (pFxDriverGlobals, Attributes) FxIoResList(
        pFxDriverGlobals, pIoResReqList);

    if (pIoResList == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    status = pIoResList->Commit(Attributes,
                                (WDFOBJECT*) ResourceList,
                                pIoResReqList);

    if (!NT_SUCCESS(status)) {
        pIoResList->DeleteFromFailedCreate();
    }

    return status;
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
FxIoResourceListInsertDescriptor(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESLIST ResourceList,
    __in
    PIO_RESOURCE_DESCRIPTOR Descriptor,
    ULONG Index
    )
/*++

Routine Description:
    Inserts a descriptor into a resource list at a particular index.

Arguments:
    ResourceList - list to be modified

    Descriptor - descriptor to insert

    Index - zero based index to insert at

Return Value:
    NTSTATUS

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxIoResList* pList;
    FxResourceIo* pObject;
    NTSTATUS status;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   ResourceList,
                                   FX_TYPE_IO_RES_LIST,
                                   (PVOID*) &pList,
                                   &pFxDriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, Descriptor);

    if (pList->m_OwningList->IsAddAllowed() == FALSE) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
                            "Removes not allowed on WDFIORESLIST %p",
                            ResourceList);
        FxVerifierDbgBreakPoint(pFxDriverGlobals);
        return STATUS_ACCESS_DENIED;
    }

    pObject = new(pFxDriverGlobals)
        FxResourceIo(pFxDriverGlobals, Descriptor);

    if (pObject == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    status = pObject->AssignParentObject(pList);
    if (!NT_SUCCESS(status)) {
        pObject->DeleteObject();
        return status;
    }

    status = pList->AddAt(Index, pObject);

    //
    // Mark both this list and its owning list as changed so when it comes
    // time to evaluate the entire requirements list for changes, we do not
    // have to iterate over all the resource lists.
    //
    if (NT_SUCCESS(status)) {
        pList->m_OwningList->MarkChanged();
    }

    return status;
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
STDCALL
WDFEXPORT(WdfIoResourceListInsertDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESLIST ResourceList,
    __in
    PIO_RESOURCE_DESCRIPTOR Descriptor,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Inserts a descriptor into a resource list at a particular index.

Arguments:
    ResourceList - list to be modified

    Descriptor - descriptor to insert

    Index - zero based index to insert at

Return Value:
    NTSTATUS

  --*/
{
    return FxIoResourceListInsertDescriptor(DriverGlobals,
                                            ResourceList,
                                            Descriptor,
                                            Index);
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
STDCALL
WDFEXPORT(WdfIoResourceListAppendDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESLIST ResourceList,
    __in
    PIO_RESOURCE_DESCRIPTOR Descriptor
    )
/*++

Routine Description:
   Appends a descriptor to a resource list

Arguments:
    ResourceList - list to be modified

    Descriptor - item to be appended

Return Value:
    NTSTATUS

  --*/
{
    return FxIoResourceListInsertDescriptor(DriverGlobals,
                                            ResourceList,
                                            Descriptor,
                                            WDF_INSERT_AT_END);
}

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfIoResourceListUpdateDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESLIST ResourceList,
    __in
    PIO_RESOURCE_DESCRIPTOR Descriptor,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Updates resource requirement in place in the list.

Arguments:
    ResourceList - list to be modified

    Descriptor - Pointer to descriptor whic contains the updated value

    Index - zero based location in the list to update

Return Value:
    None

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxIoResList* pList;
    FxResourceIo* pObject;
    KIRQL irql;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   ResourceList,
                                   FX_TYPE_IO_RES_LIST,
                                   (PVOID*) &pList,
                                   &pFxDriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, Descriptor);

    pList->Lock(&irql);
    pObject = (FxResourceIo*) pList->GetItem(Index);
    pList->Unlock(irql);

    if (pObject != NULL) {
        //
        // We don't check for add or remove access because we don't know what
        // the update is actually doing (ie widening a range, shortening it, etc).
        // For this operation we have to trust the driver that it is doing the
        // right thing at the right time.
        //
        RtlCopyMemory(&pObject->m_Descriptor,
                      Descriptor,
                      sizeof(pObject->m_Descriptor));

        //
        // Mark both this list and its owning list as changed so when it comes
        // time to evaluate the entire requirements list for changes, we do not
        // have to iterate over all the resource lists.
        //
        pList->MarkChanged();
        pList->m_OwningList->MarkChanged();
    }
    else {
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
            "WDFIORESREQLIST %p, cannot update item at index %d, item not found,"
            " list item count is %d", ResourceList, Index, pList->Count());

        FxVerifierDbgBreakPoint(pFxDriverGlobals);
    }
}

__drv_maxIRQL(DISPATCH_LEVEL)
ULONG
STDCALL
WDFEXPORT(WdfIoResourceListGetCount)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESLIST ResourceList
    )
/*++

Routine Description:
    Returns the number of descriptors in the resource list

Arguments:
    ResourceList - resource list whose count will be returned

Return Value:
    number of elements in the list

  --*/
{
    FxIoResList* pList;
    ULONG count;
    KIRQL irql;

    FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
                         ResourceList,
                         FX_TYPE_IO_RES_LIST,
                         (PVOID*) &pList);

    pList->Lock(&irql);
    count = pList->Count();
    pList->Unlock(irql);

    return count;
}


__drv_maxIRQL(DISPATCH_LEVEL)
PIO_RESOURCE_DESCRIPTOR
STDCALL
WDFEXPORT(WdfIoResourceListGetDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESLIST ResourceList,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Retrieves an io resource desciptor for a given index in the resource list

Arguments:
    ResourceList - list being looked up

    Index - zero based index into the list to find the value of

Return Value:
    pointer to an io resource descriptor upon success, NULL upon error

  --*/

{
    FxIoResList* pList;
    FxResourceIo* pObject;
    KIRQL irql;

    FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
                         ResourceList,
                         FX_TYPE_IO_RES_LIST,
                         (PVOID*) &pList);

    pList->Lock(&irql);
    pObject = (FxResourceIo*) pList->GetItem(Index);
    pList->Unlock(irql);

    if (pObject == NULL) {
        return NULL;
    }
    else {
        //
        // Copy the current descriptor to the clone and return it
        //
        RtlCopyMemory(&pObject->m_DescriptorClone,
                      &pObject->m_Descriptor,
                      sizeof(pObject->m_Descriptor));

        return &pObject->m_DescriptorClone;
    }
}

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfIoResourceListRemove)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESLIST ResourceList,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Removes a descriptor in an io resource list

Arguments:
    ResourceList - resource list to modify

    Index - zero based index into the list in which to remove the descriptor

Return Value:
    None

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxIoResList* pList;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   ResourceList,
                                   FX_TYPE_IO_RES_LIST,
                                   (PVOID*) &pList,
                                   &pFxDriverGlobals);

    if (pList->RemoveAndDelete(Index)) {
        //
        // Mark this list's owning list as changed so when it comes
        // time to evaluate the entire requirements list for changes, we do not
        // have to iterate over all the resource lists.
        //
        // RemoveAndDelete marked pList as changed already
        //
        pList->m_OwningList->MarkChanged();
    }
    else {
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
            "WDFIORESLIST %p, could not remove item at index %d (not found), "
            "list item count is %d", ResourceList, Index, pList->Count());

        FxVerifierDbgBreakPoint(pFxDriverGlobals);
    }
}

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfIoResourceListRemoveByDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFIORESLIST ResourceList,
    __in
    PIO_RESOURCE_DESCRIPTOR Descriptor
    )
/*++

Routine Description:
    Removes a descriptor by value in a given io resource list.  Equality is
    determined by RtlCompareMemory.

Arguments:
    ResourceList - the io resource list to modify

    Descriptor - pointer to a descriptor to remove.

Return Value:
    None

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxCollectionEntry* cur, *end;
    FxIoResList* pList;
    FxResourceIo* pObject;
    KIRQL irql;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   ResourceList,
                                   FX_TYPE_IO_RES_LIST,
                                   (PVOID*) &pList,
                                   &pFxDriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, Descriptor);

    if (pList->IsRemoveAllowed() == FALSE) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
                            "Removes not allowed on WDFIORESLIST %p",
                            ResourceList);

        FxVerifierDbgBreakPoint(pFxDriverGlobals);
        return;
    }

    pList->Lock(&irql);

    cur = pList->Start();
    end = pList->End();
    pObject = NULL;

    while (cur != end) {
        pObject = (FxResourceIo*) cur->m_Object;

        if (RtlCompareMemory(&pObject->m_Descriptor,
                             Descriptor,
                             sizeof(*Descriptor)) == sizeof(*Descriptor)) {
            //
            // Mark both this list and its owning list as changed so when it
            // comes time to evaluate the entire requirements list for
            // changes, we do not have to iterate over all the resource lists.
            //
            pList->MarkChanged();
            pList->m_OwningList->MarkChanged();

            pList->RemoveEntry(cur);
            break;
        }

        //
        // Set to NULL so that we do not delete it if this is the last item in
        // the list.
        //
        pObject = NULL;

        cur = cur->Next();
    }

    pList->Unlock(irql);

    if (pObject != NULL) {
        pObject->DeleteObject();
    }
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
FxCmResourceListInsertDescriptor(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFCMRESLIST List,
    __in
    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Inserts a descriptor into a cm resource list at a particular index.

Arguments:
    ResourceList - list to be modified

    Descriptor - descriptor to insert

    Index - zero based index to insert at

Return Value:
    NTSTATUS

  --*/
{
    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxCmResList* pList;
    FxResourceCm* pObject;
    NTSTATUS status;

    pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, Descriptor);

    FxObjectHandleGetPtr(pFxDriverGlobals,
                         List,
                         FX_TYPE_CM_RES_LIST,
                         (PVOID*) &pList);

    pObject = new(pFxDriverGlobals) FxResourceCm(pFxDriverGlobals, Descriptor);

    if (pObject == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    status = pObject->AssignParentObject(pList);
    if (!NT_SUCCESS(status)) {
        pObject->DeleteObject();
        return status;
    }

    return pList->AddAt(Index, pObject);
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
STDCALL
WDFEXPORT(WdfCmResourceListInsertDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFCMRESLIST List,
    __in
    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Inserts a descriptor into a cm resource list at a particular index.

Arguments:
    ResourceList - list to be modified

    Descriptor - descriptor to insert

    Index - zero based index to insert at

Return Value:
    NTSTATUS

  --*/
{
    DDI_ENTRY();

    return FxCmResourceListInsertDescriptor(DriverGlobals,
                                            List,
                                            Descriptor,
                                            Index);
}

_Must_inspect_result_
__drv_maxIRQL(DISPATCH_LEVEL)
NTSTATUS
STDCALL
WDFEXPORT(WdfCmResourceListAppendDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFCMRESLIST List,
    __in
    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
    )
/*++

Routine Description:
   Appends a descriptor to a cm resource list

Arguments:
    ResourceList - list to be modified

    Descriptor - item to be appended

Return Value:
    NTSTATUS

  --*/
{
    DDI_ENTRY();

    return FxCmResourceListInsertDescriptor(DriverGlobals,
                                            List,
                                            Descriptor,
                                            WDF_INSERT_AT_END);
}

__drv_maxIRQL(DISPATCH_LEVEL)
ULONG
STDCALL
WDFEXPORT(WdfCmResourceListGetCount)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFCMRESLIST List
    )
/*++

Routine Description:
    Returns the number of cm descriptors in the resource list

Arguments:
    ResourceList - resource list whose count will be returned

Return Value:
    number of elements in the list

  --*/
{
    FxCmResList* pList;

    FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
                         List,
                         FX_TYPE_CM_RES_LIST,
                         (PVOID*) &pList);

    return pList->GetCount();
}


__drv_maxIRQL(DISPATCH_LEVEL)
PCM_PARTIAL_RESOURCE_DESCRIPTOR
STDCALL
WDFEXPORT(WdfCmResourceListGetDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFCMRESLIST List,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Retrieves a cm resource desciptor for a given index in the resource list

Arguments:
    ResourceList - list being looked up

    Index - zero based index into the list to find the value of

Return Value:
    pointer to a cm resource descriptor upon success, NULL upon error

  --*/
{
    DDI_ENTRY();

    FxCmResList* pList;

    FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals),
                         List,
                         FX_TYPE_CM_RES_LIST,
                         (PVOID*) &pList);

    return pList->GetDescriptor(Index);
}

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfCmResourceListRemove)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFCMRESLIST List,
    __in
    ULONG Index
    )
/*++

Routine Description:
    Removes a descriptor in an cm resource list

Arguments:
    ResourceList - resource list to modify

    Index - zero based index into the list in which to remove the descriptor

Return Value:
    None

  --*/
{
    DDI_ENTRY();

    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxCmResList* pList;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   List,
                                   FX_TYPE_CM_RES_LIST,
                                   (PVOID*) &pList,
                                   &pFxDriverGlobals);

    if (pList->RemoveAndDelete(Index) == FALSE) {
        DoTraceLevelMessage(
            pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
            "WDFCMRESLIST %p, could not remove list at index %d (not found), "
            "list item count is %d", List, Index, pList->Count());

        FxVerifierDbgBreakPoint(pFxDriverGlobals);
    }
}

__drv_maxIRQL(DISPATCH_LEVEL)
VOID
STDCALL
WDFEXPORT(WdfCmResourceListRemoveByDescriptor)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFCMRESLIST List,
    __in
    PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
    )
/*++

Routine Description:
    Removes a descriptor by value in a given cm resource list.  Equality is
    determined by RtlCompareMemory.

Arguments:
    ResourceList - the io resource list to modify

    Descriptor - pointer to a descriptor to remove.

Return Value:
    None

  --*/
{
    DDI_ENTRY();

    PFX_DRIVER_GLOBALS pFxDriverGlobals;
    FxCollectionEntry* cur;
    FxCollectionEntry* end;
    FxCmResList* pList;
    FxResourceCm* pObject;
    KIRQL irql;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   List,
                                   FX_TYPE_CM_RES_LIST,
                                   (PVOID*) &pList,
                                   &pFxDriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, Descriptor);

    if (pList->IsRemoveAllowed() == FALSE) {
        DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
                            "Removes not allowed on WDFCMRESLIST %p", List);

        FxVerifierDbgBreakPoint(pFxDriverGlobals);
        return;
    }

    pList->Lock(&irql);

    cur = pList->Start();
    end = pList->End();
    pObject = NULL;

    while (cur != end) {
        pObject = (FxResourceCm*) cur->m_Object;

        if (RtlCompareMemory(&pObject->m_Descriptor,
                             Descriptor,
                             sizeof(*Descriptor)) == sizeof(*Descriptor)) {
            pList->MarkChanged();

            pList->RemoveEntry(cur);
            break;
        }

        //
        // Set to NULL so that we do not delete it if this is the last item in
        // the list.
        //
        pObject = NULL;

        cur = cur->Next();
    }

    pList->Unlock(irql);

    if (pObject != NULL) {
        pObject->DeleteObject();
        pObject = NULL;
    }
}

} // extern "C"