📄 cpipe.hpp
字号:
//
// 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 + -