mirror of
https://github.com/reactos/reactos.git
synced 2025-01-05 22:12:46 +00:00
1f377076d7
Not all files are included, but these are necessary to compile cdrom driver. So far it can only be statically linked with drivers, a proper implementation requires wdfldr helper driver
739 lines
19 KiB
C++
739 lines
19 KiB
C++
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
FxResourceCollection.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements a base object for derived collection classes and
|
|
the derived collection classes.
|
|
|
|
Author:
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
Both kernel and user mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "fxsupportpch.hpp"
|
|
|
|
extern "C" {
|
|
#if defined(EVENT_TRACING)
|
|
#include "FxResourceCollection.tmh"
|
|
#endif
|
|
}
|
|
|
|
BOOLEAN
|
|
FxResourceCollection::RemoveAndDelete(
|
|
__in ULONG Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Removes an entry from the collection and then deletes it if found. The
|
|
caller must have removal permissions to perform this action.
|
|
|
|
Arguments:
|
|
Index - zero based index into the collection at which to perform the removal
|
|
|
|
Return Value:
|
|
TRUE if the item was found and deleted, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
FxObject* pObject;
|
|
FxCollectionEntry* pEntry;
|
|
KIRQL irql;
|
|
|
|
if (IsRemoveAllowed() == FALSE) {
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"Removes not allowed on handle %p, remove at index %d"
|
|
"failed", GetObjectHandle(), Index);
|
|
|
|
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
|
return FALSE;
|
|
}
|
|
|
|
pObject = NULL;
|
|
|
|
Lock(&irql);
|
|
|
|
pEntry = FindEntry(Index);
|
|
if (pEntry != NULL) {
|
|
|
|
//
|
|
// Mark the list as changed so when we go to create a WDM resource list we
|
|
// know if a new list is needed.
|
|
//
|
|
MarkChanged();
|
|
|
|
pObject = pEntry->m_Object;
|
|
|
|
//
|
|
// Remove the entry
|
|
//
|
|
RemoveEntry(pEntry);
|
|
}
|
|
Unlock(irql);
|
|
|
|
if (pObject != NULL) {
|
|
//
|
|
// Delete the object since we created it
|
|
//
|
|
pObject->DeleteObject();
|
|
pObject = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxResourceCollection::AddAt(
|
|
__in ULONG Index,
|
|
__in FxObject* Object
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Adds an object into the collection at the specified index.
|
|
|
|
Arguments:
|
|
Index - zero baesd index in which to insert into the list. WDF_INSERT_AT_END
|
|
is a special value which indicates that the insertion is an append.
|
|
|
|
Object - object to add
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
FxCollectionEntry *pNew;
|
|
PLIST_ENTRY ple;
|
|
NTSTATUS status;
|
|
KIRQL irql;
|
|
|
|
if (IsAddAllowed() == FALSE) {
|
|
DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"Adds not allowed on handle %p, add at index %d"
|
|
"failed", GetObjectHandle(), Index);
|
|
|
|
FxVerifierDbgBreakPoint(GetDriverGlobals());
|
|
|
|
return STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
Lock(&irql);
|
|
|
|
ple = NULL;
|
|
status = STATUS_SUCCESS;
|
|
|
|
pNew = AllocateEntry(GetDriverGlobals());
|
|
|
|
if (pNew != NULL) {
|
|
//
|
|
// Inserting at the current count (i.e. one past the end) is the same
|
|
// as append.
|
|
//
|
|
if (Index == WDF_INSERT_AT_END || Index == Count()) {
|
|
ple = &m_ListHead;
|
|
}
|
|
else {
|
|
FxCollectionEntry* cur, *end;
|
|
ULONG i;
|
|
|
|
for (cur = Start(), end = End(), i = 0;
|
|
cur != end;
|
|
cur = cur->Next(), i++) {
|
|
if (i == Index) {
|
|
ple = &cur->m_ListEntry;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ple == NULL) {
|
|
delete pNew;
|
|
status = STATUS_ARRAY_BOUNDS_EXCEEDED;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
PLIST_ENTRY blink;
|
|
|
|
// ple now points to the list entry which we will insert our node
|
|
// *before*
|
|
|
|
blink = ple->Blink;
|
|
|
|
// Link the previous with the new entry
|
|
blink->Flink = &pNew->m_ListEntry;
|
|
pNew->m_ListEntry.Blink = blink;
|
|
|
|
// Link the current with the new entry
|
|
pNew->m_ListEntry.Flink = ple;
|
|
ple->Blink = &pNew->m_ListEntry;
|
|
|
|
AddEntry(pNew, Object);
|
|
|
|
//
|
|
// Mark the list as changed so when we go to create a WDM resource list
|
|
// we know if a new list is needed.
|
|
//
|
|
MarkChanged();
|
|
}
|
|
|
|
Unlock(irql);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
Object->DeleteFromFailedCreate();
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxIoResList::BuildFromWdmList(
|
|
__deref_in PIO_RESOURCE_LIST* WdmResourceList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Builds up the collection with FxResourceIo objects based on the passed in
|
|
WDM io resource list
|
|
|
|
Arguments:
|
|
WdmResourceList - list which specifies the io resource objects to create
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PIO_RESOURCE_DESCRIPTOR pWdmDescriptor;
|
|
ULONG i, count;
|
|
NTSTATUS status;
|
|
|
|
pWdmDescriptor = &(*WdmResourceList)->Descriptors[0];
|
|
count = (*WdmResourceList)->Count;
|
|
status = STATUS_SUCCESS;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
//
|
|
// Now create a new resource object for each resource
|
|
// in our list.
|
|
//
|
|
FxResourceIo *pResource;
|
|
|
|
pResource = new(GetDriverGlobals())
|
|
FxResourceIo(GetDriverGlobals(), pWdmDescriptor);
|
|
|
|
if (pResource == NULL) {
|
|
//
|
|
// We failed, clean up, and exit. Since we are only
|
|
// keeping references on the master collection, if
|
|
// we free this, everything else will go away too.
|
|
//
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
status = pResource->AssignParentObject(this);
|
|
|
|
//
|
|
// See notes in previous AssignParentObject as to why
|
|
// we are asserting.
|
|
//
|
|
ASSERT(NT_SUCCESS(status));
|
|
UNREFERENCED_PARAMETER(status);
|
|
|
|
status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
pWdmDescriptor++;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
status = m_OwningList->Add(this) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
*WdmResourceList = (PIO_RESOURCE_LIST) pWdmDescriptor;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxCmResList::BuildFromWdmList(
|
|
__in PCM_RESOURCE_LIST WdmResourceList,
|
|
__in UCHAR AccessFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Builds up the collection with FxResourceCm objects based on the passed in
|
|
WDM io resource list.
|
|
|
|
Arguments:
|
|
WdmResourceList - list which specifies the io resource objects to create
|
|
|
|
AccessFlags - permissions to be associated with the list
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Predispose to success
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
|
|
Clear();
|
|
|
|
m_AccessFlags = AccessFlags;
|
|
|
|
if (WdmResourceList != NULL) {
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
|
|
ULONG count, i;
|
|
|
|
//
|
|
// We only expect to see one full resource descriptor.
|
|
//
|
|
ASSERT(WdmResourceList->Count == 1);
|
|
|
|
count = WdmResourceList->List[0].PartialResourceList.Count;
|
|
pDescriptor = WdmResourceList->List[0].PartialResourceList.PartialDescriptors;
|
|
|
|
for(i = 0; i < count; i++, pDescriptor++) {
|
|
FxResourceCm *pResource;
|
|
|
|
pResource = new(GetDriverGlobals())
|
|
FxResourceCm(GetDriverGlobals(), pDescriptor);
|
|
|
|
if (pResource == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
status = pResource->AssignParentObject(this);
|
|
|
|
//
|
|
// Since we control our own lifetime here, the assign should
|
|
// always work.
|
|
//
|
|
ASSERT(NT_SUCCESS(status));
|
|
|
|
status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
Clear();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
PCM_RESOURCE_LIST
|
|
FxCmResList::CreateWdmList(
|
|
__in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Allocates and initializes a WDM CM resource list based off of the current
|
|
contents of this collection.
|
|
|
|
Arguments:
|
|
PoolType - the pool type from which to allocate the resource list
|
|
|
|
Return Value:
|
|
a new resource list upon success, NULL upon failure
|
|
|
|
--*/
|
|
{
|
|
PCM_RESOURCE_LIST pWdmResourceList;
|
|
ULONG size;
|
|
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
|
|
|
pWdmResourceList = NULL;
|
|
pFxDriverGlobals = GetDriverGlobals();
|
|
|
|
if (Count()) {
|
|
//
|
|
// NOTE: This function assumes all resources are on the same bus
|
|
// and therefore there is only one FULL_RESOURCE_DESCRIPTOR.
|
|
//
|
|
size = sizeof(CM_RESOURCE_LIST) +
|
|
(sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count() - 1));
|
|
|
|
pWdmResourceList = (PCM_RESOURCE_LIST)
|
|
MxMemory::MxAllocatePoolWithTag(PoolType, size, pFxDriverGlobals->Tag);
|
|
|
|
if (pWdmResourceList != NULL) {
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
|
|
FxCollectionEntry *cur, *end;
|
|
|
|
RtlZeroMemory(pWdmResourceList, size);
|
|
|
|
pWdmResourceList->Count = 1; // We only return one full descriptor
|
|
|
|
pWdmResourceList->List[0].PartialResourceList.Version = 1;
|
|
pWdmResourceList->List[0].PartialResourceList.Revision = 1;
|
|
pWdmResourceList->List[0].PartialResourceList.Count = Count();
|
|
|
|
pDescriptor =
|
|
pWdmResourceList->List[0].PartialResourceList.PartialDescriptors;
|
|
|
|
end = End();
|
|
for (cur = Start(); cur != end; cur = cur->Next()) {
|
|
FxResourceCm *pResource;
|
|
|
|
pResource = (FxResourceCm*) cur->m_Object;
|
|
|
|
RtlCopyMemory(pDescriptor,
|
|
&pResource->m_Descriptor,
|
|
sizeof(pResource->m_Descriptor));
|
|
pDescriptor++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pWdmResourceList;
|
|
}
|
|
|
|
ULONG
|
|
FxCmResList::GetCount(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG count;
|
|
KIRQL irql;
|
|
|
|
Lock(&irql);
|
|
count = Count();
|
|
Unlock(irql);
|
|
|
|
return count;
|
|
}
|
|
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR
|
|
FxCmResList::GetDescriptor(
|
|
__in ULONG Index
|
|
)
|
|
{
|
|
FxResourceCm* pObject;
|
|
KIRQL irql;
|
|
|
|
Lock(&irql);
|
|
pObject = (FxResourceCm*) GetItem(Index);
|
|
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;
|
|
}
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
FxIoResReqList*
|
|
FxIoResReqList::_CreateFromWdmList(
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
|
__in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList,
|
|
__in UCHAR AccessFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Allocates and populates an FxIoResReqList based on the WDM resource
|
|
requirements list.
|
|
|
|
Arguments:
|
|
WdmRequirementsList - a list of IO_RESOURCE_LISTs which will indicate how
|
|
to fill in the returned collection object
|
|
|
|
AccessFlags - permissions to associate with the newly created object
|
|
|
|
Return Value:
|
|
a new object upon success, NULL upon failure
|
|
|
|
--*/
|
|
|
|
{
|
|
FxIoResReqList* pIoResReqList;
|
|
ULONG i;
|
|
|
|
pIoResReqList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
|
|
FxIoResReqList(FxDriverGlobals, AccessFlags);
|
|
|
|
if (pIoResReqList != NULL) {
|
|
PIO_RESOURCE_LIST pWdmResourceList;
|
|
NTSTATUS status;
|
|
|
|
if (WdmRequirementsList == NULL) {
|
|
return pIoResReqList;
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
pWdmResourceList = &WdmRequirementsList->List[0];
|
|
|
|
pIoResReqList->m_InterfaceType = WdmRequirementsList->InterfaceType;
|
|
pIoResReqList->m_SlotNumber = WdmRequirementsList->SlotNumber;
|
|
|
|
for (i = 0; i < WdmRequirementsList->AlternativeLists; i++) {
|
|
FxIoResList *pResList;
|
|
|
|
pResList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
|
|
FxIoResList(FxDriverGlobals, pIoResReqList);
|
|
|
|
if (pResList != NULL) {
|
|
status = pResList->AssignParentObject(pIoResReqList);
|
|
|
|
//
|
|
// Since we control our own lifetime, assigning the parent should
|
|
// never fail.
|
|
//
|
|
ASSERT(NT_SUCCESS(status));
|
|
|
|
status = pResList->BuildFromWdmList(&pWdmResourceList);
|
|
}
|
|
else {
|
|
//
|
|
// We failed to allocate a child collection. Clean up
|
|
// and break out of the loop.
|
|
//
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// Cleanup and return a NULL object
|
|
//
|
|
pIoResReqList->DeleteObject();
|
|
pIoResReqList = NULL;
|
|
}
|
|
}
|
|
|
|
return pIoResReqList;
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
PIO_RESOURCE_REQUIREMENTS_LIST
|
|
FxIoResReqList::CreateWdmList(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Creates a WDM io resource requirements list based off of the current
|
|
contents of the collection
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
new WDM io resource requirements list allocated out of paged pool upon success,
|
|
NULL upon failure or an empty list
|
|
|
|
--*/
|
|
{
|
|
PIO_RESOURCE_REQUIREMENTS_LIST pRequirementsList;
|
|
FxCollectionEntry *cur, *end;
|
|
NTSTATUS status;
|
|
ULONG totalDescriptors;
|
|
ULONG size;
|
|
ULONG count;
|
|
ULONG tmp;
|
|
PFX_DRIVER_GLOBALS pFxDriverGlobals;
|
|
|
|
totalDescriptors = 0;
|
|
pRequirementsList = NULL;
|
|
|
|
count = Count();
|
|
pFxDriverGlobals = GetDriverGlobals();
|
|
|
|
if (count > 0) {
|
|
//
|
|
// The collection object should contain a set of child collections
|
|
// with each of the various requirement lists. Use the number of
|
|
// these collections to determine the size of our requirements
|
|
// list.
|
|
//
|
|
end = End();
|
|
for (cur = Start(); cur != end; cur = cur->Next()) {
|
|
status = RtlULongAdd(totalDescriptors,
|
|
((FxIoResList *) cur->m_Object)->Count(),
|
|
&totalDescriptors);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Overflow;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We now have enough information to determine how much memory we
|
|
// need to allocate for our requirements list.
|
|
//
|
|
// size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
|
|
// (sizeof(IO_RESOURCE_LIST) * (count - 1)) +
|
|
// (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors) -
|
|
// (sizeof(IO_RESOURCE_DESCRIPTOR) * count);
|
|
//
|
|
// sizeof(IO_RESOURCE_DESCRIPTOR) * count is subtracted off because
|
|
// each IO_RESOURCE_LIST has an embedded IO_RESOURCE_DESCRIPTOR in it
|
|
// and we don't want to overallocated.
|
|
//
|
|
|
|
//
|
|
// To handle overflow each mathematical operation is split out into an
|
|
// overflow safe call.
|
|
//
|
|
size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
|
|
|
|
// sizeof(IO_RESOURCE_LIST) * (count - 1)
|
|
status = RtlULongMult(sizeof(IO_RESOURCE_LIST), count - 1, &tmp);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Overflow;
|
|
}
|
|
|
|
status = RtlULongAdd(size, tmp, &size);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Overflow;
|
|
}
|
|
|
|
// (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors)
|
|
status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR),
|
|
totalDescriptors,
|
|
&tmp);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Overflow;
|
|
}
|
|
|
|
status = RtlULongAdd(size, tmp, &size);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Overflow;
|
|
}
|
|
|
|
// - sizeof(IO_RESOURCE_DESCRIPTOR) * Count() (note the subtraction!)
|
|
status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR), count, &tmp);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Overflow;
|
|
}
|
|
|
|
// Sub, not Add!
|
|
status = RtlULongSub(size, tmp, &size);
|
|
if (!NT_SUCCESS(status)) {
|
|
goto Overflow;
|
|
}
|
|
|
|
pRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST)
|
|
MxMemory::MxAllocatePoolWithTag(PagedPool, size, pFxDriverGlobals->Tag);
|
|
|
|
if (pRequirementsList != NULL) {
|
|
PIO_RESOURCE_LIST pList;
|
|
FxResourceIo *pResource;
|
|
|
|
pList = pRequirementsList->List;
|
|
|
|
//
|
|
// Start by zero initializing our structure
|
|
//
|
|
RtlZeroMemory(pRequirementsList, size);
|
|
|
|
//
|
|
// InterfaceType and BusNumber are unused for WDM, but InterfaceType
|
|
// is used by the arbiters.
|
|
//
|
|
pRequirementsList->InterfaceType = m_InterfaceType;
|
|
|
|
pRequirementsList->SlotNumber = m_SlotNumber;
|
|
|
|
//
|
|
// Now populate the requirements list with the resources from
|
|
// our collections.
|
|
//
|
|
pRequirementsList->ListSize = size;
|
|
pRequirementsList->AlternativeLists = Count();
|
|
|
|
end = End();
|
|
for (cur = Start(); cur != end; cur = cur->Next()) {
|
|
FxIoResList* pIoResList;
|
|
PIO_RESOURCE_DESCRIPTOR pDescriptor;
|
|
FxCollectionEntry *pIoResCur, *pIoResEnd;
|
|
|
|
pIoResList = (FxIoResList*) cur->m_Object;
|
|
|
|
pList->Version = 1;
|
|
pList->Revision = 1;
|
|
pList->Count = pIoResList->Count();
|
|
|
|
pDescriptor = pList->Descriptors;
|
|
|
|
pIoResEnd = pIoResList->End();
|
|
for (pIoResCur = pIoResList->Start();
|
|
pIoResCur != pIoResEnd;
|
|
pIoResCur = pIoResCur->Next()) {
|
|
|
|
pResource = (FxResourceIo *) pIoResCur->m_Object;
|
|
RtlCopyMemory(pDescriptor,
|
|
&pResource->m_Descriptor,
|
|
sizeof(pResource->m_Descriptor));
|
|
pDescriptor++;
|
|
}
|
|
|
|
pList = (PIO_RESOURCE_LIST) pDescriptor;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pRequirementsList;
|
|
|
|
Overflow:
|
|
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
|
|
"Integer overflow occured when computing size of "
|
|
"IO_RESOURCE_REQUIREMENTS_LIST");
|
|
|
|
return NULL;
|
|
}
|