📄 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 2005, All Rights Reserved
//
//**********************************************************************
#include "atamain.h"
#include <oalintr.h>
#include <CEDDK.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
//
// By expermentations it could be up to 10 Seconds between the time the
// dma completes before an interrupt is generated.
//
#define UDMA_IDE_TIMEOUT 10000
#define UDMA_DMA_TIMEOUT 50
//
// Include code to insure that IRQ/FIQ cannot interrupt PIO write
//
#define WLG_FIX_INTERRUPT_PIO_WRITE
//#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;
// int ThreadPriority;
//
// 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 for the IDE interupt.
//
m_hIdeIntEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
if(!m_hIdeIntEvent)
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to Create Interrupt Event for IDE.\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 for IDE.\r\n")));
}
}
//
// Create an event for the DMA interrupt.
//
if(bResult)
{
m_hDmaIntEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
if(!m_hDmaIntEvent)
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to Create Interrupt Event for DMA .\r\n")));
bResult = FALSE;
}
}
//
// Create an DMA interrupt.
//
if(bResult)
{
bResult = InterruptInitialize(SYSINTR_DMA_M2M0, m_hDmaIntEvent, NULL, 0) ;
if(!bResult)
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to InitializeInterrupt for DMA.\r\n")));
}
}
//
// Create an event to signal the IdeIst and the DmaIst to wait for there respective interrupts.
// also used to clean up.
//
if(bResult)
{
m_hThreadWaitEvent = CreateEvent( NULL, TRUE, FALSE, NULL);
if(!m_hThreadWaitEvent)
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to Create Common Interrupt Event.\r\n")));
bResult = FALSE;
}
}
//
// Create the DMA and IDE interrupt service threads.
//
if(bResult)
{
m_hDmaThread = CreateThread
(
(LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)CEP931xPort::DmaIst,
(PVOID)this,
0,
NULL
);
if(!m_hDmaThread)
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to Create Dma Thread.\r\n")));
bResult = FALSE;
}
}
if(bResult)
{
m_hIdeThread = CreateThread
(
(LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)CEP931xPort::IdeIst,
(PVOID)this,
0,
NULL
);
if(!m_hIdeThread)
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to Create Dma Thread.\r\n")));
bResult = FALSE;
}
}
if(bResult)
{
CeSetThreadPriority(m_hIdeThread, 50);
CeSetThreadPriority(m_hDmaThread, 50);
}
//
// Create two events for to signal WaitForDma.
//
if(bResult)
{
m_hIstEvent[DMA_EVENT] = CreateEvent( NULL, TRUE, FALSE, NULL);
if(!m_hIstEvent[DMA_EVENT])
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to Create Interrupt Event for DMA .\r\n")));
bResult = FALSE;
}
}
if(bResult)
{
m_hIstEvent[IDE_EVENT] = CreateEvent( NULL, TRUE, FALSE, NULL);
if(!m_hIstEvent[IDE_EVENT])
{
DEBUGMSG( ZONE_INIT, (TEXT("CEP931xDisk::Init Failed to Create Interrupt Event for DMA .\r\n")));
bResult = FALSE;
}
}
//
// Allocate a DMA buffer if the buffer is unaligned. This is used if the
// buffer is unaligned. HalAllocateCommonBuffer
//
if(bResult)
{
m_pucStaticBuffer = (PUCHAR) AllocPhysMem
(
131072,
PAGE_READWRITE | PAGE_NOCACHE,
0,
0,
&m_ulStaticPhysBuff
);
bResult = m_pucStaticBuffer ? TRUE:FALSE;
}
if(bResult)
{
//
// Make sure there are no glitches involving CS0 or CS1 and STOP/DIOWn
// when switching modes: deassert CS0 and CS1.
//
*IDE_CTRL |= IDE_CTRL_CS0 | IDE_CTRL_CS1;
//
// After returning from the dma state turn off the dma controller to reset
// the pointers.
//
*IDE_CFG = 0;
//
// 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;
//
// Free the memory in static DMA buffer.
//
if(m_pucStaticBuffer)
{
FreePhysMem(m_pucStaticBuffer);
m_pucStaticBuffer = 0;
}
//
// Exit the DMA thread and clean up the thread event.
//
if(m_hDmaThread || m_hIdeThread)
{
m_bThreadExit = TRUE;
SetEvent(m_hThreadWaitEvent);
if(m_hDmaThread)
{
WaitForSingleObject(m_hDmaThread,1000);
CloseHandle(m_hDmaThread);
m_hDmaThread = 0;
}
if(m_hIdeThread)
{
WaitForSingleObject(m_hIdeThread, 1000);
CloseHandle(m_hIdeThread);
m_hIdeThread = 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -