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
;
139 ASSERT(Size
<= PAGE_SIZE
);
140 //ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
145 Length
= (Size
+ m_BlockSize
-1) & ~(m_BlockSize
-1);
153 // convert to block count
155 BlockCount
= Length
/ m_BlockSize
;
160 DPRINT(__FUNCTION__
" acquire\n");
161 KeAcquireSpinLock(m_Lock
, &OldLevel
);
162 DPRINT(__FUNCTION__
" acquired\n");
167 BlocksPerPage
= PAGE_SIZE
/ m_BlockSize
;
176 // search for an free index
178 FreeIndex
= RtlFindClearBits(&m_Bitmap
, BlockCount
, FreeIndex
);
181 // check if there was a block found
183 if (FreeIndex
== MAXULONG
)
186 // no free block found
192 // check that the allocation does not spawn over page boundaries
194 StartPage
= (FreeIndex
* m_BlockSize
);
195 StartPage
= (StartPage
!= 0 ? StartPage
/ PAGE_SIZE
: 0);
196 EndPage
= ((FreeIndex
+ BlockCount
) * m_BlockSize
) / PAGE_SIZE
;
199 // does the request start and end on the same page
201 if (StartPage
== EndPage
)
206 RtlSetBits(&m_Bitmap
, FreeIndex
, BlockCount
);
213 else if ((BlockCount
== BlocksPerPage
) && (FreeIndex
% BlocksPerPage
== 0))
216 // the request equals PAGE_SIZE and is aligned at page boundary
219 RtlSetBits(&m_Bitmap
, FreeIndex
, BlockCount
);
229 // request spawned over page boundary
230 // restart search on next page
232 FreeIndex
= (EndPage
* PAGE_SIZE
) / m_BlockSize
;
240 DPRINT(__FUNCTION__
"release\n");
241 KeReleaseSpinLock(m_Lock
, OldLevel
);
244 // did allocation succeed
246 if (FreeIndex
== MAXULONG
)
249 // failed to allocate block, requestor must retry
251 return STATUS_UNSUCCESSFUL
;
257 *OutVirtualAddress
= (PVOID
)((ULONG_PTR
)m_VirtualBase
+ FreeIndex
* m_BlockSize
);
258 OutPhysicalAddress
->QuadPart
= m_PhysicalAddress
.QuadPart
+ FreeIndex
* m_BlockSize
;
263 RtlZeroMemory(*OutVirtualAddress
, Length
);
268 return STATUS_SUCCESS
;
272 CDMAMemoryManager::Release(
273 IN PVOID VirtualAddress
,
277 ULONG BlockOffset
= 0, BlockLength
;
282 PC_ASSERT(VirtualAddress
);
283 PC_ASSERT((ULONG_PTR
)VirtualAddress
>= (ULONG_PTR
)m_VirtualBase
);
284 PC_ASSERT((ULONG_PTR
)m_VirtualBase
+ m_DmaBufferSize
> (ULONG_PTR
)m_VirtualBase
);
287 // calculate block length
289 BlockLength
= ((ULONG_PTR
)VirtualAddress
- (ULONG_PTR
)m_VirtualBase
);
292 // check if its the first block
297 // divide by base block size
299 BlockOffset
= BlockLength
/ m_BlockSize
;
303 // align length to block size
305 Size
= (Size
+ m_BlockSize
- 1) & ~(m_BlockSize
- 1);
310 DPRINT(__FUNCTION__
" acquire\n");
311 KeAcquireSpinLock(m_Lock
, &OldLevel
);
312 DPRINT(__FUNCTION__
" acquired\n");
317 RtlClearBits(&m_Bitmap
, BlockOffset
, Size
);
322 DPRINT(__FUNCTION__
"release\n");
323 KeReleaseSpinLock(m_Lock
, OldLevel
);
328 return STATUS_SUCCESS
;
332 CreateDMAMemoryManager(
333 PDMAMEMORYMANAGER
*OutMemoryManager
)
335 CDMAMemoryManager
* This
;
338 // allocate controller
340 This
= new(NonPagedPool
, TAG_USBEHCI
) CDMAMemoryManager(0);
344 // failed to allocate
346 return STATUS_INSUFFICIENT_RESOURCES
;
350 // add reference count
357 *OutMemoryManager
= (PDMAMEMORYMANAGER
)This
;
362 return STATUS_SUCCESS
;