2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbehci/memory_manager.cpp
5 * PURPOSE: USB EHCI device driver.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
13 class CDMAMemoryManager
: public IDMAMemoryManager
16 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
18 STDMETHODIMP_(ULONG
) AddRef()
20 InterlockedIncrement(&m_Ref
);
23 STDMETHODIMP_(ULONG
) Release()
25 InterlockedDecrement(&m_Ref
);
35 // IDMAMemoryManager interface functions
36 virtual NTSTATUS
Initialize(IN PUSBHARDWAREDEVICE Device
, IN PKSPIN_LOCK Lock
, IN ULONG DmaBufferSize
, IN PVOID VirtualBase
, IN PHYSICAL_ADDRESS PhysicalAddress
, IN ULONG DefaultBlockSize
);
37 virtual NTSTATUS
Allocate(IN ULONG Size
, OUT PVOID
*OutVirtualBase
, OUT PPHYSICAL_ADDRESS OutPhysicalAddress
);
38 virtual NTSTATUS
Release(IN PVOID VirtualBase
, IN ULONG Size
);
40 // constructor / destructor
41 CDMAMemoryManager(IUnknown
*OuterUnknown
){}
42 virtual ~CDMAMemoryManager(){}
46 PUSBHARDWAREDEVICE m_Device
;
50 PHYSICAL_ADDRESS m_PhysicalAddress
;
53 PULONG m_BitmapBuffer
;
57 //----------------------------------------------------------------------------------------
60 CDMAMemoryManager::QueryInterface(
64 return STATUS_UNSUCCESSFUL
;
68 CDMAMemoryManager::Initialize(
69 IN PUSBHARDWAREDEVICE Device
,
71 IN ULONG DmaBufferSize
,
73 IN PHYSICAL_ADDRESS PhysicalAddress
,
74 IN ULONG DefaultBlockSize
)
81 PC_ASSERT(DmaBufferSize
>= PAGE_SIZE
);
82 PC_ASSERT(DmaBufferSize
% PAGE_SIZE
== 0);
83 PC_ASSERT(DefaultBlockSize
== 32 || DefaultBlockSize
== 64 || DefaultBlockSize
== 128);
86 // calculate bitmap length
88 BitmapLength
= (DmaBufferSize
/ DefaultBlockSize
) / 8;
91 // allocate bitmap buffer
93 m_BitmapBuffer
= (PULONG
)ExAllocatePoolWithTag(NonPagedPool
, BitmapLength
, TAG_USBEHCI
);
99 return STATUS_INSUFFICIENT_RESOURCES
;
105 RtlInitializeBitMap(&m_Bitmap
, m_BitmapBuffer
, BitmapLength
* 8);
110 RtlClearAllBits(&m_Bitmap
);
113 // initialize rest of memory allocator
115 m_PhysicalAddress
= PhysicalAddress
;
116 m_VirtualBase
= VirtualBase
;
117 m_DmaBufferSize
= DmaBufferSize
;
118 m_BitmapBuffer
= m_BitmapBuffer
;
120 m_BlockSize
= DefaultBlockSize
;
123 return STATUS_SUCCESS
;
127 CDMAMemoryManager::Allocate(
129 OUT PVOID
*OutVirtualAddress
,
130 OUT PPHYSICAL_ADDRESS OutPhysicalAddress
)
132 ULONG Length
, BlockCount
, FreeIndex
, StartPage
, EndPage
;
138 ASSERT(Size
< PAGE_SIZE
);
139 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
144 Length
= (Size
+ m_BlockSize
-1) & ~(m_BlockSize
-1);
152 // convert to block count
154 BlockCount
= Length
/ m_BlockSize
;
159 KeAcquireSpinLock(m_Lock
, &OldLevel
);
168 // search for an free index
170 FreeIndex
= RtlFindClearBits(&m_Bitmap
, BlockCount
, FreeIndex
);
173 // check if there was a block found
175 if (FreeIndex
== MAXULONG
)
178 // no free block found
184 // check that the allocation does not spawn over page boundaries
186 StartPage
= (FreeIndex
* m_BlockSize
);
187 StartPage
= (StartPage
!= 0 ? StartPage
/ PAGE_SIZE
: 0);
188 EndPage
= ((FreeIndex
+ BlockCount
) * m_BlockSize
) / PAGE_SIZE
;
191 // does the request start and end on the same page
193 if (StartPage
== EndPage
)
198 RtlSetBits(&m_Bitmap
, FreeIndex
, BlockCount
);
208 // request spawned over page boundary
209 // restart search on next page
211 FreeIndex
= (EndPage
* PAGE_SIZE
) / m_BlockSize
;
219 KeReleaseSpinLock(m_Lock
, OldLevel
);
222 // did allocation succeed
224 if (FreeIndex
== MAXULONG
)
227 // failed to allocate block, requestor must retry
229 return STATUS_UNSUCCESSFUL
;
235 *OutVirtualAddress
= (PVOID
)((ULONG_PTR
)m_VirtualBase
+ FreeIndex
* m_BlockSize
);
236 OutPhysicalAddress
->QuadPart
= m_PhysicalAddress
.QuadPart
+ FreeIndex
* m_BlockSize
;
241 RtlZeroMemory(*OutVirtualAddress
, Length
);
246 return STATUS_SUCCESS
;
250 CDMAMemoryManager::Release(
251 IN PVOID VirtualAddress
,
255 ULONG BlockOffset
= 0, BlockLength
;
260 PC_ASSERT(VirtualAddress
);
261 PC_ASSERT((ULONG_PTR
)VirtualAddress
>= (ULONG_PTR
)m_VirtualBase
);
262 PC_ASSERT((ULONG_PTR
)m_VirtualBase
+ m_DmaBufferSize
> (ULONG_PTR
)m_VirtualBase
);
265 // calculate block length
267 BlockLength
= ((ULONG_PTR
)VirtualAddress
- (ULONG_PTR
)m_VirtualBase
);
270 // check if its the first block
275 // divide by base block size
277 BlockOffset
= BlockLength
/ m_BlockSize
;
281 // align length to block size
283 Size
= (Size
+ m_BlockSize
- 1) & ~(m_BlockSize
- 1);
288 KeAcquireSpinLock(m_Lock
, &OldLevel
);
293 RtlClearBits(&m_Bitmap
, BlockOffset
, Size
);
298 KeReleaseSpinLock(m_Lock
, OldLevel
);
303 return STATUS_SUCCESS
;
307 CreateDMAMemoryManager(
308 PDMAMEMORYMANAGER
*OutMemoryManager
)
310 CDMAMemoryManager
* This
;
313 // allocate controller
315 This
= new(NonPagedPool
, TAG_USBEHCI
) CDMAMemoryManager(0);
319 // failed to allocate
321 return STATUS_INSUFFICIENT_RESOURCES
;
325 // add reference count
332 *OutMemoryManager
= (PDMAMEMORYMANAGER
)This
;
337 return STATUS_SUCCESS
;