📄 plx_lib.c
字号:
}
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 + -