📄 plx_lib.c
字号:
/************************************************************************
* File: plx_lib.c
*
* Library for accessing PLX devices.
* The code accesses hardware using WinDriver's WDC library.
*
* Copyright (c) 2003 - 2005 Jungo Ltd. http://www.jungo.com
*************************************************************************/
#if !defined (__KERNEL__)
#include <stdio.h>
#include <stdarg.h>
#endif
#include "../../include/wdc_defs.h"
#include "../../include/utils.h"
#include "../../include/status_strings.h"
#include "../../samples/shared/bits.h"
#include "plx_lib.h"
/*************************************************************
Internal definitions
*************************************************************/
/* WinDriver license registration string */
/* TODO: When using a registered WinDriver version, replace the license string
below with your specific WinDriver license registration string */
#define PLX_DEFAULT_LICENSE_STRING "12345abcde1234.license"
/* VPD EEPROM delay */
#define EEPROM_VPD_Delay() WDC_Sleep(20000, WDC_SLEEP_BUSY)
/* Run-time registers EEPROM delay */
#define EEPROM_RT_Delay() WDC_Sleep(500, WDC_SLEEP_BUSY)
/* Soft board reset delay */
#define PLX_SOFT_RESET_DELAY() WDC_Sleep(5000000, WDC_SLEEP_NON_BUSY)
typedef struct {
WD_DMA *pDma;
WD_DMA *pDmaList;
PLX_DMA_CHANNEL dmaChannel;
/* offsets of DMA registers */
DWORD dwDMACSR;
DWORD dwDMAMODE;
DWORD dwDMAPADR;
DWORD dwDMALADR;
DWORD dwDMADPR;
DWORD dwDMASIZ;
} PLX_DMA_STRUCT;
/* PLX device information struct */
typedef struct {
WD_PCI_ID id;
BOOL fIsMaster;
WD_TRANSFER *pIntTransCmds;
PLX_INT_HANDLER funcDiagIntHandler;
PLX_EVENT_HANDLER funcDiagEventHandler;
PLX_DMA_STRUCT *pPLXDma; /* relevant only for master devices */
/* offsets of some useful registers */
DWORD dwINTCSR;
DWORD dwCNTRL;
DWORD dwPROT_AREA;
DWORD dwLAS0BA;
/* TODO: You can add fields to store additional device-specific information */
} PLX_DEV_CTX, *PPLX_DEV_CTX;
/*************************************************************
Global variables definitions
*************************************************************/
/* Last PLX library error string */
CHAR gsPLX_LastErr[256];
/*************************************************************
Static functions prototypes and inline implementation
*************************************************************/
#if !defined (__KERNEL__)
static BOOL IsDeviceValid(const PWDC_DEVICE pDev);
static DWORD DeviceInit(PWDC_DEVICE pDev, BOOL fIsMaster);
static DWORD IntEnableDma(PWDC_DEVICE hDev, PLX_INT_HANDLER funcDiagIntHandler,
PLX_DMA_HANDLE hDma);
static DWORD IntEnable(PWDC_DEVICE hDev, PLX_INT_HANDLER funcDiagIntHandler);
static DWORD IntDisableDma(WDC_DEVICE_HANDLE hDev);
static DWORD IntDisable(WDC_DEVICE_HANDLE hDev);
static void DLLCALLCONV PLX_IntHandlerDma(PVOID pData);
static void DLLCALLCONV PLX_IntHandler(PVOID pData);
static void PLX_EventHandler(WD_EVENT *pEvent, PVOID pData);
#endif
static DWORD LocalAddrSetMode(WDC_DEVICE_HANDLE hDev, PLX_ADDR addrSpace,
DWORD dwLocalAddr);
static DWORD EEPROM_VPD_EnableAccess(WDC_DEVICE_HANDLE hDev, UINT32 *pu32DataOld);
static DWORD EEPROM_VPD_RestoreAccess(WDC_DEVICE_HANDLE hDev, UINT32 u32Data);
static DWORD EEPROM_VPD_RemoveWriteProtection(WDC_DEVICE_HANDLE hDev, WORD wAddr,
PBYTE pbDataOld);
static DWORD EEPROM_VPD_RestoreWriteProtection(WDC_DEVICE_HANDLE Dev, WORD wAddr);
static void EEPROM_RT_ChipSelect(WDC_DEVICE_HANDLE hDev, BOOL fSelect);
static void EEPROM_RT_ReadBit(WDC_DEVICE_HANDLE hDev, BOOL *pBit);
static void EEPROM_RT_WriteBit(WDC_DEVICE_HANDLE hDev, BOOL bit);
static void EEPROM_RT_WriteEnableDisable(WDC_DEVICE_HANDLE hDev, BOOL fEnable);
static void ErrLog(const CHAR *sFormat, ...);
static void TraceLog(const CHAR *sFormat, ...);
static inline BOOL IsValidDevice(PWDC_DEVICE pDev, const CHAR *sFunc)
{
if (!pDev || !(PPLX_DEV_CTX)(pDev->pCtx))
{
snprintf(gsPLX_LastErr, sizeof(gsPLX_LastErr) - 1, "%s: NULL device %s\n",
sFunc, !pDev ? "handle" : "context");
ErrLog(gsPLX_LastErr);
return FALSE;
}
return TRUE;
}
/*************************************************************
Functions implementation
*************************************************************/
/* -----------------------------------------------
PLX and WDC library initialize/uninit
----------------------------------------------- */
DWORD PLX_LibInit(void)
{
DWORD dwStatus;
/* Set WDC library's debug options (default: level TRACE, output to Debug Monitor) */
dwStatus = WDC_SetDebugOptions(WDC_DBG_DEFAULT, NULL);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("Failed to initialize debug options for WDC library.\n"
"Error 0x%lx - %s\n", dwStatus, Stat2Str(dwStatus));
return dwStatus;
}
/* Open a handle to the driver and initialize the WDC library */
dwStatus = WDC_DriverOpen(WDC_DRV_OPEN_DEFAULT, PLX_DEFAULT_LICENSE_STRING);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("Failed to initialize the WDC library. Error 0x%lx - %s\n",
dwStatus, Stat2Str(dwStatus));
return dwStatus;
}
return WD_STATUS_SUCCESS;
}
DWORD PLX_LibUninit(void)
{
DWORD dwStatus;
/* Uninit the WDC library and close the handle to WinDriver */
dwStatus = WDC_DriverClose();
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("Failed to uninit the WDC library. Error 0x%lx - %s\n",
dwStatus, Stat2Str(dwStatus));
}
return dwStatus;
}
BOOL PLX_IsMaster(WDC_DEVICE_HANDLE hDev)
{
PPLX_DEV_CTX pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(hDev);
return pDevCtx->fIsMaster;
}
#if !defined (__KERNEL__)
/* -----------------------------------------------
Device open/close
----------------------------------------------- */
DWORD PLX_DeviceOpenBySlot(WDC_DEVICE_HANDLE *pDeviceHandle, const WD_PCI_SLOT *pSlot, BOOL fIsMaster)
{
DWORD dwStatus;
WD_PCI_CARD_INFO deviceInfo;
PPLX_DEV_CTX pDevCtx = NULL;
WDC_DEVICE_HANDLE hDev = NULL;
/* Retrieve the device's resources information */
BZERO(deviceInfo);
deviceInfo.pciSlot = *pSlot;
dwStatus = WDC_PciGetDeviceInfo(&deviceInfo);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("PLX_DeviceOpenBySlot: Failed retrieving the device's resources information.\n"
"Error 0x%lx - %s\n", dwStatus, Stat2Str(dwStatus));
return dwStatus;
}
/* NOTE: You can modify the device's resources information here, if
necessary (mainly the deviceInfo.Card.Items array or the items number -
deviceInfo.Card.dwItems) in order to register only some of the resources
or register only a portion of a specific address space, for example. */
/* Allocate memory for the PLX device context */
pDevCtx = (PPLX_DEV_CTX)malloc(sizeof (PLX_DEV_CTX));
if (!pDevCtx)
{
ErrLog("PLX_DeviceOpenBySlot: Failed allocating memory for PLX device context\n");
return WD_INSUFFICIENT_RESOURCES;
}
BZERO(*pDevCtx);
/* Open a WDC device handle */
dwStatus = WDC_PciDeviceOpen(&hDev, &deviceInfo, pDevCtx, NULL, NULL, NULL);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("Failed opening a WDC device handle. Error 0x%lx - %s\n",
dwStatus, Stat2Str(dwStatus));
goto Error;
}
*pDeviceHandle = hDev;
/* Validate device information */
if (!IsDeviceValid(hDev))
{
dwStatus = WD_INVALID_PARAMETER;
goto Error;
}
/* Initialize device context and validate device information */
dwStatus = DeviceInit(hDev, fIsMaster);
if (dwStatus)
goto Error;
/* Return handle to the new device */
TraceLog("PLX_DeviceOpenBySlot: Opened a PLX device (handle 0x%p)\n", hDev);
return dwStatus;
Error:
if (hDev)
PLX_DeviceClose(hDev);
else
free(pDevCtx);
return dwStatus;
}
DWORD PLX_DeviceOpen(WDC_DEVICE_HANDLE *pDeviceHandle, DWORD dwVendorID,
DWORD dwDeviceID, DWORD nCardNum, BOOL fIsMaster)
{
DWORD dwStatus;
WDC_PCI_SCAN_RESULT scanResult;
WD_PCI_SLOT *slot;
BZERO(scanResult);
dwStatus = WDC_PciScanDevices(dwVendorID, dwDeviceID, &scanResult);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("PLX_DeviceOpen: Failed scanning the PLX bus.\n"
"Error: 0x%lx - %s\n", dwStatus, Stat2Str(dwStatus));
return dwStatus;
}
if (!scanResult.dwNumDevices || nCardNum >= scanResult.dwNumDevices)
{
ErrLog("PLX_DeviceOpen: No matching PLX device was found for search criteria "
"(Vendor ID 0x%lX, Device ID 0x%lX, Card Nmuber %ld)\n",
dwVendorID, dwDeviceID, nCardNum);
return WD_DEVICE_NOT_FOUND;
}
slot = &scanResult.deviceSlot[nCardNum];
return PLX_DeviceOpenBySlot(pDeviceHandle, slot, fIsMaster);
}
void PLX_DeviceClose(WDC_DEVICE_HANDLE hDev)
{
DWORD dwStatus;
PWDC_DEVICE pDev = (PWDC_DEVICE)hDev;
PPLX_DEV_CTX pDevCtx;
TraceLog("PLX_DeviceClose entered. Device handle: 0x%p\n", hDev);
if (!hDev)
{
ErrLog("PLX_DeviceClose: Error - NULL device handle\n");
return;
}
pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(pDev);
/* Disable interrupts */
if (WDC_IntIsEnabled(hDev))
{
dwStatus = PLX_IntDisable(hDev);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("Failed disabling interrupts. Error 0x%lx - %s\n",
dwStatus, Stat2Str(dwStatus));
}
}
/* Close the device */
dwStatus = WDC_PciDeviceClose(hDev);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("Failed closing a WDC device handle (0x%p). Error 0x%lx - %s\n",
hDev, dwStatus, Stat2Str(dwStatus));
}
/* Free PLX device context memory */
if (pDevCtx)
free(pDevCtx);
}
static BOOL IsDeviceValid(const PWDC_DEVICE pDev)
{
DWORD i, dwNumAddrSpaces = pDev->dwNumAddrSpaces;
/* TODO: Modify the implementation of this function in order to verify
that your device has all expected resources */
/* Verify that the device has at least one active address space */
for (i = 0; i < dwNumAddrSpaces; i++)
{
if (WDC_AddrSpaceIsActive(pDev, i))
return TRUE;
}
ErrLog("Device does not have any active memory or I/O address spaces\n");
return FALSE;
}
static DWORD DeviceInit(PWDC_DEVICE pDev, BOOL fIsMaster)
{
DWORD dwStatus;
WORD wId = 0;
PPLX_DEV_CTX pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(pDev);
/* NOTE: You can modify the implementation of this function in order to
perform any additional device initialization you require */
/* Set device type - master/target */
pDevCtx->fIsMaster = fIsMaster;
/* Set device ID */
dwStatus = WDC_PciReadCfg16(pDev, PCI_VID, &wId);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("Failed reading the vendor ID from the configuration registers\n");
return dwStatus;
}
pDevCtx->id.dwVendorId = wId;
dwStatus = WDC_PciReadCfg16(pDev, PCI_DID, &wId);
if (WD_STATUS_SUCCESS != dwStatus)
{
ErrLog("Failed reading the device ID from the configuration registers\n");
return dwStatus;
}
pDevCtx->id.dwDeviceId = wId;
/* Set specific registers infomation */
/* [DMA registers information (for master devices) will be set in PLX_DMAOpen()] */
if (fIsMaster)
{
pDevCtx->dwINTCSR = PLX_M_INTCSR;
pDevCtx->dwCNTRL = PLX_M_CNTRL;
pDevCtx->dwPROT_AREA = PLX_M_PROT_AREA;
pDevCtx->dwLAS0BA = PLX_M_LAS0BA;
}
else
{
pDevCtx->dwINTCSR = PLX_T_INTCSR;
pDevCtx->dwCNTRL = PLX_T_CNTRL;
pDevCtx->dwPROT_AREA = PLX_T_PROT_AREA;
pDevCtx->dwLAS0BA = PLX_T_LAS0BA;
}
/* Enable target abort for master devices */
if (fIsMaster)
{
UINT32 u32IntStatus = 0;
PLX_ReadReg32(pDev, PLX_M_INTCSR, &u32IntStatus);
PLX_WriteReg32(pDev, PLX_M_INTCSR, u32IntStatus | BIT12);
}
return dwStatus;
}
/* -----------------------------------------------
Interrupts
----------------------------------------------- */
static void DLLCALLCONV PLX_IntHandlerDma(PVOID pData)
{
/* TODO: Modify the interrupt handler code to suit your specific needs */
PWDC_DEVICE pDev = (PWDC_DEVICE)pData;
PPLX_DEV_CTX pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(pDev);
PLX_INT_RESULT intResult;
/* Flush the DMA data from IO cache and update the CPU caches. */
PLX_DMASyncIo((PLX_DMA_HANDLE)pDevCtx->pPLXDma);
BZERO(intResult);
intResult.u32INTCSR = pDevCtx->pIntTransCmds[0].Data.Dword;
intResult.bDMACSR = pDevCtx->pIntTransCmds[1].Data.Byte;
intResult.dwCounter = pDev->Int.dwCounter;
intResult.dwLost = pDev->Int.dwLost;
intResult.waitResult = (WD_INTERRUPT_WAIT_RESULT)pDev->Int.fStopped;
/* Execute the diagnostics application's interrupt handler routine */
pDevCtx->funcDiagIntHandler(pDev, &intResult);
}
static void DLLCALLCONV PLX_IntHandler(PVOID pData)
{
/* TODO: Modify the interrupt handler code to suit your specific needs */
PWDC_DEVICE pDev = (PWDC_DEVICE)pData;
PPLX_DEV_CTX pDevCtx = (PPLX_DEV_CTX)WDC_GetDevContext(pDev);
PLX_INT_RESULT intResult;
BZERO(intResult);
intResult.u32INTCSR = pDevCtx->pIntTransCmds[0].Data.Word;
intResult.dwCounter = pDev->Int.dwCounter;
intResult.dwLost = pDev->Int.dwLost;
intResult.waitResult = (WD_INTERRUPT_WAIT_RESULT)pDev->Int.fStopped;
/* Execute the diagnostics application's interrupt handler routine */
pDevCtx->funcDiagIntHandler(pDev, &intResult);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -