ReactOS  0.4.13-dev-241-g63286c6
memory_manager.cpp
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: lib/drivers/libusb/memory_manager.cpp
5  * PURPOSE: USB Common Driver Library.
6  * PROGRAMMERS:
7  * Michael Martin (michael.martin@reactos.org)
8  * Johannes Anderwald (johannes.anderwald@reactos.org)
9  */
10 
11 #include "libusb.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 class CDMAMemoryManager : public IDMAMemoryManager
17 {
18 public:
20 
22  {
24  return m_Ref;
25  }
27  {
29 
30  if (!m_Ref)
31  {
32  delete this;
33  return 0;
34  }
35  return m_Ref;
36  }
37 
38  // IDMAMemoryManager interface functions
39  virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Device, IN PKSPIN_LOCK Lock, IN ULONG DmaBufferSize, IN PVOID VirtualBase, IN PHYSICAL_ADDRESS PhysicalAddress, IN ULONG DefaultBlockSize);
40  virtual NTSTATUS Allocate(IN ULONG Size, OUT PVOID *OutVirtualBase, OUT PPHYSICAL_ADDRESS OutPhysicalAddress);
41  virtual NTSTATUS Release(IN PVOID VirtualBase, IN ULONG Size);
42 
43  // constructor / destructor
44  CDMAMemoryManager(IUnknown *OuterUnknown){}
45  virtual ~CDMAMemoryManager(){}
46 
47 protected:
55 
58 };
59 
60 //----------------------------------------------------------------------------------------
64  IN REFIID refiid,
65  OUT PVOID* Output)
66 {
67  return STATUS_UNSUCCESSFUL;
68 }
69 
74  IN ULONG DmaBufferSize,
75  IN PVOID VirtualBase,
77  IN ULONG DefaultBlockSize)
78 {
79  ULONG BitmapLength;
80 
81  //
82  // sanity checks
83  //
84  PC_ASSERT(DmaBufferSize >= PAGE_SIZE);
85  PC_ASSERT(DmaBufferSize % PAGE_SIZE == 0);
86  PC_ASSERT(DefaultBlockSize == 32 || DefaultBlockSize == 64 || DefaultBlockSize == 128);
87 
88  //
89  // calculate bitmap length
90  //
91  BitmapLength = (DmaBufferSize / DefaultBlockSize) / 8;
92 
93  //
94  // allocate bitmap buffer
95  //
97  if (!m_BitmapBuffer)
98  {
99  //
100  // no memory
101  //
103  }
104 
105  //
106  // initialize bitmap
107  //
108  RtlInitializeBitMap(&m_Bitmap, m_BitmapBuffer, BitmapLength * 8);
109 
110  //
111  // clear all bits
112  //
114 
115  //
116  // initialize rest of memory allocator
117  //
119  m_VirtualBase = VirtualBase;
120  m_DmaBufferSize = DmaBufferSize;
121  m_Lock = Lock;
122  m_BlockSize = DefaultBlockSize;
123 
124  /* done */
125  return STATUS_SUCCESS;
126 }
127 
128 NTSTATUS
130  IN ULONG Size,
131  OUT PVOID *OutVirtualAddress,
132  OUT PPHYSICAL_ADDRESS OutPhysicalAddress)
133 {
134  ULONG Length, BlockCount, FreeIndex, StartPage, EndPage;
135  KIRQL OldLevel;
136  ULONG BlocksPerPage;
137 
138  //
139  // sanity checks
140  //
141  ASSERT(Size <= PAGE_SIZE);
142  //ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
143 
144  //
145  // align request
146  //
147  Length = (Size + m_BlockSize -1) & ~(m_BlockSize -1);
148 
149  //
150  // sanity check
151  //
152  ASSERT(Length);
153 
154  //
155  // convert to block count
156  //
157  BlockCount = Length / m_BlockSize;
158 
159  //
160  // acquire lock
161  //
162  KeAcquireSpinLock(m_Lock, &OldLevel);
163 
164  //
165  // helper variable
166  //
167  BlocksPerPage = PAGE_SIZE / m_BlockSize;
168 
169  //
170  // start search
171  //
172  FreeIndex = 0;
173  do
174  {
175  //
176  // search for an free index
177  //
178  FreeIndex = RtlFindClearBits(&m_Bitmap, BlockCount, FreeIndex);
179 
180  //
181  // check if there was a block found
182  //
183  if (FreeIndex == MAXULONG)
184  {
185  //
186  // no free block found
187  //
188  break;
189  }
190 
191  //
192  // check that the allocation does not spawn over page boundaries
193  //
194  StartPage = (FreeIndex * m_BlockSize);
195  StartPage = (StartPage != 0 ? StartPage / PAGE_SIZE : 0);
196  EndPage = ((FreeIndex + BlockCount) * m_BlockSize) / PAGE_SIZE;
197 
198  //
199  // does the request start and end on the same page
200  //
201  if (StartPage == EndPage)
202  {
203  //
204  // reserve block
205  //
206  RtlSetBits(&m_Bitmap, FreeIndex, BlockCount);
207 
208  //
209  // reserve block
210  //
211  break;
212  }
213  else if ((BlockCount == BlocksPerPage) && (FreeIndex % BlocksPerPage == 0))
214  {
215  //
216  // the request equals PAGE_SIZE and is aligned at page boundary
217  // reserve block
218  //
219  RtlSetBits(&m_Bitmap, FreeIndex, BlockCount);
220 
221  //
222  // reserve block
223  //
224  break;
225  }
226  else
227  {
228  //
229  // request spawned over page boundary
230  // restart search on next page
231  //
232  FreeIndex = (EndPage * PAGE_SIZE) / m_BlockSize;
233  }
234  }
235  while(TRUE);
236 
237  //
238  // release lock
239  //
240  KeReleaseSpinLock(m_Lock, OldLevel);
241 
242  //
243  // did allocation succeed
244  //
245  if (FreeIndex == MAXULONG)
246  {
247  //
248  // failed to allocate block, requestor must retry
249  //
250  return STATUS_UNSUCCESSFUL;
251  }
252 
253  //
254  // return result
255  //
256  *OutVirtualAddress = (PVOID)((ULONG_PTR)m_VirtualBase + FreeIndex * m_BlockSize);
257  OutPhysicalAddress->QuadPart = m_PhysicalAddress.QuadPart + FreeIndex * m_BlockSize;
258 
259  //
260  // clear block
261  //
262  RtlZeroMemory(*OutVirtualAddress, Length);
263 
264  //
265  // done
266  //
267  return STATUS_SUCCESS;
268 }
269 
270 NTSTATUS
273  IN ULONG Size)
274 {
275  KIRQL OldLevel;
276  ULONG BlockOffset = 0, BlockLength, BlockCount;
277 
278  //
279  // sanity checks
280  //
284 
285  //
286  // calculate block length
287  //
288  BlockLength = ((ULONG_PTR)VirtualAddress - (ULONG_PTR)m_VirtualBase);
289 
290  //
291  // check if its the first block
292  //
293  if (BlockLength)
294  {
295  //
296  // divide by base block size
297  //
298  BlockOffset = BlockLength / m_BlockSize;
299  }
300 
301  //
302  // align length to block size
303  //
304  Size = (Size + m_BlockSize - 1) & ~(m_BlockSize - 1);
305 
306  //
307  // convert to blocks
308  //
309  BlockCount = Size / m_BlockSize;
310  ASSERT(BlockCount);
311 
312  //
313  // acquire lock
314  //
315  KeAcquireSpinLock(m_Lock, &OldLevel);
316 
317  //
318  // sanity check
319  //
320  ASSERT(RtlAreBitsSet(&m_Bitmap, BlockOffset, BlockCount));
321 
322  //
323  // release buffer
324  //
325  RtlClearBits(&m_Bitmap, BlockOffset, BlockCount);
326 
327  //
328  // release lock
329  //
330  KeReleaseSpinLock(m_Lock, OldLevel);
331 
332  //
333  // done
334  //
335  return STATUS_SUCCESS;
336 }
337 
338 NTSTATUS
339 NTAPI
341  PDMAMEMORYMANAGER *OutMemoryManager)
342 {
344 
345  //
346  // allocate controller
347  //
349  if (!This)
350  {
351  //
352  // failed to allocate
353  //
355  }
356 
357  //
358  // add reference count
359  //
360  This->AddRef();
361 
362  //
363  // return result
364  //
365  *OutMemoryManager = (PDMAMEMORYMANAGER)This;
366 
367  //
368  // done
369  //
370  return STATUS_SUCCESS;
371 }
372 
virtual NTSTATUS Release(IN PVOID VirtualBase, IN ULONG Size)
#define IN
Definition: typedefs.h:38
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
#define REFIID
Definition: guiddef.h:113
#define TRUE
Definition: types.h:120
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
NTSTATUS NTAPI CreateDMAMemoryManager(PDMAMEMORYMANAGER *OutMemoryManager)
#define PC_ASSERT(exp)
Definition: usbehci.h:17
IUSBHardwareDevice * PUSBHARDWAREDEVICE
_In_ PIRP _In_ PDEVICE_OBJECT Device
Definition: fatprocs.h:2020
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Device, IN PKSPIN_LOCK Lock, IN ULONG DmaBufferSize, IN PVOID VirtualBase, IN PHYSICAL_ADDRESS PhysicalAddress, IN ULONG DefaultBlockSize)
LONG NTSTATUS
Definition: precomp.h:26
STDMETHODIMP_(ULONG) Release()
STDMETHODIMP QueryInterface(REFIID InterfaceId, PVOID *Interface)
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
int WINAPI EndPage(_In_ HDC)
uint32_t ULONG_PTR
Definition: typedefs.h:63
int WINAPI StartPage(_In_ HDC)
virtual NTSTATUS Allocate(IN ULONG Size, OUT PVOID *OutVirtualBase, OUT PPHYSICAL_ADDRESS OutPhysicalAddress)
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define BlockOffset(V, L)
Definition: cdprocs.h:1660
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
long LONG
Definition: pedump.c:60
#define STDMETHODIMP
Definition: basetyps.h:43
void * PVOID
Definition: retypes.h:9
STDMETHODIMP_(ULONG) AddRef()
#define TAG_USBLIB
Definition: libusb.h:70
NTSYSAPI void WINAPI RtlClearAllBits(PRTL_BITMAP)
IN PVOID IN PVOID IN USHORT IN USHORT IN PINTERFACE Interface
Definition: pci.h:359
virtual ~CDMAMemoryManager()
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
PUSBHARDWAREDEVICE m_Device
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS PhysicalAddress
Definition: iotypes.h:1060
#define InterlockedDecrement
Definition: armddk.h:52
Definition: arc.h:85
#define PAGE_SIZE
Definition: env_spec_w32.h:49
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG IN OUT PLONG IN LONG Increment IN PNDIS_RW_LOCK Lock
Definition: CrNtStubs.h:75
_In_ ULONG _In_ BOOLEAN _Must_inspect_result_ PVOID * VirtualAddress
Definition: ndis.h:3791
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
#define MAXULONG
Definition: typedefs.h:250
NTSYSAPI BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP, ULONG, ULONG)
#define InterlockedIncrement
Definition: armddk.h:53
unsigned int * PULONG
Definition: retypes.h:1
IDMAMemoryManager * PDMAMEMORYMANAGER
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
static ULONG WINAPI AddRef(IStream *iface)
Definition: clist.c:90
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ULONG_PTR
Definition: config.h:101
NTSYSAPI void WINAPI RtlSetBits(PRTL_BITMAP, ULONG, ULONG)
CDMAMemoryManager(IUnknown *OuterUnknown)
return STATUS_SUCCESS
Definition: btrfs.c:2745
NTSYSAPI ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP, ULONG, ULONG)
PHYSICAL_ADDRESS m_PhysicalAddress
LONGLONG QuadPart
Definition: typedefs.h:112