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

📄 cpipe.hpp

📁 wince4.2 usb host driver for magic eye mmsp2 platform
💻 HPP
📖 第 1 页 / 共 2 页
字号:
//
// 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.hpp
// 
// Abstract: Implements class for managing open pipes for UHCI
//
//                             CPipe (ADT)
//                           /             \
//                  CQueuedPipe (ADT)       CIsochronousPipe
//                /         |       \ 
//              /           |         \
//   CControlPipe    CInterruptPipe    CBulkPipe
// 
// Notes: 
// 

#ifndef __CPIPE_HPP__
#define __CPIPE_HPP__

#include <globals.hpp>
#include <cphysmem.hpp>
#include "chw.hpp"

class CHCCArea;
class CUhcd;
class CPipe;
class CIsochronousPipe;
class CQueuedPipe;
class CControlPipe;
class CInterruptPipe;
class CBulkPipe;
typedef struct STransfer STransfer;

typedef struct _TD TD, *P_TD;
typedef struct _ITD ITD, *P_ITD;
typedef struct _ED ED, *P_ED;


// Not real PIDs like in UHCI, these codes are defined in the OHCI spec.
#define TD_IN_PID    2
#define TD_OUT_PID   1
#define TD_SETUP_PID 0

const UINT gcTdOffsetBits = 12; // number of bits in an offset within an OHCI page
const UINT gcTdPageSize = 1<<gcTdOffsetBits; // size of an OHCI page (4K) in bytes
const UINT gcTdMaxPages = 2;    // maximum contiguous pages referenceable by one TD
const UINT gcTdMaxBuffer = gcTdPageSize*gcTdMaxPages;

const UINT gcTdIsochMaxFrames = 60000; // leave some room - 60 seconds is plenty.

const UINT gcTdInterruptOnComplete = 0; // interrupt immediately when this TD completes
const UINT gcTdNoInterrupt = 7;    // do not interrupt when this TD completes

typedef union {
    DWORD phys;                 // used when preparing to give the TD to the HC
    P_TD td;                    // for back-linking done TDs
    P_ITD itd;                  // ditto, but eases type-casting
} TDLINK;

typedef struct _TD {
    DWORD :16;                  // reserved, bits 0-15
    DWORD bfDiscard:1;          // reserved, bit 16 (used by HCD, matches ITD))
    DWORD bfIsIsoch:1;          // reserved, bit 17 (used by HCD, matches ITD))
    DWORD bfShortPacketOk:1;    // bit 18
    DWORD bfPID:2;              // bits 19-20
    DWORD bfDelayInterrupt:3;   // bits 21-23
    DWORD bfDataToggle:2;       // bits 24-25
        enum { DATATOG_ED=0, DATATOG_0=2, DATATOG_1=3 };
    DWORD bfErrorCount:2;       // bits 26-27
    DWORD bfConditionCode:4;    // bits 28-31
    ULONG paCurBuffer;
    TDLINK paNextTd;
    ULONG paBufferEnd;

    // These add-ons are for the driver to use
    STransfer *pTransfer;       // transfer object owning this TD (until scheduled)
    TD *pNextTd;                // next TD in this transfer (paNextTd is clobbered by the HC)
    // This is temporary until we stop copying transfer objects around
    CPipe *pPipe;
    // These are unused but force proper alignment
    DWORD _reserved[1];
} TD;

typedef union {
    struct {
        // bit 12 is really a page select, but we can pretend it's an address bit
        WORD uOffset:13;
        WORD uHiBits:3;  // only the most significant 3 bits, for initting.
    };
    struct {
        WORD uSize:12;
        WORD uConditionCode:4;
    };
} ITDFrame;
const UINT gcITdNumOffsets                  = 8;

typedef struct _ITD {
    DWORD   bfStartFrame:16;    // bits 0-15
    DWORD   bfDiscard:1;        // reserved, bit 16 (used by HCD, matches TD)
    DWORD   bfIsIsoch:1;        // reserved, bit 17 (used by HCD, matches TD)
    DWORD   :3;                 // reserved, bits 18-20
    DWORD   bfDelayInterrupt:3; // bits 21-23
    DWORD   bfFrameCount:3;     // bits 24-26
    DWORD   :1;                 // undefined, bit 27
    DWORD   bfConditionCode:4;  // bits 28-31
    DWORD   paBufferPage0;      // And with gcITdPageMask
    TDLINK  paNextTd;
    DWORD   paBufferEnd;
    ITDFrame offsetPsw[gcITdNumOffsets];

    // These add-ons are for the driver to use
    STransfer *pTransfer;       // transfer object owning this TD
    P_ITD pNextTd;               // next TD in this transfer (paNextTd is clobbered by the HC)
    // This is temporary until we stop copying transfer objects around
    CPipe *pPipe;
    // These are unused but force proper alignment
    DWORD _reserved[5];
} ITD;

typedef struct _ED {
    DWORD   bfFunctionAddress:7; // bits 0-6
    DWORD   bfEndpointNumber:4; // bits 7-10
    DWORD   bfDirection:2;      // bits 11-12
    DWORD   bfIsLowSpeed:1;     // bit 13
    DWORD   bfSkip:1;           // bit 14
    DWORD   bfIsIsochronous:1;  // bit 15
    DWORD   bfMaxPacketSize:11; // bits 16-26
    DWORD   :5;                 // undefined, bits 27-31
    ULONG   paTdQueueTail;
    union {
        ULONG paTdQueueHead;
        struct {
            DWORD bfHalted:1;
            DWORD bfToggleCarry:1;
            DWORD :30;
        };
    };
    ULONG   paNextEd;
} ED;

// This is an instantaneous check; a stable check requires that the ED be disabled first.
// The LSNs of the queue pointers are not actually part of the pointers themselves.
#define IsEDQEmpty(p) (((p)->paTdQueueHead & ~0xF) == ((p)->paTdQueueTail & ~0xF))

// structure used for managing busy pipes
typedef struct _PIPE_LIST_ELEMENT {
    CPipe*                      pPipe;
    struct _PIPE_LIST_ELEMENT * pNext;
} PIPE_LIST_ELEMENT, *PPIPE_LIST_ELEMENT;

struct STransfer {
    // These are the IssueTransfer parameters
    UCHAR                     address;
    LPTRANSFER_NOTIFY_ROUTINE lpfnCallback;
    LPVOID                    lpvCallbackParameter;
    DWORD                     dwFlags;
    LPCVOID                   lpvControlHeader;
    DWORD                     paControlHeader;
    DWORD                     dwStartingFrame;
    DWORD                     dwFrames;
    LPCDWORD                  aLengths;
    DWORD                     dwBufferSize;     
    LPVOID                    lpvClientBuffer;
    ULONG                     paClientBuffer;
    LPCVOID                   lpvCancelId;
    LPDWORD                   adwIsochErrors;
    LPDWORD                   adwIsochLengths;
    LPBOOL                    lpfComplete;
    LPDWORD                   lpdwBytesTransferred;
    LPDWORD                   lpdwError;
    // additional parameters/data
    CPipe*                    rPipe;            // pipe on which this transfer was issued
    TDLINK                    vaTDList;         // TD list for the transfer (phys is invalid here)
    USHORT                    numTDsInList;     // # TDs in pTDListHead list
    USHORT                    numTDsComplete;   // # TDs completed by the HC
    PUCHAR                    vaActualBuffer;   // virt addr of buffer used by TD list
    ULONG                     paActualBuffer;   // phys addr of buffer used by TD list
    DWORD                     dwCurrentPermissions;
    struct STransfer *        lpNextTransfer;
};

class CHCCAera {
    friend class CPipe;
    friend class CIsochronousPipe;
    friend class CQueuedPipe;
    friend class CControlPipe;
    friend class CInterruptPipe;
    friend class CBulkPipe;
public:
    CHCCAera(IN CPhysMem* const pCPhysMem);
    ~CHCCAera() ;
    BOOL Initialize(IN CUhcd * const pCUhcd);
    void         DeInitialize( void );

    void         SignalCheckForDoneTransfers( DWORD paDoneHead );
private:
    static ULONG CALLBACK CheckForDoneTransfersThreadStub( IN PVOID context );
    ULONG CheckForDoneTransfersThread();

    // ****************************************************
    // Private Variables for CPipe
    // ****************************************************
#ifdef DEBUG
    BOOL             m_debug_fInitializeAlreadyCalled;
#endif // DEBUG

    // CheckForDoneTransfersThread related variables
    BOOL             m_fCheckTransferThreadClosing; // signals CheckForDoneTransfersThread to exit
    HANDLE           m_hCheckForDoneTransfersEvent; // event for CheckForDoneTransfersThread
    HANDLE           m_hCheckForDoneTransfersThread; // thread for handling done transfers
    CRITICAL_SECTION m_csBusyPipeListLock;
    PPIPE_LIST_ELEMENT m_pBusyPipeList;
#ifdef DEBUG
    int              m_debug_numItemsOnBusyPipeList;
#endif // DEBUG
public:
    
    BOOL     AddToBusyPipeList( IN CPipe* const pPipe,
                                       IN const BOOL fHighPriority );

    void     RemoveFromBusyPipeList( IN CPipe* const pPipe );

    void     HandleReclamationLoadChange( IN const BOOL fAddingTransfer  );

    void         InsertIsochTDIntoFrameList( IN_OUT TD* pTD,
                                                    IN const DWORD dwFrameIndex );

    void         RemoveIsochTDFromFrameList( IN_OUT TD* pTD,
                                                    IN const DWORD dwFrameIndex );

    inline ULONG GetQHPhysAddr( IN P_ED virtAddr ) {
        DEBUGCHK( virtAddr != NULL &&
                  m_pCPhysMem->VaToPa( PUCHAR(virtAddr) ) % 16 == 0 );
        return m_pCPhysMem->VaToPa( PUCHAR(virtAddr) );
    }

    inline ULONG GetTDPhysAddr( IN const P_TD virtAddr ) {
        DEBUGCHK( virtAddr != NULL );
        return m_pCPhysMem->VaToPa( PUCHAR(virtAddr) );
    };

    inline ULONG GetTDPhysAddr( IN const P_ITD virtAddr ) {
        DEBUGCHK( virtAddr != NULL );
        return m_pCPhysMem->VaToPa( PUCHAR(virtAddr) );
    };
    // Return the index of the m_interruptQHTree that this frame should point to
#define UHCD_MAX_INTERRUPT_INTERVAL 32
    inline UCHAR QHTreeEntry( IN const DWORD frame ) const
    {
        DEBUGCHK( frame >= 0 );
        // return interval + (frame % interval)
        DEBUGCHK( frame % UHCD_MAX_INTERRUPT_INTERVAL == (frame & (UHCD_MAX_INTERRUPT_INTERVAL - 1)) );
        return UCHAR( UHCD_MAX_INTERRUPT_INTERVAL + (frame & (UHCD_MAX_INTERRUPT_INTERVAL - 1)) );
    }
    CPhysMem *   const   m_pCPhysMem;            // memory object for our TD/QH and Frame list alloc
private:
    // ****************************************************
    // Protected Variables for CPipe
    // ****************************************************

    // schedule related vars
//    static CRITICAL_SECTION m_csFrameListLock;     // critical section for frame list
//    static PULONG           m_vaFrameList;          // virtual address of Frame List
    CRITICAL_SECTION m_csQHScheduleLock;    // crit sec for QH section of schedule
    P_ED             m_interruptQHTree[ 2 * UHCD_MAX_INTERRUPT_INTERVAL ]; 
                                            // array to keep track of the binary tree containing
                                            // the interrupt queue heads.
    P_ED             m_pFinalQH;      // final QH in the schedule
//    static PUHCD_TD         m_pFrameSynchTD; // for keeping the software frame counter in sync
    P_TD  m_pDoneHead;          // virt ptr to head of [cached] done queue

#ifdef DEBUG
    int              m_debug_TDMemoryAllocated;
    int              m_debug_QHMemoryAllocated;
    int              m_debug_BufferMemoryAllocated;
    int              m_debug_ControlExtraMemoryAllocated;
#endif // DEBUG
    UINT numReclamationTransfers;

};


class CPipe : public CPipeAbs
{
    friend class CHCCAera;
public:
    // ****************************************************
    // Public Functions for CPipe
    // ****************************************************

    CPipe( IN const LPCUSB_ENDPOINT_DESCRIPTOR lpEndpointDescriptor,
           IN const BOOL fIsLowSpeed,
           IN const UCHAR bDeviceAddress,
           IN CUhcd * const pCUhcd);

    virtual ~CPipe();

    virtual HCD_REQUEST_STATUS  OpenPipe( void ) = 0;

    virtual HCD_REQUEST_STATUS  ClosePipe( void ) = 0;

    virtual HCD_REQUEST_STATUS  IssueTransfer( 
                                IN const UCHAR address,
                                IN LPTRANSFER_NOTIFY_ROUTINE const lpfnCallback,
                                IN LPVOID const lpvCallbackParameter,
                                IN const DWORD dwFlags,
                                IN LPCVOID const lpvControlHeader,
                                IN const DWORD dwStartingFrame,
                                IN const DWORD dwFrames,
                                IN LPCDWORD const aLengths,
                                IN const DWORD dwBufferSize,     
                                IN_OUT LPVOID const lpvBuffer,
                                IN const ULONG paBuffer,
                                IN LPCVOID const lpvCancelId,
                                OUT LPDWORD const adwIsochErrors,
                                OUT LPDWORD const adwIsochLengths,
                                OUT LPBOOL const lpfComplete,
                                OUT LPDWORD const lpdwBytesTransferred,
                                OUT LPDWORD const lpdwError );

    virtual HCD_REQUEST_STATUS AbortTransfer( 
                                IN const LPTRANSFER_NOTIFY_ROUTINE lpCancelAddress,
                                IN const LPVOID lpvNotifyParameter,
                                IN LPCVOID lpvCancelId ) = 0;

    HCD_REQUEST_STATUS IsPipeHalted( OUT LPBOOL const lpbHalted );

    void ClearHaltedFlag( void );
    
    // ****************************************************
    // Public Variables for CPipe
    // ****************************************************
    UCHAR const m_bEndpointAddress;
    UCHAR const& m_bBusAddress;

⌨️ 快捷键说明

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