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

📄 cpipe.cpp

📁 Latest USB 802.3, HID printer and mass storage divers from Microsoft for Platform Builder 4.2.
💻 CPP
📖 第 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:  
//     CPipe.cpp
// Abstract:  
//     Implements the Pipe class for managing open pipes for UHCI
//
//                             CPipe (ADT)
//                           /             \
//                  CQueuedPipe (ADT)       CIsochronousPipe
//                /         |       \ 
//              /           |         \
//   CControlPipe    CInterruptPipe    CBulkPipe
// 
// 
// Notes: 
// 
//

#include "cpipe.hpp"
#include "cphysmem.hpp"
#include "chw.hpp"
#include "cuhcd.hpp"

//#pragma warning (4 : 4100)      // temporary, will clean later. JEFFRO.

CHCCAera::CHCCAera(IN CPhysMem* const pCPhysMem) 
:m_pCPhysMem(pCPhysMem)
{
#ifdef DEBUG
    m_debug_fInitializeAlreadyCalled = FALSE;
#endif // DEBUG

// schedule related vars
//CRITICAL_SECTION    CPipe::m_csFrameListLock;
//PULONG              CPipe::m_vaFrameList = NULL;
    m_pFinalQH = NULL;
                                    
#ifdef DEBUG
    m_debug_TDMemoryAllocated = 0;
    m_debug_QHMemoryAllocated = 0;
    m_debug_BufferMemoryAllocated = 0;
    m_debug_ControlExtraMemoryAllocated = 0;
#endif // DEBUG

// Handle Done Transfers thread variables
    m_pDoneHead = 0;
    m_fCheckTransferThreadClosing = FALSE;
    m_hCheckForDoneTransfersEvent = NULL;
    m_hCheckForDoneTransfersThread = NULL;
    m_pBusyPipeList = NULL;
#ifdef DEBUG
    m_debug_numItemsOnBusyPipeList = 0;
#endif // DEBUG
    numReclamationTransfers=0;
    InitializeCriticalSection( &m_csBusyPipeListLock );
    InitializeCriticalSection( &m_csQHScheduleLock );
}
CHCCAera::~CHCCAera()
{
    DeInitialize();
    DeleteCriticalSection( &m_csBusyPipeListLock );
//    DeleteCriticalSection( &m_csFrameListLock );
    DeleteCriticalSection( &m_csQHScheduleLock );
}

// *****************************************************************
// Scope: public static
BOOL CHCCAera::Initialize(IN CUhcd * const pCUhcd)
//
// Purpose: Initialize CPipe's static variables. This
//          also sets up the original empty schedule
//          with the frame list, and interrupt Queue Head tree.
//          We also set up a thread for processing done transfers
//
// Parameters: pCPhysMem - pointer to memory manager object
//
// Returns: TRUE - if everything initialized ok
//          FALSE - in case of failure
//
// Notes: This function is only called from the CUhcd::Initialize routine.
//        It should only be called once, to initialize the static variables
// ******************************************************************
{
    DEBUGMSG(ZONE_INIT, (TEXT("+CPipe::Initialize\n")));

#ifdef DEBUG // only call this once to init static vars/schedule
    DEBUGCHK( m_debug_fInitializeAlreadyCalled == FALSE );
    m_debug_fInitializeAlreadyCalled = TRUE;
#endif // DEBUG

    DEBUGCHK( m_fCheckTransferThreadClosing == FALSE &&
              m_hCheckForDoneTransfersThread == NULL &&
              m_hCheckForDoneTransfersEvent == NULL );
    DEBUGCHK( m_pBusyPipeList == NULL &&
              m_debug_numItemsOnBusyPipeList == 0 );

    if ( m_pCPhysMem == NULL ) {
        DEBUGCHK( 0 ); // This should never happen
        DEBUGMSG(ZONE_ERROR, (TEXT("-CPipe::Initialize, no memory manager object!!\n")));
        return FALSE;
    }

    // Init the list of EDs for scheduling transfers in the periodic lists
    memset( m_interruptQHTree, 0, sizeof(m_interruptQHTree) );
    // set up the periodic (intr/isoch) scheduling structures
    {
        // We set this up as follows:
        // (demonstrated for UHCD_MAX_INTERRUPT_INTERVAL = 4)
        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        //
        //                level 2 level 1 level 0    Full Speed QH     End of Schedule 
        //
        //   frame #0 -> QH #4  \
        //                         QH #2
        //   frame #2 -> QH #6  /       \
        //                               \      (1ms intr)     (isoch)
        //                                 QH # 1 - - - - QH #0 - - - - FinalQH
        //                               / 
        //   frame #1 -> QH #5  \       /
        //                         QH #3 
        //   frame #3 -> QH #7  / 
        //
        //   etc for rest of frames
        //
        //   The outermost QHs will be numbered i = UHCD_MAX_INTERRUPT_INTERVAL + x, where
        //   x = 0, 1, 2, 3, .., UHCD_MAX_INTERRUPT_INTERVAL - 1. The QH #i will be 
        //   scheduled by any frame which has index == x (mod UHCD_MAX_INTERRUPT_INTERVAL)
        //
        //   Note that the QHs in the kth level will be executed every
        //   2^k frames. Take any number n. If 2^k <= n < 2^(k+1), then
        //   QH #n is placed in the tree at level k. When we want to schedule
        //   a new queue every 2^k frames, we can place it after any existing
        //   tree queues 2^k, 2^k + 1, 2^k + 2, ..., 2^(k+1) - 1
        //
        //   Given QH #n (n > 1), if n in binary is 1x(remaining_bits)b,
        //   then QH #n links to QH # 01(remaining_bits)b.
        //   For instance, 7 = 111b links to 3 = 011b
        //   and also      4 = 100b links to 2 = 010b
        //
        //   ISOCHRONOUS EDs will be placed after QH #0.
        //
        //   INTERRUPT transfers will be placed at the appropriate point within the QH
        //   tree so that they are scheduled at regular intervals.

        // we need 2 * UHCD_MAX_INTERRUPT_INTERVAL + 1 queue heads which
        // will always remain in the schedule and never be freed
        P_ED vaQHList = NULL;
#define CPIPE_INITIALIZE_ED_MEMORY_NEEDED DWORD( (2 * UHCD_MAX_INTERRUPT_INTERVAL + 1) * sizeof( ED ) )
        if ( !m_pCPhysMem->AllocateMemory( DEBUG_PARAM( TEXT("Permanent EDs"), )
                                           CPIPE_INITIALIZE_ED_MEMORY_NEEDED,
                                           (PUCHAR *) &vaQHList,
                                           CPHYSMEM_FLAG_NOBLOCK ) ) {
            DEBUGMSG(ZONE_ERROR, (TEXT("-CPipe::Initialize - Could not get EDs for schedule\n")));
            return FALSE;
        }
    #ifdef DEBUG
        m_debug_QHMemoryAllocated += CPIPE_INITIALIZE_ED_MEMORY_NEEDED;
        DEBUGMSG( ZONE_QH, (TEXT("CPipe::Initialize - allocate persistent QHs, total bytes = %d\n"), m_debug_QHMemoryAllocated) );
    #endif // DEBUG
        m_pFinalQH = vaQHList;
        vaQHList += 1;
        m_interruptQHTree[0] = vaQHList;
        vaQHList += 1;
        // m_pFinalQH is at the very end of the schedule, and points back
        // to QH # 0. For now, the terminate bit is set in HLink, because
        // there are no high speed bulk/control transfers scheduled
        memset( m_pFinalQH, 0, sizeof(ED) );
        m_pFinalQH->bfSkip = 1;
        m_pFinalQH->paNextEd = 0;

        // QH # 0 points to m_pFinalQH
        memset( m_interruptQHTree[0], 0, sizeof(ED) );
        m_interruptQHTree[0]->bfIsIsochronous = 1;
        m_interruptQHTree[0]->bfSkip = 1;
        m_interruptQHTree[0]->paNextEd = GetQHPhysAddr( m_pFinalQH );

        for ( UCHAR pow = 1; pow <= UHCD_MAX_INTERRUPT_INTERVAL; pow <<= 1 ) {
            for ( UCHAR index = pow; index < (pow << 1); index++ ) {
                DEBUGCHK( m_interruptQHTree[ index ] == NULL );
                m_interruptQHTree[ index ] = vaQHList;
                vaQHList += 1;
                const UCHAR link = (index ^ pow) | (pow >> 1);
                DEBUGCHK( m_interruptQHTree[ link ] != NULL );
                memset( m_interruptQHTree[index], 0, sizeof(ED) );
                m_interruptQHTree[index]->bfSkip = 1;
                m_interruptQHTree[index]->paNextEd = GetQHPhysAddr( m_interruptQHTree[link] );
            }
        }

        // Fill in the HCCA Interrupt ED ListHeads.
        for (int index = 0; index < UHCD_MAX_INTERRUPT_INTERVAL; ++index)
            pCUhcd->CHW::m_pInterruptTable[index] = GetQHPhysAddr( m_interruptQHTree[index+UHCD_MAX_INTERRUPT_INTERVAL] );
    }

    // m_hCheckForDoneTransfersEvent - Auto Reset, and Initial State = non-signaled
    m_hCheckForDoneTransfersEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
    if ( m_hCheckForDoneTransfersEvent == NULL ) {
        DEBUGMSG(ZONE_ERROR, (TEXT("-CPipe::Initialize. Error creating process done transfers event\n")));
        return FALSE;
    }

    // set up our thread to check for done transfers
    // currently, the context passed to CheckForDoneTransfersThread is ignored
    m_hCheckForDoneTransfersThread = CreateThread( 0, 0, CheckForDoneTransfersThreadStub, (PVOID)this, 0, NULL );
    if ( m_hCheckForDoneTransfersThread == NULL ) {
        DEBUGMSG(ZONE_ERROR, (TEXT("-CPipe::Initialize. Error creating process done transfers thread\n")));
        return FALSE;
    }
    CeSetThreadPriority( m_hCheckForDoneTransfersThread, g_IstThreadPriority + RELATIVE_PRIO_CHECKDONE );

    DEBUGMSG(ZONE_INIT, (TEXT("-CPipe::Initialize. Success!\n")));
    return TRUE;
}

// *****************************************************************
// Scope: public static
void CHCCAera::DeInitialize( void )
//
// Purpose: DeInitialize any static variables
//
// Parameters: None
//
// Returns: Nothing
//
// Notes: This function should only be called from the ~CUhcd()
// ******************************************************************
{
#ifdef DEBUG // don't call this twice
    DEBUGCHK( m_debug_fInitializeAlreadyCalled );
    m_debug_fInitializeAlreadyCalled = FALSE;
#endif // DEBUG

    m_fCheckTransferThreadClosing = TRUE;
    // Wake up the CheckForDoneTransfersThread and give it time to die
    if ( m_hCheckForDoneTransfersEvent ) {
        SetEvent( m_hCheckForDoneTransfersEvent );
        if ( m_hCheckForDoneTransfersThread ) {
            DWORD dwWaitReturn = WaitForSingleObject( m_hCheckForDoneTransfersThread, 5000 );
            if ( dwWaitReturn != WAIT_OBJECT_0 ) {
                DEBUGCHK( 0 ); // check why thread is blocked
                TerminateThread( m_hCheckForDoneTransfersThread, DWORD(-1) );
            }
            CloseHandle( m_hCheckForDoneTransfersThread );
            m_hCheckForDoneTransfersThread = NULL;
        }
        CloseHandle( m_hCheckForDoneTransfersEvent );
        m_hCheckForDoneTransfersEvent = NULL;
    }

    // all busy pipes should have been closed by now
    DEBUGCHK( m_pBusyPipeList == NULL &&
              m_debug_numItemsOnBusyPipeList == 0 );

    m_fCheckTransferThreadClosing = FALSE;

//    m_pCPhysMem->FreeSpecialMemory( PUCHAR(m_vaFrameList));
}
// ******************************************************************
// Scope: public static
void CHCCAera::SignalCheckForDoneTransfers( DWORD paDoneHead )
//
// Purpose: This function is called when an interrupt is received by
//          the CHW class. We then signal the CheckForDoneTransfersThread
//          to check for any transfers which have completed
//
// Parameters: None
//
// Returns: Nothing
//
// Notes: DO MINIMAL WORK HERE!! Most processing should be handled by
//        The CheckForDoneTransfersThread. If this procedure blocks, it
//        will adversely affect the interrupt processing thread.
// ******************************************************************
{
    DEBUGCHK( m_hCheckForDoneTransfersEvent && m_hCheckForDoneTransfersThread );

    DEBUGCHK( paDoneHead != 0 ); // spurious interrupts are filtered in CHW

    // Traverse the list of done TDs, reversing it in place and simultaneously
    // relinking it with virtual instead of physical addresses.
    P_TD pTD = (P_TD) m_pCPhysMem->PaToVa(paDoneHead);
    P_TD pTail = pTD;
    P_TD pPrev = 0;
    while (pTD) {
        DWORD paNext = pTD->paNextTd.phys;
        P_TD pNext = paNext ? (P_TD) m_pCPhysMem->PaToVa(paNext) : 0;

        pTD->paNextTd.td = pPrev;
        pPrev = pTD;

⌨️ 快捷键说明

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