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

📄 plx_lib.c

📁 PCI口的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
        /* DMA of one page ==> direct DMA */
        PLX_WriteReg32(hDev, pPLXDma->dwDMAMODE, u32DMAMODE);
        PLX_WriteReg32(hDev, pPLXDma->dwDMAPADR, (UINT32)pPLXDma->pDma->Page[0].pPhysicalAddr);
        PLX_WriteReg32(hDev, pPLXDma->dwDMALADR, u32LocalAddr);
        PLX_WriteReg32(hDev, pPLXDma->dwDMASIZ, (UINT32)pPLXDma->pDma->Page[0].dwBytes);
        PLX_WriteReg32(hDev, pPLXDma->dwDMADPR, fIsRead ? BIT3 : 0);
    }
    else /* DMA of more then one page ==> chain DMA */
    {        
        typedef struct {
            UINT32 u32PADR;
            UINT32 u32LADR;
            UINT32 u32SIZ;
            UINT32 u32DPR;
        } DMA_LIST;
        
        DMA_LIST *pList = NULL;
        DWORD dwPageNumber;
        UINT32 u32StartOfChain, u32AlignShift, u32MemoryCopied;

        /* Allocate a kernel buffer to hold the chain of DMA descriptors
           includes extra 0x10 bytes for quadword alignment */
        WDC_DMAContigBufLock(hDev, (void *)&pList, dwOptions,
            pPLXDma->pDma->dwPages * sizeof(DMA_LIST) + 0x10, &pPLXDma->pDmaList);
        if (WD_STATUS_SUCCESS != dwStatus)
        {
            ErrLog("PLX_DMAOpen: Failed locking DMA list buffer. Error 0x%lX - %s\n",
                dwStatus, Stat2Str(dwStatus));
            goto Error;
        }

        /* Verification that bits 0-3 are zero (QUADWORD aligned) */
        u32AlignShift = 0x10 - ((UINT32)(unsigned long)pPLXDma->pDmaList->pUserAddr & 0xF);
        pList = (DMA_LIST*)((DWORD)pList + u32AlignShift);
        u32StartOfChain = (UINT32)pPLXDma->pDmaList->Page[0].pPhysicalAddr + u32AlignShift;

        /* Setting chain of DMA pages in the memory */
        for (dwPageNumber = 0, u32MemoryCopied = 0;
            dwPageNumber < pPLXDma->pDma->dwPages;
            dwPageNumber++)
        {
            pList[dwPageNumber].u32PADR = 
                htod32((UINT32)pPLXDma->pDma->Page[dwPageNumber].pPhysicalAddr);
            pList[dwPageNumber].u32LADR = 
                htod32((u32LocalAddr + (fAutoinc ? u32MemoryCopied : 0)));
            pList[dwPageNumber].u32SIZ = 
                htod32((UINT32)pPLXDma->pDma->Page[dwPageNumber].dwBytes);
            pList[dwPageNumber].u32DPR = 
                htod32((u32StartOfChain + sizeof(DMA_LIST) * (dwPageNumber + 1))
                | BIT0 | (fIsRead ? BIT3 : 0));
            u32MemoryCopied += pPLXDma->pDma->Page[dwPageNumber].dwBytes;
        }
        
        pList[dwPageNumber - 1].u32DPR |= htod32(BIT1); /* Mark end of chain */
    
        PLX_WriteReg32(hDev, pPLXDma->dwDMAMODE, u32DMAMODE | BIT9); /* Chain transfer */
        PLX_WriteReg32(hDev, pPLXDma->dwDMADPR, u32StartOfChain | BIT0);

        /* flush the list of DMA descriptors from CPU cache to system memory */
        WDC_DMASyncCpu(pPLXDma->pDmaList);
    }

    *ppDmaHandle = (PLX_DMA_HANDLE)pPLXDma;

    /* update the device cntext */
    pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(hDev);
    pDevCtx->pPLXDma = pPLXDma;
    
    return WD_STATUS_SUCCESS;

Error:
    if (pPLXDma)
        PLX_DMAClose(hDev, (PLX_DMA_HANDLE)pPLXDma);
    
    return dwStatus;
}

void PLX_DMAClose(WDC_DEVICE_HANDLE hDev, PLX_DMA_HANDLE hDma)
{
    DWORD dwStatus = WD_STATUS_SUCCESS;
    PLX_DMA_STRUCT *pPLXDma = (PLX_DMA_STRUCT*)hDma;
    
    TraceLog("PLX_DMAClose entered. Device handle: 0x%p\n", hDev);
    
    if (!IsValidDevice((PWDC_DEVICE)hDev, "PLX_DMAClose"))
        return;
    
    if (!hDma)
    {
        ErrLog("PLX_DMAClose: NULL DMA handle (device handle 0x%p)\n", hDev);
        return;
    }
    
    if (pPLXDma->pDma)
    {
        dwStatus = WDC_DMABufUnlock(pPLXDma->pDma);
        if (WD_STATUS_SUCCESS != dwStatus)
        {
            ErrLog("PLX_DMAClose: Failed unlocking DMA buffer. Error 0x%lX - %s\n",
                dwStatus, Stat2Str(dwStatus));
        }
    }
    else
    {
        TraceLog("PLX_DMAClose: DMA is not currently open ... "
            "(device handle 0x%p, DMA handle 0x%p)\n", hDev, hDma);
    }
     
    if (pPLXDma->pDmaList)
    {
        dwStatus = WDC_DMABufUnlock(pPLXDma->pDmaList);
        if (WD_STATUS_SUCCESS != dwStatus)
        {
            ErrLog("PLX_DMAClose: Failed unlocking DMA list buffer. Error 0x%lX - %s\n",
                dwStatus, Stat2Str(dwStatus));
        }
    }

    free(pPLXDma);
}

void PLX_DMASyncCpu(PLX_DMA_HANDLE hDma)
{
    WDC_DMASyncCpu(((PLX_DMA_STRUCT*)hDma)->pDma);
}

void PLX_DMASyncIo(PLX_DMA_HANDLE hDma)
{
    WDC_DMASyncIo(((PLX_DMA_STRUCT*)hDma)->pDma);
}

DWORD PLX_DMAStart(WDC_DEVICE_HANDLE hDev, PLX_DMA_HANDLE hDma)
{
    return PLX_WriteReg8(hDev, ((PLX_DMA_STRUCT*)hDma)->dwDMACSR, (BYTE)(BIT0 | BIT1));
}

BOOL PLX_DMAIsDone(WDC_DEVICE_HANDLE hDev, PLX_DMA_HANDLE hDma)
{
    BYTE val = 0;

    PLX_ReadReg8(hDev, ((PLX_DMA_STRUCT*)hDma)->dwDMACSR, &val);
    
    return (val & (BYTE)BIT4) == (BYTE)BIT4;
}

void PLX_DMAPollCompletion(WDC_DEVICE_HANDLE hDev, PLX_DMA_HANDLE hDma)
{
    while (!PLX_DMAIsDone(hDev, hDma))
        ;

    PLX_DMASyncIo(hDma);
}
#endif

/* -----------------------------------------------
    Address spaces information
   ----------------------------------------------- */
DWORD PLX_GetNumAddrSpaces(WDC_DEVICE_HANDLE hDev)
{
    PWDC_DEVICE pDev = (PWDC_DEVICE)hDev;
    
    if (!IsValidDevice(pDev, "PLX_GetNumAddrSpaces"))
        return 0;

    return pDev->dwNumAddrSpaces;
}

BOOL PLX_GetAddrSpaceInfo(WDC_DEVICE_HANDLE hDev, PLX_ADDR_SPACE_INFO *pAddrSpaceInfo)
{
    PWDC_DEVICE pDev = (PWDC_DEVICE)hDev;
    WDC_ADDR_DESC *pAddrDesc;
    DWORD dwAddrSpace, dwMaxAddrSpace;
    BOOL fIsMemory;
    
    if (!IsValidDevice(pDev, "PLX_GetAddrSpaceInfo"))
        return FALSE;

#if defined(DEBUG)
    if (!pAddrSpaceInfo)
    {
        ErrLog("PLX_GetAddrSpaceInfo: Error - NULL address space information pointer\n");
        return FALSE;
    }
#endif

    dwAddrSpace = pAddrSpaceInfo->dwAddrSpace;
    dwMaxAddrSpace = pDev->dwNumAddrSpaces - 1;

    if (dwAddrSpace > dwMaxAddrSpace)
    {
        ErrLog("PLX_GetAddrSpaceInfo: Error - Address space %ld is out of range (0 - %ld)\n",
            dwAddrSpace, dwMaxAddrSpace);
        return FALSE;
    }

    pAddrDesc = &pDev->pAddrDesc[dwAddrSpace];

    fIsMemory = WDC_ADDR_IS_MEM(pAddrDesc);
    
    snprintf(pAddrSpaceInfo->sName, MAX_NAME - 1, "BAR %ld", dwAddrSpace);
    snprintf(pAddrSpaceInfo->sType, MAX_TYPE - 1, fIsMemory ? "Memory" : "I/O");
        
    if (WDC_AddrSpaceIsActive(pDev, dwAddrSpace))
    {
        WD_ITEMS *pItem = &pDev->cardReg.Card.Item[pAddrDesc->dwItemIndex];
        DWORD dwAddr = fIsMemory ? pItem->I.Mem.dwPhysicalAddr : (DWORD)pItem->I.IO.dwAddr;
        
        snprintf(pAddrSpaceInfo->sDesc, MAX_DESC - 1, "0x%0*lX - 0x%0*lX (%ld bytes)",
            (int)WDC_SIZE_32 * 2, dwAddr,
            (int)WDC_SIZE_32 * 2, dwAddr + pAddrDesc->dwBytes - 1,
            pAddrDesc->dwBytes);
    }
    else
        snprintf(pAddrSpaceInfo->sDesc, MAX_DESC - 1, "Inactive address space");

    /* TODO: You can modify the code above to set a different address space name/description */

    return TRUE;
}

/* -----------------------------------------------
    Read/write local addresses
   ----------------------------------------------- */
#define MASK_LOCAL(hDev, addrSpace) (((PWDC_DEVICE)hDev)->pAddrDesc[addrSpace].dwBytes - 1)
static DWORD LocalAddrSetMode(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr)
{
    PWDC_DEVICE pDev = (PWDC_DEVICE)hDev;
    DWORD dwLocalBase = (dwLocalAddr & ~MASK_LOCAL(pDev, addrSpace)) | BIT0;
    DWORD dwOffset = ((PPLX_DEV_CTX)(pDev->pCtx))->dwLAS0BA +
        4 * (addrSpace - PLX_ADDR_SPACE0);

    return WDC_WriteAddr32(pDev, PLX_ADDR_REG, dwOffset, (UINT32)dwLocalBase);
}

DWORD PLX_ReadAddrLocalBlock(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, DWORD dwBytes, PVOID pData, WDC_ADDR_MODE mode,
    WDC_ADDR_RW_OPTIONS options)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;

    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    return WDC_ReadAddrBlock(hDev, addrSpace, dwOffset, dwBytes, pData,
        mode, options);
}

DWORD PLX_WriteAddrLocalBlock(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, DWORD dwBytes, PVOID pData, WDC_ADDR_MODE mode,
    WDC_ADDR_RW_OPTIONS options)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;

    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    return WDC_WriteAddrBlock(hDev, addrSpace, dwOffset, dwBytes, pData,
        mode, options);
}

DWORD PLX_ReadAddrLocal8(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, BYTE *pbData)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;
    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    return WDC_ReadAddr8(hDev, addrSpace, dwOffset, pbData);
}

DWORD PLX_WriteAddrLocal8(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, BYTE bData)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;
    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    return WDC_WriteAddr8(hDev, addrSpace, dwOffset, bData);
}

DWORD PLX_ReadAddrLocal16(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, WORD *pwData)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;
    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    return WDC_ReadAddr16(hDev, addrSpace, dwOffset, pwData);
}

DWORD PLX_WriteAddrLocal16(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, WORD wData)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;
    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    return WDC_WriteAddr16(hDev, addrSpace, dwOffset, wData);
}

DWORD PLX_ReadAddrLocal32(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, UINT32 *pu32Data)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;
    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    return WDC_ReadAddr32(hDev, addrSpace, dwOffset, pu32Data);
}

DWORD PLX_WriteAddrLocal32(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, UINT32 u32Data)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;
    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    return WDC_WriteAddr32(hDev, addrSpace, dwOffset, u32Data);
}

DWORD PLX_ReadAddrLocal64(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, UINT64 *pu64Data)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;
    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    
    return WDC_ReadAddr64(hDev, addrSpace, dwOffset, pu64Data);
}

DWORD PLX_WriteAddrLocal64(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
    DWORD dwLocalAddr, UINT64 u64Data)
{
    DWORD dwOffset = MASK_LOCAL(hDev, addrSpace) & dwLocalAddr;
    LocalAddrSetMode(hDev, addrSpace, dwLocalAddr);
    
    return WDC_WriteAddr64(hDev, addrSpace, dwOffset, u64Data);
}

/* -----------------------------------------------
    Access the serial EEPROM
   ----------------------------------------------- */
BOOL PLX_EEPROMIsPresent(WDC_DEVICE_HANDLE hDev)
{
    PPLX_DEV_CTX pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(hDev);
    UINT32 u32CNTRL = 0;
    
    PLX_ReadReg32(hDev, pDevCtx->dwCNTRL, &u32CNTRL);
    return (u32CNTRL & BIT28) == BIT28;
}

/* VPD EEPROM access */
BOOL PLX_EEPROM_VPD_Validate(WDC_DEVICE_HANDLE hDev)
{
    PWDC_DEVICE pDev = (PWDC_DEVICE)hDev;
    BYTE bData = 0;

    TraceLog("PLX_EEPROM_VPD_Validate entered. Device handle 0x%p\n", hDev);
    
    if (!IsValidDevice(pDev, "PLX_EEPROM_VPD_Validate"))
        return FALSE;
    
    /* Verify that a blank or programmed serial EEPROM is present */
    if (!PLX_EEPROMIsPresent(hDev))
    {
        ErrLog("PLX_EEPROM_VPD_Validate: Error - serial EEPROM was not found on board "
            "(handle 0x%p)\n", hDev);
        return FALSE;
    }
        
    /* Check the next capability pointers */
    WDC_PciReadCfg8(hDev, PCI_CAP, &bData);
    if (bData != (BYTE)PLX_PMCAPID)
    {
        ErrLog("PLX_EEPROM_VPD_Validate: NEW_CAP register validation failed\n");
        return FALSE;
    }

    WDC_PciReadCfg8(hDev, PLX_PMNEXT, &bData);
    if (bData != (BYTE)PLX_HS_CAPID)
    {
        ErrLog("PLX_EEPROM_VPD_Validate: PMNEXT register validation failed\n");
        return FALSE;
    }

    WDC_PciReadCfg8(hDev, PLX_HS_NEXT, &bData);
    if (bData != (BYTE)PLX_VPD_CAPID)
    {
        ErrLog("PLX_EEPROM_VPD_Validate: HS_NEXT register validation failed\n");
        return FALSE;
    }

    WDC_PciReadCfg8(hDev, PLX_VPD_NEXT, &bData);
    if (bData != 0)
    {
        ErrLog("PLX_EEPROM_VPD_Validate: VPD_NEXT register validation failed\n");
        return FALSE;
    }

    return TRUE;
}

DWORD PLX_EEPROM_VPD_Read32(WDC_DEVICE_HANDLE hDev, DWORD dwOffset,
    UINT32 *pu32Data)
{
    DWORD i;
    UINT32 u32EnableAccess;
    WORD wAddr, wData;

    if (!IsValidDevice((PWDC_DEVICE)hDev, "PLX_EEPROM_VPD_Read32"))
        return WD_INVALID_PARAMETER;

    if (dwOffset % 4)
    {
        ErrLog("PLX_EEPROM_VPD_Read32: Error - offset (0x%lX) is not a multiple of 4 "
            "(device handle: 0x%p)\n", dwOffset, hDev);
        return WD_INVALID_PARAMETER;
    }

    /* Clear EEDO Input Enable */
    EEPROM_VPD_EnableAccess(hDev, &u32EnableAccess);

    /* Write a destination serial EEPROM address and flag of operation, value of 0 */
    wAddr = (WORD)(dwOffset & ~BIT15);
    WDC_PciWriteCfg16(hDev, PLX_VPD_ADDR, wAddr);

    /* Probe a flag of operation until it changes to a 1 to ensure the Read data is available */
    for (i = 0; i < 10; i++)
    {
        EEPROM_VPD_Delay();
        WDC_PciReadCfg16(hDev, PLX_VPD_ADDR, &wData);
        
        if (wData & BIT15)
            break;
    }
    
    if (i == 10)
    {
        ErrLog("PLX_EEPROM_VPD_Read32: Error - Acknowledge to EEPROM read was not received "
            "(device handle 0x%p)\n", hDev);
        return WD_OPERATION_FAILED;
    }

    /* Read back the requested data from PVPDATA register */
    WDC_PciReadCfg32(hDev, PLX_VPD_DATA, pu32Data);

    /* Restore EEDO Input Enable */
    EEPROM_VPD_RestoreAccess(hDev, u32EnableAccess);
    
    return WD_STATUS_SUCCESS;
}

DWORD PLX_EEPROM_VPD_Write32(WDC_DEVICE_HANDLE hDev, DWORD dwOffset,

⌨️ 快捷键说明

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