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

📄 ser16550.c

📁 wince下的串口驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // just exit
    }
#pragma prefast(pop)

    // 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 (ZONE_READ, (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. (Obselete)
// 
// @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;

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

    pHWHead->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 ( 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

            EnterCriticalSection(&(pHWHead->RegCritSec));
            if (pHWHead->pIsrInfoVirt ==NULL || pHWHead->pXmitBuffer ==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0)  { // no data inbuffer. 
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
                try {
                    byte = INB(pHWHead, pIER);
                    OUTB(pHWHead, pIER, byte & ~SERIAL_IER_THR); // 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
                }
#pragma prefast(pop)
            }
            LeaveCriticalSection(&(pHWHead->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 ( 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

            EnterCriticalSection(&(pHWHead->RegCritSec));
            if (pHWHead->pIsrInfoVirt ==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) { // no data inbuffer. 
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
                try {
                    OUTB(pHWHead, pIER, IER_NORMAL_INTS); // 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
                }
#pragma prefast(pop)
            }
            LeaveCriticalSection(&(pHWHead->RegCritSec));

            // 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)));
    EnterCriticalSection(&(pHWHead->RegCritSec));
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
    try {
        if (pHWHead->pIsrInfoVirt ==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) { // no data inbuffer. 
            ReadLSR( pHWHead );
            if ( pHWHead->LSR & SERIAL_LSR_THRE ) {
                UCHAR       byteCount;
                if ( pHWHead->IIR & SERIAL_IIR_FIFOS_ENABLED )
                    byteCount = SERIAL_FIFO_DEPTH;
                else
                    byteCount = 1;
                OUTB(pHWHead, pIER, IER_NORMAL_INTS ); // Mask Xmit Interrupt.
                DEBUGMSG (ZONE_WRITE | ZONE_THREAD,
                    (TEXT("Put Bytes - Write max of %d bytes\r\n"),
                    byteCount));
                if (pHWHead->pIsrInfoVirt !=NULL && pHWHead->pXmitBuffer!=NULL)  { // Software Xmit FIFO
                    if (NumberOfBytes)	{
                        UCHAR bFirstByte=*pSrc;
                        NumberOfBytes--;
                        ++pSrc;
                        (*pBytesSent)++;
                        // Fill up the software ISR buffer.
                        while (GetXmitAvailableBuffer(pHWHead->pXmitBuffer)>min(pHWHead->pXmitBuffer->dwWaterMark,2) &&
                            NumberOfBytes) {
                            pHWHead->pXmitBuffer->bBuffer[pHWHead->pXmitBuffer->dwFIFO_In]=*pSrc;
                            pHWHead->pXmitBuffer->dwFIFO_In=IncXmitIndex(pHWHead->pXmitBuffer,pHWHead->pXmitBuffer->dwFIFO_In);
                            ++pSrc;
                            (*pBytesSent)++;
                            NumberOfBytes--;
                        }
                        OUTB(pHWHead, pData, bFirstByte);
                        OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR);
                    }
                    pHWHead->bMoreXmitData=(NumberOfBytes==0?FALSE:TRUE);
                }
                else
                    for ( ; NumberOfBytes && byteCount; NumberOfBytes--, byteCount-- ) {
                        DEBUGLED( ZONE_WRITE, (1, 0x10200000 | *pSrc) );
                        OUTB(pHWHead, pData, *pSrc);
                        ++pSrc;
                        (*pBytesSent)++;
                    }
            }
        }
        // Enable xmit intr. We need to do this no matter what, 
        // since the MDD relies on one final interrupt before
        // returning to the application. 
        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 go away until we get another TX
        // interrupt.
    }
#pragma prefast(pop)
    LeaveCriticalSection(&(pHWHead->RegCritSec));

    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 old MDD
//   whenever INTR_TX is returned by SL_GetInterruptType (Obselete)
// 
// @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.
    EnterCriticalSection(&(pHWHead->RegCritSec));
    if (pHWHead->pIsrInfoVirt ==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0)  {// no data inbuffer. 
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
        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.
        }
#pragma prefast(pop)
    }
    else 
    if (pHWHead->pIsrInfoVirt  && pHWHead->pXmitBuffer && pHWHead->pXmitBuffer->dwFIFO_Out!=pHWHead->pXmitBuffer->dwFIFO_In) {
        pHWHead->pXmitBuffer->dwFIFO_Out=pHWHead->pXmitBuffer->dwFIFO_In;
        OUTB(pHWHead, pIIR_FCR, pHWHead->FCR | SERIAL_FCR_TXMT_RESET);
        DEBUGMSG (ZONE_ERROR,(TEXT("SL_TxIntr:Xmit IST run with SOFT FIFO not empty!!!0x%X\r\n"), pHead));
    }
    LeaveCriticalSection(&(pHWHead->RegCritSec));

    // 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_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   pHWHead    = (PSER16550_INFO)pHead;
    ULONG NumberOfBytes = *pBufflen;

    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")));
        if (pHWHead->pIsrInfoVirt && pHWHead->pXmitBuffer) {
            pHWHead->bMoreXmitData=FALSE;
            while (pHWHead->pXmitBuffer->dwFIFO_In!= pHWHead->pXmitBuffer->dwFIFO_Out) {
                RETAILMSG(1,(TEXT("!!!SL_TxIntrEx: We found lost Xmit FIFO Data \r\n")));
                pHWHead->pXmitBuffer->dwFIFO_In= pHWHead->pXmitBuffer->dwFIFO_Out;
                OUTB(pHWHead, pIIR_FCR, pHWHead->FCR | SERIAL_FCR_TXMT_RESET);
            }
        }
        OUTB(pHWHead, pIER, IER_NORMAL_INTS);
        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));
#pragma prefast(disable: 322, "Recover gracefully from hardware failure")
    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 ) {
            // 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("SL_TxIntrEx, flowed off via CTS\n") ) );
                pHWHead->CTSFlowOff = TRUE;  // Record flowed off state
                if (pHWHead->pIsrInfoVirt==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0)  {// no data inbuffer. 
                    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.

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

        // 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("SL_TxIntrEx, flowed off via DSR\n") ) );
                pHWHead->DSRFlowOff = TRUE;  // Record flowed off state
                if (pHWHead->pIsrInfoVirt==NULL || pHWHead->pXmitBuffer==NULL || GetXmitDataSize(pHWHead->pXmitBuffer)==0) { // no data inbuffer. 
                    OUTB(pHWHead, pIER, IER_NORMAL_INTS); // disable TX interrupts while flowed off
                }
                // 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.
    }
#pragma prefast(pop)

    LeaveCriticalSection(&(pHWHead->RegCritSec));


    //  OK, now lets actually transmit some data.
    DEBUGMSG (ZONE_WRITE, (TEXT("SL_TxIntrEx wait for CritSec %x.\r\n"),
                           &(pHWHead->TransmitCritSec)));
    EnterCriticalSection(&(pHWHead->TransmitCritSec));
    DEBUGMSG (ZONE_WRITE, (TEXT("SL_TxIntrEx got CritSec %x.\r\n"),
                           &(pHWHead->TransmitCritSec)));

    EnterCriticalSection(&(pHWHead->RegCritSec));
#pragma prefast(disable: 322, "Recover gracefully f

⌨️ 快捷键说明

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