//
// 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.
//
// 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:  usbfndrv.cpp

Abstract:

    Serial PDD Common Code.

Notes: 
--*/

#include <windows.h>
#include <types.h>
#include <memory.h>
#include <notify.h>
#include <devload.h>
#include <windev.h>
#include <serdbg.h>
#include <serhw.h>

#include "s2440.h"
#include <nkintr.h>
#include <ceddk.h>
#include <drv_glob.h>
#include <2440usb.h>
#include <usbfndrv.h>

CUsbFuncTransfer::CUsbFuncTransfer(CUsbFuncPipe *hPipe, DWORD dwFlags,DWORD cbBuffer, PVOID pvBuffer, DWORD dwBufferPhysicalAddress)
:   m_pPipe(hPipe)
,   m_dwFlags(dwFlags)
,   m_dwBufferSize (cbBuffer)
,   m_pvBuffer (pvBuffer)
,   m_dwPhysAddr (dwBufferPhysicalAddress)
{
    ASSERT(hPipe!=NULL);
    ASSERT(cbBuffer!=NULL);
    ASSERT(pvBuffer!=NULL);
    m_hCompleteEvent=CreateEvent(NULL, TRUE, FALSE, NULL); // Manual Reset and Initial FALSE
    m_ufnTransfer = NULL;
    

}
CUsbFuncTransfer::~CUsbFuncTransfer()
{
    if (m_pPipe) {
        if ( m_ufnTransfer) {
            if (!IsTransferComplete()) { // We need Cancel it.
                AbortTransfer();
            }
            CloseTransfer();
        }
    }
    if (m_hCompleteEvent) {
        CloseHandle(m_hCompleteEvent);
    }
}
BOOL CUsbFuncTransfer::Init()
{
    return (m_pPipe && m_pPipe->GetFunctionPtr() && m_hCompleteEvent);
}
BOOL CUsbFuncTransfer::IssueTransfer(DWORD dwLength)
{
    PREFAST_ASSERT(m_pPipe);
    PREFAST_ASSERT(m_pPipe->GetFunctionPtr());
    if (dwLength>GetBufferSize())
        dwLength = GetBufferSize();
    
    if (IsTransferClosed()) {
        ResetEvent(m_hCompleteEvent);
        DWORD dwRet =m_pPipe->GetFunctionPtr()->lpIssueTransfer(
                m_pPipe->GetDeviceHandle(),m_pPipe->GetPipeHandle(),CompleteNotificationStub,this,m_dwFlags,
                dwLength,m_pvBuffer,m_dwPhysAddr, NULL, &m_ufnTransfer);
        DEBUGMSG (ZONE_EVENTS,(TEXT("CUsbFuncTransfer::IssueTransfer(Handle=0x%x,flags =0x%x size=0x%x)\r\n"),
            m_ufnTransfer,m_dwFlags, dwLength));
//        ASSERT(dwRet == ERROR_SUCCESS);
        return(dwRet == ERROR_SUCCESS);     
    }
    else
        return FALSE;
}

BOOL CUsbFuncTransfer::WaitForTransferComplete(DWORD dwTicks)
{
    PREFAST_ASSERT(m_hCompleteEvent!=NULL);
    if (!IsTransferClosed()) {
       return ( WaitForSingleObject(m_hCompleteEvent , dwTicks) == WAIT_OBJECT_0);
    }
    else
        return TRUE;
}
BOOL  CUsbFuncTransfer::GetTransferStatus(PDWORD pdwBytesTranfered, PDWORD pdwError)
{
    PREFAST_ASSERT(m_pPipe);
    PREFAST_ASSERT(m_pPipe->GetFunctionPtr());
    if (!IsTransferClosed()) {
        DWORD dwRet = m_pPipe->GetFunctionPtr()->lpGetTransferStatus(m_pPipe->GetDeviceHandle(),m_ufnTransfer,pdwBytesTranfered,pdwError);
        ASSERT(dwRet == ERROR_SUCCESS);
        return(dwRet == ERROR_SUCCESS);     
    }
    else {
        if (pdwError)
            *pdwError = UFN_NOT_COMPLETE_ERROR;
        if (pdwBytesTranfered)
            *pdwBytesTranfered = 0;
        return FALSE;
    }
}
BOOL CUsbFuncTransfer::CloseTransfer()
{
    PREFAST_ASSERT(m_pPipe);
    PREFAST_ASSERT(m_pPipe->GetFunctionPtr());
    if (!IsTransferClosed()) {
        DWORD dwRet = m_pPipe->GetFunctionPtr()->lpCloseTransfer(m_pPipe->GetDeviceHandle(),m_ufnTransfer);
        ASSERT(dwRet == ERROR_SUCCESS);
        m_ufnTransfer = NULL;
        return(dwRet == ERROR_SUCCESS);     
    }
    else
        return TRUE;
    
}
BOOL CUsbFuncTransfer::AbortTransfer()
{
    PREFAST_ASSERT(m_pPipe);
    PREFAST_ASSERT(m_pPipe->GetFunctionPtr());
    if (!IsTransferComplete()) {
        DWORD dwRet = m_pPipe->GetFunctionPtr()->lpAbortTransfer(m_pPipe->GetDeviceHandle(),m_ufnTransfer);
        DEBUGMSG (ZONE_EVENTS,(TEXT("CUsbFuncTransfer::AbortTransfer(Handle=0x%x,flags =0x%x )\r\n"),
            m_ufnTransfer,m_dwFlags));
        ASSERT(dwRet == ERROR_SUCCESS);
        return(dwRet == ERROR_SUCCESS);             
    }
    else
        return TRUE;
}
DWORD WINAPI CUsbFuncTransfer::CompleteNotificationStub(PVOID pvNotifyParameter)
{
    DEBUGMSG (ZONE_EVENTS,(TEXT("CUsbFuncTransfer::CompleteNotificationStub(pv=0x%x)\r\n"),pvNotifyParameter));
    ASSERT(pvNotifyParameter);
    if (pvNotifyParameter) {
        return ((CUsbFuncTransfer *)pvNotifyParameter) -> CompleteNotification();
    }
    else {
        ASSERT(FALSE);
        return ERROR_INVALID_DATA;
    }
}

DWORD  WINAPI  CUsbFuncTransfer::CompleteNotification()
{
    PREFAST_ASSERT(m_hCompleteEvent!=NULL);
    PREFAST_ASSERT(m_pPipe);
    if (!IsTransferClosed()) {
        SetEvent(m_hCompleteEvent);
        m_pPipe->TransferComplete(this);
        return ERROR_SUCCESS;
    }
    else {
        ASSERT(FALSE);
        return ERROR_INVALID_DATA;
    }
}

//------------------------------------------------Pipe ----------------------------------------------
CUsbFuncPipe::CUsbFuncPipe(USBSerialFn * pSerialFn, UFN_HANDLE hDevice,PCUFN_FUNCTIONS pUfnFuncs,UCHAR bEndpointAddr,BOOL fRead,DWORD dwMaxPacketSize, DWORD dwMaxTransferSize, DWORD dwMaxNumOfTransfer)
:   CMiniThread (0, TRUE) 
,   m_pSerialFn (pSerialFn)
,   m_hDevice ( hDevice)
,   m_pUfnFuncs(pUfnFuncs)
,   m_bEndpointAddr(bEndpointAddr)
,   m_fRead ( fRead )
,   m_dwMaxPacketSize ( dwMaxPacketSize )
,   m_dwTranferSize(dwMaxTransferSize)
,   m_dwNumOfTransfer(min(MAX_TRANSFER,dwMaxNumOfTransfer))
{
    // Calculate buffer needed.
    m_dwBufferSize = m_dwNumOfTransfer*m_dwTranferSize;
    m_pbBuffer = new BYTE[m_dwBufferSize ];
    m_dwBufferPhysAddr = 0; 
    for (DWORD dwIndex = 0; dwIndex<  MAX_TRANSFER; dwIndex ++)
        m_pTransferArray[dwIndex] = NULL;
    m_dwWriteIndex = m_dwCompleteIndex = 0;
    m_dwCurPosition = 0;
    m_fZeroLengthNeeded = FALSE;
    m_TerminateEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // Manual Reset and Initial FALSE
    m_hPipe = NULL;
}
BOOL CUsbFuncPipe::Init()
{
    if (m_TerminateEvent && m_pbBuffer ) {
        Lock();
        ThreadStart();
        Unlock();
        return TRUE;
    }
    return FALSE;
}
CUsbFuncPipe::~CUsbFuncPipe()
{
    Lock();
    m_bTerminated = TRUE;
    ThreadStart();
    if (m_TerminateEvent) {
        SetEvent(m_TerminateEvent);
    }
    Unlock();
    BOOL fRet=WaitThreadComplete(1000);
//    ASSERT(fRet == TRUE);
    Lock();
    ClosePipe();
    if (m_pbBuffer!=NULL) {
        delete m_pbBuffer;
    }
    if ( m_TerminateEvent)
        CloseHandle(m_TerminateEvent);
    Unlock();
}
BOOL CUsbFuncPipe::OpenPipe()
{
    Lock();
    if (m_hPipe==NULL) {
        DWORD dwRet = m_pUfnFuncs->lpOpenPipe(m_hDevice,  m_bEndpointAddr, &m_hPipe);
        if (dwRet != ERROR_SUCCESS) {
            m_hPipe = NULL;
            ASSERT(FALSE);
        }
        if (m_hPipe != NULL) {
            m_dwWriteIndex = m_dwCompleteIndex = 0;
            BOOL fReturn = TRUE;
            for (DWORD dwIndex = 0; dwIndex<m_dwNumOfTransfer; dwIndex ++) {
                m_pTransferArray[dwIndex] = new CUsbFuncTransfer(this,
                        m_fRead? USB_OUT_TRANSFER: USB_IN_TRANSFER ,
                        m_dwTranferSize,
                        m_pbBuffer + (dwIndex*m_dwTranferSize),
                        m_dwBufferPhysAddr!=0?(m_dwBufferPhysAddr+(dwIndex*m_dwTranferSize)): 0 ) ;
                if (m_pTransferArray[dwIndex]!= NULL && m_pTransferArray[dwIndex]->Init()== TRUE ) { // Successful
                    if (m_fRead) { // Lauch Issue Transfer first.
                        if (!m_pTransferArray[dwIndex]->IssueTransfer()) {
                            ASSERT(FALSE);
                            fReturn = FALSE;
                            break;
                        }
                    }                
                }
                else {
                    ASSERT(FALSE);
                    fReturn = FALSE;
                    break;
                }
            }
            if (!fReturn) { // Fail on Open Pipe or on Transfer.
                ClosePipe();
            }
        }
    }
    if (m_hPipe)
        SetEvent(m_TerminateEvent);
    Unlock();
    return (m_hPipe!=NULL);
}
void CUsbFuncPipe::ClosePipe()
{
    Lock();
    if (m_hPipe!=NULL) {
        // Delete Transfer In order is required.
        DWORD dwIndex = m_dwCompleteIndex;
        do {
            if (m_pTransferArray[dwIndex]!=NULL) {
                delete m_pTransferArray[dwIndex];
                m_pTransferArray[dwIndex] = NULL;
            }
            dwIndex= (dwIndex!=0?dwIndex-1:m_dwNumOfTransfer-1);
        }
        while (dwIndex !=m_dwCompleteIndex ) ;
        m_pUfnFuncs->lpClosePipe(m_hDevice, m_hPipe);
    }
    m_hPipe = NULL;
    Unlock();
}


DWORD CUsbFuncPipe::ReadData(PUCHAR pRxBuffer,ULONG *pBufflen)
{
    DWORD dwBytesDropped = 0;
    Lock();
    if (m_hPipe != NULL && m_fRead && pRxBuffer && pBufflen && *pBufflen) {
        DEBUGMSG (ZONE_READ,(TEXT("+CUsbFuncPipe::ReadData (0x%x,0x%x)\r\n"),pRxBuffer, pBufflen?*pBufflen:0));
        DWORD dwRoomLeft = *pBufflen;
        DWORD dwBytesStored = 0;
        PREFAST_ASSERT(m_pTransferArray[m_dwCompleteIndex] != NULL);
        DWORD dwBytes=0;
        DWORD dwError=UFN_NO_ERROR;
        if ( !m_pTransferArray[m_dwCompleteIndex]->IsTransferClosed() &&
                m_pTransferArray[m_dwCompleteIndex]->IsTransferComplete() &&
                m_pTransferArray[m_dwCompleteIndex]->GetTransferStatus(&dwBytes, &dwError) &&
                dwError == UFN_NO_ERROR ) {
            PBYTE pBuffer = (PBYTE)m_pTransferArray[m_dwCompleteIndex]->GetBufferPtr();
            while (dwRoomLeft && m_dwCurPosition < dwBytes ) { // Then we have some work to do.
                BYTE bData = pBuffer[m_dwCurPosition++];
                if (m_pSerialFn == NULL || (m_pSerialFn->DataReplaced(&bData,FALSE))) {
                     *pRxBuffer++ = bData;
                     dwRoomLeft --;
                     dwBytesStored ++;
                }
            }
            if (m_dwCurPosition >= dwBytes) { // This transfer has been completely unloaded.
                m_pTransferArray[m_dwCompleteIndex]->CloseTransfer();
                m_pTransferArray[m_dwCompleteIndex]->IssueTransfer();
                // Advance to next one.
                m_dwCompleteIndex = IncIndex(m_dwCompleteIndex);
                m_dwCurPosition = 0;
            }
        }
        else {
//            ASSERT(FALSE);
            if (!m_pTransferArray[m_dwCompleteIndex]->IsTransferClosed()) {
                m_pTransferArray[m_dwCompleteIndex]->AbortTransfer();
                m_pTransferArray[m_dwCompleteIndex]->CloseTransfer();
                m_pTransferArray[m_dwCompleteIndex]->IssueTransfer();
            }
            dwBytesDropped = m_pTransferArray[m_dwCompleteIndex]->GetBufferSize();
            m_dwCompleteIndex = IncIndex(m_dwCompleteIndex);
            m_dwCurPosition = 0;
        }
        *pBufflen = dwBytesStored;
        DEBUGMSG (ZONE_READ,(TEXT("-CUsbFuncPipe::ReadData (0x%x,0x%x) return drop=%x\r\n"),pRxBuffer, pBufflen?*pBufflen:0,dwBytesDropped));
    }
    else
        ASSERT(FALSE);
    Unlock();
    return dwBytesDropped ;
}
// 
//WriteDataOnce:
//   It generates one Transfer if transfer that indexed by m_dwWriteIndex is not used.
//
void CUsbFuncPipe::WriteDataOnce(PUCHAR pTxBuffer, ULONG *pBuffLen) 
{
    Lock();
    DEBUGMSG (ZONE_WRITE,(TEXT("+CUsbFuncPipe::WriteDataOnce (0x%x,0x%x) , m_fZeroLengthNeeded =%d \r\n"),
        pTxBuffer,pBuffLen?*pBuffLen:0,m_fZeroLengthNeeded));
    PREFAST_ASSERT(pBuffLen!=NULL);
    if (m_pTransferArray[m_dwCompleteIndex]->IsTransferComplete()) {
        m_pTransferArray[m_dwCompleteIndex]->CloseTransfer();
        m_dwCompleteIndex = IncIndex(m_dwCompleteIndex);
    }
    // Next Xmit Transfer
    if (m_pTransferArray[m_dwWriteIndex]->IsTransferClosed()) {
        if (pTxBuffer && pBuffLen && *pBuffLen) {
            DWORD dwInputLength = min(*pBuffLen,m_pTransferArray[m_dwWriteIndex]->GetBufferSize());
            memcpy(m_pTransferArray[m_dwWriteIndex]->GetBufferPtr(),pTxBuffer, dwInputLength);
            m_pTransferArray[m_dwWriteIndex]->IssueTransfer(dwInputLength);
            m_fZeroLengthNeeded = ((dwInputLength  & (m_dwMaxPacketSize-1)) == 0 );
            DEBUGMSG (ZONE_WRITE,(TEXT("CUsbFuncPipe::WriteDataOnce: MaxPacketSize=%d,dwInputLength=%d , m_fZeroLengthNeeded =%d \r\n"),
                m_dwMaxPacketSize,dwInputLength, m_fZeroLengthNeeded));
            m_dwWriteIndex = IncIndex(m_dwWriteIndex);
            SetEvent(m_TerminateEvent);
            *pBuffLen = dwInputLength;
        }
        else {
            if (m_fZeroLengthNeeded) { // Send 0 Length Packet.
                m_pTransferArray[m_dwWriteIndex]->IssueTransfer(0);
                m_dwWriteIndex = IncIndex(m_dwWriteIndex);
                SetEvent(m_TerminateEvent);
            }
            m_fZeroLengthNeeded = FALSE;
            *pBuffLen = 0;
        }
    }
    else
        *pBuffLen = 0;
    DEBUGMSG (ZONE_WRITE,(TEXT("-CUsbFuncPipe::WriteDataOnce (0x%x,0x%x) , m_fZeroLengthNeeded =%d \r\n"),
        pTxBuffer,pBuffLen?*pBuffLen:0,m_fZeroLengthNeeded));
    Unlock();
}
//
// WriteData:
//   It generate multiple Transfer when free transfer and data available.
//
void CUsbFuncPipe::WriteData(PUCHAR pTxBuffer, ULONG *pBuffLen) 
{
    Lock();
    DEBUGMSG (ZONE_WRITE,(TEXT("+CUsbFuncPipe::WriteData (0x%x,0x%x)\r\n"), pTxBuffer,pBuffLen?*pBuffLen:0));
    DWORD dwLeft =(pBuffLen?*pBuffLen:0);
    if (!m_fRead) {
        DWORD dwBytes ;
        do {
            dwBytes =  dwLeft;
            WriteDataOnce(pTxBuffer,&dwBytes);
            pTxBuffer += dwBytes;
            if (dwLeft >= dwBytes)
                dwLeft -= dwBytes;
            else 
                dwLeft = 0;
        } while (dwBytes!=0);
    }
    else
        ASSERT(FALSE);
    if (pBuffLen)
        *pBuffLen -= dwLeft;
    Unlock();
    DEBUGMSG (ZONE_WRITE,(TEXT("-CUsbFuncPipe::WriteData (0x%x,0x%x)\r\n"), pTxBuffer,pBuffLen?*pBuffLen:0));

}
BOOL  CUsbFuncPipe::CancelTransfer()
{
    Lock();
    if (m_fRead) {
        while (m_pTransferArray[m_dwCompleteIndex] && !m_pTransferArray[m_dwCompleteIndex]->IsTransferClosed() &&
                m_pTransferArray[m_dwCompleteIndex]->IsTransferComplete()) {
            m_pTransferArray[m_dwCompleteIndex]->CloseTransfer();
            m_pTransferArray[m_dwCompleteIndex]->IssueTransfer();
            // Advance to next one.
            m_dwCompleteIndex = IncIndex(m_dwCompleteIndex);
            m_dwCurPosition = 0;
        }
    }
    else {
        while (m_pTransferArray[m_dwCompleteIndex] && !m_pTransferArray[m_dwCompleteIndex]->IsTransferClosed()) {
            if (!m_pTransferArray[m_dwCompleteIndex]->IsTransferComplete())
                m_pTransferArray[m_dwCompleteIndex]->AbortTransfer();
            m_pTransferArray[m_dwCompleteIndex]->CloseTransfer();
            m_dwCompleteIndex = IncIndex(m_dwCompleteIndex);
        }
    }
    SetEvent(m_TerminateEvent);
    Unlock();
    return TRUE;
}

BOOL CUsbFuncPipe::IsAnySpaceAvailable()
{
    BOOL fReturn = FALSE;
    if (!m_fRead) {
        Lock();
        fReturn =(m_pTransferArray[m_dwWriteIndex]!=NULL 
                    && m_pTransferArray[m_dwWriteIndex]->IsTransferComplete());
        Unlock();
    }
    return fReturn;
}

DWORD CUsbFuncPipe::ThreadRun()
{
    while (m_TerminateEvent && ! IsTerminated()) {
        Lock();
        if (m_pTransferArray[m_dwCompleteIndex] && !m_pTransferArray[m_dwCompleteIndex]->IsTransferClosed()) {
            HANDLE rgh[2];
            rgh[0] = m_pTransferArray[m_dwCompleteIndex]->GetCompleteEventHandle();
            rgh[1] = m_TerminateEvent;
            Unlock();
            WaitForMultipleObjects(dim(rgh),rgh,FALSE,INFINITE);
            Lock();
        }
        else {
            Unlock();
            WaitForSingleObject(m_TerminateEvent,INFINITE);
            Lock();
        }
        if (m_pTransferArray[m_dwCompleteIndex] && !IsTerminated()) {
            DWORD dwCurIndex = m_dwCompleteIndex;
            if (!m_pTransferArray[dwCurIndex]->IsTransferClosed() && 
                    m_pTransferArray[dwCurIndex]->IsTransferComplete()) {
                Unlock();
                if (m_pSerialFn)
                    m_pSerialFn->EndpointNotification(this);                    
                Lock();
            }            
        }
        Unlock();
    }
    return (1);
}
//--------------------------USB FN Serial Driver -------------------------------------------
USBSerialFn::USBSerialFn(LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj )
:   CSerialPDD(lpActivePath, pMdd,  pHwObj  )
,   CUsbFn (lpActivePath)
{
    PREFAST_ASSERT(lpActivePath!=NULL);
    m_pBulkIn = NULL;
    m_pBulkOut = NULL;
    m_pInterruptIn = NULL;
    m_bOldHostModemStatus = m_curHostModemStatus = 0;
    m_bModemSetState[0]=m_bModemSetState[1]=0;
}
USBSerialFn::~USBSerialFn()
{
    if ( m_pBulkIn) {
//        ASSERT(FALSE);
        delete m_pBulkIn;
    }
    if ( m_pBulkOut ) {
//        ASSERT(FALSE);
        delete m_pBulkOut;
    }
    if (m_pInterruptIn ) {
//        ASSERT(FALSE);
        delete m_pInterruptIn;
            
    }
}
BOOL USBSerialFn::Init()
{
    BOOL fReturn = TRUE;
    fReturn = (CUsbFn::Init() && CSerialPDD::Init());
    ASSERT(fReturn);
    return fReturn;
};
BOOL USBSerialFn::EndpointNotification(CUsbFuncPipe * pPipe)
{
    if (pPipe!=NULL) {
        DWORD interruptType =  INTR_NONE;
        m_HardwareLock.Lock();
        if ( pPipe == m_pBulkIn) { // Device to Host.
            interruptType |= INTR_TX;
        }
        else 
        if ( pPipe == m_pBulkOut){ // Host to Device.
            interruptType |= INTR_RX;
        }
        if (pPipe == m_pInterruptIn) {
            if ( m_pInterruptIn->IsAnySpaceAvailable()) {
                if (m_bOldModemState !=m_bModemSetState[0]) {
                    DWORD dwLength = sizeof(m_bModemSetState);
                    m_bModemSetState [0] |= USBFN_SERIAL_DATA_AVAILABLE; // Always set data available.
                    m_pInterruptIn->WriteData(m_bModemSetState,&dwLength);
                    m_bOldModemState =  m_bModemSetState[0];
                }
                else
                    m_pInterruptIn->WriteData(NULL,NULL);
            }
            else
                ASSERT(FALSE);
            
        }
        m_HardwareLock.Unlock(); 
        return NotifyPDDInterrupt((INTERRUPT_TYPE)interruptType);
    }
    return FALSE;
}
/*BOOL USBSerialFn::InitXmit(BOOL bInit) 
{
    m_HardwareLock.Lock();
    BOOL bReturn = FALSE;
    if (m_pBulkIn) {
        if (bInit)
            bReturn = m_pBulkIn->OpenPipe();
        else {
            m_pBulkIn->ClosePipe();
            bReturn = TRUE;
        }
        ASSERT(bReturn);
    }
    m_HardwareLock.Unlock();
    return bReturn;
};
*/
void    USBSerialFn::XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen)
{
    m_HardwareLock.Lock();
    if (m_pBulkIn) {
        if ((m_DCB.fOutxCtsFlow && IsCTSOff()) ||(m_DCB.fOutxDsrFlow && IsDSROff())) { // We are in flow off
            DEBUGMSG(ZONE_THREAD|ZONE_WRITE,(TEXT("USBSerialFn::XmitInterruptHandler! Flow Off, Data Discard.\r\n")));
            if (pBuffLen)
                *pBuffLen= 0;
        }
        else
            m_pBulkIn->WriteData(pTxBuffer,pBuffLen);
    }
    m_HardwareLock.Unlock();
};
void    USBSerialFn::XmitComChar(UCHAR ComChar) 
{
    DWORD dwLength = 1; // We can not do special.
    BOOL fReturn = FALSE;
    while (fReturn) {
        m_HardwareLock.Lock();
        if (m_pBulkIn) {
            if (m_pBulkIn->IsAnySpaceAvailable()) {
                m_pBulkIn->WriteData(&ComChar,&dwLength);
                fReturn = FALSE;
            }
        }
        else 
            fReturn = FALSE;
        m_HardwareLock.Unlock();
        if (!fReturn)
            Sleep(10);
    }    
}
BOOL USBSerialFn::CancelXmit()
{
    m_HardwareLock.Lock();
     if (m_pBulkIn) {
        m_pBulkIn->CancelTransfer();
    }
    m_HardwareLock.Unlock();
    return TRUE;
}

/*BOOL    USBSerialFn::InitReceive(BOOL bInit)
{
    m_HardwareLock.Lock();
    BOOL bReturn = FALSE;
    if (m_pBulkOut) {
        if (bInit)
            bReturn = m_pBulkOut->OpenPipe();
        else {
            m_pBulkOut->ClosePipe();
            bReturn = TRUE;
        }
        ASSERT(bReturn);
    }
    m_HardwareLock.Unlock();
    return bReturn;
}
*/
ULONG   USBSerialFn::ReceiveInterruptHandler(PUCHAR pRxBuffer,ULONG *pBufflen)
{
    DWORD dwReturn = 0;
    m_HardwareLock.Lock();
    if (m_pBulkOut) {
        dwReturn = m_pBulkOut->ReadData(pRxBuffer,pBufflen);
    }
    m_HardwareLock.Unlock();
    return dwReturn;
}
ULONG   USBSerialFn::CancelReceive()
{
    m_HardwareLock.Lock();
     if (m_pBulkIn) {
        m_pBulkIn->CancelTransfer();
    }
    m_HardwareLock.Unlock();
    return TRUE;
}

/*BOOL    USBSerialFn::InitModem(BOOL bInit)
{
    m_HardwareLock.Lock();
    BOOL bReturn = FALSE;
    if (m_pInterruptIn) {
        if (bInit)
            bReturn = m_pInterruptIn->OpenPipe();
        else{
            m_pInterruptIn->ClosePipe();
            bReturn = TRUE;
        }
    }
    m_bOldModemState = m_bModemSetState[0]= m_bModemSetState[1] = USBFN_SERIAL_DATA_AVAILABLE;
    m_HardwareLock.Unlock();
    return bReturn;
}
*/
void USBSerialFn::SetModemSignal(BOOL bSet, BYTE bBitSet)
{
    m_HardwareLock.Lock();
    if (bSet)
        m_bModemSetState[0] |= bBitSet;
    else
        m_bModemSetState[0] &= ~bBitSet;
    
    if (m_pInterruptIn && m_bOldModemState !=m_bModemSetState[0] && m_pInterruptIn->IsAnySpaceAvailable()) {
        DWORD dwLength = sizeof(m_bModemSetState);
        m_bModemSetState [0] |= USBFN_SERIAL_DATA_AVAILABLE;
        m_pInterruptIn->WriteData(m_bModemSetState,&dwLength);
        m_bOldModemState =  m_bModemSetState[0];
    }
    m_HardwareLock.Unlock();

}
ULONG   USBSerialFn::GetModemStatus() 
{ 
    m_HardwareLock.Lock();
    ULONG Events = 0;
    m_bOldHostModemStatus ^= m_curHostModemStatus; 
    if ( m_bOldHostModemStatus & MS_DSR_ON)
        Events |= EV_DSR;
    if ( m_bOldHostModemStatus & MS_RLSD_ON)
        Events |= EV_RLSD;
    if ( m_bOldHostModemStatus & MS_CTS_ON)
        Events |= EV_CTS;
    m_bOldHostModemStatus = m_curHostModemStatus;
    m_HardwareLock.Unlock();
    if (Events)
        EventCallback(Events,m_curHostModemStatus);        
    return m_curHostModemStatus;
};

//
// D A T A / M A C R O S
//
#define MAX_INTERRUPT_ENDPOINT_PACKET_SIZE 8
#define CB_CONFIG_DESCRIPTOR  (sizeof(USB_CONFIGURATION_DESCRIPTOR)+sizeof(USB_INTERFACE_DESCRIPTOR)+3*sizeof(USB_ENDPOINT_DESCRIPTOR))
//  definitions
#define COMMAND_PASSED                      0x00
#define COMMAND_FAILED                      0x01
#define PHASE_ERROR                         0x02

#define EP0_PACKET_SIZE                     USB_FULL_HIGH_SPEED_CONTROL_MAX_PACKET_SIZE
#define HIGH_SPEED_BULK_PACKET_SIZES        USB_HIGH_SPEED_BULK_MAX_PACKET_SIZE
#define FULL_SPEED_BULK_PACKET_SIZES        USB_FULL_SPEED_BULK_MAX_PACKET_SIZE 
#define USB_VERSION                         0x200


static USB_DEVICE_DESCRIPTOR                g_HighSpeedDeviceDesc = {
    sizeof(USB_DEVICE_DESCRIPTOR),          // bLength
    USB_DEVICE_DESCRIPTOR_TYPE,             // bDescriptorType
    USB_VERSION,                            // bcdUSB
    0x00,                                   // bDeviceClass
    0x00,                                   // bDeviceSubClass
    0x00,                                   // bDeviceProtocol
    EP0_PACKET_SIZE,                        // bMaxPacketSize0
    0,                                      // idVendor
    0,                                      // idProduct
    0x0000,                                 // bcdDevice
    0x01,                                   // iManufacturer
    0x02,                                   // iProduct
    0x00,                                   // iSerialNumber
    0x01                                    // bNumConfigurations
};


static USB_DEVICE_DESCRIPTOR                g_FullSpeedDeviceDesc = {
    sizeof(USB_DEVICE_DESCRIPTOR),          // bLength
    USB_DEVICE_DESCRIPTOR_TYPE,             // bDescriptorType
    USB_VERSION,                            // bcdUSB
    0x00,                                   // bDeviceClass
    0x00,                                   // bDeviceSubClass
    0x00,                                   // bDeviceProtocol
    EP0_PACKET_SIZE,                        // bMaxPacketSize0
    0,                                      // idVendor
    0,                                      // idProduct
    0x0000,                                 // bcdDevice
    0x01,                                   // iManufacturer
    0x02,                                   // iProduct
    0x00,                                   // iSerialNumber
    0x01                                    // bNumConfigurations
};

#define BULK_IN_ENDPOINT_ADDRESS  0x81
#define BULK_OUT_ENDPOINT_ADDRESS 0x02

#define INTERRUPT_IN_ENDPOINT_ADDRESS 0x83  // Optional

#define BULK_IN_DESCRIPTOR_INDEX    0
#define BULK_OUT_DESCRIPTOR_INDEX   1
#define INTERRUPT_IN_DESCRIPTOR_INDEX 2

static UFN_ENDPOINT                         g_HighSpeedEndpoints[] = {
    {
        sizeof(UFN_ENDPOINT),
        {
            sizeof(USB_ENDPOINT_DESCRIPTOR),// bLength
            USB_ENDPOINT_DESCRIPTOR_TYPE,   // bDescriptorType
            BULK_IN_ENDPOINT_ADDRESS,       // bEndpointAddress (endpoint 1, in)
            USB_ENDPOINT_TYPE_BULK,         // bmAttributes
            HIGH_SPEED_BULK_PACKET_SIZES,	// wMaxPacketSize
            0x00                            // bInterval (interrupt only)
        },
        NULL
    },
    {
        sizeof(UFN_ENDPOINT),
        {
            sizeof(USB_ENDPOINT_DESCRIPTOR),// bLength
            USB_ENDPOINT_DESCRIPTOR_TYPE,   // bDescriptorType
            BULK_OUT_ENDPOINT_ADDRESS,      // bEndpointAddress (endpoint 2, out)
            USB_ENDPOINT_TYPE_BULK,         // bmAttributes
            HIGH_SPEED_BULK_PACKET_SIZES,	// wMaxPacketSize
            0x00                            // bInterval (interrupt only)
        },
        NULL
    },
    {
        sizeof(UFN_ENDPOINT),
        {
            sizeof(USB_ENDPOINT_DESCRIPTOR),// bLength
            USB_ENDPOINT_DESCRIPTOR_TYPE,   // bDescriptorType
            INTERRUPT_IN_ENDPOINT_ADDRESS,  // bEndpointAddress (endpoint 2, out)
            USB_ENDPOINT_TYPE_INTERRUPT,    // bmAttributes
            MAX_INTERRUPT_ENDPOINT_PACKET_SIZE,   // wMaxPacketSize
            0xc                            // bInterval (interrupt only)
        },
        NULL
    }
};

static UFN_ENDPOINT                         g_FullSpeedEndpoints[] = {
    {
        sizeof(UFN_ENDPOINT),
        {
            sizeof(USB_ENDPOINT_DESCRIPTOR),// bLength
            USB_ENDPOINT_DESCRIPTOR_TYPE,   // bDescriptorType
            BULK_IN_ENDPOINT_ADDRESS,       // bEndpointAddress (endpoint 1, in)
            USB_ENDPOINT_TYPE_BULK,         // bmAttributes
            FULL_SPEED_BULK_PACKET_SIZES,	// wMaxPacketSize
            0x00                            // bInterval (interrupt only)
        },
        NULL
    },
    {
        sizeof(UFN_ENDPOINT),
        {
            sizeof(USB_ENDPOINT_DESCRIPTOR),// bLength
            USB_ENDPOINT_DESCRIPTOR_TYPE,   // bDescriptorType
            BULK_OUT_ENDPOINT_ADDRESS,      // bEndpointAddress (endpoint 2, out)
            USB_ENDPOINT_TYPE_BULK,         // bmAttributes
            FULL_SPEED_BULK_PACKET_SIZES,	// wMaxPacketSize
            0x00                            // bInterval (interrupt only)
        },
        NULL
    },
    {
        sizeof(UFN_ENDPOINT),
        {
            sizeof(USB_ENDPOINT_DESCRIPTOR),// bLength
            USB_ENDPOINT_DESCRIPTOR_TYPE,   // bDescriptorType
            INTERRUPT_IN_ENDPOINT_ADDRESS,  // bEndpointAddress (endpoint 2, out)
            USB_ENDPOINT_TYPE_INTERRUPT,    // bmAttributes
            MAX_INTERRUPT_ENDPOINT_PACKET_SIZE,   // wMaxPacketSize
            0x20                            // bInterval (interrupt only)
        },
        NULL
    }
};

static UFN_INTERFACE                        g_HighSpeedInterface1 = {
    sizeof(UFN_INTERFACE),
    {
        sizeof(USB_INTERFACE_DESCRIPTOR),   // bLength
        USB_INTERFACE_DESCRIPTOR_TYPE,      // bDescriptorType
        0x00,                               // bInterfaceNumber    
        0x00,                               // bAlternateSetting

        dim(g_HighSpeedEndpoints),          // bNumEndpoints
        0xff,       // bInterfaceClass
        0xff,// bInterfaceSubClass
        0xff,             // bInterfaceProtocol
        0x00                                // iInterface    
    },
    NULL,                                   // extended
    0,
    g_HighSpeedEndpoints                    // endpoint array
};
static UFN_INTERFACE                        g_HighSpeedInterface2 = {
    sizeof(UFN_INTERFACE),
    {
        sizeof(USB_INTERFACE_DESCRIPTOR),   // bLength
        USB_INTERFACE_DESCRIPTOR_TYPE,      // bDescriptorType
        0x00,                               // bInterfaceNumber    
        0x00,                               // bAlternateSetting

        dim(g_HighSpeedEndpoints)-1,        // bNumEndpoints
        0xff,       // bInterfaceClass
        0xff,// bInterfaceSubClass
        0xff,             // bInterfaceProtocol
        0x00                                // iInterface    
    },
    NULL,                                   // extended
    0,
    g_HighSpeedEndpoints                    // endpoint array
};

static UFN_INTERFACE                        g_FullSpeedInterface1 = {
    sizeof(UFN_INTERFACE),
    {
        sizeof(USB_INTERFACE_DESCRIPTOR),   // bLength
        USB_INTERFACE_DESCRIPTOR_TYPE,      // bDescriptorType
        0x00,                               // bInterfaceNumber    
        0x00,                               // bAlternateSetting

        dim(g_FullSpeedEndpoints),          // bNumEndpoints
        0xff,       // bInterfaceClass
        0xff,// bInterfaceSubClass
        0xff,             // bInterfaceProtocol
        0x00                                // iInterface    
    },
    NULL,                                   // extended
    0,
    g_FullSpeedEndpoints                    // endpoint array
};

static UFN_INTERFACE                        g_FullSpeedInterface2 = {
    sizeof(UFN_INTERFACE),
    {
        sizeof(USB_INTERFACE_DESCRIPTOR),   // bLength
        USB_INTERFACE_DESCRIPTOR_TYPE,      // bDescriptorType
        0x00,                               // bInterfaceNumber    
        0x00,                               // bAlternateSetting

        dim(g_FullSpeedEndpoints)-1,          // bNumEndpoints
        0xff,       // bInterfaceClass
        0xff,// bInterfaceSubClass
        0xff,             // bInterfaceProtocol
        0x00                                // iInterface    
    },
    NULL,                                   // extended
    0,
    g_FullSpeedEndpoints                    // endpoint array
};

static UFN_CONFIGURATION                    g_HighSpeedConfig1 = {
    sizeof(UFN_CONFIGURATION),
    {
        sizeof(USB_CONFIGURATION_DESCRIPTOR),// bLength
        USB_CONFIGURATION_DESCRIPTOR_TYPE,  // bDescriptorType
        
        CB_CONFIG_DESCRIPTOR,               // wTotalLength
        0x01,                               // bNumInterfaces
        0x01,                               // bConfigurationValue
        0x00,                               // iConfiguration
        USB_CONFIG_RESERVED_ATTRIBUTE | USB_CONFIG_SELF_POWERED,            // bmAttributes
        0x00                                // MaxPower
    },
    NULL,
    0x01,                                   // number of interfaces
    &g_HighSpeedInterface1                  // interface array
};

static UFN_CONFIGURATION                    g_HighSpeedConfig2 = {
    sizeof(UFN_CONFIGURATION),
    {
        sizeof(USB_CONFIGURATION_DESCRIPTOR),// bLength
        USB_CONFIGURATION_DESCRIPTOR_TYPE,  // bDescriptorType
        
        CB_CONFIG_DESCRIPTOR- sizeof(USB_ENDPOINT_DESCRIPTOR), // wTotalLength
        0x01,                               // bNumInterfaces
        0x01,                               // bConfigurationValue
        0x00,                               // iConfiguration
        USB_CONFIG_RESERVED_ATTRIBUTE | USB_CONFIG_SELF_POWERED,            // bmAttributes
        0x00                                // MaxPower
    },
    NULL,
    0x01,                                   // number of interfaces
    &g_HighSpeedInterface2                  // interface array
};

static UFN_CONFIGURATION                    g_FullSpeedConfig1 = {
    sizeof(UFN_CONFIGURATION),
    {
        sizeof(USB_CONFIGURATION_DESCRIPTOR),// bLength
        USB_CONFIGURATION_DESCRIPTOR_TYPE,  // bDescriptorType
        
        CB_CONFIG_DESCRIPTOR,               // wTotalLength
        0x01,                               // bNumInterfaces
        0x01,                               // bConfigurationValue
        0x00,                               // iConfiguration
        USB_CONFIG_RESERVED_ATTRIBUTE | USB_CONFIG_SELF_POWERED,            // bmAttributes
        0x00                                // MaxPower
    },
    NULL,
    0x01,                                   // number of interfaces
    &g_FullSpeedInterface1                   // interface array
};

static UFN_CONFIGURATION                    g_FullSpeedConfig2 = {
    sizeof(UFN_CONFIGURATION),
    {
        sizeof(USB_CONFIGURATION_DESCRIPTOR),// bLength
        USB_CONFIGURATION_DESCRIPTOR_TYPE,  // bDescriptorType
        
        CB_CONFIG_DESCRIPTOR - sizeof(USB_ENDPOINT_DESCRIPTOR), // wTotalLength
        0x01,                               // bNumInterfaces
        0x01,                               // bConfigurationValue
        0x00,                               // iConfiguration
        USB_CONFIG_RESERVED_ATTRIBUTE | USB_CONFIG_SELF_POWERED,            // bmAttributes
        0x00                                // MaxPower
    },
    NULL,
    0x01,                                   // number of interfaces
    &g_FullSpeedInterface2                   // interface array
};


static UFN_CLIENT_REG_INFO g_RegInfo = { sizeof(UFN_CLIENT_REG_INFO) };

static LPCWSTR g_rgpszStrings0409[] = {
    g_RegInfo.szVendor, g_RegInfo.szProduct
};

static UFN_STRING_SET g_rgStringSets[] = {
    0x0409, g_rgpszStrings0409, dim(g_rgpszStrings0409)
};


CUsbFn::CUsbFn (LPCTSTR lpActivePath)
:   m_pUfnFuncs(&m_UfnFuncs)
{
    DWORD dwLen = _tcslen(lpActivePath);
    m_lpActivePath = new TCHAR[dwLen+1];
    if (m_lpActivePath) {
        _tcscpy(m_lpActivePath,lpActivePath);
        m_lpActivePath[dwLen]= 0;
    }
    m_hDevice = NULL;
    m_pvInterface = NULL;
    m_CurrentSpeed = BS_HIGH_SPEED;
}
#define COMLAYER_DRIVER_PATH TEXT("ComLayer")
BOOL CUsbFn::Init()
{
    if (m_lpActivePath &&
            UfnInitializeInterface(m_lpActivePath, &m_hDevice, &m_UfnFuncs, &m_pvInterface)== ERROR_SUCCESS) {
        PREFAST_ASSERT(m_hDevice!=NULL);
        PREFAST_ASSERT(m_pUfnFuncs!=NULL);
        CRegistryEdit driverKey(m_lpActivePath);
        if (driverKey.IsKeyOpened()) {
            DWORD dwRet = UfnGetRegistryInfo(m_lpActivePath, &g_RegInfo);
            if (dwRet == ERROR_SUCCESS) {
                g_HighSpeedDeviceDesc.idVendor = (USHORT) g_RegInfo.idVendor;
                g_HighSpeedDeviceDesc.idProduct = (USHORT) g_RegInfo.idProduct;
                g_HighSpeedDeviceDesc.bcdDevice = (USHORT) g_RegInfo.bcdDevice;

                g_FullSpeedDeviceDesc.idVendor = g_HighSpeedDeviceDesc.idVendor;
                g_FullSpeedDeviceDesc.idProduct = g_HighSpeedDeviceDesc.idProduct;
                g_FullSpeedDeviceDesc.bcdDevice = g_HighSpeedDeviceDesc.bcdDevice;
                
                // Register the descriptor tree with device controller
                m_fInterrupt = TRUE;
                dwRet = ERROR_GEN_FAILURE;
                
#ifdef USE_INTERRUPT_ENDPOINT
                dwRet = m_pUfnFuncs->lpRegisterDevice(m_hDevice,
                    &g_HighSpeedDeviceDesc, &g_HighSpeedConfig1, 
                    &g_FullSpeedDeviceDesc, &g_FullSpeedConfig1, 
                    g_rgStringSets, dim(g_rgStringSets));
#endif            
                if (dwRet != ERROR_SUCCESS) { // Try Second
                    m_fInterrupt = FALSE;
                    dwRet = m_pUfnFuncs->lpRegisterDevice(m_hDevice,
                        &g_HighSpeedDeviceDesc, &g_HighSpeedConfig2, 
                        &g_FullSpeedDeviceDesc, &g_FullSpeedConfig2, 
                        g_rgStringSets, dim(g_rgStringSets));
                }
                if (dwRet == ERROR_SUCCESS ) { // Do I need Initial Pipe Here?
                    dwRet = m_pUfnFuncs->lpStart(m_hDevice, DeviceNotifyStub, this,  &m_hDefaultPipe);

                }
            }
            return (dwRet == ERROR_SUCCESS );
        }
    }
    return FALSE;
}
CUsbFn::~CUsbFn()
{
    if (m_lpActivePath)
        delete m_lpActivePath;

    if (m_pvInterface)
        UfnDeinitializeInterface(m_pvInterface);
}

BOOL WINAPI CUsbFn::DeviceNotifyStub(PVOID   pvNotifyParameter, DWORD   dwMsg, DWORD   dwParam)
{
    PREFAST_ASSERT(pvNotifyParameter!=NULL);
    return ((CUsbFn *)pvNotifyParameter)->DeviceNotify(dwMsg,dwParam);
}
BOOL CUsbFn::DeviceNotify(DWORD dwMsg, DWORD dwParam)
{
    DEBUGMSG (ZONE_WRITE|ZONE_EVENTS,(TEXT("DeviceNotify (0x%x,0x%x)\r\n"),dwMsg, dwParam));
    switch(dwMsg) {
        case UFN_MSG_BUS_EVENTS: {
            // Ensure device is in running state
            DEBUGCHK(m_hDefaultPipe);

           switch(dwParam) {                
                case UFN_DETACH:
                    CableDetached();
                    break;
                case UFN_ATTACH:
                    break;
                case UFN_RESET: {
                    CableDetached();
                    break;
                }
             } 

           break;
        }
        
        case UFN_MSG_BUS_SPEED:
             m_CurrentSpeed = (UFN_BUS_SPEED) dwParam;
        break;

        case UFN_MSG_SETUP_PACKET:
        case UFN_MSG_PREPROCESSED_SETUP_PACKET: {
            HandleRequest(dwMsg,*(PUSB_DEVICE_REQUEST)dwParam);
            break;
        }

        case UFN_MSG_CONFIGURED: {
            if (dwParam == 0) {
                CableDetached();
            }
            else {
                CableAttached();
            }
            break;
        }
        
    }
    return TRUE;
}
void CUsbFn::HandleRequest(
    DWORD dwMsg,
    USB_DEVICE_REQUEST udr
    )
{
    CONTROL_RESPONSE response;

    if (dwMsg == UFN_MSG_PREPROCESSED_SETUP_PACKET) {
        response = CR_SUCCESS; // Don't respond since it was already handled.
        
        if ( udr.bmRequestType ==
            (USB_REQUEST_HOST_TO_DEVICE | USB_REQUEST_STANDARD | USB_REQUEST_FOR_ENDPOINT) ) {
            switch (udr.bRequest) {
                case USB_REQUEST_CLEAR_FEATURE:
                    // This may be needed in the future to terminate a transfer 
                    // in progress
                    HandleClearFeature(udr);
                    break;
            }
        }
    }
    else {
        DEBUGCHK(dwMsg == UFN_MSG_SETUP_PACKET);
        response = CR_STALL_DEFAULT_PIPE;

        if (udr.bmRequestType & USB_REQUEST_CLASS) {
            response = HandleClassRequest(udr);
        }
    }

    if (response == CR_STALL_DEFAULT_PIPE) {
        m_pUfnFuncs->lpStallPipe(m_hDevice, m_hDefaultPipe);
        m_pUfnFuncs->lpSendControlStatusHandshake(m_hDevice);
    }
    else if (response == CR_SUCCESS_SEND_CONTROL_HANDSHAKE) {
        m_pUfnFuncs->lpSendControlStatusHandshake(m_hDevice);
    }
}
CONTROL_RESPONSE CUsbFn::HandleClassRequest(
    USB_DEVICE_REQUEST udr
    )
{

    CONTROL_RESPONSE response = CR_STALL_DEFAULT_PIPE;
           
    if (udr.bmRequestType == 
            (USB_REQUEST_CLASS | USB_REQUEST_FOR_INTERFACE | USB_REQUEST_HOST_TO_DEVICE) ) { 
        if (udr.bRequest == SET_CONTROL_LINE_STATE) {
            /* Host is notifying us of control line state.
             * wValue contains bitmask
             * 0 - DTR
             * 1 - RTS
             */
            DEBUGMSG( ZONE_FUNCTION, (TEXT("SET_CONTROL_LINE_STATE %X\r\n"),
                 udr.wValue));
            DWORD dwModemStatus = 0;
            if (udr.wValue & USB_COMM_DTR)
              dwModemStatus |= (MS_DSR_ON|MS_RLSD_ON); // DTR active, set DSR/RLSD
            if (udr.wValue & USB_COMM_RTS) 
              dwModemStatus |= MS_CTS_ON;   // RTS active, set CTS
            ModemSignal(dwModemStatus);
            response = CR_SUCCESS_SEND_CONTROL_HANDSHAKE;
        }
    }
    else {
        RETAILMSG(1, (_T("Unrecognized Serial class bRequest -> 0x%x\r\n"), udr.bmRequestType));
        ASSERT(FALSE);
    }
    ASSERT(response == CR_SUCCESS_SEND_CONTROL_HANDSHAKE);
    return response;
}
void USBSerialFn::CableDetached()
{
    // This is last time to call this structure.
    m_HardwareLock.Lock();
    CloseBulkIn();
    CloseBulkOut();
    CloseInterruptIn();
    m_HardwareLock.Unlock();
    ModemSignal(0);
}
void USBSerialFn::CableAttached() 
{
    m_HardwareLock.Lock();
    DWORD dwBulkSize = (m_CurrentSpeed == BS_HIGH_SPEED?
        g_HighSpeedEndpoints[BULK_IN_DESCRIPTOR_INDEX].Descriptor.wMaxPacketSize:
        g_FullSpeedEndpoints[BULK_IN_DESCRIPTOR_INDEX].Descriptor.wMaxPacketSize);
    BYTE uEdptAddr  = (m_CurrentSpeed == BS_HIGH_SPEED?
        g_HighSpeedEndpoints[BULK_IN_DESCRIPTOR_INDEX].Descriptor.bEndpointAddress:
        g_FullSpeedEndpoints[BULK_IN_DESCRIPTOR_INDEX].Descriptor.bEndpointAddress);
    OpenBulkIn(m_hDevice, m_pUfnFuncs,uEdptAddr,FALSE, dwBulkSize, 0x1000, 2);
    
    dwBulkSize = (m_CurrentSpeed == BS_HIGH_SPEED?
        g_HighSpeedEndpoints[BULK_OUT_DESCRIPTOR_INDEX].Descriptor.wMaxPacketSize:
        g_FullSpeedEndpoints[BULK_OUT_DESCRIPTOR_INDEX].Descriptor.wMaxPacketSize);
    uEdptAddr  = (m_CurrentSpeed == BS_HIGH_SPEED?
        g_HighSpeedEndpoints[BULK_OUT_DESCRIPTOR_INDEX].Descriptor.bEndpointAddress:
        g_FullSpeedEndpoints[BULK_OUT_DESCRIPTOR_INDEX].Descriptor.bEndpointAddress);
    OpenBulkOut(m_hDevice, m_pUfnFuncs,uEdptAddr,TRUE,dwBulkSize,dwBulkSize, 4); // WCEUSBSH Bug. Only can usb MaxPacketSize
    
    if (m_fInterrupt) {
        DWORD dwInterruptSize = (m_CurrentSpeed == BS_HIGH_SPEED?
            g_HighSpeedEndpoints[INTERRUPT_IN_DESCRIPTOR_INDEX].Descriptor.wMaxPacketSize:
            g_FullSpeedEndpoints[INTERRUPT_IN_DESCRIPTOR_INDEX].Descriptor.wMaxPacketSize);
        uEdptAddr  = (m_CurrentSpeed == BS_HIGH_SPEED?
            g_HighSpeedEndpoints[INTERRUPT_IN_DESCRIPTOR_INDEX].Descriptor.bEndpointAddress:
            g_FullSpeedEndpoints[INTERRUPT_IN_DESCRIPTOR_INDEX].Descriptor.bEndpointAddress);
        OpenInterruptIn(m_hDevice, m_pUfnFuncs,uEdptAddr,FALSE,dwInterruptSize,8, 1);
    }
    m_HardwareLock.Unlock();
}
CSerialPDD * CreateSerialObject(LPTSTR lpActivePath, PVOID pMdd,PHWOBJ pHwObj, DWORD )
{
    CSerialPDD * pSerialPDD = new USBSerialFn(lpActivePath,pMdd, pHwObj);
    if (pSerialPDD && !pSerialPDD->Init()) {
        delete pSerialPDD;
        pSerialPDD = NULL;
    }
    return pSerialPDD;
}
void DeleteSerialObject(CSerialPDD * pSerialPDD)
{
    if (pSerialPDD)
        delete pSerialPDD;
}

