📄 pdd16550.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 16550 Common Code.
Notes:
--*/
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <ddkreg.h>
#include <serhw.h>
#include <hw16550.h>
#include <Serdbg.h>
#include "pdd16550.h"
extern "C" BOOL TranslateBusAddr(HANDLE hBusAccess,
INTERFACE_TYPE InterfaceType,ULONG BusNumber,PHYSICAL_ADDRESS BusAddress,PULONG AddressSpace,PPHYSICAL_ADDRESS TranslatedAddress );
CReg16550::CReg16550(PBYTE pRegAddr, DWORD dwStride)
: m_pReg (pRegAddr)
, m_dwStride(dwStride)
{
m_pData = pRegAddr + (dwStride * RECEIVE_BUFFER_REGISTER);
m_pIER = pRegAddr + (dwStride * INTERRUPT_ENABLE_REGISTER);
m_pIIR_FCR=pRegAddr + (dwStride * INTERRUPT_IDENT_REGISTER);
m_pLCR = pRegAddr + (dwStride * LINE_CONTROL_REGISTER);
m_pMCR = pRegAddr + (dwStride * MODEM_CONTROL_REGISTER);
m_pLSR = pRegAddr + (dwStride * LINE_STATUS_REGISTER);
m_pMSR = pRegAddr + (dwStride * MODEM_STATUS_REGISTER);
m_pSRC = pRegAddr + (dwStride * SCRATCH_REGISTER);
m_FCR = 0;
m_fIsBackedUp = FALSE;
}
void CReg16550::Backup()
{
m_fIsBackedUp = TRUE;
m_IERBackup = Read_IER();
m_LCRBackup = Read_LCR();
m_MCRBackup = Read_MCR();
}
void CReg16550::Restore()
{
if (m_fIsBackedUp) {
Write_FCR(m_FCR);
Write_IER(m_IERBackup);
Write_LCR(m_LCRBackup);
Write_MCR( m_MCRBackup);
Write_BaudRate(m_BaudRate);
m_fIsBackedUp = FALSE;
}
}
#ifdef DEBUG
void CReg16550::DumpRegister()
{
UINT8 byte;
byte = Read_LSR() ;
NKDbgPrintfW(TEXT("16550 lsr: \t%2.2X\t"), byte);
if ( byte & SERIAL_LSR_DR )
NKDbgPrintfW(TEXT("DataReady "));
if ( byte & SERIAL_LSR_OE )
NKDbgPrintfW(TEXT("OverRun "));
if ( byte & SERIAL_LSR_PE )
NKDbgPrintfW(TEXT("ParityErr "));
if ( byte & SERIAL_LSR_FE )
NKDbgPrintfW(TEXT("FramingErr "));
if ( byte & SERIAL_LSR_BI )
NKDbgPrintfW(TEXT("BreakIntpt "));
if ( byte & SERIAL_LSR_THRE )
NKDbgPrintfW(TEXT("THREmpty "));
if ( byte & SERIAL_LSR_TEMT )
NKDbgPrintfW(TEXT("TXEmpty "));
if ( byte & SERIAL_LSR_FIFOERR )
NKDbgPrintfW(TEXT("FIFOErr "));
NKDbgPrintfW(TEXT("\r\n"));
byte = Read_Data() ;
NKDbgPrintfW(TEXT("16550 rbr/thr:\t%2.2X\r\n"), byte);
byte = Read_IER();
NKDbgPrintfW(TEXT("16550 IER: \t%2.2X\t"), byte);
if ( byte & SERIAL_IER_RDA )
NKDbgPrintfW(TEXT("RXData "));
if ( byte & SERIAL_IER_THR )
NKDbgPrintfW(TEXT("TXData "));
if ( byte & SERIAL_IER_RLS )
NKDbgPrintfW(TEXT("RXErr "));
if ( byte & SERIAL_IER_MS )
NKDbgPrintfW(TEXT("ModemStatus "));
NKDbgPrintfW(TEXT("\r\n"));
byte = Read_IIR();
NKDbgPrintfW(TEXT("16550 iir: \t%2.2X\t"), byte);
if ((byte & SERIAL_IIR_INT_INVALID) == 0) {
NKDbgPrintfW(TEXT("IntPending "));
switch (byte & SERIAL_IIR_INT_MASK) {
case SERIAL_IIR_RLS :
NKDbgPrintfW(TEXT("Line Status "));
break;
case SERIAL_IIR_RDA : case SERIAL_IIR_CTI :case SERIAL_IIR_CTI_2:
NKDbgPrintfW(TEXT("RXData "));
break;
case SERIAL_IIR_THRE:
NKDbgPrintfW(TEXT("TXData "));
break;
case SERIAL_IIR_MS :
NKDbgPrintfW(TEXT("ModemStatus "));
break;
default:
NKDbgPrintfW(TEXT("Unknown "));
break;
}
}
NKDbgPrintfW(TEXT("\r\n"));
byte = Read_LCR();
NKDbgPrintfW(TEXT("16550 lcr: \t%2.2X\t"), byte);
NKDbgPrintfW(TEXT("%dBPC "), ((byte & 0x03)+5) );
if ( byte & SERIAL_LCR_DLAB )
NKDbgPrintfW(TEXT("DLAB "));
if ( byte & SERIAL_LCR_DLAB )
NKDbgPrintfW(TEXT("Break "));
NKDbgPrintfW(TEXT("\r\n"));
byte = Read_MSR();
NKDbgPrintfW(TEXT("16550 msr: \t%2.2X\t"), byte);
if ( byte & SERIAL_MSR_DCTS )
NKDbgPrintfW(TEXT("DCTS "));
if ( byte & SERIAL_MSR_DDSR )
NKDbgPrintfW(TEXT("DDSR "));
if ( byte & SERIAL_MSR_TERI )
NKDbgPrintfW(TEXT("TERI "));
if ( byte & SERIAL_MSR_DDCD )
NKDbgPrintfW(TEXT("DDCD"));
if ( byte & SERIAL_MSR_CTS )
NKDbgPrintfW(TEXT(" CTS"));
if ( byte & SERIAL_MSR_DSR )
NKDbgPrintfW(TEXT("DSR "));
if ( byte & SERIAL_MSR_RI )
NKDbgPrintfW(TEXT("RI "));
if ( byte & SERIAL_MSR_DCD )
NKDbgPrintfW(TEXT("DCD "));
NKDbgPrintfW(TEXT("\r\n"));
}
#endif
BOOL CReg16550::Write_BaudRate(UINT16 uData)
{
UINT8 lcr = Read_LCR();
Write_LCR( lcr | SERIAL_LCR_DLAB);
Write_DATA(uData & 0xff);
Write_IER((uData >> 8) & 0xff);
Write_LCR( lcr );
m_BaudRate = uData;
return TRUE;
}
CPdd16550::CPdd16550 (LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj )
: CSerialPDD(lpActivePath,pMdd, pHwObj)
, m_ActiveReg(HKEY_LOCAL_MACHINE,lpActivePath)
, CMiniThread (0, TRUE)
{
m_pReg16550 = NULL;
m_dwSysIntr = MAXDWORD;
m_hISTEvent = NULL;
m_dwDevIndex = 0;
m_pRegVirtualAddr = NULL;
m_bIsIo = TRUE;
m_XmitFlushDone = CreateEvent(0, FALSE, FALSE, NULL);
m_XmitFifoEnable = FALSE;
m_dwWaterMark = 8 ;
}
CPdd16550::~CPdd16550()
{
if (m_pReg16550)
InitModem(FALSE);
if (m_hISTEvent) {
m_bTerminated=TRUE;
ThreadStart();
SetEvent(m_hISTEvent);
ThreadTerminated(1000);
if (m_dwSysIntr != MAXDWORD)
InterruptDisable( m_dwSysIntr );
CloseHandle(m_hISTEvent);
};
if (m_pReg16550)
delete m_pReg16550;
if (m_XmitFlushDone)
CloseHandle(m_XmitFlushDone);
if (m_pRegVirtualAddr != NULL && m_bIsIo != TRUE) {
MmUnmapIoSpace((PVOID)m_pRegVirtualAddr,0UL);
}
}
BOOL CPdd16550::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) {
if (!InterruptInitialize(m_dwSysIntr,m_hISTEvent,0,0)) {
m_dwSysIntr = MAXDWORD ;
return FALSE;
}
}
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 (!MapHardware() || !CreateHardwareAccess()) {
return FALSE;
}
return TRUE;
}
return FALSE;
}
BOOL CPdd16550::MapHardware()
{
if (m_pRegVirtualAddr !=NULL)
return TRUE;
m_dwRegStride = 1;
if (!GetRegValue(PC_REG_REGSTRIDE_VAL_NAME,(PBYTE)&m_dwRegStride, PC_REG_REGSTRIDE_VAL_LEN)) {
m_dwRegStride = 1;
}
// Get IO Window From Registry
DDKWINDOWINFO dwi;
if ( GetWindowInfo( &dwi)!=ERROR_SUCCESS ||
dwi.dwNumIoWindows < 1 ||
dwi.ioWindows[0].dwBase == 0 ||
dwi.ioWindows[0].dwLen < m_dwRegStride * (SCRATCH_REGISTER+1))
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.ioWindows[0].dwBase, 0};
ULONG inIoSpace = 1;
if (TranslateBusAddr(m_hParent,(INTERFACE_TYPE)dwi.dwInterfaceType,dwi.dwBusNumber, ioPhysicalBase,&inIoSpace,&ioPhysicalBase)) {
if (inIoSpace) {
m_bIsIo = TRUE;;
m_pRegVirtualAddr = (PVOID)ioPhysicalBase.LowPart;
}
else {
// Map it if it is Memeory Mapped IO.
m_pRegVirtualAddr = MmMapIoSpace(ioPhysicalBase, dwi.ioWindows[0].dwLen,FALSE);
m_bIsIo = FALSE;
}
}
return (m_pRegVirtualAddr!=NULL);
}
BOOL CPdd16550::CreateHardwareAccess()
{
if (m_pReg16550)
return TRUE;
if (m_pRegVirtualAddr!=NULL) {
m_pReg16550 =(m_bIsIo? new CReg16550((PBYTE)m_pRegVirtualAddr,m_dwRegStride) : new CMemReg16550 ((PBYTE)m_pRegVirtualAddr,m_dwRegStride));
if (m_pReg16550 && !m_pReg16550->Init()) { // FALSE.
delete m_pReg16550 ;
m_pReg16550 = NULL;
}
}
return (m_pReg16550!=NULL);
}
#define MAX_RETRY 0x1000
void CPdd16550::PostInit()
{
DWORD dwCount=0;
m_HardwareLock.Lock();
UCHAR uData;
while (((uData =m_pReg16550->Read_IIR()) & SERIAL_IIR_INT_INVALID )==0 && dwCount <MAX_RETRY) { // Interrupt.
InitReceive(TRUE);
InitModem(TRUE);
InitLine(TRUE);
dwCount++;
}
ASSERT((uData & SERIAL_IIR_INT_INVALID) == SERIAL_IIR_INT_INVALID);
// IST Start to Run.
m_HardwareLock.Unlock();
CSerialPDD::PostInit();
CeSetPriority(m_dwPriority256);
#ifdef DEBUG
if ( ZONE_INIT )
m_pReg16550->DumpRegister();
#endif
ThreadStart(); // Start IST.
}
DWORD CPdd16550::ThreadRun()
{
while ( m_hISTEvent!=NULL && !IsTerminated()) {
if (WaitForSingleObject( m_hISTEvent,INFINITE)==WAIT_OBJECT_0) {
UCHAR bData;
while (!IsTerminated() &&
((bData = m_pReg16550->Read_IIR()) & SERIAL_IIR_INT_INVALID)==0) {
DEBUGMSG(ZONE_THREAD,
(TEXT("CPdd16550::ThreadRun IIR=%x\r\n"),bData));
DWORD interrupts=0;
switch ( bData & SERIAL_IIR_INT_MASK ) {
case SERIAL_IIR_RLS:
interrupts |= INTR_LINE;
break;
case SERIAL_IIR_CTI: case SERIAL_IIR_CTI_2: case SERIAL_IIR_RDA:
interrupts |= INTR_RX;
break;
case SERIAL_IIR_THRE:
interrupts |= INTR_TX;
break;
case SERIAL_IIR_MS :
interrupts |= INTR_MODEM;
break;
default:
ASSERT(FALSE);
}
NotifyPDDInterrupt((INTERRUPT_TYPE)interrupts);
}
InterruptDone(m_dwSysIntr);
}
else
ASSERT(FALSE);
}
return 1;
}
BOOL CPdd16550::InitialEnableInterrupt(BOOL bEnable )
{
m_HardwareLock.Lock();
CSerialPDD::InitialEnableInterrupt(bEnable );
if (bEnable)
m_pReg16550->Write_IER(IER_NORMAL_INTS);
else
m_pReg16550->Write_IER(SERIAL_IER_MS);
m_HardwareLock.Unlock();
return TRUE;
}
BOOL CPdd16550::InitXmit(BOOL bInit)
{
m_HardwareLock.Lock();
if (bInit) {
m_pReg16550->Write_FCR(m_pReg16550->Read_FCR() | SERIAL_FCR_TXMT_RESET | SERIAL_FCR_ENABLE);
m_XmitFifoEnable = TRUE;
}
m_HardwareLock.Unlock();
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -