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