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

📄 ser16550.c

📁 WinCE 3.0 BSP, 包含Inter SA1110, Intel_815E, Advantech_PCM9574 等
💻 C
📖 第 1 页 / 共 4 页
字号:
    
    try
    {
         // 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) )
        {
            DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
					  (TEXT("PutBytes, flowed on via DSR\n") ) );
            pHWHead->DSRFlowOff = FALSE;
             // DSR is set, so go ahead and resume sending
            OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR); // Enable xmit intr.
             // Then simulate a TX intr to get things moving
			pHWHead->AddTXIntr = TRUE;
        }
        if ( pHWHead->CTSFlowOff && (pHWHead->MSR & SERIAL_MSR_CTS) )
        {
            DEBUGMSG (ZONE_WRITE|ZONE_FLOW,
					  (TEXT("PutBytes, flowed on via CTS\n") ) );
            pHWHead->CTSFlowOff = FALSE;
             // CTS is set, so go ahead and resume sending
            OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR); // Enable xmit intr.
             // Then simulate a TX intr to get things moving
			pHWHead->AddTXIntr = TRUE;
        }
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Just exit
    }
    
    DEBUGMSG (0,
              (TEXT("-SL_OtherIntr 0x%X\r\n"), pHead));
}
        

//  
// @doc OEM
// @func	ULONG | SL_GetStatus | This structure is called by the MDD
//   to retrieve the contents of a COMSTAT structure.
//
// @rdesc	The return is a ULONG, representing success (0) or failure (-1).
//
ULONG
SL_GetStatus(
    PVOID	pHead,	// @parm PVOID returned by HWInit.
    LPCOMSTAT	lpStat	// Pointer to LPCOMMSTAT to hold status.
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
    ULONG	  RetVal  = pHWHead->CommErrors;
    
    DEBUGMSG (ZONE_FUNCTION,
              (TEXT("+SL_GetStatus 0x%X\r\n"), pHead));

    pHWHead->CommErrors = 0; // Clear old errors each time

    if ( lpStat )
	{
        try
        {
            if (pHWHead->CTSFlowOff)
                pHWHead->Status.fCtsHold = 1;
            else
                pHWHead->Status.fCtsHold = 0;
                    
            if (pHWHead->DSRFlowOff)
                pHWHead->Status.fDsrHold = 1;
            else
                pHWHead->Status.fDsrHold = 0;

             // NOTE - I think what they really want to know here is
             // the amount of data in the MDD buffer, not the amount
             // in the UART itself.  Just set to 0 for now since the
             // MDD doesn't take care of this.
            pHWHead->Status.cbInQue  = 0;
            pHWHead->Status.cbOutQue = 0;

            memcpy(lpStat, &(pHWHead->Status), sizeof(COMSTAT));
        }
        except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
            RetVal = (ULONG)-1;
        }        
	}
    else
        RetVal = (ULONG)-1;

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

//
// @doc OEM
// @func	ULONG | SL_Reset | Perform any operations associated
//   with a device reset
//
// @rdesc	None.
//
VOID
SL_Reset(
    PVOID   pHead	// @parm PVOID returned by HWInit.
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;

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

    memset(&pHWHead->Status, 0, sizeof(COMSTAT));
    try
    {
        OUTB(pHWHead, pIER, IER_NORMAL_INTS);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Do nothing
    }
    
    DEBUGMSG (ZONE_FUNCTION,
              (TEXT("-SL_Reset 0x%X\r\n"), pHead));
}

//
// @doc OEM
// @func	VOID | SL_GetModemStatus | Retrieves modem status.
//
// @rdesc	None.
//
VOID
SL_GetModemStatus(
    PVOID   pHead,	    // @parm PVOID returned by HWInit.
    PULONG  pModemStatus    // @parm PULONG passed in by user.
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
    UINT8 ubModemStatus;

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

    ReadMSR( pHWHead );
    ubModemStatus = pHWHead->MSR;
    
    if ( ubModemStatus & SERIAL_MSR_CTS )
        *pModemStatus |= MS_CTS_ON;

    if ( ubModemStatus & SERIAL_MSR_DSR )
        *pModemStatus |= MS_DSR_ON;

    if ( ubModemStatus & SERIAL_MSR_RI )
        *pModemStatus |= MS_RING_ON;

    if ( ubModemStatus & SERIAL_MSR_DCD )
        *pModemStatus |= MS_RLSD_ON;

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

//
// @doc OEM
// @func	VOID | SL_PurgeComm | Purge RX and/or TX
// 
// @rdesc	None.
//

VOID
SL_PurgeComm(
    PVOID   pHead,	    // @parm PVOID returned by HWInit.
    DWORD   fdwAction	    // @parm Action to take. 
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;

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

    try
    {
#ifdef TODO
        // REVIEW THIS - I don't see how this could have terminated a pending read,
        // nor how RX interrupts would ever get turned back on.  I suspect that
        // RXABORT and TXABORT would both be better implemented in the MDD.
        if ( fdwAction & PURGE_RXABORT )
            OUTB(pHWHead, pIER, IER_NORMAL_INTS & ~SERIAL_IER_RDA);
#endif    
        if ( fdwAction & PURGE_TXCLEAR )
        {
            // Write the TX reset bit.  It is self clearing
            OUTB(pHWHead, pIIR_FCR, pHWHead->FCR | SERIAL_FCR_TXMT_RESET);
        }

        if ( fdwAction & PURGE_RXCLEAR )
        {
            // Write the RX reset bit.  It is self clearing
            OUTB(pHWHead, pIIR_FCR, pHWHead->FCR | SERIAL_FCR_RCVR_RESET);
        }
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Just exit
    }
    
    DEBUGMSG (ZONE_FUNCTION,
              (TEXT("-SL_PurgeComm 0x%X\r\n"), pHead));
    return;
}

//
// @doc OEM
// @func	BOOL | SL_XmitComChar | Transmit a char immediately
// 
// @rdesc	TRUE if succesful
//
BOOL
SL_XmitComChar(
    PVOID   pHead,    // @parm PVOID returned by HWInit.
    UCHAR   ComChar   // @parm Character to transmit. 
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
    
     // Get critical section, then transmit when buffer empties
    DEBUGMSG (ZONE_WRITE, (TEXT("XmitComChar wait for CritSec %x.\r\n"),
                           &(pHWHead->TransmitCritSec)));
    EnterCriticalSection(&(pHWHead->TransmitCritSec));
    DEBUGMSG (ZONE_WRITE, (TEXT("XmitComChar got CritSec %x.\r\n"),
                           &(pHWHead->TransmitCritSec)));
    try
    {
        while( TRUE )  // We know THR will eventually empty
        {
             // Write the character if we can
            ReadLSR( pHWHead );
            if( pHWHead->LSR & SERIAL_LSR_THRE )
            {
                OUTB(pHWHead, pData, ComChar);
                break;
            }

            // If we couldn't write the data yet, then wait for a
            // TXINTR to come in and try it again.
            
            // Enable xmit intr.
            OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR);
             // Wait until the txintr has signalled.
            WaitForSingleObject(pHWHead->FlushDone, (ULONG)1000);
        }
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Just exit
    }
    
    LeaveCriticalSection(&(pHWHead->TransmitCritSec));
    DEBUGMSG (ZONE_WRITE, (TEXT("XmitComChar released CritSec %x.\r\n"),
                           &(pHWHead->TransmitCritSec)));   
    return TRUE;
}

//
// @doc OEM
// @func	BOOL | SL_PowerOff | Perform powerdown sequence.
// 
// @rdesc	TRUE if succesful
//
VOID
SL_PowerOff(
    PVOID   pHead	    // @parm	PVOID returned by HWInit.
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;

     // Current FCR is already saved in a shadow
    
     // Current IER is not normally shadowed, save it
    pHWHead->IER = INB(pHWHead, pIER);

     // Current LCR is not normally shadowed, save it
    pHWHead->LCR = INB(pHWHead, pLCR);

     // Current MCR is not normally shadowed, save it
    pHWHead->MCR = INB(pHWHead, pMCR);

     // Current Scratch is not normally shadowed, save it
    pHWHead->Scratch = INB(pHWHead, pScratch);
}

//
// @doc OEM
// @func	BOOL | SL_PowerOn | Perform poweron sequence.
// 
// @rdesc	TRUE if succesful
//
VOID
SL_PowerOn(
    PVOID   pHead	    // @parm	PVOID returned by HWInit.
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;

     // Restore any registers that we need
    OUTB(pHWHead, pIIR_FCR, pHWHead->FCR);
    OUTB(pHWHead, pIER, pHWHead->IER);
    OUTB(pHWHead, pLCR, pHWHead->LCR);
    OUTB(pHWHead, pMCR, pHWHead->MCR);
    OUTB(pHWHead, pScratch, pHWHead->Scratch);

     // And we didn't save the Divisor Reg, so set baud rate
    SL_SetBaudRate( pHWHead, pHWHead->dcb.BaudRate );
}

//
// @doc OEM
// @func	BOOL | SL_SetDCB | Sets new values for DCB.  This
// routine gets a DCB from the MDD.  It must then compare
// this to the current DCB, and if any fields have changed take
// appropriate action.
// 
// @rdesc	ULONG
//
ULONG
SL_SetDCB(
    PVOID   pHead,	    // @parm	PVOID returned by HWInit.
    LPDCB   lpDCB       // @parm    Pointer to DCB structure
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
    ULONG retval = 0;

     // If the device is open, scan for changes and do whatever
     // is needed for the changed fields.  if the device isn't
     // open yet, just save the DCB for later use by the open.
    if( pHWHead->OpenCount )
    {
         // Note, fparity just says whether we should check
         // receive parity.  And the 16550 won't let us NOT
         // check parity if we generate it.  So this field
         // has no effect on the hardware.
    
        if( lpDCB->BaudRate != pHWHead->dcb.BaudRate )
        {
            SL_SetBaudRate( pHWHead, lpDCB->BaudRate );
        }
    
        if( lpDCB->ByteSize != pHWHead->dcb.ByteSize )
        {
            SL_SetByteSize( pHWHead, lpDCB->ByteSize );
        }
    
        if( lpDCB->Parity != pHWHead->dcb.Parity )
        {
            SL_SetParity( pHWHead, lpDCB->Parity );
        }
    
        if( lpDCB->StopBits != pHWHead->dcb.StopBits )
        {
            SL_SetStopBits( pHWHead, lpDCB->StopBits );
        }

         // Don't worry about fOutxCtsFlow.  It is a flag which
         // will be examined every time we load the TX buffer.
         // No special action required here.
    }
    
     // Now that we have done the right thing, store this DCB
    pHWHead->dcb = *lpDCB;
    return retval;
}

//
// @doc OEM
// @func	BOOL | SL_SetCommTimeouts | Sets new values for the
// CommTimeouts structure. routine gets a DCB from the MDD.  It
// must then compare this to the current DCB, and if any fields
// have changed take appropriate action.
// 
// @rdesc	ULONG
//
ULONG
SL_SetCommTimeouts(
    PVOID   pHead,	    // @parm	PVOID returned by HWInit.
    LPCOMMTIMEOUTS   lpCommTimeouts // @parm Pointer to CommTimeout structure
    )
{
    PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
    ULONG retval = 0;
    
    DEBUGMSG (ZONE_FUNCTION,
              (TEXT("+SL_SetCommTimeout 0x%X\r\n"), pHead));

     // OK, first check for any changes and act upon them
    if( lpCommTimeouts->WriteTotalTimeoutMultiplier !=
        pHWHead->CommTimeouts.WriteTotalTimeoutMultiplier )
    {
    }
    
     // Now that we have done the right thing, store this DCB
    pHWHead->CommTimeouts = *lpCommTimeouts;

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

    return retval;
}



//
//  @doc OEM
//  @func	BOOL | SL_Ioctl | Device IO control routine.  
//  @parm DWORD | dwOpenData | value returned from COM_Open call
//	@parm DWORD | dwCode | io control code to be performed
//	@parm PBYTE | pBufIn | input data to the device
//	@parm DWORD | dwLenIn | number of bytes being passed in
//	@parm PBYTE | pBufOut | output data from the device
//	@parm DWORD | dwLenOut |maximum number of bytes to receive from device
//	@parm PDWORD | pdwActualOut | actual number of bytes received from device
//
//	@rdesc		Returns TRUE for success, FALSE for failure
//
//  @remark  The MDD will pass any unrecognized IOCTLs through to this function.
//
BOOL
SL_Ioctl(PVOID pHead, DWORD dwCode,PBYTE pBufIn,DWORD dwLenIn,
              PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut)
{
    BOOL RetVal = TRUE;
    DEBUGMSG (ZONE_FUNCTION, (TEXT("+SL_Ioctl 0x%X\r\n"), pHead));
    switch (dwCode) {

        // Currently, no defined IOCTLs
        default:
            RetVal = FALSE;
            DEBUGMSG (ZONE_FUNCTION, (TEXT(" Unsupported ioctl 0x%X\r\n"), dwCode));
            break;            
	}
    DEBUGMSG (ZONE_FUNCTION, (TEXT("-SL_Ioctl 0x%X\r\n"), pHead));
    return RetVal;
}

⌨️ 快捷键说明

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