serialhw.c

来自「Microsoft WinCE 6.0 BSP FINAL release so」· C语言 代码 · 共 1,841 行 · 第 1/5 页

C
1,841
字号
            interrupts = INTR_LINE;    // 0x1
        } else if ((pHWHead->pUartReg->USR2 & CSP_BITFVAL(UART_USR2_TXDC,UART_USR2_TXDC_SET)) 
            && (pHWHead->pUartReg->UCR4 & CSP_BITFVAL(UART_UCR4_TCEN, UART_UCR4_TCEN_ENABLE))){
            CSP_BITFCLR(pHWHead->pUartReg->UCR4, UART_UCR4_TCEN);
            interrupts = INTR_TX;      // 0x4
        } else if (((pHWHead->pUartReg->USR2 & CSP_BITFVAL(UART_USR2_RDR, UART_USR2_RDR_SET))
            && (pHWHead->pUartReg->UCR4 & CSP_BITFVAL(UART_UCR4_DREN, UART_UCR4_DREN_ENABLE)))
            || (pHWHead->pUartReg->USR1 & CSP_BITFVAL(UART_USR1_AGTIM, UART_USR1_AGTIM_SET))){
            pHWHead->pUartReg->USR1=CSP_BITFVAL(UART_USR1_AGTIM, UART_USR1_AGTIM_SET); 
            interrupts = INTR_RX;
        } else if ((pHWHead->pUartReg->USR1 & CSP_BITFVAL(UART_USR1_RTSD, UART_USR1_RTSD_SET)) 
            && (pHWHead->pUartReg->UCR1& CSP_BITFVAL(UART_UCR1_RTSDEN, UART_UCR1_RTSDEN_ENABLE))){

            DEBUGMSG(ZONE_FUNCTION, (TEXT("RTS change state detected 0x%x\r\n"),pHWHead->pUartReg->USR1));
            interrupts = INTR_MODEM;   // 0x8
        } else if (pHWHead->pUartReg->USR2 & CSP_BITFVAL(UART_USR2_IRINT, UART_USR2_IRINT_SET)){    //Infrared
            pHWHead->pUartReg->USR2=CSP_BITFVAL(UART_USR2_IRINT, UART_USR2_IRINT_SET); 
            interrupts = INTR_MODEM;   // 0x8
        } else 
            interrupts = INTR_NONE;      // 0x0 No interrupts pending, vector is useless
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
        EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        intPndVal = INTR_NONE; // simulate no interrupt
    }
    LeaveCriticalSection(&(pHWHead->RegCritSec));

    if (pHWHead->AddTXIntr) {
        interrupts |= INTR_TX;
        pHWHead->AddTXIntr = FALSE;
        DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_GetIntrType - AddTXIntr 0x%x\r\n"),pHWHead->pUartReg->USR1));                
    }
    DEBUGMSG(ZONE_FUNCTION, (TEXT("UART_USR1: 0x%x | UART_USR2: 0x%x\r\n"), pHWHead->pUartReg->USR1,  pHWHead->pUartReg->USR2));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_GetIntrType- 0x%X\r\n"),interrupts));

    return(interrupts);
}


//-----------------------------------------------------------------------------
//
// Function: SL_RxIntrHandler
//
// This function gets zero or more characters 
// from the hardware receive buffer and puts them 
// into the location pointed to by the pTargetBuffer 
// parameter. If there are no characters available 
// for reading, this function returns immediately. 
// This function is called in response to a receive 
// interrupt indication from the SL_GetInterruptType
// function.
//
// Parameters:
//      pContext 
//          [in] Pointer to device head.
//      pTargetBuffer 
//          [in] Pointer to the target buffer in which to put the data.
//      pByteNumber 
//          [in] Pointer to, on entry, the maximum 
//                number of bytes to read. On exit, the number of 
//                bytes read.
//
// Returns:  
//      The return value indicates the number of overruns 
//      detected. The actual number of dropped characters 
//      may be higher.
//
//-----------------------------------------------------------------------------
ULONG SL_RxIntrHandler( PVOID pContext, PUCHAR pTargetBuffer, ULONG *pByteNumber )
{
    PUART_INFO pHWHead = (PUART_INFO)pContext;

    ULONG RetVal = 0;
    ULONG TargetRoom = *pByteNumber;
    BOOL fRXFlag = FALSE;
    BOOL fReplaceparityErrors = FALSE;
    BOOL fNull;
    UCHAR cEvtChar, cRXChar;
    ULONG ulTemp=0;
    ULONG LineEvents = 0;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_RxIntrHandler+ : len %d. EvtChar 0x%x\r\n"), *pByteNumber,pHWHead->dcb.EvtChar));

    *pByteNumber = 0;

    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
            SL_ReadLineStatus(pHWHead);

            if (pHWHead->sUSR2 & CSP_BITFVAL(UART_USR2_RDR, UART_USR2_RDR_SET)) {
                // Read the RX register
                ulTemp = INREG32(&pHWHead->pUartReg->URXD);

                //Discard the echo char for irda
                if (pHWHead->UseIrDA)
                    if (pHWHead->ulDiscard) {
                        pHWHead->ulDiscard--;
                        continue;
                    }
                //Check if a valid char
                if(ulTemp & CSP_BITFVAL(UART_URXD_ERR, UART_URXD_ERR_ERROR)) {
                    DEBUGMSG(ZONE_ERROR,(TEXT("READ ERROR!!!  x%x\r\n"),ulTemp));
                    continue;
                }

                cRXChar = (UCHAR)ulTemp & UART_URXD_RX_DATA_MSK;
                DEBUGMSG(ZONE_FUNCTION, (TEXT("Read x%x\r\n"), cRXChar));

                // But we may want to discard it
                //Check DSR(DTR)
                if (pHWHead->dcb.fDsrSensitivity && (!pHWHead->bDSR)) {
                    // Do nothing - byte gets discarded
                    DEBUGMSG(ZONE_FUNCTION, (TEXT("Dropping byte because DSR is high\r\n")));
                }
                else if (!cRXChar && fNull) {
                    // Do nothing - byte gets discarded
                    DEBUGMSG(ZONE_FUNCTION, (TEXT("Dropping NULL byte due to fNull\r\n")));
                }
                else {
                    // Do character replacement if parity error detected.
                    //if ( fReplaceparityErrors && (pHWHead->sUSR1 & CSP_BITFVAL(UART_USR1_PARITYERR, UART_USR1_PARITYERR_SET)) ) {
                    if (fReplaceparityErrors && (ulTemp & CSP_BITFVAL(UART_URXD_PRERR, UART_URXD_PRERR_ERROR))) {
                        cRXChar = pHWHead->dcb.ErrorChar;
                    }
                    else {
                        // See if we need to generate an EV_RXFLAG for the received char.
                        if (cRXChar == cEvtChar) {
                            DEBUGMSG(ZONE_FUNCTION, (TEXT("Evt Char x%x\r\n"), cEvtChar));
                            fRXFlag = TRUE;
                        }
                    }
                    // Finally, we can get byte, update status and save.
                    *pTargetBuffer++ = cRXChar;

                    DEBUGMSG(ZONE_FUNCTION,(TEXT("R%02x\r\n"),cRXChar));
                    (*pByteNumber)++;
                    --TargetRoom;
                }
            }
            else {
                // We read all chars, so we're done
                break;
            }
        }
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
        EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
    }

    // if we saw one (or more) EVT chars, then generate an event
    if (fRXFlag) {
        pHWHead->EventCallback(pHWHead->pMDDContext, EV_RXFLAG);
        DEBUGMSG(ZONE_FUNCTION, (TEXT("EV_RXFLAG set\r\n")));
    }
    else {
        DEBUGMSG(ZONE_FUNCTION, (TEXT("EV_RXFLAG not set\r\n")));
    }
    if (pHWHead->DroppedBytes)
        DEBUGMSG(ZONE_FUNCTION, (TEXT("Rx drop %d.\r\n"), pHWHead->DroppedBytes));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_RxIntrHandler - rx'ed %d, dropped %d.\r\n"), *pByteNumber, pHWHead->DroppedBytes));

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

    return(RetVal);
}


//-----------------------------------------------------------------------------
//
// Function: SL_TxIntrHandler
//
// This function is called when the driver 
// detects a transmit interrupt (INTR_TX), as set by 
// the SL_GetInterruptType function. It sends several 
// characters to the hardware transmission buffer.
//
// Parameters:
//      pContext 
//          [in] Pointer to device head.
//      pSourceBuffer 
//          [in] Pointer to the source buffer that contains data to be sent.
//      pByteNumber 
//          [in] When SL_TxIntrEx is called, 
//                 pByteNumber points to the maximum number of bytes 
//                 to send. When SL_TxIntrEx returns, pByteNumber 
//                 points to the actual number of bytes sent..
//
// Returns:  
//      None.
//
//-----------------------------------------------------------------------------
VOID SL_TxIntrHandler( PVOID pContext, PUCHAR pSourceBuffer, ULONG *pByteNumber )
{
    PUART_INFO pHWHead = (PUART_INFO)pContext;
 
    UCHAR byteCount;
    ULONG NumberOfBytes = *pByteNumber;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler+\r\n")));
    DEBUGMSG(ZONE_FUNCTION, (TEXT("Transmit Event 0x%X, Len %d\r\n"), pContext, *pByteNumber));

    SL_ReadModemStatus(pHWHead);
    // We may be done sending.  If so, just disable the TX interrupts
    // and return to the MDD.  
    if (! *pByteNumber) {
        DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler - Disable INTR_TX.\r\n")));
        //Disable the TX interrupts
        OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );
        return;
    }

    *pByteNumber = 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) {
            DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler - fOutxCtsFlow true\r\n")));
            // 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.
            //Check CTS (RTS), 1:low, 0:high;
            if (!(pHWHead->sUSR1 & CSP_BITFVAL(UART_USR1_RTSS, UART_USR1_RTSS_SET))) {
                DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler - fOutxCtsFlow true 0x%x, 0x%x\r\n"),pHWHead->sUSR1,pHWHead->pUartReg->USR1));                
                DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler, flowed off via CTS\n") ) );
                pHWHead->CTSFlowOff = TRUE;  // Record flowed off state

                // disable TX interrupts while flowed off
                OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );

                // 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(&(pHWHead->RegCritSec));
                return;
            }
        }

        // Same thing applies for DSR
        if (pHWHead->dcb.fOutxDsrFlow) {
            DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler - fOutxDsrFlow true\r\n")));
            // We don't need to explicitly read the register, since we always enable
            // interrupt, which ensures that we will get an interrupt and read
            // the register whenever CTS, DSR, TERI, or DCD change.
            //Check shadow bDSR, 1:low, 0:high
            if (!pHWHead->bDSR) {
                pHWHead->DSRFlowOff = TRUE;  // Record flowed off state
                // disable TX interrupts while flowed off
                OUTREG32( &pHWHead->pUartReg->UCR4, INREG32(&pHWHead->pUartReg->UCR4)&~CSP_BITFMASK(UART_UCR4_TCEN) );

                // See the comment above above positive return codes.
                LeaveCriticalSection(&(pHWHead->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(&(pHWHead->RegCritSec));

    //  OK, now lets actually transmit some data.
    EnterCriticalSection(&(pHWHead->TransmitCritSec));

    EnterCriticalSection(&(pHWHead->RegCritSec));
    try {
        // Enable xmit intr. We need to do this no matter what, 
        // since the MDD relies on one final interrupt before
        // returning to the application. 
        OUTREG32(&pHWHead->pUartReg->USR2,CSP_BITFVAL(UART_USR2_TXDC, UART_USR2_TXDC_SET)); 

        SL_ReadLineStatus(pHWHead);
        if (pHWHead->sUSR2 & CSP_BITFVAL(UART_USR2_TXFE, UART_USR2_TXFE_SET)) {
            //always enable FIFO
            byteCount = UART_TXFIFO_DEPTH-SER_FIFO_TXTL;
            DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler - Write max of %d bytes to 0x%x\r\n"), byteCount, &pHWHead->pUartReg->UTXD));

            for (*pByteNumber=0; NumberOfBytes && byteCount; NumberOfBytes--, byteCount--) {
                OUTREG32(&pHWHead->pUartReg->UTXD,*pSourceBuffer);
                DEBUGMSG(ZONE_FUNCTION, (TEXT("Write x%x\r\n"), *pSourceBuffer));
				
                //We need to discard the echo char for irda
                if (pHWHead->UseIrDA)
                    pHWHead->ulDiscard++;

                ++pSourceBuffer;
                (*pByteNumber)++;
            }
        }

        DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler: Enable INTR_TX.\r\n")));
        INSREG32BF(&pHWHead->pUartReg->UCR4, UART_UCR4_TCEN, UART_UCR4_TCEN_ENABLE); 
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
        EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
    }
    LeaveCriticalSection(&(pHWHead->RegCritSec));
    LeaveCriticalSection(&(pHWHead->TransmitCritSec));

    DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_TxIntrHandler- sent %d.\r\n"), *pByteNumber));

    return;
}


//-----------------------------------------------------------------------------
//
// Function: SL_ModemIntrHandler
//
// This function handles the modem interrupt. It
// collects the modem status of the serial port, and 
// updates internal driver status information. 
// In the new serial port upper layer implementation 
// available in Microsoft Windows CE 3.0 and later, 
// this function replaces the HWOtherIntrHandler 
// function.
//
// Parameters:
//      pContext 
//          [in] Pointer to device head.
//
// Returns:  
//      None.
//
//-----------------------------------------------------------------------------
VOID SL_ModemIntrHandler( PVOID pContext )
{
    PUART_INFO pHWHead = (PUART_INFO)pContext;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("SL_ModemIntrHandler+\r\n")));
    
    SL_ReadModemStatus( pHWHead );
    if (!((PSER_INFO)pContext)->cOpenCount) {
        // We want to indicate a cable event.
        if (!pHWHead->UseIrDA) {
            if ((pHWHead->sUSR1 & CSP_BITFVAL(UART_USR1_RTSS, UART_USR1_RTSS_SET)))
                if (IsAPIReady(SH_WMGR)) {
                        DEBUGMSG(ZONE_FUNCTION, (TEXT("RS232 notification!!!\r\n")));
                        CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED,NULL);
                    }
        }

⌨️ 快捷键说明

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