/*++
*******************************************************************************
* Copyright (c) 1990-2000 Digi International Inc., All Rights Reserved                  *
*                                                                                                                                                                                                               *
* This software contains proprietary and confidential information of Digi               *
* International Inc.  By accepting transfer of this copy, Recipient agrees              *
* to retain this software in confidence, to prevent disclosure to others,               *
* and to make no use of this software other than that for which it was                  *
* delivered.  This is an unpublished copyrighted work of Digi International     *
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly     *
* prohibited.                                                                                                                                                                           *
*                                                                                                                                                                                                               *
* Restricted Rights Legend                                                                                                                                              *
*                                                                                                                                                                                                               *
* Use, duplication, or disclosure by the Government is subject to                                       *
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in                   *
* Technical Data and Computer Software clause at DFARS 252.227-7031 or                  *
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -                            *
* Restricted Rights at 48 CFR 52.227-19, as applicable.                                                         *
*                                                                                                                                                                                                               *
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343                            *
*                                                                                                                                                                                                               *
*******************************************************************************

Module Name:

   pppmodem.c

Abstract:

   Implementation of the DCD detection.
   

--*/
#include "digippp.h"
#include "wan_proto.h"
#include "wan_control.h"


VOID
MdmEngine(   
        IN PVOID hEngine )
/*++

Description:

        The worker bee routine which checks the carrier signal

--*/
{
    PDIGI_PPP_MDMENGINE pEngine = hEngine;
    PDIGI_PPP_ADAPTER   pAdapter = pEngine->pAdapter;
    BOOLEAN CalledConnend = FALSE;

    DigiDump( DIGIINIT, ( "PPP!MdmEngine: Starting.  pEngine 0x%x, pAdapter 0x%x\n", pEngine, pAdapter ) );

    ASSERT( pEngine->Type == DIGI_PPP_TYPE_MDMENGINE );
    ASSERT( pAdapter->Type == DIGI_PPP_TYPE_ADAPTER );
    ASSERT( pEngine->pDispatch && pEngine->pDispatch->OnConnend );

    for (;;)
    {
        DigiAcquireSpinLock( &pEngine->Lock );
        if ( pEngine->fHalt )
        {
            DigiDump( DIGIMDMENGINE, ( "PPP!MdmEngine: Halt detected, pEngine 0x%x \n", pEngine ) );
            DigiReleaseSpinLock( &pEngine->Lock );
            break;
        }
        DigiReleaseSpinLock( &pEngine->Lock );

        // Ask the card for current state of control signals (interested in DCD)
        {
            ULONG error;        
            NTSTATUS    status;
            struct wan_mdmioc modemIoctlBlock;
            modemIoctlBlock.snid = pEngine->pAdapter->Snid;
            modemIoctlBlock.mask = W_DCD ;
            modemIoctlBlock.signals = (ULONG) 0;

            status = DsIoctl( pEngine->hStream, W_GETMODEM, &modemIoctlBlock, sizeof(modemIoctlBlock), &error );
            if ( (!NT_SUCCESS(status) || !(modemIoctlBlock.signals & W_DCD)) && CalledConnend == FALSE ) {
                (*pEngine->pDispatch->OnConnend)(pEngine->hLine);
                CalledConnend = TRUE;
            }
        }
        
        NdisMSleep( 2*1000000 );        // 2s
    }
    
#ifdef STRATUS_DEVICE
    // This is the fix for windxb-189, PnP hang during system shutdown.
    if (CalledConnend == FALSE)
        (*pEngine->pDispatch->OnConnend)(pEngine->hLine);
#endif

    DigiDump( DIGIINIT, ( "PPP!MdmEngine: Stopped.  pEngine 0x%x, pAdapter 0x%x\n", pEngine, pAdapter ) );
}


VOID
MdmEngineStop( 
        IN PDIGI_PPP_MDMENGINE pEngine )
/*++

Description:

        Stops the modem signal thread.
--*/
{
    DigiDump( DIGIMDMENGINE, ( "PPP!MdmEngineStop: pEngine 0x%x\n", pEngine ) );

    if ( pEngine->fStarted )
    {
        DigiAcquireSpinLock( &pEngine->Lock );
        pEngine->fHalt = TRUE;
        DigiReleaseSpinLock( &pEngine->Lock );

        (void)KeWaitForSingleObject( pEngine->pThread, Executive, KernelMode, TRUE, 0 );
        ObDereferenceObject( pEngine->pThread );         
        pEngine->pThread = NULL; 

        pEngine->fStarted = FALSE;
    }
}


NTSTATUS
MdmEngineStart(
        IN PDIGI_PPP_MDMENGINE      pEngine,
        IN PDIGI_PPP_ADAPTER        pAdapter,
        IN HANDLE                   hLine,
        IN HANDLE                   hStream,
        IN PDIGI_PPP_EVENT_HANDLERS pDispatchTable
        )
/*++

Description:

        Starts the engine, which immediately starts sending Ioctl requests.  Requires a 
        previously opened dxb stream.

Parameters

        pEngine
                Address of struct to store engine parameters.

        pAdapter
                Address of adapter data

        hLine
                Line data

        hStream
                Previously opened dxb stream (opened via DsOpen or DsOpenEx).

        pDispatchTable
                Table of function pointers to handlers for incoming PPP messages and data.

--*/
{
    PKTHREAD hThread;
    PKTHREAD pThread;
    NTSTATUS Status;

    DigiDump( DIGIMDMENGINE, ( "PPP!MdmEngineStart: pEngine 0x%x\n", pEngine) );

    pEngine->Type         = DIGI_PPP_TYPE_MDMENGINE;
    pEngine->hStream      = hStream;
    pEngine->fHalt        = FALSE;
    pEngine->pAdapter     = pAdapter;
    pEngine->hLine        = hLine;
    pEngine->pDispatch    = pDispatchTable;

    DigiInitializeSpinLock( &pEngine->Lock );

    Status = PsCreateSystemThread( &hThread, THREAD_ALL_ACCESS, NULL, 0, NULL, MdmEngine, pEngine );
    if ( NT_SUCCESS( Status ) )
    {
        Status = ObReferenceObjectByHandle( hThread, THREAD_ALL_ACCESS, NULL, KernelMode, &pThread, NULL );
        ZwClose( hThread );

        if ( NT_SUCCESS( Status ) )
        {
            pEngine->fStarted = TRUE;
            pEngine->pThread = pThread;
        }
        else
        {
            // Tell thread to stop.  
            DigiDump( DIGIERROR, ( "PPP!MdmEngineStart: ObReferenceObject failed, status 0x%x\n", Status ) );
            pEngine->fHalt = TRUE;
        }
    }
    return Status;
}


NTSTATUS
MdmDropDtrRts(
        IN PDIGI_PPP_LINE pLine )
{
    struct wan_mdmioc modemIoctlBlock = {0};
    NTSTATUS        status; 
    ULONG error;
    DigiDump( DIGIMDMENGINE, ( "PPP!MdmDropDrRts: pLine 0x%x\n", pLine ) );

    modemIoctlBlock.snid = pLine->Snid;
    modemIoctlBlock.signals = ~(W_DTR | W_RTS);
    modemIoctlBlock.mask = W_DTR | W_RTS;
    status = DsIoctl( pLine->hStream, W_SETMODEM, &modemIoctlBlock, sizeof modemIoctlBlock, &error );
    return status;
}


NTSTATUS
MdmRaiseDtrRts(
        IN PDIGI_PPP_LINE pLine )
{
    struct wan_mdmioc modemIoctlBlock = {0};
    NTSTATUS        status; 
    ULONG error;
        
    DigiDump( DIGIMDMENGINE, ( "PPP!MdmRaiseDrRts: pLine 0x%x\n", pLine ) );        
    modemIoctlBlock.snid = pLine->Snid;
    modemIoctlBlock.signals = modemIoctlBlock.mask = W_DTR | W_RTS;
    status = DsIoctl( pLine->hStream, W_SETMODEM, &modemIoctlBlock, sizeof modemIoctlBlock, &error );
    return status;
}
