📄 bvd_ser16550.c
字号:
/* Copyright ?1999 Intel Corp. */
/*++
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.
Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
Module Name:
bvd_ser16550.c
Abstract:
This file implements the standard device specific functions for a Cotulla's 16550
compatible UART based serial device.
Functions:
HW_XSC1_Init()
HW_XSC1_PostInit()
HW_XSC1_Deinit()
HW_XSC1_Open()
HW_XSC1_Close()
HW_XSC1_ClearDTR()
HW_XSC1_SetDTR()
HW_XSC1_ClearRTS()
HW_XSC1_SetRTS()
HW_XSC1_ClearBreak()
HW_XSC1_SetBreak()
HW_XSC1_SetBaudRate()
HW_XSC1_SetByteSize()
HW_XSC1_SetParity()
HW_XSC1_SetStopBits()
HW_XSC1_GetRxBufferSize()
HW_XSC1_GetRxStart()
HW_XSC1_GetInterruptType()
HW_XSC1_RxIntr()
HW_XSC1_TxIntrEx()
HW_XSC1_LineIntr()
HW_XSC1_ModemIntr()
HW_XSC1_GetStatus()
HW_XSC1_Reset()
HW_XSC1_GetModemStatus()
HW_XSC1_PurgeComm()
HW_XSC1_XmitComChar()
HW_XSC1_PowerOff()
HW_XSC1_PowerOn()
HW_XSC1_SetDCB()
HW_XSC1_SetCommTimeouts()
HW_XSC1_Ioctl()
HW_XSC1_ReadLSR()
HW_XSC1_ReadMSR()
HW_XSC1_DumpSerialRegisters()
HW_XSC1_LookUpValue()
HW_XSC1_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 <ceddk.h>
#include <memory.h>
#include <notify.h>
#include <serhw.h>
#include "bvd1.h"
#include "xllp_gpio.h"
#include "bvd_ser16550.h"
#include "bvd_hw16550.h"
#include "bvd_serbaud.h"
#include "xllp_defs.h"
#include "xllp_serialization.h"
#include "xllp_clkmgr.h"
#include <serdbg.h>
#include <excpt.h>
/*
#if defined(WAVECOM_DRIVER) || defined(OEM1_DRIVER)
//From gsmradio.h
//Needed for WAVECOM module
//Currently, these two IOCTLs are not supported by the serial driver
#define FILE_DEVICE_GSMRADIO 0x200
#define IOCTL_SPKR_ENABLE CTL_CODE(FILE_DEVICE_GSMRADIO, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_SPKR_DISABLE CTL_CODE(FILE_DEVICE_GSMRADIO, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
#else
#define IOCTL_SPKR_ENABLE 0
#define IOCTL_SPKR_DISABLE 0
#endif
*/
//extern XLLP_UINT32_T XllpLock(XLLP_PROTECTED_REGISTER Xllp_RegisterID);
//extern void XllpUnlock(XLLP_UINT32_T Xllp_LockID);
extern void usWait(unsigned usVal);
// Macros to read/write serial registers
// Modified macros for ULONGs instead of UCHARs
// In Cotulla's 16550 UART, we always do 32 bit reads/writes,
// even though the actual data is in the least significant byte only.
#define INB(pInfo, reg) ( (*((pInfo)->reg)) & 0xff)
#define OUTB(pInfo, reg, value) ( *((pInfo)->reg) = ((value) & 0xff) )
BOOL IsAPIReady(DWORD hAPI);
BOOL HW_XSC1_SetByteSize(PVOID pHead, ULONG ByteSize);
BOOL HW_XSC1_SetStopBits(PVOID pHead, ULONG StopBits);
BOOL HW_XSC1_SetParity(PVOID pHead, ULONG Parity);
VOID HW_XSC1_DisableTxRx(PVOID pHead);
VOID HW_XSC1_EnableTxRx(PVOID pHead);
void HW_XSC1_Enable_IR_Rx_Tx(PVOID pHead,BOOL Rxenable, BOOL Txenable);
BOOL StartClock(unsigned int,BOOL);
BOOL StopClock(unsigned int,BOOL);
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
//#define UART_32_BIT_PERIPHERAL_BUS 1
//#define INITIAL_MSR_STATE (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_DCD)
//Stubs for now
//To do:
__inline XLLP_UINT32_T XllpLock(XLLP_PROTECTED_REGISTER Xllp_RegisterID)
{
return 0;
}
__inline void XllpUnlock(XLLP_UINT32_T Xllp_LockID)
{
}
//
// 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
HW_XSC1_ReadLSR(
PSER16550_INFO pHWHead
)
{
ULONG LineEvents = 0;
UCHAR cRXChar ;
unsigned int count = 0;
DEBUGMSG (ZONE_FUNCTION,(TEXT("+HW_XSC1_ReadLSR\r\n")));
// DEBUGMSG (1,(TEXT("**************HW_XSC1_ReadLSR\r\n")));
try {
pHWHead->LSR = INB(pHWHead, pLSR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
pHWHead->LSR = SERIAL_LSR_TDRQ;
}
//FIFOE bit set (SERIAL_LSR_FIFOERR)
while (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")));
// DEBUGMSG (1, (TEXT("**************Overrun\r\n")));
pHWHead->DroppedBytes++;
pHWHead->CommErrors |= CE_OVERRUN;
}
if ( pHWHead->LSR & SERIAL_LSR_PE ) {
DEBUGMSG (ZONE_WARN, (TEXT("***parity\r\n")));
// DEBUGMSG (1, (TEXT("**************Parity\r\n")));
pHWHead->CommErrors |= CE_RXPARITY;
}
if ( pHWHead->LSR & SERIAL_LSR_FE ) {
DEBUGMSG (ZONE_WARN, (TEXT("***frame\r\n")));
// DEBUGMSG (1, (TEXT("**************Frame\r\n")));
pHWHead->CommErrors |= CE_FRAME;
}
LineEvents |= EV_ERR;
// Read chars out of FIFO until no FIFOE
cRXChar = (UCHAR) INB(pHWHead, pTHR_RBR_DLL);
//DEBUGMSG(1,(TEXT("********** Throwing out FIFOE data(0x%x char:%c) count:%d\r\n"),cRXChar, cRXChar, ++count));
DEBUGMSG(ZONE_WARN,(TEXT("***FIFOE 0x%X 0d%d \r\n"),cRXChar, cRXChar));
try
{
pHWHead->LSR = INB(pHWHead, pLSR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
pHWHead->LSR = SERIAL_LSR_TDRQ;
}
}
if ( pHWHead->LSR & SERIAL_LSR_BI ) {
// DEBUGMSG (1, (TEXT("**************Break\r\n")));
DEBUGMSG (ZONE_WARN, (TEXT("***Break\r\n")));
LineEvents |= EV_BREAK;
}
// Let WaitCommEvent know about this error
if ( LineEvents )
pHWHead->EventCallback( pHWHead->pMddHead, LineEvents );
}
//
// 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
HW_XSC1_ReadMSR(
PSER16550_INFO pHWHead
)
{
ULONG Events = 0;
ULONG msr;
UINT blr = 0;
DEBUGMSG (ZONE_FUNCTION,(TEXT("+HW_XSC1_ReadMSR\r\n")));
// DEBUGMSG (1,(TEXT("**************HW_XSC1_ReadMSR\r\n")));
try {
msr = INB(pHWHead, pMSR);
if (pHWHead->IOBase == BTUART_BASE_U_VIRTUAL)
{
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
msr = 0;
}
// Save the MSR value in a shadow
pHWHead->MSR = msr;
// For changes, we use callback to evaluate the event
if (msr & SERIAL_MSR_DCTS)
Events |= EV_CTS;
if (pHWHead->IOBase == FFUART_BASE_U_VIRTUAL)
{
if ( msr & SERIAL_MSR_DDSR )
Events |= EV_DSR;
if ( msr & SERIAL_MSR_TERI )
Events |= EV_RING;
if ( msr & SERIAL_MSR_DDCD )
Events |= EV_RLSD;
}
if ( Events )
pHWHead->EventCallback( pHWHead->pMddHead, Events );
//#ifdef USE_MERLIN
// If RLSD transitioned to active, we need to generate event.
//DEBUGMSG(ZONE_EVENTS,(TEXT("************ HW_XSC1_ReadMSR EV_RLSD\r\n")));
if ((pHWHead->OpenCount==0) && (msr & SERIAL_MSR_DDCD) && (msr & SERIAL_MSR_DCD))
{
//Putting this wait as a workaround to detect whether its a valid DCD event and
//the target is still connected to the host and not the cable has been removed.
usWait(500);
msr = INB(pHWHead, pMSR);
if (pHWHead->IOBase == BTUART_BASE_U_VIRTUAL)
{
}
if (msr & SERIAL_MSR_DCD)
{
// If RLSD transitioned to active, we need to generate event.
if (IsAPIReady(SH_WMGR))
{
CeEventHasOccurred(NOTIFICATION_EVENT_RS232_DETECTED,NULL);
DEBUGMSG(1|ZONE_EVENTS,(TEXT("****** HW_XSC1_ReadMSR NOTIFICATION_EVENT_RS232_DETECTED\r\n")));
//NKDbgPrintfW(TEXT("HW_XSC1_ReadMSR msr:%X MSR:%X MCR:%X\r\n"), msr, pHWHead->MSR, pHWHead->MCR);
}
}
}
//#endif
/*
#ifdef USE_TALISKER
// If RLSD transitioned to active, we need to generate event.
//DEBUGMSG(ZONE_EVENTS,(TEXT("************ HW_XSC1_ReadMSR EV_RLSD\r\n")));
if ((pHWHead->OpenCount==0) && (msr & SERIAL_MSR_DDSR))
{
// If RLSD transitioned to active, we need to generate event.
if (IsAPIReady(SH_WMGR))
{
CeEventHasOccurred(NOTIFICATION_EVENT_RS232_DETECTED,NULL);
DEBUGMSG(1|ZONE_EVENTS,(TEXT("****** HW_XSC1_ReadMSR NOTIFICATION_EVENT_RS232_DETECTED\r\n")));
}
}
#endif
*/
DEBUGMSG (ZONE_FUNCTION,(TEXT("-HW_XSC1_ReadMSR\r\n")));
}
#ifdef DEBUG
//
// This routine is used only for debugging, and performs a formatted
// ascii dump of the various UART registers.
//
VOID
HW_XSC1_DumpSerialRegisters(
PVOID pHead
)
{
ULONG value;
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
try {
HW_XSC1_ReadLSR( pHWHead );
value = pHWHead->LSR;
NKDbgPrintfW(TEXT("Cotulla 16550 lsr: \t%2.2X\t"), value);
if ( value & SERIAL_LSR_DR )
NKDbgPrintfW(TEXT("DataReady "));
if ( value & SERIAL_LSR_OE )
NKDbgPrintfW(TEXT("OverRun "));
if ( value & SERIAL_LSR_PE )
NKDbgPrintfW(TEXT("ParityErr "));
if ( value & SERIAL_LSR_FE )
NKDbgPrintfW(TEXT("FramingErr "));
if ( value & SERIAL_LSR_BI )
NKDbgPrintfW(TEXT("BreakIntpt "));
if ( value & SERIAL_LSR_TDRQ )
NKDbgPrintfW(TEXT("THREmpty "));
if ( value & SERIAL_LSR_TEMT )
NKDbgPrintfW(TEXT("TXEmpty "));
if ( value & SERIAL_LSR_FIFOERR )
NKDbgPrintfW(TEXT("FIFOErr "));
NKDbgPrintfW(TEXT("\r\n"));
value = INB(pHWHead, pTHR_RBR_DLL);
NKDbgPrintfW(TEXT("Cotulla 16550 rbr/thr:\t%2.2X\r\n"), value);
value = INB(pHWHead, pIER_DLH);
NKDbgPrintfW(TEXT("Cotulla 16550 IER: \t%2.2X\t"), value);
if ( value & SERIAL_IER_RAVIE )
NKDbgPrintfW(TEXT("RXData "));
if ( value & SERIAL_IER_TIE )
NKDbgPrintfW(TEXT("TXData "));
if ( value & SERIAL_IER_RLSE )
NKDbgPrintfW(TEXT("RXErr "));
if ( value & SERIAL_IER_MIE )
NKDbgPrintfW(TEXT("ModemStatus "));
if ( value & SERIAL_IER_RTOIE )
NKDbgPrintfW(TEXT("RxTimeOut "));
if ( value & SERIAL_IER_NRZE )
NKDbgPrintfW(TEXT("NRZEncoding "));
if ( value & SERIAL_IER_UUE )
NKDbgPrintfW(TEXT("UartEnabled "));
if ( value & SERIAL_IER_DMAE )
NKDbgPrintfW(TEXT("DMAEnabled "));
NKDbgPrintfW(TEXT("\r\n"));
value = INB(pHWHead, pIIR_FCR);
NKDbgPrintfW(TEXT("Cotulla 16550 iir: \t%2.2X\t"), value);
if ( value & SERIAL_IIR_RDA )
NKDbgPrintfW(TEXT("RXData "));
if ( value & SERIAL_IIR_THRE )
NKDbgPrintfW(TEXT("TXData "));
if ( value & SERIAL_IIR_RLS )
NKDbgPrintfW(TEXT("RXErr "));
if ( (value & SERIAL_IIR_CTI) == SERIAL_IIR_CTI )
NKDbgPrintfW(TEXT("CTI "));
if ( value & SERIAL_IIR_MS )
NKDbgPrintfW(TEXT("ModemStatus "));
if (!( value | SERIAL_IIR_INTERRUPT_PENDING ))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -