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

📄 ser16950.c

📁 Windows CE操作系统中适用的蓝牙驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1999  Socket Communications

Module Name:  

ser16950.c

Abstract:  

	This file implements the standard device specific functions for a 16C950
	based serial device.

Functions:

	SL_Init()
	SL_Deinit()
	SL_Open()
	SL_Close()
	SL_ClearDTR()
	SL_SetDTR()
	SL_ClearRTS()
	SL_SetRTS()
	SL_ClearBreak()
	SL_SetBreak()
	SL_SetBaudRate()
	SL_SetByteSize()
	SL_SetParity()
	SL_SetStopBits()
	SL_GetRxBufferSize()
	SL_GetRxStart()
	SL_GetInterruptType()
	SL_RxIntr()
	SL_PutBytes()
	SL_TxIntr()
	SL_LineIntr()
	SL_OtherIntr()
	SL_GetStatus()
	SL_Reset()
	SL_GetModemStatus()
	SL_PurgeComm()
	SL_XmitComChar()
	SL_PowerOff()
	SL_PowerOn()
	SL_SetDCB()
	SL_SetCommTimeouts()
	SL_Ioctl()
	ReadLSR()
	ReadMSR()
	DumpSerialRegisters()
	LookUpValue()
	DivisorOfRate()



Notes:


--*/
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <memory.h>
#include <serhw.h>

#include <cardserv.h>
#include <sockserv.h>
#include <tuple.h>

#include "ser16950.h"
#include "hw16550.h"
#include <serdbg.h>
#include <excpt.h>

// Macros to read/write serial registers.

#define INB(pInfo, reg) (READ_PORT_UCHAR((UCHAR *)((pInfo)->reg)))
#define OUTB(pInfo, reg, value) (WRITE_PORT_UCHAR((UCHAR *)((pInfo)->reg), (unsigned char)(value)))

//#define INB(pInfo, reg) (*((pInfo)->reg))    
//#define OUTB(pInfo, reg, value) (*((pInfo)->reg)) = ((unsigned char)(value))

// Macros to read/write hardware registers in the mapped I/O space.
#define VOLB *(volatile BYTE* const)

//#define INB(pClientContext, regOffset) \
//   (VOLB(((pClientContext)->regOffset)))

//#define OUTB(pClientContext, regOffset, value) \
//    (VOLB((pClientContext)->regOffset) = (UCHAR)(value))

// Some forward references...
BOOL SL_SetByteSize(PVOID pHead, ULONG ByteSize);
BOOL SL_SetStopBits(PVOID pHead, ULONG StopBits);
BOOL SL_SetParity(PVOID pHead, ULONG Parity);
				  
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION 

#ifdef DEBUG
#pragma message ("Compile DEBUG is on:WendySer[ser16950.c]")
#endif

//
// Define SLIP wrapper values
//
#define SLIP_END		0xc0
#define SLIP_ESC		0xdb
#define SLIP_ESC_END	0xdc
#define SLIP_ESC_ESC	0xdd

//
// Reading the LSR clears most of its bits.  So, we provide this wrapper,
// which reads the register, records any interesting values, and
// stores the current LSR contents in the shadow register.
//
__inline
UINT8
ReadLSR(
    PSER16950_INFO  pHWHead
    )
{
    ULONG LineEvents = 0;
    
    try
    {
        pHWHead->LSR = INB(pHWHead, pLSR);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        pHWHead->LSR = SERIAL_LSR_THRE;
    }

    if ( pHWHead->LSR & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE))
    {
        // Note: Its not wise to do debug msgs in here since they will
        // pretty much guarantee that the FIFO gets overrun.
        if ( pHWHead->LSR & SERIAL_LSR_OE )
        {
            // DEBUGMSG (ZONE_WARN, (TEXT("Overrun\r\n")));
            pHWHead->DroppedBytes++;
            pHWHead->CommErrors |= CE_OVERRUN;
        }

        if ( pHWHead->LSR & SERIAL_LSR_PE )
        {
            // DEBUGMSG (ZONE_WARN, (TEXT("parity\r\n")));
            pHWHead->CommErrors |= CE_RXPARITY;
        }

        if ( pHWHead->LSR & SERIAL_LSR_FE )
        {
            // DEBUGMSG (ZONE_WARN, (TEXT("frame\r\n")));
            pHWHead->CommErrors |= CE_FRAME;
        }

        LineEvents |= EV_ERR;
    }

    if( pHWHead->LSR & SERIAL_LSR_BI )
        LineEvents |= EV_BREAK;
    
     // Let WaitCommEvent know about this error
    if( LineEvents )
        pHWHead->EventCallback( pHWHead->pMddHead, LineEvents );
	return pHWHead->LSR;
}

//
// Reading the MSR clears many of its bits.  So, we provide this wrapper,
// which reads the register, records any interesting values, and
// stores the current MSR contents in the shadow register.
// Note that we always have DDCD and DCTS enabled, so if someone
// wants to keep an eye on these lines, its OK to simply read the
// shadow register, since if the value changes, the interrupt
// will cause the shadow to be updated.
//
__inline
VOID
ReadMSR(
    PSER16950_INFO  pHWHead
    )
{
    ULONG		Events = 0;
    UCHAR       msr;
    
    try
    {
        msr = INB(pHWHead, pMSR);
    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        msr = 0;
    }
    
    // Save the MSR value in a shadow
    pHWHead->MSR = msr;

    // For changes, we use callback to evaluate the event
    if (msr & SERIAL_MSR_DCTS)
        Events |= EV_CTS;

    if( msr & SERIAL_MSR_DDSR )
        Events |= EV_DSR;

    if ( msr & SERIAL_MSR_TERI )
        Events |= EV_RING;

    if ( msr & SERIAL_MSR_DDCD )
        Events |= EV_RLSD;

    if( Events )
        pHWHead->EventCallback( pHWHead->pMddHead, Events );
}

#ifdef DEBUG
//
// This routine is used only for debugging, and performs a formatted
// ascii dump of the various UART registers.
//
VOID
DumpSerialRegisters(
    PVOID  pHead
    )
{
    UINT8 byte;
    PSER16950_INFO   pHWHead   = (PSER16950_INFO)pHead;

    
    try
    {
        byte = ReadLSR( pHWHead );
        
        NKDbgPrintfW(TEXT("16950 lsr: \t%2.2X\t"), byte);
        if( byte & SERIAL_LSR_DR )
            NKDbgPrintfW(TEXT("DataReady "));
        if( byte & SERIAL_LSR_OE )
            NKDbgPrintfW(TEXT("OverRun "));
        if( byte & SERIAL_LSR_PE )
            NKDbgPrintfW(TEXT("ParityErr "));
        if( byte & SERIAL_LSR_FE )
            NKDbgPrintfW(TEXT("FramingErr "));
        if( byte & SERIAL_LSR_BI )
            NKDbgPrintfW(TEXT("BreakIntpt "));
        if( byte & SERIAL_LSR_THRE )
            NKDbgPrintfW(TEXT("THREmpty "));
        if( byte & SERIAL_LSR_TEMT )
            NKDbgPrintfW(TEXT("TXEmpty "));
        if( byte & SERIAL_LSR_FIFOERR )
            NKDbgPrintfW(TEXT("FIFOErr "));
        NKDbgPrintfW(TEXT("\r\n"));
       
        byte = INB(pHWHead, pData);
        NKDbgPrintfW(TEXT("16950 rbr/thr:\t%2.2X\r\n"), byte);
    
        byte = INB(pHWHead, pIER);
        NKDbgPrintfW(TEXT("16950 IER: \t%2.2X\t"), byte);
        if( byte & SERIAL_IER_RDA )
            NKDbgPrintfW(TEXT("RXData "));
        if( byte & SERIAL_IER_THR )
            NKDbgPrintfW(TEXT("TXData "));
        if( byte & SERIAL_IER_RLS )
            NKDbgPrintfW(TEXT("RXErr "));
        if( byte & SERIAL_IER_MS )
            NKDbgPrintfW(TEXT("ModemStatus "));
        NKDbgPrintfW(TEXT("\r\n"));
    
        byte = INB(pHWHead, pIIR_FCR);
        NKDbgPrintfW(TEXT("16950 iir: \t%2.2X\t"), byte);
        if( byte & SERIAL_IIR_RDA )
            NKDbgPrintfW(TEXT("RXData "));
        if( byte & SERIAL_IIR_THRE )
            NKDbgPrintfW(TEXT("TXData "));
        if( byte & SERIAL_IIR_RLS )
            NKDbgPrintfW(TEXT("RXErr "));
        if( (byte & SERIAL_IIR_CTI) == SERIAL_IIR_CTI )
            NKDbgPrintfW(TEXT("CTI "));
        if( byte == SERIAL_IIR_MS )
            NKDbgPrintfW(TEXT("ModemStatus "));
        if( byte & 0x01 )
            NKDbgPrintfW(TEXT("IntPending "));
        NKDbgPrintfW(TEXT("\r\n"));
    
        byte = INB(pHWHead, pLCR);
        NKDbgPrintfW(TEXT("16950 lcr: \t%2.2X\t"), byte);

        NKDbgPrintfW(TEXT("%dBPC "), ((byte & 0x03)+5) );
        
        if( byte & SERIAL_LCR_DLAB )
            NKDbgPrintfW(TEXT("DLAB "));
        if( byte & SERIAL_LCR_DLAB )
            NKDbgPrintfW(TEXT("Break "));
        NKDbgPrintfW(TEXT("\r\n"));
    
        byte = INB(pHWHead, pMCR);
        NKDbgPrintfW(TEXT("16950 mcr: \t%2.2X\t"), byte);
        if( byte & SERIAL_MCR_DTR )
            NKDbgPrintfW(TEXT("DTR "));
        if( byte & SERIAL_MCR_RTS )
            NKDbgPrintfW(TEXT("RTS "));
        if( byte & SERIAL_MCR_OUT1 )
            NKDbgPrintfW(TEXT("OUT1 "));
        if( byte & SERIAL_MCR_OUT2 )
            NKDbgPrintfW(TEXT("OUT2 "));
        if( byte & SERIAL_MCR_LOOP )
            NKDbgPrintfW(TEXT("LOOP "));
        if( byte & MCR_BAUD_PRESCALE )
            NKDbgPrintfW(TEXT("PRESCALE "));
        NKDbgPrintfW(TEXT("\r\n"));

        ReadMSR( pHWHead );
        byte = pHWHead->MSR;
        NKDbgPrintfW(TEXT("16950 msr: \t%2.2X\t"), byte);
        if( byte & SERIAL_MSR_DCTS )
            NKDbgPrintfW(TEXT("DCTS "));
        if( byte & SERIAL_MSR_DDSR )
            NKDbgPrintfW(TEXT("DDSR "));
        if( byte & SERIAL_MSR_TERI )
            NKDbgPrintfW(TEXT("TERI "));
        if( byte & SERIAL_MSR_DDCD )
            NKDbgPrintfW(TEXT("DDCD"));
        if( byte & SERIAL_MSR_CTS )
            NKDbgPrintfW(TEXT(" CTS"));
        if( byte & SERIAL_MSR_DSR )
            NKDbgPrintfW(TEXT("DSR "));
        if( byte & SERIAL_MSR_RI )
            NKDbgPrintfW(TEXT("RI "));
        if( byte & SERIAL_MSR_DCD )
            NKDbgPrintfW(TEXT("DCD "));
        NKDbgPrintfW(TEXT("\r\n"));

    }
    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
            EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
        // Nothing much to clean up here.
    }
}
#endif // DEBUG

//
// Helper routine to search through a lookup table for a designated
// key.
//
BOOL
LookUpValue(
    ULONG	Key,
    PLOOKUP_TBL_4 pTbl,
    PULONG	pdivisor,
	PULONG	pscaler,
	PULONG	ptimesclock
    )
{
    ULONG   index = 0;
	ULONG	errorcode = 0;

    while ( index < pTbl->Size )
	{
        if ( Key == pTbl->Table[index].Key )
			{
			*pdivisor = pTbl->Table[index].AssociatedValue;
			*pscaler = pTbl->Table[index].AssociatedValue2;
			*ptimesclock = pTbl->Table[index].AssociatedValue3;
			return TRUE;
			}
        ++index;
	}
   return FALSE;
}
//
// Helper function.  Pass in a baudrate, and the corresponding divisor
// (from the baudtable) is returned.  If no matching baudrate is found
// in baudtable, then return 0.
//
#define	DIVISOROFRATE(pHead, BaudRate, pdivisor, pscaler, ptimesclock) \
		LookUpValue(BaudRate,(PLOOKUP_TBL_4)((PSER16950_INFO) pHead)->pBaudTable, pdivisor, pscaler, ptimesclock)

#define IER_NORMAL_INTS (SERIAL_IER_RDA | SERIAL_IER_RLS | SERIAL_IER_MS)


//
/////////////////// Start of exported entrypoints ////////////////
//

//
// @doc OEM 
// @func PVOID | SL_Open | Configures 16950 for default behaviour.
//
VOID
SL_Open(
    PVOID   pHead // @parm PVOID returned by HWinit.
    )
{
    PSER16950_INFO pHWHead = (PSER16950_INFO)pHead;

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

     // If the device is already open, all we do is increment count
    if( pHWHead->OpenCount++ )
    {
        DEBUGMSG (ZONE_OPEN,
                  (TEXT("-SL_Open 0x%X (%d opens)\r\n"),
                   pHead, pHWHead->OpenCount));
        return ;
    }
    
    pHWHead->FCR = 0;
    pHWHead->IER = 0;
    pHWHead->IIR = 0;
    pHWHead->LSR = 0;
    pHWHead->MSR = 0;
	pHWHead->mimicACR = 0;
    pHWHead->DroppedBytes = 0;
    pHWHead->CTSFlowOff = FALSE;  // Not flowed off yet
    pHWHead->DSRFlowOff = FALSE;  // Not flowed off yet
    pHWHead->RINGFlowOff = FALSE; // Not flowed off yet
    pHWHead->SLIPStartOfPacket = FALSE;
    pHWHead->SLIPEndOfPacket   = FALSE;
    pHWHead->SLIPEscapeFound   = FALSE;
    pHWHead->RIToggleCount = 0;
    pHWHead->RIToggleTimeout = 0;
    pHWHead->CommErrors   = 0;
    pHWHead->ModemStatus  = 0;
	pHWHead->bSleepDisable = 0;
	// Setup some defaults...
	pHWHead->RxFifoTrigger = SERIAL_BYTE_RX_HIGH_WATER;
	pHWHead->TxFifoTrigger = SERIAL_BYTE_TX_LOW_WATER;
	
    try
    {
		pHWHead->ChipID = CHIP_ID_WENDY1;

		pHWHead->IER = IER_NORMAL_INTS;		// Shadow the IER
        OUTB(pHWHead, pIER, pHWHead->IER);

		pHWHead->MCR = INB(pHWHead, pMCR) & 0xF0;	// Only take state of upper 4 bits
		pHWHead->MCR |= SERIAL_MCR_IRQ_ENABLE;
        OUTB(pHWHead, pMCR, pHWHead->MCR);

         // Set default framing bits.
		//pHWHead->LCR = SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY;
        OUTB(pHWHead, pLCR, pHWHead->LCR);

    
        DEBUGMSG (ZONE_OPEN,
                  (TEXT("SL_Open Setting DCB parameters\r\n")));

		// Actually, for WENDY, FIFO always enabled....
		// This sets up 256 byte trigger
        // Shadow the FCR bitmask since reading this location is the IIR.
        pHWHead->FCR = SERIAL_FCR_ENABLE | SERIAL_8_BYTE_HIGH_WATER ;
        OUTB(pHWHead, pIIR_FCR,
                 (pHWHead->FCR | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET) );

         // Get defaults from the DCB structure
        //SL_SetBaudRate( pHead, pHWHead->dcb.BaudRate );
        //SL_SetByteSize( pHead, pHWHead->dcb.ByteSize );
        //SL_SetStopBits( pHead, pHWHead->dcb.StopBits );
        //SL_SetParity(   pHead, pHWHead->dcb.Parity );

        // Ugly.  On PC's, the PIC is edge triggered.  So because of the
        // sequence in which we initialize interrupts, etc it is possible
        // to have the UART generating its level based interrupt but the
        // PIC never gets an edge, so we never start the entire interrupt/
        // interrupt-acknowledge sequence.  All we need to do here is ensure
        // that any already pending interrupts get cleared at the UART.
        pHWHead->IIR = INB(pHWHead, pIIR_FCR); 
        while( ! (pHWHead->IIR & 0x01) )
        {
            DEBUGMSG (ZONE_OPEN, (TEXT("!!IIR %X\r\n"), pHWHead->IIR));
            // Reading LSR clears RLS interrupts.
            ReadLSR( pHWHead );
            

⌨️ 快捷键说明

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