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

📄 dmatrans.cpp

📁 我自己编译的armv4i wince60模拟器的bps源文件,已经验证可以使用,欢迎下载
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*==================================================================
    File:		DMATrans.cpp
    
    Contains:	Stream-interface CE driver for the Emulator's
                DMATransportDevice. This driver provides a stream
                interface for applications running in the emulator
                to communicate with applications running on the
                host machine (outside the emulator).
                
                Communication on the other side of the device
                is done via the Emulator's IVirtualTransport COM
                interface.
                
    Written by:	Paul Pearcy
    
    Copyright:	2001 Connectix Corporation
==================================================================*/

//#include "stdafx.h"
#include <windows.h>        // For later builds of Talisker, remove the "stdafx.h" include and add this line
#include <bsp.h>
#include <devload.h> //for OpenDeviceKey
#include "dmatrans.h"
#include <ceddk.h> // for READ_PORT_XXXX, WRITE_PORT_XXXX

/*------------------------------------------------------------------
    Defines and const
------------------------------------------------------------------*/

// These two configuration options are quite important. The
// Emulator's DMATransportDevice is the device this driver
// communicates with. The device can use either IRQ 14 or 15.
// The Emulator KITL is normally configured to use IRQ 14, so
// this driver must use IRQ 15 to avoid a conflict with the KITL.
// The Base address is the physical memory address (in the
// emulated machine) that we'll use to DMA packets to and from.
// The address here must match the address in the platform's
// Config.bib file (which is where we reserve physical
// memory for the DMATransportDevice.)

// IRQ
ULONG   kDMATransport_IRQ;

// Global
const ULONG kDMATrasportHandshake           = 1 << 0;
const ULONG kDMATransportInterruptEnabled   = 1 << 8;

// flags
const ULONG kDMATransportDataReady          = 1 << 0;

// channel base address on the bus
#define kDMATransportBase               (vInputBuffer+0x2080)

// Channel size
const ULONG kDMATransportChannelSize        = 0x20;

// DMATransportDevice register offsets.
enum
{
    kDMATransportGlobalRegister         = 0x00,
    kDMATransportFlagsRegister          = 0x04,
    kDMATransportIOInputRegister        = 0x08,
    kDMATransportIOOutputRegister       = 0x0C,
    kDMATransportIRQRegister            = 0x10,
    kDMATransportIRQAcknowledgeRegister	= 0x14,
};

// Regisgter macros, given the channel returns specific register
#define DMA_GLOBAL_REG(a)               ((ULONG*)(kDMATransportBase+(a*kDMATransportChannelSize)+kDMATransportGlobalRegister))
#define DMA_FLAGS_ADDRESS_REG(a)        ((ULONG*)(kDMATransportBase+(a*kDMATransportChannelSize)+kDMATransportFlagsRegister))
#define DMA_IO_INPUT_REG(a)             ((ULONG*)(kDMATransportBase+(a*kDMATransportChannelSize)+kDMATransportIOInputRegister))
#define DMA_IO_OUTPUT_REG(a)            ((ULONG*)(kDMATransportBase+(a*kDMATransportChannelSize)+kDMATransportIOOutputRegister))
#define DMA_IRQ_REG(a)                  ((ULONG*)(kDMATransportBase+(a*kDMATransportChannelSize)+kDMATransportIRQRegister))
#define DMA_IRQ_ACK_REG(a)              ((ULONG*)(kDMATransportBase+(a*kDMATransportChannelSize)+kDMATransportIRQAcknowledgeRegister))

// Virtual channel operation register offsets.
enum
{
    kDMAVirtualChannel          = 0x00,
    kDMAVirtualOperation        = 0x04,
    kDMAVirtualStatus           = 0x08,
    kDMAFlagsChannel            = 0x0C,
    kDMAReadChannel             = 0x10,
    kDMAWriteChannel            = 0x14,
};

#define DMA_CURR_V_CHANNEL              ((ULONG*)(kDMATransportBase+(NUM_DMA_CHANNELS*kDMATransportChannelSize)+kDMAVirtualChannel))
#define DMA_CURR_V_OPERATION            ((ULONG*)(kDMATransportBase+(NUM_DMA_CHANNELS*kDMATransportChannelSize)+kDMAVirtualOperation))
#define DMA_CURR_V_STATUS               ((ULONG*)(kDMATransportBase+(NUM_DMA_CHANNELS*kDMATransportChannelSize)+kDMAVirtualStatus))
#define DMA_V_CHANNEL_FLAGS             ((ULONG*)(kDMATransportBase+(NUM_DMA_CHANNELS*kDMATransportChannelSize)+kDMAFlagsChannel))
#define DMA_V_CHANNEL_READ              ((ULONG*)(kDMATransportBase+(NUM_DMA_CHANNELS*kDMATransportChannelSize)+kDMAReadChannel))
#define DMA_V_CHANNEL_WRITE             ((ULONG*)(kDMATransportBase+(NUM_DMA_CHANNELS*kDMATransportChannelSize)+kDMAWriteChannel))

enum
{
    kDMAVirtOperationAttach         = 0x01,
    kDMAVirtOperationDetach         = 0x02,
    kDMAVirtOpetationIsInUse        = 0x04,
    kDMAVirtOperationNewVirtChannel = 0x08,
    kDMAVirtOperationNewAddrChannel = 0x10,
};

#define VIRTUAL_BASE    0x80000000
// Names of events which allow us to signal calling app that data is available
// These match up with the names in the header file included by applications using the transport
const LPTSTR    channelEventName[]  = { {L"channel4"}, 
                                        {L"channel5"},
                                        {L"channel6"}, 
                                        {L"channel7"} };

// Number of channels
#define NUM_DMA_CHANNELS                        4

#define NUM_DMA_FIRST_CHANNEL                   4
#define NUM_DMA_LAST_CHANNEL                    7

// Packet size: 4KB
#define DMA_PACKET_SIZE                         0x1000

// Virtual channels
#define VIRT_CHANNEL_REQUEST                    8
#define ADDR_CHANNEL_REQUEST                    9

// Size of the memory window for accessing the DMA Transport peripheral device.
// The x86 dmatrans.cpp uses "(DMA_PACKET_SIZE * 2) + (NUM_DMA_CHANNELS * sizeof(ULONG)) + (2 * sizeof(IOParamBlock)+0x20)"
// But that size is smaller than what is actually used.  The value, below, is based on examination of
// the dmatrans.cpp sources.
#define DMA_DEVICE_SIZE                         0x2120

/*------------------------------------------------------------------
    Types
------------------------------------------------------------------*/

// Parameter block structure used to communicate with Emulated hardware.
struct IOParamBlock
{
    volatile ULONG	ioDataLength; //NOTE: non-cached, not an issue on an emulated system.
    volatile ULONG	ioDataPtr;
    volatile ULONG	ioStatus;
};


// Holds data for the transport
struct DMATransportInfo
{
    DMATransportInfo()				// Constructor
    {
        fDMAInterruptEvent = 0;		// Event signaled when DMA interrupt occurs
        fInterruptID = 0;			// IRQ of the interrupt
        fIntrServiceThread = NULL;	// Handle to the interrupt servicing thread (IST)
        fKillISTEvent = NULL;		// Event signaled when IST should be ended.
        fKillIST = false;			// Set to true when we should signal the killISTEvent.
    }			
    
    HANDLE		fDMAInterruptEvent;	// fDMAInterruptEvent signaled when interrupt occurs

    HANDLE		fIntrServiceThread;	// Handle to InterruptServiceThread
    HANDLE		fKillISTEvent;		// Signalled when we want to kill the IST
    BOOL		fKillIST;			// Set to true when we want to stop the IST
    
    DWORD		fInterruptID;		// Logical interrupt ID
};


// Holds info for DMA channel, an instance per channel
struct DMAChannel
{
    DMAChannel()
    {
        open = FALSE;
        vPFlags = NULL;
        pFlags = NULL;
        access = 0;
        dataReadyEvent = NULL;
        next = NULL;
        channelNumber = 0;
    }
    
    BOOL				open;				// True if channel is open

    PULONG				vPFlags;			// Virtual pointer to flags
    PULONG				pFlags;				// Physical pointer to flags

    ULONG				access;				// Read/Write access
    
    HANDLE				dataReadyEvent;		// Event is created in calling application, app passes event name to DeviceIOControl, and driver gets a handle to it
                                            // Fired when data is ready to be read
    ULONG               channelNumber;
    DMAChannel *        next;
};


/*------------------------------------------------------------------
    Globals
------------------------------------------------------------------*/

// Critical sections
// Locks are required because different processes in CE can call read or write simultaneously
CRITICAL_SECTION writeMutex;
CRITICAL_SECTION readMutex;
CRITICAL_SECTION vchannelAccess;

// Global parameter block variables

// physical
IOParamBlock*       inputPB;
IOParamBlock*       outputPB;

// virtual
IOParamBlock*       vInputPB;
IOParamBlock*       vOutputPB;

// Global buffers
PUCHAR              vInputBuffer;
PUCHAR              vOutputBuffer;

PUCHAR              inputBuffer;
PUCHAR              outputBuffer;

// Global structure to access transport info
DMATransportInfo    dmaTransportInfo;
DMAChannel          channels[NUM_DMA_CHANNELS];
DMAChannel *        virtChannels;

BOOL                initialized = FALSE;

/*------------------------------------------------------------------
    Local Prototypes
------------------------------------------------------------------*/

static DWORD WINAPI DMAInterruptServiceThread( PVOID Empty );
static BOOL StartIST();
static BOOL InitializeGlobals();

DMAChannel * getVirtualChannel(DWORD channelNumber);
DMAChannel * addVirtualChannel(DWORD channelNumber);
void deleteVirtualChannel(DMAChannel * channel);

/*------------------------------------------------------------------
    DllMain
    
    Entry point called when a process hooks up to the DLL.
------------------------------------------------------------------*/

BOOL APIENTRY DllMain(HANDLE hinstDLL, DWORD fdwReason, LPVOID lpv)
{

    switch ( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
            break;
        case DLL_PROCESS_DETACH:
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
    }
    
    return TRUE;
}


/*------------------------------------------------------------------
    DMAInterruptServiceThread
    
    When interrupt occurs on IRQ 15, this thread is triggered and
    in turn sets the dataReadyEvent for the appropriate channels
------------------------------------------------------------------*/

static DWORD WINAPI
DMAInterruptServiceThread( PVOID /*ignore*/ )   // NULL pointer does nothing.
{
    while ( TRUE )		// loop forever
    {
        // Wait for DMA event that is triggered by a the host sending data to the guest, so the guest reads
        if ( WaitForSingleObject( dmaTransportInfo.fDMAInterruptEvent, INFINITE ) == WAIT_FAILED ) // Something bad happened
        {
            continue;
        }
        
        // Acknowledge the interrupt. Note we write to index 0, which is actually
        // Channel 4 in our case. We're sharing one interrupt for all four channels,
        // so we only need to ack on one of the channels to pull the IRQ line low.
        // It doesn't matter what we write, the data is ignored.
        WRITE_PORT_ULONG( DMA_IRQ_ACK_REG(0), 0 );
        
        if ( dmaTransportInfo.fKillIST )		// Event was fired from stopIST()
        {
            SetEvent( dmaTransportInfo.fKillISTEvent );
            ExitThread(0);
        }
        
        // Loop through channels
        for ( USHORT channelIndex = 0;  channelIndex < NUM_DMA_CHANNELS; ++channelIndex )
        {
            if ( channels[channelIndex].open )	// Channel is open
            {                
                if ( *(channels[channelIndex].vPFlags) & kDMATransportDataReady )	// Channel has data to read
                {
                    SetEvent( channels[channelIndex].dataReadyEvent );
                }
            }
        }
        
        // Loop through virtual channels
        EnterCriticalSection( &vchannelAccess );

        DMAChannel * currChannel = virtChannels;
        while (currChannel != NULL )
        {
            if ( currChannel->open)
            {
                WRITE_PORT_ULONG( DMA_V_CHANNEL_FLAGS, currChannel->channelNumber );
                // We can read any of the four flags registers - pick base one
                if ( *(DMA_V_CHANNEL_FLAGS) & kDMATransportDataReady )	// Channel has data to read
                {
                    SetEvent( currChannel->dataReadyEvent );
                }
            }
            currChannel = currChannel->next;
        }

        LeaveCriticalSection( &vchannelAccess );

        // Tell kernel we're done processing the interrupt
        InterruptDone( dmaTransportInfo.fInterruptID );
    }
    
    return(0);
}


/*------------------------------------------------------------------
    StartIST
    
    Starts the interrupt service thread
    Returns: Success(true) or failure(false)
------------------------------------------------------------------*/

BOOL
StartIST()
{
    dmaTransportInfo.fKillIST = FALSE;
    
    // Initialize the interrupt to be associated with the fDMAInterruptEvent event
    if ( !InterruptInitialize(dmaTransportInfo.fInterruptID, dmaTransportInfo.fDMAInterruptEvent, NULL, 0) ) 
    {
        DEBUGMSG( TRUE, (TEXT("DMATransport:StartIST() failed on InterruptInitialize.\n")) );
        return FALSE;
    }
    
    // Create the thread
    dmaTransportInfo.fIntrServiceThread = CreateThread(NULL, 0, DMAInterruptServiceThread, NULL, 0, NULL);
    
    if ( dmaTransportInfo.fIntrServiceThread == NULL ) // Failure
    {
        DEBUGMSG( TRUE, (TEXT("DMATransport:StartIST() failed to create interrupt service thread.\n")) );
        return FALSE;
    }
    
    // Set thread priority above normal
    //CeSetThreadPriority( dmaTransportInfo.fIntrServiceThread, THREAD_PRIORITY_ABOVE_NORMAL );
    SetThreadPriority(dmaTransportInfo.fIntrServiceThread, THREAD_PRIORITY_HIGHEST);
    
    // Clear any interrupts lingering
    InterruptDone( dmaTransportInfo.fInterruptID );
    
    return TRUE;
}



/*------------------------------------------------------------------
    InitializeGlobals
    
    Initializations that should only occur once for the
    entire life of the driver
------------------------------------------------------------------*/

BOOL InitializeGlobals()

⌨️ 快捷键说明

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