📄 serio.c
字号:
if( pHWHead->dcb.fDsrSensitivity && (!(pHWHead->MSR & SERIAL_MSR_DSR)) ){
// Do nothing - byte gets discarded.
DEBUGMSG(ZONE_FUNCTION, (TEXT("GetByte DSR Sensitivity!!\r\n")));
}
else {
// Get byte, update status and save.
++pTargetBuffer;
(*pByteNumber)++;
--TargetRoom;
}
}
else {
// We read all chars, so we're done
DEBUGMSG(ZONE_FUNCTION, (TEXT("GetByte DSR OFF!!\r\n")));
break;
}
}
RetVal = pHWHead->DroppedBytes;
pHWHead->DroppedBytes = 0;
LeaveCriticalSection(&(pHWHead->CS));
return RetVal;
}
// *********************************************************************
//
// @doc OEM
//
// @func PVOID | HWGetRxStart |
// This routine returns the start of the hardware receive buffer.
// Required by NK Interrupt support.
//
// @parm PVOID | pHead | PDD device context (returned from HWInit())
//
// @rdesc The return value is a pointer to the start of the device
// receive buffer.
//
// @remark This parameter is passed to the InterruptInitialize() call
// in the HAL. It was intended for the ISR to handle receive
// characters in a fast path but is currently unused.
//**********************************************************************
PVOID
HWGetRxStart(PVOID pHead)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("Serial PDD: Enter HWGetRxStart\r\n")));
return NULL;
}
// ***************************************************************************
//
// @doc OEM
//
// @func INTERRUPT_TYPE | HWGetIntrType | Returns the current interrupt type.
//
// @parm PVOID | pHead | PDD device context (returned from HWInit())
//
// @rdesc The interrupt type.
//
// @remark This is called by the MDD to determine what type of interrupt
// occured.
//*****************************************************************************
INTERRUPT_TYPE
HWGetIntrType( PVOID pHead )
{
PPERP_IO_SER_INFO pHWHead = (PPERP_IO_SER_INFO)pHead;
INTERRUPT_TYPE interrupts = INTR_NONE;
ULONG win32status = 0;
USHORT CMUClkMsk; // @BUGBUG
USHORT aaa;
DEBUGMSG(ZONE_FUNCTION, (TEXT("Serial PDD: Enter HWGetIntrType\r\n")));
CMUClkMsk = REG16(VRCmuRegs.cmuclkmsk);
InterlockedAndOr16(pVRIO+CMUCLKMSK, 0xFFFF, MSKSIU | MSKSSIU);
EnterCriticalSection(&(pHWHead->CS));
pHWHead->IIR = REG8(ASICSiuRegs.siuiid_fc);
DEBUGMSG(ZONE_FUNCTION, (TEXT("Intr = 0x%x\r\n"), pHWHead->IIR));
if( pHWHead->IIR & SERIAL_IIR_INT_INVALID ){
HWReadLSR(pHWHead);
if( pHWHead->LSR & SERIAL_LSR_DR ){
interrupts = INTR_RX;
}
else {
// 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 :
pHWHead->MSR = REG8(ASICSiuRegs.siums);
interrupts = INTR_MODEM;
break;
default:
HWReadLSR( pHWHead );
if( pHWHead->LSR & SERIAL_LSR_DR ){
interrupts = INTR_RX;
}
else {
interrupts = INTR_NONE;
}
break;
}
}
if (REG16(VRGiuRegs.giuintstat) & DCDINTR) {
READ_VALUE16(aaa, VRGiuRegs.giuintalsell);
aaa ^= DCDINTR;
WRITE_VALUE16(VRGiuRegs.giuintalsell, aaa);
REG16(VRGiuRegs.giuintstat) = DCDINTR;
pHWHead->DCDWakeUp = TRUE;
interrupts = INTR_MODEM;
}
if (pHWHead->AddTXIntr){
interrupts |= INTR_TX;
pHWHead->AddTXIntr = FALSE;
}
// Check for power status.
if (pHWHead->fPowerOff == 1) {
pHWHead->fPowerOff = 0;
win32status |= EV_POWER;
EvaluateEventFlag(pHWHead->pMddHead, win32status);
}
// if (!(CMUClkMsk & (MSKSIU | MSKSSIU))) {
if (!(CMUClkMsk & MSKSSIU)) {
// DISABLE_BITS16(VRCmuRegs.cmuclkmsk, MSKSIU | MSKSSIU);
DISABLE_BITS16(VRCmuRegs.cmuclkmsk, MSKSSIU);
}
LeaveCriticalSection(&(pHWHead->CS));
DEBUGMSG(ZONE_FUNCTION, (TEXT("Interrupt = 0x%x\r\n"), interrupts));
return interrupts;
}
// **********************************************************************
//
// @doc OEM
//
// @func VOID | HWClearOtherIntr |
// This routine clears the status bits assoicated with a
// modem status interrupt. On standard UARTS, the MODEM interrupt
// covers events DCTS, DDSR, RI and DDCD. The PeRP hardware
// only supports DDSR and DCTS. DDCD and RI are handled by a
// check in getIntrType.
//
// @rdesc None.
//**********************************************************************
VOID
HWClearOtherIntr(
PVOID pHead /*@parm PVOID returned by HWInit */
)
{
PPERP_IO_SER_INFO pHWHead = (PPERP_IO_SER_INFO)pHead;
DEBUGMSG(ZONE_FUNCTION, (TEXT("Serial PDD: Enter HWClearOtherIntr\r\n")));
HWReadMSR( pHWHead );
// If we are currently flowed off via CTS or DSR, then
// we better signal the TX thread when one of them changes
// so that TX can resume sending.
if ( pHWHead->DSRFlowOff && (pHWHead->MSR & SERIAL_MSR_DSR) ){
pHWHead->DSRFlowOff = FALSE;
// DSR is set, so go ahead and resume sending
ENABLE_BITS8(ASICSiuRegs.siuie, SERIAL_IER_RDA | SERIAL_IER_RLS
| SERIAL_IER_MS | SERIAL_IER_THR);
// Then simulate a TX intr to get things moving
pHWHead->AddTXIntr = TRUE;
DEBUGMSG(ZONE_FUNCTION, (TEXT("AddTXIntr = TRUE for DSRFlow\r\n")));
}
if ( pHWHead->CTSFlowOff && (pHWHead->MSR & SERIAL_MSR_CTS) ){
pHWHead->CTSFlowOff = FALSE;
// CTS is set, so go ahead and resume sending
ENABLE_BITS8(ASICSiuRegs.siuie, SERIAL_IER_RDA | SERIAL_IER_RLS
| SERIAL_IER_MS | SERIAL_IER_THR);
// Then simulate a TX intr to get things moving
DEBUGMSG(ZONE_FUNCTION, (TEXT("AddTXIntr = TRUE for CTSFlow\r\n")));
pHWHead->AddTXIntr = TRUE;
}
}
// ****************************************************************
//
// @doc OEM
//
// @func VOID | HWClearLineIntr |
// This routine clears the status bits for line events
// (parity, break, framing, overrun). This applies to most
// standard UARTS, but since the PeRP hardware doesn't
// have a corresponding interrupt, we do nothing here.
//
// @rdesc None.
//******************************************************************
VOID
HWClearLineIntr(
PVOID pHead /*@parm PVOID returned by HWInit */
)
{
PPERP_IO_SER_INFO pHWHead = (PPERP_IO_SER_INFO)pHead;
DEBUGMSG(ZONE_FUNCTION, (TEXT("Serial PDD: Enter HWClearLineIntr\r\n")));
HWReadLSR( pHWHead );
}
// ****************************************************************************
//
// @doc OEM
//
// @func ULONG | HWGetRxBufferSize |
// This routine returns the maximal number of bytes the hardware
// buffer can hold, not counting the padding, stop, start bits, etc.
//
// @rdesc Returns the number of bytes in the hardware receive queue.
//*****************************************************************************
ULONG
HWGetRxBufferSize(
PVOID pHead /*@parm PVOID returned by HWInit */
)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("Serial PDD: Enter HWGetRxBufferSize\r\n")));
return 0;
}
// ************************************************************************
//
// @doc OEM
//
// @func VOID | HWTxIntrHandler | This routine handles the tx interrupt.
//
// @parm PVOID | pHead | PDD device context (returned from HWInit())
//
// @rdesc This routine cleas the transmit status bit in the hardware CSR
// and performs some internal bookkeeping so that HWPutBytes will
// send data. It is called when the driver detects a transmit
// interrupt as set by HWGetIntrType.
//**************************************************************************
VOID
HWTxIntrHandler(
PVOID pHead
)
{
PPERP_IO_SER_INFO pHWHead = (PPERP_IO_SER_INFO)pHead;
DEBUGMSG(ZONE_FUNCTION, (TEXT("Serial PDD: Enter HWTxIntrHandler\r\n")));
if ( pHWHead->IrMode ){
while(TRUE){
HWReadLSR( pHWHead );
if( pHWHead->LSR & SERIAL_LSR_TEMT ){
break;
}
}
REG8(ASICSiuRegs.siuiid_fc) = SERIAL_FCR_RCVR_RESET;
REG8(ASICSiuRegs.siuiid_fc) = pHWHead->FCR;
ENABLE_BITS8(ASICSiuRegs.siuie, SERIAL_IER_RDA);
DISABLE_BITS8(ASICSiuRegs.siumc, SERIAL_MCR_RTS);
}
DISABLE_BITS8(ASICSiuRegs.siuie, SERIAL_IER_THR);
// Let the putbytes routine know he can continue
PulseEvent(pHWHead->FlushDone);
}
// ****************************************************************
//
// @doc OEM
// @func ULONG | HWPutBytes |
// Called by driver to write bytes to hardware.
//
// @rdesc This function returns 0, or the minimum number of milliseconds
// before the mdd layer should call again. This is used if the
// device does not support indications of modem lines for hardware
// flow control. Thus the MDD layer will call again to see if
// the flow control condition has been removed. Without much
// testing I've used 10msecs as the wait period. Perhaps this
// value should be tuned.
//**********************************************************************
ULONG
HWPutBytes(
PVOID pHead, /*@parm PVOID returned by HWInit. */
PUCHAR pSrc, /*@parm Pointer to bytes to be sent. */
ULONG NumberOfBytes, /*@parm Number of bytes to be sent. */
PULONG pBytesSent /*@parm Pointer to actual number of bytes put. */
)
{
PPERP_IO_SER_INFO pHWHead = (PPERP_IO_SER_INFO)pHead;
UCHAR byteCount;
DEBUGMSG(ZONE_FUNCTION, (TEXT("Serial PDD: Enter HWPutBytes\r\n")));
DEBUGMSG(ZONE_FUNCTION, (TEXT("NumberOfBytes = %d\r\n"), NumberOfBytes));
*pBytesSent = 0;
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 ){
// 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) ){
DEBUGMSG(ZONE_FUNCTION, (TEXT("CSTFlow = TRUE\r\n")));
pHWHead->CTSFlowOff = TRUE; // Record flowed off state
DISABLE_BITS8(ASICSiuRegs.siuie, SERIAL_IER_THR);
// We could return a positive value here, which would
// cause the MDD to periodically check the flow control
// status. However, we don't need to since we know that
// the DCTS interrupt will cause the MDD to call us, and we
// will subsequently fake a TX interrupt to the MDD, causing
// him to call back into PutBytes.
return 0;
}
}
// Same thing applies for DSR
if ( pHWHead->dcb.fOutxDsrFlow ){
// 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_DSR) ){
DEBUGMSG(ZONE_FUNCTION, (TEXT("DSRFlow = TRUE\r\n")));
pHWHead->DSRFlowOff = TRUE; // Record flowed off state
DISABLE_BITS8(ASICSiuRegs.siuie, SERIAL_IER_THR);
// See the comment above above positive return codes.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -