/*++ Copyright (c) 1993 Microsoft Corporation Module Name: openhci.h Abstract: This module contains the PRIVATE definitions for the code that implements the OpenHCI Host Controller Driver for USB. Environment: Kernel & user mode Revision History: 12-28-95 : created jfuller --*/ #include "stdarg.h" #include "wdm.h" #include "usbdi.h" #include "hcdi.h" #include "usbdlibi.h" #include "usbdlib.h" #include "dbg.h" #ifndef OPENHCI_H #define OPENHCI_H // #define COMPAQ // #define NEC // #define CMD // #define NSC //National Semiconductor #define NEC_XXX #define DISABLE_INT_DELAY_NO_INT 0 #define PREALLOCATE_DESCRIPTOR_MEMORY 1 #define PREALLOCATE_DESCRIPTOR_MEMORY_NUM_PAGES 2 #define RESOURCES_NOT_ON_IRP_STACK 0 #ifdef PNP_POWER #define PnPEnabled() TRUE #else #define PnPEnabled() FALSE #endif /* PNP_POWER */ #define HCD_PENDING_STATUS_SUBMITTING 0x40404001 #define HCD_PENDING_STATUS_SUBMITTED 0x40404002 #define HCD_PENDING_STATUS_QUEUED 0x40404003 // // OpenHCI PCI Identification values // #define OpenHCI_PCI_BASE_CLASS 0x0C // base class is serial bus #define OpenHCI_PCI_SUB_CLASS 0x03 // sub class is USB #define OpenHCI_PCI_PROG_IF 0x10 // programming interface is OpenHCI // // Tag for memory allocations: 'OHCI' // #define OpenHCI_TAG 0x4943484F // // Eventually CacheCommon should determine if the platform snoops i/o cycles; // for now, just cache memory allocated by HalAllocateCommonBuffer #define CacheCommon TRUE // // Maximum length of name strings used in initialization code // #define NAME_MAX 256 #define NAME_STRING L"\\Device\\USB#" /* 0 1234567 89012345 */ #define NAME_NO_POS 11 // // highest physical address we can use // #define OpenHCI_HIGHEST_ADDRESS 0x000000FFFFFFFF; // // Maximum frame and packet overhead // #define MAXIMUM_OVERHEAD 210 #define OHCI_PAGE_SIZE 0x1000 // #define OHCI_PAGE_SIZE 0x20 #define OHCI_PAGE_SIZE_MASK (OHCI_PAGE_SIZE - 1) #if DBG #if !defined(FAKEPORTCHANGE) #define FAKEPORTCHANGE 1 #endif #else #if !defined(FAKEPORTCHANGE) #define FAKEPORTCHANGE 0 #endif #endif #ifdef MAX_DEBUG #define OHCI_DEFAULT_DEBUG_OUTPUT_LEVEL 0xFFFFFFFF #else //#define OHCI_DEFAULT_DEBUG_OUTPUT_LEVEL 0xFEAAFFEE // 0xF8A8888E #define OHCI_DEFAULT_DEBUG_OUTPUT_LEVEL 0x00000000 #endif #define MIN(_A_,_B_) (((_A_) < (_B_)) ? (_A_) : (_B_)) #define IoDecrementStackLocation(IRP) \ (IRP)->CurrentLocation++; \ (IRP)->Tail.Overlay.CurrentStackLocation++; #define IoCopyStackToNextStack(IRP) \ { \ PIO_STACK_LOCATION now, later; \ now = IoGetCurrentIrpStackLocation (IRP); \ later = IoGetNextIrpStackLocation (IRP); \ later->Parameters = now->Parameters; \ later->MajorFunction = now->MajorFunction; \ later->MinorFunction = now->MinorFunction; \ later->Flags = now->Flags; \ } // // 7.1.1 HcRevision Register // Definition of Host Controller Revision register // typedef union _HC_REVISION { ULONG ul; struct { ULONG Rev:8; ULONG :24; }; } HC_REVISION, *PHC_REVISION; // // 7.1.2 HcControl Register // Definition of Host Controller Control register // typedef union _HC_CONTROL { ULONG ul; struct { ULONG ControlBulkServiceRatio:2; ULONG PeriodicListEnable:1; ULONG IsochronousEnable:1; ULONG ControlListEnable:1; ULONG BulkListEnable:1; ULONG HostControllerFunctionalState:2; ULONG InterruptRouting:1; ULONG RemoteWakeupConnected:1; ULONG RemoteWakeupEnable:1; ULONG :21; }; } HC_CONTROL, *PHC_CONTROL; #define HcCtrl_CBSR_MASK 0x00000003L #define HcCtrl_CBSR_1_to_1 0x00000000L #define HcCtrl_CBSR_2_to_1 0x00000001L #define HcCtrl_CBSR_3_to_1 0x00000002L #define HcCtrl_CBSR_4_to_1 0x00000003L #define HcCtrl_PeriodicListEnable 0x00000004L #define HcCtrl_IsochronousEnable 0x00000008L #define HcCtrl_ControlListEnable 0x00000010L #define HcCtrl_BulkListEnable 0x00000020L #define HcCtrl_ListEnableMask 0x00000038L #define HcCtrl_HCFS_MASK 0x000000C0L #define HcCtrl_HCFS_USBReset 0x00000000L #define HcCtrl_HCFS_USBResume 0x00000040L #define HcCtrl_HCFS_USBOperational 0x00000080L #define HcCtrl_HCFS_USBSuspend 0x000000C0L #define HcCtrl_InterruptRouting 0x00000100L #define HcCtrl_RemoteWakeupConnected 0x00000200L #define HcCtrl_RemoteWakeupEnable 0x00000400L #define HcHCFS_USBReset 0x00000000 #define HcHCFS_USBResume 0x00000001 #define HcHCFS_USBOperational 0x00000002 #define HcHCFS_USBSuspend 0x00000003 // // 7.1.3 HcCommandStatus Register // Definition of Host Controller Command/Status register // typedef union _HC_COMMAND_STATUS { ULONG ul; // use HcCmd flags below struct { ULONG HostControllerReset:1; ULONG ControlListFilled:1; ULONG BulkListFilled:1; ULONG OwnershipChangeRequest:1; ULONG :12; ULONG SchedulingOverrunCount:2; ULONG :14; }; } HC_COMMAND_STATUS, *PHC_COMMAND_STATUS; #define HcCmd_HostControllerReset 0x00000001 #define HcCmd_ControlListFilled 0x00000002 #define HcCmd_BulkListFilled 0x00000004 #define HcCmd_OwnershipChangeRequest 0x00000008 #define HcCmd_SOC_Mask 0x00030000 #define HcCmd_SOC_Offset 16 #define HcCmd_SOC_Mask_LowBits 0x00000003 // // 7.3.1 HcFmInterval Register // Definition of Host Controller Frame Interval register // typedef union _HC_FM_INTERVAL { ULONG ul; // use HcFmI flags below struct { ULONG FrameInterval:14; ULONG :2; ULONG FSLargestDataPacket:15; ULONG FrameIntervalToggle:1; }; } HC_FM_INTERVAL, *PHC_FM_INTERVAL; #define HcFmI_FRAME_INTERVAL_MASK 0x00003FFF #define HcFmI_FS_LARGEST_DATA_PACKET_MASK 0x7FFF0000 #define HcFmI_FS_LARGEST_DATA_PACKET_SHIFT 16 #define HcFmI_FRAME_INTERVAL_TOGGLE 0x80000000 // // 7.3.2 HcFmRemaining Register // Definition of Host Controller Frame Remaining register // typedef union _HC_FM_REMAINING { ULONG ul; struct { ULONG FrameRemaining:14; ULONG :17; ULONG FrameRemainingToggle:1; }; } HC_FM_REMAINING, *PHC_FM_REMAINING; // // 7.4.1 HcRhDescriptorA Register // Definition of Host Controller Root Hub DescriptorA register // typedef union _HC_RH_DESCRIPTOR_A { ULONG ul; struct { ULONG NumberDownstreamPorts:8; ULONG PowerSwitchingMode:1; ULONG NoPowerSwitching:1; ULONG :1; ULONG OverCurrentProtectionMode:1; ULONG NoOverCurrentProtection:1; ULONG :11; ULONG PowerOnToPowerGoodTime:8; }; } HC_RH_DESCRIPTOR_A, *PHC_RH_DESCRIPTOR_A; // // 7.4.2 HcRhDescriptorB Register // Definition of Host Controller Root Hub DescritorB register // typedef union _HC_RH_DESCRIPTOR_B { ULONG ul; struct { USHORT DeviceRemovableMask; USHORT PortPowerControlMask; }; } HC_RH_DESCRIPTOR_B, *PHC_RH_DESCRIPTOR_B; // // Host Controler Hardware Registers as accessed in memory // typedef struct _HC_OPERATIONAL_REGISTER { // 0 0x00 - 0,4,8,c HC_REVISION HcRevision; HC_CONTROL HcControl; HC_COMMAND_STATUS HcCommandStatus; ULONG HcInterruptStatus; // use HcInt flags below // 1 0x10 ULONG HcInterruptEnable; // use HcInt flags below ULONG HcInterruptDisable; // use HcInt flags below ULONG HcHCCA; // physical pointer to Host Controller Communications Area ULONG HcPeriodCurrentED; // physical ptr to current periodic ED // 2 0x20 ULONG HcControlHeadED; // physical ptr to head of control list ULONG HcControlCurrentED; // physical ptr to current control ED ULONG HcBulkHeadED; // physical ptr to head of bulk list ULONG HcBulkCurrentED; // physical ptr to current bulk ED // 3 0x30 ULONG HcDoneHead; // physical ptr to internal done queue HC_FM_INTERVAL HcFmInterval; HC_FM_REMAINING HcFmRemaining; ULONG HcFmNumber; // 4 0x40 ULONG HcPeriodicStart; ULONG HcLSThreshold; HC_RH_DESCRIPTOR_A HcRhDescriptorA; HC_RH_DESCRIPTOR_B HcRhDescriptorB; // 5 0x50 ULONG HcRhStatus; // use HcRhS flags below ULONG HcRhPortStatus[15]; // use HcRhPS flags below } HC_OPERATIONAL_REGISTER, *PHC_OPERATIONAL_REGISTER; // // 7.1.4 HcInterrruptStatus Register // 7.1.5 HcInterruptEnable Register // 7.1.6 HcInterruptDisable Register // #define HcInt_SchedulingOverrun 0x00000001L #define HcInt_WritebackDoneHead 0x00000002L #define HcInt_StartOfFrame 0x00000004L #define HcInt_ResumeDetected 0x00000008L #define HcInt_UnrecoverableError 0x00000010L #define HcInt_FrameNumberOverflow 0x00000020L #define HcInt_RootHubStatusChange 0x00000040L #define HcInt_OwnershipChange 0x40000000L #define HcInt_MasterInterruptEnable 0x80000000L // // 7.4.3 HcRhStatus Register // #define HcRhS_LocalPowerStatus 0x00000001 // read only #define HcRhS_OverCurrentIndicator 0x00000002 // read only #define HcRhS_DeviceRemoteWakeupEnable 0x00008000 // read only #define HcRhS_LocalPowerStatusChange 0x00010000 // read only #define HcRhS_OverCurrentIndicatorChange 0x00020000 // read only #define HcRhS_ClearGlobalPower 0x00000001 // write only #define HcRhS_SetRemoteWakeupEnable 0x00008000 // write only #define HcRhS_SetGlobalPower 0x00010000 // write only #define HcRhS_ClearOverCurrentIndicatorChange 0x00020000 // write only #define HcRhS_ClearRemoteWakeupEnable 0x80000000 // write only // // 7.4.4 HcRhPortStatus Register // #define HcRhPS_CurrentConnectStatus 0x00000001 // read only #define HcRhPS_PortEnableStatus 0x00000002 // read only #define HcRhPS_PortSuspendStatus 0x00000004 // read only #define HcRhPS_PortOverCurrentIndicator 0x00000008 // read only #define HcRhPS_PortResetStatus 0x00000010 // read only #define HcRhPS_PortPowerStatus 0x00000100 // read only #define HcRhPS_LowSpeedDeviceAttached 0x00000200 // read only #define HcRhPS_ConnectStatusChange 0x00010000 // read only #define HcRhPS_PortEnableStatusChange 0x00020000 // read only #define HcRhPS_PortSuspendStatusChange 0x00040000 // read only #define HcRhPS_OverCurrentIndicatorChange 0x00080000 // read only #define HcRhPS_PortResetStatusChange 0x00100000 // read only #define HcRhPS_ClearPortEnable 0x00000001 // write only #define HcRhPS_SetPortEnable 0x00000002 // write only #define HcRhPS_SetPortSuspend 0x00000004 // write only #define HcRhPS_ClearPortSuspend 0x00000008 // write only #define HcRhPS_SetPortReset 0x00000010 // write only #define HcRhPS_SetPortPower 0x00000100 // write only #define HcRhPS_ClearPortPower 0x00000200 // write only #define HcRhPS_ClearConnectStatusChange 0x00010000 // write only #define HcRhPS_ClearPortEnableStatusChange 0x00020000 // write only #define HcRhPS_ClearPortSuspendStatusChange 0x00040000 // write only #define HcRhPS_ClearPortOverCurrentChange 0x00080000 // write only #define HcRhPS_ClearPortResetStatusChange 0x00100000 // write only #define HcRhPS_RESERVED (~(HcRhPS_CurrentConnectStatus | \ HcRhPS_PortEnableStatus | \ HcRhPS_PortSuspendStatus | \ HcRhPS_PortOverCurrentIndicator | \ HcRhPS_PortResetStatus | \ HcRhPS_PortPowerStatus | \ HcRhPS_LowSpeedDeviceAttached | \ HcRhPS_ConnectStatusChange | \ HcRhPS_PortEnableStatusChange | \ HcRhPS_PortSuspendStatusChange | \ HcRhPS_OverCurrentIndicatorChange | \ HcRhPS_PortResetStatusChange \ )) // // Host Controller Communications Area // typedef struct _HCCA_BLOCK { ULONG HccaInterruptTable[32]; // physical pointer to interrupt lists USHORT HccaFrameNumber; // 16-bit current frame number USHORT HccaPad1; // When the HC updates // HccaFrameNumber, it sets // this word to zero. ULONG HccaDoneHead; // pointer to done queue ULONG Reserved[30]; // pad to 256 bytes } HCCA_BLOCK, *PHCCA_BLOCK; C_ASSERT(sizeof(HCCA_BLOCK) == 256); #define HCCADoneHead_INT_FLAG 0x00000001 // bit set if other ints pending // // Host Controller Endpoint Descriptor Control DWORD // typedef union _HC_ENDPOINT_CONTROL { ULONG Control; // use HcEDControl flags below struct { ULONG FunctionAddress:7; ULONG EndpointNumber:4; ULONG Direction:2; // use HcEDDirection flags below ULONG LowSpeed:1; ULONG sKip:1; ULONG Isochronous:1; ULONG MaxPacket:11; ULONG Unused:5; //available for software use }; } HC_ENDPOINT_CONTROL, *PHC_ENDPOINT_CONTROL; // // Definitions for HC_ENDPOINT_CONTROL.Control // #define HcEDControl_MPS_MASK 0x07FF0000 // Maximum Packet Size field #define HcEDControl_MPS_SHIFT 16 // Shift Count for MPS #define HcEDControl_ISOCH 0x00008000 // Bit set for isochronous endpoints #define HcEDControl_SKIP 0x00004000 // Bit tells hw to skip this endpoint #define HcEDControl_LOWSPEED 0x00002000 // Bit set if device is a low speed device #define HcEDControl_DIR_MASK 0x00001800 // Transfer direction field #define HcEDControl_DIR_DEFER 0x00000000 // Defer direction select to TD (Control Endpoints) #define HcEDControl_DIR_OUT 0x00000800 // Direction is from host to device #define HcEDControl_DIR_IN 0x00001000 // Direction is from device to host #define HcEDControl_EN_MASK 0x00000780 // Endpoint Number field #define HcEDControl_EN_SHIFT 7 // Shift Count for EN #define HcEDControl_FA_MASK 0x0000007F // Function Address field #define HcEDControl_FA_SHIFT 0 // Shift Count for FA // // Definitions for HC_ENDPOINT_CONTROL.Direction // #define HcEDDirection_Defer 0 // Defer direction to TD (Control Endpoints) #define HcEDDirection_Out 1 // Direction from host to device #define HcEDDirection_In 2 // Direction from device to host // // Host Controller Endpoint Descriptor, refer to Section 4.2, Endpoint Descriptor // typedef struct _HC_ENDPOINT_DESCRIPTOR { HC_ENDPOINT_CONTROL; // dword 0 ULONG TailP; //physical pointer to HC_TRANSFER_DESCRIPTOR volatile ULONG HeadP; //flags + phys ptr to HC_TRANSFER_DESCRIPTOR ULONG NextED; //phys ptr to HC_ENDPOINT_DESCRIPTOR } HC_ENDPOINT_DESCRIPTOR, *PHC_ENDPOINT_DESCRIPTOR; C_ASSERT(sizeof(HC_ENDPOINT_DESCRIPTOR) == 16); // // Definitions for HC_ENDPOINT_DESCRIPTOR.HeadP // #define HcEDHeadP_FLAGS 0x0000000F //mask for flags in HeadP #define HcEDHeadP_HALT 0x00000001 //hardware stopped bit #define HcEDHeadP_CARRY 0x00000002 //hardware toggle carry bit // // HCD Isochronous offset/status words // typedef union _HC_OFFSET_PSW { struct { USHORT Offset:13; // Offset within two pages of packet buffer USHORT Ones:3; // should be 111b when in Offset format }; struct { USHORT Size:11; // Size of packet received USHORT :1; // reserved USHORT ConditionCode:4; // use HcCC flags below }; USHORT PSW; // use HcPSW flags below } HC_OFFSET_PSW, *PHC_OFFSET_PSW; // // Definitions for HC_OFFSET_PSW.PSW // #define HcPSW_OFFSET_MASK 0x0FFF // Packet buffer offset field #define HcPSW_SECOND_PAGE 0x1000 // Is this packet on 2nd page #define HcPSW_ONES 0xE000 // The ones for Offset form #define HcPSW_CONDITION_CODE_MASK 0xF000 // Packet ConditionCode field #define HcPSW_CONDITION_CODE_SHIFT 12 // shift count for Code #define HcPSW_RETURN_SIZE 0x07FF // The size field. // // HCD Transfer Descriptor Control DWord // typedef union _HC_TRANSFER_CONTROL { ULONG Control; // use HcTDControl flags below struct _HC_GENERAL_TD_CONTROL{ ULONG :16; // available for s/w use in GTD ULONG IsochFlag:1; // should be 0 for GTD, s/w flag ULONG :1; // available for s/w use ULONG ShortXferOk:1; // if set don't report error on short transfer ULONG Direction:2; // use HcTDDirection flags below ULONG IntDelay:3; // use HcTDIntDelay flags below ULONG Toggle:2; // use HcTDToggle flags below ULONG ErrorCount:2; ULONG ConditionCode:4; // use HcCC flags below }; struct _HC_ISOCHRONOUS_TD_CONTROL{ ULONG StartingFrame:16; ULONG Isochronous:1; // should be 1 for ITD, s/w flag ULONG :1; // available for s/w use ULONG :3; // available for s/w use in ITD ULONG :3; // IntDelay ULONG FrameCount:3; // one less than number of frames described in ITD ULONG :1; // available for s/w use in ITD ULONG :4; // ConditionCode }; } HC_TRANSFER_CONTROL, *PHC_TRANSFER_CONTROL; // // Definitions for HC_TRANSFER_CONTROL.Control // #define HcTDControl_STARTING_FRAME 0x0000FFFF // mask for starting frame (Isochronous) #define HcTDControl_ISOCHRONOUS 0x00010000 // 1 for Isoch TD, 0 for General TD #define HcTDControl_SHORT_XFER_OK 0x00040000 // 0 if short transfers are errors #define HcTDControl_DIR_MASK 0x00180000 // Transfer direction field #define HcTDControl_DIR_SETUP 0x00000000 // direction is setup packet from host to device #define HcTDControl_DIR_OUT 0x00080000 // direction is from host to device #define HcTDControl_DIR_IN 0x00100000 // direction is from device to host #define HcTDControl_INT_DELAY_MASK 0x00E00000 // Interrupt Delay field #define HcTDControl_INT_DELAY_0_MS 0x00000000 // Interrupt at end of frame TD is completed #define HcTDControl_INT_DELAY_1_MS 0x00200000 // Interrupt no later than end of 1st frame after TD is completed #define HcTDControl_INT_DELAY_2_MS 0x00400000 // Interrupt no later than end of 2nd frame after TD is completed #define HcTDControl_INT_DELAY_3_MS 0x00600000 // Interrupt no later than end of 3rd frame after TD is completed #define HcTDControl_INT_DELAY_4_MS 0x00800000 // Interrupt no later than end of 4th frame after TD is completed #define HcTDControl_INT_DELAY_5_MS 0x00A00000 // Interrupt no later than end of 5th frame after TD is completed #define HcTDControl_INT_DELAY_6_MS 0x00C00000 // Interrupt no later than end of 6th frame after TD is completed #ifdef NSC #define HcTDControl_INT_DELAY_NO_INT 0x00C00000 // Almost infinity but not yet quite. #elif DISABLE_INT_DELAY_NO_INT #define HcTDControl_INT_DELAY_NO_INT 0x00000000 // Interrupt at the completion of all packets. #else #define HcTDControl_INT_DELAY_NO_INT 0x00E00000 // Do not cause an interrupt for normal completion of this TD #endif #define HcTDControl_FRAME_COUNT_MASK 0x07000000 // mask for FrameCount field (Isochronous) #define HcTDControl_FRAME_COUNT_SHIFT 24 // shift count for FrameCount (Isochronous) #define HcTDControl_FRAME_COUNT_MAX 8 // Max number of for frame count per TD #define HcTDControl_TOGGLE_MASK 0x03000000 // mask for Toggle control field #define HcTDControl_TOGGLE_FROM_ED 0x00000000 // get data toggle from CARRY field of ED #define HcTDControl_TOGGLE_DATA0 0x02000000 // use DATA0 for data PID #define HcTDControl_TOGGLE_DATA1 0x03000000 // use DATA1 for data PID #define HcTDControl_ERROR_COUNT 0x0C000000 // mask for Error Count field #define HcTDControl_CONDITION_CODE_MASK 0xF0000000 // mask for ConditionCode field #define HcTDControl_CONDITION_CODE_SHIFT 28 // shift count for ConditionCode // // Definitions for HC_TRANSFER_CONTROL.Direction // #define HcTDDirection_Setup 0 // setup packet from host to device #define HcTDDirection_Out 1 // direction from host to device #define HcTDDirection_In 2 // direction from device to host // // Definitions for Hc_TRANSFER_CONTROL.IntDelay // #define HcTDIntDelay_0ms 0 // interrupt at end of frame TD is completed #define HcTDIntDelay_1ms 1 // Interrupt no later than end of 1st frame after TD is completed #define HcTDIntDelay_2ms 2 // Interrupt no later than end of 2nd frame after TD is completed #define HcTDIntDelay_3ms 3 // Interrupt no later than end of 3rd frame after TD is completed #define HcTDIntDelay_4ms 4 // Interrupt no later than end of 4th frame after TD is completed #define HcTDIntDelay_5ms 5 // Interrupt no later than end of 5th frame after TD is completed #define HcTDIntDelay_6ms 6 // Interrupt no later than end of 6th frame after TD is completed #define HcTDIntDelay_NoInterrupt 7 // do not generate interrupt for normal completion of this TD // // Definitions for HC_TRANSFER_CONTROL.Toggle // #define HcTDToggle_FromEd 0 // get toggle for Endpoint Descriptor toggle CARRY bit #define HcTDToggle_Data0 2 // use Data0 PID #define HcTDToggle_Data1 3 // use Data1 PID // // Definitions for HC_TRANSFER_CONTROL.ConditionCode and HC_OFFSET_PSW.ConditionCode // #define HcCC_NoError 0x0UL #define HcCC_CRC 0x1UL #define HcCC_BitStuffing 0x2UL #define HcCC_DataToggleMismatch 0x3UL #define HcCC_Stall 0x4UL #define HcCC_DeviceNotResponding 0x5UL #define HcCC_PIDCheckFailure 0x6UL #define HcCC_UnexpectedPID 0x7UL #define HcCC_DataOverrun 0x8UL #define HcCC_DataUnderrun 0x9UL // 0xA // reserved // 0xB // reserved #define HcCC_BufferOverrun 0xCUL #define HcCC_BufferUnderrun 0xDUL #define HcCC_NotAccessed 0xEUL // 0xF // this also means NotAccessed // // Host Controller Transfer Descriptor, refer to Section 4.3, Transfer Descriptors // typedef struct _HC_TRANSFER_DESCRIPTOR { HC_TRANSFER_CONTROL; // dword 0 ULONG CBP; // phys ptr to start of buffer ULONG NextTD; // phys ptr to HC_TRANSFER_DESCRIPTOR ULONG BE; // phys ptr to end of buffer (last byte) HC_OFFSET_PSW Packet[8]; // isoch & Control packets } HC_TRANSFER_DESCRIPTOR, *PHC_TRANSFER_DESCRIPTOR; // // HCD Endpoint Descriptor // typedef struct _HCD_ENDPOINT_DESCRIPTOR { HC_ENDPOINT_DESCRIPTOR HcED; ULONG Pad[4]; // make Physical Address the same as in HCD_TRANSFER_DESCRIPTOR ULONG PhysicalAddress; UCHAR ListIndex; UCHAR PauseFlag; UCHAR Flags; UCHAR Reserved[1]; // fill out to 64 bytes LIST_ENTRY Link; struct _HCD_ENDPOINT *Endpoint; ULONG ReclamationFrame; LIST_ENTRY PausedLink; #ifdef _WIN64 ULONG Pad24[9]; // file out to 128 bytes #endif } HCD_ENDPOINT_DESCRIPTOR, *PHCD_ENDPOINT_DESCRIPTOR; C_ASSERT((sizeof(HCD_ENDPOINT_DESCRIPTOR) == 64) || (sizeof(HCD_ENDPOINT_DESCRIPTOR) == 128)); // Values for HCD_ENDPOINT_DESCRIPTOR->PauseFlag // // Used by: // // OpenHCI_CancelTDsForED() // OpenHCI_PauseED() // OpenHCI_CloseEndpoint() // // Normal state. If the endpoint is in this state, OpenHCI_PauseED() // will set the endpoint sKip bit, else the sKip bit is already set. // #define HCD_ED_PAUSE_NOT_PAUSED 0 // Set when OpenHCI_PauseED() is called, which is called either by // OpenHCI_CancelTransfer() or by OpenHCI_AbortEndpoint(). // #define HCD_ED_PAUSE_NEEDED 1 // Set when OpenHCI_CancelTDsForED() starts running. If the endpoint is // still in this state after OpenHCI_CancelTDsForED() has made a pass through // all of the requests queued on the endpoint, the pause is complete and // the state is set back to HCD_ED_PAUSE_NOT_PAUSED and the sKip is cleared. // Else the state is set back to HCD_ED_PAUSE_PROCESSING again and another // pass is made through all of the requests queued on the endpoints. // #define HCD_ED_PAUSE_PROCESSING 2 // // HCD Transfer Descriptor // // // HCD_TRANSFER_DESCRIPTOR and HCD_ENDPOINT_DESCRIPTOR structures are // allocated from a common pool and share the Flags field. // #define TD_FLAG_INUSE 0x01 // Indicates that the structure is allocated #define TD_FLAG_IS_ED 0x80 // Indicates that the structure is an ED // This structure MUST be exactly 64 or 128 bytes long // we use 128 byte EDs for the 64 bit platform typedef struct _HCD_TRANSFER_DESCRIPTOR { HC_TRANSFER_DESCRIPTOR HcTD; /* first 16 bytes */ ULONG PhysicalAddress; UCHAR BaseIsocURBOffset; BOOLEAN Canceled; UCHAR Flags; UCHAR Reserved[1]; // fill out to 64 bytes LIST_ENTRY RequestList; /* list of TDs for a req */ struct _HCD_TRANSFER_DESCRIPTOR *NextHcdTD; PHCD_URB UsbdRequest; struct _HCD_ENDPOINT *Endpoint; ULONG TransferCount; #ifdef _WIN64 ULONG64 _SortNext; ULONG Pad22[8]; // fill out to 128 bytes #endif } HCD_TRANSFER_DESCRIPTOR, *PHCD_TRANSFER_DESCRIPTOR; C_ASSERT((sizeof(HCD_TRANSFER_DESCRIPTOR) == 64) || (sizeof(HCD_TRANSFER_DESCRIPTOR) == 128)); C_ASSERT(sizeof(HCD_ENDPOINT_DESCRIPTOR) == sizeof(HCD_TRANSFER_DESCRIPTOR)); C_ASSERT(FIELD_OFFSET(HCD_ENDPOINT_DESCRIPTOR, PhysicalAddress) == FIELD_OFFSET(HCD_TRANSFER_DESCRIPTOR, PhysicalAddress)); C_ASSERT(FIELD_OFFSET(HCD_ENDPOINT_DESCRIPTOR, Flags) == FIELD_OFFSET(HCD_TRANSFER_DESCRIPTOR, Flags)); #ifdef _WIN64 #define SortNext _SortNext #else #define SortNext HcTD.NextTD #endif // // HCD Endpoint control structure // // set when ep is closed successfully #define EP_CLOSED 0x00000001 // set to if the root hub code owns this ep #define EP_ROOT_HUB 0x00000002 // need to abort all transfers for this endpoint #define EP_ABORT 0x00000004 // endpoint needs to be freed #define EP_FREE 0x00000008 // endpoint has had no transfers submitted, // restored on reset #define EP_VIRGIN 0x00000020 // limit endpoint to one outstanding TD #define EP_ONE_TD 0x00000040 // in active list #define EP_IN_ACTIVE_LIST 0x00000080 #define SET_EPFLAG(ep, flag) ((ep)->EpFlags |= (flag)) #define CLR_EPFLAG(ep, flag) ((ep)->EpFlags &= ~(flag)) typedef struct _HCD_ENDPOINT { ULONG Sig; PHCD_ENDPOINT_DESCRIPTOR HcdED; PHCD_TRANSFER_DESCRIPTOR HcdHeadP; PHCD_TRANSFER_DESCRIPTOR HcdTailP; ULONG EpFlags; UCHAR Pad[3]; UCHAR Rate; LIST_ENTRY RequestQueue; // Protected by QueueLock LIST_ENTRY EndpointListEntry; LONG EndpointStatus; // Requests currently on HW LONG MaxRequest; // Max requests allowed on HW UCHAR Type; UCHAR ListIndex; USHORT Bandwidth; struct _HCD_DEVICE_DATA *DeviceData; HC_ENDPOINT_CONTROL; // copy of control that is/will be in ULONG DescriptorsReserved; KSPIN_LOCK QueueLock; // QueueLock protects RequestQueue ULONG NextIsoFreeFrame; ULONG MaxTransfer; PVOID TrueTail; PIRP AbortIrp; } HCD_ENDPOINT, *PHCD_ENDPOINT; // // Each Host Controller Endpoint Descriptor is also doubly linked into a list tracked by HCD. // Each ED queue is managed via an HCD_ED_LIST // typedef struct _HCD_ED_LIST { LIST_ENTRY Head; PULONG PhysicalHead; USHORT Bandwidth; UCHAR Next; BOOLEAN HcRegister; // PhysicalHead is in a Host Controller register } HCD_ED_LIST, *PHCD_ED_LIST; // // The different ED lists are as follows. // #define ED_INTERRUPT_1ms 0 #define ED_INTERRUPT_2ms 1 #define ED_INTERRUPT_4ms 3 #define ED_INTERRUPT_8ms 7 #define ED_INTERRUPT_16ms 15 #define ED_INTERRUPT_32ms 31 #define ED_CONTROL 63 #define ED_BULK 64 #define ED_ISOCHRONOUS 0 // same as 1ms interrupt queue #define NO_ED_LISTS 65 #define ED_EOF 0xff // // HCD Descriptor Page List Entry data structure. // // These entries are used to link together the common buffer pages that are // allocated to hold TD and ED data structures. In addition, the HCCA and the // static EDs for the interrupt endpoint polling interval tree are contained // in the first common buffer page that is allocated. // typedef struct _PAGE_LIST_ENTRY *PPAGE_LIST_ENTRY; typedef struct _PAGE_LIST_ENTRY { PPAGE_LIST_ENTRY NextPage; // NULL terminated list ULONG BufferSize; // Allocated buffer size PHYSICAL_ADDRESS PhysAddr; // Base phys address of page PHYSICAL_ADDRESS FirstTDPhys; // Phys addr of the first TD PHYSICAL_ADDRESS LastTDPhys; // Phys addr of the last TD PCHAR VirtAddr; // Base virt address of page PHCD_TRANSFER_DESCRIPTOR FirstTDVirt; // Virt addr of the first TD PHCD_TRANSFER_DESCRIPTOR LastTDVirt; // Virt Addr of the last TD } PAGE_LIST_ENTRY, *PPAGE_LIST_ENTRY; //values for HcFlags #define HC_FLAG_REMOTE_WAKEUP_CONNECTED 0x00000001 #define HC_FLAG_LEGACY_BIOS_DETECTED 0x00000002 #define HC_FLAG_SLOW_BULK_ENABLE 0x00000004 #define HC_FLAG_SHUTDOWN 0x00000008 // not really used #define HC_FLAG_MAP_SX_TO_D3 0x00000010 #define HC_FLAG_IDLE 0x00000020 #define HC_FLAG_DISABLE_IDLE_CHECK 0x00000040 #define HC_FLAG_DEVICE_STARTED 0x00000080 #define HC_FLAG_LOST_POWER 0x00000100 #define HC_FLAG_DISABLE_IDLE_MODE 0x00000200 #define HC_FLAG_USE_HYDRA_HACK 0x00000400 #define HC_FLAG_IN_DPC 0x00000800 #define HC_FLAG_SUSPEND_NEXT_D3 0x00001000 #define HC_FLAG_LIST_FIX_ENABLE 0x00002000 #define HC_FLAG_HUNG_CHECK_ENABLE 0x00004000 #define PENDING_TD_LIST_SIZE 1000 // // HCD Device Data == Device Extention data // typedef struct _HCD_DEVICE_DATA { UCHAR UsbdWorkArea[sizeof(USBD_EXTENSION)]; ULONG DebugLevel; ULONG DeviceNameHandle; // handle passed to USBD to generate device name ULONG HcFlags; KSPIN_LOCK InterruptSpin; // Spinlock for interrupt PDEVICE_OBJECT DeviceObject; // point back to device object PDMA_ADAPTER AdapterObject; // point to our adapter object ULONG NumberOfMapRegisters;// max number of map registers per transfer PKINTERRUPT InterruptObject; // Pointer to interrupt object. KDPC IsrDPC; PHC_OPERATIONAL_REGISTER HC; // pointer to hw registers ULONG HClength; // save length for MmUnmapIoSpace PHCCA_BLOCK HCCA; // pointer to shared memory KSPIN_LOCK EDListSpin; // our pool of descriptors SINGLE_LIST_ENTRY FreeDescriptorList; ULONG FreeDescriptorCount; PPAGE_LIST_ENTRY PageList; // pages aquired for descriptors LIST_ENTRY StalledEDReclamation; LIST_ENTRY RunningEDReclamation; LIST_ENTRY PausedEDRestart; LIST_ENTRY ActiveEndpointList; // list of // endpoints that // processing LONG HcDma; HCD_ED_LIST EDList[NO_ED_LISTS]; HC_CONTROL CurrentHcControl; HC_CONTROL ListEnablesAtNextSOF; HC_FM_INTERVAL OriginalInterval; ULONG FrameHighPart; ULONG AvailableBandwidth; ULONG MaxBandwidthInUse; ULONG ControlSav; ULONG BulkSav; ULONG HcHCCASav; ULONG LostDoneHeadCount; // Diagnostic aid ULONG ResurrectHCCount; // Diagnostic aid ULONG FrozenHcDoneHead; ULONG LastHccaDoneHead; ULONGLONG LastDeadmanTime; KSPIN_LOCK DescriptorsSpin; KSPIN_LOCK ReclamationSpin; KSPIN_LOCK PausedSpin; KSPIN_LOCK HcFlagSpin; KSPIN_LOCK PageListSpin; KSPIN_LOCK HcDmaSpin; LARGE_INTEGER LastIdleTime; LONG IdleTime; struct { /* A context structure between Isr and Dpc */ ULONG ContextInfo; ULONG Frame; } IsrDpc_Context; BOOLEAN InterruptShare; UCHAR Pad3[3]; PHYSICAL_ADDRESS cardAddress; PHCD_ENDPOINT RootHubControl; PHCD_ENDPOINT RootHubInterrupt; // root hub interrupt endpoint (EP 1) UCHAR RootHubAddress; // device address of root hub (starts as 0) ULONG PortsSuspendedAtSuspend; ULONG PortsEnabledAtSuspend; DEVICE_POWER_STATE CurrentDevicePowerState; // When we suspend, the states of the ports are not kept by the host // controller through the resume. We have to find out what the states // are and put them back. These are bit masks of the ports that are // either set enabled or suspended. // UCHAR RootHubConfig; UCHAR NumberOfPorts; UCHAR Pad2[1]; UCHAR ZeroLoadEndpoint_AddrHolder; USHORT VendorID; USHORT DeviceID; UCHAR RevisionID; UCHAR Pad[3]; PDEVICE_OBJECT RealPhysicalDeviceObject; PDEVICE_OBJECT TopOfStackPhysicalDeviceObject; KTIMER DeadmanTimer; KDPC DeadmanTimerDPC; #define ZERO_LOAD_ENDPOINT(DeviceData) \ ((PVOID) (&(DeviceData)->ZeroLoadEndpoint_AddrHolder)) // // We need a memory location that will not be used by any other // pointer so that we can uniquely identify an endpoint on which there // is a max packet size of zero. AKA one with no load. // LONG OpenCloseSync; // Debugging tool to insure serial // _OpenEndpoint and _CloseEndpoint ULONG FakePortChange; // Per port bitmap ULONG FakePortDisconnect; // Per port bitmap } HCD_DEVICE_DATA, *PHCD_DEVICE_DATA; typedef struct _OHCI_RESOURCES { ULONG InterruptVector; KIRQL InterruptLevel; KAFFINITY Affinity; BOOLEAN ShareIRQ; KINTERRUPT_MODE InterruptMode; } OHCI_RESOURCES, *POHCI_RESOURCES; #define OHCI_MAP_INIT 0x01 typedef struct _MAP_CONTEXT { BOOLEAN Mapped; UCHAR Flags; UCHAR Pad[2]; PHYSICAL_ADDRESS PhysAddress; ULONG LengthMapped; PVOID CurrentVa; PVOID MapRegisterBase; ULONG TotalLength; } MAP_CONTEXT, *PMAP_CONTEXT; typedef struct _KeSync_HcControl { PHCD_DEVICE_DATA DeviceData; HC_CONTROL NewHcControl; } KeSynch_HcControl, *PKeSynch_HcControl; #ifdef DEBUG_LOG #ifdef IRP_LOG #define IRP_IN(i) OHCI_LogIrp((i), 1) #define IRP_OUT(i) OHCI_LogIrp((i), 0) #else #define IRP_IN(i) #define IRP_OUT(i) #endif #define LOGENTRY(m, sig, info1, info2, info3) \ OHCI_Debug_LogEntry(m, sig, (ULONG_PTR)info1, \ (ULONG_PTR)info2, \ (ULONG_PTR)info3) #define LOGIRQL() LOGENTRY(G, 'IRQL', KeGetCurrentIrql(), 0, 0); VOID OHCI_Debug_LogEntry( IN ULONG Mask, IN ULONG Sig, IN ULONG_PTR Info1, IN ULONG_PTR Info2, IN ULONG_PTR Info3 ); VOID OHCI_LogInit( ); VOID OHCI_LogFree( VOID ); #else #define LOGENTRY(mask, sig, info1, info2, info3) #define OHCI_LogInit() #define OHCI_LogFree() #define LOGIRQL() #define IRP_IN(i) #define IRP_OUT(i) #endif #define ENABLE_LIST(hc, ep) \ { \ ULONG listFilled = 0;\ ULONG temp;\ ASSERT_ENDPOINT(ep);\ \ temp = READ_REGISTER_ULONG (&(hc)->HcControlHeadED);\ if (temp) {\ listFilled |= HcCmd_ControlListFilled;\ }\ temp = READ_REGISTER_ULONG (&(hc)->HcBulkHeadED);\ if (temp) {\ listFilled |= HcCmd_BulkListFilled;\ }\ if (USB_ENDPOINT_TYPE_BULK == (ep)->Type) {\ listFilled |= HcCmd_BulkListFilled;\ } else if (USB_ENDPOINT_TYPE_CONTROL == (ep)->Type) {\ listFilled |= HcCmd_ControlListFilled;\ }\ WRITE_REGISTER_ULONG(&(hc)->HcCommandStatus.ul,\ listFilled);\ LOGENTRY(G, 'enaL', listFilled, ep, 0); \ }; // // Function Prototypes // BOOLEAN OpenHCI_InterruptService (IN PKINTERRUPT Interrupt, IN void * ServiceContext); NTSTATUS OpenHCI_URB_Dispatch (IN PDEVICE_OBJECT, IN PIRP); ULONG Get32BitFrameNumber (PHCD_DEVICE_DATA); PHCD_ENDPOINT_DESCRIPTOR InsertEDForEndpoint (IN PHCD_DEVICE_DATA, IN PHCD_ENDPOINT, IN UCHAR, IN PHCD_TRANSFER_DESCRIPTOR *); PHCD_TRANSFER_DESCRIPTOR OpenHCI_Alloc_HcdTD( PHCD_DEVICE_DATA DeviceData ); VOID OpenHCI_Free_HcdTD( PHCD_DEVICE_DATA DeviceData, PHCD_TRANSFER_DESCRIPTOR Td ); PHCD_ENDPOINT_DESCRIPTOR OpenHCI_Alloc_HcdED( PHCD_DEVICE_DATA DeviceData ); VOID OpenHCI_Free_HcdED( PHCD_DEVICE_DATA DeviceData, PHCD_ENDPOINT_DESCRIPTOR Ed ); PHCD_TRANSFER_DESCRIPTOR OpenHCI_LogDesc_to_PhyDesc (PHCD_DEVICE_DATA, ULONG); void OpenHCI_PauseED (PHCD_ENDPOINT); BOOLEAN OpenHCI_InterruptService (PKINTERRUPT, void *); void OpenHCI_IsrDPC (PKDPC, PVOID, PVOID, PVOID); void OpenHCI_CompleteIrp(PDEVICE_OBJECT, PIRP, NTSTATUS); BOOLEAN OpenHCI_StartController (PVOID context); void OpenHCI_StartEndpoint (PHCD_ENDPOINT); NTSTATUS OpenHCI_StartTransfer (PDEVICE_OBJECT, PIRP); NTSTATUS OpenHCI_RootHubStartXfer (PDEVICE_OBJECT, PHCD_DEVICE_DATA, PIRP, PHCD_URB, PHCD_ENDPOINT); BOOLEAN OpenHCI_HcControl_OR (PVOID); BOOLEAN OpenHCI_HcControl_AND (PVOID); BOOLEAN OpenHCI_HcControl_SetHCFS (PVOID); BOOLEAN OpenHCI_ListEnablesAtNextSOF (PVOID); void OpenHCI_CancelTransfer (PDEVICE_OBJECT, PIRP); NTSTATUS OpenHCI_AbortEndpoint(PDEVICE_OBJECT, PIRP, PHCD_DEVICE_DATA, PHCD_URB); void EmulateRootHubInterruptXfer(PHCD_DEVICE_DATA, PHC_OPERATIONAL_REGISTER); NTSTATUS CheckRootHub(PHCD_DEVICE_DATA , PHC_OPERATIONAL_REGISTER HC, PHCD_URB); //jd VOID RemoveEDForEndpoint( IN PHCD_ENDPOINT ); NTSTATUS OpenHCI_SetDevicePowerState( IN PDEVICE_OBJECT, IN PIRP, IN DEVICE_POWER_STATE ); NTSTATUS OpenHCI_DeferredStartDevice( IN PDEVICE_OBJECT, IN PIRP ); NTSTATUS OpenHCI_DeferIrpCompletion( PDEVICE_OBJECT, PIRP, PVOID ); NTSTATUS OpenHCI_StartDevice( IN PDEVICE_OBJECT, IN POHCI_RESOURCES ); NTSTATUS OpenHCI_QueryCapabilities( PDEVICE_OBJECT, PDEVICE_CAPABILITIES ); NTSTATUS OpenHCI_PnPAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject ); NTSTATUS OpenHCI_SaveHCstate( PHCD_DEVICE_DATA ); NTSTATUS OpenHCI_RestoreHCstate( PHCD_DEVICE_DATA, PBOOLEAN ); NTSTATUS OpenHCI_DeferPoRequestCompletion( IN PDEVICE_OBJECT, IN UCHAR, IN POWER_STATE, IN PVOID, IN PIO_STATUS_BLOCK ); NTSTATUS OpenHCI_RootHubPower( IN PDEVICE_OBJECT, IN PIRP ); NTSTATUS OpenHCI_ReserveDescriptors( IN PHCD_DEVICE_DATA, IN ULONG ); NTSTATUS OpenHCI_QueueTransfer( PDEVICE_OBJECT , PIRP ); NTSTATUS OpenHCI_Dispatch( IN PDEVICE_OBJECT , IN PIRP ); VOID OpenHCI_Unload( IN PDRIVER_OBJECT ); VOID OpenHCI_SetTranferError( PHCD_URB, NTSTATUS ); VOID OpenHCI_EndpointWorker( PHCD_ENDPOINT ); NTSTATUS OpenHCI_GrowDescriptorPool ( IN PHCD_DEVICE_DATA DeviceData, IN ULONG ReserveLength, OUT PCHAR *VirtAddr OPTIONAL, OUT PHYSICAL_ADDRESS *PhysAddr OPTIONAL ); VOID OpenHCI_LockAndCheckEndpoint( PHCD_ENDPOINT , PBOOLEAN , PBOOLEAN , PKIRQL ); VOID OpenHCI_UnlockEndpoint( PHCD_ENDPOINT , KIRQL ); BOOLEAN OpenHCI_StopController( IN PVOID ); NTSTATUS OpenHCI_StopDevice( IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN TouchTheHardware ); NTSTATUS OpenHCI_Shutdown( IN PDEVICE_OBJECT DeviceObject ); NTSTATUS OpenHCI_StartBIOS( IN PDEVICE_OBJECT DeviceObject ); NTSTATUS OpenHCI_StopBIOS( IN PDEVICE_OBJECT DeviceObject ); NTSTATUS OpenHCI_GetSOFRegModifyValue( IN PDEVICE_OBJECT DeviceObject, IN OUT PULONG SofModifyValue ); NTSTATUS OpenHCI_GetRegFlags( IN PDEVICE_OBJECT DeviceObject, IN OUT PULONG SofModifyValue ); VOID OpenHCI_DeadmanDPC( PKDPC Dpc, PVOID DeviceObject, PVOID Context1, PVOID Context2 ); NTSTATUS OpenHCI_InsertMagicEDs( IN PDEVICE_OBJECT DeviceObject ); NTSTATUS OpenHCI_ResurrectHC( PHCD_DEVICE_DATA DeviceData ); ULONG FindLostDoneHead ( IN PHCD_DEVICE_DATA DeviceData ); PHYSICAL_ADDRESS OpenHCI_IoMapTransfer( IN PMAP_CONTEXT MapContext, IN PDMA_ADAPTER DmaAdapter, IN PMDL Mdl, IN PVOID MapRegisterBase, IN PVOID CurrentVa, IN OUT PULONG Length, IN ULONG TotalLength, IN BOOLEAN WriteToDevice ); NTSTATUS OpenHCI_ExternalGetCurrentFrame( IN PDEVICE_OBJECT DeviceObject, IN PULONG CurrentFrame ); ULONG OpenHCI_ExternalGetConsumedBW( IN PDEVICE_OBJECT DeviceObject ); BOOLEAN OpenHCI_RhPortsIdle( PHCD_DEVICE_DATA DeviceData ); VOID OpenHCI_ProcessEndpoint( PHCD_DEVICE_DATA DeviceData, PHCD_ENDPOINT Endpoint ); NTSTATUS OpenHCI_Resume( PDEVICE_OBJECT DeviceObject, BOOLEAN LostPower ); ULONG ReadPortStatusFix( PHCD_DEVICE_DATA DeviceData, ULONG PortIndex ); #endif /* OPENHCI_H */