#ifndef __DRIVER_DEFS_H
#define __DRIVER_DEFS_H

/*******************************************************************************
 * Copyright (c) PLX Technology, Inc.
 *
 * PLX Technology Inc. licenses this source file under the GNU Lesser General Public
 * License (LGPL) version 2.  This source file may be modified or redistributed
 * under the terms of the LGPL and without express permission from PLX Technology.
 *
 * PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY,
 * EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  PLX makes no guarantee
 * or representations regarding the use of, or the results of the use of,
 * the software and documentation in terms of correctness, accuracy,
 * reliability, currentness, or otherwise; and you rely on the software,
 * documentation and results solely at your own risk.
 *
 * IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
 * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
 * OF ANY KIND.
 *
 ******************************************************************************/

/******************************************************************************
 *
 * File Name:
 *
 *      DrvDefs.h
 *
 * Description:
 *
 *      Common definitions used in the driver
 *
 * Revision History:
 *
 *      05-01-13 : PLX SDK v7.10
 *
 ******************************************************************************/


#include "Plx.h"
#include "PlxTypes.h"




/**********************************************
 *               Definitions
 *********************************************/
#define PLX_DRIVER_NAME                     "Plx8000_NT"
#define PLX_DRIVER_NAME_UNICODE             L"Plx8000_NT"
#define PLX_MAX_NAME_LENGTH                 0x20          // Max length of registered device name
#define DEFAULT_SIZE_COMMON_BUFFER          (8 * 1024)    // Default size of Common Buffer
#define MIN_WORKING_POWER_STATE             PowerDeviceD2 // Minimum state required for local register access


// Set log destination
#if defined(PLX_LOG_TO_FILE)
    #define PLX_DBG_DEST_FILE
#else
    #define PLX_DBG_DEST_DEBUGGER
#endif


// Macros to support Kernel-level logging in Debug builds
#if defined(PLX_DBG_DEST_DEBUGGER)
    #define _PlxDbgFunc                     DbgPrint
#elif defined(PLX_DBG_DEST_FILE)
    #define _PlxDbgFunc                     PlxLogPrintf
    #define PLX_LOG_FILE_UNICODE            L"\\SystemRoot\\Plx8000-NT.log"     // Log file name
#endif

#if defined(PLX_DEBUG)
    #define DebugPrintf(arg)                _Debug_Print_Macro(arg)
    #define DebugPrintf_Cont(arg)           _PlxDbgFunc arg
#else
    #define DebugPrintf(arg)                do { } while(0)
    #define DebugPrintf_Cont(arg)           do { } while(0)
#endif
#define ErrorPrintf(arg)                    _Debug_Print_Macro(arg)
#define ErrorPrintf_Cont(arg)               _PlxDbgFunc arg

#define _Debug_Print_Macro(arg)            \
    do                                     \
    {                                      \
        _PlxDbgFunc(PLX_DRIVER_NAME ": "); \
        _PlxDbgFunc arg;                   \
    }                                      \
    while (0)



// Macros for Memory access to/from user-space addresses
#define DEV_MEM_TO_USER_8( VaUser, VaDev, count)    READ_REGISTER_BUFFER_UCHAR(  (UCHAR*)(VaDev),  (UCHAR*)(VaUser),  (count))
#define DEV_MEM_TO_USER_16(VaUser, VaDev, count)    READ_REGISTER_BUFFER_USHORT((USHORT*)(VaDev), (USHORT*)(VaUser),  (count) >> 1)
#define DEV_MEM_TO_USER_32(VaUser, VaDev, count)    READ_REGISTER_BUFFER_ULONG(  (ULONG*)(VaDev),  (ULONG*)(VaUser),  (count) >> 2)
#define USER_TO_DEV_MEM_8( VaDev, VaUser, count)    WRITE_REGISTER_BUFFER_UCHAR(  (UCHAR*)(VaDev),  (UCHAR*)(VaUser), (count))
#define USER_TO_DEV_MEM_16(VaDev, VaUser, count)    WRITE_REGISTER_BUFFER_USHORT((USHORT*)(VaDev), (USHORT*)(VaUser), (count) >> 1)
#define USER_TO_DEV_MEM_32(VaDev, VaUser, count)    WRITE_REGISTER_BUFFER_ULONG(  (ULONG*)(VaDev),  (ULONG*)(VaUser), (count) >> 2)


// Macros for I/O port access
#define IO_PORT_READ_8(port)                        READ_PORT_UCHAR ( (U8*) (port) )
#define IO_PORT_READ_16(port)                       READ_PORT_USHORT( (U16*)(port) )
#define IO_PORT_READ_32(port)                       READ_PORT_ULONG ( (U32*)(port) )
#define IO_PORT_WRITE_8(port, value)                WRITE_PORT_UCHAR ( (U8*) (port), (value) )
#define IO_PORT_WRITE_16(port, value)               WRITE_PORT_USHORT( (U16*)(port), (value) )
#define IO_PORT_WRITE_32(port, value)               WRITE_PORT_ULONG ( (U32*)(port), (value) )


// Macros for memory access
#define PHYS_MEM_READ_8                             READ_REGISTER_UCHAR
#define PHYS_MEM_READ_16                            READ_REGISTER_USHORT
#define PHYS_MEM_READ_32                            READ_REGISTER_ULONG
#define PHYS_MEM_WRITE_8                            WRITE_REGISTER_UCHAR
#define PHYS_MEM_WRITE_16                           WRITE_REGISTER_USHORT
#define PHYS_MEM_WRITE_32                           WRITE_REGISTER_ULONG

// 64-bit macros not provided by WDK for 32-bit and only Vista WDK or higher
#if !defined(PLX_64BIT) || (WINVER <= 0x0502)
    #define READ_REGISTER_ULONG64(reg)              (*(U64*)(reg))
    #define WRITE_REGISTER_ULONG64(reg, value)      (*(U64*)(reg) = (value))
#endif



// Macros for PLX chip register access
#define PLX_8000_REG_READ(pdx, offset)   \
    PHYS_MEM_READ_32(                    \
        (U32*)((pdx)->pRegVa + (offset)) \
        )

#define PLX_8000_REG_WRITE(pdx, offset, value) \
    PHYS_MEM_WRITE_32(                         \
        (U32*)((pdx)->pRegVa + (offset)),      \
        (value)                                \
        )




/***********************************************************
 * The following definition sets the maximum size that an
 * MDL can describe.  Although not documented in the DDK
 * until recently, the memory allocated for an MDL is 64k,
 * which limits the number of physical page entries allowed
 * after the MDL.
 *
 * Assuming 4k page sizes, the limit calculation yields a
 * size of just under 64MB on a 32-bit system.  On a system with
 * 64-bit addressing, the max size per MDL is less than 32MB.
 * The calculation for determining the max size is:
 *
 *   Total Mem = PAGE_SIZE * ((64k - sizeof(MDL)) / sizeof(PLX_UINT_PTR))
 *
 * The total size is decremented by an additional amount because
 * Windows may still fail mappings in certain cases if the size
 * MAX_MDL_SIZE is too large.
 **********************************************************/
#define MAX_MDL_SIZE                        (PAGE_SIZE * ((65535 - sizeof(MDL)) / sizeof(PLX_UINT_PTR))) - (1 << 21)



/***********************************************************
 * The following definition sets the maximum number of
 * consecutive virtual addresses for a PCI BAR space.  Since
 * individual MDLs are limited to 64MB, when mapping a space
 * to obtain a user-mode virtual address, each individual
 * MDL for a space must be mapped separately.  The virtual
 * addresses must be saved for later unmapping.
 *
 * The following calculation determines the theoretical
 * limitation of a user mapping for a PCI space:
 *
 *   Max mapping size = (Max # virt addresses) * (Max MDL size)
 * 
 * If the max virtual address count is 5, for example, and
 * each MDL is limited to 60MB, the theoretical limit that the
 * driver can map will be a 300MB PCI space.
 *
 * NOTE: Increasing this number has no effect if a mapping
 *       fails due to system resource constraints.  It is
 *       primarily used to store multiple addresses so they
 *       can later be unmapped properly.
 **********************************************************/
#define MAX_VIRTUAL_ADDR                    10      // Max number of virtual addresses for a space



/***********************************************************
 * The following definition determines the maximum size
 * of all contiguous page-locked buffers the driver may try
 * to allocate.
 *
 * The driver allocates a DMA adapter object for each
 * device it owns.  When the adapter object is allocated,
 * with IoGetDmaAdapter, the maximum DMA transfer length must
 * be specified.  During creation of the DMA adapter object,
 * the OS reserves enough resources (i.e. map registers) to
 * handle simultaneously allocated buffers up to the size
 * specified in IoGetDmaAdapter.  Since the DMA Adapter
 * object is used to allocate common buffers, the total
 * size is limited to the DMA length used in IoGetDmaAdapter.
 *
 * In other words, if IoGetDmaAdapter is called with a DMA
 * length of 8MB, the driver can allocate, for example, only
 * two 4MB buffers.  A call to allocate an additional buffer
 * will fail since the 8MB limit is reached.  As a result,
 * the definition below can be set to a large number, such
 * as 100MB, so as not to severely limit buffer allocation.
 *
 * NOTE: The OS will only reserve enough resources to handle
 *       a large-enough buffer.  It will NOT actually reserve
 *       memory.  Available memory is determined at the time
 *       of the allocation request and requests may still
 *       fail, depending upon system resources.
 **********************************************************/
#define PHYS_MEM_MAX_SIZE_ALL               (100 << 20)     // Max total allowable size of physically memory to allocate



// Information stored in Registry
typedef struct _PLX_REGISTRY_INFO
{
    U32 Size_CommonBuffer;
} PLX_REGISTRY_INFO;


// PCI Interrupt wait object
typedef struct _PLX_WAIT_OBJECT
{
    LIST_ENTRY  ListEntry;
    VOID       *pOwner;
    U32         Notify_Flags;                   // Registered interrupt(s) for notification
    U32         Notify_Doorbell;                // Registered doorbell interrupt(s) for notification
    U32         Source_Ints;                    // Interrupt(s) that caused notification
    U32         Source_Doorbell;                // Doorbells that caused notification
    PKEVENT     pKEvent;
} PLX_WAIT_OBJECT;


// Argument for interrupt source access functions
typedef struct _PLX_INTERRUPT_DATA
{
    struct _DEVICE_EXTENSION *pdx;
    U32                       Source_Ints;
    U32                       Source_Doorbell;
} PLX_INTERRUPT_DATA;


// Information about contiguous, page-locked buffers
typedef struct _PLX_PHYS_MEM_OBJECT
{
    LIST_ENTRY   ListEntry;
    VOID        *pOwner;
    U8          *pKernelVa;
    U64          CpuPhysical;                   // CPU Physical Address
    U64          BusPhysical;                   // Bus Physical Address
    U32          Size;                          // Buffer size
    PMDL         pMdl;
    BOOLEAN      bCacheable;
    LIST_ENTRY   List_Mappings;                 // List of mappings for this physical memory
    KSPIN_LOCK   Lock_MappingsList;             // Spinlock for mappings list
} PLX_PHYS_MEM_OBJECT;


// Mappings to user virtual space
typedef struct _PLX_USER_MAPPING
{
    LIST_ENTRY  ListEntry;
    VOID       *pOwner;
    U8          BarIndex;
    VOID       *pUserVa[MAX_VIRTUAL_ADDR];
} PLX_USER_MAPPING;


// PCI BAR Space information
typedef struct _PLX_PCI_BAR_INFO
{
    U8               *pVa;                      // BAR Kernel Virtual Address
    PLX_PCI_BAR_PROP  Properties;               // BAR Properties
    PMDL              pMdl;                     // MDL for the BAR space
} PLX_PCI_BAR_INFO;


// Argument for ISR synchronized register access
typedef struct _PLX_REG_DATA
{
    struct _DEVICE_EXTENSION *pdx;
    U32                       offset;
    U32                       BitsToSet;
    U32                       BitsToClear;
} PLX_REG_DATA;


// All relevant information about the device
typedef struct _DEVICE_EXTENSION
{
    DEVICE_OBJECT      *pDeviceObject;                  // Device object this extension belongs to
    DMA_ADAPTER        *pDmaAdapter;                    // DMA Adapter object for allocating physical memory
    DEVICE_OBJECT      *pLowerDeviceObject;
    DEVICE_OBJECT      *pPhysicalDeviceObject;

    PLX_DEVICE_KEY      Key;                            // Device location & identification
    WCHAR               LinkName[PLX_MAX_NAME_LENGTH];
    PLX_PCI_BAR_INFO    PciBar[PCI_NUM_BARS_TYPE_00];

    DEVICE_POWER_STATE  PowerState;                     // Power management information
    BOOLEAN             bSaveContext;

    PKINTERRUPT         pInterruptObject;
    KDPC                DpcForIsr;
    U32                 Source_Ints;                    // Interrupts detected by ISR
    U32                 Source_Doorbell;                // Doorbell interrupts detected by ISR
    U32                 Offset_DB_IntStatus;            // Offset of doorbell IRQ status register
    U32                 Offset_DB_IntClear;             // Offset of doorbell IRQ clear register
    U32                 Offset_DB_IntMaskSet;           // Offset of doorbell IRQ set mask register
    U32                 Offset_DB_IntMaskClear;         // Offset of doorbell IRQ clear mask register
    U32                 Offset_LE_IntMask;              // Offset of Link Error mask register
    U32                 Offset_LE_IntStatus;            // Offset of Link Error status register

    U8                 *pRegVa;                         // Virtual address to registers
    U32                 Offset_RegBase;                 // The NT register base offset
    U32                 UpstreamBarSize;                // For virtual-side, size of upsteam BAR 0 space

    LIST_ENTRY          List_BarMappings;               // List of mappings to user space
    KSPIN_LOCK          Lock_BarMappingsList;           // Spinlock for user mappings list

    LIST_ENTRY          List_PhysicalMem;               // List of user-allocated physical memory
    KSPIN_LOCK          Lock_PhysicalMemList;           // Spinlock for physical memory list

    LIST_ENTRY          List_WaitObjects;               // List of registered notification objects
    KSPIN_LOCK          Lock_WaitObjectsList;           // Spinlock for notification objects list

} DEVICE_EXTENSION;



#endif
