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

📄 plx_lib.c

📁 PCI口的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/************************************************************************
*  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 + -