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

📄 mdd.c

📁 SBC2410 WinCE 5.0 BSP.绝大多数驱动已经调通。
💻 C
📖 第 1 页 / 共 5 页
字号:
//
// 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.

Module Name:  

mdd.c

Abstract:  

This file contains the serial mdd (model device driver) code.  This is
intended to work with a series of serial pdds to implement serial
devices for the WinCE OS.  Since most of the serial handling can be
done in a hardware independant way this should limit the amount of
individual code an OEM would need to develop.

Functions:
COM_Init
COM_Open
COM_Close
COM_Deinit
COM_Read
COM_Write
COM_Seek
COM_PowerUp
COM_PowerDown
COM_IOControl
DllEntry
SerialEventHandler
SerialDispatchThread
ApplyDCB
SerialGetDroppedByteNumber
WaitCommEvent
EvaluateEventFlag
ProcessExiting


Notes: 


--*/
#include <windows.h>
#include <types.h>
#include <memory.h>
#include <linklist.h>
#include <nkintr.h>
#include <serdbg.h>
#include <serpriv.h>
#include <hwcomapi.h>
#include <pegdser.h>
#include <devload.h>
#include <pm.h>

#ifdef TARGET_NT
    #include <devemul.h>
    #include <nteser.h>
#endif

/* Debug Zones.
 */
#ifdef DEBUG

    #define DBG_INIT    0x0001
    #define DBG_OPEN    0x0002
    #define DBG_READ    0x0004
    #define DBG_WRITE   0x0008
    #define DBG_CLOSE   0x0010
    #define DBG_IOCTL   0x0020
    #define DBG_THREAD  0x0040
    #define DBG_EVENTS  0x0080
    #define DBG_CRITSEC 0x0100
    #define DBG_FLOW    0x0200
    #define DBG_IR      0x0400
    #define DBG_NOTHING 0x0800
    #define DBG_ALLOC   0x1000
    #define DBG_FUNCTION 0x2000
    #define DBG_WARNING 0x4000
    #define DBG_ERROR   0x8000

DBGPARAM dpCurSettings = {
    TEXT("Serial"), {
        TEXT("Init"),TEXT("Open"),TEXT("Read"),TEXT("Write"),
        TEXT("Close"),TEXT("Ioctl"),TEXT("Thread"),TEXT("Events"),
        TEXT("CritSec"),TEXT("FlowCtrl"),TEXT("Infrared"),TEXT("User Read"),
        TEXT("Alloc"),TEXT("Function"),TEXT("Warning"),TEXT("Error")},
    0
}; 
#endif

#ifndef MIN
    #define MIN(x,y)		((x) < (y) ? (x) : (y))
#endif

//
// Macros to maintain a usage count for a particular serial structure,
// so that we know when it is safe to deallocate it.
//
#define COM_INC_USAGE_CNT(pOpenHead)  \
    InterlockedIncrement(&pOpenHead->StructUsers)

#define COM_DEC_USAGE_CNT(pOpenHead)  \
    InterlockedDecrement(&pOpenHead->StructUsers)

// Define some internally used functions
BOOL COM_Close(PHW_OPEN_INFO    pOpenHead);
BOOL COM_Deinit(PHW_INDEP_INFO pSerialHead);
VOID EvaluateEventFlag(PVOID pHead, ULONG fdwEventMask);

/*
 @doc INTERNAL
 @func	BOOL | DllEntry | Process attach/detach api.
 *
 @rdesc The return is a BOOL, representing success (TRUE) or failure (FALSE).
 */
BOOL
DllEntry(
              HINSTANCE   hinstDll,             /*@parm Instance pointer. */
              DWORD   dwReason,                 /*@parm Reason routine is called. */
              LPVOID  lpReserved                /*@parm system parameter. */
              )
{
    if ( dwReason == DLL_PROCESS_ATTACH ) {
        DEBUGREGISTER(hinstDll);
        DEBUGMSG (ZONE_INIT, (TEXT("serial port process attach\r\n")));
	DisableThreadLibraryCalls((HMODULE) hinstDll);
    }

    if ( dwReason == DLL_PROCESS_DETACH ) {
        DEBUGMSG (ZONE_INIT, (TEXT("process detach called\r\n")));
    }

    return(TRUE);
}

/*
 @doc INTERNAL
 @func	VOID | DoTxData | Sends next available chunk of TX data.
 *
 */
VOID
DoTxData( PHW_INDEP_INFO pSerialHead )
{
    PHW_VTBL            pFuncTbl = pSerialHead->pHWObj->pFuncTbl;
    PVOID               pHWHead = pSerialHead->pHWHead;
    ULONG               Len;



    DEBUGMSG (ZONE_WRITE, (TEXT("DoPutBytes wait for CritSec %x.\r\n"),
                           &(pSerialHead->TxBufferInfo.CS)));
    TxEnterCS(pSerialHead);
    DEBUGMSG (ZONE_WRITE, (TEXT("DoPutBytes got CritSec %x.\r\n"),
                           &(pSerialHead->TxBufferInfo.CS)));

    // If device was closed from under us, stop transmitting
    if ( !pSerialHead->OpenCnt ) {
        DEBUGMSG (ZONE_THREAD|ZONE_WRITE , (TEXT("Device closed! Quit transmission!\r\n")));
        DEBUGMSG (ZONE_WRITE,
                  (TEXT("SerialEventHandler: %d sent up-to-now.\n\r"),pSerialHead->TxBytesSent));
        pSerialHead->TxBufferInfo.Permissions = 0;
        pSerialHead->TxBufferInfo.TxCharBuffer = NULL;
        pSerialHead->TxBufferInfo.Length = 0;
        TxRead(pSerialHead) = 0;
    }

    // Check the flow control status, and if not flowed off, call the
    // hw TX routine to actually transmit some data.
    if ( pSerialHead->TxBufferInfo.TxCharBuffer && TxBytesAvail(pSerialHead) ) {
        DWORD oldPerm = SetProcPermissions(pSerialHead->TxBufferInfo.Permissions);

        if ( pSerialHead->DCB.fRtsControl == RTS_CONTROL_TOGGLE ) {
            DEBUGMSG (ZONE_THREAD|ZONE_WRITE , (TEXT("RTS set.\r\n")));
            pFuncTbl->HWSetRTS(pHWHead);
        }

        // Don't transmit anything if we are flowed off.
        if ( pSerialHead->StopXmit ) {
            // But we still need to call TxIntrHandler so that the interrupt
            // gets cleared.
            DEBUGMSG (ZONE_FLOW|ZONE_WRITE , (TEXT("XOFF'ed, send nothing.\r\n")));
            Len = 0;
        } else {
            DEBUGMSG (ZONE_WRITE,
                      (TEXT("TxRead = %d, TxLength = %d, TxBytesAvail = %d.\r\n"),
                       TxRead(pSerialHead), TxLength(pSerialHead),
                       TxBytesAvail(pSerialHead)));
            Len = TxBytesAvail(pSerialHead);
        }
        DEBUGMSG (ZONE_WRITE, (TEXT("About to copy %d bytes\r\n"), Len));
        pFuncTbl->HWTxIntrHandler(pHWHead,
                                  TxBuffRead(pSerialHead),
                                  &Len);
        DEBUGMSG (ZONE_WRITE, (TEXT("%d bytes actually copied.\r\n"), Len));
        // Update Fifo info
        pSerialHead->TxBytes += Len;
        pSerialHead->TxBytesSent += Len;
        TxRead(pSerialHead) += Len;

        // Even if everything was Tx'ed, don't signal TX complete until
        // we get transmit interrupt indicating that the data has
        // actually been sent.  Since few/no UARTS have a way to tell
        // how much data remains, we don't bother trying to adjust the
        // return length to account for partially completed hardware buffer TX
        SetProcPermissions(oldPerm);
    } else {
        // Even if there is nothing left to send, we need to call
        // the interrupt handler so that it can clear the
        // transmit interrupt
        Len = 0;
        pFuncTbl->HWTxIntrHandler(pHWHead,
                                  NULL,
                                  &Len);        
        DEBUGMSG (ZONE_WRITE, (TEXT("Transmission complete, %d bytes sent\r\n"), Len));
        pSerialHead->TxBufferInfo.Permissions = 0;
        pSerialHead->TxBufferInfo.TxCharBuffer = NULL;
        pSerialHead->TxBufferInfo.Length = 0;
        TxRead(pSerialHead) = 0;
        SetEvent(pSerialHead->hTransmitEvent);
    }

    TxLeaveCS(pSerialHead);
    DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
              (TEXT("DoPutBytes released CritSec: %x.\r\n"),
               &(pSerialHead->TxBufferInfo.CS)));

}

VOID
SerialEventHandler(PHW_INDEP_INFO       pSerialHead)
{
    PHW_VTBL            pFuncTbl = pSerialHead->pHWObj->pFuncTbl;
    PVOID               pHWHead = pSerialHead->pHWHead;
    ULONG               CharIndex;
    ULONG               RoomLeft = 0;
    ULONG               TotalLeft = 0;
    INTERRUPT_TYPE      it = INTR_NONE;
    BOOL                RxDataAvail = FALSE;

    DEBUGMSG (ZONE_THREAD, (TEXT("+SerialEventHandler, pHead 0x%X\r\n"),
                            pSerialHead));

    if ( pSerialHead->KillRxThread ||
         !pSerialHead->hSerialEvent ) {
        DEBUGMSG (ZONE_THREAD, (TEXT("Exitting thread\r\n")));
        SetEvent(pSerialHead->hKillDispatchThread);
        ExitThread(0);
    }

// NOTE - This one is a little tricky.  If the only owner is a monitoring task
// then I don't have an owner for read/write, yet I might be in this routine
// due to a change in line status.  Lets just do the best we can and increment
// the count for the access owner if available.
    if ( pSerialHead->pAccessOwner )
        COM_INC_USAGE_CNT(pSerialHead->pAccessOwner);

    while ( 1 ) {

        if ( !(it = pFuncTbl->HWGetIntrType(pHWHead)) ) {
            DEBUGMSG (ZONE_THREAD,
                      (TEXT("SerialEventHandler, No Interrupt.\r\n")));
            break;
        }

        DEBUGMSG (ZONE_THREAD,
                  (TEXT("SerialEventHandler, Interrupts 0x%X\r\n"), it));
        if ( it & INTR_RX ) {
            // It's read data event. Optimize the read by reading chunks
            // if the user has not specified using xflow control
            // or event/error/eof characters. Ack the receive,
            // unmask the interrupt, get the current data pointer
            // and see if data is available.

            DEBUGMSG (ZONE_THREAD|ZONE_READ , (TEXT("Rx Event\r\n")));

            if ( RxRead(pSerialHead) == 0 ) {
                // have to leave one byte free.
                RoomLeft = RxLength(pSerialHead) - RxWrite(pSerialHead) - 1;
            } else {
                RoomLeft = RxLength(pSerialHead) - RxWrite(pSerialHead);
            }
            if ( RxRead(pSerialHead) > RxWrite(pSerialHead) ) {
                RoomLeft = RxRead(pSerialHead) - RxWrite(pSerialHead) - 1;
            }
            if ( RoomLeft ) {
                pSerialHead->DroppedBytesPDD +=
                pFuncTbl->HWRxIntrHandler(pHWHead,
                                          RxBuffWrite(pSerialHead),
                                          &RoomLeft);
            } else {
                BYTE    TempBuf[16];
                RoomLeft = 16;
                pFuncTbl->HWRxIntrHandler(pHWHead,
                                          TempBuf,
                                          &RoomLeft);

                pSerialHead->DroppedBytesMDD += RoomLeft;
                DEBUGMSG (ZONE_WARN|ZONE_READ, (TEXT("Tossed %d bytes\r\n"),
                                                RoomLeft));
                RoomLeft = 0;
            }

            DEBUGMSG (ZONE_READ ,
                      (TEXT("After HWGetBytes, Fifo(R=%d,W=%d,BA=%d,L=%d) ByteRead=%d\r\n"),
                       RxRead(pSerialHead), RxWrite(pSerialHead),
                       RxBytesAvail(pSerialHead), RxLength(pSerialHead),
                       RoomLeft));


            // If flow control enabled then we need to scan for XON/XOFF
            // characters
            if ( pSerialHead->XFlow ) {
                for ( CharIndex=0; CharIndex < RoomLeft; ) {
                    if ( RxBuffWrite(pSerialHead)[CharIndex] ==
                         pSerialHead->DCB.XoffChar ) {
                        DEBUGMSG (ZONE_FLOW, (TEXT("Received XOFF\r\n")));

                        pSerialHead->StopXmit = 1;
                        memmove (RxBuffWrite(pSerialHead)+CharIndex,
                                 RxBuffWrite(pSerialHead)+CharIndex+1,
                                 RoomLeft - CharIndex);
                        RoomLeft--;
                        continue;
                    } else if ( RxBuffWrite(pSerialHead)[CharIndex] ==
                                pSerialHead->DCB.XonChar ) {
                        pSerialHead->StopXmit = 0;
                        DEBUGMSG (ZONE_FLOW, (TEXT("Received XON\r\n")));

⌨️ 快捷键说明

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