📄 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 <pipeabs.hpp>
class CPipe;
class CIsochronousPipe;
class CQueuedPipe;
class CControlPipe;
class CInterruptPipe;
class CBulkPipe;
class CUHCIFrame;
class CUhcd;
struct _UHCD_TD;
struct _UHCD_QH;
//
// Frame List (Section 3.1 of UHCI spec)
//
// number of entries in the frame list - 1024
#define FRAME_LIST_LENGTH DWORD(0x400)
#define FRAME_LIST_LENGTH_MASK DWORD(0x3FF)
// each of the 1024 entries of the frame list is 32 bits
typedef ULONG FRAME_LIST_POINTER;
// this should come out to be 4Kb, and will be debug checked in the code
#define FRAME_LIST_SIZE_IN_BYTES DWORD(FRAME_LIST_LENGTH * sizeof(FRAME_LIST_POINTER))
// UHCI spec section 3.1.1 defines the structure of the Frame List Pointer
#define FRAME_LIST_POINTER_MASK DWORD(0xFFFFFFF0)
#define FRAME_LIST_POINTER_TERMINATE DWORD(1 << 0)
#define FRAME_LIST_POINTER_VALID DWORD(0 << 0)
#define FRAME_LIST_POINTER_QH DWORD(1 << 1)
#define FRAME_LIST_POINTER_TD DWORD(0 << 1)
//
// Transfer Descriptor for UHCI (Section 3.2 of UHCI spec)
//
typedef ULONG TD_LINK_POINTER_PHYSICAL_ADDRESS;
#define TD_LINK_POINTER_MASK DWORD(0xFFFFFFF0)
#define TD_LINK_POINTER_TERMINATE DWORD(1 << 0)
#define TD_LINK_POINTER_VALID DWORD(0 << 0)
#define TD_LINK_POINTER_QH DWORD(1 << 1)
#define TD_LINK_POINTER_TD DWORD(0 << 1)
#define TD_LINK_POINTER_DEPTH_FIRST DWORD(1 << 2)
#define TD_LINK_POINTER_BREADTH_FIRST DWORD(0 << 2)
typedef ULONG TD_BUFFER_PHYSICAL_ADDRESS;
typedef ULONG TD_PHYSICAL_ADDRESS;
typedef struct _UHCD_TD *PUHCD_TD;
typedef struct _UHCD_QH *PUHCD_QH;
typedef struct _UHCD_TD {
TD_LINK_POINTER_PHYSICAL_ADDRESS HW_paLink; // DWORD1 - link used by host controller
// to find next TD/QH to process
DWORD ActualLength:11; // DWORD2, 0 ..10 - actual amount of data transferred
// encoded in (n-1) form
DWORD Reserved_1:1; // DWORD2, 11
DWORD fIsFinalTD:1; // DWORD2, 12 - indicates if it is a last TD
DWORD bTransferType:2; // DWORD2,13...14 - Transfer Type
DWORD bPipeType:2; // DWORD2,15...16 - Pipe Type
DWORD StatusField:6; // DWORD2, 17..22 - used to indicate done transfer's status
DWORD Active:1; // DWORD2, 23 - indicates whether transfer is active
DWORD InterruptOnComplete:1; // DWORD2, 24 - indicates to send USB interrupt when finished
DWORD Isochronous:1; // DWORD2, 25 - indicates Isochronous vs Queued transfer
DWORD LowSpeedControl:1; // DWORD2, 26 - indicates transfer to low speed device
DWORD ErrorCounter:2; // DWORD2, 27..28 - this field is decremented every time
// there is an error on the transfer
DWORD ShortPacketDetect:1; // DWORD2, 29 - indicates to allow ActualLength < MaxLength
DWORD ReservedMBZ:2; // DWORD2, 30..31
DWORD PID:8; // DWORD3, 0..7 - indicates SETUP/IN/OUT transfer
DWORD Address:7; // DWORD3, 8..14 - address of device to send transfer to
DWORD Endpoint:4; // DWORD3, 15..18 - endpoint on device to send transfer to
DWORD DataToggle:1; // DWORD3, 19 - used to send multipacket transfers
DWORD Reserved_2:1; // DWORD3, 20
DWORD MaxLength:11; // DWORD3, 21..31 - maximum data size to send/receive
//TD_BUFFER_PHYSICAL_ADDRESS HW_paBuffer; // DWORD4 - phys addr of data buffer
PUCHAR HW_vaBuffer; // DWORD4 - virtual addr of data buffer
// These 4 DWORDs are for software use
PUHCD_TD vaPrevIsochTD; // prev TD (only for Isoch)
PUHCD_TD vaNextTD; // next TD
PUHCD_QH pPipeQH;
UCHAR ezPort; //port number
UCHAR bUNUSED1;
USHORT wUNUSED2;
} UHCD_TD;
// Status bits for StatusField in UHCD_TD
// Reserved bit is taken care of by Reserved_1 above
#define TD_STATUS_NO_ERROR DWORD(0)
#define TD_STATUS_BITSTUFF_ERROR DWORD(1 << 0)
#define TD_STATUS_CRC_TIMEOUT_ERROR DWORD(1 << 1)
#define TD_STATUS_NAK_RECEIVED DWORD(1 << 2)
#define TD_STATUS_BABBLE_DETECTED DWORD(1 << 3)
#define TD_STATUS_DATA_BUFFER_ERROR DWORD(1 << 4)
#define TD_STATUS_STALLED DWORD(1 << 5)
#define TD_STATUS_EVERY_ERROR DWORD(TD_STATUS_BITSTUFF_ERROR | TD_STATUS_CRC_TIMEOUT_ERROR | TD_STATUS_NAK_RECEIVED | TD_STATUS_BABBLE_DETECTED | TD_STATUS_DATA_BUFFER_ERROR | TD_STATUS_STALLED)
// For ErrorCounter field
#define TD_ERRORCOUNTER_NEVER_INTERRUPT DWORD(0)
#define TD_ERRORCOUNTER_INTERRUPT_AFTER_ONE DWORD(1)
#define TD_ERRORCOUNTER_INTERRUPT_AFTER_TWO DWORD(2)
#define TD_ERRORCOUNTER_INTERRUPT_AFTER_THREE DWORD(3)
// Active bit has its own field above
// TDs are 32 bytes long
#define TD_REQUIRED_SIZE_IN_BYTES DWORD(32)
// TDs must be aligned on 16 byte boundaries
#define TD_ALIGNMENT_BOUNDARY DWORD(16)
#define TD_ENDPOINT_MASK DWORD(0xF)
// constants for MaxLength field
#define TD_MAXLENGTH_MAX DWORD(0x4FF)
#define TD_MAXLENGTH_INVALID DWORD(0x7FE)
#define TD_MAXLENGTH_NULL_BUFFER DWORD(0x7FF)
// constants for ActualLength field (used for SW to maintain data integrity)
#define TD_ACTUALLENGTH_INVALID TD_MAXLENGTH_INVALID
// constants for the PID (Packet Identifcation) field
// see UHCI spec 3.2.3
#define TD_IN_PID DWORD(0x69)
#define TD_OUT_PID DWORD(0xE1)
#define TD_SETUP_PID DWORD(0x2D)
// Queue Head for UHCI (Section 3.3 of UHCI spec)
typedef ULONG QUEUE_HEAD_LINK_POINTER_PHYSICAL_ADDRESS;
#define QUEUE_HEAD_LINK_POINTER_MASK DWORD(0xFFFFFFF0)
#define QUEUE_HEAD_LINK_POINTER_TERMINATE DWORD(1 << 0)
#define QUEUE_HEAD_LINK_POINTER_VALID DWORD(0 << 0)
#define QUEUE_HEAD_LINK_POINTER_QH DWORD(1 << 1)
// #define QUEUE_HEAD_LINK_POINTER_TD DWORD(0 << 1) <- our QH's never point horizontally to TDs
typedef ULONG QUEUE_ELEMENT_LINK_POINTER_PHYSICAL_ADDRESS;
#define QUEUE_ELEMENT_LINK_POINTER_MASK DWORD(0xFFFFFFF0)
#define QUEUE_ELEMENT_LINK_POINTER_TERMINATE DWORD(1 << 0)
#define QUEUE_ELEMENT_LINK_POINTER_VALID DWORD(0 << 0)
// #define QUEUE_ELEMENT_LINK_POINTER_QH DWORD(1 << 1) <- our QH's never point vertically to QHs
#define QUEUE_ELEMENT_LINK_POINTER_TD DWORD(0 << 1)
typedef struct _UHCD_QH {
QUEUE_HEAD_LINK_POINTER_PHYSICAL_ADDRESS HW_paHLink; // phys addr of next QH
QUEUE_ELEMENT_LINK_POINTER_PHYSICAL_ADDRESS HW_paVLink; // phys addr of queued TD
// queue heads must be aligned on 16 byte boundaries. We'll make
// them 32 bytes long. These fields are for SW use only.
PUHCD_QH vaPrevQH; // virt addr of prev QH
PUHCD_QH vaNextQH; // virt addr of next QH
PUHCD_TD vaVertTD; // virt addr of queued TD
// dwInterruptTree is used for interrupt transfer QHs.
// For m_interruptQHTree members, which are just placeholders and
// do not actually carry transfers, the Load field will describe
// how much interrupt traffic follows the QH branch. For other
// QHs, the BranchIndex field will describe where in the tree the
// QH is located
union {
DWORD Load;
DWORD BranchIndex;
} dwInterruptTree;
UCHAR ezPort; //port number
UCHAR bTransferType;
UCHAR fPipeIsHalted;
UCHAR fIsFinalQH;
PUHCD_TD pLoadedTD; // used for the EZ-Host
} UHCD_QH;
// QHs must be aligned on 16 byte boundaries
#define QH_ALIGNMENT_BOUNDARY DWORD(16)
// THIS ***MUST*** BE A POWER OF TWO!!! It is the maximum number of milliseconds
// that can go between polling for an interrupt on a device. We use this
// to set up the interrupt queue tree. This tree contains 2*MAX_INTERRUPT_INTERVAL - 1
// nodes, and allows us to specify intervals of 1, 2, 4, 8, ..., MAX_INTERRUPT_INTERVAL
#define UHCD_MAX_INTERRUPT_INTERVAL UCHAR(32)
// 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
PUCHAR vaTDList; // TD list for the transfer
USHORT numTDsInList; // # TDs in pTDListHead list
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;
};
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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -