//{ **************************************************************************** }
//{ FileName............: DRIVER.H                                               }
//{ Project.............: FLEXCOP                                                }
//{ Author(s)...........: M.Majoor                                               }
//{ Original contents...: Walter Oney ('Programming the Windows Driver Model')   }
//{ Version.............: 1.01                                                   }
//{ ---------------------------------------------------------------------------- }
//{ Declarations for FLEXCOP driver.                                             }
//{                                                                              }
//{ Version  Date      Comment                                                   }
//{ 1.00     20050410  - Initial release based on SAA7146A driver V2.02          }
//{ 1.01     20050428  - Minor changes to compile with Windows Server 2003 DDK   }
//{ **************************************************************************** }


#ifndef DRIVER_H
  #define DRIVER_H
  #include "DevQueue.h"

  #define DRIVERNAME   "FLEXCOP"                           // For use in messages
  #define LDRIVERNAME L"FLEXCOP"                           // For use in UNICODE string constants

  #define COMMONBUFFERSIZE (64 * PAGE_SIZE)                // Maximum size allowed for common DMA buffers
  #define DMABUFFERS   256                                 // Different individual DMA buffers we can allocate
  #define FIFOBUFFERS  256                                 // Max number of individual FIFO buffers we can use
  #define IRQBUFFERS   12                                  // Number of IRQ buffers

  // Device states
  enum DEVSTATE
  {
    STOPPED,                                               // Device stopped
    WORKING,                                               // Started and working
    PENDINGSTOP,                                           // Stop pending
    PENDINGREMOVE,                                         // Remove pending
    SURPRISEREMOVED,                                       // Removed by surprise
    REMOVED,                                               // Removed
  };

  // Structure used to hold DMA buffer information
  typedef struct _DMABUFFER
  {
    LONG             bufferId;                             // Identification of buffer (in use)
    PVOID            vaBuffer;                             // Virtual address buffer
    PHYSICAL_ADDRESS paBuffer;                             // Physical address buffer
    ULONG            buffersize;                           // Size of buffer (in bytes)
  } DMABUFFER, *PDMABUFFER;

  // Structure used to hold FIFO buffer information
  typedef struct _FIFOBUFFER
  {
    LONG             bufferId;                             // Identification of buffer (in use)
    PVOID            vaBuffer;                             // Virtual address allocated FIFO buffer
                                                           // Also used to hold the redirection FIFO buffer
    PVOID            vaBufferSource[2];                    // Virtual address source buffer to copy from
    ULONG            bufferSize;                           // Size of buffer (also copy size)
    UCHAR            irqBuffer;                            // Linked to which IRQ buffer
    BOOLEAN          writeTag;                             // Flag indicating buffer written
    ULONG            bufferIrqsActiveReceived;             // Copy of <irqsActiveReceived> counter when FIFO was written
    ULONG            bufferOverflows;                      // Counter incremented when written to buffer with <writeTag> TRUE
  } FIFOBUFFER, *PFIFOBUFFER;

  // Structure used to hold IRQ information
  // Each interrupt can signal something, so a RPS program
  // can be informed about a specific interrupt being generated.
  // An interrupt can also trigger a buffering action. It uses the FIFO buffers for this.
  // A buffering action always copies a complete buffer (<bufferSize> of FIFOBUFFER).
  typedef struct _IRQBUFFER
  {
    ULONG            irqsReceived;                         // Counter incremented for each interrupt of this type
    ULONG            irqsActiveReceived;                   // Counter incremented for each interrupt of this type when active
    BOOLEAN          active;                               // Global activation flag of the interrupt
    BOOLEAN          eventActive;                          // Indicates notify event to be triggered
    BOOLEAN          signalActive;                         // Indicates SIGx to be triggered
    BOOLEAN          fifoActive;                           // Indicates FIFO to be used
    BOOLEAN          irqAutoDisable;                       // NOT SUPPORTED

    ULONG            signalRegister;                       // FLEXCOP register to read and write back for banking info
    ULONG            signalAnd;                            // AND operation to perform on register contents to extract bit
    ULONG            signalOr;                             // OR  peration to perform on ANDED register contents to extract bit
    ULONG            signalXor;                            // XOR (invert) operation to perform on ANDED and ORED register contents to write bit

    UCHAR            fifoBufferPrevious;                   // Previous FIFO used (index FIFO buffer array)
    UCHAR            fifoBufferFirst;                      // First FIFO to use (index FIFO buffer array)
    UCHAR            fifoBufferLast;                       // Last  FIFO to use (index FIFO buffer array)
    ULONG            fifoBufferCirculated;                 // Counter incremented each time <fifoBufferNext> == <fifoBufferStart>
    ULONG            fifoOverflows;                        // Counter incremented each time a FIFO <writeTag> was still set when written to it
  } IRQBUFFER, *PIRQBUFFER;

  // Device extenstion
  typedef struct _DEVICE_EXTENSION
  {
    PDEVICE_OBJECT      DeviceObject;                      // Device object this extension belongs to
    PDEVICE_OBJECT      LowerDeviceObject;                 // Next lower driver in same stack
    PDEVICE_OBJECT      Pdo;                               // The Physical Device Object
    IO_REMOVE_LOCK      RemoveLock;                        // Removal control locking structure
    UNICODE_STRING      ifname;                            // Interface name
    DEVSTATE            state;                             // Current state of device
    DEVSTATE            prevstate;                         // State prior to removal query
    DEVICE_POWER_STATE  devpower;                          // Current device power state
    SYSTEM_POWER_STATE  syspower;                          // Current system power state
    DEVICE_CAPABILITIES devcaps;                           // Copy of most recent device capabilities
    LIST_ENTRY          PendingIoctlList;                  // Listing of pending async IOCTLs
    KSPIN_LOCK          IoctlListLock;                     // Spin lock to guard PendingIoctlList
    NTSTATUS            IoctlAbortStatus;                  // Status being used to abort pending IOCTLs

    // Next are for handling event notification to the application
    LONG                handles;                           // # open handles
    PIRP                NotifyIrp;                         // Pending notification IRP (neede if we want to remove it using a IOCTL)
    KSPIN_LOCK          lockHandles;                       // Lock for handles list
    LIST_ENTRY          hlist;                             // Anchor of handle object list

    // The single event notification which can be used by a single application
    PKEVENT             pevent;                            // Registered event object (if any)

    // Specific stuff for the FLEXCOP driver
    LONG            InterruptCount;                        // Counter incremented for each interrupt
    ULONG           ISR;                                   // Interrupt Service Register

    // TODO Instead of using a single DEVQUEUE for both reads and writes, you could
    // create several queues and define an array of pointers to them. I.e.:
    //	DEVQUEUE dqRead;
    //	DEVQUEUE dqWrite;
    //	PDEVQUEUE queues[2];

    DEVQUEUE        dqReadWrite;                           // Queue for reads and writes
    PKINTERRUPT     InterruptObject;                       // Address of interrupt object
    PUCHAR          membase;                               // Mapped memory base address
    ULONG           memsize;                               // Size of mapped memory area
    PADAPTER_OBJECT AdapterObject;                         // DMA adapter object
    ULONG           nMapRegisters;                         // Maximum # mapping registers

    ULONG xfer;                                            // # bytes to transfer in this stage
    ULONG numxfer;                                         // # bytes transferred so far
    ULONG nbytes;                                          // # bytes remaining to transfer
    ULONG nMapRegistersAllocated;                          // # map registers allocated for this transfer
    PVOID vaddr;                                           // Virtual addr for this stage of transfer
    PVOID regbase;                                         // Handle for base of mapping register set

    // DMA common buffer
    DMABUFFER       dmaBuffers[DMABUFFERS];                // Allow .. DMA buffers to be allocated

    FIFOBUFFER      fifoBuffers[FIFOBUFFERS];              // Allow .. FIFO buffers to be allocated
    ULONG           fifoOverflows;                         // Count the global FIFO overflows (written to a buffer which was not read)

    IRQBUFFER       irqBuffers[IRQBUFFERS];                // There are a total of 32 possible interrupt sources

    ULONG  Dma1Sub0;                                       // Retained value DMA1 sub buffer 0
    ULONG  Dma1Sub1;                                       // Retained value DMA1 sub buffer 1
    ULONG  Dma1SubLargest;                                 // Largest of the two sub buffer address (used in selection process)
    CHAR   Dma1SubLargestOrder[2];                         // Indicates order of subbuffers, value is 0 or 1, [1] = associated with DmaXSubLargest
    ULONG  Dma2Sub0;                                       // Retained value DMA2 sub buffer 0
    ULONG  Dma2Sub1;                                       // Retained value DMA2 sub buffer 1
    ULONG  Dma2SubLargest;                                 // Largest of the two sub buffer address (used in selection process)
    CHAR   Dma2SubLargestOrder[2];                         // Indicates order of subbuffers, value is 0 or 1. [1] = associated with DmaXSubLargest

    // TODO add additional per-device declarations

    BOOLEAN busy;                                          // True if device busy with a request
    BOOLEAN StalledForPower;                               // Power management has stalled IRP queue
    } DEVICE_EXTENSION, *PDEVICE_EXTENSION;

  // Structure for handling event notifications to application
  typedef struct _HANDLE_OBJECT
  {
    LONG         refcnt;                                   // Reference count
    LIST_ENTRY   link;                                     // Linking field for pdx->handles list
    PKEVENT      pevent;                                   // Registered event object (if any)
    PFILE_OBJECT FileObject;                               // File object for which handle opened
  } HANDLE_OBJECT, *PHANDLE_OBJECT;

  PHANDLE_OBJECT FindHandle       (PDEVICE_EXTENSION pdx, PFILE_OBJECT fop);
  VOID           ReleaseHandle    (PHANDLE_OBJECT hop);

  VOID     RemoveDevice           (IN PDEVICE_OBJECT fdo);
  NTSTATUS CompleteRequest        (IN PIRP Irp, IN NTSTATUS status, IN ULONG_PTR info);
  NTSTATUS CompleteRequest        (IN PIRP Irp, IN NTSTATUS status);
  NTSTATUS ForwardAndWait         (IN PDEVICE_OBJECT fdo, IN PIRP Irp);
  NTSTATUS SendDeviceSetPower     (PDEVICE_EXTENSION fdo, DEVICE_POWER_STATE state, BOOLEAN wait = FALSE);
  VOID     SendAsyncNotification  (PVOID context);
  VOID     EnableAllInterfaces    (PDEVICE_EXTENSION pdx, BOOLEAN enable);
  VOID     DeregisterAllInterfaces(PDEVICE_EXTENSION pdx);
  VOID     AbortPendingIoctls     (PDEVICE_EXTENSION pdx, NTSTATUS status);
  VOID     CleanupControlRequests (PDEVICE_EXTENSION pdx, NTSTATUS status, PFILE_OBJECT fop);
  PIRP     UncacheControlRequest  (PDEVICE_EXTENSION pdx, PIRP* pIrp);
  NTSTATUS StartDevice            (PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated);

  // TODO If you decide to queue reads and writes separately, you need
  // separate StartIo routines too. E.g.:
  //	VOID StartIoRead(PDEVICE_OBJECT fdo, PIRP Irp);
  //	VOID StartioWrite(PDEVICE_OBJECT fdo, PIRP Irp);

  VOID StartIo      (PDEVICE_OBJECT fdo, PIRP Irp);
  VOID StopDevice   (PDEVICE_OBJECT fdo, BOOLEAN oktouch = FALSE);
  VOID WmiInitialize(IN PDEVICE_OBJECT fdo);
  VOID WmiTerminate (IN PDEVICE_OBJECT fdo);
  VOID DpcForIsr    (PKDPC Dpc, PDEVICE_OBJECT fdo, PIRP junk, PDEVICE_EXTENSION pdx);

  // I/O request handlers

  NTSTATUS DispatchCreate         (PDEVICE_OBJECT fdo, PIRP Irp);
  NTSTATUS DispatchClose          (PDEVICE_OBJECT fdo, PIRP Irp);
  NTSTATUS DispatchReadWrite      (PDEVICE_OBJECT fdo, PIRP Irp);
  NTSTATUS DispatchControl        (PDEVICE_OBJECT fdo, PIRP Irp);
  NTSTATUS DispatchInternalControl(PDEVICE_OBJECT fdo, PIRP Irp);
  NTSTATUS DispatchCleanup        (PDEVICE_OBJECT fdo, PIRP Irp);
  NTSTATUS DispatchPower          (PDEVICE_OBJECT fdo, PIRP Irp);
  NTSTATUS DispatchWmi            (PDEVICE_OBJECT fdo, PIRP Irp);
  NTSTATUS DispatchPnp            (PDEVICE_OBJECT fdo, PIRP Irp);

  extern BOOLEAN win98;
  extern UNICODE_STRING servkey;


  //{ **************************************************************************** }
  //{ Descript : Register definitions for FLEXCOP.                                 }
  //{ **************************************************************************** }
  #define FLEXCOP_PWROFF             0xFFFFFFF7            // All powers off
  #define FLEXCOP_DMA1SUB0           0x000                 // DMA1 sub buffer 0 address
  #define FLEXCOP_DMA1ADDRESS        0x008                 // DMA1 address last written
  #define FLEXCOP_DMA1SUB1           0x00C                 // DMA1 sub buffer 1 address
  #define FLEXCOP_DMA2SUB0           0x010                 // DMA2 sub buffer 0 address
  #define FLEXCOP_DMA2ADDRESS        0x018                 // DMA2 address last written
  #define FLEXCOP_DMA2SUB1           0x01C                 // DMA2 sub buffer 1 address
  #define FLEXCOP_PWR                0x204                 // Revision information and power setting
  #define FLEXCOP_IER                0x208                 // Interrupt enable
  #define FLEXCOP_ISR                0x20C                 // Interrupt status


#endif
