Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

550 lines
20 KiB

//-------------------------------------------------------------------
// This is abstract class for generic device
// Specific devices should use it as a parent device
// Author: Sergey Ivanov
// Log:
// 08/11/99 - implemented
//-------------------------------------------------------------------
#ifndef __DEVICE__
#define __DEVICE__
#include "generic.h"
enum DEVSTATE
{
STOPPED, // device stopped
WORKING, // started and working
PENDINGSTOP, // stop pending
PENDINGREMOVE, // remove pending
SURPRISEREMOVED, // removed by surprise
REMOVED, // removed
};
// Remove eventually previous declaration!...
typedef enum _DEVICE_PNP_STATE {
NOT_STARTED = 0, // Not started yet
STARTED, // Device has received the START_DEVICE IRP
STOP_PENDING, // Device has received the QUERY_STOP IRP
_STOPPED_, // Device has received the STOP_DEVICE IRP
REMOVE_PENDING, // Device has received the QUERY_REMOVE IRP
SURPRISE_REMOVE_PENDING, // Device has received the SURPRISE_REMOVE IRP
DELETED // Device has received the REMOVE_DEVICE IRP
} DEVICE_PNP_STATE;
enum POWERSTATE
{
POWERON, // power on, device in D0 state
POWEROFFPENDING, // power off operation is pending
POWEROFF, // power off, device in D3 state
IDLEOFF, // power off due to idle detection
};
typedef struct _PPOWER_CONTEXT_
{
PKEVENT powerEvent;
NTSTATUS status;
} POWER_CONTEXT,*PPOWER_CONTEXT;
#define INITIALIZE_PNP_STATE() \
this->m_DevicePnPState = NOT_STARTED;\
this->m_PreviousPnPState = NOT_STARTED
#define SET_NEW_PNP_STATE(__state_) \
this->m_PreviousPnPState = this->m_DevicePnPState;\
this->m_DevicePnPState = (_state_)
#define RESTORE_PREVIOUS_PNP_STATE() \
this->m_DevicePnPState = this->m_PreviousPnPState
#define IS_DEVICE_PNP_STATE(_state_) \
(this->m_DevicePnPState == _state_)
#define DEVICE_SURPRISE_REMOVAL_OK 1
#define PNPTABSIZE IRP_MN_QUERY_LEGACY_BUS_INFORMATION+1
#define POWERTABSIZE IRP_MN_QUERY_POWER+1
#define STATETABSIZE REMOVED+1
#define SYSTEM_POWER_TAB_NAMESIZE 8
#define DEVICE_POWER_TAB_NAMESIZE 6
typedef enum PENDING_REQUEST_TYPE
{
OPEN_REQUEST = 0,
CLOSE_REQUEST,
READ_REQUEST,
WRITE_REQUEST,
IOCTL_REQUEST,
PNP_REQUEST,
POWER_REQUEST,
SYSTEM_REQUEST,
FLUSH_REQUEST,
CLEAN_REQUEST,
START_IO_REQUEST
} PENDING_REQUEST_TYPE;
class CPendingIRP
{
public:
NTSTATUS m_Status;
SAFE_DESTRUCTORS();
virtual VOID dispose(){self_delete();};
public:
LIST_ENTRY entry;
PENDING_REQUEST_TYPE Type;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
public:
CPendingIRP(PIRP Irp,PENDING_REQUEST_TYPE rt = OPEN_REQUEST,
PDEVICE_OBJECT tdo = NULL,PFILE_OBJECT tfo = NULL):
Irp(Irp), Type(rt), DeviceObject(tdo)
{
};
};
// ABSTRUCT class
// This is main interface from system to the device.
// Specific devices should implement the interface to support system requests.
class CDevice;
class CSystem;
class CIrp;
class CEvent;
class CPower;
class CDebug;
class CLock;
class CMemory;
class CIoPacket;
class CThread;
typedef struct _REMOVE_LOCK
{
LONG usage; // reference count
BOOLEAN removing; // true if removal is pending
KEVENT evRemove; // event to wait on
} REMOVE_LOCK, *PREMOVE_LOCK;
class CDevice;
#pragma PAGEDCODE
class CDevice
{
public:
NTSTATUS m_Status;
SAFE_DESTRUCTORS();
public:
ULONG m_Type;
// Support for the linked list of devices...
LIST_ENTRY entry;
protected:
LONG m_Usage; // use count on this device
static ULONG DeviceNumber; // Device instance number
UNICODE_STRING m_Ifname;
CUString* m_DeviceObjectName;
UCHAR m_VendorName[MAXIMUM_ATTR_STRING_LENGTH];
USHORT m_VendorNameLength;
UCHAR m_DeviceType[MAXIMUM_ATTR_STRING_LENGTH];
USHORT m_DeviceTypeLength;
BOOL m_Started; // Set TRUE if device started, FALSE if stopped
BOOL m_Openned; // Set TRUE if device openned, FALSE if closed
BOOL m_Added; // Set TRUE if device was added to system, FALSE if it is not
BOOL m_SurprizeRemoved;
REMOVE_LOCK m_RemoveLock;
BOOL m_RestartActiveThread;
KEVENT m_evEnabled; // event to wait on after device was disabled
// Event to signal device Idle state
//KMUTEX IdleState;=========== It will be much better!!!!!!!!!
KEVENT IdleState;
// Capabilities structure and device flags to handle
DEVICE_CAPABILITIES m_DeviceCapabilities;
ULONG m_Flags;
// Power management constants
PULONG m_Idle; // idle counter pointer
ULONG Idle_conservation;
ULONG Idle_performance;
DEVICE_POWER_STATE m_CurrentDevicePowerState;
DEVICE_POWER_STATE m_PowerDownLevel;
PIRP m_PowerIrp;
BOOL m_EnabledForWakeup;
//Current device state
DEVSTATE m_DeviceState;
// Will be used for canceled request
DEVSTATE m_DevicePreviousState;
// Next members will remove previous two (eventually)...
DEVICE_PNP_STATE m_PreviousPnPState;
DEVICE_PNP_STATE m_DevicePnPState;
CSystem* system;
CIrp* irp;
CEvent* event;
CPower* power;
CDebug* debug;
CLock* lock;
CMemory* memory;
// Support for asynchronous communications
CThread* IoThread;
LONG DevicePoolingInterval;
LONG Write_To_Read_Delay;
LONG Power_WTR_Delay;// Delay at power command
LONG DeviceCommandTimeout;// Timeout for the device commands
GUID InterfaceClassGuid;
BOOL m_DeviceInterfaceRegistered;
ULONG CardState;
// --------- ASYNCHRONOUS REQUESTS SUPPORT FUNCTIONS ----------------------------
// This group of functions will allow to create asynchronous
// communications with the driver.
// It includes -
// - functions to mark our Irp as pending and to include it into
// our device requests queue (makeRequestPending());
// - to extract next Irp from the device queue (startNextPendingRequest())
// and to start device specific Irp processing (startIoRequest())
// - getIoRequestsQueue() allows devices to verify device queue state.
// It is completely is up to specific device how to manage the device queue and
// to make synchronous or asynchronous Irp processing.
// For expl. device can create specific thread to process Irps.
// More than this - some devices can deside to make asyncronous communications only
// for specific (time consuming) device request while processing others syschronously.
//
// cancelPendingIrp() will cancel current Irp and remove corresponding IoRequest from
// IoRequestQueue.
protected:
CLinkedList<CPendingIRP>* m_IoRequests; // Clients' IO requests
// Support for dynamic device connections
PIRP m_OpenSessionIrp;
public:
virtual CLinkedList<CPendingIRP>* getIoRequestsQueue() = 0;
virtual VOID cancelPendingIrp(PIRP Irp) = 0;
virtual NTSTATUS cancelPendingRequest(CPendingIRP* IrpReq) = 0;
virtual NTSTATUS cancelAllPendingRequests() = 0;
virtual NTSTATUS makeRequestPending(PIRP Irp_request,PDEVICE_OBJECT toDeviceObject,PENDING_REQUEST_TYPE Type) = 0;
// Next functions will be called by Irp processing thread.
// Checks if request queue is empty and if it is NOT - starts next request...
virtual NTSTATUS startNextPendingRequest() = 0;
// Device specific function which processes pending requests...
// It will be redefied by specific devices.
virtual NTSTATUS startIoRequest(CPendingIRP*) = 0;
// --------- ASYNCHRONOUS REQUESTS SUPPORT FUNCTIONS ----------------------------
public:
CDevice()
{
m_Type = GRCLASS_DEVICE;
m_Openned = FALSE;
m_Added = FALSE;
// At begining device is at stop state
m_DevicePreviousState = STOPPED;
m_DeviceState = STOPPED;
m_SurprizeRemoved = FALSE;
m_RestartActiveThread = FALSE;
m_DeviceInterfaceRegistered = FALSE;
m_ParentDeviceObject = NULL;
DevicePoolingInterval = 500;// 0.5s better for detection
set_Default_WTR_Delay(); //1ms corrects "0 bytes" problem
Power_WTR_Delay = 1; //1ms should be OK...
DeviceCommandTimeout = 60000;// 60sec
m_IoRequests = NULL;
DBG_PRINT(" New Device %8.8lX was created...\n",this);
}; // Default pooling interval
BOOL PnPfcntab[PNPTABSIZE];
BOOL Powerfcntab[POWERTABSIZE];
#ifdef DEBUG
PCHAR PnPfcnname[PNPTABSIZE];
PCHAR Powerfcnname[POWERTABSIZE];
PCHAR Powersysstate[SYSTEM_POWER_TAB_NAMESIZE];
PCHAR Powerdevstate[DEVICE_POWER_TAB_NAMESIZE];
PCHAR statenames[STATETABSIZE];
#endif // DEBUG
protected:
virtual ~CDevice(){};
// Complete current request with given information
virtual NTSTATUS completeDeviceRequest(PIRP Irp, NTSTATUS status, ULONG info) {return STATUS_SUCCESS;};
VOID activatePnPHandler(LONG HandlerID)
{
if (HandlerID >= arraysize(PnPfcntab)) return;
PnPfcntab[HandlerID] = TRUE;
};
VOID disActivatePnPHandler(LONG HandlerID)
{
if (HandlerID >= arraysize(PnPfcntab)) return;
PnPfcntab[HandlerID] = FALSE;
};
public:
virtual CDevice* create(VOID) {return NULL;};
virtual VOID addRef(){refcount++;};
virtual VOID removeRef(){if(refcount) refcount--;};
virtual LONG getRefCount(){ return refcount;};
virtual VOID markAsOpenned(){ m_Openned = TRUE;};
virtual VOID markAsClosed() { m_Openned = FALSE;};
virtual BOOL isOpenned() { return m_Openned;};
virtual VOID setDeviceState(DEVSTATE state)
{
m_DevicePreviousState = m_DeviceState;
m_DeviceState = state;
};
virtual DEVSTATE getDeviceState(){return m_DeviceState;};
virtual VOID restoreDeviceState(){m_DeviceState = m_DevicePreviousState;};
virtual getObjectType(){return m_Type;};
virtual ULONG getCardState(){return CardState;};
virtual VOID setCardState(ULONG state){CardState = state;};
// Call this function instead of destructor.
// It will assure safety device removal.
virtual VOID dispose() {};
// Checks if device object is still valid.
virtual BOOL checkValid() {return FALSE;};
// Next methods should be defined by ALL clients...
virtual BOOL createDeviceObjects() {return FALSE;};
virtual VOID removeDeviceObjects() {};
virtual VOID initializeRemoveLock() {};
virtual NTSTATUS acquireRemoveLock() {return STATUS_SUCCESS;};
virtual VOID releaseRemoveLock() {};
virtual VOID releaseRemoveLockAndWait() {};
virtual BOOL isDeviceLocked() {return FALSE;};
virtual VOID setBusy() {};
virtual VOID setIdle() {};
virtual NTSTATUS waitForIdle() {return STATUS_SUCCESS;};
virtual NTSTATUS waitForIdleAndBlock() {return STATUS_SUCCESS;};
//virtual NTSTATUS add(PDRIVER_OBJECT Driver,PDEVICE_OBJECT PnpDeviceObject) {};
virtual NTSTATUS add(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pPdo) {return STATUS_UNSUCCESSFUL;};
PDEVICE_OBJECT getSystemObject(){return m_DeviceObject;};
PDEVICE_OBJECT getPhysicalObject(){return m_PhysicalDeviceObject;};
PDEVICE_OBJECT getLowerDriver(){return m_pLowerDeviceObject;};
UNICODE_STRING* getDeviceInterfaceName(){return &m_Ifname;};
GUID* getDeviceInterfaceGUID(){return &InterfaceClassGuid;};
BOOL isDeviceInterfaceRegistered(){return m_DeviceInterfaceRegistered;};
virtual BOOL registerDeviceInterface(const GUID* Guid) {return FALSE;};
virtual VOID unregisterDeviceInterface(UNICODE_STRING* InterfaceName) {};
CUString* getDeviceName(){return m_DeviceObjectName;};
ULONG getDeviceNumber(){ULONG ID = DeviceNumber; if(ID) --ID; return ID;};
ULONG incrementDeviceNumber(){ULONG ID = DeviceNumber; ++DeviceNumber; return ID;};
virtual VOID remove() {};
virtual VOID onDeviceStart() {};
virtual VOID onDeviceStop() {};
// These functions will create driver's IRPs to transfer datas.
// Device stack will keep track of all active (sended to lower level)
// and pending (mark as pending) IRPs...
virtual NTSTATUS send(CIoPacket* Irp) {return STATUS_SUCCESS;};
virtual NTSTATUS sendAndWait(CIoPacket* Irp) {return STATUS_SUCCESS;};
// Functions will send request and wait for a reply...
virtual NTSTATUS write(PUCHAR pRequest,ULONG RequestLength) {return STATUS_SUCCESS;};
virtual NTSTATUS writeAndWait(PUCHAR pRequest,ULONG RequestLength,PUCHAR pReply,ULONG* pReplyLength) {return STATUS_SUCCESS;};
virtual NTSTATUS readAndWait(PUCHAR pRequest,ULONG RequestLength,PUCHAR pReply,ULONG* pReplyLength) {return STATUS_SUCCESS;};
// Interface for system requests. ..
virtual NTSTATUS pnpRequest(IN PIRP Irp) {return STATUS_SUCCESS;};
virtual NTSTATUS powerRequest(PIRP irp) {return STATUS_SUCCESS;};
virtual NTSTATUS open(PIRP irp) {return STATUS_SUCCESS;};//Create
virtual NTSTATUS close(PIRP irp) {return STATUS_SUCCESS;};
virtual NTSTATUS read(PIRP irp) {return STATUS_SUCCESS;};
virtual NTSTATUS write(PIRP irp) {return STATUS_SUCCESS;};
virtual VOID startIo(PIRP irp){};
virtual NTSTATUS deviceControl(PIRP irp) {return STATUS_SUCCESS;};
virtual NTSTATUS cleanup(PIRP Irp) {return STATUS_SUCCESS;};
virtual NTSTATUS flush(PIRP Irp) {return STATUS_SUCCESS;};
virtual LONG getDevicePoolingInterval()
{
return DevicePoolingInterval;
};
virtual VOID setDevicePoolingInterval(LONG interval)
{
DevicePoolingInterval = interval;
};
virtual LONG getCommandTimeout()
{
return DeviceCommandTimeout;
};
virtual VOID setCommandTimeout(LONG timeout)
{
DeviceCommandTimeout = timeout;
};
// Inhereted classes will overwrite this function
virtual NTSTATUS ThreadRoutine()
{
return STATUS_SUCCESS;
};
#pragma LOCKEDCODE
// This is callback function for the attached threads
static VOID ThreadFunction(CDevice* device)
{
if(device) device->ThreadRoutine();
};
#pragma PAGEDCODE
virtual LONG get_Power_WTR_Delay()
{
return Power_WTR_Delay;
};
virtual LONG get_WTR_Delay()
{
return Write_To_Read_Delay;
};
virtual VOID set_WTR_Delay(LONG Delay)
{
Write_To_Read_Delay = Delay;
};
virtual VOID set_Default_WTR_Delay()
{
Write_To_Read_Delay = 1;
};
virtual VOID registerPowerIrp(PIRP Irp){m_PowerIrp = Irp;};
virtual PIRP getPowerIrp(){return m_PowerIrp;};
virtual VOID unregisterPowerIrp(){m_PowerIrp = NULL;};
virtual BOOL isEnabledForWakeup(){return m_EnabledForWakeup;};
virtual VOID setCurrentDevicePowerState(DEVICE_POWER_STATE state){m_CurrentDevicePowerState = state;};
virtual NTSTATUS sendDeviceSetPower(DEVICE_POWER_STATE devicePower, BOOLEAN wait) = 0;
virtual VOID setSurprizeRemoved(){m_SurprizeRemoved = TRUE;};
virtual VOID clearSurprizeRemoved(){m_SurprizeRemoved = FALSE;};
virtual BOOL isSurprizeRemoved(){ return m_SurprizeRemoved;};
virtual VOID setThreadRestart(){m_RestartActiveThread = TRUE;};
virtual VOID clearThreadRestart(){m_RestartActiveThread = FALSE;};
virtual BOOL isRequiredThreadRestart(){ return m_RestartActiveThread;};
protected:
WCHAR Signature[3];
PDRIVER_OBJECT m_DriverObject;
// Back reference to system object
PDEVICE_OBJECT m_DeviceObject;
// Device object lower at stack
PDEVICE_OBJECT m_pLowerDeviceObject;
// Interrupt handle/object
IN PKINTERRUPT m_InterruptObject;
// Physical device object used at Power management
PDEVICE_OBJECT m_PhysicalDeviceObject;
// Will be used by child at bus to access parent
PDEVICE_OBJECT m_ParentDeviceObject;
protected:
BOOL initialized;//Current object finished initialization
LONG refcount;
};
#ifdef DEBUG
#define INCLUDE_PNP_FUNCTIONS_NAMES() \
PnPfcnname[IRP_MN_START_DEVICE] = "IRP_MN_START_DEVICE";\
PnPfcnname[IRP_MN_QUERY_REMOVE_DEVICE] = "IRP_MN_QUERY_REMOVE_DEVICE";\
PnPfcnname[IRP_MN_REMOVE_DEVICE] = "IRP_MN_REMOVE_DEVICE";\
PnPfcnname[IRP_MN_CANCEL_REMOVE_DEVICE] = "IRP_MN_CANCEL_REMOVE_DEVICE";\
PnPfcnname[IRP_MN_STOP_DEVICE] = "IRP_MN_STOP_DEVICE";\
\
PnPfcnname[IRP_MN_QUERY_STOP_DEVICE] = "IRP_MN_QUERY_STOP_DEVICE";\
PnPfcnname[IRP_MN_CANCEL_STOP_DEVICE] = "IRP_MN_CANCEL_STOP_DEVICE";\
PnPfcnname[IRP_MN_QUERY_DEVICE_RELATIONS]= "IRP_MN_QUERY_DEVICE_RELATIONS";\
\
PnPfcnname[IRP_MN_QUERY_INTERFACE] = "IRP_MN_QUERY_INTERFACE";\
PnPfcnname[IRP_MN_QUERY_CAPABILITIES] = "IRP_MN_QUERY_CAPABILITIES";\
PnPfcnname[IRP_MN_QUERY_RESOURCES] = "IRP_MN_QUERY_RESOURCES";\
\
PnPfcnname[IRP_MN_QUERY_RESOURCE_REQUIREMENTS] = "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";\
PnPfcnname[IRP_MN_QUERY_DEVICE_TEXT] = "IRP_MN_QUERY_DEVICE_TEXT";\
PnPfcnname[IRP_MN_FILTER_RESOURCE_REQUIREMENTS] = "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";\
PnPfcnname[14] = "Unsupported PnP function";\
\
PnPfcnname[IRP_MN_READ_CONFIG] = "IRP_MN_READ_CONFIG";\
PnPfcnname[IRP_MN_WRITE_CONFIG] = "IRP_MN_WRITE_CONFIG";\
PnPfcnname[IRP_MN_EJECT] = "IRP_MN_EJECT";\
\
PnPfcnname[IRP_MN_SET_LOCK] = "IRP_MN_SET_LOCK";\
PnPfcnname[IRP_MN_QUERY_ID] = "IRP_MN_QUERY_ID";\
PnPfcnname[IRP_MN_QUERY_PNP_DEVICE_STATE] = "IRP_MN_QUERY_PNP_DEVICE_STATE";\
PnPfcnname[IRP_MN_QUERY_BUS_INFORMATION] = "IRP_MN_QUERY_BUS_INFORMATION";\
PnPfcnname[IRP_MN_DEVICE_USAGE_NOTIFICATION] = "IRP_MN_DEVICE_USAGE_NOTIFICATION";\
PnPfcnname[IRP_MN_SURPRISE_REMOVAL] = "IRP_MN_SURPRISE_REMOVAL";\
PnPfcnname[IRP_MN_QUERY_LEGACY_BUS_INFORMATION] = "IRP_MN_QUERY_LEGACY_BUS_INFORMATION";
#define INCLUDE_POWER_FUNCTIONS_NAMES() \
Powerfcnname[IRP_MN_WAIT_WAKE] = "IRP_MN_WAIT_WAKE";\
Powerfcnname[IRP_MN_POWER_SEQUENCE] = "IRP_MN_POWER_SEQUENCE";\
Powerfcnname[IRP_MN_SET_POWER] = "IRP_MN_SET_POWER";\
Powerfcnname[IRP_MN_QUERY_POWER] = "IRP_MN_QUERY_POWER";\
\
Powersysstate[0] = "PowerSystemUnspecified";\
Powersysstate[1] = "PowerSystemWorking";\
Powersysstate[2] = "PowerSystemSleeping1";\
Powersysstate[3] = "PowerSystemSleeping2";\
Powersysstate[4] = "PowerSystemSleeping3";\
Powersysstate[5] = "PowerSystemShutdown";\
Powersysstate[6] = "PowerSystemMaximum";\
\
Powerdevstate[0] = "PowerDeviceUnspecified";\
Powerdevstate[1] = "PowerDeviceD0";\
Powerdevstate[2] = "PowerDeviceD1";\
Powerdevstate[3] = "PowerDeviceD2";\
Powerdevstate[4] = "PowerDeviceD3";\
Powerdevstate[5] = "PowerDeviceMaximum";
#define INCLUDE_STATE_NAMES() \
statenames[0] = "STOPPED";\
statenames[1] = "WORKING";\
statenames[2] = "PENDINGSTOP";\
statenames[3] = "PENDINGREMOVE";\
statenames[4] = "SURPRISEREMOVED";\
statenames[5] = "REMOVED";
#else
#define INCLUDE_PNP_FUNCTIONS_NAMES()
#define INCLUDE_POWER_FUNCTIONS_NAMES()
#define INCLUDE_STATE_NAMES()
#endif // DEBUG
#endif