[usb/usbehci]:
authorMichael Martin <michael.martin@reactos.org>
Thu, 30 Dec 2010 15:12:46 +0000 (15:12 +0000)
committerMichael Martin <michael.martin@reactos.org>
Thu, 30 Dec 2010 15:12:46 +0000 (15:12 +0000)
- Reorganization code to put hardware related structures and routines in own source files.
- Modify ResetPort to correctly reset the port instead of the controller.
- Implement allocating chunks of memory from the Common Buffer for use with the rest of source code.

svn path=/trunk/; revision=50223

reactos/drivers/usb/usbehci/hardware.c [new file with mode: 0644]
reactos/drivers/usb/usbehci/hardware.h [new file with mode: 0644]
reactos/drivers/usb/usbehci/physmem.c [new file with mode: 0644]
reactos/drivers/usb/usbehci/physmem.h [new file with mode: 0644]

diff --git a/reactos/drivers/usb/usbehci/hardware.c b/reactos/drivers/usb/usbehci/hardware.c
new file mode 100644 (file)
index 0000000..0adf59e
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbehci/hardware.c
+ * PURPOSE:     Hardware related routines.
+ * PROGRAMMERS:
+ *              Michael Martin (michael.martin@reactos.org)
+ */
+
+#include "hardware.h"
+#define NDEBUG
+#include <debug.h>
+
+//FORCEINLINE
+VOID
+SetAsyncListQueueRegister(PEHCI_HOST_CONTROLLER hcd, ULONG PhysicalAddr)
+{   
+    ULONG OpRegisters = hcd->OpRegisters;
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_ASYNCLISTBASE), PhysicalAddr);
+}
+
+//FORCEINLINE
+ULONG
+GetAsyncListQueueRegister(PEHCI_HOST_CONTROLLER hcd)
+{
+    ULONG OpRegisters = hcd->OpRegisters;
+    return READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_ASYNCLISTBASE));
+}
+
+//FORCEINLINE
+VOID
+SetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd, ULONG PhysicalAddr)
+{
+    ULONG OpRegisters = hcd->OpRegisters;
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_PERIODICLISTBASE), PhysicalAddr);
+}
+
+//FORCEINLINE
+ULONG
+GetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd)
+{
+    ULONG OpRegisters = hcd->OpRegisters;
+    return READ_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_PERIODICLISTBASE));
+}
+
+//FORCEINLINE
+ULONG
+ReadControllerStatus(PEHCI_HOST_CONTROLLER hcd)
+{
+    ULONG OpRegisters = hcd->OpRegisters;
+    return READ_REGISTER_ULONG ((PULONG) (OpRegisters + EHCI_USBSTS));
+}
+
+//FORCEINLINE
+VOID
+ClearControllerStatus(PEHCI_HOST_CONTROLLER hcd, ULONG Status)
+{
+    ULONG OpRegisters = hcd->OpRegisters;
+    WRITE_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBSTS), Status);
+}
+
+VOID
+ResetPort(PEHCI_HOST_CONTROLLER hcd, UCHAR Port)
+{
+    ULONG tmp;
+    ULONG OpRegisters = hcd->OpRegisters;
+    DPRINT1("Reset Port %x\n", Port);
+
+    tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)));
+    if (tmp & 0x400)
+    {
+        DPRINT1("Non HighSpeed device connected. Releasing ownership.\n");
+        WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)), 0x2000);
+    }
+
+    /* Get current port state */
+    tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)));
+
+    /* Set reset and clear enable */
+    tmp |= 0x100;
+    tmp &= ~0x04;
+    WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)), tmp);
+
+    /* USB 2.0 Spec 10.2.8.1, more than 50ms */
+    KeStallExecutionProcessor(100);
+
+    /* Clear reset */
+    tmp &= ~0x100;
+    WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)), tmp);
+
+    KeStallExecutionProcessor(100);
+
+    tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)));
+
+    if (tmp & 0x100)
+    {
+        DPRINT1("EHCI ERROR: Port Reset did not complete!\n");
+    }
+}
+
+VOID
+StopEhci(PEHCI_HOST_CONTROLLER hcd)
+{
+    ULONG OpRegisters = hcd->OpRegisters;
+    PEHCI_USBCMD_CONTENT UsbCmd;
+    PEHCI_USBSTS_CONTEXT UsbSts;
+    LONG FailSafe;
+    LONG tmp;
+
+    DPRINT1("Stopping Ehci controller\n");
+
+    WRITE_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBINTR), 0);
+
+    tmp = READ_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBCMD));
+    UsbCmd = (PEHCI_USBCMD_CONTENT) & tmp;
+    UsbCmd->Run = FALSE;
+    WRITE_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBCMD), tmp);
+
+    /* Wait for the device to stop */
+    for (FailSafe = 100; FailSafe > 1; FailSafe++)
+    {
+        KeStallExecutionProcessor(10);
+        tmp = READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBSTS));
+        UsbSts = (PEHCI_USBSTS_CONTEXT)&tmp;
+
+        if (UsbSts->HCHalted)
+        {
+            break;
+        }
+    }
+    if (!UsbSts->HCHalted)
+        DPRINT1("EHCI ERROR: Controller is not responding to Stop request!\n");
+}
+
+VOID
+StartEhci(PEHCI_HOST_CONTROLLER hcd)
+{
+    ULONG OpRegisters = hcd->OpRegisters;
+    PEHCI_USBCMD_CONTENT UsbCmd;
+    PEHCI_USBSTS_CONTEXT UsbSts;
+    LONG FailSafe;
+    LONG tmp;
+    LONG tmp2;
+
+    DPRINT("Starting Ehci controller\n");
+
+    tmp = READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBSTS));
+    UsbSts = (PEHCI_USBSTS_CONTEXT)&tmp;
+
+    if (!UsbSts->HCHalted)
+    {
+        StopEhci(hcd);
+    }
+
+    tmp = READ_REGISTER_ULONG ((PULONG)(OpRegisters + EHCI_USBCMD));
+
+    /* Reset the device */
+    UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
+    UsbCmd->HCReset = TRUE;
+    WRITE_REGISTER_ULONG ((PULONG)(OpRegisters + EHCI_USBCMD), tmp);
+
+    /* Wait for the device to reset */
+    for (FailSafe = 100; FailSafe > 1; FailSafe++)
+    {
+        KeStallExecutionProcessor(10);
+        tmp = READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBCMD));
+        UsbCmd = (PEHCI_USBCMD_CONTENT)&tmp;
+
+        if (!UsbCmd->HCReset)
+        {
+            break;
+        }
+        DPRINT("Waiting for reset, USBCMD: %x\n", READ_REGISTER_ULONG ((PULONG)(OpRegisters + EHCI_USBCMD)));
+    }
+
+    if (UsbCmd->HCReset)
+    {
+        DPRINT1("EHCI ERROR: Controller failed to reset! Will attempt to continue.\n");
+    }
+
+    UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
+
+    /* Disable Interrupts on the device */
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBINTR), 0);
+    /* Clear the Status */
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBSTS), 0x0000001f);
+
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_CTRLDSSEGMENT), 0);
+
+    SetAsyncListQueueRegister(hcd, hcd->AsyncListQueue->PhysicalAddr | QH_TYPE_QH);
+    /* Set the ansync and periodic to disable */
+    UsbCmd->PeriodicEnable = FALSE;
+    UsbCmd->AsyncEnable = TRUE;
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBCMD), tmp);
+
+    /* Set the threshold */
+    UsbCmd->IntThreshold = 1;
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBCMD), tmp);
+
+    /* Turn back on interrupts */
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBINTR),
+                        EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
+                        /*| EHCI_USBINTR_FLROVR*/  | EHCI_USBINTR_PC);
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBINTR),
+                        EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
+                        /*| EHCI_USBINTR_FLROVR*/  | EHCI_USBINTR_PC);
+
+    UsbCmd->Run = TRUE;
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBCMD), tmp);
+
+    /* Wait for the device to start */
+    for (;;)
+    {
+        KeStallExecutionProcessor(10);
+        tmp2 = READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBSTS));
+        UsbSts = (PEHCI_USBSTS_CONTEXT)&tmp2;
+
+        if (!UsbSts->HCHalted)
+        {
+            break;
+        }
+        DPRINT("Waiting for start, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG)(OpRegisters + EHCI_USBSTS)));
+    }
+
+    /* Set all port routing to ECHI controller */
+    WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_CONFIGFLAG), 1);
+}
+
+VOID
+GetCapabilities(PEHCI_CAPS PCap, ULONG CapRegister)
+{
+    PEHCI_HCS_CONTENT PHCS;
+    LONG i;
+
+    if (!PCap)
+        return;
+
+    PCap->Length = READ_REGISTER_UCHAR((PUCHAR)CapRegister);
+    PCap->Reserved = READ_REGISTER_UCHAR((PUCHAR)(CapRegister + 1));
+    PCap->HCIVersion = READ_REGISTER_USHORT((PUSHORT)(CapRegister + 2));
+    PCap->HCSParamsLong = READ_REGISTER_ULONG((PULONG)(CapRegister + 4));
+    PCap->HCCParams = READ_REGISTER_ULONG((PULONG)(CapRegister + 8));
+
+    DPRINT1("Length %d\n", PCap->Length);
+    DPRINT1("Reserved %d\n", PCap->Reserved);
+    DPRINT1("HCIVersion %x\n", PCap->HCIVersion);
+    DPRINT1("HCSParams %x\n", PCap->HCSParamsLong);
+    DPRINT1("HCCParams %x\n", PCap->HCCParams);
+
+    if (PCap->HCCParams & 0x02)
+        DPRINT1("Frame list size is configurable\n");
+
+    if (PCap->HCCParams & 0x01)
+        DPRINT1("64bit address mode not supported!\n");
+
+    DPRINT1("Number of Ports: %d\n", PCap->HCSParams.PortCount);
+
+    if (PCap->HCSParams.PortPowerControl)
+        DPRINT1("Port Power Control is enabled\n");
+
+    if (!PCap->HCSParams.CHCCount)
+    {
+        DPRINT1("Number of Companion Host controllers %x\n", PCap->HCSParams.CHCCount);
+        DPRINT1("Number of Ports Per CHC: %d\n", PCap->HCSParams.PortPerCHC);
+    }
+
+    PHCS = (PEHCI_HCS_CONTENT)&PCap->HCSParams;
+    if (PHCS->PortRouteRules)
+    {
+        for (i = 0; i < PCap->HCSParams.PortCount; i++)
+        {
+            PCap->PortRoute[i] = READ_REGISTER_UCHAR((PUCHAR) (CapRegister + 12 + i));
+        }
+    }
+}
diff --git a/reactos/drivers/usb/usbehci/hardware.h b/reactos/drivers/usb/usbehci/hardware.h
new file mode 100644 (file)
index 0000000..bc9d1d3
--- /dev/null
@@ -0,0 +1,307 @@
+#pragma once
+
+#include <ntddk.h>
+
+/* USB Command Register */
+#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
+
+/* USB Interrupt Register Flags 32 Bits */
+#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 32 Bits */
+#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 )
+
+
+/* Last bit in QUEUE ELEMENT TRANSFER DESCRIPTOR Next Pointer */
+/* Used for Queue Element Transfer Descriptor Pointers
+   and Queue Head Horizontal Link Pointers */
+#define TERMINATE_POINTER       0x01
+
+/* QUEUE ELEMENT TRANSFER DESCRIPTOR, Token defines and structs */
+
+/* PIDCodes for QETD_TOKEN
+OR with QUEUE_TRANSFER_DESCRIPTOR Token.PIDCode*/
+#define PID_CODE_OUT_TOKEN      0x00
+#define PID_CODE_IN_TOKEN       0x01
+#define PID_CODE_SETUP_TOKEN    0x02
+
+/* Split Transaction States
+OR with QUEUE_TRANSFER_DESCRIPTOR Token.SplitTransactionState */
+#define DO_START_SPLIT          0x00
+#define DO_COMPLETE_SPLIT       0x01
+
+/* Ping States, OR with QUEUE_TRANSFER_DESCRIPTOR Token. */
+#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 of 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;
+
+typedef struct _END_POINT_CAPABILITIES
+{
+    ULONG InterruptScheduleMask:8;
+    ULONG SplitCompletionMask:8;
+    ULONG HubAddr:6;
+    ULONG PortNumber:6;
+    /* Multi */
+    ULONG NumberOfTransactionPerFrame:2;
+} END_POINT_CAPABILITIES, *PEND_POINT_CAPABILITIES;
+
+
+/* QUEUE HEAD defines and structs */
+
+/* QUEUE HEAD Select Types, OR with QUEUE_HEAD HorizontalLinkPointer */
+#define QH_TYPE_IDT         0x00
+#define QH_TYPE_QH          0x02
+#define QH_TYPE_SITD            0x04
+#define QH_TYPE_FSTN            0x06
+
+/* QUEUE HEAD */
+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_COUNTER */
+    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;
+
+/* USBCMD register 32 bits */
+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;
+
+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_CONTEXT, *PEHCI_USBSTS_CONTEXT;
+
+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;
+    };
+    ULONG HCCParams;
+    UCHAR PortRoute [8];
+} EHCI_CAPS, *PEHCI_CAPS;
+
+typedef struct _EHCI_HOST_CONTROLLER
+{
+    ULONG OpRegisters;
+    EHCI_CAPS ECHICaps;
+    PVOID CommonBufferVA;
+    PHYSICAL_ADDRESS CommonBufferPA;
+    ULONG CommonBufferSize;
+    PQUEUE_HEAD AsyncListQueue;
+    KSPIN_LOCK Lock;
+} EHCI_HOST_CONTROLLER, *PEHCI_HOST_CONTROLLER;
+
+ULONG
+ReadControllerStatus(PEHCI_HOST_CONTROLLER hcd);
+
+VOID
+ClearControllerStatus(PEHCI_HOST_CONTROLLER hcd, ULONG Status);
+
+VOID
+GetCapabilities(PEHCI_CAPS PCap, ULONG CapRegister);
+
+VOID
+ResetPort(PEHCI_HOST_CONTROLLER hcd, UCHAR Port);
+
+VOID
+StartEhci(PEHCI_HOST_CONTROLLER hcd);
+
+VOID
+StopEhci(PEHCI_HOST_CONTROLLER hcd);
+
+VOID
+SetAsyncListQueueRegister(PEHCI_HOST_CONTROLLER hcd, ULONG PhysicalAddr);
+
+ULONG
+GetAsyncListQueueRegister(PEHCI_HOST_CONTROLLER hcd);
+
+VOID
+SetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd, ULONG PhysicalAddr);
+
+ULONG
+GetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd);
+
diff --git a/reactos/drivers/usb/usbehci/physmem.c b/reactos/drivers/usb/usbehci/physmem.c
new file mode 100644 (file)
index 0000000..ac6b4ed
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbehci/physmem.c
+ * PURPOSE:     Common Buffer routines.
+ * PROGRAMMERS:
+ *              Michael Martin (michael.martin@reactos.org)
+ */
+
+#include "physmem.h"
+#include "debug.h"
+
+#define SMALL_ALLOCATION_SIZE 32
+
+VOID
+DumpPages()
+{
+    //PMEM_HEADER MemBlock = (PMEM_HEADER)EhciSharedMemory.VirtualAddr;
+}
+
+// Returns Virtual Address of Allocated Memory
+ULONG
+AllocateMemory(PEHCI_HOST_CONTROLLER hcd, ULONG Size, ULONG *PhysicalAddress)
+{
+    PMEM_HEADER MemoryPage = (PMEM_HEADER)hcd->CommonBufferVA;
+    ULONG PageCount = 0;
+    ULONG NumberOfPages = hcd->CommonBufferSize / PAGE_SIZE;
+    ULONG BlocksNeeded;
+    ULONG i,j, freeCount;
+    ULONG RetAddr = 0;
+
+    Size = ((Size + SMALL_ALLOCATION_SIZE - 1) / SMALL_ALLOCATION_SIZE) * SMALL_ALLOCATION_SIZE;
+    BlocksNeeded = Size / SMALL_ALLOCATION_SIZE;
+
+    do
+    {
+        if (MemoryPage->IsFull)
+        {
+            PageCount++;
+            MemoryPage = (PMEM_HEADER)((ULONG)MemoryPage + PAGE_SIZE);
+            continue;
+        }
+        freeCount = 0;
+        for (i = 0; i < sizeof(MemoryPage->Entry); i++)
+        {
+            if (!MemoryPage->Entry[i].InUse)
+            {
+                freeCount++;
+            }
+            else
+            {
+                freeCount = 0;
+            }
+
+            if (freeCount == BlocksNeeded)
+            {
+                for (j = 0; j < freeCount; j++)
+                {
+                    MemoryPage->Entry[i-j].InUse = 1;
+                    MemoryPage->Entry[i-j].Blocks = 0;
+                }
+
+                MemoryPage->Entry[i-freeCount + 1].Blocks = BlocksNeeded;
+
+                RetAddr = (ULONG)MemoryPage + (SMALL_ALLOCATION_SIZE * (i - freeCount + 1)) + sizeof(MEM_HEADER);
+
+                *PhysicalAddress = (ULONG)hcd->CommonBufferPA.LowPart + (RetAddr - (ULONG)hcd->CommonBufferVA);
+                return RetAddr;
+            }
+        }
+
+        PageCount++;
+        MemoryPage = (PMEM_HEADER)((ULONG)MemoryPage + PAGE_SIZE);
+    } while (PageCount < NumberOfPages);
+
+    return 0;
+}
+
+VOID
+ReleaseMemory(ULONG Address)
+{
+    PMEM_HEADER MemoryPage;
+    ULONG Index, i;
+
+    MemoryPage = (PMEM_HEADER)(Address & ~(PAGE_SIZE - 1));
+
+    Index = (Address - ((ULONG)MemoryPage + sizeof(MEM_HEADER))) / SMALL_ALLOCATION_SIZE;
+
+    for (i = 0; i < MemoryPage->Entry[Index].Blocks; i++)
+    {
+        MemoryPage->Entry[Index + i].InUse = 0;
+        MemoryPage->Entry[Index + i].Blocks = 0;
+    }
+}
diff --git a/reactos/drivers/usb/usbehci/physmem.h b/reactos/drivers/usb/usbehci/physmem.h
new file mode 100644 (file)
index 0000000..9b9de0b
--- /dev/null
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "hardware.h"
+
+typedef struct _MEM_ENTRY
+{
+    UCHAR InUse:1;
+    UCHAR Blocks:7;
+} MEM_ENTRY, *PMEM_ENTRY;
+
+typedef struct _MEM_HEADER
+{
+    UCHAR IsFull;
+    MEM_ENTRY Entry[127];    
+} MEM_HEADER, *PMEM_HEADER;
+
+VOID
+DumpPages();
+
+ULONG
+AllocateMemory(PEHCI_HOST_CONTROLLER hcd, ULONG Size, ULONG *PhysicalAddress);
+
+VOID
+ReleaseMemory(ULONG Address);
+