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

📄 dmatrans.cpp

📁 我自己编译的armv4i wince60模拟器的bps源文件,已经验证可以使用,欢迎下载
💻 CPP
📖 第 1 页 / 共 3 页
字号:
{
    // Initialize critical sections
    InitializeCriticalSection( &readMutex );
    InitializeCriticalSection( &writeMutex );
    InitializeCriticalSection( &vchannelAccess );

    // No virtual channels have been allocated 
    virtChannels = NULL;

    // Set up physical buffer
    // Allocate 2 4KB buffers, 4 4-byte IOFlags, 2 12-byte IOParam
    vInputBuffer = (PUCHAR)VirtualAlloc( 0, 
                                        DMA_DEVICE_SIZE,
                                        MEM_RESERVE,
                                        PAGE_NOACCESS );
    
    // Check virtualalloc succeded
    if (!vInputBuffer)  
    {
        return FALSE;
    }
    
    // Map physical address to virtual address
    if (!VirtualCopy( (LPVOID) vInputBuffer,
                   (LPVOID)(BSP_BASE_REG_PA_DMA >> 8),
                   DMA_DEVICE_SIZE,
                   PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL))
    {
        return FALSE;
    }
    
    // Set up virtual addresses we've allocated
    vOutputBuffer		= vInputBuffer + DMA_PACKET_SIZE;
    
    channels[0].vPFlags	= (PULONG)(vOutputBuffer + DMA_PACKET_SIZE);
    channels[1].vPFlags	= (channels[0].vPFlags + 1);
    channels[2].vPFlags	= (channels[1].vPFlags + 1);
    channels[3].vPFlags	= (channels[2].vPFlags + 1);
    
    vInputPB			= (IOParamBlock*)(channels[3].vPFlags + 1);
    vOutputPB			= (IOParamBlock*)((PUCHAR)vInputPB + sizeof(IOParamBlock));
    
    // Set physical addresses we've allocated
    inputBuffer			= ( PUCHAR )( BSP_BASE_REG_PA_DMA );
    outputBuffer		= inputBuffer + DMA_PACKET_SIZE;
    
    channels[0].pFlags	= (PULONG)(outputBuffer + DMA_PACKET_SIZE);
    channels[1].pFlags	= (channels[0].pFlags + 1);
    channels[2].pFlags	= (channels[1].pFlags + 1);
    channels[3].pFlags	= (channels[2].pFlags + 1);
    
    inputPB				= (IOParamBlock*)(channels[3].pFlags + 1);
    outputPB			= (IOParamBlock*)((PUCHAR)inputPB + sizeof(IOParamBlock));

    // Create events
    dmaTransportInfo.fDMAInterruptEvent				= CreateEvent(0, FALSE, FALSE, NULL);
    dmaTransportInfo.fKillISTEvent			= CreateEvent(0, FALSE, FALSE, NULL);
    
    // Make sure events are valid
    if ( !dmaTransportInfo.fDMAInterruptEvent	|| 
         !dmaTransportInfo.fKillISTEvent	   )
    {
        return (FALSE);
    }
    
    // Request a SYSINTR corresponding to the IRQ
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &kDMATransport_IRQ, sizeof(DWORD), &dmaTransportInfo.fInterruptID, sizeof(DWORD), NULL))
    {
        RETAILMSG(1, (TEXT("DMATransport:InitializeGlobals Failed to obtain sysintr value for data interrupt.\r\n")));
        dmaTransportInfo.fInterruptID = SYSINTR_UNDEFINED;
        return (0);
    }       

    // Hook the interrupt and start the associated thread.
    if ( !StartIST() ) 
    {
        return FALSE;	
    }

    return TRUE;
}


/*------------------------------------------------------------------
    DMA_Init
    
    Called for each channel as device manager enumerates through
    registry entries.
------------------------------------------------------------------*/

DWORD
DMA_Init( DWORD registryPath )
{
    ULONG   index;

    // Figure out the DMA channel we're trying to Init by reading the registry
	HKEY	hRegKey	    = OpenDeviceKey( (LPCTSTR)registryPath );
    ULONG	dataSize	= sizeof(DWORD);
    ULONG	valueType	= 0;
    ULONG	channel		= 0;	// 4, 5, 6, 7 representing channel wanted
    ULONG	global		= 0; 
    
    ULONG   channelIRQ      = 0;
	
	// Index.
    if (ERROR_SUCCESS != RegQueryValueEx(hRegKey, 
                        L"Index", 
                        NULL, 
                        &valueType,
                        (LPBYTE)&channel, 
	                    &dataSize))
	{
		RETAILMSG(TRUE, (TEXT("DMATransport:DMA_Init() ERROR: failed to read INDEX value from the registry.\r\n")));
		return(0);
	}

	// Irq.
        if (ERROR_SUCCESS != RegQueryValueEx(hRegKey, 
						                 L"Irq", 
						                 NULL, 
						                 &valueType,
						                 (LPBYTE)&channelIRQ, 
						                 &dataSize))
	{
		RETAILMSG(TRUE, (TEXT("DMATransport:DMA_Init() ERROR: failed to read IRQ value from the registry.\r\n")));
		return(0);
	}

	RegCloseKey(hRegKey); 

	// Initialize global driver state.
	//
	if ( initialized == FALSE )
	{
	        kDMATransport_IRQ = channelIRQ;
		InitializeGlobals();
		for ( index = 0; index < NUM_DMA_CHANNELS; index++ )
		{
			WRITE_PORT_ULONG( DMA_GLOBAL_REG(index), kDMATrasportHandshake );
		}
		initialized = TRUE;
	}
	else if ( channelIRQ != kDMATransport_IRQ )
	{
		RETAILMSG(TRUE, (TEXT("DMATransport:DMA_Init() ERROR: mismatched IRQ values.\r\n")));
		return(0);         
	}
    
    // If we found a valid channel number, initialize the hardware.
    if ( channel >= NUM_DMA_FIRST_CHANNEL && channel <= NUM_DMA_LAST_CHANNEL )
    {
        // Channels go from 4-7, but access to channel array needs indecies 0-3
		index = channel - NUM_DMA_FIRST_CHANNEL;
        
        // Read the "global" port for this channel from the DMATransportDevice.
        global = READ_PORT_ULONG( DMA_GLOBAL_REG(index) );
        
        // If the handshake succeeded,
        if ( global & kDMATrasportHandshake )
        {
            // Set flags address.
            WRITE_PORT_ULONG( DMA_FLAGS_ADDRESS_REG(index), (ULONG)channels[index].pFlags );
            
            // Init interrupt request line.
			WRITE_PORT_ULONG( DMA_IRQ_REG(index), kDMATransport_IRQ );
            
            // Enable interrupts.
            global |= kDMATransportInterruptEnabled;
            WRITE_PORT_ULONG( DMA_GLOBAL_REG(index), global );
        }
        else
        {
            // Error initializing hardware. Tear down.
            DEBUGMSG( TRUE, (TEXT("DMA Transport:DMA_Init() failed!\n")) );
            DMA_Deinit( channel );
            return 0;
        }
    }

    return channel;
}


/*------------------------------------------------------------------
    DMA_Deinit
    
    Deinitializes indicated channel for DMA, called by device
    manager when
------------------------------------------------------------------*/

BOOL
DMA_Deinit( DWORD channel )
{   
    // Make sure channel is closed
    DMA_Close(channel);
    return TRUE;
}


/*------------------------------------------------------------------
    DMA_Open
    
    Opens the desired channel for an application, returns the
    channel opened, or zero for failure (if the channel is
    already open.)
------------------------------------------------------------------*/

extern "C" DWORD
DMA_Open( DWORD channelNumber,  // In: Channel number opening, 4 - 7
          DWORD access,			// In: Access, read, write, or read | write
          DWORD shareMode		// In: not used in this driver
                                )
{
    if ( channelNumber >= VIRT_CHANNEL_REQUEST )
    {
        DWORD index = channelNumber - NUM_DMA_FIRST_CHANNEL;	// Channels go from 4 - 7, but access to channel array needs indexes 0-3
        DMAChannel * channel = NULL;

        EnterCriticalSection( &vchannelAccess );
        // Check if we need to generate the channel number
        if ( channelNumber == VIRT_CHANNEL_REQUEST ||
             channelNumber == ADDR_CHANNEL_REQUEST)
        {
            // Notify the emulator that the channel has been opened on the device
            WRITE_PORT_ULONG(DMA_CURR_V_CHANNEL, 0);
            if ( channelNumber == VIRT_CHANNEL_REQUEST )
                WRITE_PORT_ULONG(DMA_CURR_V_OPERATION, kDMAVirtOperationNewVirtChannel);
            else
                WRITE_PORT_ULONG(DMA_CURR_V_OPERATION, kDMAVirtOperationNewAddrChannel);
            // Read the new channel number
            channelNumber = *DMA_CURR_V_STATUS;
        }
        // Select the right channel
        if ( index < NUM_DMA_CHANNELS )
            channel = &channels[index];
        else if ( channelNumber >= VIRTUAL_BASE )
        {
            channel = getVirtualChannel(channelNumber);
            if (!channel)
                channel = addVirtualChannel(channelNumber);
            if (!channel)
            {
                DEBUGMSG( TRUE, (TEXT("DMA Transport:Could not allocate new virt channel\n")) );
                goto Error;   // out of memory
            }
        }
        else
        {
            DEBUGMSG( TRUE, (TEXT("DMA Transport:Invalid channel passed in\n")) );
            goto Error;   // invalid channel number passed in
        }

        if ( channel->open )		// Channel already been opened
        {
            DEBUGMSG( TRUE, (TEXT("DMA Transport:Channel already open\n")) );
            goto Error; 
        }
        if ( index < NUM_DMA_CHANNELS )
            channel->dataReadyEvent = CreateEvent( NULL, FALSE, FALSE, channelEventName[index] );
        else
            channel->dataReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

        if ( !channel->dataReadyEvent ) // Create event failed
        {
            if ( channelNumber >= VIRTUAL_BASE )
                deleteVirtualChannel(channel);
            DEBUGMSG( TRUE, (TEXT("DMA Transport:Could not create event for channel %x\n"), channelNumber) );
            goto Error;
        }

        // Notify the emulator that the channel has been opened on the device
        WRITE_PORT_ULONG(DMA_CURR_V_CHANNEL, (channelNumber >= VIRTUAL_BASE ? channelNumber: index));
        WRITE_PORT_ULONG(DMA_CURR_V_OPERATION, kDMAVirtOperationAttach);

        // Check if the emulator was able to create an endpoint for this channel
        if (*DMA_CURR_V_STATUS)
        {
            DMA_Close(channelNumber);
            DEBUGMSG( TRUE, (TEXT("DMA Transport:Emulator returned failure\n")) );
            goto Error;
        }

        channel->open          = TRUE;
        channel->access        = access;
        LeaveCriticalSection( &vchannelAccess );

        // Return actual channel
        return channelNumber;
Error:
        DEBUGMSG( TRUE, (TEXT("DMA Transport:FAILED DMA_Open() for %x\n"), channelNumber) );
        LeaveCriticalSection( &vchannelAccess );
        return 0;
    }
    else 
    {
        DWORD index = channelNumber - NUM_DMA_FIRST_CHANNEL;	// Channels go from 4 - 7, but access to channel array needs indexes 0-3
        if ( channels[index].open )		// Channel already been opened
        {
            return 0; 
        }
        
        channels[index].dataReadyEvent	= CreateEvent( NULL, FALSE, FALSE, channelEventName[index] );
        if ( !channels[index].dataReadyEvent ) // Create event failed
        {
            return 0;
        }

        channels[index].open			= TRUE;
        channels[index].access			= access;

        // Return actual channel
        return channelNumber;
    }
}


/*------------------------------------------------------------------
    DMA_Close
    
    Closes indicated DMA channel.
------------------------------------------------------------------*/

BOOL
DMA_Close( DWORD channelNumber )
{
    if ( channelNumber >= VIRTUAL_BASE )
    {
        DWORD index = channelNumber - NUM_DMA_FIRST_CHANNEL;
        DMAChannel * channel = NULL;

        EnterCriticalSection( &vchannelAccess );
        // Select the right channel
        if ( index < NUM_DMA_CHANNELS )
            channel = &channels[index];
        else if ( channelNumber >= VIRTUAL_BASE )
        {
            channel = getVirtualChannel(channelNumber);
            if (!channel)
            {
                LeaveCriticalSection( &vchannelAccess );
                return FALSE;   // invalid channel number passed in
            }
        }
        else
        {
            LeaveCriticalSection( &vchannelAccess );
            return FALSE;   // invalid channel number passed in
        }

        // Make sure tha channel is open
        if ( channel->open )
        {
            channel->open = FALSE;
            if ( channel->dataReadyEvent != NULL )
                CloseHandle( channel->dataReadyEvent );
        }

        // Remove the node from the linked list for virtual channels
        if ( channelNumber >= VIRTUAL_BASE )
            deleteVirtualChannel(channel);

        // Notify the emulator that the channel has been opened on the device
        WRITE_PORT_ULONG(DMA_CURR_V_CHANNEL, (channelNumber >= VIRTUAL_BASE ? channelNumber: index));
        WRITE_PORT_ULONG(DMA_CURR_V_OPERATION, kDMAVirtOperationDetach);

        // Check if the emulator was able to create an endpoint for this channel
        if (*DMA_CURR_V_STATUS)
        {
            DEBUGMSG( TRUE, (TEXT("DMA Transport:Emulator returned failure closing channel %x\n"), channelNumber) );
        }

        LeaveCriticalSection( &vchannelAccess );

        return TRUE;
    }
    else 
    {
        DWORD index = channelNumber - NUM_DMA_FIRST_CHANNEL;
        
        // Make sure tha channel is open
        if ( channels[index].open )
        {
            channels[index].open = FALSE;
            CloseHandle( channels[index].dataReadyEvent );
        }

        return TRUE;
    }
}


/*------------------------------------------------------------------
    DMA_Write

⌨️ 快捷键说明

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