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

📄 dmatrans.cpp

📁 windows mobile 5 下的底层驱动包
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        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;	
    }

    DEBUGMSG( TRUE, (TEXT("DMA Transport:Leaving InitializeGlobals\n")) );
    return TRUE;
}


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

DWORD
DMA_Init( DWORD registryPath )
{
    DEBUGMSG( TRUE, (TEXT("DMA Transport:Enter DMA_Init\n")) );

    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);         
	}
    
    DEBUGMSG( TRUE, (TEXT("DMATransport:DMA_Init() initializing channel %d.\n"), channel) );
    
    // 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;
        }
    }

    DEBUGMSG( TRUE, (TEXT("DMA Transport:Leaving DMA_Init\n")) );
    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 )
        goto NewOpenCode;
    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;
    }

NewOpenCode:
    DEBUGMSG( TRUE, (TEXT("DMA Transport:Enter DMA_Open() for %x\n"), channelNumber) );
    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)
    {
        DEBUGMSG( TRUE, (TEXT("DMA Transport:Generating channel number\n")) );
        // 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;
        DEBUGMSG( TRUE, (TEXT("DMA Transport:Selected channel %x\n"), channelNumber) );
    }
    // 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
    DEBUGMSG( TRUE, (TEXT("DMA Transport:SUCCESS DMA_Open() for %x\n"), channelNumber) );
    return channelNumber;
Error:
    DEBUGMSG( TRUE, (TEXT("DMA Transport:FAILED DMA_Open() for %x\n"), channelNumber) );
    LeaveCriticalSection( &vchannelAccess );
    return 0;
}


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

BOOL
DMA_Close( DWORD channelNumber )
{
    if ( channelNumber >= VIRTUAL_BASE )
        goto NewCloseCode;
    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;
    }

NewCloseCode:
    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) );
    }

    DEBUGMSG( TRUE, (TEXT("DMA Transport:SUCCESS DMA_Close() for %x\n"), channelNumber) );
    LeaveCriticalSection( &vchannelAccess );

    return TRUE;
}


/*------------------------------------------------------------------
    DMA_Write
    
    Writes indicated number of bytes to DMA device, up to a
    maximum of 4K. (The DMATransport device transmits data in 4K
    chunks. We leave it up to the client of this driver to handle
    breaking up packets.)
    
    Returns failure, or the number of bytes actually written.
------------------------------------------------------------------*/

DWORD
DMA_Write( DWORD    channel,    // In: channel number: 4-7
           LPCVOID	writeBytes,	// In: Data to write
           DWORD	numBytes	// In: number of bytes to write
                                )
{   
    if ( channel >= VIRTUAL_BASE )
        goto NewWriteCode;
    else 
    {
    // Enter critical section so no other write call can interfere
    EnterCriticalSection( &writeMutex );
    
    vOutputPB->ioStatus		= 0;
    vOutputPB->ioDataPtr	= (ULONG)outputBuffer; // specify physical address
    
    if ( numBytes > DMA_PACKET_SIZE )	// Trying to write too many bytes, can only write at the max DMA_PACKET_SIZE
    {
        vOutputPB->ioDataLength = DMA_PACKET_SIZE;
    }
    else	// Writing numBytes
    {
        vOutputPB->ioDataLength = numBytes;
    }

⌨️ 快捷键说明

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