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

📄 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"
// ******************************************************************               
void InitializeTD( OUT PUHCD_TD const pTD,
                          IN const TD_LINK_POINTER_PHYSICAL_ADDRESS HW_paLink,
                          IN const PUHCD_TD vaNextTD,
                          IN const UCHAR InterruptOnComplete,
                          IN const UCHAR Isochronous,
                          IN const BOOL  LowSpeedControl,
                          IN const DWORD PID,
                          IN const UCHAR Address,
                          IN const UCHAR Endpoint,
                          IN const USHORT DataToggle,
                          IN const DWORD MaxLength,
                          IN const TD_BUFFER_PHYSICAL_ADDRESS HW_paBuffer, 
                          IN const BOOL bShortPacketOk /*= FALSE*/)
//
// Purpose: Fill in Transfer Descriptor fields
//
// Parameters: pTD - pointer to transfer descriptor to fill in
//
//             Rest of Params - various transfer descriptor fields
//
// Returns: Nothing
//
// Notes: MaxLength field should already be encoded by caller into 
//        (n-1) form
// ******************************************************************
{
    // HW DWORD 1 - Hardware link to the next item in schedule
    pTD->HW_paLink = HW_paLink;

    // HW DWORD 2
    // pTD->ActualLength <- don't need to set
    // pTD->Reserved_1 <- don't need to set
    pTD->Active = 1;
    pTD->StatusField = TD_STATUS_NO_ERROR;
    DEBUGCHK( (InterruptOnComplete & 1) == InterruptOnComplete );
    pTD->InterruptOnComplete = InterruptOnComplete;
    DEBUGCHK( (Isochronous & 1) == Isochronous );
    pTD->Isochronous = Isochronous;
    DEBUGCHK( (LowSpeedControl & 1) == LowSpeedControl );
    pTD->LowSpeedControl = LowSpeedControl;
    pTD->ErrorCounter = TD_ERRORCOUNTER_INTERRUPT_AFTER_THREE;
    pTD->ShortPacketDetect = bShortPacketOk ? 1 : 0;
    // pTD->ReservedMBZ <- don't need to set

    // HW DWORD 3
    DEBUGCHK( PID == TD_IN_PID ||
              PID == TD_OUT_PID ||
              PID == TD_SETUP_PID );
    pTD->PID = PID;
    DEBUGCHK( Address <= USB_MAX_ADDRESS );
    pTD->Address = Address;
    DEBUGCHK( (Endpoint & TD_ENDPOINT_MASK) == Endpoint );
    pTD->Endpoint = Endpoint;
    DEBUGCHK( (DataToggle & 1) == DataToggle );
    pTD->DataToggle = DataToggle;
    // pTD->Reserved_2 <- don't need to set
    // MaxLength is a nonzero length minus one or, for a zero length TD,
    // it might be seen here as a 32-bit -1 or as a zero-extended 11-bit -1.
    DEBUGCHK( (MaxLength == TD_MAXLENGTH_NULL_BUFFER) ||
              (MaxLength == (DWORD)-1) ||
              (MaxLength <= TD_MAXLENGTH_MAX && HW_paBuffer != 0) );
    pTD->MaxLength = MaxLength;

    // HW DWORD 4 - physical address of buffer
    pTD->HW_paBuffer = HW_paBuffer;

    // SW DWORD 5 - virt addr of previous Isoch TD
    pTD->vaPrevIsochTD = NULL;

    // SW DWORD 6 - virt addr of next TD in list
    pTD->vaNextTD = vaNextTD;

#ifdef DEBUG
    // SW DWORD 7 - Unused for now
    pTD->dwUNUSED1 = 0xdeadbeef;
    // SW DWORD 8 - Unused for now
    pTD->dwUNUSED2 = 0xdeadbeef;
#endif // DEBUG
}


// ******************************************************************               
void InitializeQH( OUT PUHCD_QH const pQH, 
                          IN const PUHCD_QH vaPrevQH,
                          IN const QUEUE_HEAD_LINK_POINTER_PHYSICAL_ADDRESS HW_paHLink,
                          IN const PUHCD_QH vaNextQH )
//
// Purpose: Fill in Queue Head Fields
//
// Parameters: pQH - pointer to Queue Head to Initialize
//
//             Rest of Params - various Queue Head fields
//
// Returns: Nothing
//
// Notes: 
// ******************************************************************
{
    DEBUGCHK( pQH != NULL );

    // HW DWORD #1 - Horizontal link 
    pQH->HW_paHLink = HW_paHLink;
    // HW DWORD #2 - Vertical link - No Transfer Descriptors right now
    pQH->HW_paVLink = QUEUE_ELEMENT_LINK_POINTER_TERMINATE;
    // SW DWORD #3 - previous QH in schedule, or NULL
    pQH->vaPrevQH = vaPrevQH;
    // SW DWORD #4 - next QH in schedule, or NULL
    pQH->vaNextQH = vaNextQH;
    // SW DWORD #5 - first Transfer Descriptor - NULL for now
    pQH->vaVertTD = NULL;
#ifdef DEBUG
    // SW DWORD #6
    pQH->dwInterruptTree.Load = 0xdeadbeef;
    // SW DWORD #7
    pQH->dwUNUSED1 = 0xdeadbeef;
    // SW DWORD #8
    pQH->dwUNUSED2 = 0xdeadbeef;
#endif // DEBUG
}

CUHCIFrame::CUHCIFrame(IN CPhysMem* const pCPhysMem ) 
:   m_pCPhysMem( pCPhysMem)
{
// memory manager
    numReclamationTransfers = 0;
    m_pCUhcd=NULL;
#ifdef DEBUG
    m_debug_fInitializeAlreadyCalled = FALSE;
#endif // DEBUG

// schedule related vars
    m_vaFrameList = NULL;
    m_pFinalQH = NULL;
    m_pFrameSynchTD = 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_fCheckTransferThreadClosing = FALSE;
    m_hCheckForDoneTransfersEvent = NULL;
    m_hCheckForDoneTransfersThread = NULL;
    m_pBusyPipeList = NULL;
#ifdef DEBUG
    m_debug_numItemsOnBusyPipeList = 0;
#endif // DEBUG
};
CUHCIFrame::~CUHCIFrame()
{
    DeInitialize();
}
// *****************************************************************
// Scope: public static
BOOL CUHCIFrame::Initialize(  CUhcd * 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("+CUHCIFrame::Initialize\n")));
    m_pCUhcd=pCUhcd;
    
#ifdef DEBUG // only call this once to init static vars/schedule
    DEBUGCHK( m_debug_fInitializeAlreadyCalled == FALSE );
    m_debug_fInitializeAlreadyCalled = TRUE;
#endif // DEBUG

    // TDs and QHs must satisfy certain size/alignment criteria
    DEBUGCHK( sizeof( UHCD_TD ) == TD_REQUIRED_SIZE_IN_BYTES );
    DEBUGCHK( sizeof( UHCD_QH ) % QH_ALIGNMENT_BOUNDARY == 0 );
    // memory manager will provide alignment - check if it
    // will satisfy our TD/QH requirements
    DEBUGCHK( CPHYSMEM_MEMORY_ALIGNMENT % TD_ALIGNMENT_BOUNDARY == 0 );
    DEBUGCHK( CPHYSMEM_MEMORY_ALIGNMENT % QH_ALIGNMENT_BOUNDARY == 0 );

    // init static variables
    // frame list variables
    InitializeCriticalSection( &m_csFrameListLock );
    DEBUGCHK( m_vaFrameList == NULL );
    // QH scheduling variables
    InitializeCriticalSection( &m_csQHScheduleLock );
    memset( m_interruptQHTree, 0, 2 * UHCD_MAX_INTERRUPT_INTERVAL * sizeof( PUHCD_QH ) );
    // check for done transfers thread variables
    DEBUGCHK( m_fCheckTransferThreadClosing == FALSE &&
              m_hCheckForDoneTransfersThread == NULL &&
              m_hCheckForDoneTransfersEvent == NULL );
    DEBUGCHK( m_pBusyPipeList == NULL &&
              m_debug_numItemsOnBusyPipeList == 0 );
    InitializeCriticalSection( &m_csBusyPipeListLock );

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

    // 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 );

    // ask CHW about the frame list
    {
        // 
        // The frame list is just an array of FRAME_LIST_LENGTH pointers. Each
        // is either invalid, or points to a TD/QH which starts the schedule for
        // that frame.
        //
        // frame list should be 4Kb according to UHCI spec
        DEBUGCHK( FRAME_LIST_SIZE_IN_BYTES == 4096 );
        // frame list should be same size as USBPAGESIZE used by memory manager
        DEBUGCHK( FRAME_LIST_SIZE_IN_BYTES == USBPAGESIZE );
    
        DEBUGCHK( m_vaFrameList == NULL );
        m_vaFrameList = m_pCUhcd->CHW::GetFrameListAddr(); // was allocated from CPhysMem by CHW
    
        // the frame list MUST be aligned on a 4Kb memory boundary
        if ( GetFrameListPhysAddr() % FRAME_LIST_SIZE_IN_BYTES != 0 ) {
            DEBUGMSG(ZONE_ERROR, (TEXT("-CPipe::Initialize - Error. Unable to create frame list. m_vaFrameList = 0x%X\n"), m_vaFrameList ));
            DEBUGCHK( 0 ); // this should never happen
            return FALSE;
        }
    
        DEBUGCHK( m_vaFrameList != NULL );
        DEBUGMSG(ZONE_INIT && ZONE_VERBOSE, (TEXT("CPipe::Initialize - Created frame list. m_vaFrameList = 0x%X, PhysAddr=0x%X\n"), m_vaFrameList, GetFrameListPhysAddr() ));
    } 

    // set up the queue head 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 
        //

⌨️ 快捷键说明

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