📄 ep931xide.cpp
字号:
//**********************************************************************
//
// Filename: EP931xide.cpp
//
// Description: IDE driver for the internal EP931x port.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Use of this source code is subject to the terms of the Cirrus end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to
// use this source code. For a copy of the EULA, please see the
// EULA.RTF on your install media.
//
// Copyright(c) Cirrus Logic Corporation 2003, All Rights Reserved
//
//**********************************************************************
#include "atamain.h"
#include <oalintr.h>
#include "ep931xide.h"
#include <hwdefs.h>
#include <dbgapi.h>
#define DELAY_5NS __emit(0xe1a00000);
#define DELAY_10NS __emit(0xe1a00000); \
__emit(0xe1a00000);
#define DELAY_50NS __emit(0xe1a00000); \
__emit(0xe1a00000); \
__emit(0xe1a00000); \
__emit(0xe1a00000); \
__emit(0xe1a00000); \
__emit(0xe1a00000); \
__emit(0xe1a00000); \
__emit(0xe1a00000); \
__emit(0xe1a00000);
#define DELAY_100NS DELAY_50NS \
DELAY_50NS
//#define DATA_REGISTER 0x00
//#define ERRORREGISTER 0x01
//#define FEATURESREGISTER 0x01
//#define SECTORCOUNTREGISTER 0x02
//#define SECTORNUMBERREGISTER 0x03
//#define CYLINDERLOWREGISTER 0x04
//#define CYLINDERHIGHREGISTER 0x05
//#define DEVICEHEADREGISTER 0x06
//#define COMMANDREGISTER 0x07
//#define STATUSREGISTER 0x07
// ATA Control Registers
//#define DEVICECONTROLREGISTER 0x06
//#define ALTERNATESTATUSREGISTER 0x06
//****************************************************************************
// ATAReadRegister
//****************************************************************************
//
//
__inline ULONG ATAReadRegister(ULONG ulRegister)
{
ULONG uiValue;
register ULONG ulControl;
//
// Setup the control register for a read.
//
*IDE_CTRL = ulControl = IDE_CTRL_DIOR | IDE_CTRL_DIOW | ulRegister;
//
// See Section 10.2.2 of the ATA/ATAPI Specification Version 5 for Delay
// Information.
//
// PIO Mode 0 - Delay for 70ns.
// PIO Mode 1 - Delay for 50ns.
// PIO Mode 2 - Delay for 30ns.
// PIO Mode 3 - Delay for 30ns.
// PIO Mode 4 - Delay for 25ns.
//
// For a write to a APB register with HCLK at 100Mhz is 130ns.
// No extra delay is needed.
//
*IDE_CTRL = ulControl &= ~IDE_CTRL_DIOR;
//
// See Section 10.2.2 of the ATA/ATAPI Specification Version 5 for Delay
// Information.
//
// PIO Mode 0 - Delay for 290ns.
// PIO Mode 1 - Delay for 290s.
// PIO Mode 2 - Delay for 290s.
// PIO Mode 3 - Delay for 80ns.
// PIO Mode 4 - Delay for 70ns.
//
// For a write to a APB register with HCLK at 100Mhz is 130ns.
// No extra delay is needed.
//
*IDE_CTRL = ulControl |= IDE_CTRL_DIOR;
uiValue = *IDE_DATAIN;
if(ulRegister == CSDA_DATA_REG)
{
return(uiValue & 0xFFFF);
}
else
{
return(uiValue & 0xFF);
}
}
//-----------------------------------------------------------------------------
//
// Function Name: ATAWriteCommandRegister
//
// Function Description: Writes an 8-bit value to an ATA command register.
//
//-----------------------------------------------------------------------------
__inline void ATAWriteRegister(ULONG ulRegister, UINT uiData)
{
register ULONG ulControl;
//
// Setup the control register for a write.
//
*IDE_CTRL = ulControl = IDE_CTRL_DIOR | IDE_CTRL_DIOW | ulRegister;
*IDE_DATAOUT = uiData;
//
// See Section 10.2.2 of the ATA/ATAPI Specification Version 5 for Delay
// Information.
//
// PIO Mode 0 - Delay for 70ns.
// PIO Mode 1 - Delay for 50ns.
// PIO Mode 2 - Delay for 30ns.
// PIO Mode 3 - Delay for 30ns.
// PIO Mode 4 - Delay for 25ns.
//
// For a write to a APB register with HCLK at 100Mhz is 130ns.
// No extra delay is needed.
//
*IDE_CTRL = ulControl &= ~IDE_CTRL_DIOW;
//
// See Section 10.2.2 of the ATA/ATAPI Specification Version 5 for Delay
// Information.
//
// PIO Mode 0 - Delay for 290ns.
// PIO Mode 1 - Delay for 290s.
// PIO Mode 2 - Delay for 290s.
// PIO Mode 3 - Delay for 80ns.
// PIO Mode 4 - Delay for 70ns.
//
// For a write to a APB register with HCLK at 100Mhz is 130ns.
// No extra delay is needed.
//
*IDE_CTRL = ulControl |= IDE_CTRL_DIOW;
//
// See Section 10.2.2 of the ATA/ATAPI Specification Version 5 for Delay
// Information. There are also delays from all the returns and
// function calls so I am not putting the full delay in.
//
// PIO Mode 0 - N/A
// PIO Mode 1 - N/A
// PIO Mode 2 - N/A
// PIO Mode 3 - Delay for 70ns.
// PIO Mode 4 - Delay for 25ns.
//
// This 25ns easily gets eaten up by the function call return call and the few
// necessary instructions in the functions were it is used.
// DELAY_10NS
// DELAY_10NS
// DELAY_10NS
}
//****************************************************************************
// CEP931xPort::Init
//****************************************************************************
//
// Return TRUE - Success
// FALSE - Failure
//
BOOL CEP931xPort::Init()
{
BOOL bResult = TRUE;
ULONG ulShifted;
//
// Find out the shift factor for the page size.
//
m_ulPageShift = 0;
ulShifted = UserKInfo[KINX_PAGESIZE];
while(ulShifted != 1)
{
m_ulPageShift++;
ulShifted= ulShifted>>1;
}
//
// Create an event and a thread, and then associate them.
//
m_hIdeIntEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
if(!m_hIdeIntEvent)
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to Create Interrupt Event.\r\n")));
bResult = FALSE;
}
//
// Get the event handle, register the interrupt, and then
// associate it with the event.
//
if(bResult)
{
bResult = InterruptInitialize(SYSINTR_IDE, m_hIdeIntEvent, NULL, 0) ;
if(!bResult)
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to InitializeInterrupt.\r\n")));
}
}
//
// Allocate a DMA buffer if the buffer is unaligned. This is used if the
// buffer is unaligned.
//
if(bResult)
{
m_pucStaticBuffer = (PUCHAR) AllocPhysMem
(
MAX_DMA_SECT_PER_COMMAND * BYTES_PER_SECTOR,
PAGE_READWRITE | PAGE_NOCACHE,
0,
0,
&m_ulStaticPhysBuff
);
bResult = m_pucStaticBuffer ?TRUE:FALSE;
}
if(bResult)
{
//
// Initialize the IDE interface to PIO mode 4.
//
*IDE_CFG = IDE_CFG_IDEEN | IDE_CFG_PIOEN | IDE_CFG_PIO4 | (1 <<IDE_CFG_WST_SHIFT);
*IDE_CTRL = IDE_CTRL_DIOR | IDE_CTRL_DIOW | CSDA_DATA_REG;
//
// Make sure that MDMA and UDMA are disabled.
//
*IDE_MDMAOP = 0;
*IDE_UDMAOP = 0;
}
return bResult;
}
//****************************************************************************
// CEP931xPort::~CEP931xPort
//****************************************************************************
// Destructor
//
//
CEP931xPort::~CEP931xPort()
{
BOOL bResult = TRUE;
if(m_hIdeIntEvent)
{
CloseHandle(m_hIdeIntEvent);
}
DeleteCriticalSection( &m_CriticalSection);
}
//****************************************************************************
// CEP931xPort::SetupDMA
//****************************************************************************
// Sets up the dma controller and prepares the DMA buffers.
//
//
BOOL CEP931xPort::SetupDMA
(
PSG_BUF pSgBuf,
DWORD dwSgCount,
BOOL fRead,
ULONG ulCurrentMode
)
{
BOOL fLockRet;
ULONG ulDmaCount;
ULONG ulIDESource, ulIDEDest;
ULONG ulBuffer;
LPBYTE pBuffer;
BOOL fPagesLocked;
DWORD PFNs[16];
ULONG ulPage, ulNumPages;
ULONG ulPageSize = UserKInfo[KINX_PAGESIZE];
DEBUGMSG
(
ZONE_DMA,
(
TEXT("ATAPI:SetupDMA Request = %s SgCount=%ld\r\n"),
fRead ? TEXT("Read") : TEXT("Write"),
dwSgCount
)
);
//
// Stop any DMA that is occuring.
//
m_pulDmaBase[M2M_CTRL>>2] &= ~M2M_CTRL_START;
//
// Lets save off the DMA information.
//
m_pDMASgBuf = pSgBuf;
m_dwDMASgCount = dwSgCount;
m_fDMARead = fRead;
m_fAligned = TRUE;
m_ulCurrentMode = ulCurrentMode;
ulDmaCount = 0;
//
// Check if either the buffer or the buffer length is unaligned. If the buffers are not
//
if(dwSgCount ==1 && !((ULONG)pSgBuf[0].sb_buf & 0x3) && !(pSgBuf[0].sb_len & 0x3))
{
//
// Map the pointer to the process so that we have a valid pointer in our process.
//
m_pucDmaBuffer = (LPBYTE)MapPtrToProcess(pSgBuf[0].sb_buf, GetCallerProcess());
//
// Lock the pages for reading or writing.
//
fPagesLocked = LockPages
(
m_pucDmaBuffer,
pSgBuf[0].sb_len,
PFNs,
fRead ? LOCKFLAG_WRITE : LOCKFLAG_READ
);
//
// If the function succeds, Check to make sure that the pages are physically contiguous.
// If they are not then do the unaligned buffer case.
//
if(fPagesLocked)
{
ulNumPages = 1 + ( (ULONG(m_pucDmaBuffer) + pSgBuf[0].sb_len) >> m_ulPageShift) -
( ULONG(m_pucDmaBuffer) >> m_ulPageShift);
for(ulPage = 0; ulPage< (ulNumPages - 1); ulPage++)
{
if(PFNs[ulPage] !=PFNs[ulPage + 1])
{
m_fAligned = FALSE;
break;
}
}
//
// If it is aligned then calculate the current physical address.
//
if(m_fAligned )
{
m_ulDmaPhysBuff = PFNs[0] + ((ULONG)m_pucDmaBuffer & (ulPageSize -1));
m_ulDmaCount = pSgBuf[0].sb_len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -