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

📄 atamx27.cpp

📁 Microsoft WinCE 6.0 BSP FINAL release source code for use with the i.MX27ADS TO2 WCE600_FINAL_MX27_S
💻 CPP
📖 第 1 页 / 共 3 页
字号:

BOOL
CMX27Disk::ConfigPort(
    )
{
    DWORD dwIRQ_DMACHRX = IRQ_DMACH6;
    DWORD dwIRQ_DMACHTX = IRQ_DMACH7;

    DEBUGMSG(ZONE_FUNC, (_T("CMX27Disk: ConfigPort+")));

    m_pATAReg = (PBYTE)m_pPort->m_dwRegBase;
    m_pATARegAlt = (PBYTE)m_pPort->m_dwRegAlt;

    if(!InitializePort()) 
    {
        return FALSE;
    }

    // this function is called for the master and slave on this channel; if
    // this has already been called, then exit
    if (m_pPort->m_hIRQEvent) {
        m_dwDeviceFlags |= DFLAGS_DEVICE_INITIALIZED;
        return TRUE;
    }

    // create interrupt event
    if (NULL == (m_pPort->m_hIRQEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) {
        DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T(
            "Ata!CMX27Disk::ConfigPort> Failed to create interrupt event for device(%d)\r\n"
            ), m_dwDeviceId));
        return FALSE;
    }

    // Translate IRQ to SYSINTR
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &(m_pPort->m_dwIrq), 
            sizeof(m_pPort->m_dwIrq), &m_pPort->m_dwSysIntr, 
            sizeof(m_pPort->m_dwSysIntr), NULL))
    {
        ERRORMSG(1,(TEXT("%s: Request SYSINTR failed\r\n"), __WFUNCTION__));
        return FALSE;
    }


    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &(dwIRQ_DMACHRX), 
            sizeof(dwIRQ_DMACHRX), &m_pPort->m_dwSysIntrRX, 
            sizeof(m_pPort->m_dwSysIntrRX), NULL))
    {
        ERRORMSG(1,(TEXT("%s: Request SYSINTR failed\r\n"), __WFUNCTION__));
        return FALSE;
    }

    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &(dwIRQ_DMACHTX), 
            sizeof(dwIRQ_DMACHTX), &m_pPort->m_dwSysIntrTX, 
            sizeof(m_pPort->m_dwSysIntrTX), NULL))
    {
        ERRORMSG(1,(TEXT("%s: Request SYSINTR failed\r\n"), __WFUNCTION__));
        return FALSE;
    }
    // associate interrupt event with IRQ
    if (!InterruptInitialize(
        m_pPort->m_dwSysIntr,
        m_pPort->m_hIRQEvent,
        NULL,
        0)
    ) {
        DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T(
            "Ata!CMX27Disk::ConfigPort> Failed to initialize interrupt(SysIntr(%d)) for device(%d)\r\n"
            ), m_pPort->m_dwSysIntr, m_dwDeviceId));
        return FALSE;
    }

    if (!InterruptInitialize(
        m_pPort->m_dwSysIntrRX,
        m_pPort->m_hIRQEvent,
        NULL,
        0)
    ) {
        DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T(
            "Ata!CMX27Disk::ConfigPort> Failed to initialize interrupt(SysIntr(%d)) for device(%d)\r\n"
            ), m_pPort->m_dwSysIntrRX, m_dwDeviceId));
        return FALSE;
    }
    if (!InterruptInitialize(
        m_pPort->m_dwSysIntrTX,
        m_pPort->m_hIRQEvent,
        NULL,
        0)
    ) {
        DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T(
            "Ata!CMX27Disk::ConfigPort> Failed to initialize interrupt(SysIntr(%d)) for device(%d)\r\n"
            ), m_pPort->m_dwSysIntrTX, m_dwDeviceId));
        return FALSE;
    }


    // c=Create interrupt wait event
    if (NULL == (m_pPort->m_hWaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) {
        DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T(
            "Ata!CMX27Disk::ConfigPort> Failed to create interrupt wait event for device(%d)\r\n"
            ), m_dwDeviceId));
        return FALSE;
    }

    // Create IST for ATA interrupts
    m_pPort->m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) IntrServThread, m_pPort, 0, NULL);      
    if (!m_pPort->m_hThread) 
    {
        DEBUGMSG(ZONE_INIT|ZONE_ERROR, (_T(
            "Ata!CMX27Disk::ConfigPort> Failed to create IST for device(%d)\r\n"
            ), m_dwDeviceId));
        return FALSE;
    }

    DEBUGMSG(ZONE_FUNC, (_T("CMX27Disk: ConfigPort-")));
    return TRUE;
}

// SetTimingRegisters() programs host timing. "speed" is the ATA mode programmed,
// mode can be PIO_MODE, UDMA_MODE or MDMA_MODE, ClkSpd is the clock period in
// ns 
void CMX27Disk::SetTimingRegisters(int speed, int mode, int ClkSpd)
{
    DEBUGMSG(ZONE_FUNC, (_T("CMX27Disk: SetTimingRegisters+(%d,%d,%d)+"), speed,mode,ClkSpd));
    INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG0, 0x0000ffff, 0x00000202);
    switch(mode)
    {
        case PIO_MODE:
            INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG0, 0xffff0000,
                    ((pio_timing_1[speed] << 16) | 
                    (pio_timing_2[speed] << 24))) ;
            INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG1, 0xffffffff,
                    ((pio_timing_2[speed]) | 
                    (pio_timing_3[speed] << 8) |
                    (1 << 16) | 
                    (pio_timing_4[speed] << 24))) ;
            INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG2, 0xff, (pio_timing_5[speed]));
            break ;
        case MDMA_MODE :
            INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG2, 0xffffff00,
                    ((mdma_timing_1[speed] << 8) | 
                    (mdma_timing_2[speed] << 16) |
                    (mdma_timing_3[speed] << 24))) ;
            INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG3, 0xff, mdma_timing_4[speed]) ;
            break ;
        case UDMA_MODE :
            INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG3, 0xffffff00,
                    ((udma_timing_1[speed] << 8) |
                    (udma_timing_2[speed] << 16) |
                    ((udma_timing_3[speed] + 2) << 24))) ;
            INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG4, 0xffffffff,
                    (udma_timing_4[speed] |
                    (udma_timing_5[speed] << 8) |
                    (udma_timing_6[speed] << 16) |
                    (udma_timing_7[speed] << 24))) ;
            INSREG32(&g_pVAtaReg->ATA_TIME_CONFIG5, 0xffffffff,
                    ((udma_timing_8[speed] << 24) |
                    (udma_timing_11[speed] << 16) |
                    (udma_timing_10[speed] << 8) |
                    udma_timing_9[speed] )) ;
            break ;
        default :
            break;
    }
    DEBUGMSG(ZONE_FUNC, (_T("CMX27Disk: SetTimingRegisters-")));
}

// ----------------------------------------------------------------------------
// Function: InitializePort
//     Initialize ATA Port
//
// Parameters:
//     None
// Returns:
//      Returns TRUE if successful, otherwise returns FALSE.
// ----------------------------------------------------------------------------
BOOL CMX27Disk::InitializePort(void)
{
    PHYSICAL_ADDRESS phyAddr;
    BOOL bRet = FALSE;

    DEBUGMSG(ZONE_FUNC, (_T("CMX27Disk: InitializePort+")));
    if(g_pVAtaReg == NULL)
    {
        phyAddr.QuadPart = CSP_BASE_REG_PA_ATA;
        g_pVAtaReg = (PCSP_ATA_REG) MmMapIoSpace(phyAddr, sizeof(CSP_ATA_REG), FALSE);

        // Check if virtual mapping failed
        if (g_pVAtaReg == NULL)
        {
            DEBUGMSG(ZONE_ERROR, (TEXT("CMX27Disk: MmMapIoSpace failed!\r\n")));
            goto exit;
        }

        m_pATAReg = (PBYTE) (g_pVAtaReg);
        m_pATARegAlt = (PBYTE) (g_pVAtaReg);

        ConfigureRegisterBlock(4);
        
        // Enabling ATA Clock
        if (!BSPATAEnableClock(TRUE))
        {
            DEBUGMSG(ZONE_FUNC, (TEXT("BSPATAEnableClock(): ATA Clock cannot be enabled! \r\n")));
            return FALSE;
        }
        
        // BSPATAIOMUXConfig configure the available IOMUX settings 
        BSPATAIOMUXConfig();
        
        SetTimingRegisters(0, PIO_MODE, CLOCK_PERIOD);
        SetTimingRegisters(0, MDMA_MODE, CLOCK_PERIOD);
        SetTimingRegisters(0, UDMA_MODE, CLOCK_PERIOD);

        OUTREG32(&g_pVAtaReg->ATAControl, 0x00); // set reset (clear to set ata_reset_b 0, low active)
        Sleep(20);
        OUTREG32(&g_pVAtaReg->ATAControl, 0x40); // release reset (normal work)
        Sleep(20);
    }
    bRet = TRUE;

exit:;
    DEBUGMSG(ZONE_FUNC, (_T("CMX27Disk: InitializePort-")));
    return bRet;
}

// ----------------------------------------------------------------------------
// Function: ShowRegisters
//     Print current ATA registers
//
// Parameters:
//     None
// Returns:
//     None
// ----------------------------------------------------------------------------
void CMX27Disk::ShowRegisters(UCHAR usel)
{
    if(usel & 0x01)
    {
        DEBUGMSG(ZONE_INIT, (_T("ATAReg: ATA_TIME_CONFIG0 %p,0x%08x\n"), &g_pVAtaReg->ATA_TIME_CONFIG0, INREG32(&g_pVAtaReg->ATA_TIME_CONFIG0)));
        DEBUGMSG(ZONE_INIT, (_T("ATAReg: ATA_TIME_CONFIG1 %p,0x%08x\n"), &g_pVAtaReg->ATA_TIME_CONFIG1, INREG32(&g_pVAtaReg->ATA_TIME_CONFIG1)));
        DEBUGMSG(ZONE_INIT, (_T("ATAReg: ATA_TIME_CONFIG2 %p,0x%08x\n"), &g_pVAtaReg->ATA_TIME_CONFIG2, INREG32(&g_pVAtaReg->ATA_TIME_CONFIG2)));
        DEBUGMSG(ZONE_INIT, (_T("ATAReg: ATA_TIME_CONFIG3 %p,0x%08x\n"), &g_pVAtaReg->ATA_TIME_CONFIG3, INREG32(&g_pVAtaReg->ATA_TIME_CONFIG3)));
        DEBUGMSG(ZONE_INIT, (_T("ATAReg: ATA_TIME_CONFIG4 %p,0x%08x\n"), &g_pVAtaReg->ATA_TIME_CONFIG4, INREG32(&g_pVAtaReg->ATA_TIME_CONFIG4)));
        DEBUGMSG(ZONE_INIT, (_T("ATAReg: ATA_TIME_CONFIG5 %p,0x%08x\n"), &g_pVAtaReg->ATA_TIME_CONFIG5, INREG32(&g_pVAtaReg->ATA_TIME_CONFIG5)));

        DEBUGMSG(ZONE_INIT, (_T("ATAReg: ATAControl %p,0x%02x\n"), &g_pVAtaReg->ATAControl, INREG32(&g_pVAtaReg->ATAControl)));
        DEBUGMSG(ZONE_INIT, (_T("ATAReg: InterruptPending %p,0x%02x\n"), &g_pVAtaReg->InterruptPending, INREG32(&g_pVAtaReg->InterruptPending)));
    } 

    if(usel & 0x02)
    {
    }
}

// ----------------------------------------------------------------------------
// Function: SetupDMA
//     Setup DMA transfer
//
// Parameters:
//     pSgBuf -
//     dwSgCount -
//     fRead -
// ----------------------------------------------------------------------------
BOOL CMX27Disk::SetupDMA(PSG_BUF pSgBuf, DWORD dwSgCount, BOOL fRead)
{
    UINT8 chan = fRead ? DmaChanATARx : DmaChanATATx;
    BOOL rc = TRUE;
#ifdef USE_DMA_SG_LIST
    BOOL fAlign = TRUE;
#else
    BOOL fAlign = FALSE;
#endif
    DWORD dwLockedPages = 0;
    DWORD dwSize;
    DWORD dwBytesRemain = dwSectorsToTransfer * BYTES_PER_SECTOR; 

    DEBUGMSG(ZONE_FUNC, (_T("CMX27Disk::SetupDMA(%d, %d)+\n"), fRead, dwSectorsToTransfer * BYTES_PER_SECTOR));
     
    m_pDMASgBuf = pSgBuf;
    m_dwAlignedSgCount = 0;
    m_dwAlignedDescCount = 0;
    m_dwAlignedSgBytes = 0;
    m_DMAChan = chan;
    
    OUTREG32(&g_pVAtaReg->ATAControl, 0x40);  
     
    DWORD currentSg = 0;
    DWORD currentDesc = 0;
    DWORD pdwPages[ATA_MAX_DESC_COUNT];

    // For each ATA watermark aligned scatter/gather buffer 
    while((currentSg < dwSgCount) && fAlign)
    {    
        // Map address and check for security violation
        LPBYTE pBuffer = (LPBYTE)pSgBuf[currentSg].sb_buf;
        if (pSgBuf[currentSg].sb_buf != NULL && pBuffer == NULL) 
        {
            // security violation
            ERRORMSG(ZONE_ERROR, (TEXT(
                "CMX27Disk::SetupDMA> Failed to map pointer to caller\r\n"
                )));
            rc = FALSE;
            goto cleanUp;
        }

        if (!LockPages(pBuffer,pSgBuf[currentSg].sb_len,pdwPages, fRead ? LOCKFLAG_WRITE : LOCKFLAG_READ))
        {
            DEBUGMSG(ZONE_ERROR, (TEXT(
                "CMX27Disk::SetupDMA> LockPages failed\r\n"
                )));
            // Try to fall back to copy using aligned buffer
            fAlign = FALSE;
            break;
        }
        else
        {
            // Keep track of how many pages we have locked so we can
            // unlock them if we encounter a failure
            dwLockedPages++;
        }
            
        DWORD dwMaxPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(pSgBuf[currentSg].sb_buf,pSgBuf[currentSg].sb_len);
        DWORD dwTempLen = pSgBuf[currentSg].sb_len;
        DWORD dwTempPtr = (DWORD)pBuffer;

        for(DWORD i = 0; (i < dwMaxPages) && (dwTempLen > 0) && fAlign; i++)
        {                                   
            // try and rule out broken values
            DEBUGCHK(pdwPages[i] != 0);

            DWORD dwPhys = pdwPages[i] << UserKInfo[KINX_PFN_SHIFT]; // get the start address of pages        
            DWORD dwOffset = dwTempPtr & (UserKInfo[KINX_PAGESIZE] - 1); // offset into page, if any                       
            dwSize = UserKInfo[KINX_PAGESIZE] - dwOffset;
            
            if(dwSize > dwTempLen)
                dwSize = dwTempLen;
            
            dwPhys += dwOffset;                
            
            dwTempLen -= dwSize;
            dwTempPtr += dwSize;

            // If we have any unaligned SG pages, perform remainder of transfer
            // using a copy into an aligned buffer
            if (dwSize & (0x3))
            {
                //DEBUGMSG(ZONE_FUNC, (_T("CMX27Disk::SetupDMA unaligned page (sg = %d, page = %d, size = %d\r\n"), currentSg, i, dwSize));
                
                UnlockPages(pBuffer,pSgBuf[currentSg].sb_len);
                --dwLockedPages;

                fAlign = FALSE;
            }
            else
            {
                // if we're at the end to enable the intr flag
                // to do: DMA chaining
                ++currentDesc;                                                                
            }                                
        }

        if (fAlign)
        {
            // Keep track of the aligned SG buffers.  If we encounter a
            // a misaligned length while walking through the current 
            // SG buffer pages, we will punt the remainder of the list back to
            // MapDMABuffers implementation
            m_dwAlignedSgBytes += pSgBuf[currentSg].sb_len;
            m_dwAlignedDescCount = currentDesc;
            m_dwAlignedSgCount = ++currentSg;
        }        
                                        
    }

    if (!fAlign)
    {
        if (fRead)
        {
            dwSize = dwSectorsToTransfer * BYTES_PER_SECTOR - m_dwAlignedSgBytes;
        }
        else
        {
            dwSize = MoveDMABuffer(pSgBuf, m_dwAlignedSgCount, dwSgCount, fRead);
            DEBUGCHK(dwSize == (dwSectorsToTransfer * BYTES_PER_SECTOR - m_dwAlignedSgBytes));
        }
            
        DEBUGCHK(!(dwSize & (ATA_DMA_WATERMARK - 1)));

        // Set number of bytes to transfer
        DDKDmacSetTransCount(chan, dwSize);
        // Clear DMAC status regs in order to restart channel.
        DDKDmacClearChannelIntr(chan);
    }

    DDKDmacEnableChannelIntr(chan);
    DDKDmacStartChan(chan);
    
    // set fifo alarm to 16 halfwords, midway
    OUTREG32(&g_pVAtaReg->FIFOAlarm, ATA_DMA_WATERMARK/2);
    OUTREG32(&g_pVAtaReg->InterruptClear, 0xff);
    OUTREG32(&g_pVAtaReg->InterruptEnable, 0x80);

cleanUp:
    if(!rc)
    {
        // Unlock any previous locked page ranges
        for(DWORD i = 0; i < dwLockedPages; i++)
        {
            LPBYTE pUnlockBuffer = (LPBYTE)pSgBuf[i].sb_buf; 
            UnlockPages(pUnlockBuffer,pSgBuf[i].sb_len);
        }
        
    }

    return rc;
}


// ----------------------------------------------------------------------------
// Function: BeginDMA
//     Begin DMA transfer

⌨️ 快捷键说明

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