www.pudn.com > pcmcia_sample.rar > PcmciaDevice.cpp


// PcmciaDevice.cpp 
// Implementation of PcmciaDevice device class 
// 
// Generated by DriverWizard version DriverStudio 2.7.0 (Build 562) 
// Requires Compuware's DriverWorks classes 
// 
 
#pragma warning(disable:4065) // Allow switch statement with no cases 
		   
#include  
#include "..\PcmciaDeviceinterface.h" 
 
#include "Pcmcia.h" 
#include "PcmciaDevice.h" 
 
#pragma hdrstop("Pcmcia.pch") 
 
extern KTrace t;			// Global driver trace object	 
 
GUID PcmciaDevice_Guid = PcmciaDevice_CLASS_GUID; 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::PcmciaDevice 
// 
//	Routine Description: 
//		This is the constructor for the Functional Device Object, or FDO. 
//		It is derived from KPnpDevice, which builds in automatic 
//	    dispatching of subfunctions of IRP_MJ_POWER and IRP_MJ_PNP to 
//		virtual member functions. 
// 
//	Parameters: 
//		Pdo - Physical Device Object - this is a pointer to a system 
//			device object that represents the physical device. 
// 
//		Unit - Unit number. This is a number to append to the device's 
//			base device name to form the Logical Device Object's name 
// 
//	Return Value: 
//		None    
// 
//	Comments: 
//		The object being constructed contains a data member (m_Lower) of type 
//		KPnpLowerDevice. By initializing it, the driver binds the FDO to the 
//		PDO and creates an interface to the upper edge of the system class driver. 
// 
 
PcmciaDevice::PcmciaDevice(PDEVICE_OBJECT Pdo, ULONG Unit) : 
	KPnpDevice(Pdo, &PcmciaDevice_Guid) 
{ 
	t << "Entering PcmciaDevice::PcmciaDevice (constructor)\n"; 
 
 
	// Check constructor status 
    if ( ! NT_SUCCESS(m_ConstructorStatus) ) 
	{ 
	    return; 
	} 
 
	// Remember our unit number 
	m_Unit = Unit; 
 
	// Initialize the lower device 
	m_Lower.Initialize(this, Pdo); 
 
    // Inform the base class of the lower edge device object 
	SetLowerDevice(&m_Lower); 
 
	// Initialize the PnP Policy settings to the "standard" policy 
	SetPnpPolicy(); 
 
// TODO:	Customize the PnP Policy for this device by setting 
//			flags in m_Policies. 
 
	// Initialize the Power Policy settings to the "standard" policy 
	SetPowerPolicy(); 
 
// TODO:	Customize the Power Policy for this device by setting 
//			flags in m_PowerPolicies. 
 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::~PcmciaDevice 
// 
//	Routine Description: 
//		This is the destructor for the Functional Device Object, or FDO. 
// 
//	Parameters: 
//		None 
// 
//	Return Value: 
//		None 
// 
//	Comments: 
//		None 
// 
 
PcmciaDevice::~PcmciaDevice() 
{ 
	t << "Entering PcmciaDevice::~PcmciaDevice() (destructor)\n"; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PNPMinorFunctionName 
// 
//	Routine Description: 
//		Return a string describing the Plug and Play minor function	 
// 
//	Parameters: 
//		mn - Minor function code 
// 
//	Return Value: 
//		char * - Ascii name of minor function 
// 
//	Comments: 
//		This function is used for tracing the IRPs.  Remove the function, 
//		or conditionalize it for debug-only builds, if you want to save 
//		space in the driver image. 
// 
	 
char *PNPMinorFunctionName(ULONG mn) 
{ 
	static char* minors[] = { 
		"IRP_MN_START_DEVICE", 
		"IRP_MN_QUERY_REMOVE_DEVICE", 
		"IRP_MN_REMOVE_DEVICE", 
		"IRP_MN_CANCEL_REMOVE_DEVICE", 
		"IRP_MN_STOP_DEVICE", 
		"IRP_MN_QUERY_STOP_DEVICE", 
		"IRP_MN_CANCEL_STOP_DEVICE", 
		"IRP_MN_QUERY_DEVICE_RELATIONS", 
		"IRP_MN_QUERY_INTERFACE", 
		"IRP_MN_QUERY_CAPABILITIES", 
		"IRP_MN_QUERY_RESOURCES", 
		"IRP_MN_QUERY_RESOURCE_REQUIREMENTS", 
		"IRP_MN_QUERY_DEVICE_TEXT", 
		"IRP_MN_FILTER_RESOURCE_REQUIREMENTS", 
		"", 
		"IRP_MN_READ_CONFIG", 
		"IRP_MN_WRITE_CONFIG", 
		"IRP_MN_EJECT", 
		"IRP_MN_SET_LOCK", 
		"IRP_MN_QUERY_ID", 
		"IRP_MN_QUERY_PNP_DEVICE_STATE", 
		"IRP_MN_QUERY_BUS_INFORMATION", 
		"IRP_MN_DEVICE_USAGE_NOTIFICATION", 
		"IRP_MN_SURPRISE_REMOVAL", 
		"IRP_MN_QUERY_LEGACY_BUS_INFORMATION" 
	}; 
 
	if (mn > 0x18) // IRP_MN_QUERY_LEGACY_BUS_INFORMATION 
		return ""; 
	else 
		return minors[mn]; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::DefaultPnp 
// 
//	Routine Description: 
//		Default handler for IRP_MJ_PNP 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result returned from lower device 
// 
//	Comments: 
//		This routine just passes the IRP through to the lower device. It is  
//		the default handler for IRP_MJ_PNP. IRPs that correspond to 
//		any virtual members of KpnpDevice that handle minor functions of 
//		IRP_MJ_PNP and that are not overridden get passed to this routine. 
// 
 
NTSTATUS PcmciaDevice::DefaultPnp(KIrp I)  
{ 
	t << "Entering PcmciaDevice::DefaultPnp with IRP minor function=" 
	  << PNPMinorFunctionName(I.MinorFunction()) << EOL; 
 
	I.ForceReuseOfCurrentStackLocationInCalldown(); 
	return m_Lower.PnpCall(this, I); 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::DefaultPower 
// 
//	Routine Description: 
//		Default handler for IRP_MJ_POWER  
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result returned from lower device 
// 
//	Comments: 
//		This routine just passes the IRP through to the lower device. It is  
//		the default handler for IRP_MJ_POWER. 
// 
 
NTSTATUS PcmciaDevice::DefaultPower(KIrp I)  
{ 
	t << "Entering PcmciaDevice::DefaultPower\n"; 
 
	I.IndicatePowerIrpProcessed(); 
	I.CopyParametersDown(); 
	return m_Lower.PnpPowerCall(this, I); 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::SystemControl 
// 
//	Routine Description: 
//		Default handler for IRP_MJ_SYSTEM_CONTROL 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result returned from lower device 
// 
//	Comments: 
//		This routine just passes the IRP through to the next device since this driver 
//		is not a WMI provider. 
// 
 
NTSTATUS PcmciaDevice::SystemControl(KIrp I)  
{ 
	t << "Entering PcmciaDevice::SystemControl\n"; 
 
	I.ForceReuseOfCurrentStackLocationInCalldown(); 
	return m_Lower.PnpCall(this, I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::OnStartDevice 
// 
//	Routine Description: 
//		Handler for IRP_MJ_PNP subfcn IRP_MN_START_DEVICE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
//		Initialize the physical device. Typically, the driver initializes 
//		physical resources here.  Call I.AllocatedResources() for a list 
//		of the raw resources that the system has assigned to the device, 
//		or I.TranslatedResources() for the translated resource list. 
// 
 
NTSTATUS PcmciaDevice::OnStartDevice(KIrp I) 
{ 
	t << "Entering PcmciaDevice::OnStartDevice\n"; 
 
	NTSTATUS status = STATUS_SUCCESS; 
 
	I.Information() = 0; 
 
	// The default Pnp policy has already cleared the IRP with the lower device 
	// Initialize the physical device object. 
 
	// Get the list of raw resources from the IRP 
	PCM_RESOURCE_LIST pResListRaw = I.AllocatedResources(); 
	// Get the list of translated resources from the IRP 
	PCM_RESOURCE_LIST pResListTranslated = I.TranslatedResources(); 
 
// TODO:	Add device-specific code to start your device. 
 
    // The base class will handle completion 
 
	return status; 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::OnStopDevice 
// 
//	Routine Description: 
//		Handler for IRP_MJ_PNP subfcn IRP_MN_STOP_DEVICE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
//		The system calls this when the device is stopped. 
//		The driver should release any hardware resources 
//		in this routine. 
// 
//		The base class passes the irp to the lower device. 
// 
 
NTSTATUS PcmciaDevice::OnStopDevice(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering PcmciaDevice::OnStopDevice\n"; 
 
 
// TODO:	Add device-specific code to stop your device    
 
	return status; 
	 
	// The following macro simply allows compilation at Warning Level 4 
	// If you reference this parameter in the function simply remove the macro. 
	UNREFERENCED_PARAMETER(I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::OnRemoveDevice 
// 
//	Routine Description: 
//		Handler for IRP_MJ_PNP subfcn IRP_MN_REMOVE_DEVICE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
//		The system calls this when the device is removed. 
//		Our PnP policy will take care of  
//			(1) giving the IRP to the lower device 
//			(2) detaching the PDO 
//			(3) deleting the device object 
// 
 
NTSTATUS PcmciaDevice::OnRemoveDevice(KIrp I) 
{ 
	t << "Entering PcmciaDevice::OnRemoveDevice\n"; 
 
 
 
 
// TODO:	Add device-specific code to remove your device    
 
	return STATUS_SUCCESS; 
 
	// The following macro simply allows compilation at Warning Level 4 
	// If you reference this parameter in the function simply remove the macro. 
	UNREFERENCED_PARAMETER(I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::OnDevicePowerUp 
// 
//	Routine Description: 
//		Handler for IRP_MJ_POWER with minor function IRP_MN_SET_POWER 
//		for a request to go to power on state from low power state 
// 
//	Parameters: 
//		I - IRP containing POWER request 
// 
//	Return Value: 
//		NTSTATUS - Status code indicating success or failure 
// 
//	Comments: 
//		This routine implements the OnDevicePowerUp function. 
//		This function was called by the framework from the completion 
//		routine of the IRP_MJ_POWER dispatch handler in KPnpDevice. 
//		The bus driver has completed the IRP and this driver can now 
//		access the hardware device.   
//		This routine runs at dispatch level. 
//	 
 
NTSTATUS PcmciaDevice::OnDevicePowerUp(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering PcmciaDevice::OnDevicePowerUp\n"; 
 
// TODO:	Service the device. 
//			Restore any context to the hardware device that 
//			was saved during the handling of a power down request. 
//			See the OnDeviceSleep function. 
//			Do NOT complete this IRP. 
// 
	return status; 
 
	// The following macro simply allows compilation at Warning Level 4 
	// If you reference this parameter in the function simply remove the macro. 
	UNREFERENCED_PARAMETER(I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::OnDeviceSleep 
// 
//	Routine Description: 
//		Handler for IRP_MJ_POWER with minor function IRP_MN_SET_POWER 
//		for a request to go to a low power state from a high power state 
// 
//	Parameters: 
//		I - IRP containing POWER request 
// 
//	Return Value: 
//		NTSTATUS - Status code indicating success or failure 
// 
//	Comments: 
//		This routine implements the OnDeviceSleep function. 
//		This function was called by the framework from the IRP_MJ_POWER  
//		dispatch handler in KPnpDevice prior to forwarding to the PDO. 
//		The hardware has yet to be powered down and this driver can now 
//		access the hardware device.   
//		This routine runs at passive level. 
//	 
 
NTSTATUS PcmciaDevice::OnDeviceSleep(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering PcmciaDevice::OnDeviceSleep\n"; 
 
// TODO:	Service the device. 
//			Save any context to the hardware device that will be required  
//			during a power up request. See the OnDevicePowerUp function. 
//			Do NOT complete this IRP.  The base class handles forwarding 
//			this IRP to the PDO. 
// 
	return status; 
 
	// The following macro simply allows compilation at Warning Level 4 
	// If you reference this parameter in the function simply remove the macro. 
	UNREFERENCED_PARAMETER(I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::Create 
// 
//	Routine Description: 
//		Handler for IRP_MJ_CREATE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
// 
 
NTSTATUS PcmciaDevice::Create(KIrp I) 
{ 
	NTSTATUS status; 
 
	t << "Entering PcmciaDevice::Create, " << I << EOL; 
 
// TODO: Add driver specific create handling code here 
 
	// Generally a create IRP is targeted at our FDO, so we don't need 
	// to pass it down to the PDO.  We have found for some devices, the 
	// PDO is not expecting this Irp and returns an error code. 
	// The default wizard code, therefore completes the Irp here using 
	// PnpComplete().  The following commented code could be used instead 
	// of PnpComplete() to pass the Irp to the PDO, which would complete it. 
	// 
//	I.ForceReuseOfCurrentStackLocationInCalldown(); 
//	status = m_Lower.PnpCall(this, I); 
 
	status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT); 
 
	t << "PcmciaDevice::Create Status " << (ULONG)status << EOL; 
 
	return status; 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::Close 
// 
//	Routine Description: 
//		Handler for IRP_MJ_CLOSE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
// 
 
NTSTATUS PcmciaDevice::Close(KIrp I) 
{ 
	NTSTATUS status; 
 
	t << "Entering PcmciaDevice::Close, " << I << EOL; 
 
// TODO: Add driver specific close handling code here 
 
	// Generally a close IRP is targeted at our FDO, so we don't need 
	// to pass it down to the PDO.  We have found for some devices, the 
	// PDO is not expecting this Irp and returns an error code. 
	// The default wizard code, therefore completes the Irp here using 
	// PnpComplete().  The following commented code could be used instead 
	// of PnpComplete() to pass the Irp to the PDO, which would complete it. 
	// 
//	I.ForceReuseOfCurrentStackLocationInCalldown(); 
//	status = m_Lower.PnpCall(this, I); 
 
	status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT); 
 
	t << "PcmciaDevice::Close Status " << (ULONG)status << EOL; 
 
    return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::Cleanup 
// 
//	Routine Description: 
//		Handler for IRP_MJ_CLEANUP	 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
// 
 
NTSTATUS PcmciaDevice::CleanUp(KIrp I) 
{ 
	t << "Entering CleanUp, " << I << EOL; 
 
// TODO:	Insert your code to respond to the CLEANUP message. 
//			This code cleans up the single Wizard created queue.  If you 
//			have created additional queues,	or have any outstanding Irps 
//			stored in some other fashion in your driver, you should clean 
//			these up as well for the file object specified in the cleanup Irp. 
 
	m_DriverManagedQueue.PnpCleanUp(this, I.FileObject()); 
	return I.PnpComplete(this, STATUS_SUCCESS); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::SerialRead 
//	 
//	Routine Description: 
//		Handler for serialized READ 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		None 
// 
//	Comments: 
//		This routine is called when the IRP is removed from the 
//		STARTIO queue.  This guarantees that multiple requests are 
//		never processed simultaneously. 
// 
//		This routine is called at dispatch level. 
// 
 
void PcmciaDevice::SerialRead(KIrp I) 
{ 
	t << "Entering PcmciaDevice::SerialRead, " << I << EOL; 
	NTSTATUS status		= STATUS_SUCCESS; 
 
	// Declare a memory object 
	KMemory Mem(I.Mdl()); 
	// Use the memory object to create a pointer to the caller's buffer 
	PUCHAR	pBuffer		= (PUCHAR) Mem.MapToSystemSpace(); 
 
	ULONG   dwTotalSize = I.ReadSize(CURRENT);	// Requested read size 
	ULONG   dwBytesRead = 0;					// Count of bytes read 
 
// TODO:	If the read can be satisfied immediately, set the Information 
//			and Status fields now, then call NextIrp to complete this IRP 
//			and start processing the next IRP in the queue. 
 
// TODO:	If the data is not yet available, initiate a request to the 
//			physical device here, and defer the Information, Status, 
//			and NextIrp handling until the hardware indicates that the 
//			read is complete.  Typically, this might be handled in a 
//			DPC that is called after the hardware finishes transferring 
//			the data. 
 
// TODO:	To satisfy the read now, transfer data from the device to 
//			caller's buffer at "pBuffer".  Then, indicate how much data was 
//			transferred: 
 
	I.Information() = dwBytesRead; 
 
	I.Status() = status; 
 
 
	// PnpNextIrp completes this IRP and starts processing  
	// for the next IRP in the driver managed queue. 
// TODO:	The Wizard creates a single queue for all Irps. 
//			If you have created additional queues, select 
//			the appropriate queue for this Irp here. 
	m_DriverManagedQueue.PnpNextIrp(I); 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::Read 
// 
//	Routine Description: 
//		Handler for IRP_MJ_READ 
// 
//	Parameters: 
//		I			Current IRP 
// 
//	Return Value: 
//		NTSTATUS	Result code 
// 
//	Comments: 
//		This routine handles read requests. 
// 
//		The KPnpDevice class handles restricting IRP flow 
//		if the device is stopping or being removed. 
// 
 
NTSTATUS PcmciaDevice::Read(KIrp I)  
{ 
	t << "Entering PcmciaDevice::Read, " << I << EOL; 
// TODO:	Check the incoming request.  Replace "FALSE" in the following 
//			line with a check that returns TRUE if the request is not valid. 
 
    if (FALSE)		// If (Request is invalid) 
	{ 
		// Invalid parameter in the Read request 
		I.Information() = 0; 
		return I.PnpComplete(this, STATUS_INVALID_PARAMETER); 
	} 
 
	// Always ok to read 0 elements. 
	if (I.ReadSize() == 0) 
	{ 
		I.Information() = 0; 
		return I.PnpComplete(this, STATUS_SUCCESS); 
	} 
 
	// Queue the IRP for processing in the driver managed queue. 
	// The actual read function is performed in SerialRead 
// TODO:	The Wizard creates a single queue for all Irps. 
//			If you have created additional queues, select 
//			the appropriate queue for this Irp here. 
	return m_DriverManagedQueue.QueueIrp(I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::SerialWrite 
//	 
//	Routine Description: 
//		Handler for serialized WRITE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		None 
// 
//	Comments: 
//		This routine is called when the IRP is removed from the 
//		STARTIO queue.  This guarantees that multiple requests are 
//		never processed simultaneously. 
// 
 
void PcmciaDevice::SerialWrite(KIrp I) 
{ 
	t << "Entering PcmciaDevice::SerialWrite, " << I << EOL; 
	NTSTATUS status		= STATUS_SUCCESS; 
 
	// Declare a memory object 
	KMemory Mem(I.Mdl()); 
	// Use the memory object to create a pointer to the caller's buffer 
	PUCHAR	pBuffer		= (PUCHAR) Mem.MapToSystemSpace(); 
 
	ULONG   dwTotalSize = I.WriteSize(CURRENT); 
	ULONG   dwBytesSent = 0; 
 
// TODO:	If the write can be satisfied immediately, set the Information 
//			and Status fields now, then call NextIrp to complete this IRP 
//			and start processing the next IRP in the queue. 
 
// TODO:	If the device cannot accept all of the data yet, initiate a  
//			request to the physical device here, and defer the Information, 
//			Status, and NextIrp handling until the hardware indicates that 
//			the write is complete.  Typically, this might be handled in a 
//			DPC that is called after the hardware finishes transferring 
//			the data. 
 
// TODO:	To satisfy the write now, transfer data to the device 
//			from caller's buffer at "pBuffer".  Then, indicate how much 
//			data was transferred: 
 
	I.Information() = dwBytesSent; 
 
	I.Status() = status; 
 
 
	// PnpNextIrp completes this IRP and starts processing  
	// for the next IRP in the driver managed queue. 
// TODO:	The Wizard creates a single queue for all Irps. 
//			If you have created additional queues, select 
//			the appropriate queue for this Irp here. 
	m_DriverManagedQueue.PnpNextIrp(I); 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::Write 
// 
//	Routine Description: 
//		Handler for IRP_MJ_WRITE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
//		This routine handles write requests. 
// 
//		The KPnpDevice class handles restricting IRP flow 
//		if the device is stopping or being removed. 
// 
 
NTSTATUS PcmciaDevice::Write(KIrp I)  
{ 
	t << "Entering PcmciaDevice::Write, " << I << EOL; 
// TODO:	Check the incoming request.  Replace "FALSE" in the following 
//			line with a check that returns TRUE if the request is not valid. 
    if (FALSE) 
	{ 
		// Invalid parameter in the Write request 
		I.Information() = 0; 
		return I.PnpComplete(this, STATUS_INVALID_PARAMETER); 
	} 
 
	// Always ok to write 0 elements. 
	if (I.WriteSize() == 0) 
	{ 
		I.Information() = 0; 
		return I.PnpComplete(this, STATUS_SUCCESS); 
	} 
 
	// Queue the IRP for processing in the driver managed queue. 
	// The actual write function is performed in SerialWrite 
 
// TODO:	The Wizard creates a single queue for all Irps. 
//			If you have created additional queues, select 
//			the appropriate queue for this Irp here. 
	return m_DriverManagedQueue.QueueIrp(I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice::DeviceControl 
// 
//	Routine Description: 
//		Handler for IRP_MJ_DEVICE_CONTROL 
// 
//	Parameters: 
//		I - Current IRP 
//  
//	Return Value: 
//		None 
// 
//	Comments: 
//		This routine is the first handler for Device Control requests. 
//		Some function codes may be handled immediately,  
//		while others may be serialized through the StartIo routine. 
//		 
//		The KPnpDevice class handles restricting IRP flow 
//		if the device is stopping or being removed. 
// 
 
NTSTATUS PcmciaDevice::DeviceControl(KIrp I)  
{ 
	NTSTATUS status; 
 
	t << "Entering PcmciaDevice::Device Control, " << I << EOL; 
	switch (I.IoctlCode()) 
	{ 
		default: 
			// Unrecognized IOCTL request 
			status = STATUS_INVALID_PARAMETER; 
			break; 
	} 
 
	// If the IRP was queued, or its IOCTL handler deferred processing using some 
	// driver specific scheme, the status variable is set to STATUS_PENDING. 
	// In this case we simply return that status, and the IRP will be completed 
	// later.  Otherwise, complete the IRP using the status returned by the 
	// IOCTL handler. 
	if (status == STATUS_PENDING) 
	{ 
		return status; 
	} 
	else 
	{ 
		return I.PnpComplete(this, status); 
	} 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
//  PcmciaDevice_DriverManagedQueue::StartIo 
//	 
//	Routine Description: 
//		This routine is called when an IRP is taken off 
//		the Driver Managed Queue (used for serializing I/O) and 
//		presented for processing. 
// 
//	Parameters: 
//		I - IRP removed from queue 
// 
//	Return Value: 
//		None 
// 
//	Comments: 
// 
 
VOID PcmciaDevice_DriverManagedQueue::StartIo(KIrp I) 
{ 
	t  << "Entering PcmciaDevice_DriverManagedQueue StartIo, " << I; 
 
	// The KDriverManagedQueueEx class gives us the Irp in a non-cancelable state 
	// (cancel routine set to NULL) so we can process it without having to worry 
	// about clearing the cancel routine first, as is the case with system queuing, 
	// or the legacy class KDriverManagedQueue. You may want to set a different cancel 
	// routine here, or at other points during the processing of this Irp. 
 
	// Find the device class so we can call the serialized 
	// routines in the device class.  The handlers can be 
	// moved to the DriverManagedQueue class if it is more 
	// convenient. 
	PcmciaDevice *pDev = (PcmciaDevice *) KDevicePTR(I.DeviceObject()); 
 
	// Start processing request. 
 
	// Switch on the IRP's function: 
	switch (I.MajorFunction()) 
	{ 
		case IRP_MJ_READ: 
			pDev->SerialRead(I); 
			break; 
 
		case IRP_MJ_WRITE: 
			pDev->SerialWrite(I); 
			break; 
 
		case IRP_MJ_DEVICE_CONTROL: 
			switch (I.IoctlCode()) 
			{ 
				default: 
					// We queued a request that shouldn't have been queued 
					// (should never get here) 
					ASSERT(FALSE); 
					break; 
			} 
			break; 
 
		default: 
			// Error - unexpected IRP received 
			// NextIrp completes this IRP and starts processing 
			// for the next IRP in the queue. 
			ASSERT(FALSE); 
			I.Status() = STATUS_INVALID_PARAMETER; 
			PnpNextIrp(I); 
			break; 
	} 
}