www.pudn.com > BPSK9054.rar > BPSKDevice.cpp


// BPSKDevice.cpp 
// Implementation of BPSKDevice device class 
// 
// Generated by DriverWizard version DriverStudio 3.1.0 (Build 1722) 
// Requires Compuware's DriverWorks classes 
// 
#pragma warning(disable:4065) // Allow switch statement with no cases 
		   
#include  
#include "BPSKDeviceinterface.h" 
 
#include "BPSK.h" 
#include "BPSKDevice.h" 
#include "BPSKioctl.h" 
 
#pragma hdrstop("BPSK.pch") 
 
extern KDebugOnlyTrace t;	// Global driver trace object	 
 
GUID BPSKDevice_Guid = BPSKDevice_CLASS_GUID; 
 
#define INTCSR    0x68  //中断控制地址 
#define DMAMODE0  0x80  //DMA0通道 
#define DMAPADR0  0x84  //DMA0通道PCI地址 
#define DMALADR0  0x88  //DMA0通道本地地址 
#define DMASIZ0   0x8C  //DMA0通道传输字节计数 
#define DMADPR0   0x90  //DMA0通道指针 
#define DMACSR0   0xA8  //DMA(0、1)通道状态 
 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::BPSKDevice 
// 
//	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. 
// 
BPSKDevice::BPSKDevice(PDEVICE_OBJECT Pdo, ULONG Unit) : 
	KPnpDevice(Pdo, &BPSKDevice_Guid) 
{ 
	t << "Entering BPSKDevice::BPSKDevice (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. 
 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::~BPSKDevice 
// 
//	Routine Description: 
//		This is the destructor for the Functional Device Object, or FDO. 
// 
//	Parameters: 
//		None 
// 
//	Return Value: 
//		None 
// 
//	Comments: 
//		None 
// 
 
BPSKDevice::~BPSKDevice() 
{ 
	t << "Entering BPSKDevice::~BPSKDevice() (destructor)\n"; 
} 
 
 
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" 
	}; 
 
	if (mn > IRP_MN_SURPRISE_REMOVAL)  
		return ""; 
	else 
		return minors[mn]; 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::DefaultPnp(KIrp I)  
{ 
	t << "Entering BPSKDevice::DefaultPnp\n" << I << EOL; 
 
	I.ForceReuseOfCurrentStackLocationInCalldown(); 
	return m_Lower.PnpCall(this, I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::DefaultPower(KIrp I)  
{ 
	t << "Entering BPSKDevice::DefaultPower\n" << I << EOL; 
 
	I.IndicatePowerIrpProcessed(); 
	I.CopyParametersDown(); 
	return m_Lower.PnpPowerCall(this, I); 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::SystemControl(KIrp I)  
{ 
	t << "Entering BPSKDevice::SystemControl\n"; 
 
	I.ForceReuseOfCurrentStackLocationInCalldown(); 
	return m_Lower.PnpCall(this, I); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::Invalidate 
// 
//	Routine Description: 
//		Calls Invalidate methods for system resources 
// 
//	Parameters: 
//		None 
// 
//	Return Value: 
//		None 
// 
//	Comments: 
//		This function is called from OnStopDevice, OnRemoveDevice and 
//		OnStartDevice (in error conditions).  It calls the Invalidate 
//		member funcitons for each resource to free the underlying system 
//		resource if allocated.  It is safe to call Invalidate more than 
//		once for a resource, or for an uninitialized resource. 
 
VOID BPSKDevice::Invalidate() 
{ 
 
	// It is not necessary to release the system resource for the DMA adapter 
	// object, since NT provides no mechanism for this. 
	//不需要释放DMA适配器对象即m_Dma; 
	if(m_Buffer.IsValid()) 
	m_Buffer.Invalidate();//添加 
	// For each memory mapped region, release the underlying system resoruce. 
	m_MemoryRange0.Invalidate(); 
 
	// For each I/O port mapped region, release the underlying system resource. 
	m_IoPortRange0.Invalidate(); 
	m_IoPortRange1.Invalidate(); 
 
	// For the interrupt, release the underlying system resource. 
//	m_Irq.Invalidate(); 
	if(m_pEvent) 
		delete m_pEvent; 
	if(m_pEvent1) 
		delete m_pEvent1; 
 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::OnStartDevice(KIrp I) 
{ 
	t << "Entering BPSKDevice::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:	Check to ensure that the following parameters are correct for your hardware 
// 
#define MAX_DMA_LENGTH	0x100000	// 0x100000 is 1 MB 
//DMA对象 
	// Initialize the device descriptor for the DMA object using the assigned resource 
	DEVICE_DESCRIPTION dd; 
	RtlZeroMemory(&dd, sizeof(dd)); 
	dd.Version = DEVICE_DESCRIPTION_VERSION; 
	dd.Master = TRUE; 
	dd.ScatterGather = FALSE; 
	dd.DemandMode = FALSE;//Indicates whether to use the system DMA controller's demand mode. Not used for busmaster DMA.  
	dd.AutoInitialize = FALSE; 
	dd.Dma32BitAddresses = TRUE; 
	dd.IgnoreCount = FALSE; 
	dd.DmaChannel = 0; 
	dd.InterfaceType = PCIBus; 
	dd.DmaWidth = Width32Bits;	// PCI default width 32bit 
	dd.DmaSpeed = Compatible; 
	dd.MaximumLength = MAX_DMA_LENGTH; 
 
	// Initialize the DMA adapter object 
	m_Dma.Initialize(&dd, m_Lower.TopOfStack()); 
	m_Buffer.Initialize(&m_Dma,1024*64);//初始化KCommonDmaBuffer类对象大小64k 
	KPciConfiguration PciConfig(m_Lower.TopOfStack()); 
 
	// For each memory mapped region, initialize the memory mapped range 
	// using the resources provided by NT. Once initialized, each memory 
	// range's base virtual address in system space can be obtained by calling 
	// member Base(). Each memory range's physical address in CPU space can 
	// obtained by calling CpuPhysicalAddress(). To access the memory mapped 
	// range use member functions such as inb/outb, or the array element operator.  
	status = m_MemoryRange0.Initialize( 
		pResListTranslated, 
		pResListRaw, 
		PciConfig.BaseAddressIndexToOrdinal(0) 
			); 
 
	if (!NT_SUCCESS(status)) 
	{ 
		Invalidate(); 
		return status;		 
	} 
 
	// For each I/O port mapped region, initialize the I/O port range using 
	// the resources provided by NT. Once initialized, use member functions such as 
	// inb/outb, or the array element operator to access the ports range. 
	status = m_IoPortRange0.Initialize( 
		pResListTranslated, 
		pResListRaw, 
		PciConfig.BaseAddressIndexToOrdinal(1) 
		); 
	 
	if (!NT_SUCCESS(status)) 
	{ 
		Invalidate(); 
		return status;		 
	} 
 
	status = m_IoPortRange1.Initialize( 
		pResListTranslated, 
		pResListRaw, 
		PciConfig.BaseAddressIndexToOrdinal(2), 
		TRUE 
		); 
	 
	if (!NT_SUCCESS(status)) 
	{ 
		Invalidate(); 
		return status;		 
	} 
 
	// Initialize and connect the interrupt 
	status = m_Irq.InitializeAndConnect( 
		pResListTranslated,  
		LinkTo(Isr_Irq),  
		this 
		); 
	if (!NT_SUCCESS(status)) 
	{ 
		Invalidate(); 
		return status;		 
	} 
 
	// Setup the DPC to be used for interrupt processing 
	m_DpcFor_Irq.Setup(LinkTo(DpcFor_Irq), this); 
 
// TODO:	Add device-specific code to start your device. 
 
    // The base class will handle completion 
 
	return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::DeviceControl(KIrp I)  
{ 
	NTSTATUS status; 
 
	t << "Entering BPSKDevice::Device Control, " << I << EOL; 
	switch (I.IoctlCode()) 
	{ 
		case CONFIG_SYMBOL_RATE: 
			status = CONFIG_SYMBOL_RATE_Handler(I); 
			break; 
 
		case MODULATE_MODE: 
			status = MODULATE_MODE_Handler(I); 
			break; 
 
		case SET_IF_FRE: 
			status = SET_IF_FRE_Handler(I); 
			break; 
 
		case CTRL_AD9851_INIT: 
			status = CTRL_AD9851_INIT_Handler(I); 
			break; 
 
		case IOCTL_SET_NOTIFICATION_EVENT: 
			status = IOCTL_SET_NOTIFICATION_EVENT_Handler(I); 
			break; 
 
		case START_COLLECT: 
			status = START_COLLECT_Handler(I); 
			break; 
		case STOP_COLLECT: 
			status = STOP_COLLECT_Handler(I); 
			break; 
 
		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); 
	} 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::OnStopDevice(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering BPSKDevice::OnStopDevice\n"; 
 
	// Device stopped, release the system resources. 
	Invalidate(); 
 
// 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); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::OnRemoveDevice(KIrp I) 
{ 
	t << "Entering BPSKDevice::OnRemoveDevice\n"; 
 
	// Device removed, release the system resources. 
	m_Irq.Disconnect(); 
	 
	// Device removed, release the system resources. 
	m_Irq.Invalidate(); 
	Invalidate(); 
 
// 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); 
} 
VOID BPSKDevice::CancelQueuedIrp(KIrp I) 
{ 
	KDeviceQueue dq(DeviceQueue()); 
 
	// Test if the IRP is the current IRP如果请求的IRP是当前IRP就直接将他删除. 
	if ( (PIRP)I == CurrentIrp() ) 
	{ 
		CurrentIrp() = NULL; 
		CancelSpinLock::Release(I.CancelIrql()); 
	    I.Information() = 0; 
		I.Status() = STATUS_CANCELLED; 
		PnpNextIrp(I); 
	} 
	// See if the IRP can be removed from the device queue,如果不是当前的但是在排队序列中就找到他然后将其删除. 
	else if (dq.RemoveSpecificEntry(I)) 
	{ 
		CancelSpinLock::Release(I.CancelIrql()); 
	    I.Information() = 0; 
		I.PnpComplete(this, STATUS_CANCELLED); 
	} 
	//如果请求取消的IRP不在对列中,释放对IRP的请求 
	else 
	{ 
		CancelSpinLock::Release(I.CancelIrql()); 
	} 
} 
 
VOID BPSKDevice::StartIo(KIrp I) 
{ 
	if ( !I.TestAndSetCancelRoutine( 
		LinkTo(CancelQueuedIrp), 
		NULL, 
		CurrentIrp()) ) 
	{ 
		return; 
	} 
 
	switch (I.MajorFunction()) 
	{ 
		case IRP_MJ_READ: 
			SerialRead(I); 
			break; 
		case IRP_MJ_WRITE: 
			SerialWrite(I); 
			break; 
		default: 
			ASSERT(FALSE); 
			PnpNextIrp(I); 
			break; 
	} 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::OnDevicePowerUp(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering BPSKDevice::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); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::OnDeviceSleep(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering BPSKDevice::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); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::Create 
// 
//	Routine Description: 
//		Handler for IRP_MJ_CREATE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
// 
 
NTSTATUS BPSKDevice::Create(KIrp I) 
{ 
	NTSTATUS status; 
 
	t << "Entering BPSKDevice::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 << "BPSKDevice::Create Status " << (ULONG)status << EOL; 
 
	return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::Close 
// 
//	Routine Description: 
//		Handler for IRP_MJ_CLOSE 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
// 
 
NTSTATUS BPSKDevice::Close(KIrp I) 
{ 
	NTSTATUS status; 
 
	t << "Entering BPSKDevice::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 << "BPSKDevice::Close Status " << (ULONG)status << EOL; 
 
    return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::Cleanup 
// 
//	Routine Description: 
//		Handler for IRP_MJ_CLEANUP	 
// 
//	Parameters: 
//		I - Current IRP 
// 
//	Return Value: 
//		NTSTATUS - Result code 
// 
//	Comments: 
// 
 
NTSTATUS BPSKDevice::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. 
	KDeviceQueue dq(DeviceQueue()); 
	dq.PnpCleanUp(this, I.FileObject()); 
	return I.PnpComplete(this, STATUS_SUCCESS); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::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 BPSKDevice::SerialRead(KIrp I) 
{ 
	t << "Entering BPSKDevice::SerialRead, " << I << EOL; 
	NTSTATUS status		= STATUS_SUCCESS; 
//进行DMA传输 
 
	m_CurrentTransfer=new(NonPagedPool)KDmaTransfer(this,&m_Dma); 
	if(m_CurrentTransfer==NULL) 
	{ 
		status=STATUS_INSUFFICIENT_RESOURCES; 
		t<<"unable to allocate transfer object:"<Initiate(I.Mdl(),(I.MajorFunction()==IRP_MJ_READ)? 
								FromDeviceToMemory:FromMemoryToDevice, 
								LinkTo(OnDmaReady) 
										); 
*/ 
	status=m_CurrentTransfer->Initiate(this,&m_Dma,I.Mdl(),(I.MajorFunction()==IRP_MJ_READ)? 
					FromDeviceToMemory:FromMemoryToDevice, 
					LinkTo(OnDmaReady),&m_Buffer 
				   ); 
 
	// If the transfer cannot be initiated, complete it with an error status. 
	if ( ! NT_SUCCESS(status) ) 
	{ 
		t<<"unable to initiate transfer: "<< status<BytesCount;i++) 
	{ 
		t<< "Control Word is:  "<ControlWord[i]<ControlWord[i]); 
	} 
	BYTE TEMP=m_IoPortRange1.inb(0xf0);//0xf0:Range for PCI-to-Local Address Space 1 
	I.Information() = 0; 
 
	return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::MODULATE_MODE_Handler 
// 
//	Routine Description: 
//		Handler for IO Control Code MODULATE_MODE 
// 
//	Parameters: 
//		I - IRP containing IOCTL request 
// 
//	Return Value: 
//		NTSTATUS - Status code indicating success or failure 
// 
//	Comments: 
//		This routine implements the MODULATE_MODE function. 
//		This routine runs at passive level. 
// 
 
NTSTATUS BPSKDevice::MODULATE_MODE_Handler(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering BPSKDevice::MODULATE_MODE_Handler, " << I << EOL; 
// TODO:	Verify that the input parameters are correct 
//			If not, return STATUS_INVALID_PARAMETER 
 
// TODO:	Handle the the MODULATE_MODE request, or  
//			defer the processing of the IRP (i.e. by queuing) and set 
//			status to STATUS_PENDING. 
 
// TODO:	Assuming that the request was handled here. Set I.Information 
//			to indicate how much data to copy back to the user. 
	BYTE *ModulMode=(BYTE *)(I.IoctlBuffer()); 
	BYTE TEMP=*ModulMode; 
	m_IoPortRange1.outb(0x30,*ModulMode);//0x30:PCI Base Address for Local Expansion ROM 
	I.Information() = 0; 
 
	return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::SET_IF_FRE_Handler 
// 
//	Routine Description: 
//		Handler for IO Control Code SET_IF_FRE 
// 
//	Parameters: 
//		I - IRP containing IOCTL request 
// 
//	Return Value: 
//		NTSTATUS - Status code indicating success or failure 
// 
//	Comments: 
//		This routine implements the SET_IF_FRE function. 
//		This routine runs at passive level. 
// 
 
NTSTATUS BPSKDevice::SET_IF_FRE_Handler(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering BPSKDevice::SET_IF_FRE_Handler, " << I << EOL; 
// TODO:	Verify that the input parameters are correct 
//			If not, return STATUS_INVALID_PARAMETER 
 
// TODO:	Handle the the SET_IF_FRE request, or  
//			defer the processing of the IRP (i.e. by queuing) and set 
//			status to STATUS_PENDING. 
 
// TODO:	Assuming that the request was handled here. Set I.Information 
//			to indicate how much data to copy back to the user. 
	IF_FRE_STRUCT *IF_FRE= (IF_FRE_STRUCT *)(I.IoctlBuffer()); 
	for(DWORD i = 0;i < IF_FRE->BytesCount;i++) 
	{ 
		t<< "Control Word is:  "<ControlWord[i]<ControlWord[i]); 
	} 
	m_IoPortRange1.inb(0x60);//0x60:PCI-to-Local Doorbell Register 
	I.Information() = 0; 
 
	return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::CTRL_AD9851_INIT_Handler 
// 
//	Routine Description: 
//		Handler for IO Control Code CTRL_AD9851_INIT 
// 
//	Parameters: 
//		I - IRP containing IOCTL request 
// 
//	Return Value: 
//		NTSTATUS - Status code indicating success or failure 
// 
//	Comments: 
//		This routine implements the CTRL_AD9851_INIT function. 
//		This routine runs at passive level. 
// 
 
NTSTATUS BPSKDevice::CTRL_AD9851_INIT_Handler(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering BPSKDevice::CTRL_AD9851_INIT_Handler, " << I << EOL; 
// TODO:	Verify that the input parameters are correct 
//			If not, return STATUS_INVALID_PARAMETER 
 
// TODO:	Handle the the CTRL_AD9851_INIT request, or  
//			defer the processing of the IRP (i.e. by queuing) and set 
//			status to STATUS_PENDING. 
 
// TODO:	Assuming that the request was handled here. Set I.Information 
//			to indicate how much data to copy back to the user. 
	m_IoPortRange1.inb(0x90); 
	AD9851_CONTROL_STRUCT *AD9851_ctrl = (AD9851_CONTROL_STRUCT *)(I.IoctlBuffer()); 
	for(DWORD i = 0;i < AD9851_ctrl->BytesCount;i++) 
	{ 
		t<< "Control Word is:  "<ControlWord[i]<ControlWord[i]); 
	} 
	m_IoPortRange1.inb(0x60);//0x60:PCI-to-Local Doorbell Register 
	I.Information() = 0; 
 
	return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::BPSK_IOCTL_804_Handler 
// 
//	Routine Description: 
//		Handler for IO Control Code BPSK_IOCTL_804 
// 
//	Parameters: 
//		I - IRP containing IOCTL request 
// 
//	Return Value: 
//		NTSTATUS - Status code indicating success or failure 
// 
//	Comments: 
//		This routine implements the BPSK_IOCTL_804 function. 
//		This routine runs at passive level. 
// 
 
NTSTATUS BPSKDevice::IOCTL_SET_NOTIFICATION_EVENT_Handler(KIrp I) 
{ 
	t << "Entering BPSKDevice::IOCTL_SET_NOTIFICATION_EVENT_Handler, " << I << EOL; 
 
	HANDLE hEvent; 
	NTSTATUS status; 
	hEvent=*(HANDLE*)I.IoctlBuffer(); 
/*	KMemory Mem(I.Mdl()); 
	// Use the memory object to create a pointer to the caller's buffer 
	hEvent=*(HANDLE*) Mem.MapToSystemSpaceAddress(); 
*/ 
	m_pEvent=new(NonPagedPool)KEvent(hEvent,OBJECT_TYPE_ALL_ACCESS); 
	status=(m_pEvent!=NULL)?STATUS_SUCCESS:STATUS_INSUFFICIENT_RESOURCES; 
	I.Information()=0; 
	return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::DpcFor_Irq 
// 
//	Routine Description: 
//		Deferred Procedure Call (DPC) for Irq 
// 
//	Parameters: 
//		Arg1 - User-defined context variable 
//		Arg2 - User-defined context variable 
// 
//	Return Value: 
//		None 
// 
//	Comments: 
//		This function is called for secondary processing of an interrupt. 
//		Most code that runs at elevated IRQL should run here rather than 
//		in the ISR, so that other interrupt handlers can continue to run. 
// 
 
VOID BPSKDevice::DpcFor_Irq(PVOID Arg1, PVOID Arg2) 
{ 
	t<<"Entering Dpc"<Continue(UseTransferSize); 
		t<<"继续DMA传输"<Set(); 
		} 
		else 
			t<<"DPC error synchronizing\n"; 
	} 
	} 
	UNREFERENCED_PARAMETER(Arg1); 
	UNREFERENCED_PARAMETER(Arg2); 
	 
} 
BOOLEAN BPSKDevice::TestAndClearNotifyApp(PVOID p) 
{ 
	t<<"Entering BPSKDevice::TestAndClearNotifyApp, "<< EOL; 
	*(BOOLEAN*)p=m_bNotifyApp; 
	m_bNotifyApp=FALSE; 
	return TRUE; 
} 
//////////////////////////////////////////////////////////////////////// 
//  BPSKDevice::Isr_Irq 
// 
//	Routine Description: 
//		Interrupt Service Routine (ISR) for IRQ Irq 
// 
//	Parameters: 
//		None 
//  
//	Return Value: 
//		BOOLEAN		True if this is our interrupt 
// 
//	Comments: 
// 
 
BOOLEAN BPSKDevice::Isr_Irq(void) 
{ 
	t<<"Entering Isr_Irq."<BytesRemaining(); 
	if (pXfer->BytesRemaining() == 0) 
	{ 
		// If there are no bytes left to transfer, the callback must call 
		// Terminate(). Then it completes the IRP with STATUS_SUCCESS. 
		pXfer->Terminate(); 
		I.Information() = I.ReadSize(CURRENT); 
		I.Status() = STATUS_SUCCESS; 
		PnpNextIrp(I); 
		m_CurrentTransfer = NULL; 
//		t<<"一次DMA传输结束,通知应用程序取数据"<Set(); 
		delete pXfer; 
		m_IoPortRange0.outd(INTCSR,0x40900);//允许本地中断 
		return; 
	} 
 
	// We must get the descriptor for the physical memory location for 
	// the DMA transfer. 
 
	PTRANSFER_DESCRIPTOR ptd; 
 
	while (pXfer->SequenceTransferDescriptors(&ptd)) { 
		// program the h/w using  ppTD 
		t << " Physical address 0x" << ptd->td_PhysAddr.LowPart << ". Length is 0x" 
			<< ptd->td_Length << "." << EOL; 
	} 
 
	// If this is the first time through, then start the DMA going. 
	// We only want to do this ONCE for a given Read transfer.  That 
	// way, our data will be collected smoothly, without interruptions 
	// or dropouts. 
	TEMP=I.ReadSize(); 
	if ((ULONG) pXfer->BytesRemaining() == I.ReadSize()) 
		StartDMA(ptd->td_PhysAddr.LowPart,ptd->td_Length); 
} 
 
 
 
NTSTATUS BPSKDevice::START_COLLECT_Handler(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
	ULONG test2; 
	t << "Entering BPSKDevice::START_COLLECT_Handler, " << I << EOL; 
 
//	m_IoPortRange1.inb(0x90); 
	m_IoPortRange1.inb(0x10);//0x10 
	// TODO:允许PCI中断和DMA通道0中断 
	m_IoPortRange0.outd(INTCSR,0x40900); 
	test2=m_IoPortRange0.ind(INTCSR); 
	I.Information() = 0; 
 
	return status; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//  PCI9054Device::PCI9054_IOCTL_803_Handler 
// 
//	Routine Description: 
//		Handler for IO Control Code PCI9054_IOCTL_803 
// 
//	Parameters: 
//		I - IRP containing IOCTL request 
// 
//	Return Value: 
//		NTSTATUS - Status code indicating success or failure 
// 
//	Comments: 
//		This routine implements the PCI9054_IOCTL_803 function. 
//		This routine runs at passive level. 
// 
 
NTSTATUS BPSKDevice::STOP_COLLECT_Handler(KIrp I) 
{ 
	NTSTATUS status = STATUS_SUCCESS; 
 
	t << "Entering BPSKDevice::STOP_COLLECT_Handler, " << I << EOL; 
	m_IoPortRange1.inb(0x20);//0x20:Local Base Address for PCI Initiator-to-PCI Memory 
	I.Information() = 0; 
 
	return status; 
}