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

📄 cpipe.hpp

📁 Intel PXA270 Wince5.0 BSP
💻 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 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;

#define TD_ENDPOINT_MASK 0xF

// 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 CPipe
{
public:
    // ****************************************************
    // Public Functions for CPipe
    // ****************************************************
    static BOOL         Initialize( IN CPhysMem* const pCPhysMem );

    static void         DeInitialize( void );

    static void         SignalCheckForDoneTransfers( DWORD paDoneHead );

    CPipe() : m_bEndpointAddress(0), m_bBusAddress(m_private_address)
        { DEBUGCHK( 0 ); } // should never be called

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

    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;

private:
    // ****************************************************
    // Private Functions for CPipe
    // ****************************************************
    static ULONG CALLBACK CheckForDoneTransfersThread( IN PVOID unused );

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

    // CheckForDoneTransfersThread related variables
    static BOOL             m_fCheckTransferThreadClosing; // signals CheckForDoneTransfersThread to exit
    static HANDLE           m_hCheckForDoneTransfersEvent; // event for CheckForDoneTransfersThread
    static HANDLE           m_hCheckForDoneTransfersThread; // thread for handling done transfers
    static CRITICAL_SECTION m_csBusyPipeListLock;
    static PPIPE_LIST_ELEMENT m_pBusyPipeList;
#ifdef DEBUG
    static int              m_debug_numItemsOnBusyPipeList;
#endif // DEBUG

    // Private instance variables
    UCHAR m_private_address;    // maintains the USB address of this pipe's device
                                //  (default zero; settable once during enumeration)

protected:
    // ****************************************************
    // Protected Functions for CPipe
    // ****************************************************
#ifdef DEBUG
    virtual const TCHAR*  GetPipeType( void ) const = 0;
#endif // DEBUG

    virtual const int     GetTdSize( void ) const = 0;

    virtual USHORT  GetNumTDsNeeded( const STransfer *pTransfer = NULL ) const = 0;

    virtual BOOL    AreTransferParametersValid( const STransfer *pTransfer = NULL ) const = 0;

    virtual DWORD   GetMemoryAllocationFlags( void ) const;

    virtual HCD_REQUEST_STATUS  ScheduleTransfer( void ) = 0;

    virtual HCD_REQUEST_STATUS  AddTransfer( STransfer *pTransfer )
        // The default defn simply disallows the queueing of multiple transfers.
        { /* compiler wants this referenced: */ (void) pTransfer;
          return m_fTransferInProgress ? requestFailed : requestOK; };

    virtual BOOL    CheckForDoneTransfers( void ) = 0;

    static BOOL     AddToBusyPipeList( IN CPipe* const pPipe,
                                       IN const BOOL fHighPriority );

    static void     RemoveFromBusyPipeList( IN CPipe* const pPipe );

    void            FreeTransferMemory( STransfer *pTransfer = NULL );

    static void     HandleReclamationLoadChange( IN const BOOL fAddingTransfer  );

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

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

    inline virtual ULONG * GetListHead( IN const BOOL fEnable ) = 0;

    void     InitializeTD( OUT P_TD const pTD,
                                  IN       STransfer *pTransfer,
                              IN const P_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 paBuffer,
                              IN const DWORD MaxLength,
                              IN const BOOL bShortPacketOk = FALSE);

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

⌨️ 快捷键说明

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