//------------------------------------------------------------------- // 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* m_IoRequests; // Clients' IO requests // Support for dynamic device connections PIRP m_OpenSessionIrp; public: virtual CLinkedList* 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