/****************************************************************************

Copyright (c) 1998  Microsoft Corporation

Module Name:

        USBSER.H

Abstract:

        This header file is used for the Legacy USB Modem Driver

Environment:

        Kernel mode & user mode

Notes:

        THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
        KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
        IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
        PURPOSE.

        Copyright (c) 1998 Microsoft Corporation.  All Rights Reserved.

Revision History:

        12/23/97 : created

Author:

        Tom Green

****************************************************************************/

#ifndef __USBSER_H__
#define __USBSER_H__

#ifdef DRIVER

// Various definitions
#define NAME_MAX                        80

#define MILLISECONDS_TIMEOUT(x) ((ULONGLONG) ((-x) * 10000))

#define NOTIFICATION_BUFF_SIZE  10

#define MAXIMUM_TRANSFER_SIZE           (8 * 1024)
#define RX_BUFF_SIZE             		(16 * 1024)
#define USB_RX_BUFF_SIZE				(RX_BUFF_SIZE / 4)
#define LOW_WATER_MARK					(USB_RX_BUFF_SIZE * 3)

#define DEVICE_STATE_UNKNOWN            0x0000
#define DEVICE_STATE_STARTED            0x0001
#define DEVICE_STATE_STOPPED            0x0002
#define DEVICE_STATE_REMOVED            0x0003

// device capabilities
#define DEVICE_CAP_VERSION              0x0001
#define DEVICE_CAP_UNUSED_PARAM         ((ULONG) -1)

// these describe bits in the modem status register
#define SERIAL_MSR_DCTS                 0x0001
#define SERIAL_MSR_DDSR                 0x0002
#define SERIAL_MSR_TERI                 0x0004
#define SERIAL_MSR_DDCD                 0x0008
#define SERIAL_MSR_CTS                  0x0010
#define SERIAL_MSR_DSR                  0x0020
#define SERIAL_MSR_RI                   0x0040
#define SERIAL_MSR_DCD                  0x0080

//
// These masks define access to the line status register.  The line
// status register contains information about the status of data
// transfer.  The first five bits deal with receive data and the
// last two bits deal with transmission.  An interrupt is generated
// whenever bits 1 through 4 in this register are set.
//

//
// This bit is the data ready indicator.  It is set to indicate that
// a complete character has been received.  This bit is cleared whenever
// the receive buffer register has been read.
//
#define SERIAL_LSR_DR       0x01

//
// This is the overrun indicator.  It is set to indicate that the receive
// buffer register was not read befor a new character was transferred
// into the buffer.  This bit is cleared when this register is read.
//
#define SERIAL_LSR_OE       0x02

//
// This is the parity error indicator.  It is set whenever the hardware
// detects that the incoming serial data unit does not have the correct
// parity as defined by the parity select in the line control register.
// This bit is cleared by reading this register.
//
#define SERIAL_LSR_PE       0x04

//
// This is the framing error indicator.  It is set whenever the hardware
// detects that the incoming serial data unit does not have a valid
// stop bit.  This bit is cleared by reading this register.
//
#define SERIAL_LSR_FE       0x08

//
// This is the break interrupt indicator.  It is set whenever the data
// line is held to logic 0 for more than the amount of time it takes
// to send one serial data unit.  This bit is cleared whenever the
// this register is read.
//
#define SERIAL_LSR_BI       0x10

//
// This is the transmit holding register empty indicator.  It is set
// to indicate that the hardware is ready to accept another character
// for transmission.  This bit is cleared whenever a character is
// written to the transmit holding register.
//
#define SERIAL_LSR_THRE     0x20

//
// This bit is the transmitter empty indicator.  It is set whenever the
// transmit holding buffer is empty and the transmit shift register
// (a non-software accessable register that is used to actually put
// the data out on the wire) is empty.  Basically this means that all
// data has been sent.  It is cleared whenever the transmit holding or
// the shift registers contain data.
//
#define SERIAL_LSR_TEMT     0x40

//
// This bit indicates that there is at least one error in the fifo.
// The bit will not be turned off until there are no more errors
// in the fifo.
//
#define SERIAL_LSR_FIFOERR  0x80



//
// Serial naming values
//

//
// Maximum length for symbolic link
//

#define SYMBOLIC_NAME_LENGTH    128

//
// This define gives the default Object directory
// that we should use to insert the symbolic links
// between the NT device name and namespace used by
// that object directory.

#define DEFAULT_DIRECTORY               L"DosDevices"

//
// Where in the DeviceMap section of the registry serial port entries
// should appear
//

#define SERIAL_DEVICE_MAP               L"SERIALCOMM"


// performance info for modem driver
typedef struct _PERF_INFO
{
        BOOLEAN                         PerfModeEnabled;
    ULONG                               BytesPerSecond;
} PERF_INFO, *PPERF_INFO;


#define SANITY_CHECK                    ((ULONG) 'ENAS')

#else

#include <winioctl.h>

#endif

// IOCTL info, needs to be visible for application

#define USBSER_IOCTL_INDEX      0x0800


#define GET_DRIVER_LOG          CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 0,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define GET_IRP_HIST            CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 1,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define GET_PATH_HIST           CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 2,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define GET_ERROR_LOG           CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 3,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define GET_ATTACHED_DEVICES    CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 4,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define SET_IRP_HIST_SIZE       CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 5,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define SET_PATH_HIST_SIZE      CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 6,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define SET_ERROR_LOG_SIZE      CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 7,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define GET_DRIVER_INFO         CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 8,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)


#define ENABLE_PERF_TIMING      CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 9,        \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define DISABLE_PERF_TIMING     CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 10,       \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define GET_PERF_DATA           CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 11,       \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#define SET_DEBUG_TRACE_LEVEL   CTL_CODE(FILE_DEVICE_UNKNOWN,           \
                                         USBSER_IOCTL_INDEX + 12,       \
                                         METHOD_BUFFERED,               \
                                         FILE_ANY_ACCESS)

#ifdef DRIVER

// info about the driver, initialized in DriverEntry routine
PCHAR       DriverName;
PCHAR       DriverVersion;
ULONG       Usbser_Debug_Trace_Level;
ULONG       UsbSerSerialDebugLevel;
KSPIN_LOCK  GlobalSpinLock;

//
// Count of how many times the paged code has been locked
//

ULONG       PAGEUSBSER_Count;

//
// Handle to the locked paged code
//

PVOID       PAGEUSBSER_Handle;

//
// Pointer to funcion
//

PVOID       PAGEUSBSER_Function;

typedef struct _READ_CONTEXT
{
        PURB                            Urb;
        PDEVICE_OBJECT                  DeviceObject;
        PIRP                            Irp;
} READ_CONTEXT, *PREAD_CONTEXT;

// device extension for driver instance, used to store needed data

typedef struct _DEVICE_EXTENSION
{
        PDEVICE_OBJECT                  PhysDeviceObject;       // physical device object
        PDEVICE_OBJECT                  StackDeviceObject;      // stack device object
        CHAR                            LinkName[NAME_MAX];     // string name of symbolic link
        PUSB_DEVICE_DESCRIPTOR          DeviceDescriptor;       // device descriptor for device
        USBD_CONFIGURATION_HANDLE       ConfigurationHandle;    // configuration of USB device
        USBD_PIPE_HANDLE                DataInPipe;             // pipe for reading data
        USBD_PIPE_HANDLE                DataOutPipe;            // pipe for writing data
        USBD_PIPE_HANDLE                NotificationPipe;       // pipe for getting notifications from the device
        ULONG                           IRPCount;               // number of IRPs that passed through this device object
        LARGE_INTEGER                   ByteCount;              // number of bytes of data passed through this device object
        ULONG                           Instance;               // instance of device
        BOOLEAN                         IsDevice;               // is this a device or "global" device object
        BOOLEAN                         PerfTimerEnabled;       // enable perf timing
        LARGE_INTEGER                   BytesXfered;            // byte count for perf
        LARGE_INTEGER                   ElapsedTime;            // elapsed time for perf
        LARGE_INTEGER                   TimerStart;             // timer start for perf
        DEVICE_CAPABILITIES             DeviceCapabilities;
        ULONG                           PowerDownLevel;
        DEVICE_POWER_STATE              CurrentDevicePowerState;
        PIRP                            PowerIrp;
        BOOLEAN                         SelfPowerIrp;
        KEVENT                          SelfRequestedPowerIrpEvent;

        //
        // Nota Bene:  Locking hierarchy is acquire ControlLock *then*
        //             acquire CancelSpinLock.  We don't want to stall other
        //             drivers waiting for the cancel spin lock
        //

        KSPIN_LOCK                      ControlLock;            // protect extension
        ULONG                           CurrentBaud;            // current baud rate
        SERIAL_TIMEOUTS                 Timeouts;               // timeout controls for device
        ULONG                           IsrWaitMask;            // determine if occurence of events should be noticed
        SERIAL_LINE_CONTROL             LineControl;            // current value of line control reg
        SERIAL_HANDFLOW                 HandFlow;               // Handshake and control flow settings
        SERIALPERF_STATS                PerfStats;              // performance stats
        SERIAL_CHARS                    SpecialChars;           // special characters
        ULONG                           DTRRTSState;            // keep track of the current state of these lines
        ULONG                           SupportedBauds;         // "named" baud rates for device
        UCHAR                           EscapeChar;             // for LsrmstInsert IOCTL
        USHORT                          FakeModemStatus;        // looks like status register on modem
        USHORT                          FakeLineStatus;         // looks like line status register
        USHORT                          RxMaxPacketSize;        // max packet size fo the in data pipe
        PIRP                            NotifyIrp;              // Irp for notify reads
        PURB                            NotifyUrb;              // Urb for notify Irp
        PIRP                            ReadIrp;                // Irp for read requests
        PURB                            ReadUrb;                // Urb for read requests
        KEVENT                          ReadEvent;              // used to cancel a read Irp
        ULONG                           CharsInReadBuff;        // current number of characters buffered
        ULONG                           CurrentReadBuffPtr;     // pointer into read buffer
        BOOLEAN                         AcceptingRequests;      // is the device stopped or removed
        PIRP                            CurrentMaskIrp;         // current set or wait mask Irp
        ULONG                           HistoryMask;            // store mask events here
        ULONG                           OpenCnt;                // number of create calls on device
        PUCHAR                          NotificationBuff;       // buffer for notifications
        PUCHAR                          ReadBuff;               // circular buffer for read requests
        PUCHAR							USBReadBuff;			// buffer to get data from device
        UCHAR                           CommInterface;          // index of communications interface
        ULONG                           RxQueueSize;            // fake read buffer size
        ULONG                           ReadInterlock;          // state machine for starting reads from completion routine
        BOOLEAN                         ReadInProgress;
        ULONG                           DeviceState;            // current state of enumeration

        //
        // True if a symbolic link has been created and should be
        // removed upon deletion.
        //

        BOOLEAN                         CreatedSymbolicLink;

        //
        // Symbolic link name -- e.g., \\DosDevices\COMx
        //

        UNICODE_STRING                  SymbolicLinkName;

        //
        // Dos Name -- e.g., COMx
        //

        UNICODE_STRING                  DosName;

        //
        // Device Name -- e.g., \\Devices\UsbSerx
        //

        UNICODE_STRING                  DeviceName;

        //
        // Current Read Irp which is pending
        //

        PIRP                            CurrentReadIrp;

        //
        // Current Write Irp which is pending
        //

        PIRP                            CurrentWriteIrp;

        //
        // Read queue
        //

        LIST_ENTRY                      ReadQueue;

        //
        // This value holds the number of characters desired for a
        // particular read.  It is initially set by read length in the
        // IRP.  It is decremented each time more characters are placed
        // into the "users" buffer buy the code that reads characters
        // out of the typeahead buffer into the users buffer.  If the
        // typeahead buffer is exhausted by the read, and the reads buffer
        // is given to the isr to fill, this value is becomes meaningless.
        //

        ULONG                           NumberNeededForRead;

        //
        // Timer for timeout on total read request
        //

        KTIMER                          ReadRequestTotalTimer;

        //
        // Timer for timeout on the interval
        //

        KTIMER                          ReadRequestIntervalTimer;

        //
        // This is the kernal timer structure used to handle
        // total time request timing.
        //

        KTIMER                          WriteRequestTotalTimer;

        //
        // This value is set by the read code to hold the time value
        // used for read interval timing.  We keep it in the extension
        // so that the interval timer dpc routine determine if the
        // interval time has passed for the IO.
        //

        LARGE_INTEGER                   IntervalTime;

        //
        // This holds the value that we use to determine if we should use
        // the long interval delay or the short interval delay.
        //

        LARGE_INTEGER                   CutOverAmount;

        //
        // This holds the system time when we last time we had
        // checked that we had actually read characters.  Used
        // for interval timing.
        //

        LARGE_INTEGER                   LastReadTime;

        //
        // This points the the delta time that we should use to
        // delay for interval timing.
        //

        PLARGE_INTEGER                  IntervalTimeToUse;

        //
        // These two values hold the "constant" time that we should use
        // to delay for the read interval time.
        //

        LARGE_INTEGER                   ShortIntervalAmount;
        LARGE_INTEGER                   LongIntervalAmount;

        //
        // This dpc is fired off if the timer for the total timeout
        // for the read expires.  It will execute a dpc routine that
        // will cause the current read to complete.
        //
        //

        KDPC                            TotalReadTimeoutDpc;

        //
        // This dpc is fired off if the timer for the interval timeout
        // expires.  If no more characters have been read then the
        // dpc routine will cause the read to complete.  However, if
        // more characters have been read then the dpc routine will
        // resubmit the timer.
        //

        KDPC                            IntervalReadTimeoutDpc;

        //
        // This dpc is fired off if the timer for the total timeout
        // for the write expires.  It will execute a dpc routine that
        // will cause the current write to complete.
        //
        //

        KDPC                            TotalWriteTimeoutDpc;

        //
        // This keeps a total of the number of characters that
        // are in all of the "write" irps that the driver knows
        // about.  It is only accessed with the cancel spinlock
        // held.
        //

        ULONG                           TotalCharsQueued;

        //
        // This holds a count of the number of characters read
        // the last time the interval timer dpc fired.  It
        // is a long (rather than a ulong) since the other read
        // completion routines use negative values to indicate
        // to the interval timer that it should complete the read
        // if the interval timer DPC was lurking in some DPC queue when
        // some other way to complete occurs.
        //

        LONG                            CountOnLastRead;

        //
        // This is a count of the number of characters read by the
        // isr routine.  It is *ONLY* written at isr level.  We can
        // read it at dispatch level.
        //

        ULONG                           ReadByIsr;

        //
        // If non-NULL, means this write timed out and we should correct the
        // return value in the completion routine.
        //

        PIRP                            TimedOutWrite;

        //
        // If TRUE, that means we need to insert LSRMST
        //

        BOOLEAN                         EscapeSeen;


        //
        // Holds data that needs to be pushed such as LSRMST data
        //

        LIST_ENTRY                      ImmediateReadQueue;

        //
        // Pending wait-wake irp
        //

        PIRP                            PendingWakeIrp;

        //
        // True if WaitWake needs to be sent down before a powerdown
        //

        BOOLEAN                         SendWaitWake;

        //
        // SystemWake from devcaps
        //

        SYSTEM_POWER_STATE              SystemWake;

        //
        // DeviceWake from devcaps
        //

        DEVICE_POWER_STATE              DeviceWake;

        //
        // Count of Writes pending in the lower USB levels
        //

        ULONG                           PendingWriteCount;

        //
        // Counters and events to drain USB requests
        //

        KEVENT                          PendingDataInEvent;
        KEVENT                          PendingDataOutEvent;
        KEVENT                          PendingNotifyEvent;
        KEVENT                          PendingFlushEvent;

        ULONG                           PendingDataInCount;
        ULONG                           PendingDataOutCount;
        ULONG                           PendingNotifyCount;
        ULONG                           SanityCheck;

      	// selective suspend support
      	PIRP                        	PendingIdleIrp;
      	PUSB_IDLE_CALLBACK_INFO       	IdleCallbackInfo;
    	PIO_WORKITEM 					IoWorkItem;
    	IO_STATUS_BLOCK                 StatusBlock;

#ifdef SPINLOCK_TRACKING
      	LONG							CancelSpinLockCount;
      	LONG							SpinLockCount;
      	LONG							WaitingOnCancelSpinLock;
      	LONG							WaitingOnSpinLock;
#endif

#ifdef WMI_SUPPORT
      //
      // WMI Information
      //

      WMILIB_CONTEXT WmiLibInfo;

      //
      // Name to use as WMI identifier
      //

      UNICODE_STRING WmiIdentifier;

#endif

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

typedef struct _USBSER_IMMEDIATE_READ_PACKET {
   //
   // List of packets
   //

   LIST_ENTRY ImmediateReadQueue;

   //
   // Length of data
   //

   ULONG BufferLen;

   //
   //  Buffer itself, leave last in struct
   //

   UCHAR Buffer;



} USBSER_IMMEDIATE_READ_PACKET, *PUSBSER_IMMEDIATE_READ_PACKET;

typedef struct _USBSER_WRITE_PACKET {
   //
   // Device extension for this write
   //

   PDEVICE_EXTENSION DeviceExtension;

   //
   // Irp this packet belongs with
   //

   PIRP Irp;

   //
   // Write timer
   //

   KTIMER WriteTimer;

   //
   // Timeout value
   //

   LARGE_INTEGER WriteTimeout;

   //
   // TimerDPC
   //

   KDPC TimerDPC;

   //
   // Status
   //

   NTSTATUS Status;

   //
   // Urb for this write  N.B.: size is variable, so leave last
   //

   URB Urb;
} USBSER_WRITE_PACKET, *PUSBSER_WRITE_PACKET;


typedef NTSTATUS (*PUSBSER_START_ROUTINE)(IN PDEVICE_EXTENSION);
typedef VOID (*PUSBSER_GET_NEXT_ROUTINE) (IN PIRP *CurrentOpIrp,
                                          IN PLIST_ENTRY QueueToProcess,
                                          OUT PIRP *NewIrp,
                                          IN BOOLEAN CompleteCurrent,
                                          PDEVICE_EXTENSION Extension);

NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);

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

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

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

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

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

VOID
UsbSer_Unload(IN PDRIVER_OBJECT DriverObject);

NTSTATUS
UsbSer_PnPAddDevice(IN PDRIVER_OBJECT DriverObject,
                                        IN PDEVICE_OBJECT PhysicalDeviceObject);

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

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

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

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

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

NTSTATUS
UsbSerStartOrQueue(IN PDEVICE_EXTENSION PDevExt, IN PIRP PIrp,
                   IN PLIST_ENTRY PQueue, IN PIRP *PPCurrentIrp,
                   IN PUSBSER_START_ROUTINE Starter);

VOID
UsbSerCancelQueued(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp);

NTSTATUS
UsbSerStartRead(IN PDEVICE_EXTENSION PDevExt);


VOID
UsbSerCancelCurrentRead(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp);

BOOLEAN
UsbSerGrabReadFromRx(IN PVOID Context);

VOID
UsbSerTryToCompleteCurrent(IN PDEVICE_EXTENSION PDevExt,
                           IN KIRQL IrqlForRelease, IN NTSTATUS StatusToUse,
                           IN PIRP *PpCurrentOpIrp,
                           IN PLIST_ENTRY PQueue OPTIONAL,
                           IN PKTIMER PIntervalTimer OPTIONAL,
                           IN PKTIMER PTotalTimer OPTIONAL,
                           IN PUSBSER_START_ROUTINE Starter OPTIONAL,
                           IN PUSBSER_GET_NEXT_ROUTINE PGetNextIrp OPTIONAL,
                           IN LONG RefType, IN BOOLEAN Complete);

VOID
UsbSerReadTimeout(IN PKDPC PDpc, IN PVOID DeferredContext,
                  IN PVOID SystemContext1, IN PVOID SystemContext2);

VOID
UsbSerIntervalReadTimeout(IN PKDPC PDpc, IN PVOID DeferredContext,
                          IN PVOID SystemContext1, IN PVOID SystemContext2);

VOID
UsbSerKillPendingIrps(PDEVICE_OBJECT PDevObj);

VOID
UsbSerCompletePendingWaitMasks(IN PDEVICE_EXTENSION DeviceExtension);


VOID
UsbSerKillAllReadsOrWrites(IN PDEVICE_OBJECT PDevObj,
                           IN PLIST_ENTRY PQueueToClean,
                           IN PIRP *PpCurrentOpIrp);

VOID
UsbSerRestoreModemSettings(PDEVICE_OBJECT PDevObj);

VOID
UsbSerProcessEmptyTransmit(IN PDEVICE_EXTENSION PDevExt);

VOID
UsbSerWriteTimeout(IN PKDPC Dpc, IN PVOID DeferredContext,
                   IN PVOID SystemContext1, IN PVOID SystemContext2);

NTSTATUS
UsbSerGiveWriteToUsb(IN PDEVICE_EXTENSION PDevExt, IN PIRP PIrp,
                     IN LARGE_INTEGER TotalTime);

VOID
UsbSerCancelWaitOnMask(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp);

NTSTATUS
UsbSerWriteComplete(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp,
                    IN PUSBSER_WRITE_PACKET PPacket);

NTSTATUS
UsbSerFlush(IN PDEVICE_OBJECT PDevObj, PIRP PIrp);

NTSTATUS
UsbSerTossWMIRequest(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp,
                     IN ULONG GuidIndex);

NTSTATUS
UsbSerSystemControlDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp);

NTSTATUS
UsbSerSetWmiDataItem(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp,
                     IN ULONG GuidIndex, IN ULONG InstanceIndex,
                     IN ULONG DataItemId,
                     IN ULONG BufferSize, IN PUCHAR PBuffer);

NTSTATUS
UsbSerSetWmiDataBlock(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp,
                      IN ULONG GuidIndex, IN ULONG InstanceIndex,
                      IN ULONG BufferSize,
                      IN PUCHAR PBuffer);

NTSTATUS
UsbSerQueryWmiDataBlock(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp,
                        IN ULONG GuidIndex,
                        IN ULONG InstanceIndex,
                        IN ULONG InstanceCount,
                        IN OUT PULONG InstanceLengthArray,
                        IN ULONG OutBufferSize,
                        OUT PUCHAR PBuffer);

NTSTATUS
UsbSerQueryWmiRegInfo(IN PDEVICE_OBJECT PDevObj, OUT PULONG PRegFlags,
                      OUT PUNICODE_STRING PInstanceName,
                      OUT PUNICODE_STRING *PRegistryPath,
                      OUT PUNICODE_STRING MofResourceName,
                      OUT PDEVICE_OBJECT *Pdo);


//
// The following three macros are used to initialize, set
// and clear references in IRPs that are used by
// this driver.  The reference is stored in the fourth
// argument of the irp, which is never used by any operation
// accepted by this driver.
//

#define USBSER_REF_RXBUFFER    (0x00000001)
#define USBSER_REF_CANCEL      (0x00000002)
#define USBSER_REF_TOTAL_TIMER (0x00000004)
#define USBSER_REF_INT_TIMER   (0x00000008)

#ifdef SPINLOCK_TRACKING

#define ACQUIRE_CANCEL_SPINLOCK(DEVEXT, IRQL)					\
{																\
	ASSERT(DEVEXT->SpinLockCount == 0);							\
	DEVEXT->WaitingOnCancelSpinLock++; 							\
	IoAcquireCancelSpinLock(IRQL);								\
	DEVEXT->CancelSpinLockCount++;								\
	DEVEXT->WaitingOnCancelSpinLock--; 							\
	ASSERT(DEVEXT->CancelSpinLockCount == 1);					\
}

#define RELEASE_CANCEL_SPINLOCK(DEVEXT, IRQL)					\
{																\
	DEVEXT->CancelSpinLockCount--;								\
	ASSERT(DEVEXT->CancelSpinLockCount == 0);					\
	IoReleaseCancelSpinLock(IRQL);								\
}

#define ACQUIRE_SPINLOCK(DEVEXT, LOCK, IRQL)					\
{																\
	DEVEXT->WaitingOnSpinLock++; 								\
	KeAcquireSpinLock(LOCK, IRQL);					    		\
	DEVEXT->SpinLockCount++;									\
	DEVEXT->WaitingOnSpinLock--; 								\
	ASSERT(DEVEXT->SpinLockCount == 1);							\
}

#define RELEASE_SPINLOCK(DEVEXT, LOCK, IRQL)					\
{																\
	DEVEXT->SpinLockCount--;									\
	ASSERT(DEVEXT->SpinLockCount == 0);							\
	KeReleaseSpinLock(LOCK, IRQL);					    		\
}

#else

#define ACQUIRE_CANCEL_SPINLOCK(DEVEXT, IRQL) 	IoAcquireCancelSpinLock(IRQL)
#define RELEASE_CANCEL_SPINLOCK(DEVEXT, IRQL) 	IoReleaseCancelSpinLock(IRQL)
#define ACQUIRE_SPINLOCK(DEVEXT, LOCK, IRQL)	KeAcquireSpinLock(LOCK, IRQL)
#define RELEASE_SPINLOCK(DEVEXT, LOCK, IRQL)	KeReleaseSpinLock(LOCK, IRQL)

#endif


#define USBSER_INIT_REFERENCE(Irp) { \
    IoGetCurrentIrpStackLocation((Irp))->Parameters.Others.Argument4 = NULL; \
    }

#define USBSER_SET_REFERENCE(Irp,RefType) \
   do { \
       LONG _refType = (RefType); \
       PUINT_PTR _arg4 = (PVOID)&IoGetCurrentIrpStackLocation((Irp))->Parameters.Others.Argument4; \
       *_arg4 |= _refType; \
   } while (0)

#define USBSER_CLEAR_REFERENCE(Irp,RefType) \
   do { \
       LONG _refType = (RefType); \
       PUINT_PTR _arg4 = (PVOID)&IoGetCurrentIrpStackLocation((Irp))->Parameters.Others.Argument4; \
       *_arg4 &= ~_refType; \
   } while (0)

#define USBSER_REFERENCE_COUNT(Irp) \
    ((UINT_PTR)((IoGetCurrentIrpStackLocation((Irp))->Parameters.Others.Argument4)))


//
// These values are used by the routines that can be used
// to complete a read (other than interval timeout) to indicate
// to the interval timeout that it should complete.
//
#define SERIAL_COMPLETE_READ_CANCEL ((LONG)-1)
#define SERIAL_COMPLETE_READ_TOTAL ((LONG)-2)
#define SERIAL_COMPLETE_READ_COMPLETE ((LONG)-3)

#if DBG

#define USBSERDUMPRD    ((ULONG)0x00000001)
#define USBSERDUMPWR    ((ULONG)0x00000002)
#define USBSERCOMPEV    ((ULONG)0x00000004)

#define USBSERTRACETM   ((ULONG)0x00100000)
#define USBSERTRACECN   ((ULONG)0x00200000)
#define USBSERTRACEPW   ((ULONG)0x00400000)
#define USBSERTRACERD   ((ULONG)0x01000000)
#define USBSERTRACEWR   ((ULONG)0x02000000)
#define USBSERTRACEIOC  ((ULONG)0x04000000)
#define USBSERTRACEOTH  ((ULONG)0x08000000)

#define USBSERBUGCHECK  ((ULONG)0x80000000)

#define USBSERTRACE     ((ULONG)0x0F700000)
#define USBSERDBGALL    ((ULONG)0xFFFFFFFF)

extern ULONG UsbSerSerialDebugLevel;

#define UsbSerSerialDump(LEVEL, STRING) \
   do { \
      ULONG _level = (LEVEL); \
      if (UsbSerSerialDebugLevel & _level) { \
         DbgPrint("UsbSer: "); \
         DbgPrint STRING; \
      } \
      if (_level == USBSERBUGCHECK) { \
         ASSERT(FALSE); \
      } \
   } while (0)
#else

#define UsbSerSerialDump(LEVEL,STRING) do {;} while (0)

#endif // DBG

#define USBSER_VENDOR_COMMAND 0
#define USBSER_CLASS_COMMAND  1

#endif  // DRIVER


#endif // __USBSER_H__