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

📄 supportfunc.c

📁 本压缩包为作者截取的PCI9054的WDM官方驱动源码。欢迎下载。
💻 C
📖 第 1 页 / 共 3 页
字号:
        IoFreeMdl(
            pdx->DmaInfo[DmaIndex].pMdl
            );

        pdx->DmaInfo[DmaIndex].pMdl = NULL;
    }

    // Clear the DMA pending flag
    pdx->DmaInfo[DmaIndex].bPending = FALSE;

    KeReleaseSpinLock(
        &(pdx->Lock_DmaChannel),
        IrqL_Original
        );
}




/******************************************************************************
 *
 * Function   :  PlxLockBufferAndBuildSgl
 *
 * Description:  Lock a user buffer and build an SGL for it
 *
 ******************************************************************************/
U32
PlxLockBufferAndBuildSgl(
    DEVICE_EXTENSION     *pdx,
    U8                    DmaIndex,
    DMA_TRANSFER_ELEMENT *pDma
    )
{
    U32           i;
    U32           offset;
    U32           BusSgl;
    U32           BusSglOriginal;
    U32           BusAddr;
    U32           SglSize;
    U32           BlockSize;
    U32           LocalAddr;
    U32           TotalPages;
    U32          *pCurrentPage;
    U32           BytesRemaining;
    PMDL          pMdl;
    KIRQL         IrqL_Original;
    BOOLEAN       bFlag;
    PLX_UINT_PTR  VaSgl;


    DebugPrintf(("Building SGL descriptors for buffer...\n"));
    DebugPrintf(("   User VA   : 0x%08lx\n", (PLX_UINT_PTR)pDma->u.UserVa));
    DebugPrintf(("   Local Addr: 0x%08x\n", pDma->LocalAddr));
    DebugPrintf(("   Size      : %d bytes\n", pDma->TransferCount));

    // Get the MDL for the User buffer to get the page list
    pMdl =
        IoAllocateMdl(
            (VOID*)pDma->u.UserVa,
            pDma->TransferCount,
            FALSE,
            FALSE,
            NULL
            );

    if (pMdl == NULL)
    {
        DebugPrintf(("ERROR - Unable to allocate an MDL for the User buffer\n"));
        return 0;
    }

    // Attempt to lock the user buffer into memory
    bFlag = FALSE;

    try
    {
        MmProbeAndLockPages(
            pMdl,
            UserMode,
            IoModifyAccess
            );
    }
    except(EXCEPTION_EXECUTE_HANDLER)
    {
        // Flag the exception
        bFlag = TRUE;
    }

    // Verify that the pages were locked
    if (bFlag)
    {
        DebugPrintf(("ERROR - Unable to lock user mode buffer pages\n"));
        IoFreeMdl(
            pMdl
            );
        return 0;
    }

    // Calculate total pages
    TotalPages  = (((U16)pMdl->Size - sizeof(MDL)) / sizeof(U32));

    DebugPrintf((
        "Page-locked %d user buffer pages...\n",
        TotalPages
        ));


    /******************************************************
     * Build SGL descriptors
     *
     * The following code will build the SGL descriptors
     * in PCI memory.  There will be one descriptor for
     * each page of memory since the pages are scattered
     * throughout physical memory.
     *****************************************************/

    /*************************************************************
     * Calculate memory needed for SGL descriptors
     *
     * Mem needed = #pages * size of descriptor
     *
     * Additionally, a value of 16 (10h) is added to provide a
     * buffer to allow space to round up to the next 16-byte
     * boundary, which is a requirement of the hardware.
     ************************************************************/
    SglSize = (TotalPages * (4 * sizeof(U32))) + 16;

    // Check if a previously allocated buffer can be re-used
    if (pdx->DmaInfo[DmaIndex].SglBuffer.pKernelVa != NULL)
    {
        if (pdx->DmaInfo[DmaIndex].SglBuffer.Size >= SglSize)
        {
            // Buffer can be re-used, do nothing
            DebugPrintf(("Re-using previously allocated SGL descriptor buffer\n"));
        }
        else
        {
            DebugPrintf(("Releasing previously allocated SGL descriptor buffer\n"));

            // Release memory used for SGL descriptors
            Plx_dma_buffer_free(
                pdx,
                &pdx->DmaInfo[DmaIndex].SglBuffer
                );

            pdx->DmaInfo[DmaIndex].SglBuffer.pKernelVa = NULL;
        }
    }

    // Allocate memory for SGL descriptors if necessary
    if (pdx->DmaInfo[DmaIndex].SglBuffer.pKernelVa == NULL)
    {
        DebugPrintf(("Allocating PCI memory for SGL descriptor buffer...\n"));

        // Setup for transfer
        pdx->DmaInfo[DmaIndex].SglBuffer.Size       = SglSize;
        pdx->DmaInfo[DmaIndex].SglBuffer.bCacheable = FALSE;

        VaSgl =
            (PLX_UINT_PTR)Plx_dma_buffer_alloc(
                pdx,
                &pdx->DmaInfo[DmaIndex].SglBuffer
                );

        if (VaSgl == 0)
        {
            DebugPrintf((
                "ERROR - Unable to allocate %d bytes for %d SGL descriptors\n",
                pdx->DmaInfo[DmaIndex].SglBuffer.Size,
                TotalPages
                ));

            MmUnlockPages(
                pMdl
                );

            IoFreeMdl(
                pMdl
                );

            return 0;
        }
    }
    else
    {
        VaSgl = (PLX_UINT_PTR)pdx->DmaInfo[DmaIndex].SglBuffer.pKernelVa;
    }


    // Save MDL for deallocation after the DMA transfer
    KeAcquireSpinLock(
        &(pdx->Lock_DmaChannel),
        &IrqL_Original
        );

    pdx->DmaInfo[DmaIndex].pMdl = pMdl;

    KeReleaseSpinLock(
        &(pdx->Lock_DmaChannel),
        IrqL_Original
        );

    // Prepare for build of SGL
    LocalAddr = pDma->LocalAddr;

    // Get bus physical address of SGL descriptors
    BusSgl = (U32)pdx->DmaInfo[DmaIndex].SglBuffer.BusPhysical;

    // Make sure addresses are aligned on 16-byte boundary
    VaSgl  = (VaSgl + 0xF) & ~(0xF);
    BusSgl = (BusSgl + 0xF) & ~(0xF);

    // Store the starting address of the SGL for later return
    BusSglOriginal = BusSgl;

    DebugPrintf((
        "Building SGL descriptor list located at 0x%08x...\n",
        BusSglOriginal
        ));

    // Point to first page in physical page list (located at end of MDL)
    pCurrentPage = (U32*)(((U8*)pMdl) + sizeof(MDL));

    // Set offset of first page
    offset = pMdl->ByteOffset;

    // Initialize bytes remaining
    BytesRemaining = pDma->TransferCount;

    // Build the SGL list
    for (i = 0; i < TotalPages; i++)
    {
        // Calculate transfer size
        if (BytesRemaining > (PAGE_SIZE - offset))
        {
            BlockSize = PAGE_SIZE - offset;
        }
        else
        {
            BlockSize = BytesRemaining;
        }

        // Get bus address of buffer
        BusAddr = (*pCurrentPage << PAGE_SHIFT) + offset;

        // Enable the following to display the parameters of each SGL descriptor
        if (PLX_DEBUG_DISPLAY_SGL_DESCR)
        {
            DebugPrintf((
                "SGL Desc %02d: PCI=%08Xh  Loc=%08Xh  Size=%Xh (%d) bytes\n",
                i, (U32)BusAddr, LocalAddr, BlockSize, BlockSize
                ));
        }

        // Write PCI address in descriptor
        *(((U32*)VaSgl) + SGL_DESC_IDX_PCI_ADDR) = BusAddr;

        // Write Local address in descriptor
        *(((U32*)VaSgl) + SGL_DESC_IDX_LOC_ADDR) = LocalAddr;

        // Write transfer count in descriptor
        *(((U32*)VaSgl) + SGL_DESC_IDX_COUNT) = BlockSize;

        // Adjust byte count
        BytesRemaining -= BlockSize;

        if (BytesRemaining == 0)
        {
            // Write the last descriptor
            *(((U32*)VaSgl) + SGL_DESC_IDX_NEXT_DESC) =
                            (pDma->LocalToPciDma << 3) | (1 << 1) | (1 << 0);
        }
        else
        {
            // Calculate address of next descriptor
            BusSgl += (4 * sizeof(U32));

            // Write next descriptor address
            *(((U32*)VaSgl) + SGL_DESC_IDX_NEXT_DESC) =
                             BusSgl | (pDma->LocalToPciDma << 3) | (1 << 0);

            // Adjust Local address
            if (pdx->DmaInfo[DmaIndex].bLocalAddrConstant == FALSE)
                LocalAddr += BlockSize;

            // Adjust virtual address to next descriptor
            VaSgl += (4 * sizeof(U32));

            // Clear offset
            offset = 0;
        }

        // Go to next page
        pCurrentPage++;
    }

    // Make sure cache data is flushed
    KeFlushIoBuffers(
        pMdl,
        (BOOLEAN)pDma->LocalToPciDma,   // Read from device operation?
        TRUE                            // DMA transfer?
        );

    // Return the physical address of the SGL
    return BusSglOriginal;
}

#endif // DMA_SUPPORT




/******************************************************************************
 *
 * Function   :  Plx_dma_buffer_alloc
 *
 * Description:  Allocates physically contiguous non-paged memory
 *
 ******************************************************************************/
VOID*
Plx_dma_buffer_alloc(
    DEVICE_EXTENSION    *pdx,
    PLX_PHYS_MEM_OBJECT *pMemObject
    )
{
    PHYSICAL_ADDRESS BufferLogicalAddress;


    // Verify the DMA adapter object
    if (pdx->pDmaAdapter == NULL)
    {
        DebugPrintf((
            "ERROR - DMA Adapter object does not exist, cannot allocate physical memory\n"
            ));

        return NULL;
    }

    // Attempt to allocate contiguous memory
#if defined(PLX_NT_DRIVER)
    pMemObject->pKernelVa =
        HalAllocateCommonBuffer(
            pdx->pDmaAdapter,
            pMemObject->Size,
            &BufferLogicalAddress,
            pMemObject->bCacheable      // Enable Caching for buffer?
            );
#else
    pMemObject->pKernelVa =
        pdx->pDmaAdapter->DmaOperations->AllocateCommonBuffer(
            pdx->pDmaAdapter,
            pMemObject->Size,
            &BufferLogicalAddress,
            pMemObject->bCacheable      // Enable Caching for buffer?
            );
#endif // PLX_NT_DRIVER

    if (pMemObject->pKernelVa == NULL)
    {
        return NULL;
    }

    // Store the buffer logical/bus physical address
    pMemObject->BusPhysical = BufferLogicalAddress.QuadPart;

    // CPU Address is the same as bus on this architecture
    pMemObject->CpuPhysical = BufferLogicalAddress.QuadPart;

    // Clear the buffer
    RtlZeroMemory(
        pMemObject->pKernelVa,
        pMemObject->Size
        );

    DebugPrintf(("Allocated physical memory...\n"));

    DebugPrintf((
        "    CPU Phys Addr: 0x%08lx\n",
        (PLX_UINT_PTR)pMemObject->CpuPhysical
        ));

    DebugPrintf((
        "    Bus Phys Addr: 0x%08lx\n",
        (PLX_UINT_PTR)pMemObject->BusPhysical
        ));

    DebugPrintf((
        "    Kernel VA    : 0x%p\n",
        pMemObject->pKernelVa
        ));

    DebugPrintf((
        "    Size         : "
        ));

    if (pMemObject->Size >= (10 << 10))
    {
        DebugPrintf_NoInfo((
            "%d Kb\n",
            (pMemObject->Size >> 10)
            ));
    }
    else
    {
        DebugPrintf_NoInfo((
            "%d bytes\n",
            pMemObject->Size
            ));
    }

    DebugPrintf((
        "    Cacheable?   : %s\n",
        (pMemObject->bCacheable == FALSE) ? "No" : "Yes"
        ));

    return pMemObject->pKernelVa;
}




/******************************************************************************
 *
 * Function   :  Plx_dma_buffer_free
 *
 * Description:  Frees previously allocated physical memory
 *
 ******************************************************************************/
VOID
Plx_dma_buffer_free(
    DEVICE_EXTENSION    *pdx,
    PLX_PHYS_MEM_OBJECT *pMemObject
    )
{
    PHYSICAL_ADDRESS  BufferLogicalAddress;


    // Verify the DMA adapter object
    if (pdx->pDmaAdapter == NULL)
    {
        DebugPrintf((
            "ERROR - DMA Adapter object does not exist, cannot allocate physical memory\n"
            ));

        return;
    }

    // Set logical address
    BufferLogicalAddress.QuadPart = pMemObject->BusPhysical;

    // Release the buffer

#if defined(PLX_NT_DRIVER)
    HalFreeCommonBuffer(
        pdx->pDmaAdapter,
        pMemObject->Size,
        BufferLogicalAddress,
        pMemObject->pKernelVa,
        pMemObject->bCacheable      // Enable Caching for buffer?
        );
#else
    pdx->pDmaAdapter->DmaOperations->FreeCommonBuffer(
        pdx->pDmaAdapter,
        pMemObject->Size,
        BufferLogicalAddress,
        pMemObject->pKernelVa,
        pMemObject->bCacheable      // Enable Caching for buffer?
        );
#endif // PLX_NT_DRIVER

    DebugPrintf((
        "Released physical memory at 0x%08lx ",
        (PLX_UINT_PTR)pMemObject->CpuPhysical
        ));

    if (pMemObject->Size >= (10 << 10))
    {
        DebugPrintf_NoInfo((
            "(%d Kb)\n",
            (pMemObject->Size >> 10)
            ));
    }
    else
    {
        DebugPrintf_NoInfo((
            "(%d bytes)\n",
            pMemObject->Size
            ));
    }

    // Clear memory object properties
    RtlZeroMemory(
        pMemObject,
        sizeof(PLX_PHYS_MEM_OBJECT)
        );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -