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

📄 pl010ser.c

📁 EP931X系列的WinCE串口驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
                // Read the byte
                cRXChar = INB(pSerAMBA, pUART_DR);

// The UART error status data doesn't generate an interrupt (hence we don't
// get an INTR_LINE on the Integrator.  Instead, we must read the status 
// after reading data from the FIFO.  We'll call SL_LineIntr ourselves, as
// though we received a line status interrupt.  Any error state read will be
// sent back to the MDD through the callback provided.
SL_LineIntr(pHead);

                // But we may want to discard it
                if (pSer16550->dcb.fDsrSensitivity && !(INB(pSerAMBA, pUART_FR) & AMBA_UARTFR_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 && (INB(pSerAMBA, pUART_RSR) & AMBA_UARTRSR_PE) )
                    {
                        cRXChar = pSer16550->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 )
        pSer16550->EventCallback( pSer16550->pMddHead, EV_RXFLAG );

    if ( pSer16550->DroppedBytes )
        DEBUGMSG (ZONE_WARN, (TEXT("Rx drop %d.\r\n"),
                              pSer16550->DroppedBytes));

    DEBUGMSG (0, (TEXT("-GetBytes - rx'ed %d, dropped %d.\r\n"),
                  *pBufflen,
                  pSer16550->DroppedBytes));

    RetVal = pSer16550->DroppedBytes;
    pSer16550->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. (Obsolete)
// 
// @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  pSer16550 = &(((PSER_INFO)pHead)->ser16550);
    PAMBA_UART_INFO pSerAMBA  = &(((PSER_INFO)pHead)->serAMBA);
    UCHAR       byteCount = 0;
    UCHAR       ucCR;

    DEBUGMSG (ZONE_WRITE, (TEXT("+PutBytes - Len %d.\r\n"),
                           NumberOfBytes));

    pSer16550->CommErrors &= ~CE_TXFULL;
    *pBytesSent = 0;

    // 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 ( pSer16550->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 (!(INB(pSerAMBA, pUART_FR) & AMBA_UARTFR_CTS))
        {
            unsigned char byte = 0;
            DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
                      (TEXT("PutBytes, flowed off via CTS\n") ) );
            pSer16550->CTSFlowOff = TRUE;  // Record flowed off state

            EnterCriticalSection(&(pSer16550->RegCritSec));
            try
            {
                byte = INB(pSerAMBA, pUART_CR);
                OUTB(pSerAMBA, pUART_CR, byte & ~AMBA_UARTIIR_TIS); // disable TX interrupts while flowed off
            }
            except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
                    EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
                // Just ignore it, we'll eventually fall out of here
            }
            LeaveCriticalSection(&(pSer16550->RegCritSec));

            // 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 ( pSer16550->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 (!(INB(pSerAMBA, pUART_FR) & AMBA_UARTFR_DSR))
        {
            DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
                      (TEXT("PutBytes, flowed off via DSR\n") ) );
            pSer16550->DSRFlowOff = TRUE;  // Record flowed off state

            EnterCriticalSection(&(pSer16550->RegCritSec));
            try
            {
                ucCR = CR_NORMAL_INTS;
                if(((PSER_INFO)pHead)->fIRMode)
                {
                    ucCR |= CR_SIREN;
                }

                OUTB(pSerAMBA, pUART_CR, ucCR ); // disable TX interrupts while flowed off
            }
            except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
                    EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
                // Just ignore it, we'll eventually fall out of here
            }
            LeaveCriticalSection(&(pSer16550->RegCritSec));

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

    DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes wait for CritSec %x.\r\n"),
                           &(pSer16550->TransmitCritSec)));
    EnterCriticalSection(&(pSer16550->TransmitCritSec));
    DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes got CritSec %x.\r\n"),
                           &(pSer16550->TransmitCritSec)));

    // If the Tx FIFO is empty and we've enabled the FIFO, we know how many
    // bytes we can write quickly...
    //
    if ((INB(pSerAMBA, pUART_FR) & AMBA_UARTFR_TXFE))
    {
        if (INB(pSerAMBA, pUART_LCR_H) & AMBA_UARTLCR_H_FEN)
            byteCount = SERIAL_FIFO_DEPTH;
        else
            byteCount = 1;

        DEBUGMSG (ZONE_WRITE | ZONE_THREAD,
                  (TEXT("Put Bytes - Write max of %d bytes\r\n"),
                   byteCount));

        EnterCriticalSection(&(pSer16550->RegCritSec));
        try
        {
            for ( ; NumberOfBytes && byteCount; NumberOfBytes--, byteCount-- )
            {
                DEBUGLED( ZONE_WRITE, (1, 0x10200000 | *pSrc) );
                OUTB(pSerAMBA, pUART_DR, *pSrc);
                ++pSrc;
                (*pBytesSent)++;
            }
        }
        except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
            // Just ignore it, we'll eventually fall out of here
        }
        LeaveCriticalSection(&(pSer16550->RegCritSec));

    }

    // Enable xmit intr. We need to do this no matter what, 
    // since the MDD relies on one final interrupt before
    // returning to the application. 
    EnterCriticalSection(&(pSer16550->RegCritSec));
    try
    {
        ucCR = CR_NORMAL_INTS | AMBA_UARTCR_TIE;
        if(((PSER_INFO)pHead)->fIRMode)
        {
            ucCR |= CR_SIREN;
        }

        OUTB(pSerAMBA, pUART_CR, ucCR ); // disable TX interrupts while flowed off
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Hmm, not sure what would cause this.  Lets just tell
        // the MDD to go away until we get another TX
        // interrupt.
    }
    LeaveCriticalSection(&(pSer16550->RegCritSec));

    LeaveCriticalSection(&(pSer16550->TransmitCritSec));
    DEBUGMSG (ZONE_WRITE, (TEXT("PutBytes released CritSec %x.\r\n"),
                           &(pSer16550->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 old MDD
//   whenever INTR_TX is returned by SL_GetInterruptType (Obselete)
// 
// @rdesc None
//
VOID
SL_TxIntr(
         PVOID pHead                // Hardware Head
         )
{
    PSER16550_INFO  pSer16550 = &(((PSER_INFO)pHead)->ser16550);
    PAMBA_UART_INFO pSerAMBA  = &(((PSER_INFO)pHead)->serAMBA);
    UCHAR   ucCR;

    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.
    EnterCriticalSection(&(pSer16550->RegCritSec));
    try
    {
        ucCR = CR_NORMAL_INTS;
        if(((PSER_INFO)pHead)->fIRMode)
        {
            ucCR |= CR_SIREN;
        }

        OUTB(pSerAMBA, pUART_CR, ucCR ); 
    }
    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.
    }
    LeaveCriticalSection(&(pSer16550->RegCritSec));

    // Let the putbytes routine know he can continue
    PulseEvent(pSer16550->FlushDone);

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

//
// @doc OEM
// @func ULONG | SL_TXIntrEx | This routine is called from the new MDD
//   whenever INTR_TX is returned by SL_GetInterruptType
// 
// @rdesc None
//
VOID
SL_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  pSer16550 = &(((PSER_INFO)pHead)->ser16550);
    PAMBA_UART_INFO pSerAMBA  = &(((PSER_INFO)pHead)->serAMBA);
    UCHAR       byteCount = 0;
    ULONG NumberOfBytes = *pBufflen;
    UCHAR   ucCR;
    unsigned char byte;

    DEBUGMSG (ZONE_THREAD, (TEXT("Transmit Event\r\n")));

    DEBUGMSG (ZONE_WRITE,
              (TEXT("+SL_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 ) {
        DEBUGMSG (ZONE_WRITE, (TEXT("SL_TxIntrEx: Disable INTR_TX.\r\n")));

        ucCR = CR_NORMAL_INTS;
        if(((PSER_INFO)pHead)->fIRMode)
        {
            ucCR |= CR_SIREN;
        }

        OUTB(pSerAMBA, pUART_CR, ucCR ); 
        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(&(pSer16550->RegCritSec));
    try {
        // Need to signal FlushDone for XmitComChar
        PulseEvent(pSer16550->FlushDone);

        pSer16550->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 ( pSer16550->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 (!(INB(pSerAMBA, pUART_FR) & AMBA_UARTFR_CTS))
            {
                byte = 0;
                DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
                          (TEXT("SL_TxIntrEx, flowed off via CTS\n") ) );
                pSer16550->CTSFlowOff = TRUE;  // Record flowed off state
                byte = INB(pSerAMBA, pUART_CR);
                OUTB(pSerAMBA, pUART_CR, byte & ~AMBA_UARTCR_TIE); // 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.

                LeaveCriticalSection(&(pSer16550->RegCritSec));
                return;
            }
        }

        // Same thing applies for DSR
        if ( pSer16550->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 (!(INB(pSerAMBA, pUART_FR) & AMBA_UARTFR_DSR))
            {
                DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
                          (TEXT("SL_TxIntrEx, flowed off via DSR\n") ) );
                pSer16550->DSRFlowOff = TRUE;  // Record flowed off state
                byte = CR_NORMAL_INTS;
                if(((PSER_INFO)pHead)->fIRMode)
                {
                    byte |= CR_SIREN;
                }

                OUTB(pSerAMBA, pUART_CR, byte );  // disable TX interrupts while flowed off
                // See the comment above above positive return codes.

                LeaveCriticalSection(&(pSer16550->RegCritSec));
                return;
            }
        }
    }
    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.
    }


    LeaveCriticalSection(&(pSer16550->RegCritSec));

⌨️ 快捷键说明

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