Port-ofppc archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[no subject]
Hi, i want to ask you a question. How about the continue() of the driverstudio?
When i make a dma, and the dma cannot be processed once, what should i do?
thank you
// 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
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();
// 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();
}
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.
// 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;
dd.IgnoreCount = FALSE;
dd.DmaChannel = 0;
dd.InterfaceType = PCIBus;
dd.DmaWidth = Width32Bits; // PCI default width
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,2048);
// 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;
}
// 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,
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);//ÔÊÐíPCIÖжϺÍDMAͨµÀ0ÖжÏ
return status;
}
NTSTATUS PCI9054Device::OnStopDevice(KIrp I)
{
m_IoPortRange0.outd(INTCSR,0);//½ûÖ¹PCIÖжϺÍDMAͨµÀ0ÖжÏ
m_Irq.Disconnect();
Invalidate();
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";
// Create a new DMA transfer object for this IRP
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);
}
//ÏÂÃæ²ÉÓÃÓ¦ÓóÌÐòµÄÊý¾Ý»º³åÇø×÷ΪDMAÊý¾ÝÇø
status = m_CurrentTransfer->Initiate(
I.Mdl(),
(I.MajorFunction() == IRP_MJ_READ) ? FromDeviceToMemory :
FromMemoryToDevice,
LinkTo(OnDmaReady)
);
/* ÏÂÃæ²ÉÓù«Óûº³åÇø×÷ΪDMAÊý¾ÝÇø
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;
ULONG i;
// 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;
//Çå¿ÕFIFO
m_IoPortRange1.outb(0,0);
//ÓÃI/OÊä³öÃüÁîÍùFIFOдÊý¾Ý
for (i=0;i<dwTotalSize;i++) m_IoPortRange1.outb(0x4,*pBuffer++);
I.Information() = dwBytesSent;
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 to indicate that this device did not cause the
interrupt.
return FALSE;
}
m_IoPortRange0.outd(DMAMODE0,0x20800);
m_IoPortRange0.outb(DMACSR0,0x10);//Clear Interrupt
// 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::StartDMA(ULONG PAddress,ULONG NBytes)
{
//ÏÂÃ漸ÌõÓï¾äÉèÖÃDMAͨµÀ0¼Ä´æÆ÷£¬Æô¶¯¿é´«Ê䷽ʽ£¬´ÓFIFO¶ÁÊý¾Ý
//Channel0 interrupt to the PCI Bus interrupt,Done Interrupt Enable,FIFO
m_IoPortRange0.outd(DMAMODE0,0x20C00);
//DMA Channel0 PCI Address
m_IoPortRange0.outd(DMAPADR0,PAddress);
//DMA Channel0 Local Address£¬×Ô¼ºÉè¼ÆµÄFIFOµØÖ·
m_IoPortRange0.outd(DMALADR0,0x8);
//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::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;
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.
if ((ULONG) pXfer->BytesRemaining() == I.ReadSize())
StartDMA(ptd->td_PhysAddr.LowPart,ptd->td_Length);
}
Home |
Main Index |
Thread Index |
Old Index