pdds3c24a0_ser.cpp
来自「S3C24A0的完整BSP包,对开发此芯片的开发者很有用.」· C++ 代码 · 共 777 行 · 第 1/2 页
CPP
777 行
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft 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 LICENSE.RTF on your
// install media.
//
//
/*++
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.
Module Name:
Abstract:
Serial PDD for SamSang 24A0 UART Common Code.
Notes:
--*/
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <ddkreg.h>
#include <serhw.h>
#include <Serdbg.h>
#include <pdds3c24A0_ser.h>
#include <s3c24A0_base_regs.h>
CReg24A0Uart::CReg24A0Uart(PULONG pRegAddr)
: m_pReg(pRegAddr)
{
m_fIsBackedUp = FALSE;
PROCESSOR_INFO procInfo;
DWORD dwBytesReturned;
if (!KernelIoControl(IOCTL_PROCESSOR_INFORMATION, NULL, 0, &procInfo, sizeof(PROCESSOR_INFO), &dwBytesReturned))
{
m_s3c24A0_pclk = DEFAULT_S3C24A0X_PCLK;
RETAILMSG(TRUE, (TEXT("WARNING: CReg24A0Uart::CReg24A0Uart failed to obtain processor frequency - using default value (%d).\r\n"), m_s3c24A0_pclk));
}
else
{
m_s3c24A0_pclk = procInfo.dwClockSpeed;
RETAILMSG(TRUE, (TEXT("INFO: CReg24A0Uart::CReg24A0Uart using processor frequency reported by the OAL (%d).\r\n"), m_s3c24A0_pclk));
}
}
BOOL CReg24A0Uart::Init()
{
if (m_pReg) { // Set Value to default.
Write_ULCON(0);
Write_UCON(0);
Write_UFCON(0);
Write_UMCON(0);
return TRUE;
}
else
return FALSE;
}
void CReg24A0Uart::Backup()
{
m_fIsBackedUp = TRUE;
m_ULCONBackup = Read_ULCON();
m_UCONBackup = Read_UCON();
m_UFCONBackup = Read_UFCON();
m_UMCOMBackup = Read_UMCON();
m_UBRDIVBackup = Read_UBRDIV();
}
void CReg24A0Uart::Restore()
{
if (m_fIsBackedUp) {
Write_ULCON(m_ULCONBackup );
Write_UCON( m_UCONBackup );
Write_UFCON( m_UFCONBackup );
Write_UMCON( m_UMCOMBackup );
Write_UBRDIV( m_UBRDIVBackup);
m_fIsBackedUp = FALSE;
}
}
CReg24A0Uart::Write_BaudRate(ULONG BaudRate)
{
DEBUGMSG(ZONE_INIT, (TEXT("SetBaudRate -> %d\r\n"), BaudRate));
if ( (Read_UCON() & CS_MASK) == CS_PCLK ) {
Write_UBRDIV( (int)(m_s3c24A0_pclk/16.0/BaudRate) -1 );
return TRUE;
}
else {
// TODO: Support external UART clock.
//OUTREG(pHWHead,UBRDIV,( (int)(S24A0UCLK/16.0/BaudRate) -1 ));
RETAILMSG(TRUE, (TEXT("ERROR: The s3c24A0x serial driver doesn't support an external UART clock.\r\n")));
ASSERT(FALSE);
return(FALSE);
}
}
#ifdef DEBUG
void CReg24A0Uart::DumpRegister()
{
NKDbgPrintfW(TEXT("DumpRegister (ULCON=%x, UCON=%x, UFCON=%x, UMCOM = %x, UBDIV =%x)\r\n"),
Read_ULCON(),Read_UCON(),Read_UFCON(),Read_UMCON(),Read_UBRDIV());
}
#endif
CPdd24A0Uart::CPdd24A0Uart (LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj )
: CSerialPDD(lpActivePath,pMdd, pHwObj)
, m_ActiveReg(HKEY_LOCAL_MACHINE,lpActivePath)
, CMiniThread (0, TRUE)
{
m_pReg24A0Uart = NULL;
m_pINTregs = NULL;
m_dwIntShift = 0;
m_dwSysIntr = MAXDWORD;
m_hISTEvent = NULL;
m_dwDevIndex = 0;
m_pRegVirtualAddr = NULL;
m_XmitFlushDone = CreateEvent(0, FALSE, FALSE, NULL);
m_XmitFifoEnable = FALSE;
m_dwWaterMark = 8 ;
}
CPdd24A0Uart::~CPdd24A0Uart()
{
InitModem(FALSE);
if (m_hISTEvent) {
m_bTerminated=TRUE;
ThreadStart();
SetEvent(m_hISTEvent);
ThreadTerminated(1000);
InterruptDisable( m_dwSysIntr );
CloseHandle(m_hISTEvent);
};
if (m_pReg24A0Uart)
delete m_pReg24A0Uart;
if (m_XmitFlushDone)
CloseHandle(m_XmitFlushDone);
if (m_pRegVirtualAddr != NULL) {
MmUnmapIoSpace((PVOID)m_pRegVirtualAddr,0UL);
}
if (m_pINTregs!=NULL) {
MmUnmapIoSpace((PVOID)m_pINTregs,0UL);
}
}
BOOL CPdd24A0Uart::Init()
{
if ( CSerialPDD::Init() && IsKeyOpened() && m_XmitFlushDone!=NULL) {
// IST Setup .
DDKISRINFO ddi;
if (GetIsrInfo(&ddi)!=ERROR_SUCCESS) {
return FALSE;
}
m_dwSysIntr = ddi.dwSysintr;
//RETAILMSG(TRUE, (TEXT("Sysint : The gkp s3c24A0 serial driver intr :irq%d sysintr %d.\r\n"),ddi.dwIrq, m_dwSysIntr));
if (m_dwSysIntr != MAXDWORD && m_dwSysIntr!=0 )
m_hISTEvent= CreateEvent(0,FALSE,FALSE,NULL);
if (m_hISTEvent!=NULL)
InterruptInitialize(m_dwSysIntr,m_hISTEvent,0,0);
else
return FALSE;
// Get Device Index.
if (!GetRegValue(PC_REG_DEVINDEX_VAL_NAME, (PBYTE)&m_dwDevIndex, PC_REG_DEVINDEX_VAL_LEN)) {
m_dwDevIndex = 0;
}
if (!GetRegValue(PC_REG_SERIALWATERMARK_VAL_NAME,(PBYTE)&m_dwWaterMark,sizeof(DWORD))) {
m_dwWaterMark = 8;
}
if (!GetRegValue(PC_REG_24A0UART_INTBIT_VAL_NAME,(PBYTE)&m_dwIntShift,sizeof(DWORD))) {
RETAILMSG(1,(TEXT("Registery does not have %s set. Drivers fail!!!\r\n"),PC_REG_24A0UART_INTBIT_VAL_NAME));
m_dwIntShift =0;
return FALSE;
}
if (!GetRegValue(PC_REG_24A0UART_IST_TIMEOUTS_VAL_NAME,(PBYTE)&m_dwISTTimeout, PC_REG_24A0UART_IST_TIMEOUTS_VAL_LEN)) {
m_dwISTTimeout = INFINITE;
}
if (!MapHardware() || !CreateHardwareAccess()) {
return FALSE;
}
return TRUE;
}
return FALSE;
}
BOOL CPdd24A0Uart::MapHardware()
{
if (m_pRegVirtualAddr !=NULL)
return TRUE;
// Get IO Window From Registry
DDKWINDOWINFO dwi;
if ( GetWindowInfo( &dwi)!=ERROR_SUCCESS ||
dwi.dwNumMemWindows < 1 ||
dwi.memWindows[0].dwBase == 0 ||
dwi.memWindows[0].dwLen < 0x2c)
return FALSE;
DWORD dwInterfaceType;
if (m_ActiveReg.IsKeyOpened() &&
m_ActiveReg.GetRegValue( DEVLOAD_INTERFACETYPE_VALNAME, (PBYTE)&dwInterfaceType,sizeof(DWORD))) {
dwi.dwInterfaceType = dwInterfaceType;
}
// Translate to System Address.
PHYSICAL_ADDRESS ioPhysicalBase = { dwi.memWindows[0].dwBase, 0};
ULONG inIoSpace = 0;
if (TranslateBusAddr(m_hParent,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber, ioPhysicalBase,&inIoSpace,&ioPhysicalBase)) {
// Map it if it is Memeory Mapped IO.
m_pRegVirtualAddr = MmMapIoSpace(ioPhysicalBase, dwi.memWindows[0].dwLen,FALSE);
}
ioPhysicalBase.LowPart = S3C24A0_BASE_REG_PA_INTR ;
ioPhysicalBase.HighPart = 0;
inIoSpace = 0;
if (TranslateBusAddr(m_hParent,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber, ioPhysicalBase,&inIoSpace,&ioPhysicalBase)) {
m_pINTregs = (S3C24A0_INTR_REG *) MmMapIoSpace(ioPhysicalBase,sizeof(S3C24A0_INTR_REG),FALSE);
}
return (m_pRegVirtualAddr!=NULL && m_pINTregs!=NULL);
}
BOOL CPdd24A0Uart::CreateHardwareAccess()
{
if (m_pReg24A0Uart)
return TRUE;
if (m_pRegVirtualAddr!=NULL) {
m_pReg24A0Uart = new CReg24A0Uart((PULONG)m_pRegVirtualAddr);
if (m_pReg24A0Uart && !m_pReg24A0Uart->Init()) { // FALSE.
delete m_pReg24A0Uart ;
m_pReg24A0Uart = NULL;
}
}
return (m_pReg24A0Uart!=NULL);
}
#define MAX_RETRY 0x1000
void CPdd24A0Uart::PostInit()
{
DWORD dwCount=0;
m_HardwareLock.Lock();
m_pReg24A0Uart->Write_UCON(0); // Set to Default;
DisableInterrupt(S24A0UART_INT_RXD|S24A0UART_INT_TXD|S24A0UART_INT_ERR);
// Mask all interrupt.
while ((GetInterruptStatus() & (S24A0UART_INT_RXD|S24A0UART_INT_TXD|S24A0UART_INT_ERR))!=0 &&
dwCount <MAX_RETRY) { // Interrupt.
InitReceive(TRUE);
InitLine(TRUE);
ClearInterrupt(S24A0UART_INT_RXD|S24A0UART_INT_TXD|S24A0UART_INT_ERR);
dwCount++;
}
ASSERT((GetInterruptStatus() & (S24A0UART_INT_RXD|S24A0UART_INT_TXD|S24A0UART_INT_ERR))==0);
// IST Start to Run.
m_HardwareLock.Unlock();
CSerialPDD::PostInit();
CeSetPriority(m_dwPriority256);
#ifdef DEBUG
if ( ZONE_INIT )
m_pReg24A0Uart->DumpRegister();
#endif
ThreadStart(); // Start IST.
}
DWORD CPdd24A0Uart::ThreadRun()
{
while ( m_hISTEvent!=NULL && !IsTerminated()) {
if (WaitForSingleObject( m_hISTEvent,m_dwISTTimeout)==WAIT_OBJECT_0) {
m_HardwareLock.Lock();
while (!IsTerminated() ) {
DWORD dwData = (GetInterruptStatus() & (S24A0UART_INT_RXD|S24A0UART_INT_TXD|S24A0UART_INT_ERR));
DWORD dwMask = (GetIntrruptMask() & (S24A0UART_INT_RXD|S24A0UART_INT_TXD|S24A0UART_INT_ERR));
DEBUGMSG(ZONE_THREAD,
(TEXT(" CPdd24A0Uart::ThreadRun INT=%x, MASK =%x\r\n"),dwData,dwMask));
dwMask &= dwData;
if (dwMask) {
DEBUGMSG(ZONE_THREAD,
(TEXT(" CPdd24A0Uart::ThreadRun Active INT=%x\r\n"),dwMask));
DWORD interrupts=INTR_MODEM; // Always check Modem when we have change. It may work at polling mode.
if ((dwMask & S24A0UART_INT_RXD)!=0)
interrupts |= INTR_RX;
if ((dwMask & S24A0UART_INT_TXD)!=0)
interrupts |= INTR_TX;
if ((dwMask & S24A0UART_INT_ERR)!=0)
interrupts |= INTR_LINE|INTR_RX;
NotifyPDDInterrupt((INTERRUPT_TYPE)interrupts);
ClearInterrupt(dwData);
}
else
break;
}
m_HardwareLock.Unlock();
InterruptDone(m_dwSysIntr);
}
else { // Polling Modem.
NotifyPDDInterrupt(INTR_MODEM);
//DEBUGMSG(ZONE_THREAD,(TEXT(" CPdd24A0Uart::ThreadRun timeout INT=%x,MASK=%d\r\n"),m_pINTregs->SUBSRCPND,m_pINTregs->INTSUBMSK));
#ifdef DEBUG
//if ( ZONE_THREAD )
// m_pReg24A0Uart->DumpRegister();
#endif
}
}
return 1;
}
BOOL CPdd24A0Uart::InitialEnableInterrupt(BOOL bEnable )
{
m_HardwareLock.Lock();
if (bEnable)
{
EnableInterrupt(S24A0UART_INT_RXD | S24A0UART_INT_ERR );
RETAILMSG(1,(TEXT("gkp InitialEnableInterrupt receive intr enable rx!!!\r\n")));
}
else
DisableInterrupt(S24A0UART_INT_RXD | S24A0UART_INT_ERR );
m_HardwareLock.Unlock();
return TRUE;
}
BOOL CPdd24A0Uart::InitXmit(BOOL bInit)
{
if (bInit) {
m_HardwareLock.Lock();
DWORD dwBit = m_pReg24A0Uart->Read_UCON();
// Set TxINterrupt To Level.
dwBit |= (1<<9);
// Set Interrupt Tx Mode.
dwBit &= ~(3<<2);
dwBit |= (1<<2);
m_pReg24A0Uart->Write_UCON(dwBit );
dwBit = m_pReg24A0Uart->Read_UFCON();
// Reset Xmit Fifo.
dwBit |= (1<<2);
dwBit &= ~(1<<0);
m_pReg24A0Uart->Write_UFCON( dwBit);
// Set Trigger level to 4.
dwBit &= ~(3<<6);
dwBit |= (1<<6);
m_pReg24A0Uart->Write_UFCON(dwBit);
// Enable Xmit FIFO.
dwBit &= ~(1<<2);
dwBit |= (1<<0);
m_pReg24A0Uart->Write_UFCON(dwBit); // Xmit Fifo Reset Done..
m_HardwareLock.Unlock();
}
else { // Make Sure data has been trasmit out.
// We have to make sure the xmit is complete because MDD will shut donw the device after this return
DWORD dwTicks = 0;
DWORD dwUTRState;
while (dwTicks < 1000 &&
(((dwUTRState = m_pReg24A0Uart->Read_UTRSTAT())>>1) & 3)!=3 ) { // Transmitter empty is not true
DEBUGMSG(ZONE_THREAD|ZONE_WRITE,(TEXT("CPdd16550::InitXmit! Wait for UTRSTAT=%x clear.\r\n"), dwUTRState));
Sleep(5);
dwTicks +=5;
}
}
return TRUE;
}
DWORD CPdd24A0Uart::GetWriteableSize()
{
DWORD dwWriteSize = 0;
DWORD dwUfState = m_pReg24A0Uart->Read_UFSTAT() ;
//Guru
//if ((dwUfState& (1<<9))==0) { // It is not full. for 2410 9th bit
if ((dwUfState & SER24A0_FIFOFULL_TX) == 0) { // It is not full.
//dwUfState = ((dwUfState>>4) & 0xf); // It is fifo count. for 2410
dwUfState = ((dwUfState & SER24A0_FIFOCNT_MASK_TX) >> SER24A0_TX_FIFOCNT_BIT_SHIFT);
if (dwUfState < SER24A0_FIFO_DEPTH_TX-1)
dwWriteSize = SER24A0_FIFO_DEPTH_TX-1 - dwUfState;
}
return dwWriteSize;
}
void CPdd24A0Uart::XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen)
{
PREFAST_DEBUGCHK(pBuffLen!=NULL);
m_HardwareLock.Lock();
if (*pBuffLen == 0) {
EnableXmitInterrupt(FALSE);
}
else {
DEBUGCHK(pTxBuffer);
PulseEvent(m_XmitFlushDone);
DWORD dwDataAvaiable = *pBuffLen;
*pBuffLen = 0;
Rx_Pause(TRUE);
if ((m_DCB.fOutxCtsFlow && IsCTSOff()) ||(m_DCB.fOutxDsrFlow && IsDSROff())) { // We are in flow off
DEBUGMSG(ZONE_THREAD|ZONE_WRITE,(TEXT("CPdd16550::XmitInterruptHandler! Flow Off, Data Discard.\r\n")));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?