⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci9054device.cpp

📁 DS+DDK+VC开发的适用于PCI、PCI-E的驱动程序。
💻 CPP
字号:
// PCI9054Device.cpp
// Implementation of PCI9054Device device class
//
// Generated by DriverWizard version DriverStudio 2.6.0 (Build 336)
// Requires Compuware's DriverWorks classes
//

#pragma warning(disable:4065) // Allow switch statement with no cases
		  
#include <vdw.h>
#include "..\PCI9054Deviceinterface.h"

#include "PCI9054.h"
#include "PCI9054Device.h"

#pragma hdrstop("PCI9054.pch")


#define INTCSR    0x68
#define DMAMODE0  0x80
#define DMAPADR0  0x84
#define DMALADR0  0x88
#define DMASIZ0   0x8C
#define DMADPR0   0x90
#define DMACSR0   0xA8
#define CNTRL	  0x6C

GUID PCI9054Device_Guid = PCI9054Device_CLASS_GUID;
KTrace t("PCI9054");

PCI9054Device::PCI9054Device(PDEVICE_OBJECT Pdo, ULONG Unit) :
	KPnpDevice(Pdo, &PCI9054Device_Guid)
{

	// 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();

}

PCI9054Device::~PCI9054Device()
{
}

NTSTATUS PCI9054Device::DefaultPnp(KIrp I) 
{
	I.ForceReuseOfCurrentStackLocationInCalldown();
	return m_Lower.PnpCall(this, I);
}

NTSTATUS PCI9054Device::DefaultPower(KIrp I) 
{
	I.IndicatePowerIrpProcessed();
	I.CopyParametersDown();
	return m_Lower.PnpPowerCall(this, I);
}

NTSTATUS PCI9054Device::SystemControl(KIrp I) 
{
	I.ForceReuseOfCurrentStackLocationInCalldown();
	return m_Lower.PnpCall(this, I);
}

VOID PCI9054Device::Invalidate()
{
	// It is not necessary to release the system resource for the DMA adapter
	// object, since NT provides no mechanism for this.
	m_Buffer.Invalidate();

	m_MemoryRange0.Invalidate();
	m_MemoryRange1.Invalidate();
	m_MemoryRange2.Invalidate();

	// For each I/O port mapped region, release the underlying system resource.
	m_IoPortRange0.Invalidate();

	// For the interrupt, release the underlying system resource.
	m_Irq.Invalidate();
}

NTSTATUS PCI9054Device::OnStartDevice(KIrp I)
{
	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.

	CreateLink(L"PCI9054_DAQ");

	// 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

	// 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 = TRUE;
	dd.AutoInitialize = FALSE;
	dd.Dma32BitAddresses = TRUE;	//非32位DMA
	dd.IgnoreCount = FALSE;
	dd.DmaChannel = 0;
	dd.InterfaceType = PCIBus;
	dd.DmaWidth = Width16Bits;	// 16 bit PCI Bus
	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,65536);

	// Create an instance of KPciConfiguration so we can map Base Address
	// Register indicies to ordinals for memory or I/O port ranges.
	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;		
	}

	status = m_MemoryRange1.Initialize(
		pResListTranslated,
		pResListRaw,
		PciConfig.BaseAddressIndexToOrdinal(2)
		);

	if (!NT_SUCCESS(status))
	{
		Invalidate();
		return status;		
	}

	status = m_MemoryRange2.Initialize(
		pResListTranslated,
		pResListRaw,
		PciConfig.BaseAddressIndexToOrdinal(3)
		);

	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;		
	}


	// 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.
	m_IoPortRange0.outd(INTCSR,0x40100);

	return status;
}

NTSTATUS PCI9054Device::OnStopDevice(KIrp I)
{
	m_IoPortRange0.outd(INTCSR,0);
	m_Irq.Disconnect();	
	Invalidate();	

	DestroyLink(L"PCI9054_DAQ");

	return STATUS_SUCCESS;
}

NTSTATUS PCI9054Device::OnRemoveDevice(KIrp I)
{
	m_IoPortRange0.outd(INTCSR,0);
	m_Irq.Disconnect();
	Invalidate();

	return STATUS_SUCCESS;
}

VOID PCI9054Device::CancelQueuedIrp(KIrp I)
{
	KDeviceQueue dq(DeviceQueue());

	// Test if the IRP is the current 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);
	}
	else
	{
		CancelSpinLock::Release(I.CancelIrql());
	}
}

VOID PCI9054Device::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;
	}
}

NTSTATUS PCI9054Device::Create(KIrp I)
{
	NTSTATUS status;

	status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT);

	return status;
}

NTSTATUS PCI9054Device::Close(KIrp I)
{
	NTSTATUS status;

	status = I.PnpComplete(this, STATUS_SUCCESS, IO_NO_INCREMENT);

    return status;
}

NTSTATUS PCI9054Device::CleanUp(KIrp I)
{
    KDeviceQueue dq(DeviceQueue());
	dq.PnpCleanUp(this, I.FileObject());
	return I.PnpComplete(this, STATUS_SUCCESS);
}

void PCI9054Device::SerialRead(KIrp I)
{	
	NTSTATUS status		= STATUS_SUCCESS;

	t << "Entering SerialRead\n";

	m_CurrentTransfer = new(NonPagedPool) KDmaTransfer(this, &m_Dma);

	if ( m_CurrentTransfer == NULL )
	{
		status = STATUS_INSUFFICIENT_RESOURCES;
		DbgPrint("unable to allocate transfer object: %x\n", status);

		I.Information() = 0;
		I.Status() = status;
		PnpNextIrp(I);
	}

/*	status = m_CurrentTransfer->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) )
	{
		DbgPrint("unable to initiate transfer: %x\n", status);

		delete m_CurrentTransfer;
		m_CurrentTransfer = NULL;

		I.Information() = 0;
		I.Status() = status;
		PnpNextIrp(I);
	}
}

NTSTATUS PCI9054Device::Read(KIrp I) 
{
	if (I.ReadSize() == 0)
	{
		I.Information() = 0;
		return I.PnpComplete(this, STATUS_SUCCESS);
	}

	return QueueIrp(I, LinkTo(CancelQueuedIrp));
}

void PCI9054Device::SerialWrite(KIrp I)
{
	
	NTSTATUS status		= STATUS_SUCCESS;

	t << "Entering SerialWrite\n";

	m_CurrentTransfer = new(NonPagedPool) KDmaTransfer(this, &m_Dma);

	if ( m_CurrentTransfer == NULL )
	{
		status = STATUS_INSUFFICIENT_RESOURCES;
		DbgPrint("unable to allocate transfer object: %x\n", status);

		I.Information() = 0;
		I.Status() = status;
		PnpNextIrp(I);
	}

/*	
	status = m_CurrentTransfer->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) )
	{
		DbgPrint("unable to initiate transfer: %x\n", status);

		delete m_CurrentTransfer;
		m_CurrentTransfer = NULL;

		I.Information() = 0;
		I.Status() = status;
		PnpNextIrp(I);
	}
	
}

NTSTATUS PCI9054Device::Write(KIrp I) 
{
	if (I.WriteSize() == 0)
	{
		I.Information() = 0;
		return I.PnpComplete(this, STATUS_SUCCESS);
	}

	return QueueIrp(I, LinkTo(CancelQueuedIrp));
}

VOID PCI9054Device::DpcFor_Irq(PVOID Arg1, PVOID Arg2)
{
	m_CurrentTransfer->Continue(UseTransferSize);
	
}

BOOLEAN PCI9054Device::Isr_Irq(void)
{	
	ULONG status;

	status=	m_IoPortRange0.ind(INTCSR);

	if ((status & 0x200000)==0)
	{	
		return FALSE;	
	}


	m_IoPortRange0.outd(DMAMODE0,0x20800);	
	m_IoPortRange0.outb(DMACSR0,0x10);		

	// Request deferred procedure call
	// The arguments to Request may be any values that you choose
	if (!m_DpcFor_Irq.Request(NULL, NULL))
	{
// TODO:	Request is already in the queue
//			You may want to set flags or perform
//			other actions in this case
	}

	// Return TRUE to indicate that our device caused the interrupt
	return TRUE;
}

VOID PCI9054Device::StartDMARead(ULONG PAddress,ULONG NBytes)
{
	
	//Channel0 interrupt to the PCI Bus interrupt,Done Interrupt Enable,FIFO
	m_IoPortRange0.outd(DMAMODE0,0x20409);		//Local bus is 16 bits width
	//m_IoPortRange0.outd(DMAMODE0,0x205C3);
	//DMA Channel0 PCI Address
	m_IoPortRange0.outd(DMAPADR0,PAddress);
	//DMA Channel0 Local Address
	m_IoPortRange0.outd(DMALADR0,m_LocalBase);
//	m_LocalBase += NBytes;
	//DMA Channel0 Transfer Size(Bytes)
	m_IoPortRange0.outd(DMASIZ0,NBytes);
	//from the Local Bus to the PCI Bus
	m_IoPortRange0.outd(DMADPR0,0x8);
	//Channel0 Enable,Start
	m_IoPortRange0.outb(DMACSR0,0x3);
}
VOID PCI9054Device::StartDMAWrite(ULONG PAddress,ULONG NBytes)
{
	//Channel0 interrupt to the PCI Bus interrupt,Done Interrupt Enable,FIFO
	m_IoPortRange0.outd(DMAMODE0,0x20409);		//Local bus is 16 bits width
	//m_IoPortRange0.outd(DMAMODE0,0x205C3);
	//DMA Channel0 PCI Address
	m_IoPortRange0.outd(DMAPADR0,PAddress);
	//DMA Channel0 Local Address
	m_IoPortRange0.outd(DMALADR0,m_LocalBase);
//	m_LocalBase += NBytes;
	//DMA Channel0 Transfer Size(Bytes)
	m_IoPortRange0.outd(DMASIZ0,NBytes);
	//from the PCI Bus to the LOCAL Bus
	m_IoPortRange0.outd(DMADPR0,0x0);
	//Channel0 Enable,Start
	m_IoPortRange0.outb(DMACSR0,0x3);
}                             
VOID PCI9054Device::OnDmaReady(KDmaTransfer* pXfer, KIrp I)
{
	// All KDmaTransfer callbacks must first check to see if there are any bytes
	// left to transfer.
	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;
		delete pXfer;
		return;
	}

	// We must get the descriptor for the physical memory location for
	// the DMA transfer.

	PTRANSFER_DESCRIPTOR ptd;

	if(pXfer->SequenceTransferDescriptors(&ptd)) {
		// program the h/w using  ppTD
		t << " Physical address 0x" << ptd->td_PhysAddr.LowPart << ". Length is 0x"
			<< ptd->td_Length << "." << EOL;
		//m_LastLength = ptd->td_Length;

		if(I.MajorFunction() == IRP_MJ_READ)
		{
			StartDMARead(ptd->td_PhysAddr.LowPart,ptd->td_Length);
		}
		else
		{
			StartDMAWrite(ptd->td_PhysAddr.LowPart,ptd->td_Length);
		}
	}
	else
	{
		pXfer->Terminate();
	
		I.Information() = I.ReadSize(CURRENT);
		I.Status() = STATUS_SUCCESS;
		m_CurrentTransfer = NULL;
		PnpNextIrp(I);

		delete pXfer;
	}

}
////////////////////////////////////////////////////////////////////////
//  PCI9054Device::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 PCI9054Device::DeviceControl(KIrp I) 
{
	NTSTATUS status;
	status = STATUS_SUCCESS;
	PULONG	pBuffer;

	t << "Entering PCI9054Device::Device Control, " << I << EOL;
	switch (I.IoctlCode())
	{
	case PCI9054_IOCTL_SET_LOCALBASE:
		if(I.IoctlInputBufferSize(CURRENT)<4)
		{
			I.Information() = 0;
			I.Status() = STATUS_INVALID_PARAMETER;
			break;
		}
		
		pBuffer = (PULONG)I.IoctlBuffer();
		m_LocalBase = *pBuffer;
		I.Information() = 4;
		I.Status() = status;
		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);
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -