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/usbohci/memory_manager.cpp
5 * PURPOSE: USB OHCI 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_USBOHCI
);
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 KeAcquireSpinLock(m_Lock
, &OldLevel
);
165 BlocksPerPage
= PAGE_SIZE
/ m_BlockSize
;
174 // search for an free index
176 FreeIndex
= RtlFindClearBits(&m_Bitmap
, BlockCount
, FreeIndex
);
179 // check if there was a block found
181 if (FreeIndex
== MAXULONG
)
184 // no free block found
190 // check that the allocation does not spawn over page boundaries
192 StartPage
= (FreeIndex
* m_BlockSize
);
193 StartPage
= (StartPage
!= 0 ? StartPage
/ PAGE_SIZE
: 0);
194 EndPage
= ((FreeIndex
+ BlockCount
) * m_BlockSize
) / PAGE_SIZE
;
197 // does the request start and end on the same page
199 if (StartPage
== EndPage
)
204 RtlSetBits(&m_Bitmap
, FreeIndex
, BlockCount
);
211 else if ((BlockCount
== BlocksPerPage
) && (FreeIndex
% BlocksPerPage
== 0))
214 // the request equals PAGE_SIZE and is aligned at page boundary
217 RtlSetBits(&m_Bitmap
, FreeIndex
, BlockCount
);
227 // request spawned over page boundary
228 // restart search on next page
230 FreeIndex
= (EndPage
* PAGE_SIZE
) / m_BlockSize
;
238 KeReleaseSpinLock(m_Lock
, OldLevel
);
241 // did allocation succeed
243 if (FreeIndex
== MAXULONG
)
246 // failed to allocate block, requestor must retry
248 return STATUS_UNSUCCESSFUL
;
254 *OutVirtualAddress
= (PVOID
)((ULONG_PTR
)m_VirtualBase
+ FreeIndex
* m_BlockSize
);
255 OutPhysicalAddress
->QuadPart
= m_PhysicalAddress
.QuadPart
+ FreeIndex
* m_BlockSize
;
260 RtlZeroMemory(*OutVirtualAddress
, Length
);
265 return STATUS_SUCCESS
;
269 CDMAMemoryManager::Release(
270 IN PVOID VirtualAddress
,
274 ULONG BlockOffset
= 0, BlockLength
, BlockCount
;
279 PC_ASSERT(VirtualAddress
);
280 PC_ASSERT((ULONG_PTR
)VirtualAddress
>= (ULONG_PTR
)m_VirtualBase
);
281 PC_ASSERT((ULONG_PTR
)m_VirtualBase
+ m_DmaBufferSize
> (ULONG_PTR
)m_VirtualBase
);
284 // calculate block length
286 BlockLength
= ((ULONG_PTR
)VirtualAddress
- (ULONG_PTR
)m_VirtualBase
);
289 // check if its the first block
294 // divide by base block size
296 BlockOffset
= BlockLength
/ m_BlockSize
;
300 // align length to block size
302 Size
= (Size
+ m_BlockSize
- 1) & ~(m_BlockSize
- 1);
307 BlockCount
= Size
/ m_BlockSize
;
313 KeAcquireSpinLock(m_Lock
, &OldLevel
);
318 ASSERT(RtlAreBitsSet(&m_Bitmap
, BlockOffset
, BlockCount
));
323 RtlClearBits(&m_Bitmap
, BlockOffset
, BlockCount
);
328 KeReleaseSpinLock(m_Lock
, OldLevel
);
333 return STATUS_SUCCESS
;
337 CreateDMAMemoryManager(
338 PDMAMEMORYMANAGER
*OutMemoryManager
)
340 CDMAMemoryManager
* This
;
343 // allocate controller
345 This
= new(NonPagedPool
, TAG_USBOHCI
) CDMAMemoryManager(0);
349 // failed to allocate
351 return STATUS_INSUFFICIENT_RESOURCES
;
355 // add reference count
362 *OutMemoryManager
= (PDMAMEMORYMANAGER
)This
;
367 return STATUS_SUCCESS
;