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

📄 mdd.c

📁 wince4.2 USB function driver for magic eye mmsp2 platform
💻 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 amout 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
SerialDllEntry
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>

/* 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

#define ZONE_WRITE		1
#define ZONE_FUNCTION	1

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 cout 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 | SerialDllEntry | Process attach/detach api.
 *
 @rdesc The return is a BOOL, representing success (TRUE) or failure (FALSE).
 */
BOOL
SerialDllEntry(
              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);
}

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
// 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 ( it = pFuncTbl->HWGetIntrType(pHWHead) ) {
        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
            // Note: We have to copy RxRead and RxWrite index to local in order to make it atomic.
            register DWORD RxWIndex=RxWrite(pSerialHead), RxRIndex=RxRead(pSerialHead);

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

            RxEnterCS(pSerialHead);
            if ( RxRIndex == 0 ) {
                // have to leave one byte free.
                RoomLeft = RxLength(pSerialHead) - RxWIndex - 1;
            } else {
                RoomLeft = RxLength(pSerialHead) - RxWIndex;
            }
            if ( RxRIndex > RxWIndex ) {
                RoomLeft = RxRIndex - RxWIndex - 1;
            }
            if ( RoomLeft ) {
                pSerialHead->DroppedBytesPDD +=
                pFuncTbl->HWGetBytes(pHWHead,
                                     RxBuffWrite(pSerialHead),
                                     &RoomLeft);
            } else {
                BYTE    TempBuf[16];
                RoomLeft = 16;
                pFuncTbl->HWGetBytes(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")));
                        memmove (RxBuffWrite(pSerialHead)+CharIndex,
                                 RxBuffWrite(pSerialHead)+CharIndex+1,
                                 RoomLeft - CharIndex);
                        RoomLeft--;
                        continue;
                    }
                    CharIndex++;
                }
            }

            pSerialHead->RxBytes += RoomLeft;
            RxWrite(pSerialHead) = 
                (RxWrite(pSerialHead)+RoomLeft<RxLength(pSerialHead)? RxWrite(pSerialHead)+RoomLeft: RxWrite(pSerialHead)+RoomLeft-RxLength(pSerialHead));

            RxLeaveCS(pSerialHead);

            if ( RoomLeft ) {
                RxDataAvail = TRUE;
            }

            /* Support DTR_CONTROL_HANDSHAKE/RTS_CONTROL_HANDSHAKE
             * signal is cleared when the input buffer is more than 3/4 full.
             */
            if ( (pSerialHead->DCB.fDtrControl == DTR_CONTROL_HANDSHAKE) &&
                 (!pSerialHead->DtrFlow) && 
                 (4*RxBytesAvail(pSerialHead) > (3*RxLength(pSerialHead))) ) {
                DEBUGMSG (ZONE_READ|ZONE_FLOW,
                          (TEXT("DTR_CONTROL_HANDSHAKE Clearing DTR\r\n")));
                pSerialHead->DtrFlow = 1;
                pFuncTbl->HWClearDTR(pHWHead);
            }
            if ( (pSerialHead->DCB.fRtsControl == RTS_CONTROL_HANDSHAKE) &&
                 (!pSerialHead->RtsFlow) &&
                 (4*RxBytesAvail(pSerialHead) > (3*RxLength(pSerialHead))) ) {
                DEBUGMSG (ZONE_READ|ZONE_FLOW,
                          (TEXT("RTS_CONTROL_HANDSHAKE Clearing RTS\r\n")));
                pSerialHead->RtsFlow = 1;
                pFuncTbl->HWClearRTS(pHWHead);
            }

            /* If Xon/Xoff flow control is desired. check the limit against
             * the remaining room and act accordingly.
             */
            if ( pSerialHead->DCB.fInX && !(pSerialHead->SentXoff) &&
                 ( pSerialHead->DCB.XoffLim >=
                   (RxLength(pSerialHead) - RxBytesAvail(pSerialHead))) ) {
                DEBUGMSG (ZONE_FLOW, (TEXT("Sending XOFF\r\n")));
                pFuncTbl->HWXmitComChar(pHWHead, pSerialHead->DCB.XoffChar);

                pSerialHead->SentXoff = 1;
                if ( !pSerialHead->DCB.fTXContinueOnXoff ) {
                    pSerialHead->StopXmit = 1;
                }
            }

        }

        if ( it & INTR_TX ) {
            /* If the transmit interrupt bit is set in the serial CSR, then
             * it must be a transmit interrupt, so call the HW tx handler,
             * unmask the interrupt and then notify SerialTransmit() that if
             * it has a PutBytes pending, it can do that now.
             */
            DEBUGMSG (ZONE_THREAD, (TEXT("Transmit Event\r\n")));

            /* Call the hardware Tx interrupt handler since the hardware
             * has interrupted.
             */
            pFuncTbl->HWTxIntrHandler(pHWHead);
            SetEvent(pSerialHead->hTransmitEvent);
        }

        if ( (it & INTR_MODEM) ) {
            DEBUGMSG (ZONE_THREAD, (TEXT("Other Event, it:%x\r\n"), it));

            /* Call low level status clean up code.
             */
            pFuncTbl->HWOtherIntrHandler(pHWHead);
        }

        if ( it & INTR_LINE ) {
            DEBUGMSG (ZONE_THREAD, (TEXT("Line Event, it:%x\r\n"), it));

            /* Call low level line status clean up code.
             * Then unmask the interrupt
             */
            pFuncTbl->HWLineIntrHandler(pHWHead);
        }
    }

    // We kept this till the end to optimize the above loop
    if ( RxDataAvail ) {
        // Signal COM_Read that bytes are available.
        SetEvent(pSerialHead->hReadEvent);
        EvaluateEventFlag(pSerialHead, EV_RXCHAR);
    }

    DEBUGMSG (ZONE_THREAD ,
              (TEXT("-SerialEventHandler, Fifo(R=%d,W=%d,L=%d)\r\n"),
               RxRead(pSerialHead), RxWrite(pSerialHead),
               RxLength(pSerialHead)));

    if ( pSerialHead->pAccessOwner )
        COM_DEC_USAGE_CNT(pSerialHead->pAccessOwner);
    return;
}

⌨️ 快捷键说明

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