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