?? ccir.c
字號:
/*
Copyright(c) 1998,1999 SIC/Hitachi,Ltd.
Module Name:
ccir.c
Revision History:
26th April 1999 Released
*/
#include <windows.h>
#include <types.h>
#include <memory.h>
#include <serhw.h>
#include <hw16550.h>
#include <serdbg.h>
#include <excpt.h>
#include "ccir.h"
#include "cc.h"
#include "macros.h"
//#include "shx.h"
//#include "mobytel.h"
#ifdef TARGET_NT
#include <devemul.h>
#include <ser_emul.h>
#define try __try
#define except __except
#endif
#define INB(pInfo, reg) (READ_REGISTER_USHORT((pInfo)->reg) & 0x00FF)
#define OUTB(pInfo, reg, value) (WRITE_REGISTER_USHORT(((pInfo)->reg), (value) & 0x00FF))
BOOL CCIR_SetByteSize(PVOID pHead, ULONG ByteSize);
BOOL CCIR_SetStopBits(PVOID pHead, ULONG StopBits);
BOOL CCIR_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
ReadLSR(
PSER16550_INFO pHWHead
)
{
ULONG LineEvents = 0;
try
{
pHWHead->LSR = INB(pHWHead, pLSR);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
pHWHead->LSR = SERIAL_LSR_THRE;
}
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 )
{
//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
ReadMSR(
PSER16550_INFO pHWHead
)
{
ULONG Events = 0;
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;
// For changes, we use callback to evaluate the event
if (msr & SERIAL_MSR_DCTS)
Events |= EV_CTS;
if( msr & SERIAL_MSR_DDSR )
Events |= EV_DSR;
if ( msr & SERIAL_MSR_RI )
Events |= EV_RING;
if ( msr & SERIAL_MSR_DDCD )
Events |= EV_RLSD;
if( Events )
pHWHead->EventCallback( pHWHead->pMddHead, Events );
}
#ifdef DEBUG
//
// This routine is used only for debugging, and performs a formatted
// ascii dump of the various UART registers.
//
VOID
CCIR_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, 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, 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
CCIR_LookUpValue(
ULONG Key,
PLOOKUP_TBL pTbl,
PULONG pErrorCode
)
{
ULONG index = 0;
*pErrorCode = 0;
while ( index < pTbl->Size )
{
if ( Key == pTbl->Table[index].Key )
return pTbl->Table[index].AssociatedValue;
++index;
}
*pErrorCode = (ULONG)-1;
return 0;
}
#define BAUD_TABLE_SIZE 23
static const
PAIRS LS_BaudPairs[BAUD_TABLE_SIZE] = {
{50, 2307},
{75, 1538},
{110, 1049},
{135, 858},
{150, 769},
{300, 384},
{600, 192},
{1200, 96},
{1800, 64},
{2000, 58},
{2400, 48},
{3600, 32},
{4800, 24},
{7200, 16},
{9600, 12},
{12800, 9},
{14400, 8},
{19200, 6},
{23040, 5},
{28800, 4},
{38400, 3},
{57600, 2},
{115200, 1}
};
static const
LOOKUP_TBL LS_BaudTable = {BAUD_TABLE_SIZE, (PAIRS *) LS_BaudPairs};
//
// Helper function. Pass in a baudrate, and the corresponding divisor
// (from the baudtable) is returned. If no matching baudrate is found
// in baudtable, then return 0.
//
USHORT
CCIR_DivisorOfRate(
PVOID pHead, // @parm PVOID returned by HWinit.
ULONG BaudRate // @parm ULONG representing decimal baud rate.
)
{
ULONG errorcode = 0;
USHORT divisor;
divisor = (USHORT)CCIR_LookUpValue(BaudRate,
((PSER16550_INFO) pHead)->pBaudTable, &errorcode);
if ( errorcode )
divisor = 0;
return divisor;
}
//
// This is a reverse lookup table which can be used to determine
// the FIFO trigger level from the 2 bit value stored in the FCR
//
#define HIGH_WATER_SIZE 4
static const
PAIRS HighWaterPairs[HIGH_WATER_SIZE] = {
{SERIAL_1_BYTE_HIGH_WATER, 0},
{SERIAL_4_BYTE_HIGH_WATER, 4},
{SERIAL_8_BYTE_HIGH_WATER, 8},
{SERIAL_14_BYTE_HIGH_WATER, 14}
};
static const
LOOKUP_TBL HighWaterTable = {HIGH_WATER_SIZE, (PAIRS *) HighWaterPairs};
#define IER_NORMAL_INTS (SERIAL_IER_RDA | SERIAL_IER_RLS | SERIAL_IER_MS)
//
/////////////////// Start of exported entrypoints ////////////////
//
//
// @doc OEM
// @func PVOID | CCIR_Open | Configures 16550 for default behaviour.
//
VOID
CCIR_Open(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
DEBUGMSG (ZONE_OPEN,
(TEXT("+CCIR_Open 0x%X\r\n"), pHead));
// If the device is already open, all we do is increment count
if( pHWHead->OpenCount++ )
{
DEBUGMSG (ZONE_OPEN,
(TEXT("-CCIR_Open 0x%X (%d opens)\r\n"),
pHead, pHWHead->OpenCount));
return ;
}
pHWHead->FCR = 0;
pHWHead->IER = 0;
pHWHead->IIR = 0;
pHWHead->LSR = 0;
pHWHead->MSR = 0;
pHWHead->DroppedBytes = 0;
pHWHead->CTSFlowOff = FALSE; // Not flowed off yet
pHWHead->DSRFlowOff = FALSE; // Not flowed off yet
pHWHead->CommErrors = 0;
pHWHead->ModemStatus = 0;
try
{
#ifdef NOTDEF
// Enable all interrupts, then disable THR. Note IRQ enable in MCR.
// Enable THR in PutBytes.
*pHWHead->pIER = (UCHAR)(SERIAL_IER_RDA | SERIAL_IER_THR |
SERIAL_IER_RLS | SERIAL_IER_MS);
*pHWHead->pIER &= ~SERIAL_IER_THR;
#else
OUTB(pHWHead, pIER, (UCHAR)IER_NORMAL_INTS|SERIAL_IER_THR);
OUTB(pHWHead, pIER, (UCHAR)IER_NORMAL_INTS);
#endif
OUTB(pHWHead, pMCR, SERIAL_MCR_IRQ_ENABLE);
// Set default framing bits.
OUTB(pHWHead, pLCR, SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY);
DEBUGMSG (ZONE_OPEN,
(TEXT("CCIR_Open Setting DCB parameters\r\n")));
// Get defaults from the DCB structure
CCIR_SetBaudRate( pHead, pHWHead->dcb.BaudRate );
CCIR_SetByteSize( pHead, pHWHead->dcb.ByteSize );
CCIR_SetStopBits( pHead, pHWHead->dcb.StopBits );
CCIR_SetParity( pHead, pHWHead->dcb.Parity );
//
// A 16450 (which is pretty much a FIFO-less 16550) can be supported by
// not initializing the FIFO.
//
if (pHWHead->ChipID == CHIP_ID_16550) {
// Set up to use 16550 fifo for 14 byte interrupt granularity.
// Shadow the FCR bitmask since reading this location is the IIR.
// NOTE: to minimize overruns, trigger RX INT on 1 byte in FIFO
pHWHead->FCR = SERIAL_FCR_ENABLE | SERIAL_1_BYTE_HIGH_WATER |
SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET;
OUTB(pHWHead, pIIR_FCR, pHWHead->FCR);
pHWHead->IIR = INB(pHWHead, pIIR_FCR); // Update IIR shadow
}
#ifdef DEBUG
if( ZONE_INIT )
CCIR_DumpSerialRegisters(pHWHead);
#endif
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Just get out of here.
}
DEBUGMSG (ZONE_OPEN,
(TEXT("-CCIR_Open 0x%X\r\n"), pHead));
}
//
// @doc OEM
// @func PVOID | CCIR_Close | Does nothing except keep track of the
// open count so that other routines know what to do.
//
VOID
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -