📄 atamx27.cpp
字号:
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 + -