📄 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 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 + -