⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ser16550.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
📖 第 1 页 / 共 4 页
字号:
    
        OUTB(pHWHead, pLCR, lcr);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Do nothing - we're in enough trouble
    }

    DEBUGMSG (ZONE_FUNCTION,
              (TEXT("-SL_SetStopBits 0x%X\r\n"), pHead));
    
    return TRUE;
}

//
// @doc OEM
// @func ULONG | SL_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 ISR.
//
// 
// @rdesc This routine always returns 0 for 16550 UARTS.
// 
ULONG
SL_GetRxBufferSize(
    PVOID pHead
    )
{
    return 0;
}

//
// @doc OEM
// @func PVOID | SC_GetRxStart | This routine returns the start of the hardware
// receive buffer.  See SL_GetRxBufferSize.
// 
// @rdesc The return value is a pointer to the start of the device receive buffer.
// 
PVOID
SL_GetRxStart(
    PVOID   pHead // @parm PVOID returned by SC_init.
    )
{
    return  NULL;
}

//
// @doc OEM
// @func ULONG | SL_GetGetInterruptType | 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
SL_GetInterruptType(
    PVOID pHead      // Pointer to hardware head
    )
{
    PSER16550_INFO	pHWHead = (PSER16550_INFO)pHead;
    INTERRUPT_TYPE interrupts;
    
    DEBUGMSG (0,
              (TEXT("+SL_GetInterruptType 0x%X\r\n"), pHead));
    try
    {
        pHWHead->IIR = INB(pHWHead, pIIR_FCR);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        pHWHead->IIR = SERIAL_IIR_INT_INVALID; // simulate no interrupt
    }

    if( pHWHead->IIR & SERIAL_IIR_INT_INVALID )
    {
		// 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("-SL_GetInterruptType 0x%X, 0x%X\r\n"),
			   pHead, interrupts));

	return interrupts;
}


// @doc OEM
// @func ULONG | SL_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
SL_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("+GetBytes - 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
            ReadLSR( pHWHead );
        
            if( pHWHead->LSR & SERIAL_LSR_DR )
            {
                 // Read the byte
                cRXChar = INB(pHWHead, pData);

                 // 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;
            }
        }
    }
    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 (0, (TEXT("-GetBytes - rx'ed %d, dropped %d.\r\n"),
                  *pBufflen,
                  pHWHead->DroppedBytes));

    RetVal = pHWHead->DroppedBytes;
    pHWHead->DroppedBytes = 0;
    return RetVal;
}

// @doc OEM
// @func ULONG | SL_PutBytes | This routine is called from the MDD
//   in order to write a stream of data to the device.
// 
// @rdesc Always returns 0
//
ULONG
SL_PutBytes(
    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.
    )
{
    PSER16550_INFO   pHWHead	= (PSER16550_INFO)pHead;
    UCHAR       byteCount;
    
    DEBUGMSG (ZONE_WRITE, (TEXT("+PutBytes - Len %d.\r\n"),
                           NumberOfBytes));

    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 )
    {
        // 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) )
        {
			unsigned char byte;
            DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
                      (TEXT("PutBytes, flowed off via CTS\n") ) );
            pHWHead->CTSFlowOff = TRUE;  // Record flowed off state
            byte = INB(pHWHead, pIER);
            OUTB(pHWHead, pIER, byte & ~SERIAL_IER_THR); // disable TX interrupts while flowed off
            
            // 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 )
    {
        // 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_DSR) )
        {
            DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
                      (TEXT("PutBytes, flowed off via DSR\n") ) );
            pHWHead->DSRFlowOff = TRUE;  // Record flowed off state
            OUTB(pHWHead, pIER, IER_NORMAL_INTS); // disable TX interrupts while flowed off

            // See the comment above above positive return codes.
            return 0;
        }
    }

    DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes wait for CritSec %x.\r\n"),
                           &(pHWHead->TransmitCritSec)));
    EnterCriticalSection(&(pHWHead->TransmitCritSec));
    DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes got CritSec %x.\r\n"),
                           &(pHWHead->TransmitCritSec)));
    
    ReadLSR( pHWHead );
    if( pHWHead->LSR & SERIAL_LSR_THRE )
    {
        if( pHWHead->IIR & SERIAL_IIR_FIFOS_ENABLED )
            byteCount = SERIAL_FIFO_DEPTH;
        else
            byteCount = 1;
            
        DEBUGMSG (ZONE_WRITE | ZONE_THREAD,
                  (TEXT("Put Bytes - Write max of %d bytes\r\n"),
                   byteCount));
        try
        {
            for( ; NumberOfBytes && byteCount; NumberOfBytes--, byteCount-- )
            {
                OUTB(pHWHead, pData, *pSrc);
                ++pSrc;
                (*pBytesSent)++;
            }
        }
        except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
            // Just ignore it, we'll eventually fall out of here
        }
                
    }
            
    // Enable xmit intr. We need to do this no matter what, 
    // since the MDD relies on one final interrupt before
    // returning to the application. 
    try
    {
        OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Hmm, not sure what would cause this.  Lets just tell
        // the MDD to get lost until we get another TX
        // interrupt.
    }
            
    LeaveCriticalSection(&(pHWHead->TransmitCritSec));
    DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes released CritSec %x.\r\n"),
                           &(pHWHead->TransmitCritSec)));

    DEBUGMSG (ZONE_WRITE, (TEXT("-PutBytes - sent %d.\r\n"),
                           *pBytesSent));

    return 0;
}

//
// @doc OEM
// @func ULONG | SL_TXIntr | This routine is called from the MDD
//   whenever INTR_TX is returned by SL_GetInterruptType
// 
// @rdesc None
//
VOID
SL_TxIntr(
    PVOID pHead                // Hardware Head
    )
{
    PSER16550_INFO   pHWHead	= (PSER16550_INFO)pHead;

    DEBUGMSG (0,
              (TEXT("+SL_TxIntr 0x%X\r\n"), pHead));

     // 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.
    try
    {
        OUTB(pHWHead, pIER, IER_NORMAL_INTS);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Do nothing.  The worst case is that this was a fluke,
        // and a TX Intr will come right back at us and we will
        // resume transmission.
    }

    // Let the putbytes routine know he can continue
    PulseEvent(pHWHead->FlushDone);
    
    DEBUGMSG (0,
              (TEXT("+SL_TxIntr 0x%X\r\n"), pHead));
}

//
// @doc OEM
// @func ULONG | SL_LineIntr | This routine is called from the MDD
//   whenever INTR_LINE is returned by SL_GetInterruptType.
// 
// @rdesc None
//
VOID
SL_LineIntr(
    PVOID pHead                // Hardware Head
    )
{
    PSER16550_INFO   pHWHead	= (PSER16550_INFO)pHead;

    DEBUGMSG (0,
              (TEXT("+SL_LineIntr 0x%X\r\n"), pHead));

    ReadLSR( pHWHead );

    DEBUGMSG (0,
              (TEXT("-SL_LineIntr 0x%X\r\n"), pHead));
}

//
// @doc OEM
// @func ULONG | SL_OtherIntr | This routine is called from the MDD
//   whenever INTR_MODEM is returned by SL_GetInterruptType.
// 
// @rdesc None
//
VOID
SL_OtherIntr(
    PVOID pHead                // Hardware Head
    )
{
    PSER16550_INFO   pHWHead	= (PSER16550_INFO)pHead;

    DEBUGMSG (0,
              (TEXT("+SL_OtherIntr 0x%X\r\n"), pHead));

    ReadMSR( pHWHead );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -