mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 07:08:19 +00:00
418 lines
12 KiB
C
418 lines
12 KiB
C
/*
|
|
* PROJECT: ReactOS USB EHCI Miniport Driver
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: USBEHCI hardware declarations
|
|
* COPYRIGHT: Copyright 2017-2018 Vadim Galyant <vgal@rambler.ru>
|
|
*/
|
|
|
|
#define EHCI_FRAME_LIST_MAX_ENTRIES 1024 // Number of frames in Frame List
|
|
|
|
/* EHCI hardware registers */
|
|
#define EHCI_USBCMD 0
|
|
#define EHCI_USBSTS 1
|
|
#define EHCI_USBINTR 2
|
|
#define EHCI_FRINDEX 3
|
|
#define EHCI_CTRLDSSEGMENT 4
|
|
#define EHCI_PERIODICLISTBASE 5
|
|
#define EHCI_ASYNCLISTBASE 6
|
|
#define EHCI_CONFIGFLAG 16
|
|
#define EHCI_PORTSC 17
|
|
|
|
#define EHCI_FLADJ_PCI_CONFIG_OFFSET 0x61
|
|
|
|
typedef union _EHCI_LEGACY_EXTENDED_CAPABILITY {
|
|
struct {
|
|
ULONG CapabilityID : 8;
|
|
ULONG NextCapabilityPointer : 8;
|
|
ULONG BiosOwnedSemaphore : 1;
|
|
ULONG Reserved1 : 7;
|
|
ULONG OsOwnedSemaphore : 1;
|
|
ULONG Reserved2 : 7;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_LEGACY_EXTENDED_CAPABILITY;
|
|
|
|
C_ASSERT(sizeof(EHCI_LEGACY_EXTENDED_CAPABILITY) == sizeof(ULONG));
|
|
|
|
typedef union _EHCI_HC_STRUCTURAL_PARAMS {
|
|
struct {
|
|
ULONG PortCount : 4;
|
|
ULONG PortPowerControl : 1;
|
|
ULONG Reserved1 : 2;
|
|
ULONG PortRouteRules : 1;
|
|
ULONG PortsPerCompanion : 4;
|
|
ULONG CompanionControllers : 4;
|
|
ULONG PortIndicators : 1;
|
|
ULONG Reserved2 : 3;
|
|
ULONG DebugPortNumber : 4; //Optional
|
|
ULONG Reserved3 : 8;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_HC_STRUCTURAL_PARAMS;
|
|
|
|
C_ASSERT(sizeof(EHCI_HC_STRUCTURAL_PARAMS) == sizeof(ULONG));
|
|
|
|
typedef union _EHCI_HC_CAPABILITY_PARAMS {
|
|
struct {
|
|
ULONG Addressing64bitCapability : 1;
|
|
ULONG IsProgrammableFrameList : 1;
|
|
ULONG IsScheduleParkSupport : 1;
|
|
ULONG Reserved1 : 1;
|
|
ULONG IsoSchedulingThreshold : 4;
|
|
ULONG ExtCapabilitiesPointer : 8; // (EECP)
|
|
ULONG Reserved2 : 16;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_HC_CAPABILITY_PARAMS;
|
|
|
|
C_ASSERT(sizeof(EHCI_HC_CAPABILITY_PARAMS) == sizeof(ULONG));
|
|
|
|
typedef struct _EHCI_HC_CAPABILITY_REGISTERS {
|
|
UCHAR RegistersLength; // RO
|
|
UCHAR Reserved; // RO
|
|
USHORT InterfaceVersion; // RO
|
|
EHCI_HC_STRUCTURAL_PARAMS StructParameters; // RO
|
|
EHCI_HC_CAPABILITY_PARAMS CapParameters; // RO
|
|
UCHAR CompanionPortRouteDesc[8]; // RO
|
|
} EHCI_HC_CAPABILITY_REGISTERS, *PEHCI_HC_CAPABILITY_REGISTERS;
|
|
|
|
typedef union _EHCI_USB_COMMAND {
|
|
struct {
|
|
ULONG Run : 1;
|
|
ULONG Reset : 1;
|
|
ULONG FrameListSize : 2;
|
|
ULONG PeriodicEnable : 1;
|
|
ULONG AsynchronousEnable : 1;
|
|
ULONG InterruptAdvanceDoorbell : 1;
|
|
ULONG LightResetHC : 1; // optional
|
|
ULONG AsynchronousParkModeCount : 2; // optional
|
|
ULONG Reserved1 : 1;
|
|
ULONG AsynchronousParkModeEnable : 1; // optional
|
|
ULONG Reserved2 : 4;
|
|
ULONG InterruptThreshold : 8;
|
|
ULONG Reserved3 : 8;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_USB_COMMAND;
|
|
|
|
C_ASSERT(sizeof(EHCI_USB_COMMAND) == sizeof(ULONG));
|
|
|
|
typedef union _EHCI_USB_STATUS {
|
|
struct {
|
|
ULONG Interrupt : 1;
|
|
ULONG ErrorInterrupt : 1;
|
|
ULONG PortChangeDetect : 1;
|
|
ULONG FrameListRollover : 1;
|
|
ULONG HostSystemError : 1;
|
|
ULONG InterruptOnAsyncAdvance : 1;
|
|
ULONG Reserved1 : 6;
|
|
ULONG HCHalted : 1;
|
|
ULONG Reclamation : 1;
|
|
ULONG PeriodicStatus : 1;
|
|
ULONG AsynchronousStatus : 1;
|
|
ULONG Reserved2 : 16;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_USB_STATUS;
|
|
|
|
C_ASSERT(sizeof(EHCI_USB_STATUS) == sizeof(ULONG));
|
|
|
|
#define EHCI_INTERRUPT_MASK 0x3F
|
|
|
|
typedef union _EHCI_INTERRUPT_ENABLE {
|
|
struct {
|
|
ULONG Interrupt : 1;
|
|
ULONG ErrorInterrupt : 1;
|
|
ULONG PortChangeInterrupt : 1;
|
|
ULONG FrameListRollover : 1;
|
|
ULONG HostSystemError : 1;
|
|
ULONG InterruptOnAsyncAdvance : 1;
|
|
ULONG Reserved : 26;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_INTERRUPT_ENABLE;
|
|
|
|
C_ASSERT(sizeof(EHCI_INTERRUPT_ENABLE) == sizeof(ULONG));
|
|
|
|
#define EHCI_LINE_STATUS_K_STATE_LOW_SPEED 1
|
|
#define EHCI_PORT_OWNER_COMPANION_CONTROLLER 1
|
|
|
|
typedef union _EHCI_PORT_STATUS_CONTROL {
|
|
struct {
|
|
ULONG CurrentConnectStatus : 1;
|
|
ULONG ConnectStatusChange : 1;
|
|
ULONG PortEnabledDisabled : 1;
|
|
ULONG PortEnableDisableChange : 1;
|
|
ULONG OverCurrentActive : 1;
|
|
ULONG OverCurrentChange : 1;
|
|
ULONG ForcePortResume : 1;
|
|
ULONG Suspend : 1;
|
|
ULONG PortReset : 1;
|
|
ULONG Reserved1 : 1;
|
|
ULONG LineStatus : 2;
|
|
ULONG PortPower : 1;
|
|
ULONG PortOwner : 1;
|
|
ULONG PortIndicatorControl : 2;
|
|
ULONG PortTestControl : 4;
|
|
ULONG WakeOnConnectEnable : 1;
|
|
ULONG WakeOnDisconnectEnable : 1;
|
|
ULONG WakeOnOverCurrentEnable : 1;
|
|
ULONG Reserved2 : 9;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_PORT_STATUS_CONTROL;
|
|
|
|
C_ASSERT(sizeof(EHCI_PORT_STATUS_CONTROL) == sizeof(ULONG));
|
|
|
|
/* FRINDEX Frame Index Register */
|
|
#define EHCI_FRINDEX_FRAME_MASK 0x7FF
|
|
#define EHCI_FRINDEX_INDEX_MASK 0x3FF
|
|
|
|
#define EHCI_CONFIG_FLAG_CONFIGURED 1
|
|
|
|
typedef struct _EHCI_HW_REGISTERS {
|
|
EHCI_USB_COMMAND HcCommand; // RO, R/W (field dependent), WO
|
|
EHCI_USB_STATUS HcStatus; // RO, R/W, R/WC, (field dependent)
|
|
EHCI_INTERRUPT_ENABLE HcInterruptEnable; // R/W
|
|
ULONG FrameIndex; // R/W (Writes must be DWord Writes)
|
|
ULONG SegmentSelector; // R/W (Writes must be DWord Writes)
|
|
ULONG PeriodicListBase; // R/W (Writes must be DWord Writes)
|
|
ULONG AsyncListBase; // Read/Write (Writes must be DWord Writes)
|
|
ULONG Reserved[9];
|
|
ULONG ConfigFlag; // R/W
|
|
EHCI_PORT_STATUS_CONTROL PortControl[15]; // (1-15) RO, R/W, R/WC (field dependent)
|
|
} EHCI_HW_REGISTERS, *PEHCI_HW_REGISTERS;
|
|
|
|
/* Link Pointer */
|
|
#define EHCI_LINK_TYPE_iTD 0 // isochronous transfer descriptor
|
|
#define EHCI_LINK_TYPE_QH 1 // queue head
|
|
#define EHCI_LINK_TYPE_siTD 2 // split transaction isochronous transfer
|
|
#define EHCI_LINK_TYPE_FSTN 3 // frame span traversal node
|
|
|
|
/* Used for QHs and qTDs to mark Pointers as the end */
|
|
#define TERMINATE_POINTER 1
|
|
|
|
#define LINK_POINTER_MASK 0xFFFFFFE0
|
|
|
|
typedef union _EHCI_LINK_POINTER {
|
|
struct {
|
|
ULONG Terminate : 1;
|
|
ULONG Type : 2;
|
|
ULONG Reserved : 2;
|
|
ULONG Address : 27;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_LINK_POINTER;
|
|
|
|
C_ASSERT(sizeof(EHCI_LINK_POINTER) == sizeof(ULONG));
|
|
|
|
/* Isochronous (High-Speed) Transfer Descriptor (iTD) */
|
|
typedef union _EHCI_TRANSACTION_CONTROL {
|
|
struct {
|
|
ULONG xOffset : 12;
|
|
ULONG PageSelect : 3;
|
|
ULONG InterruptOnComplete : 1;
|
|
ULONG xLength : 12;
|
|
ULONG Status : 4;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_TRANSACTION_CONTROL;
|
|
|
|
C_ASSERT(sizeof(EHCI_TRANSACTION_CONTROL) == sizeof(ULONG));
|
|
|
|
typedef union _EHCI_TRANSACTION_BUFFER {
|
|
struct {
|
|
ULONG DeviceAddress : 7;
|
|
ULONG Reserved1 : 1;
|
|
ULONG EndpointNumber : 4;
|
|
ULONG DataBuffer0 : 20;
|
|
};
|
|
struct {
|
|
ULONG MaximumPacketSize : 11;
|
|
ULONG Direction : 1;
|
|
ULONG DataBuffer1 : 20;
|
|
};
|
|
struct {
|
|
ULONG Multi : 2;
|
|
ULONG Reserved2 : 10;
|
|
ULONG DataBuffer2 : 20;
|
|
};
|
|
struct {
|
|
ULONG Reserved3 : 12;
|
|
ULONG DataBuffer : 20;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_TRANSACTION_BUFFER;
|
|
|
|
C_ASSERT(sizeof(EHCI_TRANSACTION_BUFFER) == sizeof(ULONG));
|
|
|
|
typedef struct _EHCI_ISOCHRONOUS_TD { // must be aligned on a 32-byte boundary
|
|
EHCI_LINK_POINTER NextLink;
|
|
EHCI_TRANSACTION_CONTROL Transaction[8];
|
|
EHCI_TRANSACTION_BUFFER Buffer[7];
|
|
ULONG ExtendedBuffer[7];
|
|
} EHCI_ISOCHRONOUS_TD, *PEHCI_ISOCHRONOUS_TD;
|
|
|
|
C_ASSERT(sizeof(EHCI_ISOCHRONOUS_TD) == 92);
|
|
|
|
/* Split Transaction Isochronous Transfer Descriptor (siTD) */
|
|
typedef union _EHCI_FS_ENDPOINT_PARAMS {
|
|
struct {
|
|
ULONG DeviceAddress : 7;
|
|
ULONG Reserved1 : 1;
|
|
ULONG EndpointNumber : 4;
|
|
ULONG Reserved2 : 4;
|
|
ULONG HubAddress : 7;
|
|
ULONG Reserved3 : 1;
|
|
ULONG PortNumber : 7;
|
|
ULONG Direction : 1;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_FS_ENDPOINT_PARAMS;
|
|
|
|
C_ASSERT(sizeof(EHCI_FS_ENDPOINT_PARAMS) == sizeof(ULONG));
|
|
|
|
typedef union _EHCI_MICROFRAME_CONTROL {
|
|
struct {
|
|
ULONG StartMask : 8;
|
|
ULONG CompletionMask : 8;
|
|
ULONG Reserved : 16;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_MICROFRAME_CONTROL;
|
|
|
|
C_ASSERT(sizeof(EHCI_MICROFRAME_CONTROL) == sizeof(ULONG));
|
|
|
|
typedef union _EHCI_SPLIT_TRANSFER_STATE {
|
|
struct {
|
|
ULONG Status : 8;
|
|
ULONG ProgressMask : 8;
|
|
ULONG TotalBytes : 10;
|
|
ULONG Reserved : 4;
|
|
ULONG PageSelect : 1;
|
|
ULONG InterruptOnComplete : 1;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_SPLIT_TRANSFER_STATE;
|
|
|
|
C_ASSERT(sizeof(EHCI_SPLIT_TRANSFER_STATE) == sizeof(ULONG));
|
|
|
|
typedef union _EHCI_SPLIT_BUFFER_POINTER {
|
|
struct {
|
|
ULONG CurrentOffset : 12;
|
|
ULONG DataBuffer0 : 20;
|
|
};
|
|
struct {
|
|
ULONG TransactionCount : 3;
|
|
ULONG TransactionPosition : 2;
|
|
ULONG Reserved : 7;
|
|
ULONG DataBuffer1 : 20;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_SPLIT_BUFFER_POINTER;
|
|
|
|
C_ASSERT(sizeof(EHCI_SPLIT_BUFFER_POINTER) == sizeof(ULONG));
|
|
|
|
typedef struct _EHCI_SPLIT_ISOCHRONOUS_TD { // must be aligned on a 32-byte boundary
|
|
EHCI_LINK_POINTER NextLink;
|
|
EHCI_FS_ENDPOINT_PARAMS EndpointCharacteristics;
|
|
EHCI_MICROFRAME_CONTROL MicroFrameControl;
|
|
EHCI_SPLIT_TRANSFER_STATE TransferState;
|
|
EHCI_SPLIT_BUFFER_POINTER Buffer[2];
|
|
ULONG BackPointer;
|
|
ULONG ExtendedBuffer[2];
|
|
} EHCI_SPLIT_ISOCHRONOUS_TD, *PEHCI_SPLIT_ISOCHRONOUS_TD;
|
|
|
|
C_ASSERT(sizeof(EHCI_SPLIT_ISOCHRONOUS_TD) == 36);
|
|
|
|
/* Queue Element Transfer Descriptor (qTD) */
|
|
#define EHCI_MAX_QTD_BUFFER_PAGES 5
|
|
|
|
#define EHCI_TOKEN_STATUS_ACTIVE (1 << 7)
|
|
#define EHCI_TOKEN_STATUS_HALTED (1 << 6)
|
|
#define EHCI_TOKEN_STATUS_DATA_BUFFER_ERROR (1 << 5)
|
|
#define EHCI_TOKEN_STATUS_BABBLE_DETECTED (1 << 4)
|
|
#define EHCI_TOKEN_STATUS_TRANSACTION_ERROR (1 << 3)
|
|
#define EHCI_TOKEN_STATUS_MISSED_MICROFRAME (1 << 2)
|
|
#define EHCI_TOKEN_STATUS_SPLIT_STATE (1 << 1)
|
|
#define EHCI_TOKEN_STATUS_PING_STATE (1 << 0)
|
|
|
|
#define EHCI_TD_TOKEN_PID_OUT 0
|
|
#define EHCI_TD_TOKEN_PID_IN 1
|
|
#define EHCI_TD_TOKEN_PID_SETUP 2
|
|
#define EHCI_TD_TOKEN_PID_RESERVED 3
|
|
|
|
typedef union _EHCI_TD_TOKEN {
|
|
struct {
|
|
ULONG Status : 8;
|
|
ULONG PIDCode : 2;
|
|
ULONG ErrorCounter : 2;
|
|
ULONG CurrentPage : 3;
|
|
ULONG InterruptOnComplete : 1;
|
|
ULONG TransferBytes : 15;
|
|
ULONG DataToggle : 1;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_TD_TOKEN, *PEHCI_TD_TOKEN;
|
|
|
|
C_ASSERT(sizeof(EHCI_TD_TOKEN) == sizeof(ULONG));
|
|
|
|
typedef struct _EHCI_QUEUE_TD { // must be aligned on 32-byte boundaries
|
|
ULONG NextTD;
|
|
ULONG AlternateNextTD;
|
|
EHCI_TD_TOKEN Token;
|
|
ULONG Buffer[5];
|
|
ULONG ExtendedBuffer[5];
|
|
} EHCI_QUEUE_TD, *PEHCI_QUEUE_TD;
|
|
|
|
C_ASSERT(sizeof(EHCI_QUEUE_TD) == 52);
|
|
|
|
/* Queue Head */
|
|
#define EHCI_QH_EP_FULL_SPEED 0
|
|
#define EHCI_QH_EP_LOW_SPEED 1
|
|
#define EHCI_QH_EP_HIGH_SPEED 2
|
|
|
|
typedef union _EHCI_QH_EP_PARAMS {
|
|
struct {
|
|
ULONG DeviceAddress : 7;
|
|
ULONG InactivateOnNextTransaction : 1;
|
|
ULONG EndpointNumber : 4;
|
|
ULONG EndpointSpeed : 2;
|
|
ULONG DataToggleControl : 1;
|
|
ULONG HeadReclamationListFlag : 1;
|
|
ULONG MaximumPacketLength : 11; // corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize).
|
|
ULONG ControlEndpointFlag : 1;
|
|
ULONG NakCountReload : 4;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_QH_EP_PARAMS;
|
|
|
|
C_ASSERT(sizeof(EHCI_QH_EP_PARAMS) == sizeof(ULONG));
|
|
|
|
typedef union _EHCI_QH_EP_CAPS {
|
|
struct {
|
|
ULONG InterruptMask : 8;
|
|
ULONG SplitCompletionMask : 8;
|
|
ULONG HubAddr : 7;
|
|
ULONG PortNumber : 7;
|
|
ULONG PipeMultiplier : 2;
|
|
};
|
|
ULONG AsULONG;
|
|
} EHCI_QH_EP_CAPS;
|
|
|
|
C_ASSERT(sizeof(EHCI_QH_EP_CAPS) == sizeof(ULONG));
|
|
|
|
typedef struct _EHCI_QUEUE_HEAD { // must be aligned on 32-byte boundaries
|
|
EHCI_LINK_POINTER HorizontalLink;
|
|
EHCI_QH_EP_PARAMS EndpointParams;
|
|
EHCI_QH_EP_CAPS EndpointCaps;
|
|
ULONG CurrentTD;
|
|
ULONG NextTD;
|
|
ULONG AlternateNextTD;
|
|
EHCI_TD_TOKEN Token;
|
|
ULONG Buffer[5];
|
|
ULONG ExtendedBuffer[5];
|
|
} EHCI_QUEUE_HEAD, *PEHCI_QUEUE_HEAD;
|
|
|
|
C_ASSERT(sizeof(EHCI_QUEUE_HEAD) == 68);
|