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