/******************************************************************
Replacement of resource requirement list, when needed:
The procedure traverses over all the resource lists in existing resource requirement list
(we receive it in IRP information field).
When the driver is not built to work with MSI resources, we must remove them from the
resource requirement list, otherwise the driver will fail to initialize
Typically MSI interrupts are labeled as preferred ones, when line interrupts are labeled as
alternative resources. Removing message interrupts, remove also "alternative" label from line interrupts.
*******************************************************************/
static PIO_RESOURCE_REQUIREMENTS_LIST ParseFilterResourceIrp(
    IN NDIS_HANDLE  MiniportAddDeviceContext,
    PIO_RESOURCE_REQUIREMENTS_LIST prrl,
    BOOLEAN bRemoveMSIResources)
{
    tRRLData newRRLData;
    ULONG nRemoved = 0;
    PIO_RESOURCE_REQUIREMENTS_LIST newPrrl = NULL;
    DPrintf(resourceFilterLevel, ("[%s]%s\n", __FUNCTION__, bRemoveMSIResources ? "(Remove MSI resources...)" : ""));
    if (MiniportAddDeviceContext && prrl) newPrrl = (PIO_RESOURCE_REQUIREMENTS_LIST)NdisAllocateMemoryWithTagPriority(
            MiniportAddDeviceContext,
            prrl->ListSize,
            PARANDIS_MEMORY_TAG,
            NormalPoolPriority);
    InitializeNewResourceRequirementsList(&newRRLData, newPrrl, prrl);
    if (prrl)
    {
        ULONG n, offset;
        PVOID p = &prrl->List[0];
        DPrintf(resourceFilterLevel, ("[%s] %d bytes, %d lists\n", __FUNCTION__, prrl->ListSize, prrl->AlternativeLists));
        offset = RtlPointerToOffset(prrl, p);
        for (n = 0; n < prrl->AlternativeLists && offset < prrl->ListSize; ++n)
        {
            ULONG nDesc;
            IO_RESOURCE_LIST *pior = (IO_RESOURCE_LIST *)p;
            if ((offset + sizeof(*pior)) < prrl->ListSize)
            {
                IO_RESOURCE_DESCRIPTOR *pd = &pior->Descriptors[0];
                DPrintf(resourceFilterLevel, ("[%s]+%d %d:%d descriptors follow\n", __FUNCTION__, offset, n, pior->Count));
                offset += RtlPointerToOffset(p, pd);
                AddNewResourceList(&newRRLData, pior);
                for (nDesc = 0; nDesc < pior->Count; ++nDesc)
                {
                    BOOLEAN bRemove = FALSE;
                    if ((offset + sizeof(*pd)) <= prrl->ListSize)
                    {
                        DPrintf(resourceFilterLevel, ("[%s]+%d %d: type %d, flags %X, option %X\n", __FUNCTION__, offset, nDesc, pd->Type, pd->Flags, pd->Option));
                        if (pd->Type == CmResourceTypeInterrupt)
                        {
                            if (pd->Flags & CM_RESOURCE_INTERRUPT_MESSAGE)
                            {
                                bRemove = bRemoveMSIResources;
                            }
                            else
                            {
                                // reset IO_RESOURCE_ALTERNATIVE attribute on Line Interrupt,
                                // if we remove MSI vectors, otherwise Windows will not allocate it for the device
                                if (bRemoveMSIResources && (pd->Option & IO_RESOURCE_ALTERNATIVE))
                                {
                                    pd->Option &= ~IO_RESOURCE_ALTERNATIVE;
                                }
                            }
                        }
                        if (!bRemove) AddNewResourceDescriptor(&newRRLData, pd);
                        else nRemoved++;
                    }
                    offset += sizeof(*pd);
                    pd = (IO_RESOURCE_DESCRIPTOR *)RtlOffsetToPointer(prrl, offset);
                }
                FinalizeResourceList(&newRRLData);
                p = pd;
            }
        }
    }
    if (bRemoveMSIResources && nRemoved)
    {
        DPrintf(0, ("[%s] %d resources removed\n", __FUNCTION__, nRemoved));
    }
    return newPrrl;
}
/******************************************************************
Replacement of resource requirement list, when needed:
The procedure traverses over all the resource lists in existing resource requirement list
(we receive it in IRP information field).
When the driver is not built to work with MSI resources, we must remove them from the
resource requirement list, otherwise the driver will fail to initialize
Typically MSI interrupts are labeled as preferred ones, when line interrupts are labeled as
alternative resources. Removing message interrupts, remove also "alternative" label from line interrupts.
*******************************************************************/
static PIO_RESOURCE_REQUIREMENTS_LIST ParseFilterResourceIrp(
    IN NDIS_HANDLE  MiniportAddDeviceContext,
    PIO_RESOURCE_REQUIREMENTS_LIST prrl,
    BOOLEAN bRemoveMSIResources)
{
    tRRLData newRRLData;
    ULONG nRemoved = 0;
    UINT nInterrupts = 0;
    PIO_RESOURCE_REQUIREMENTS_LIST newPrrl = NULL;
    ULONG QueueNumber;
#if NDIS_SUPPORT_NDIS620    
    QueueNumber = NdisGroupActiveProcessorCount(ALL_PROCESSOR_GROUPS) + 1;
#elif NDIS_SUPPORT_NDIS6
    QueueNumber = NdisSystemProcessorCount();
#else
    QueueNumber = 0; /* Don't create MSI resource descriptors*/
#endif


    if (QueueNumber > 2048)
        QueueNumber = 2048;

    DPrintf(resourceFilterLevel, ("[%s]%s\n", __FUNCTION__, bRemoveMSIResources ? "(Remove MSI resources...)" : ""));

    newPrrl = (PIO_RESOURCE_REQUIREMENTS_LIST)NdisAllocateMemoryWithTagPriority(
            MiniportAddDeviceContext,
            prrl->ListSize + (bRemoveMSIResources ? 0 : QueueNumber * sizeof(IO_RESOURCE_DESCRIPTOR)),
            PARANDIS_MEMORY_TAG,
            NormalPoolPriority);

    InitializeNewResourceRequirementsList(&newRRLData, newPrrl, prrl);
    if (prrl)
    {
        ULONG n, offset;
        PVOID p = &prrl->List[0];
        DPrintf(resourceFilterLevel, ("[%s] %d bytes, %d lists\n", __FUNCTION__, prrl->ListSize, prrl->AlternativeLists));
        offset = RtlPointerToOffset(prrl, p);
        for (n = 0; n < prrl->AlternativeLists && offset < prrl->ListSize; ++n)
        {
            ULONG nDesc;
            IO_RESOURCE_LIST *pior = (IO_RESOURCE_LIST *)p;
            if ((offset + sizeof(*pior)) < prrl->ListSize)
            {
                IO_RESOURCE_DESCRIPTOR *pd = &pior->Descriptors[0];
                DPrintf(resourceFilterLevel, ("[%s]+%d %d:%d descriptors follow\n", __FUNCTION__, offset, n, pior->Count));
                offset += RtlPointerToOffset(p, pd);
                AddNewResourceList(&newRRLData, pior);
                for (nDesc = 0; nDesc < pior->Count; ++nDesc)
                {
                    BOOLEAN bRemove = FALSE;
                    if ((offset + sizeof(*pd)) <= prrl->ListSize)
                    {
#ifdef DBG
                        DPrintf(resourceFilterLevel, ("[%s]+%d %d: type %d/%s, flags %X, option %X\n", __FUNCTION__, offset, nDesc, pd->Type, 
                            CM_RESOURCE_TYPE2String(pd->Type), pd->Flags, pd->Option));
#else
                        DPrintf(resourceFilterLevel, ("[%s]+%d %d: type %d, flags %X, option %X\n", __FUNCTION__, offset, nDesc, pd->Type,
                            pd->Flags, pd->Option));
#endif

                        if (pd->Type == CmResourceTypeInterrupt)
                        {
                            nInterrupts++;
                            DPrintf(0, ("[%s] min/max = %lx/%lx Option = 0x%lx, ShareDisposition = %u \n", __FUNCTION__, pd->u.Interrupt.MinimumVector, pd->u.Interrupt.MaximumVector,
                                pd->Option, pd->ShareDisposition));
                            if (pd->Flags & CM_RESOURCE_INTERRUPT_MESSAGE)
                            {
                                bRemove = bRemoveMSIResources;
                            }
                            else
                            {
                                // reset IO_RESOURCE_ALTERNATIVE attribute on Line Interrupt,
                                // if we remove MSI vectors, otherwise Windows will not allocate it for the device
                                if (bRemoveMSIResources && (pd->Option & IO_RESOURCE_ALTERNATIVE))
                                {
                                    pd->Option &= ~IO_RESOURCE_ALTERNATIVE;
                                }
                            }
                        }
                        if (!bRemove) AddNewResourceDescriptor(&newRRLData, pd);
                        else nRemoved++;
                    }
                    offset += sizeof(*pd);
                    pd = (IO_RESOURCE_DESCRIPTOR *)RtlOffsetToPointer(prrl, offset);
                }

                if (!bRemoveMSIResources)
                {
                    while (nInterrupts < QueueNumber)
                    {
                        IO_RESOURCE_DESCRIPTOR ior;
                        ior.Type = CmResourceTypeInterrupt;
                        ior.Flags = CM_RESOURCE_INTERRUPT_LATCHED | CM_RESOURCE_INTERRUPT_MESSAGE | CM_RESOURCE_INTERRUPT_POLICY_INCLUDED;
                        ior.Option = 0;
                        ior.ShareDisposition = CmResourceShareDeviceExclusive;
                        ior.u.Interrupt.MinimumVector = ior.u.Interrupt.MaximumVector = CM_RESOURCE_INTERRUPT_MESSAGE_TOKEN;
                        ior.u.Interrupt.AffinityPolicy = IrqPolicyMachineDefault;
                        ior.u.Interrupt.PriorityPolicy = IrqPriorityNormal;
                        AddNewResourceDescriptor(&newRRLData, &ior);
                        nInterrupts++;
                    }
                }

                FinalizeResourceList(&newRRLData);
                p = pd;
            }
        }
    }
    if (!bRemoveMSIResources)
    {
        SetupInterrruptAffinity(newPrrl);
    }
    if (bRemoveMSIResources && nRemoved)
    {
        DPrintf(0, ("[%s] %d resources removed\n", __FUNCTION__, nRemoved));
    }
    return newPrrl;
}