// =================================================================
//
//    test98.h
//    This module contains the common private declarations 
//    for the USB Test Device 
//
//    kernel mode only
//
//
// =================================================================

#undef FAR
#define FAR
#undef PHYSICAL_ADDRESS
#define PHYSICAL_ADDRESS LARGE_INTEGER

typedef struct _TEST98_REMOVE_HARDWARE
{
    IN ULONG   Size; // sizeof (struct _REMOVE_HARDWARE)
    IN PVOID   HardwareHandle;
} TEST98_REMOVE_HARDWARE, *PTEST98_REMOVE_HARDWARE;


DEFINE_GUID(GUID_TEST_DEVICE,0xca56030,0x684a,0x11d0,0xd6,
0xf6,0x00,0xc0,0x4f,0xb1,0x72,0x8b);


#define TEST98_POOL_TAG (ULONG) 'emaG'
#undef ExAllocatePool
#define ExAllocatePool(type, size) \
            ExAllocatePoolWithTag (type, size, TEST98_POOL_TAG)


#pragma warning(error:4100)   // Unreferenced formal parameter
#pragma warning(error:4705)   // Statement has no effect


// ===============================================================
// Debugging Output Levels

#define TEST_DBG_PNP_MASK               0x000000F0
#define TEST_DBG_PNP_NOISE              0x00000010
#define TEST_DBG_PNP_TRACE              0x00000020
#define TEST_DBG_PNP_INFO               0x00000040
#define TEST_DBG_PNP_ERROR              0x00000080

#define TEST_DEFAULT_DEBUG_OUTPUT_LEVEL 0xCCCCCC88

#if DBG
#define Test98_KdPrint(_d_,_l_, _x_) \
            if ((_d_)->DebugLevel & (_l_)) { \
               DbgPrint ("Testdrv.SYS: "); \
               DbgPrint _x_; \
            }

#define Test98_KdPrint_Cont(_d_,_l_, _x_) \
            if ((_d_)->DebugLevel & (_l_)) { \
               DbgPrint _x_; \
            }

#define Test98_KdPrint_Def(_l_, _x_) \
            if (TEST_DEFAULT_DEBUG_OUTPUT_LEVEL & (_l_)) { \
               DbgPrint ("Testdrv.SYS: "); \
               DbgPrint _x_; \
            }

#define TRAP() DbgBreakPoint()
#define DbgRaiseIrql(_x_,_y_) KeRaiseIrql(_x_,_y_)
#define DbgLowerIrql(_x_) KeLowerIrql(_x_)
#else

#define Test98_KdPrint(_d_, _l_, _x_)
#define Test98_KdPrint_Cont(_d_, _l_, _x_)
#define Test98_KdPrint_Def(_l_, _x_)
#define TRAP()
#define DbgRaiseIrql(_x_,_y_)
#define DbgLowerIrql(_x_)

#endif

#define MIN(_A_,_B_) (((_A_) < (_B_)) ? (_A_) : (_B_))

// ===================================================================
// A common header for the device extensions 

typedef struct _COMMON_DEVICE_DATA
{
    PDEVICE_OBJECT  Self;
        // A backpointer to the device object for which this is the extension

    CHAR            Reserved[3];
    BOOLEAN         IsFDO;
    ULONG           DebugLevel;

    SYSTEM_POWER_STATE  SystemState;
    DEVICE_POWER_STATE  DeviceState;
} COMMON_DEVICE_DATA, *PCOMMON_DEVICE_DATA;


typedef struct _PDO_DEVICE_DATA
{
    COMMON_DEVICE_DATA;

    PWCHAR      HardwareIDs;
        // An array of (zero terminated wide character strings).
        // The array itself also null terminated

    UCHAR       Reserved2;
    BOOLEAN     Started;
    BOOLEAN     Attached;
    BOOLEAN     Removed;
    
    LIST_ENTRY  Link;
    
} PDO_DEVICE_DATA, *PPDO_DEVICE_DATA;


typedef struct _FDO_DEVICE_DATA
{
    COMMON_DEVICE_DATA;

    KSPIN_LOCK      Spin;
                // A syncronization for access to the device extension.

    BOOLEAN         MappedPorts;
    BOOLEAN         PowerQueryLock;
                // Are we currently in a query power state?
    BOOLEAN         Started;
                // Are we started ?
    BOOLEAN         Removed;
                // Has this device been removed?  
                
    LIST_ENTRY      PDOs;
    ULONG           NumPDOs;
    
    PDEVICE_OBJECT  UnderlyingPDO;
    PDEVICE_OBJECT  TopOfStack;
    
    KEVENT          CallEvent;
        // An event on which to wait for IRPs sent to the lower device objects
        // to complete.

    ULONG           OutstandingIO;
        // the number of IRPs sent from the bus to the underlying device object

    KEVENT          RemoveEvent;
        // On remove device plugplay request we must wait until all outstanding
        // requests have been completed before we can delete the device
        // object.

    UNICODE_STRING DevClassAssocName;
        // The name returned from IoRegisterDeviceClass Association,
        
    PHYSICAL_ADDRESS    PhysicalAddress;
    PVOID               TestPortAddress;

    } FDO_DEVICE_DATA, *PFDO_DEVICE_DATA;


// =================================================================

NTSTATUS
Test98_CreateClose (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

VOID
Test98_DriverUnload (
    IN PDRIVER_OBJECT DriverObject
    );

NTSTATUS
Test98_PnP (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
Test98_Power (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
Test98_AddDevice(
    IN PDRIVER_OBJECT DriverObject,
    IN PDEVICE_OBJECT BusDeviceObject
    );

NTSTATUS
Test98_Remove (
    PTEST98_REMOVE_HARDWARE   Remove,
    PFDO_DEVICE_DATA            DeviceData
    );

NTSTATUS
Test98_PnPRemove (
    PDEVICE_OBJECT      Device,
    PPDO_DEVICE_DATA    PdoData
    );

NTSTATUS
Test98_FDO_PnP (
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp,
    IN PIO_STACK_LOCATION   IrpStack,
    IN PFDO_DEVICE_DATA     DeviceData
    );


NTSTATUS
Test98_StartFdo (
    IN  PFDO_DEVICE_DATA            FdoData,
    IN  PCM_PARTIAL_RESOURCE_LIST   partialResourceList,
    IN  PCM_PARTIAL_RESOURCE_LIST   partialResourceListTranslated
    );

NTSTATUS
Test98_IncIoCount (
    PFDO_DEVICE_DATA   Data
    );

VOID
Test98_DecIoCount (
    PFDO_DEVICE_DATA   Data
    );

NTSTATUS
Test98_FDO_Power (
    PFDO_DEVICE_DATA    FdoData,
    PIRP                Irp
    );


