📄 pddisr.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 "pddisr.h"
CPdd16550Isr::CPdd16550Isr(LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj)
: CPdd16550 (lpActivePath, pMdd, pHwObj)
{
m_pVirtualStaticAddr = NULL;
m_pIsrInfoVirt = NULL ;
m_pXmitBuffer = NULL;
m_pReceiveBuffer = NULL ;
m_hIsrHandler = NULL ;
}
CPdd16550Isr::~CPdd16550Isr()
{
if (m_hIsrHandler){
FreeIntChainHandler(m_hIsrHandler);
};
if (m_pIsrInfoVirt) {
FreePhysMem((PVOID)m_pIsrInfoVirt);
}
}
#define NUM_OF_SHARED_PAGE 1
BOOL CPdd16550Isr::Init()
{
// IST Setup .
DDKISRINFO ddi;
if (GetIsrInfo(&ddi)!=ERROR_SUCCESS) {
return FALSE;
}
if (CPdd16550::Init() &&
ddi.dwIrq<0xff && ddi.dwIrq!=0 && ddi.szIsrDll[0] != 0 && ddi.szIsrHandler[0] !=0) { // USE IISR according registry.
// Water Marker minimun can be 4 for ISR.
if (m_dwWaterMark<4)
m_dwWaterMark = 4;
// We create Shared Structure First.
DWORD dwBlockSize=NUM_OF_SHARED_PAGE*PAGE_SIZE;
PVOID pIsrAddress=NULL;
KLibAllocShareMem(NUM_OF_SHARED_PAGE,TRUE,(LPVOID *)&m_pIsrInfoVirt,&pIsrAddress);
DEBUGMSG (ZONE_INIT,(TEXT("SL_InstallSoftwareISR, VirtualAddr=0x%X Kernel Addr=0x%X\r\n"),m_pIsrInfoVirt ,pIsrAddress));
// Translate IO to static.
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;
}
PHYSICAL_ADDRESS ioPhysicalBase = { dwi.ioWindows[0].dwBase, 0};
ULONG inIoSpace = 1;
if (!TransBusAddrToStatic((INTERFACE_TYPE)dwi.dwInterfaceType, 0, ioPhysicalBase,dwi.ioWindows[0].dwLen , &inIoSpace,&m_pIoStaticAddr)) {
DEBUGMSG(ZONE_ERROR,(TEXT("CPdd16550Isr::Init!TransBusAddrToStatic(%x,%x) call failed.\r\n"),
dwi.ioWindows[0].dwBase,dwi.ioWindows[0].dwLen));
return FALSE;
}
// Intialize the Structure and then load IISR.
if (m_pIsrInfoVirt) {
DWORD dwRcvBlockSize;
DWORD dwXmitBlockSize;
m_pIsrInfoVirt->pBlockPhysAddr=pIsrAddress;
m_pIsrInfoVirt->dwBlockSize=dwBlockSize;
m_pIsrInfoVirt->dwReceiveHWWaterMaker=GetWaterMark();
m_pIsrInfoVirt->InBufferOffset=sizeof(ISR16550_INFO);
dwRcvBlockSize=dwBlockSize - sizeof(ISR16550_INFO);
dwRcvBlockSize = dwRcvBlockSize * 2 / 3; // Harf for xmitting harf for Receiving. receive buffer is double size of send
dwRcvBlockSize = (dwRcvBlockSize/sizeof(DWORD))*sizeof(DWORD); // Make DWORD alignment.
m_pIsrInfoVirt->OutBufferOffset=sizeof(ISR16550_INFO)+dwRcvBlockSize;
// Initial Receive
m_pReceiveBuffer=(PRcvDataBuffer)((PBYTE)m_pIsrInfoVirt+m_pIsrInfoVirt->InBufferOffset);
m_pReceiveBuffer->dwBufferSize=(dwRcvBlockSize-sizeof(RcvDataBuffer))/sizeof(IIR_EVENT);
m_pReceiveBuffer->dwWaterMark=m_pReceiveBuffer->dwBufferSize/2;
m_pReceiveBuffer->dwFIFO_In = m_pReceiveBuffer->dwFIFO_Out=0;
// Inital Xmit Buffer.
m_pXmitBuffer=(PXmitDataBuffer)((PBYTE)m_pIsrInfoVirt+m_pIsrInfoVirt->OutBufferOffset);
ASSERT(m_pIsrInfoVirt->OutBufferOffset+sizeof(XmitDataBuffer)<dwBlockSize);
dwXmitBlockSize =dwBlockSize- m_pIsrInfoVirt->OutBufferOffset;
m_pXmitBuffer->dwBufferSize=dwXmitBlockSize-sizeof(XmitDataBuffer);
m_pXmitBuffer->dwWaterMark=m_pXmitBuffer->dwBufferSize/2;
m_pXmitBuffer->dwFIFO_In= m_pXmitBuffer->dwFIFO_Out=0;
//Set Hardware Info.
m_pIsrInfoVirt->SysIntr=m_dwSysIntr;
m_pIsrInfoVirt->pIoAddress = (PBYTE)m_pIoStaticAddr;
m_pIsrInfoVirt->lIoSpace = inIoSpace;
m_pIsrInfoVirt->uMultiplier= m_dwRegStride;
//m_bMoreXmitData=FALSE;
m_pIsrInfoVirt->bIntrBypass=FALSE;
// Install The ISR.
DEBUGMSG (ZONE_INIT,(TEXT("SL_InstallSoftwareISR, SysIntr=0x%X,Irq=0x%X,ioAddr==0x%X \r\n"),
m_pIsrInfoVirt->SysIntr,ddi.dwIrq,m_pIsrInfoVirt->pIoAddress));
m_hIsrHandler = LoadIntChainHandler(ddi.szIsrDll, ddi.szIsrHandler, (BYTE)ddi.dwIrq);
if (m_hIsrHandler == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("SL_InstallSoftwareISR: LoadIntChainHandler(%s, %s, %d) failed\r\n"),
ddi.szIsrDll, ddi.szIsrHandler,ddi.dwIrq));
return FALSE;;
}
if (!KernelLibIoControl(m_hIsrHandler, IOCTL_ISR16550_INFO, pIsrAddress, dwBlockSize, NULL, 0, NULL)) {
DEBUGMSG(ZONE_ERROR,(TEXT("SL_InstallSoftwareISR: KernelLibIoControl call failed.\r\n")));
KernelLibIoControl(m_hIsrHandler, IOCTL_ISR16550_UNLOAD, (LPVOID)&m_pIsrInfoVirt, sizeof(ISR16550_INFO), NULL, 0, NULL);
return FALSE;
}
return TRUE;
}
else {
DEBUGMSG (ZONE_ERROR,(TEXT("SL_InstallSoftwareISR, Cano not alloc Phys Buffer size=0x%X - ERROR\r\n"),dwBlockSize ));
}
}
return FALSE;
}
inline BOOL CPdd16550Isr::PeekIIRData(PBYTE pbInt,PBYTE pbData)
{
ASSERT(m_pReceiveBuffer!=NULL);
if (GetRcvDataSize(m_pReceiveBuffer)>0) {
if (pbInt)
*pbInt=m_pReceiveBuffer->bBuffer[m_pReceiveBuffer->dwFIFO_Out].bIntFlag;
if (pbData)
*pbData=m_pReceiveBuffer->bBuffer[m_pReceiveBuffer->dwFIFO_Out].bIntData;
return TRUE;
}
else
return FALSE;
}
inline BOOL CPdd16550Isr::ReadIIRData(PBYTE pbInt,PBYTE pbData)
{
m_HardwareLock.Lock();
BOOL bReturn = PeekIIRData(pbInt,pbData);
if (bReturn)
m_pReceiveBuffer->dwFIFO_Out=IncRcvIndex(m_pReceiveBuffer,m_pReceiveBuffer->dwFIFO_Out);
m_HardwareLock.Unlock();
return bReturn;
}
inline BOOL CPdd16550Isr::WriteFIFOData(BYTE bData)
{
if ( GetXmitAvailableBuffer(m_pXmitBuffer)>2) {
m_pXmitBuffer->bBuffer[m_pXmitBuffer->dwFIFO_In]=bData;
m_pXmitBuffer->dwFIFO_In=IncXmitIndex(m_pXmitBuffer,m_pXmitBuffer->dwFIFO_In);
return TRUE;
}
else
return FALSE;
}
DWORD CPdd16550Isr::ThreadRun()
{
DEBUGMSG(ZONE_THREAD, (TEXT("CPdd16550isr::ThreadRun IST Started.\r\n")));
while ( m_hISTEvent!=NULL && !IsTerminated()) {
if (WaitForSingleObject( m_hISTEvent,INFINITE)==WAIT_OBJECT_0) {
UCHAR bInt,bData;
while (!IsTerminated() && PeekIIRData(&bInt,&bData)) {
DEBUGMSG(ZONE_THREAD,
(TEXT("CPdd16550isr::ThreadRun IIR=%x, bData=%x\r\n"),bInt,bData));
DWORD interrupts=0;
switch ( bInt & 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:
DEBUGMSG(ZONE_ERROR,(TEXT("CPdd16550isr::ThreadRun: Wrong Interrupt Event IIR=%x, bData=%x\r\n"),bInt,bData));
ReadIIRData(NULL,NULL);
ASSERT(FALSE);
}
NotifyPDDInterrupt((INTERRUPT_TYPE)interrupts);
}
InterruptDone(m_dwSysIntr);
}
else
ASSERT(FALSE);
}
return 1;
}
ULONG CPdd16550Isr::ReceiveInterruptHandler(PUCHAR pRxBuffer,ULONG *pBufflen)
{
DWORD dwBytesDropped = 0;
if (pRxBuffer && pBufflen ) {
DWORD dwBytesStored = 0 ;
DWORD dwRoomLeft = *pBufflen;
m_bReceivedCanceled = FALSE;
m_HardwareLock.Lock();
BYTE ubIIR;
BYTE ubData;
while (dwRoomLeft && !m_bReceivedCanceled) {
if (PeekIIRData(&ubIIR,NULL)) {
ubIIR &= SERIAL_IIR_INT_MASK;
if (ubIIR == SERIAL_IIR_CTI || ubIIR == SERIAL_IIR_CTI_2 || ubIIR ==SERIAL_IIR_RDA ) { // Receive Data.
BOOL bRead = ReadIIRData(NULL,&ubData);
ASSERT(bRead);
if (DataReplaced(&ubData,FALSE)) { // We lost Line status because ISR does not store them.
*pRxBuffer++ = ubData;
dwRoomLeft--;
dwBytesStored++;
}
}
else
break;
}
else
break;
}
if (m_bReceivedCanceled)
dwBytesStored = 0;
m_HardwareLock.Unlock();
*pBufflen = dwBytesStored;
}
else {
ASSERT(FALSE);
}
return dwBytesDropped;
}
ULONG CPdd16550Isr::CancelReceive()
{
m_HardwareLock.Lock();
// Cancel anything in software fifo.
InterruptMask(m_dwSysIntr,TRUE);
// We have to Mask interrupt because ISR also touching this variable.
m_pReceiveBuffer->dwFIFO_In = m_pReceiveBuffer->dwFIFO_Out; // Data Gone
InterruptMask(m_dwSysIntr,FALSE);
DWORD dwReturn = CPdd16550::CancelReceive();
m_HardwareLock.Unlock();
return dwReturn;
}
void CPdd16550Isr::XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen)
{
DEBUGCHK(pBuffLen!=NULL);
BYTE bInt;
m_HardwareLock.Lock();
while (PeekIIRData(&bInt,NULL) && (bInt&SERIAL_IIR_INT_MASK) == SERIAL_IIR_THRE ) { // Dump Xmit Empty Signal in Input Queue
ReadIIRData(NULL,NULL);
}
if (*pBuffLen == 0) {
if (GetXmitDataSize(m_pXmitBuffer)== 0 )
EnableXmitInterrupt(FALSE);
}
else {
DEBUGCHK(pTxBuffer);
PulseEvent(m_XmitFlushDone);
DWORD dwDataAvaiable = *pBuffLen;
*pBuffLen = 0;
if ((m_DCB.fOutxCtsFlow && IsCTSOff()) ||(m_DCB.fOutxDsrFlow && IsDSROff())) { // We are Follow off
DEBUGMSG(ZONE_THREAD|ZONE_WRITE,(TEXT("CPdd16550::XmitInterruptHandler! Flow Off, Data Discard.\r\n")));
EnableXmitInterrupt(FALSE);
}
else
if (dwDataAvaiable){
DWORD dwByteWrite=0;
while (dwDataAvaiable!=0 && WriteFIFOData(*pTxBuffer)) {
pTxBuffer ++;
dwDataAvaiable--;
dwByteWrite++;
}
EnableXmitInterrupt(TRUE);
*pBuffLen = dwByteWrite;
DEBUGMSG(ZONE_THREAD|ZONE_WRITE,(TEXT("CPdd16550::XmitInterruptHandler! Write %d byte to FIFO\r\n"),dwByteWrite));
}
}
m_HardwareLock.Unlock();
}
void CPdd16550Isr::XmitComChar(UCHAR ComChar)
{
// This function has to pull until the Data can be sent out.
BOOL bDone = FALSE;
do {
m_HardwareLock.Lock();
if ( WriteFIFOData(ComChar) ) { // If Empty.
bDone = TRUE;
}
else {
EnableXmitInterrupt(TRUE);
}
m_HardwareLock.Unlock();
if (!bDone)
WaitForSingleObject(m_XmitFlushDone, (ULONG)1000);
}
while (!bDone);
}
BOOL CPdd16550Isr::CancelXmit()
{
m_HardwareLock.Lock();
// Cancel anything in software fifo.
InterruptMask(m_dwSysIntr,TRUE);
// We have to Mask interrupt because ISR also touching this variable.
m_pXmitBuffer->dwFIFO_In = m_pXmitBuffer->dwFIFO_Out; // Data Gone
InterruptMask(m_dwSysIntr,FALSE);
DWORD dwReturn = CPdd16550::CancelXmit();
m_HardwareLock.Unlock();
return dwReturn;
}
//
//Line Function
void CPdd16550Isr::LineInterruptHandler()
{
BYTE bInt,bData;
DEBUGCHK(PeekIIRData(&bInt,NULL) && (bInt&SERIAL_IIR_INT_MASK) == SERIAL_IIR_RLS);
if (ReadIIRData(&bInt, &bData) && ((bInt&SERIAL_IIR_INT_MASK)== SERIAL_IIR_RLS)) {
ULONG ulError = 0;
if (bData & SERIAL_LSR_OE ) {
ulError |= CE_OVERRUN;
}
if (bData & SERIAL_LSR_PE) {
ulError |= CE_RXPARITY;
}
if (bData & SERIAL_LSR_FE) {
ulError |= CE_FRAME;
}
if (ulError)
SetReceiveError(ulError);
if (bData & SERIAL_LSR_BI) {
EventCallback(EV_BREAK);
}
}
}
//
//Modem Function
void CPdd16550Isr::ModemInterruptHandler()
{
BYTE bInt,ubModemStatus;
DEBUGCHK(PeekIIRData(&bInt,NULL) && (bInt & SERIAL_IIR_INT_MASK) == SERIAL_IIR_MS);
if (ReadIIRData(&bInt, &ubModemStatus) && ((bInt & SERIAL_IIR_INT_MASK)== SERIAL_IIR_MS)) {
// Event Notification.
ULONG Events = 0;
if (ubModemStatus & SERIAL_MSR_DCTS)
Events |= EV_CTS;
if ( ubModemStatus & SERIAL_MSR_DDSR )
Events |= EV_DSR;
if ( ubModemStatus & SERIAL_MSR_TERI )
Events |= EV_RING;
if ( ubModemStatus & SERIAL_MSR_DDCD )
Events |= EV_RLSD;
if (Events!=0)
EventCallback(Events, (ubModemStatus & SERIAL_MSR_DCD)!=0?MS_RLSD_ON:0);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -