📄 xrser16550.c
字号:
////////////////////////////////////////
//(c) 2005 EXAR Corporation
//All Rights Reserved.
//
//Exar Corporation ("Exar") hereby grants the User of this Exar
//product-specific XR17C15x Windows CE.Net Device Driver (hereinafter
//referred to as "Driver") a non-exclusive, nontransferable license
//to use the Driver in accordance with the term set forth below.
//Before using the Driver, the User should read the following use
//restrictions. If the User does not accept these terms, the Driver
//should not be used or downloaded.
//The User is granted this limited license to use this Driver for
//User's end product that includes the Exar XR17C158/XR17D158 Octal UART PCI
//device, XR17C154/XR17D154 Quad UART PCI Device, and XR17C152/XR17D152 Dual UART
//PCI Device and is not granted rights to sell, loan, rent, lease or
//license the Driver, in whole or in part, or in modified form to anyone
//other than User. User may modify the Driver to suit its specific
//applications but rights to derivative works and such modifications
//shall belong to Exar.
//
//The Driver is provided on an "AS IS" basis and Exar makes absolutely
//no warranty with respect to performance or the information contained
//therein. EXAR DISCLAIMS AND USER WAIVES ALL WARRANTIES, EXPRESS OR
//IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
//PARTICULAR PURPOSE. The entire risk as to Driver quality and
//performance is with the User. ACCORDINGLY, IN NO EVENT SHALL EXAR
//BE LIABLE FOR ANY DAMAGES, WHETHER IN CONTRACT OR TORT, INCLUDING
//ANY LOST PROFITS OR OTHER INCIDENTAL, CONSEQUENTIAL, EXEMPLARY, OR
//PUNITIVE DAMAGES ARISING OUT OF THE USE OR APPLICATION OF THE DRIVER.
//Further, Exar reserves the right to make changes tot eh Driver without
//notice to improve reliability, function or design. Exar does not
//convey any license under patent rights or any other intellectual
//property rights, including those of third parties.
//
//Exar is not obligated to provide maintenance or support for the Driver.
//
//////////////////////////////////////////////////////////
/*++
Module Name: xrser16550.c
Abstract:
This file implements the standard device (PDD) specific functions for a 16550
based serial device.
Functions:
XRSL_Init()
XRSL_PostInit()
XRSL_Deinit()
XRSL_Open()
XRSL_Close()
XRSL_ClearDTR()
XRSL_SetDTR()
XRSL_ClearRTS()
XRSL_SetRTS()
XRSL_ClearBreak()
XRSL_SetBreak()
XRSL_SetBaudRate()
XRSL_SetByteSize()
XRSL_SetParity()
XRSL_SetStopBits()
XRSL_GetRxBufferSize()
XRSL_GetRxStart()
XRSL_GetInterruptType()
XRSL_RxIntr()
XRSL_PutBytes()
XRSL_TxIntr()
XRSL_LineIntr()
XRSL_OtherIntr()
XRSL_GetStatus()
XRSL_Reset()
XRSL_GetModemStatus()
XRSL_PurgeComm()
XRSL_XmitComChar()
XRSL_PowerOff()
XRSL_PowerOn()
XRSL_SetDCB()
XRSL_SetCommTimeouts()
XRSL_Ioctl()
ReadLSR()
ReadMSR()
DumpSerialRegisters()
LookUpValue()
DivisorOfRate()
Notes:
The RegCritSec is there to protect against non-atomic access of
register pairs. On a 16550, the main such collision comes from
the fact that THR and IER are overloaded as the DivLatch registers
and their mode is controlled via the LCR. So we need the
critical section protection around all access of these 3 registers.
But we also need to watch out for read/modify/write where we are
setting/ckearing a bit. In general, I just go ahead and acquire
the CS around all register accesses.
--*/
#include <windows.h>
#include <types.h>
#include <nkintr.h>
#include <ceddk.h>
#include <memory.h>
#include <devload.h>
#include <ddkreg.h>
#include <serhw.h>
#include "..\xrisr\xrisr.h"
#include "ser16550.h"
#include "hw16550.h"
#include <serdbg.h>
#include <excpt.h>
#include <pm.h>
#include "xrcom16550.h"
#include "xrser16550.h"
// Macros to read/write serial registers.
#define INB(pInfo, reg) (READ_REGISTER_UCHAR((pInfo)->reg))
#define OUTB(pInfo, reg, value) (WRITE_REGISTER_UCHAR(((pInfo)->reg), (unsigned char)(value)))
#define Read1Byte(pInfo,reg) (READ_REGISTER_UCHAR(pInfo + reg))
#define Write1Byte(pInfo,reg, value) (WRITE_REGISTER_UCHAR((pInfo+reg), (unsigned char)(value)))
BOOL XRSL_SetByteSize(PVOID pHead, ULONG ByteSize);
BOOL XRSL_SetStopBits(PVOID pHead, ULONG StopBits);
BOOL XRSL_SetParity(PVOID pHead, ULONG Parity);
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
//
// Reading the LSR clears most of its bits. So, we provide this wrapper,
// which reads the register, records any interesting values, and
// stores the current LSR contents in the shadow register.
//
__inline
VOID ProcessLSR (PSER16550_INFO pHWHead)
{
ULONG LineEvents = 0;
if ( pHWHead->LSR & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE)) {
// Note: Its not wise to do debug msgs in here since they will
// pretty much guarantee that the FIFO gets overrun.
if ( pHWHead->LSR & SERIAL_LSR_OE ) {
// DEBUGMSG (ZONE_WARN, (TEXT("Overrun\r\n")));
pHWHead->DroppedBytes++;
pHWHead->CommErrors |= CE_OVERRUN;
}
if ( pHWHead->LSR & SERIAL_LSR_PE ) {
// DEBUGMSG (ZONE_WARN, (TEXT("parity\r\n")));
pHWHead->CommErrors |= CE_RXPARITY;
}
if ( pHWHead->LSR & SERIAL_LSR_FE ) {
// DEBUGMSG (ZONE_WARN, (TEXT("frame\r\n")));
pHWHead->CommErrors |= CE_FRAME;
}
LineEvents |= EV_ERR;
}
if ( pHWHead->LSR & SERIAL_LSR_BI )
LineEvents |= EV_BREAK;
// Let WaitCommEvent know about this error
if ( LineEvents )
pHWHead->EventCallback( pHWHead->pMddHead, LineEvents );
}
__inline
VOID
ReadLSR(
PSER16550_INFO pHWHead
)
{
try {
pHWHead->LSR = INB(pHWHead, pLSR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
pHWHead->LSR = SERIAL_LSR_THRE;
}
ProcessLSR (pHWHead);
}
//
// Reading the MSR clears many of its bits. So, we provide this wrapper,
// which reads the register, records any interesting values, and
// stores the current MSR contents in the shadow register.
// Note that we always have DDCD and DCTS enabled, so if someone
// wants to keep an eye on these lines, its OK to simply read the
// shadow register, since if the value changes, the interrupt
// will cause the shadow to be updated.
//
__inline
VOID ProcessMSR (PSER16550_INFO pHWHead)
{
ULONG Events = 0;
// For changes, we use callback to evaluate the event
if (pHWHead->MSR & SERIAL_MSR_DCTS)
Events |= EV_CTS;
if ( pHWHead->MSR & SERIAL_MSR_DDSR )
Events |= EV_DSR;
if ( pHWHead->MSR & SERIAL_MSR_TERI )
Events |= EV_RING;
if ( pHWHead->MSR & SERIAL_MSR_DDCD )
Events |= EV_RLSD;
if ( Events )
pHWHead->EventCallback( pHWHead->pMddHead, Events );
}
__inline
VOID
ReadMSR(
PSER16550_INFO pHWHead
)
{
UCHAR msr;
try {
msr = INB(pHWHead, pMSR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
msr = 0;
}
// Save the MSR value in a shadow
pHWHead->MSR = msr;
ProcessMSR (pHWHead);
}
#ifdef DEBUG
//
// This routine is used only for debugging, and performs a formatted
// ascii dump of the various UART registers.
//
VOID
DumpSerialRegisters(
PVOID pHead
)
{
UINT8 byte;
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
try {
ReadLSR( pHWHead );
byte = pHWHead->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 = INB(pHWHead, pData);
NKDbgPrintfW(TEXT("16550 rbr/thr:\t%2.2X\r\n"), byte);
byte = INB(pHWHead, pIER);
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 = INB(pHWHead, pIIR_FCR);
NKDbgPrintfW(TEXT("16550 iir: \t%2.2X\t"), byte);
if ( byte & SERIAL_IIR_RDA )
NKDbgPrintfW(TEXT("RXData "));
if ( byte & SERIAL_IIR_THRE )
NKDbgPrintfW(TEXT("TXData "));
if ( byte & SERIAL_IIR_RLS )
NKDbgPrintfW(TEXT("RXErr "));
if ( (byte & SERIAL_IIR_CTI) == SERIAL_IIR_CTI )
NKDbgPrintfW(TEXT("CTI "));
if ( byte == SERIAL_IIR_MS )
NKDbgPrintfW(TEXT("ModemStatus "));
if ( byte & 0x01 )
NKDbgPrintfW(TEXT("IntPending "));
NKDbgPrintfW(TEXT("\r\n"));
byte = INB(pHWHead, pLCR);
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 = INB(pHWHead, pMCR);
NKDbgPrintfW(TEXT("16550 mcr: \t%2.2X\t"), byte);
if ( byte & SERIAL_MCR_DTR )
NKDbgPrintfW(TEXT("DTR "));
if ( byte & SERIAL_MCR_RTS )
NKDbgPrintfW(TEXT("RTS "));
if ( byte & SERIAL_MCR_OUT1 )
NKDbgPrintfW(TEXT("OUT1 "));
if ( byte & SERIAL_MCR_OUT2 )
NKDbgPrintfW(TEXT("OUT2 "));
if ( byte & SERIAL_MCR_LOOP )
NKDbgPrintfW(TEXT("LOOP "));
NKDbgPrintfW(TEXT("\r\n"));
ReadMSR( pHWHead );
byte = pHWHead->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"));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Nothing much to clean up here.
}
}
#endif // DEBUG
//
// Helper routine to search through a lookup table for a designated
// key.
//
ULONG
LookUpValue(
ULONG Key,
PLOOKUP_TBL pTbl,
PULONG pErrorCode
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -