From: Michael Martin Date: Sat, 16 Apr 2011 02:20:23 +0000 (+0000) Subject: [USBEHCI_NEW] X-Git-Tag: backups/usb-bringup@55523~144 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=9b44c5121d0ecef2fd3858281ca579e230746803;hp=a61d852c84f90cfc34389b0894bae10ecfd59e35 [USBEHCI_NEW] - Add flags and structures needed for communicating with controller and handling schedules. - Add support routines for modifying operational registers on controller. - Implement getting the controller capabilties, starting and stopping the controller. svn path=/branches/usb-bringup/; revision=51365 --- diff --git a/drivers/usb/usbehci_new/hardware.cpp b/drivers/usb/usbehci_new/hardware.cpp index 25adfec4a56..379d972df67 100644 --- a/drivers/usb/usbehci_new/hardware.cpp +++ b/drivers/usb/usbehci_new/hardware.cpp @@ -10,6 +10,13 @@ #define INITGUID #include "usbehci.h" +#include "hardware.h" + +BOOLEAN +NTAPI +InterruptServiceRoutine( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext); class CUSBHardwareDevice : public IUSBHardwareDevice { @@ -40,6 +47,8 @@ public: NTSTATUS GetDeviceDetails(PULONG VendorId, PULONG DeviceId, PULONG NumberOfPorts, PULONG Speed); NTSTATUS GetDmaMemoryManager(OUT struct IDMAMemoryManager **OutMemoryManager); NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue); + NTSTATUS StartController(); + NTSTATUS StopController(); NTSTATUS ResetController(); NTSTATUS ResetPort(ULONG PortIndex); KIRQL AcquireDeviceLock(void); @@ -65,6 +74,21 @@ protected: PULONG m_Base; PDMA_ADAPTER m_Adapter; ULONG m_MapRegisters; + PQUEUE_HEAD AsyncListQueueHead; + EHCI_CAPS m_Capabilities; + + VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd); + VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd); + VOID SetStatusRegister(PEHCI_USBSTS_CONTENT UsbSts); + VOID GetStatusRegister(PEHCI_USBSTS_CONTENT UsbSts); + //VOID SetPortRegister(PEHCI_USBPORTSC_CONTENT UsbPort); + //VOID GetPortRegister(PEHCI_USBPORTSC_CONTENT UsbPort); + ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset); + ULONG EHCI_READ_REGISTER_USHORT(ULONG Offset); + ULONG EHCI_READ_REGISTER_UCHAR(ULONG Offset); + VOID EHCI_WRITE_REGISTER_ULONG(ULONG Offset, ULONG Value); + VOID EHCI_WRITE_REGISTER_USHORT(ULONG Offset, ULONG Value); + VOID EHCI_WRITE_REGISTER_UCHAR(ULONG Offset, ULONG Value); }; //================================================================================================= @@ -112,13 +136,81 @@ CUSBHardwareDevice::Initialize( return STATUS_SUCCESS; } +VOID +CUSBHardwareDevice::SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd) +{ + PULONG Register; + Register = (PULONG)UsbCmd; + WRITE_REGISTER_ULONG((PULONG)((ULONG)m_Base + EHCI_USBCMD), *Register); +} + +VOID +CUSBHardwareDevice::GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd) +{ + PULONG Register; + Register = (PULONG)UsbCmd; + *Register = READ_REGISTER_ULONG((PULONG)((ULONG)m_Base + EHCI_USBCMD)); +} + + +VOID +CUSBHardwareDevice::SetStatusRegister(PEHCI_USBSTS_CONTENT UsbSts) +{ + PULONG Register; + Register = (PULONG)UsbSts; + WRITE_REGISTER_ULONG((PULONG)((ULONG)m_Base + EHCI_USBSTS), *Register); +} + +VOID +CUSBHardwareDevice::GetStatusRegister(PEHCI_USBSTS_CONTENT UsbSts) +{ + PULONG CmdRegister; + CmdRegister = (PULONG)UsbSts; + *CmdRegister = READ_REGISTER_ULONG((PULONG)((ULONG)m_Base + EHCI_USBSTS)); +} + +ULONG +CUSBHardwareDevice::EHCI_READ_REGISTER_ULONG(ULONG Offset) +{ + return READ_REGISTER_ULONG((PULONG)((ULONG)m_Base + Offset)); +} + +ULONG +CUSBHardwareDevice::EHCI_READ_REGISTER_USHORT(ULONG Offset) +{ + return READ_REGISTER_USHORT((PUSHORT)((ULONG)m_Base + Offset)); +} + +ULONG +CUSBHardwareDevice::EHCI_READ_REGISTER_UCHAR(ULONG Offset) +{ + return READ_REGISTER_UCHAR((PUCHAR)((ULONG)m_Base + Offset)); +} + +VOID +CUSBHardwareDevice::EHCI_WRITE_REGISTER_ULONG(ULONG Offset, ULONG Value) +{ + WRITE_REGISTER_ULONG((PULONG)((ULONG)m_Base + Offset), Value); +} + +VOID +CUSBHardwareDevice::EHCI_WRITE_REGISTER_USHORT(ULONG Offset, ULONG Value) +{ + WRITE_REGISTER_USHORT((PUSHORT)((ULONG)m_Base + Offset), Value); +} + +VOID +CUSBHardwareDevice::EHCI_WRITE_REGISTER_UCHAR(ULONG Offset, ULONG Value) +{ + WRITE_REGISTER_UCHAR((PUCHAR)((ULONG)m_Base + Offset), Value); +} NTSTATUS CUSBHardwareDevice::PnpStart( PCM_RESOURCE_LIST RawResources, PCM_RESOURCE_LIST TranslatedResources) { - ULONG Index; + ULONG Index, Count; PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; DEVICE_DESCRIPTION DeviceDescription; PVOID ResourceBase; @@ -174,8 +266,26 @@ CUSBHardwareDevice::PnpStart( } // - //FIXME: query capabilities and update m_Base + // Get controllers capabilities + // + m_Capabilities.Length = READ_REGISTER_UCHAR((PUCHAR)ResourceBase); + m_Capabilities.HCIVersion = READ_REGISTER_USHORT((PUSHORT)((ULONG)ResourceBase + 2)); + m_Capabilities.HCSParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 4)); + m_Capabilities.HCCParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 8)); + + DPRINT1("Controller has %d Ports\n", m_Capabilities.HCSParams.PortCount); + if (m_Capabilities.HCSParams.PortRouteRules) + { + for (Count = 0; Count < m_Capabilities.HCSParams.PortCount; Count++) + { + m_Capabilities.PortRoute[Count] = READ_REGISTER_UCHAR((PUCHAR)(ULONG)ResourceBase + 12 + Count); + } + } + + // + // Set m_Base to the address of Operational Register Space // + m_Base = (PULONG)((ULONG)ResourceBase + m_Capabilities.Length); break; } } @@ -211,7 +321,16 @@ CUSBHardwareDevice::PnpStart( return STATUS_INSUFFICIENT_RESOURCES; } - return STATUS_SUCCESS; + // + // FIXME: Create a QueueHead that will always be the address of the AsyncList + // + AsyncListQueueHead = NULL; + + // + // Start the controller + // + DPRINT1("Starting Controller\n"); + return StartController(); } NTSTATUS @@ -258,6 +377,140 @@ CUSBHardwareDevice::GetUSBQueue( return STATUS_NOT_IMPLEMENTED; } +NTSTATUS +CUSBHardwareDevice::StartController(void) +{ + EHCI_USBCMD_CONTENT UsbCmd; + EHCI_USBSTS_CONTENT UsbSts; + LONG FailSafe; + + // + // Stop the controller if its running + // + GetStatusRegister(&UsbSts); + if (UsbSts.HCHalted) + StopController(); + + // + // Reset the device. Bit is set to 0 on completion. + // + SetCommandRegister(&UsbCmd); + UsbCmd.HCReset = TRUE; + SetCommandRegister(&UsbCmd); + + // + // Check that the controller reset + // + for (FailSafe = 100; FailSafe > 1; FailSafe--) + { + KeStallExecutionProcessor(10); + GetCommandRegister(&UsbCmd); + if (!UsbCmd.HCReset) + { + break; + } + } + + // + // If the controller did not reset then fail + // + if (UsbCmd.HCReset) + { + DPRINT1("EHCI ERROR: Controller failed to reset. Hardware problem!\n"); + return STATUS_UNSUCCESSFUL; + } + + // + // Disable Interrupts and clear status + // + EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, 0); + EHCI_WRITE_REGISTER_ULONG(EHCI_USBSTS, 0x0000001f); + + // + // FIXME: Assign the AsyncList Register + // + + // + // Set Schedules to Enable and Interrupt Threshold to 1ms. + // + GetCommandRegister(&UsbCmd); + UsbCmd.PeriodicEnable = FALSE; + UsbCmd.AsyncEnable = FALSE; //FIXME: Need USB Memory Manager + + UsbCmd.IntThreshold = 1; + // FIXME: Set framlistsize when periodic is implemented. + SetCommandRegister(&UsbCmd); + + // + // Enable Interrupts and start execution + // + EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR + /*| EHCI_USBINTR_FLROVR*/ | EHCI_USBINTR_PC); + + UsbCmd.Run = TRUE; + SetCommandRegister(&UsbCmd); + + // + // Wait for execution to start + // + for (FailSafe = 100; FailSafe > 1; FailSafe--) + { + KeStallExecutionProcessor(10); + GetStatusRegister(&UsbSts); + + if (!UsbSts.HCHalted) + { + break; + } + } + + if (!UsbSts.HCHalted) + { + DPRINT1("Could not start execution on the controller\n"); + return STATUS_UNSUCCESSFUL; + } + + // + // Set port routing to EHCI controller + // + EHCI_WRITE_REGISTER_ULONG(EHCI_CONFIGFLAG, 1); + DPRINT1("EHCI Started!\n"); + return STATUS_SUCCESS; +} + +NTSTATUS +CUSBHardwareDevice::StopController(void) +{ + EHCI_USBCMD_CONTENT UsbCmd; + EHCI_USBSTS_CONTENT UsbSts; + LONG FailSafe; + + // + // Disable Interrupts and stop execution + EHCI_WRITE_REGISTER_ULONG (EHCI_USBINTR, 0); + + GetCommandRegister(&UsbCmd); + UsbCmd.Run = FALSE; + SetCommandRegister(&UsbCmd); + + for (FailSafe = 100; FailSafe > 1; FailSafe--) + { + KeStallExecutionProcessor(10); + GetStatusRegister(&UsbSts); + if (UsbSts.HCHalted) + { + break; + } + } + + if (!UsbSts.HCHalted) + { + DPRINT1("EHCI ERROR: Controller is not responding to Stop request!\n"); + return STATUS_UNSUCCESSFUL; + } + + return STATUS_SUCCESS; +} NTSTATUS CUSBHardwareDevice::ResetController(void) @@ -314,7 +567,8 @@ CreateUSBHardware( { PUSBHARDWAREDEVICE This; - This = new(NonPagedPool, 0) CUSBHardwareDevice(0); + This = new(NonPagedPool, TAG_USBEHCI) CUSBHardwareDevice(0); + if (!This) return STATUS_INSUFFICIENT_RESOURCES; diff --git a/drivers/usb/usbehci_new/hardware.h b/drivers/usb/usbehci_new/hardware.h new file mode 100644 index 00000000000..efabd43988c --- /dev/null +++ b/drivers/usb/usbehci_new/hardware.h @@ -0,0 +1,306 @@ +#pragma once + +#include + +// +// EHCI Operational Registers +// +#define EHCI_USBCMD 0x00 +#define EHCI_USBSTS 0x04 +#define EHCI_USBINTR 0x08 +#define EHCI_FRINDEX 0x0C +#define EHCI_CTRLDSSEGMENT 0x10 +#define EHCI_PERIODICLISTBASE 0x14 +#define EHCI_ASYNCLISTBASE 0x18 +#define EHCI_CONFIGFLAG 0x40 +#define EHCI_PORTSC 0x44 + +// +// Interrupt Register Flags +// +#define EHCI_USBINTR_INTE 0x01 +#define EHCI_USBINTR_ERR 0x02 +#define EHCI_USBINTR_PC 0x04 +#define EHCI_USBINTR_FLROVR 0x08 +#define EHCI_USBINTR_HSERR 0x10 +#define EHCI_USBINTR_ASYNC 0x20 +// Bits 6:31 Reserved + +// +// Status Register Flags +// +#define EHCI_STS_INT 0x01 +#define EHCI_STS_ERR 0x02 +#define EHCI_STS_PCD 0x04 +#define EHCI_STS_FLR 0x08 +#define EHCI_STS_FATAL 0x10 +#define EHCI_STS_IAA 0x20 +// Bits 11:6 Reserved +#define EHCI_STS_HALT 0x1000 +#define EHCI_STS_RECL 0x2000 +#define EHCI_STS_PSS 0x4000 +#define EHCI_STS_ASS 0x8000 +#define EHCI_ERROR_INT (EHCI_STS_FATAL | EHCI_STS_ERR) + +// +// Terminate Pointer used for QueueHeads and Element Transfer Descriptors to mark Pointers as the end +// +#define TERMINATE_POINTER 0x01 + +// +// QUEUE ELEMENT TRANSFER DESCRIPTOR, defines and structs +// + +// +// Token Flags +// +#define PID_CODE_OUT_TOKEN 0x00 +#define PID_CODE_IN_TOKEN 0x01 +#define PID_CODE_SETUP_TOKEN 0x02 + +#define DO_START_SPLIT 0x00 +#define DO_COMPLETE_SPLIT 0x01 + +#define PING_STATE_DO_OUT 0x00 +#define PING_STATE_DO_PING 0x01 + +typedef struct _PERIODICFRAMELIST +{ + PULONG VirtualAddr; + PHYSICAL_ADDRESS PhysicalAddr; + ULONG Size; +} PERIODICFRAMELIST, *PPERIODICFRAMELIST; + +// +// QUEUE ELEMENT TRANSFER DESCRIPTOR TOKEN +// +typedef struct _QETD_TOKEN_BITS +{ + ULONG PingState:1; + ULONG SplitTransactionState:1; + ULONG MissedMicroFrame:1; + ULONG TransactionError:1; + ULONG BabbleDetected:1; + ULONG DataBufferError:1; + ULONG Halted:1; + ULONG Active:1; + ULONG PIDCode:2; + ULONG ErrorCounter:2; + ULONG CurrentPage:3; + ULONG InterruptOnComplete:1; + ULONG TotalBytesToTransfer:15; + ULONG DataToggle:1; +} QETD_TOKEN_BITS, *PQETD_TOKEN_BITS; + +// +// QUEUE ELEMENT TRANSFER DESCRIPTOR +// +typedef struct _QUEUE_TRANSFER_DESCRIPTOR +{ + //Hardware + ULONG NextPointer; + ULONG AlternateNextPointer; + union + { + QETD_TOKEN_BITS Bits; + ULONG DWord; + } Token; + ULONG BufferPointer[5]; + + //Software + ULONG PhysicalAddr; + struct _QUEUE_TRANSFER_DESCRIPTOR *PreviousDescriptor; + struct _QUEUE_TRANSFER_DESCRIPTOR *NextDescriptor; +} QUEUE_TRANSFER_DESCRIPTOR, *PQUEUE_TRANSFER_DESCRIPTOR; + +// +// EndPointSpeeds Flags and END_POINT_CHARACTERISTICS +// +#define QH_ENDPOINT_FULLSPEED 0x00 +#define QH_ENDPOINT_LOWSPEED 0x01 +#define QH_ENDPOINT_HIGHSPEED 0x02 +typedef struct _END_POINT_CHARACTERISTICS +{ + ULONG DeviceAddress:7; + ULONG InactiveOnNextTransaction:1; + ULONG EndPointNumber:4; + ULONG EndPointSpeed:2; + ULONG QEDTDataToggleControl:1; + ULONG HeadOfReclamation:1; + ULONG MaximumPacketLength:11; + ULONG ControlEndPointFlag:1; + ULONG NakCountReload:4; +} END_POINT_CHARACTERISTICS, *PEND_POINT_CHARACTERISTICS; + +// +// Capabilities +// +typedef struct _END_POINT_CAPABILITIES +{ + ULONG InterruptScheduleMask:8; + ULONG SplitCompletionMask:8; + ULONG HubAddr:6; + ULONG PortNumber:6; + ULONG NumberOfTransactionPerFrame:2; +} END_POINT_CAPABILITIES, *PEND_POINT_CAPABILITIES; + +// +// QUEUE HEAD Flags and Struct +// +#define QH_TYPE_IDT 0x00 +#define QH_TYPE_QH 0x02 +#define QH_TYPE_SITD 0x04 +#define QH_TYPE_FSTN 0x06 + +typedef struct _QUEUE_HEAD +{ + //Hardware + ULONG HorizontalLinkPointer; + END_POINT_CHARACTERISTICS EndPointCharacteristics; + END_POINT_CAPABILITIES EndPointCapabilities; + // TERMINATE_POINTER not valid for this member + ULONG CurrentLinkPointer; + // TERMINATE_POINTER valid + ULONG NextPointer; + // TERMINATE_POINTER valid, bits 1:4 is NAK_COUNTERd + ULONG AlternateNextPointer; + // Only DataToggle, InterruptOnComplete, ErrorCounter, PingState valid + union + { + QETD_TOKEN_BITS Bits; + ULONG DWord; + } Token; + ULONG BufferPointer[5]; + + //Software + ULONG PhysicalAddr; + struct _QUEUE_HEAD *PreviousQueueHead; + struct _QUEUE_HEAD *NextQueueHead; + PQUEUE_TRANSFER_DESCRIPTOR TransferDescriptor; + PIRP IrpToComplete; + PMDL MdlToFree; + PKEVENT Event; +} QUEUE_HEAD, *PQUEUE_HEAD; + +// +// Command register content +// +typedef struct _EHCI_USBCMD_CONTENT +{ + ULONG Run : 1; + ULONG HCReset : 1; + ULONG FrameListSize : 2; + ULONG PeriodicEnable : 1; + ULONG AsyncEnable : 1; + ULONG DoorBell : 1; + ULONG LightReset : 1; + ULONG AsyncParkCount : 2; + ULONG Reserved : 1; + ULONG AsyncParkEnable : 1; + ULONG Reserved1 : 4; + ULONG IntThreshold : 8; + ULONG Reserved2 : 8; +} EHCI_USBCMD_CONTENT, *PEHCI_USBCMD_CONTENT; + +// +// Status register content +// +typedef struct _EHCI_USBSTS_CONTENT +{ + ULONG USBInterrupt:1; + ULONG ErrorInterrupt:1; + ULONG DetectChangeInterrupt:1; + ULONG FrameListRolloverInterrupt:1; + ULONG HostSystemErrorInterrupt:1; + ULONG AsyncAdvanceInterrupt:1; + ULONG Reserved:6; + ULONG HCHalted:1; + ULONG Reclamation:1; + ULONG PeriodicScheduleStatus:1; + ULONG AsynchronousScheduleStatus:1; +} EHCI_USBSTS_CONTENT, *PEHCI_USBSTS_CONTENT; + +typedef struct _EHCI_USBPORTSC_CONTENT +{ + ULONG CurrentConnectStatus:1; + ULONG ConnectStatusChange:1; + ULONG PortEnabled:1; + ULONG PortEnableChanged:1; + ULONG OverCurrentActive:1; + ULONG OverCurrentChange:1; + ULONG ForcePortResume:1; + ULONG Suspend:1; + ULONG PortReset:1; + ULONG Reserved:1; + ULONG LineStatus:2; + ULONG PortPower:1; + ULONG PortOwner:1; +} EHCI_USBPORTSC_CONTENT, *PEHCI_USBPORTSC_CONTENT; + +typedef struct _EHCI_HCS_CONTENT +{ + ULONG PortCount : 4; + ULONG PortPowerControl: 1; + ULONG Reserved : 2; + ULONG PortRouteRules : 1; + ULONG PortPerCHC : 4; + ULONG CHCCount : 4; + ULONG PortIndicator : 1; + ULONG Reserved2 : 3; + ULONG DbgPortNum : 4; + ULONG Reserved3 : 8; + +} EHCI_HCS_CONTENT, *PEHCI_HCS_CONTENT; + +typedef struct _EHCI_HCC_CONTENT +{ + ULONG CurAddrBits : 1; + ULONG VarFrameList : 1; + ULONG ParkMode : 1; + ULONG Reserved : 1; + ULONG IsoSchedThreshold : 4; + ULONG EECPCapable : 8; + ULONG Reserved2 : 16; + +} EHCI_HCC_CONTENT, *PEHCI_HCC_CONTENT; + +typedef struct _EHCI_CAPS { + UCHAR Length; + UCHAR Reserved; + USHORT HCIVersion; + union + { + EHCI_HCS_CONTENT HCSParams; + ULONG HCSParamsLong; + }; + union + { + EHCI_HCC_CONTENT HCCParams; + ULONG HCCParamsLong; + }; + UCHAR PortRoute [8]; +} EHCI_CAPS, *PEHCI_CAPS; + + +typedef struct +{ + PKSPIN_LOCK Lock; + RTL_BITMAP Bitmap; + PULONG BitmapBuffer; + ULONG BlockSize; + PVOID VirtualBase; + PHYSICAL_ADDRESS PhysicalBase; + ULONG Length; +}DMA_MEMORY_ALLOCATOR, *LPDMA_MEMORY_ALLOCATOR; + +typedef struct _EHCI_HOST_CONTROLLER +{ + ULONG OpRegisters; + EHCI_CAPS ECHICaps; + PVOID CommonBufferVA; + PHYSICAL_ADDRESS CommonBufferPA; + ULONG CommonBufferSize; + PQUEUE_HEAD AsyncListQueue; + KSPIN_LOCK Lock; + LPDMA_MEMORY_ALLOCATOR DmaMemAllocator; +} EHCI_HOST_CONTROLLER, *PEHCI_HOST_CONTROLLER;