📄 pdds3c2440_ser.cpp
字号:
//
// 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 2440 UART Common Code.
Notes:
--*/
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <ddkreg.h>
#include <serhw.h>
#include <Serdbg.h>
#include <pdds3c2440_ser.h>
#include <s3c2440a_base_regs.h>
CReg2440Uart::CReg2440Uart(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_s3c2440_pclk = DEFAULT_S3C2440A_PCLK;
RETAILMSG(TRUE, (TEXT("WARNING: CReg2440Uart::CReg2440Uart failed to obtain processor frequency - using default value (%d).\r\n"), m_s3c2440_pclk));
}
else
{
m_s3c2440_pclk = procInfo.dwClockSpeed;
RETAILMSG(TRUE, (TEXT("INFO: CReg2440Uart::CReg2440Uart using processor frequency reported by the OAL (%d).\r\n"), m_s3c2440_pclk));
}
}
BOOL CReg2440Uart::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 CReg2440Uart::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 CReg2440Uart::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;
}
}
CReg2440Uart::Write_BaudRate(ULONG BaudRate)
{
DEBUGMSG(ZONE_INIT, (TEXT("SetBaudRate -> %d\r\n"), BaudRate));
if ( (Read_UCON() & CS_MASK) == CS_PCLK ) {
Write_UBRDIV( (int)(m_s3c2440_pclk/16.0/BaudRate) -1 );
return TRUE;
}
else {
// TODO: Support external UART clock.
//OUTREG(pHWHead,UBRDIV,( (int)(S2440UCLK/16.0/BaudRate) -1 ));
RETAILMSG(TRUE, (TEXT("ERROR: The s3c2440a serial driver doesn't support an external UART clock.\r\n")));
ASSERT(FALSE);
return(FALSE);
}
}
#ifdef DEBUG
void CReg2440Uart::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
CPdd2440Uart::CPdd2440Uart (LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj )
: CSerialPDD(lpActivePath,pMdd, pHwObj)
, m_ActiveReg(HKEY_LOCAL_MACHINE,lpActivePath)
, CMiniThread (0, TRUE)
{
m_pReg2440Uart = 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 ;
}
CPdd2440Uart::~CPdd2440Uart()
{
InitModem(FALSE);
if (m_hISTEvent) {
m_bTerminated=TRUE;
ThreadStart();
SetEvent(m_hISTEvent);
ThreadTerminated(1000);
InterruptDisable( m_dwSysIntr );
CloseHandle(m_hISTEvent);
};
if (m_pReg2440Uart)
delete m_pReg2440Uart;
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 CPdd2440Uart::Init()
{
if ( CSerialPDD::Init() && IsKeyOpened() && m_XmitFlushDone!=NULL) {
// IST Setup .
DDKISRINFO ddi;
if (GetIsrInfo(&ddi)!=ERROR_SUCCESS) {
return FALSE;
}
m_dwSysIntr = ddi.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_2440UART_INTBIT_VAL_NAME,(PBYTE)&m_dwIntShift,sizeof(DWORD))) {
RETAILMSG(1,(TEXT("Registery does not have %s set. Drivers fail!!!\r\n"),PC_REG_2440UART_INTBIT_VAL_NAME));
m_dwIntShift =0;
return FALSE;
}
if (!GetRegValue(PC_REG_2440UART_IST_TIMEOUTS_VAL_NAME,(PBYTE)&m_dwISTTimeout, PC_REG_2440UART_IST_TIMEOUTS_VAL_LEN)) {
m_dwISTTimeout = INFINITE;
}
if (!MapHardware() || !CreateHardwareAccess()) {
return FALSE;
}
return TRUE;
}
return FALSE;
}
BOOL CPdd2440Uart::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 = S3C2440A_BASE_REG_PA_INTR ;
ioPhysicalBase.HighPart = 0;
inIoSpace = 0;
if (TranslateBusAddr(m_hParent,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber, ioPhysicalBase,&inIoSpace,&ioPhysicalBase)) {
m_pINTregs = (S3C2440A_INTR_REG *) MmMapIoSpace(ioPhysicalBase,sizeof(S3C2440A_INTR_REG),FALSE);
}
return (m_pRegVirtualAddr!=NULL && m_pINTregs!=NULL);
}
BOOL CPdd2440Uart::CreateHardwareAccess()
{
if (m_pReg2440Uart)
return TRUE;
if (m_pRegVirtualAddr!=NULL) {
m_pReg2440Uart = new CReg2440Uart((PULONG)m_pRegVirtualAddr);
if (m_pReg2440Uart && !m_pReg2440Uart->Init()) { // FALSE.
delete m_pReg2440Uart ;
m_pReg2440Uart = NULL;
}
}
return (m_pReg2440Uart!=NULL);
}
#define MAX_RETRY 0x1000
void CPdd2440Uart::PostInit()
{
DWORD dwCount=0;
m_HardwareLock.Lock();
m_pReg2440Uart->Write_UCON(0); // Set to Default;
DisableInterrupt(S2440UART_INT_RXD|S2440UART_INT_TXD|S2440UART_INT_ERR);
// Mask all interrupt.
while ((GetInterruptStatus() & (S2440UART_INT_RXD|S2440UART_INT_TXD|S2440UART_INT_ERR))!=0 &&
dwCount <MAX_RETRY) { // Interrupt.
InitReceive(TRUE);
InitLine(TRUE);
ClearInterrupt(S2440UART_INT_RXD|S2440UART_INT_TXD|S2440UART_INT_ERR);
dwCount++;
}
ASSERT((GetInterruptStatus() & (S2440UART_INT_RXD|S2440UART_INT_TXD|S2440UART_INT_ERR))==0);
// IST Start to Run.
m_HardwareLock.Unlock();
CSerialPDD::PostInit();
CeSetPriority(m_dwPriority256);
#ifdef DEBUG
if ( ZONE_INIT )
m_pReg2440Uart->DumpRegister();
#endif
ThreadStart(); // Start IST.
}
DWORD CPdd2440Uart::ThreadRun()
{
while ( m_hISTEvent!=NULL && !IsTerminated()) {
if (WaitForSingleObject( m_hISTEvent,m_dwISTTimeout)==WAIT_OBJECT_0) {
m_HardwareLock.Lock();
while (!IsTerminated() ) {
DWORD dwData = (GetInterruptStatus() & (S2440UART_INT_RXD|S2440UART_INT_TXD|S2440UART_INT_ERR));
DWORD dwMask = (GetIntrruptMask() & (S2440UART_INT_RXD|S2440UART_INT_TXD|S2440UART_INT_ERR));
DEBUGMSG(ZONE_THREAD,
(TEXT(" CPdd2440Uart::ThreadRun INT=%x, MASK =%x\r\n"),dwData,dwMask));
dwMask &= dwData;
if (dwMask) {
DEBUGMSG(ZONE_THREAD,
(TEXT(" CPdd2440Uart::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 & S2440UART_INT_RXD)!=0)
interrupts |= INTR_RX;
if ((dwMask & S2440UART_INT_TXD)!=0)
interrupts |= INTR_TX;
if ((dwMask & S2440UART_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(" CPdd2440Uart::ThreadRun timeout INT=%x,MASK=%d\r\n"),m_pINTregs->SUBSRCPND,m_pINTregs->INTSUBMSK));
#ifdef DEBUG
if ( ZONE_THREAD )
m_pReg2440Uart->DumpRegister();
#endif
}
}
return 1;
}
BOOL CPdd2440Uart::InitialEnableInterrupt(BOOL bEnable )
{
m_HardwareLock.Lock();
if (bEnable)
EnableInterrupt(S2440UART_INT_RXD | S2440UART_INT_ERR );
else
DisableInterrupt(S2440UART_INT_RXD | S2440UART_INT_ERR );
m_HardwareLock.Unlock();
return TRUE;
}
BOOL CPdd2440Uart::InitXmit(BOOL bInit)
{
if (bInit) {
m_HardwareLock.Lock();
DWORD dwBit = m_pReg2440Uart->Read_UCON();
// Set TxINterrupt To Level.
dwBit |= (1<<9);
// Set Interrupt Tx Mode.
dwBit &= ~(3<<2);
dwBit |= (1<<2);
m_pReg2440Uart->Write_UCON(dwBit );
dwBit = m_pReg2440Uart->Read_UFCON();
// Reset Xmit Fifo.
dwBit |= (1<<2);
dwBit &= ~(1<<0);
m_pReg2440Uart->Write_UFCON( dwBit);
// Set Trigger level to 16.
dwBit &= ~(3<<6);//empty
dwBit |= (1<<6);//16
m_pReg2440Uart->Write_UFCON(dwBit);
// Enable Xmit FIFO.
dwBit &= ~(1<<2);
dwBit |= (1<<0);
m_pReg2440Uart->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_pReg2440Uart->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 CPdd2440Uart::GetWriteableSize()
{
DWORD dwWriteSize = 0;
DWORD dwUfState = m_pReg2440Uart->Read_UFSTAT() ;
if ((dwUfState& (1<<14))==0) { // It is not full.
dwUfState = ((dwUfState>>8) & 0x3f); // It is fifo count.
if (dwUfState < SER2440_FIFO_DEPTH_TX-1)
dwWriteSize = SER2440_FIFO_DEPTH_TX-1 - dwUfState;
}
return dwWriteSize;
}
void CPdd2440Uart::XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen)
{
PREFAST_DEBUGCHK(pBuffLen!=NULL);
m_HardwareLock.Lock();
if (*pBuffLen == 0) {
EnableXmitInterrupt(FALSE);
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -