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

📄 plx_lib.c

📁 PCI口的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
}

static DWORD IntEnableDma(PWDC_DEVICE pDev, PLX_INT_HANDLER funcDiagIntHandler,
    PLX_DMA_HANDLE hDma)
{
    DWORD dwStatus;
    PPLX_DEV_CTX pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(pDev);
    WDC_ADDR_DESC *pAddrDesc;
    WD_TRANSFER *pTrans;
    UINT32 u32INTCSR = 0;
    UINT32 u32DMAMODE = 0;
    PLX_DMA_STRUCT *pPLXDma = (PLX_DMA_STRUCT*)hDma;
 
    /* Validate DMA handle and verify that DMA is open */
    if (!pPLXDma || !pPLXDma->pDma)
    {
        ErrLog("IntEnableDma: Error - %s (Device handle 0x%p, DMA handle 0x%p)\n",
            !pPLXDma ? "NULL DMA handle (pData)" : "DMA is not open", pDev, pPLXDma);
        return WD_INVALID_PARAMETER;
    }

    /* Define the number of interrupt transfer commands to use */
    #define NUM_TRANS_CMDS_MASTER 3
     
    /* Allocate memory for the interrupt transfer commands */
    pTrans = (WD_TRANSFER*)calloc(NUM_TRANS_CMDS_MASTER, sizeof(WD_TRANSFER));
    if (!pTrans)
    {
        ErrLog("Failed allocating memory for interrupt transfer commands\n");
        return WD_INSUFFICIENT_RESOURCES;
    }

    /* Prepare the interrupt transfer commands */
    /* The transfer commands will be executed by WinDriver in the kernel
       for each interrupt that is received */
    
    pAddrDesc = &pDev->pAddrDesc[PLX_ADDR_REG];

    /* #1: Read interrupt status from the INTCSR register */
    pTrans[0].dwPort = pAddrDesc->kptAddr + pDevCtx->dwINTCSR;
    pTrans[0].cmdTrans = WDC_ADDR_IS_MEM(pAddrDesc) ? RM_DWORD : RP_DWORD;

    /* #2: Read DMA status from the DMACSR register */
    pTrans[1].dwPort = pAddrDesc->kptAddr + pPLXDma->dwDMACSR;
    pTrans[1].cmdTrans = WDC_ADDR_IS_MEM(pAddrDesc) ? RM_BYTE : RP_BYTE;
    
    /* #3: Write to the DMACSR register to clear the DMA DONE interrupt */
    pTrans[2].dwPort = pTrans[1].dwPort;
    pTrans[2].cmdTrans = WDC_ADDR_IS_MEM(pAddrDesc) ? WM_BYTE : WP_BYTE;
    pTrans[2].Data.Byte = (BYTE)BIT3;

    /* Init the diag interrupt handler routine, which will be executed by
       PLX_IntHandler() when an interrupt is received */
    pDevCtx->funcDiagIntHandler = funcDiagIntHandler;
    
    /* Enable the interrupts */
    dwStatus = WDC_IntEnable(pDev, pTrans, NUM_TRANS_CMDS_MASTER,
        INTERRUPT_CMD_COPY, PLX_IntHandlerDma, (PVOID)pDev, FALSE);
        
    if (WD_STATUS_SUCCESS != dwStatus)
    {
        ErrLog("IntEnableDma: Failed enabling interrupts (vid 0x%lX did 0x%lX, handle 0x%p).\n"
            "Error 0x%lx - %s\n",
            pDevCtx->id.dwVendorId, pDevCtx->id.dwDeviceId, pDev, dwStatus, Stat2Str(dwStatus));

        goto Error;
    }

    /* Physically enable the interrupts on the board */
    /* DMA DONE interrupt enable, route DMA channel interrupt to PCI interrupt */
    PLX_ReadReg32(pDev, pPLXDma->dwDMAMODE, &u32DMAMODE);
    PLX_WriteReg32(pDev, pPLXDma->dwDMAMODE, u32DMAMODE | BIT10 | BIT17);
    /* PCI interrupt enable, DMA channel local interrupt enable */
    PLX_ReadReg32(pDev, pDevCtx->dwINTCSR, &u32INTCSR);
    PLX_WriteReg32(pDev, pDevCtx->dwINTCSR,
        u32INTCSR | BIT8 | ((PLX_DMA_CHANNEL_0 == pPLXDma->dmaChannel) ? BIT18 : BIT19));

    /* Store the interrupt transfer commands in the device context */
    pDevCtx->pIntTransCmds = pTrans;

    return WD_STATUS_SUCCESS;

Error:
    if (pTrans)
        free(pTrans);

    return dwStatus;
}

static DWORD IntEnable(PWDC_DEVICE pDev, PLX_INT_HANDLER funcDiagIntHandler)
{
    DWORD dwStatus;
    PPLX_DEV_CTX pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(pDev);
    WDC_ADDR_DESC *pAddrDesc;
    WD_TRANSFER *pTrans;
    WORD wINTCSR = 0;
    
    /* Define the number of interrupt transfer commands to use */
    #define NUM_TRANS_CMDS_TARGET 2
     
    /* Allocate memory for the interrupt transfer commands */
    pTrans = (WD_TRANSFER*)calloc(NUM_TRANS_CMDS_TARGET, sizeof(WD_TRANSFER));
    if (!pTrans)
    {
        ErrLog("Failed allocating memory for interrupt transfer commands\n");
        return WD_INSUFFICIENT_RESOURCES;
    }
    
    /* Read the value of the INTCSR register */
    dwStatus = PLX_ReadReg16(pDev, pDevCtx->dwINTCSR, &wINTCSR);
    if (WD_STATUS_SUCCESS != dwStatus)
    {
        ErrLog("IntEnable: Failed reading from the INTCSR register "
            "(vid 0x%lX did 0x%lX, handle 0x%p)\n"
            "Error 0x%lx - %s\n",
            pDevCtx->id.dwVendorId, pDevCtx->id.dwDeviceId, pDev, dwStatus, Stat2Str(dwStatus));
        goto Error;
    }

    /* Prepare the interrupt transfer commands */
    /* The transfer commands will be executed by WinDriver in the kernel
       for each interrupt that is received */
    
    /* #1: Read status from the INTCSR register */
    pAddrDesc = &pDev->pAddrDesc[PLX_ADDR_REG];
    pTrans[0].dwPort = pAddrDesc->kptAddr + pDevCtx->dwINTCSR;
    pTrans[0].cmdTrans = WDC_ADDR_IS_MEM(pAddrDesc) ? RM_WORD : RP_WORD;

    /* #2: Write to the INTCSR register to clear the interrupt */
    pTrans[1].dwPort = pTrans[0].dwPort;
    pTrans[1].cmdTrans = WDC_ADDR_IS_MEM(pAddrDesc) ? WM_WORD : WP_WORD;
    pTrans[1].Data.Word = wINTCSR & ~(BIT8 | BIT10);

    /* Store the diag interrupt handler routine, which will be executed by
       PLX_IntHandler() when an interrupt is received */
    pDevCtx->funcDiagIntHandler = funcDiagIntHandler;
    
    /* Enable the interrupts */
    dwStatus = WDC_IntEnable(pDev, pTrans, NUM_TRANS_CMDS_TARGET,
        INTERRUPT_CMD_COPY, PLX_IntHandler, (PVOID)pDev, FALSE);
        
    if (WD_STATUS_SUCCESS != dwStatus)
    {
        ErrLog("IntEnable: Failed enabling interrupts (vid 0x%lX did 0x%lX, handle 0x%p).\n"
            "Error 0x%lx - %s\n",
            pDevCtx->id.dwVendorId, pDevCtx->id.dwDeviceId, pDev, dwStatus, Stat2Str(dwStatus));

        goto Error;
    }

    /* Physically enable the interrupts on the board */
    dwStatus = PLX_WriteReg16(pDev, pDevCtx->dwINTCSR, (WORD)(wINTCSR | BIT8 | BIT10));    
    if (WD_STATUS_SUCCESS != dwStatus)
    {
        ErrLog("IntEnable: Faild writing to the INTCSR register to physically enable "
            "the interrupts on the board (vid 0x%lX did 0x%lX, handle 0x%p)\n"
        "Error 0x%lx - %s\n",
        pDevCtx->id.dwVendorId, pDevCtx->id.dwDeviceId, pDev, dwStatus, Stat2Str(dwStatus));
        goto Error;
    }

    /* Store the interrupt transfer commands in the device context */
    pDevCtx->pIntTransCmds = pTrans;

    return WD_STATUS_SUCCESS;
    
Error:
    if (pTrans)
        free(pTrans);

    return dwStatus;
}

DWORD PLX_IntEnable(WDC_DEVICE_HANDLE hDev, PLX_INT_HANDLER funcDiagIntHandler,
    PVOID pData)
{
    DWORD dwStatus;
    PWDC_DEVICE pDev = (PWDC_DEVICE)hDev;

    TraceLog("PLX_IntEnable entered. Device handle: 0x%p\n", hDev);

    if (!IsValidDevice(pDev, "PLX_IntEnable"))
        return WD_INVALID_PARAMETER;

    /* Check if interrupts are already enabled */
    if (WDC_IntIsEnabled(hDev))
    {
        ErrLog("Interrupts are already enabled ...\n");
        return WD_OPERATION_ALREADY_DONE;
    }
   
    dwStatus = ((PPLX_DEV_CTX)(pDev->pCtx))->fIsMaster ?
        IntEnableDma(pDev, funcDiagIntHandler, pData) :
        IntEnable(pDev, funcDiagIntHandler);

    if (WD_STATUS_SUCCESS == dwStatus)
        TraceLog("PLX_IntEnable: Interrupts enabled\n");

    return dwStatus;
}

static DWORD IntDisableDma(WDC_DEVICE_HANDLE hDev)
{
    UINT32 u32INTCSR = 0, u32DMAMODE = 0;

    PLX_ReadReg32(hDev, PLX_M_INTCSR, &u32INTCSR);
    PLX_WriteReg32(hDev, PLX_M_INTCSR,
        u32INTCSR & ~(BIT8 | BIT18 | BIT19));

    PLX_ReadReg32(hDev, PLX_M_DMAMODE0, &u32DMAMODE);
    PLX_WriteReg32(hDev, PLX_M_DMAMODE0, u32DMAMODE & ~BIT10);

    PLX_ReadReg32(hDev, PLX_M_DMAMODE1, &u32DMAMODE);
    PLX_WriteReg32(hDev, PLX_M_DMAMODE1, u32DMAMODE & ~BIT10);
    
    return WD_STATUS_SUCCESS;
}

static DWORD IntDisable(WDC_DEVICE_HANDLE hDev)
{
    WORD wINTCSR = 0;

    PLX_ReadReg16(hDev, PLX_T_INTCSR, &wINTCSR);
    PLX_WriteReg16(hDev, PLX_T_INTCSR, (WORD)(wINTCSR & ~(BIT8 | BIT10)));

    return WD_STATUS_SUCCESS;
}

DWORD PLX_IntDisable(WDC_DEVICE_HANDLE hDev)
{
    DWORD dwStatus;
    PWDC_DEVICE pDev = (PWDC_DEVICE)hDev;
    PPLX_DEV_CTX pDevCtx;

    TraceLog("PLX_IntDisable entered. Device handle: 0x%p\n", hDev);

    if (!IsValidDevice(pDev, "PLX_IntDisable"))
        return WD_INVALID_PARAMETER;

    pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(hDev);
 
    if (!WDC_IntIsEnabled(hDev))
    {
        ErrLog("Interrupts are already disabled ...\n");
        return WD_OPERATION_ALREADY_DONE;
    }

    /* Physically disable the interrupts on the board */
    dwStatus = ((PPLX_DEV_CTX)(pDev->pCtx))->fIsMaster ?
        IntDisableDma(hDev) : IntDisable(hDev);

    if (WD_STATUS_SUCCESS == dwStatus)
        TraceLog("PLX_IntEnable: Physically disabled the interrupts on the board\n");

    /* Disable the interrupts */
    dwStatus = WDC_IntDisable(hDev);
    if (WD_STATUS_SUCCESS != dwStatus)
    {
        ErrLog("Failed disabling interrupts. Error 0x%lx - %s\n",
            dwStatus, Stat2Str(dwStatus));
    }

    /* Free the memory allocated for the interrupt transfer commands */
    if (pDevCtx->pIntTransCmds)
    {
        free(pDevCtx->pIntTransCmds);
        pDevCtx->pIntTransCmds = NULL;
    }

    return dwStatus;
}

BOOL PLX_IntIsEnabled(WDC_DEVICE_HANDLE hDev)
{
    if (!IsValidDevice((PWDC_DEVICE)hDev, "PLX_IntIsEnabled"))
        return FALSE;

    return WDC_IntIsEnabled(hDev);
}

/* -----------------------------------------------
    Plug-and-play and power management events
   ----------------------------------------------- */
static void PLX_EventHandler(WD_EVENT *pEvent, PVOID pData)
{
    PWDC_DEVICE pDev = (PWDC_DEVICE)pData;
    PPLX_DEV_CTX pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(pDev);

    TraceLog("PLX_EventHandler entered, pData 0x%p, dwAction 0x%lx\n",
        pData, pEvent->dwAction);
    
    /* Execute the diagnostics application's event handler function */
    pDevCtx->funcDiagEventHandler(pDev, pEvent->dwAction);
}

DWORD PLX_EventRegister(WDC_DEVICE_HANDLE hDev, PLX_EVENT_HANDLER funcEventHandler)
{
    DWORD dwStatus;
    PWDC_DEVICE pDev = (PWDC_DEVICE)hDev;
    PPLX_DEV_CTX pDevCtx;
    DWORD dwActions = WD_ACTIONS_ALL;
    /* TODO: Modify the above to set up the plug-and-play/power management
             events for which you wish to receive notifications.
             dwActions can be set to any combination of the WD_EVENT_ACTION
             flags defined in windrvr.h */

    TraceLog("PLX_EventRegister entered. Device handle: 0x%p\n", hDev);
    
    if (!IsValidDevice(pDev, "PLX_EventRegister"))
        return WD_INVALID_PARAMETER;

    pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(hDev);

    /* Check if event is already registered */
    if (WDC_EventIsRegistered(hDev))
    {
        ErrLog("Events are already registered ...\n");
        return WD_OPERATION_ALREADY_DONE;
    }

    /* Store the diag event handler routine to be executed from PLX_EventHandler() upon an event */
    pDevCtx->funcDiagEventHandler = funcEventHandler;

    /* Register event */
    dwStatus = WDC_EventRegister(hDev, dwActions, PLX_EventHandler, hDev, FALSE);
    
    if (WD_STATUS_SUCCESS != dwStatus)
    {
        ErrLog("Failed to register events. Error 0x%lx - %s\n",
            dwStatus, Stat2Str(dwStatus));
        return dwStatus;
    }

    TraceLog("Events registered\n");

    return WD_STATUS_SUCCESS;
}

DWORD PLX_EventUnregister(WDC_DEVICE_HANDLE hDev)
{
    DWORD dwStatus;
    
    TraceLog("PLX_EventUnregister entered. Device handle: 0x%p\n", hDev);
    
    if (!IsValidDevice((PWDC_DEVICE)hDev, "PLX_EventUnregister"))
        return WD_INVALID_PARAMETER;

    if (!WDC_EventIsRegistered(hDev))
    {
        ErrLog("Cannot unregister events - no events currently registered ...\n");
        return WD_OPERATION_ALREADY_DONE;
    }

    dwStatus = WDC_EventUnregister(hDev);
    
    if (WD_STATUS_SUCCESS != dwStatus)
    {
        ErrLog("Failed to unregister events. Error 0x%lx - %s\n",
            dwStatus, Stat2Str(dwStatus));
    }

    return dwStatus;
}

BOOL PLX_EventIsRegistered(WDC_DEVICE_HANDLE hDev)
{
    if (!IsValidDevice((PWDC_DEVICE)hDev, "PLX_EventIsRegistered"))
        return FALSE;

    return WDC_EventIsRegistered(hDev);
}

/* -----------------------------------------------
    DMA (Direct Memory Access)
   ----------------------------------------------- */
DWORD PLX_DMAOpen(WDC_DEVICE_HANDLE hDev, UINT32 u32LocalAddr, PVOID *ppBuf,
    DWORD dwOptions, DWORD dwBytes, WDC_ADDR_MODE mode,
    PLX_DMA_CHANNEL dmaChannel, PLX_DMA_HANDLE *ppDmaHandle)
{
    DWORD dwStatus;
    PPLX_DEV_CTX pDevCtx;
    UINT32 u32DMAMODE;
    BOOL fAutoinc = TRUE;
    PLX_DMA_STRUCT *pPLXDma = NULL;
    BOOL fSG = !(dwOptions & DMA_KERNEL_BUFFER_ALLOC);
    BOOL fIsRead = dwOptions & DMA_READ_FROM_DEVICE ? TRUE : FALSE;

    TraceLog("PLX_DMAOpen entered. Device handle: 0x%p\n", hDev);
    
    if (!IsValidDevice((PWDC_DEVICE)hDev, "PLX_DMAOpen"))
        return WD_INVALID_PARAMETER;
    
    if (!ppBuf)
    {
        ErrLog("PLX_DMAOpen: Error - NULL DMA buffer pointer\n");
        return WD_INVALID_PARAMETER;
    }

    pPLXDma = (PLX_DMA_STRUCT*)malloc(sizeof(PLX_DMA_STRUCT));
    if (!pPLXDma)
    {
        ErrLog("PLX_DMAOpen: Failed allocating memory for PLX DMA struct\n");
        return WD_INSUFFICIENT_RESOURCES;
    }
    BZERO(*pPLXDma);
    
    /* Allocate and lock a DMA buffer */
    dwStatus = fSG ?
        WDC_DMASGBufLock(hDev, *ppBuf, dwOptions, dwBytes, &pPLXDma->pDma) :
        WDC_DMAContigBufLock(hDev, ppBuf, dwOptions, dwBytes, &pPLXDma->pDma);

    if (WD_STATUS_SUCCESS != dwStatus) 
    {
        ErrLog("PLX_DMAOpen: Failed locking a DMA buffer. Error 0x%lX - %s\n",
            dwStatus, Stat2Str(dwStatus));
        goto Error;
    }

    pPLXDma->dmaChannel = dmaChannel;

    /* Set DMA registers information */
    pPLXDma->dwDMACSR = (PLX_DMA_CHANNEL_0 == dmaChannel ? PLX_M_DMACSR0 : PLX_M_DMACSR1);
    pPLXDma->dwDMAMODE = (PLX_DMA_CHANNEL_0 == dmaChannel ? PLX_M_DMAMODE0 : PLX_M_DMAMODE1);
    pPLXDma->dwDMAPADR = (PLX_DMA_CHANNEL_0 == dmaChannel ? PLX_M_DMAPADR0 : PLX_M_DMAPADR1);
    pPLXDma->dwDMALADR = (PLX_DMA_CHANNEL_0 == dmaChannel ? PLX_M_DMALADR0 : PLX_M_DMALADR1);
    pPLXDma->dwDMADPR = (PLX_DMA_CHANNEL_0 == dmaChannel ? PLX_M_DMADPR0 : PLX_M_DMADPR1);
    pPLXDma->dwDMASIZ = (PLX_DMA_CHANNEL_0 == dmaChannel ? PLX_M_DMASIZ0 : PLX_M_DMASIZ1);

    /* Common settings for chain and direct DMA */
    u32DMAMODE = 
        (fAutoinc ? 0 : BIT11) 
        | BIT6 /* Enable Ready input */
        | BIT8 /* Local burst */
        | ((WDC_MODE_8 == mode) ? 0 : (WDC_MODE_16 == mode) ? BIT0 : (BIT1 | BIT0));
    
    if (pPLXDma->pDma->dwPages == 1)
    {

⌨️ 快捷键说明

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