[USBEHCI_NEW]
authorMichael Martin <michael.martin@reactos.org>
Sat, 16 Apr 2011 02:20:23 +0000 (02:20 +0000)
committerMichael Martin <michael.martin@reactos.org>
Sat, 16 Apr 2011 02:20:23 +0000 (02:20 +0000)
- 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

drivers/usb/usbehci_new/hardware.cpp
drivers/usb/usbehci_new/hardware.h [new file with mode: 0644]

index 25adfec..379d972 100644 (file)
 
 #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 (file)
index 0000000..efabd43
--- /dev/null
@@ -0,0 +1,306 @@
+#pragma once
+
+#include <ntddk.h>
+
+//
+// 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;