📄 bvd_ser16550.c
字号:
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
DEBUGMSG (ZONE_FUNCTION,
(TEXT("-HW_XSC1_SetParity 0x%X\r\n"), pHead));
return(bRet);
}
//
// @doc OEM
// @func VOID | HW_XSC1_SetStopBits |
// This routine sets the Stop Bits for the device.
//
// @rdesc None.
//
BOOL
HW_XSC1_SetStopBits(
PVOID pHead, // @parm PVOID returned by HWInit
ULONG StopBits // @parm ULONG StopBits field from DCB.
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
ULONG lcr;
BOOL bRet;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("+HW_XSC1_SetStopBits 0x%X, x%X\r\n"), pHead, StopBits));
// DEBUGMSG (1, (TEXT("??????????????????+HW_XSC1_SetStopBits 0x%X, x%X\r\n"), pHead, StopBits));
bRet = TRUE;
EnterCriticalSection(&(pHWHead->RegCritSec));
lcr = INB(pHWHead, pLCR);
lcr &= ~SERIAL_STOP_MASK;
try {
HW_XSC1_DisableTxRx(pHead);
// Note that 1.5 stop bits only works if the word size
// is 5 bits. Any other xmit word size will cause the
// 1.5 stop bit setting to generate 2 stop bits.
switch ( StopBits )
{
case ONESTOPBIT :
lcr |= SERIAL_1_STOP ;
break;
case ONE5STOPBITS :
lcr |= SERIAL_1_5_STOP ;
break;
case TWOSTOPBITS :
lcr |= SERIAL_2_STOP ;
break;
default:
bRet = FALSE;
break;
}
if (bRet)
{
OUTB(pHWHead, pLCR, lcr);
}
HW_XSC1_EnableTxRx(pHead);
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
bRet = FALSE;
}
LeaveCriticalSection(&(pHWHead->RegCritSec));
DEBUGMSG (ZONE_FUNCTION,
(TEXT("-HW_XSC1_SetStopBits 0x%X\r\n"), pHead));
return(bRet);
}
//
// @doc OEM
// @func ULONG | HW_XSC1_GetRxBufferSize | This function returns
// the size of the hardware buffer passed to the interrupt
// initialize function. It would be used only for devices
// which share a buffer between the MDD/PDD and an IRDASEL.
//
//
// @rdesc This routine always returns 0 for 16550 UARTS.
//
ULONG
HW_XSC1_GetRxBufferSize(
PVOID pHead
)
{
return(0);
}
//
// @doc OEM
// @func PVOID | SC_GetRxStart | This routine returns the start of the hardware
// receive buffer. See HW_XSC1_GetRxBufferSize.
//
// @rdesc The return value is a pointer to the start of the device receive buffer.
//
PVOID
HW_XSC1_GetRxStart(
PVOID pHead // @parm PVOID returned by SC_init.
)
{
return(NULL);
}
//
// @doc OEM
// @func ULONG | HW_XSC1_GetInterruptType | This function is called
// by the MDD whenever an interrupt occurs. The return code
// is then checked by the MDD to determine which of the four
// interrupt handling routines are to be called.
//
// @rdesc This routine returns a bitmask indicating which interrupts
// are currently pending.
//
INTERRUPT_TYPE
HW_XSC1_GetInterruptType(
PVOID pHead // Pointer to hardware head
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
INTERRUPT_TYPE interrupts = INTR_NONE;
UINT blr = 0;
// DEBUGMSG (0,
// (TEXT("+HW_XSC1_GetInterruptType 0x%X\r\n"), pHead));
// DEBUGMSG (1, (TEXT("???????????????????+HW_XSC1_GetInterruptType 0x%X\r\n"), pHead));
try {
pHWHead->IIR = INB(pHWHead, pIIR_FCR);
if (pHWHead->IOBase == BTUART_BASE_U_VIRTUAL)
{
}
// DEBUGMSG (1, (TEXT("???????????????????+HW_XSC1_GetInterruptType: IIR %X\r\n"), pHWHead->IIR));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
pHWHead->IIR = SERIAL_IIR_NO_INTERRUPT_PENDING; // simulate no interrupt
}
if ( pHWHead->IIR & SERIAL_IIR_NO_INTERRUPT_PENDING ) {
// No interrupts pending, vector is useless
interrupts = INTR_NONE;
} else {
// The interrupt value is valid
switch ( pHWHead->IIR & 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:
interrupts = INTR_NONE;
break;
}
}
if (pHWHead->AddTXIntr) {
interrupts |= INTR_TX;
pHWHead->AddTXIntr = FALSE;
}
DEBUGMSG (ZONE_THREAD,
(TEXT("-HW_XSC1_GetInterruptType 0x%X, 0x%X\r\n"),
pHead, interrupts));
return(interrupts);
}
// @doc OEM
// @func ULONG | HW_XSC1_RxIntr | This routine gets several characters from the hardware
// receive buffer and puts them in a buffer provided via the second argument.
// It returns the number of bytes lost to overrun.
//
// @rdesc The return value indicates the number of overruns detected.
// The actual number of dropped characters may be higher.
//
ULONG
HW_XSC1_RxIntr(
PVOID pHead, // @parm Pointer to hardware head
PUCHAR pRxBuffer, // @parm Pointer to receive buffer
ULONG *pBufflen // @parm In = max bytes to read, out = bytes read
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
ULONG RetVal = 0;
ULONG TargetRoom = *pBufflen;
BOOL fRXFlag = FALSE;
BOOL fReplaceparityErrors = FALSE;
BOOL fNull;
UCHAR cEvtChar, cRXChar;
DEBUGMSG (0, (TEXT("+HW_XSC1_RxIntr - len %d.\r\n"),
*pBufflen));
// DEBUGMSG (1, (TEXT("??????????????+HW_XSC1_RxIntr - len %d.\r\n"), *pBufflen));
*pBufflen = 0;
// LAM - I have local copies of some DCB elements since I don't
// want to keep dereferencing inside my read loop and there are too
// many of them to trust the compiler.
cEvtChar = pHWHead->dcb.EvtChar;
fNull = pHWHead->dcb.fNull;
if ( pHWHead->dcb.fErrorChar && pHWHead->dcb.fParity )
fReplaceparityErrors = TRUE;
try {
while ( TargetRoom ) {
// See if there is another byte to be read
HW_XSC1_ReadLSR( pHWHead );
#ifdef UART_32_BIT_PERIPHERAL_BUS
//To do:
#else
if ( pHWHead->LSR & SERIAL_LSR_DR ) {
// Read the byte
cRXChar = (UCHAR) INB(pHWHead, pTHR_RBR_DLL);
DEBUGMSG (ZONE_READ | ZONE_THREAD,
(TEXT("HW_XSC1_RxIntrEx - Char Read %c\r\n"),
cRXChar));
// DEBUGMSG (ZONE_READ | ZONE_WARN, (TEXT("Rx: %c\r\n"),cRXChar));
// But we may want to discard it
if ( pHWHead->dcb.fDsrSensitivity &&
(! (pHWHead->MSR & SERIAL_MSR_DSR)) ) {
// Do nothing - byte gets discarded
DEBUGMSG (ZONE_FLOW,
(TEXT("Dropping byte because DSR is low\r\n")));
} else if (!cRXChar && fNull) {
// Do nothing - byte gets discarded
DEBUGMSG (ZONE_FLOW| ZONE_WARN,
(TEXT("Dropping NULL byte due to fNull\r\n")));
} else {
// Do character replacement if parity error detected.
if ( fReplaceparityErrors && (pHWHead->LSR & SERIAL_LSR_PE) ) {
cRXChar = pHWHead->dcb.ErrorChar;
} else {
// See if we need to generate an EV_RXFLAG for the received char.
if ( cRXChar == cEvtChar )
fRXFlag = TRUE;
}
// Finally, we can get byte, update status and save.
*pRxBuffer++ = cRXChar;
(*pBufflen)++;
--TargetRoom;
}
} else {
// We read all chars, so we're done
break;
}
#endif
}
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// just exit
}
// if we saw one (or more) EVT chars, then generate an event
if ( fRXFlag )
pHWHead->EventCallback( pHWHead->pMddHead, EV_RXFLAG );
if ( pHWHead->DroppedBytes )
DEBUGMSG (ZONE_WARN, (TEXT("Rx drop %d.\r\n"),
pHWHead->DroppedBytes));
// DEBUGMSG (1, (TEXT("-HW_XSC1_RxIntr - rx'ed %d, dropped %d.\r\n"),
// *pBufflen,
// pHWHead->DroppedBytes));
RetVal = pHWHead->DroppedBytes;
pHWHead->DroppedBytes = 0;
return(RetVal);
}
//
// @doc OEM
// @func ULONG | HW_XSC1_TXIntrEx | This routine is called from the new MDD
// whenever INTR_TX is returned by HW_XSC1_GetInterruptType
//
// @rdesc None
//
VOID
HW_XSC1_TxIntrEx(
PVOID pHead, // Hardware Head
PUCHAR pTxBuffer, // @parm Pointer to receive buffer
ULONG *pBufflen // @parm In = max bytes to transmit, out = bytes transmitted
)
{
PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
UCHAR byteCount;
ULONG NumberOfBytes = *pBufflen;
//ULONG ier;
DEBUGMSG (ZONE_THREAD, (TEXT("Transmit Event\r\n")));
DEBUGMSG (ZONE_WRITE,
(TEXT("+HW_XSC1_TxIntrEx 0x%X, Len %d\r\n"), pHead, *pBufflen));
// DEBUGMSG (1, (TEXT("?????????????????+HW_XSC1_TxIntrEx 0x%X, Len %d\r\n"), pHead, *pBufflen));
// We may be done sending. If so, just disable the TX interrupts
// and return to the MDD.
if( ! *pBufflen )
{
if (pHWHead->bIr)
{
//Enable rx and disable tx
HW_XSC1_Enable_IR_Rx_Tx(pHead, TRUE, FALSE);
}
DEBUGMSG (ZONE_WRITE, (TEXT("HW_XSC1_TxIntrEx: Disable INTR_TX.\r\n")));
//Reflect change in pHWHead->IER
pHWHead->IER = (IER_NORMAL_INTS|SERIAL_IER_UUE);
//Uart should be left enabled also
OUTB(pHWHead, pIER_DLH, (IER_NORMAL_INTS|SERIAL_IER_UUE));
/*
//#ifdef A1_Cotulla
if( (pHWHead->ProcessorStepping == COTULLA_A1_CP15_VAL) || (pHWHead->ProcessorStepping == SABINAL_A1_CP15_VAL) )
{
//A1 Cotulla: Read IIR right after disabling Tx interrupt.
pHWHead->IIR = INB(pHWHead, pIIR_FCR);
}
//#elif B0_Cotulla
//else if(pHWHead->ProcessorStepping == COTULLA_B0_CP15_VAL)
//{
//B0 Cotulla: No need to read IIR right after disabling Tx interrupt. Fixed in B0 Si.
//}
//#endif
*/
//DEBUGMSG (1, (TEXT("???????????????????-HW_XSC1_TxIntrEx: IER %X\r\n"), pHWHead->IER));
return;
}
*pBufflen = 0; // In case we don't send anything below.
// Disable xmit intr. Most 16550s will keep hammering
// us with xmit interrupts if we don't turn them off
// Whoever gets the FlushDone will then need to turn
// TX Ints back on if needed.
EnterCriticalSection(&(pHWHead->RegCritSec));
try {
// Need to signal FlushDone for XmitComChar
PulseEvent(pHWHead->FlushDone);
pHWHead->CommErrors &= ~CE_TXFULL;
// If CTS flow control is desired, check cts. If clear, don't send,
// but loop. When CTS comes back on, the OtherInt routine will
// detect this and re-enable TX interrupts (causing Flushdone).
// For finest granularity, we would check this in the loop below,
// but for speed, I check it here (up to 8 xmit characters before
// we actually flow off.
if ( pHWHead->dcb.fOutxCtsFlow ) {
//HW_XSC1_ReadMSR( pHWHead );
// We don't need to explicitly read the MSR, since we always enable
// IER_MS, which ensures that we will get an interrupt and read
// the MSR whenever CTS, DSR, TERI, or DCD change.
if (! (pHWHead->MSR & SERIAL_MSR_CTS) ) {
ULONG value;
DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
(TEXT("HW_XSC1_TxIntrEx, flowed off via CTS\n") ) );
pHWHead->CTSFlowOff = TRUE; // Record flowed off state
value = INB(pHWHead, pIER_DLH);
OUTB(pHWHea
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -