1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/dma_init.c
5 * PURPOSE: portcls dma support object
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "private.hpp"
10
11 #define NDEBUG
12 #include <debug.h>
13
14 class CDmaChannelInit : public CUnknownImpl<IDmaChannelInit>
15 {
16 public:
17 inline
18 PVOID
operator new(size_t Size,POOL_TYPE PoolType,ULONG Tag)19 operator new(
20 size_t Size,
21 POOL_TYPE PoolType,
22 ULONG Tag)
23 {
24 return ExAllocatePoolWithTag(PoolType, Size, Tag);
25 }
26
27 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
28
29 IMP_IDmaChannelInit;
CDmaChannelInit(IUnknown * OuterUnknown)30 CDmaChannelInit(IUnknown * OuterUnknown) :
31 m_pDeviceObject(nullptr),
32 m_pAdapter(nullptr),
33 m_DmaStarted(FALSE),
34 m_MapSize(0),
35 m_MapRegisterBase(nullptr),
36 m_LastTransferCount(0),
37 m_MaximumBufferSize(0),
38 m_MaxMapRegisters(0),
39 m_AllocatedBufferSize(0),
40 m_BufferSize(0),
41 m_Address({0}),
42 m_Buffer(nullptr),
43 m_Mdl(nullptr),
44 m_WriteToDevice(FALSE)
45 {
46 }
~CDmaChannelInit()47 virtual ~CDmaChannelInit(){}
48
49 protected:
50
51 PDEVICE_OBJECT m_pDeviceObject;
52 PDMA_ADAPTER m_pAdapter;
53
54 BOOL m_DmaStarted;
55
56 ULONG m_MapSize;
57 PVOID m_MapRegisterBase;
58
59 ULONG m_LastTransferCount;
60
61 ULONG m_MaximumBufferSize;
62 ULONG m_MaxMapRegisters;
63 ULONG m_AllocatedBufferSize;
64 ULONG m_BufferSize;
65
66 PHYSICAL_ADDRESS m_Address;
67 PVOID m_Buffer;
68 PMDL m_Mdl;
69 BOOLEAN m_WriteToDevice;
70
71 friend IO_ALLOCATION_ACTION NTAPI AdapterControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID MapRegisterBase, IN PVOID Context);
72 };
73
74 //---------------------------------------------------------------
75 // IUnknown methods
76 //
77
78 extern GUID IID_IDmaChannelSlave;
79
80 NTSTATUS
81 NTAPI
QueryInterface(IN REFIID refiid,OUT PVOID * Output)82 CDmaChannelInit::QueryInterface(
83 IN REFIID refiid,
84 OUT PVOID* Output)
85 {
86 if (IsEqualGUIDAligned(refiid, IID_IUnknown) ||
87 IsEqualGUIDAligned(refiid, IID_IDmaChannel))
88 //IsEqualGUIDAligned(refiid, IID_IDmaChannelSlave)) // HACK
89 {
90 *Output = PVOID(PUNKNOWN(this));
91 PUNKNOWN(*Output)->AddRef();
92 return STATUS_SUCCESS;
93 }
94 DPRINT("No interface!!!\n");
95 return STATUS_UNSUCCESSFUL;
96 }
97
98 //---------------------------------------------------------------
99 // IDmaChannel methods
100 //
101
102 NTSTATUS
103 NTAPI
AllocateBuffer(IN ULONG BufferSize,IN PPHYSICAL_ADDRESS PhysicalAddressConstraint OPTIONAL)104 CDmaChannelInit::AllocateBuffer(
105 IN ULONG BufferSize,
106 IN PPHYSICAL_ADDRESS PhysicalAddressConstraint OPTIONAL)
107 {
108 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
109
110 // Did the caller already allocate a buffer ?*/
111 if (m_Buffer)
112 {
113 DPRINT("CDmaChannelInit_AllocateBuffer free common buffer first \n");
114 return STATUS_UNSUCCESSFUL;
115 }
116
117 m_Buffer = m_pAdapter->DmaOperations->AllocateCommonBuffer(m_pAdapter, BufferSize, &m_Address, FALSE);
118 if (!m_Buffer)
119 {
120 DPRINT("CDmaChannelInit_AllocateBuffer fAllocateCommonBuffer failed \n");
121 return STATUS_UNSUCCESSFUL;
122 }
123
124 m_BufferSize = BufferSize;
125 m_AllocatedBufferSize = BufferSize;
126 DPRINT("CDmaChannelInit::AllocateBuffer Success Buffer %p BufferSize %u Address %x\n", m_Buffer, BufferSize, m_Address);
127
128 return STATUS_SUCCESS;
129 }
130
131 ULONG
132 NTAPI
AllocatedBufferSize()133 CDmaChannelInit::AllocatedBufferSize()
134 {
135 DPRINT("CDmaChannelInit_AllocatedBufferSize: this %p BufferSize %u\n", this, m_BufferSize);
136 return m_AllocatedBufferSize;
137 }
138
139 VOID
140 NTAPI
CopyFrom(IN PVOID Destination,IN PVOID Source,IN ULONG ByteCount)141 CDmaChannelInit::CopyFrom(
142 IN PVOID Destination,
143 IN PVOID Source,
144 IN ULONG ByteCount
145 )
146 {
147 DPRINT("CDmaChannelInit_CopyFrom: this %p Destination %p Source %p ByteCount %u\n", this, Destination, Source, ByteCount);
148
149 CopyTo(Destination, Source, ByteCount);
150 }
151
152 VOID
153 NTAPI
CopyTo(IN PVOID Destination,IN PVOID Source,IN ULONG ByteCount)154 CDmaChannelInit::CopyTo(
155 IN PVOID Destination,
156 IN PVOID Source,
157 IN ULONG ByteCount
158 )
159 {
160 DPRINT("CDmaChannelInit_CopyTo: this %p Destination %p Source %p ByteCount %u\n", this, Destination, Source, ByteCount);
161 RtlCopyMemory(Destination, Source, ByteCount);
162 }
163
164 VOID
165 NTAPI
FreeBuffer()166 CDmaChannelInit::FreeBuffer()
167 {
168 DPRINT("CDmaChannelInit_FreeBuffer: this %p\n", this);
169
170 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
171
172 if (!m_Buffer)
173 {
174 DPRINT("CDmaChannelInit_FreeBuffer allocate common buffer first \n");
175 return;
176 }
177
178 m_pAdapter->DmaOperations->FreeCommonBuffer(m_pAdapter, m_AllocatedBufferSize, m_Address, m_Buffer, FALSE);
179 m_Buffer = NULL;
180 m_AllocatedBufferSize = 0;
181 m_Address.QuadPart = 0LL;
182
183 if (m_Mdl)
184 {
185 IoFreeMdl(m_Mdl);
186 m_Mdl = NULL;
187 }
188 }
189
190 PADAPTER_OBJECT
191 NTAPI
GetAdapterObject()192 CDmaChannelInit::GetAdapterObject()
193 {
194 DPRINT("CDmaChannelInit_GetAdapterObject: this %p\n", this);
195 return (PADAPTER_OBJECT)m_pAdapter;
196 }
197
198 ULONG
199 NTAPI
MaximumBufferSize()200 CDmaChannelInit::MaximumBufferSize()
201 {
202 DPRINT("CDmaChannelInit_MaximumBufferSize: this %p\n", this);
203 return m_MaximumBufferSize;
204 }
205
206 #ifdef _MSC_VER
207
208 PHYSICAL_ADDRESS
209 NTAPI
PhysicalAddress()210 CDmaChannelInit::PhysicalAddress()
211 {
212 DPRINT("CDmaChannelInit_PhysicalAddress: this %p Virtual %p Physical High %x Low %x%\n", this, m_Buffer, m_Address.HighPart, m_Address.LowPart);
213
214 return m_Address;
215 }
216
217 #else
218
219 PHYSICAL_ADDRESS
220 NTAPI
PhysicalAddress(PPHYSICAL_ADDRESS Address)221 CDmaChannelInit::PhysicalAddress(
222 PPHYSICAL_ADDRESS Address)
223 {
224 DPRINT("CDmaChannelInit_PhysicalAddress: this %p Virtual %p Physical High %x Low %x%\n", this, m_Buffer, m_Address.HighPart, m_Address.LowPart);
225
226 PHYSICAL_ADDRESS Result;
227
228 Address->QuadPart = m_Address.QuadPart;
229 Result.QuadPart = (ULONG_PTR)Address;
230 return Result;
231 }
232
233 #endif
234
235 VOID
236 NTAPI
SetBufferSize(IN ULONG BufferSize)237 CDmaChannelInit::SetBufferSize(
238 IN ULONG BufferSize)
239 {
240 DPRINT("CDmaChannelInit_SetBufferSize: this %p\n", this);
241 m_BufferSize = BufferSize;
242
243 }
244
245 ULONG
246 NTAPI
BufferSize()247 CDmaChannelInit::BufferSize()
248 {
249 DPRINT("BufferSize %u\n", m_BufferSize);
250 PC_ASSERT(m_BufferSize);
251 return m_BufferSize;
252 }
253
254 PVOID
255 NTAPI
SystemAddress()256 CDmaChannelInit::SystemAddress()
257 {
258 DPRINT("CDmaChannelInit_SystemAddress: this %p\n", this);
259 return m_Buffer;
260 }
261
262 ULONG
263 NTAPI
TransferCount()264 CDmaChannelInit::TransferCount()
265 {
266 DPRINT("CDmaChannelInit_TransferCount: this %p\n", this);
267 return m_LastTransferCount;
268 }
269
270 ULONG
271 NTAPI
ReadCounter()272 CDmaChannelInit::ReadCounter()
273 {
274 ULONG Counter;
275
276 PC_ASSERT_IRQL(DISPATCH_LEVEL);
277
278 Counter = m_pAdapter->DmaOperations->ReadDmaCounter(m_pAdapter);
279
280 if (!m_DmaStarted || Counter >= m_LastTransferCount)
281 Counter = 0;
282
283 DPRINT("ReadCounter %u\n", Counter);
284
285 return Counter;
286 }
287
288 IO_ALLOCATION_ACTION
289 NTAPI
AdapterControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID MapRegisterBase,IN PVOID Context)290 AdapterControl(
291 IN PDEVICE_OBJECT DeviceObject,
292 IN PIRP Irp,
293 IN PVOID MapRegisterBase,
294 IN PVOID Context)
295 {
296 ULONG Length;
297 CDmaChannelInit * This = (CDmaChannelInit*)Context;
298
299 Length = This->m_MapSize;
300 This->m_MapRegisterBase = MapRegisterBase;
301
302 This->m_pAdapter->DmaOperations->MapTransfer(This->m_pAdapter,
303 This->m_Mdl,
304 MapRegisterBase,
305 (PVOID)((ULONG_PTR)This->m_Mdl->StartVa + This->m_Mdl->ByteOffset),
306 &Length,
307 This->m_WriteToDevice);
308
309 if (Length == This->m_BufferSize)
310 {
311 This->m_DmaStarted = TRUE;
312 }
313
314 return KeepObject;
315 }
316
317 NTSTATUS
318 NTAPI
Start(ULONG MapSize,BOOLEAN WriteToDevice)319 CDmaChannelInit::Start(
320 ULONG MapSize,
321 BOOLEAN WriteToDevice)
322 {
323 NTSTATUS Status;
324 ULONG MapRegisters;
325 KIRQL OldIrql;
326
327 DPRINT("CDmaChannelInit_Start: this %p\n", this);
328
329 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
330
331 if (m_DmaStarted)
332 return STATUS_UNSUCCESSFUL;
333
334 if (!m_Mdl)
335 {
336 m_Mdl = IoAllocateMdl(m_Buffer, m_MaximumBufferSize, FALSE, FALSE, NULL);
337 if (!m_Mdl)
338 {
339 return STATUS_INSUFFICIENT_RESOURCES;
340 }
341 MmBuildMdlForNonPagedPool(m_Mdl);
342 }
343
344 m_MapSize = MapSize;
345 m_WriteToDevice = WriteToDevice;
346 m_LastTransferCount = MapSize;
347
348 //FIXME
349 // synchronize access
350 //
351 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
352
353 MapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(m_Buffer, MapSize);
354 Status = m_pAdapter->DmaOperations->AllocateAdapterChannel(m_pAdapter, m_pDeviceObject, MapRegisters, AdapterControl, (PVOID)this);
355 KeLowerIrql(OldIrql);
356
357 if(!NT_SUCCESS(Status))
358 m_LastTransferCount = 0;
359
360 return Status;
361 }
362
363 NTSTATUS
364 NTAPI
Stop()365 CDmaChannelInit::Stop()
366 {
367 KIRQL OldIrql;
368
369 DPRINT("CDmaChannelInit::Stop: this %p\n", this);
370 PC_ASSERT_IRQL(DISPATCH_LEVEL);
371
372 if (!m_DmaStarted)
373 return STATUS_SUCCESS;
374
375 m_pAdapter->DmaOperations->FlushAdapterBuffers(m_pAdapter,
376 m_Mdl,
377 m_MapRegisterBase,
378 (PVOID)((ULONG_PTR)m_Mdl->StartVa + m_Mdl->ByteOffset),
379 m_MapSize,
380 m_WriteToDevice);
381
382 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
383
384 m_pAdapter->DmaOperations->FreeAdapterChannel(m_pAdapter);
385
386 KeLowerIrql(OldIrql);
387
388 m_DmaStarted = FALSE;
389
390 IoFreeMdl(m_Mdl);
391 m_Mdl = NULL;
392
393 return STATUS_SUCCESS;
394 }
395
396 NTSTATUS
397 NTAPI
WaitForTC(ULONG Timeout)398 CDmaChannelInit::WaitForTC(
399 ULONG Timeout)
400 {
401 ULONG RetryCount;
402 ULONG BytesRemaining;
403 ULONG PrevBytesRemaining;
404
405 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
406
407 BytesRemaining = m_pAdapter->DmaOperations->ReadDmaCounter(m_pAdapter);
408 if (!BytesRemaining)
409 {
410 return STATUS_SUCCESS;
411 }
412
413 RetryCount = Timeout / 10;
414 PrevBytesRemaining = 0xFFFFFFFF;
415 do
416 {
417 BytesRemaining = m_pAdapter->DmaOperations->ReadDmaCounter(m_pAdapter);
418
419 if (!BytesRemaining)
420 break;
421
422 if (PrevBytesRemaining == BytesRemaining)
423 break;
424
425 KeStallExecutionProcessor(10);
426 PrevBytesRemaining = BytesRemaining;
427
428 }while(RetryCount-- >= 1);
429
430 if (BytesRemaining)
431 {
432 return STATUS_UNSUCCESSFUL;
433 }
434
435 return STATUS_SUCCESS;
436
437 }
438
439 NTSTATUS
440 NTAPI
Init(IN PDEVICE_DESCRIPTION DeviceDescription,IN PDEVICE_OBJECT DeviceObject)441 CDmaChannelInit::Init(
442 IN PDEVICE_DESCRIPTION DeviceDescription,
443 IN PDEVICE_OBJECT DeviceObject)
444 {
445 INTERFACE_TYPE BusType;
446 NTSTATUS Status;
447 PDMA_ADAPTER Adapter;
448 PPCLASS_DEVICE_EXTENSION DeviceExt;
449 ULONG MapRegisters;
450 ULONG ResultLength;
451
452 // Get bus type
453 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyLegacyBusType, sizeof(BusType), (PVOID)&BusType, &ResultLength);
454 if (NT_SUCCESS(Status))
455 {
456 DeviceDescription->InterfaceType = BusType;
457 }
458 // Fetch device extension
459 DeviceExt = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
460 // Acquire dma adapter
461 Adapter = IoGetDmaAdapter(DeviceExt->PhysicalDeviceObject, DeviceDescription, &MapRegisters);
462 if (!Adapter)
463 {
464 FreeItem(this, TAG_PORTCLASS);
465 return STATUS_DEVICE_CONFIGURATION_ERROR;
466 }
467
468 // initialize object
469 m_pAdapter = Adapter;
470 m_pDeviceObject = DeviceObject;
471 m_MaximumBufferSize = DeviceDescription->MaximumLength;
472 m_MaxMapRegisters = MapRegisters;
473
474 return STATUS_SUCCESS;
475 }
476
477 NTSTATUS
478 NTAPI
PcNewDmaChannel(OUT PDMACHANNEL * OutDmaChannel,IN PUNKNOWN OuterUnknown OPTIONAL,IN POOL_TYPE PoolType,IN PDEVICE_DESCRIPTION DeviceDescription,IN PDEVICE_OBJECT DeviceObject)479 PcNewDmaChannel(
480 OUT PDMACHANNEL* OutDmaChannel,
481 IN PUNKNOWN OuterUnknown OPTIONAL,
482 IN POOL_TYPE PoolType,
483 IN PDEVICE_DESCRIPTION DeviceDescription,
484 IN PDEVICE_OBJECT DeviceObject)
485 {
486 NTSTATUS Status;
487 CDmaChannelInit * This;
488
489 DPRINT("OutDmaChannel %p OuterUnknown %p PoolType %p DeviceDescription %p DeviceObject %p\n",
490 OutDmaChannel, OuterUnknown, PoolType, DeviceDescription, DeviceObject);
491
492 This = new(PoolType, TAG_PORTCLASS)CDmaChannelInit(OuterUnknown);
493 if (!This)
494 return STATUS_INSUFFICIENT_RESOURCES;
495
496 Status = This->QueryInterface(IID_IDmaChannel, (PVOID*)OutDmaChannel);
497
498 if (!NT_SUCCESS(Status))
499 {
500 delete This;
501 return Status;
502 }
503
504 Status = This->Init(DeviceDescription, DeviceObject);
505
506 if (!NT_SUCCESS(Status))
507 {
508 delete This;
509 return Status;
510 }
511
512 return Status;
513 }
514