Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

820 lines
21 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation All Rights Reserved
  3. Module Name:
  4. savedata.cpp
  5. Abstract:
  6. Implementation of MSVAD data saving class.
  7. To save the playback data to disk, this class maintains a circular data
  8. buffer, associated frame structures and worker items to save frames to
  9. disk.
  10. Each frame structure represents a portion of buffer. When that portion
  11. of frame is full, a workitem is scheduled to save it to disk.
  12. --*/
  13. #include <msvad.h>
  14. #include "savedata.h"
  15. #include <stdio.h> // This is for using swprintf..
  16. //=============================================================================
  17. // Defines
  18. //=============================================================================
  19. #define RIFF_TAG 0x46464952;
  20. #define WAVE_TAG 0x45564157;
  21. #define FMT__TAG 0x20746D66;
  22. #define DATA_TAG 0x61746164;
  23. #define DEFAULT_FRAME_COUNT 2
  24. #define DEFAULT_FRAME_SIZE PAGE_SIZE * 4
  25. #define DEFAULT_BUFFER_SIZE DEFAULT_FRAME_SIZE * DEFAULT_FRAME_COUNT
  26. #define DEFAULT_FILE_NAME L"\\DosDevices\\C:\\STREAM"
  27. #define MAX_WORKER_ITEM_COUNT 15
  28. //=============================================================================
  29. // Statics
  30. //=============================================================================
  31. ULONG CSaveData::m_ulStreamId = 0;
  32. #pragma code_seg("PAGE")
  33. //=============================================================================
  34. // CSaveData
  35. //=============================================================================
  36. //=============================================================================
  37. CSaveData::CSaveData()
  38. : m_pDataBuffer(NULL),
  39. m_FileHandle(NULL),
  40. m_ulFrameCount(DEFAULT_FRAME_COUNT),
  41. m_ulBufferSize(DEFAULT_BUFFER_SIZE),
  42. m_ulFrameSize(DEFAULT_FRAME_SIZE),
  43. m_ulBufferPtr(0),
  44. m_ulFramePtr(0),
  45. m_fFrameUsed(NULL),
  46. m_pFilePtr(NULL),
  47. m_fWriteDisabled(FALSE)
  48. {
  49. PAGED_CODE();
  50. m_FileHeader.dwRiff = RIFF_TAG;
  51. m_FileHeader.dwFileSize = 0;
  52. m_FileHeader.dwWave = WAVE_TAG;
  53. m_FileHeader.dwFormat = FMT__TAG;
  54. m_FileHeader.dwFormatLength = sizeof(WAVEFORMATEX);
  55. m_DataHeader.dwData = DATA_TAG;
  56. m_DataHeader.dwDataLength = 0;
  57. RtlZeroMemory(&m_objectAttributes, sizeof(m_objectAttributes));
  58. m_ulStreamId++;
  59. } // CSaveData
  60. //=============================================================================
  61. CSaveData::~CSaveData()
  62. {
  63. PAGED_CODE();
  64. LARGE_INTEGER offset;
  65. IO_STATUS_BLOCK ioStatusBlock;
  66. DPF_ENTER(("[CSaveData::~CSaveData]"));
  67. // Update the wave header in data file with real file size.
  68. //
  69. if (m_pFilePtr)
  70. {
  71. m_FileHeader.dwFileSize =
  72. (DWORD) m_pFilePtr->QuadPart - 2 * sizeof(DWORD);
  73. m_DataHeader.dwDataLength = (DWORD) m_pFilePtr->QuadPart -
  74. sizeof(m_FileHeader) -
  75. m_FileHeader.dwFormatLength -
  76. sizeof(m_DataHeader);
  77. if (NT_SUCCESS(FileOpen(FALSE)))
  78. {
  79. FileWriteHeader();
  80. FileClose();
  81. }
  82. }
  83. //frees the work items
  84. #ifndef USE_OBSOLETE_FUNCS
  85. for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++)
  86. {
  87. if (m_pWorkItems[i].WorkItem!=NULL)
  88. {
  89. IoFreeWorkItem(m_pWorkItems[i].WorkItem);
  90. m_pWorkItems[i].WorkItem = NULL;
  91. }
  92. }
  93. #endif
  94. if (m_waveFormat)
  95. {
  96. ExFreePool(m_waveFormat);
  97. }
  98. if (m_fFrameUsed)
  99. {
  100. ExFreePool(m_fFrameUsed);
  101. // NOTE : Do not release m_pFilePtr.
  102. }
  103. if (m_FileName.Buffer)
  104. {
  105. ExFreePool(m_FileName.Buffer);
  106. }
  107. if (m_pDataBuffer)
  108. {
  109. ExFreePool(m_pDataBuffer);
  110. }
  111. } // CSaveData
  112. //=============================================================================
  113. void
  114. CSaveData::DestroyWorkItems
  115. (
  116. void
  117. )
  118. {
  119. if (m_pWorkItems)
  120. {
  121. ExFreePool(m_pWorkItems);
  122. m_pWorkItems = NULL;
  123. }
  124. } // DestroyWorkItems
  125. //=============================================================================
  126. void
  127. CSaveData::Disable
  128. (
  129. BOOL fDisable
  130. )
  131. {
  132. m_fWriteDisabled = fDisable;
  133. } // Disable
  134. //=============================================================================
  135. NTSTATUS
  136. CSaveData::FileClose(void)
  137. {
  138. PAGED_CODE();
  139. NTSTATUS ntStatus = STATUS_SUCCESS;
  140. if (m_FileHandle)
  141. {
  142. ntStatus = ZwClose(m_FileHandle);
  143. m_FileHandle = NULL;
  144. }
  145. return ntStatus;
  146. } // FileClose
  147. //=============================================================================
  148. NTSTATUS
  149. CSaveData::FileOpen
  150. (
  151. IN BOOL fOverWrite
  152. )
  153. {
  154. PAGED_CODE();
  155. NTSTATUS ntStatus = STATUS_SUCCESS;
  156. IO_STATUS_BLOCK ioStatusBlock;
  157. if (!m_FileHandle)
  158. {
  159. ntStatus =
  160. ZwCreateFile
  161. (
  162. &m_FileHandle,
  163. GENERIC_WRITE | SYNCHRONIZE,
  164. &m_objectAttributes,
  165. &ioStatusBlock,
  166. NULL,
  167. FILE_ATTRIBUTE_NORMAL,
  168. 0,
  169. fOverWrite ? FILE_OVERWRITE_IF : FILE_OPEN_IF,
  170. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  171. NULL,
  172. 0
  173. );
  174. if (!NT_SUCCESS(ntStatus))
  175. {
  176. DPF(D_TERSE, ("[CSaveData::FileOpen : Error opening data file]"));
  177. }
  178. }
  179. return ntStatus;
  180. } // FileOpen
  181. //=============================================================================
  182. NTSTATUS
  183. CSaveData::FileWrite
  184. (
  185. IN PBYTE pData,
  186. IN ULONG ulDataSize
  187. )
  188. {
  189. PAGED_CODE();
  190. ASSERT(pData);
  191. ASSERT(m_pFilePtr);
  192. NTSTATUS ntStatus;
  193. if (m_FileHandle)
  194. {
  195. IO_STATUS_BLOCK ioStatusBlock;
  196. ntStatus = ZwWriteFile( m_FileHandle,
  197. NULL,
  198. NULL,
  199. NULL,
  200. &ioStatusBlock,
  201. pData,
  202. ulDataSize,
  203. m_pFilePtr,
  204. NULL);
  205. if (NT_SUCCESS(ntStatus))
  206. {
  207. ASSERT(ioStatusBlock.Information == ulDataSize);
  208. m_pFilePtr->QuadPart += ulDataSize;
  209. }
  210. else
  211. {
  212. DPF(D_TERSE, ("[CSaveData::FileWrite : WriteFileError]"));
  213. }
  214. }
  215. else
  216. {
  217. DPF(D_TERSE, ("[CSaveData::FileWrite : File not open]"));
  218. ntStatus = STATUS_INVALID_HANDLE;
  219. }
  220. return ntStatus;
  221. } // FileWrite
  222. //=============================================================================
  223. NTSTATUS
  224. CSaveData::FileWriteHeader(void)
  225. {
  226. PAGED_CODE();
  227. NTSTATUS ntStatus;
  228. if (m_FileHandle && m_waveFormat)
  229. {
  230. IO_STATUS_BLOCK ioStatusBlock;
  231. m_pFilePtr->QuadPart = 0;
  232. m_FileHeader.dwFormatLength = (m_waveFormat->wFormatTag == WAVE_FORMAT_PCM) ?
  233. sizeof( PCMWAVEFORMAT ) :
  234. sizeof( WAVEFORMATEX ) + m_waveFormat->cbSize;
  235. ntStatus = ZwWriteFile( m_FileHandle,
  236. NULL,
  237. NULL,
  238. NULL,
  239. &ioStatusBlock,
  240. &m_FileHeader,
  241. sizeof(m_FileHeader),
  242. m_pFilePtr,
  243. NULL);
  244. if (!NT_SUCCESS(ntStatus))
  245. {
  246. DPF(D_TERSE, ("[CSaveData::FileWriteHeader : Write File Header Error]"));
  247. }
  248. m_pFilePtr->QuadPart += sizeof(m_FileHeader);
  249. ntStatus = ZwWriteFile( m_FileHandle,
  250. NULL,
  251. NULL,
  252. NULL,
  253. &ioStatusBlock,
  254. m_waveFormat,
  255. m_FileHeader.dwFormatLength,
  256. m_pFilePtr,
  257. NULL);
  258. if (!NT_SUCCESS(ntStatus))
  259. {
  260. DPF(D_TERSE, ("[CSaveData::FileWriteHeader : Write Format Error]"));
  261. }
  262. m_pFilePtr->QuadPart += m_FileHeader.dwFormatLength;
  263. ntStatus = ZwWriteFile( m_FileHandle,
  264. NULL,
  265. NULL,
  266. NULL,
  267. &ioStatusBlock,
  268. &m_DataHeader,
  269. sizeof(m_DataHeader),
  270. m_pFilePtr,
  271. NULL);
  272. if (!NT_SUCCESS(ntStatus))
  273. {
  274. DPF(D_TERSE, ("[CSaveData::FileWriteHeader : Write Data Header Error]"));
  275. }
  276. m_pFilePtr->QuadPart += sizeof(m_DataHeader);
  277. }
  278. else
  279. {
  280. DPF(D_TERSE, ("[CSaveData::FileWriteHeader : File not open]"));
  281. ntStatus = STATUS_INVALID_HANDLE;
  282. }
  283. return ntStatus;
  284. } // FileWriteHeader
  285. #pragma code_seg()
  286. //=============================================================================
  287. PSAVEWORKER_PARAM
  288. CSaveData::GetNewWorkItem
  289. (
  290. void
  291. )
  292. {
  293. LARGE_INTEGER timeOut = { 0 };
  294. NTSTATUS ntStatus;
  295. for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++)
  296. {
  297. ntStatus =
  298. KeWaitForSingleObject
  299. (
  300. &m_pWorkItems[i].EventDone,
  301. Executive,
  302. KernelMode,
  303. FALSE,
  304. &timeOut
  305. );
  306. if (NT_SUCCESS(ntStatus))
  307. {
  308. if (m_pWorkItems[i].WorkItem)
  309. return &(m_pWorkItems[i]);
  310. else
  311. return NULL;
  312. }
  313. }
  314. return NULL;
  315. } // GetNewWorkItem
  316. #pragma code_seg("PAGE")
  317. //=============================================================================
  318. NTSTATUS
  319. CSaveData::Initialize
  320. (
  321. void
  322. )
  323. {
  324. PAGED_CODE();
  325. NTSTATUS ntStatus = STATUS_SUCCESS;
  326. WCHAR szTemp[MAX_PATH];
  327. DPF_ENTER(("[CSaveData::Initialize]"));
  328. // Allocaet data file name.
  329. //
  330. swprintf(szTemp, L"%s_%d.wav", DEFAULT_FILE_NAME, m_ulStreamId);
  331. m_FileName.Length = 0;
  332. m_FileName.MaximumLength = (wcslen(szTemp) + 1) * sizeof(WCHAR);
  333. m_FileName.Buffer = (PWSTR)
  334. ExAllocatePool
  335. (
  336. PagedPool,
  337. m_FileName.MaximumLength
  338. );
  339. if (!m_FileName.Buffer)
  340. {
  341. DPF(D_TERSE, ("[Could not allocate memory for FileName]"));
  342. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  343. }
  344. // Allocate memory for data buffer.
  345. //
  346. if (NT_SUCCESS(ntStatus))
  347. {
  348. wcscpy(m_FileName.Buffer, szTemp);
  349. m_FileName.Length = wcslen(m_FileName.Buffer) * sizeof(WCHAR);
  350. DPF(D_BLAB, ("[New DataFile -- %s", m_FileName.Buffer));
  351. m_pDataBuffer = (PBYTE)
  352. ExAllocatePoolWithTag
  353. (
  354. NonPagedPool,
  355. m_ulBufferSize,
  356. MSVAD_POOLTAG
  357. );
  358. if (!m_pDataBuffer)
  359. {
  360. DPF(D_TERSE, ("[Could not allocate memory for Saving Data]"));
  361. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  362. }
  363. }
  364. // Allocate memory for frame usage flags and m_pFilePtr.
  365. //
  366. if (NT_SUCCESS(ntStatus))
  367. {
  368. m_fFrameUsed = (PBOOL)
  369. ExAllocatePoolWithTag
  370. (
  371. NonPagedPool,
  372. m_ulFrameCount * sizeof(BOOL) +
  373. sizeof(LARGE_INTEGER),
  374. MSVAD_POOLTAG
  375. );
  376. if (!m_fFrameUsed)
  377. {
  378. DPF(D_TERSE, ("[Could not allocate memory for frame flags]"));
  379. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  380. }
  381. }
  382. // Initialize the spinlock to synchronize access to the frames
  383. //
  384. KeInitializeSpinLock ( &m_FrameInUseSpinLock ) ;
  385. // Open the data file.
  386. //
  387. if (NT_SUCCESS(ntStatus))
  388. {
  389. // m_fFrameUsed has additional memory to hold m_pFilePtr
  390. //
  391. m_pFilePtr = (PLARGE_INTEGER)
  392. (((PBYTE) m_fFrameUsed) + m_ulFrameCount * sizeof(BOOL));
  393. RtlZeroMemory(m_fFrameUsed, m_ulFrameCount * sizeof(BOOL));
  394. // Create data file.
  395. InitializeObjectAttributes
  396. (
  397. &m_objectAttributes,
  398. &m_FileName,
  399. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  400. NULL,
  401. NULL
  402. );
  403. // Write wave header information to data file.
  404. ntStatus = FileOpen(TRUE);
  405. if (NT_SUCCESS(ntStatus))
  406. {
  407. ntStatus = FileWriteHeader();
  408. FileClose();
  409. }
  410. }
  411. return ntStatus;
  412. } // Initialize
  413. //=============================================================================
  414. NTSTATUS
  415. CSaveData::InitializeWorkItems
  416. (
  417. IN PDEVICE_OBJECT DeviceObject
  418. )
  419. {
  420. PAGED_CODE();
  421. ASSERT(DeviceObject);
  422. NTSTATUS ntStatus = STATUS_SUCCESS;
  423. DPF_ENTER(("[CSaveData::InitializeWorkItems]"));
  424. m_pDeviceObject = DeviceObject;
  425. m_pWorkItems = (PSAVEWORKER_PARAM)
  426. ExAllocatePoolWithTag
  427. (
  428. NonPagedPool,
  429. sizeof(SAVEWORKER_PARAM) * MAX_WORKER_ITEM_COUNT,
  430. MSVAD_POOLTAG
  431. );
  432. if (m_pWorkItems)
  433. {
  434. for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++)
  435. {
  436. #ifdef USE_OBSOLETE_FUNCS
  437. ExInitializeWorkItem
  438. (
  439. &m_pWorkItems[i].WorkItem,
  440. SaveFrameWorkerCallback,
  441. &m_pWorkItems[i]
  442. );
  443. #else
  444. m_pWorkItems[i].WorkItem = IoAllocateWorkItem(DeviceObject);
  445. if(m_pWorkItems[i].WorkItem == NULL)
  446. {
  447. return STATUS_INSUFFICIENT_RESOURCES;
  448. }
  449. #endif
  450. KeInitializeEvent
  451. (
  452. &m_pWorkItems[i].EventDone,
  453. NotificationEvent,
  454. TRUE
  455. );
  456. }
  457. }
  458. else
  459. {
  460. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  461. }
  462. return ntStatus;
  463. } // InitializeWorkItems
  464. //=============================================================================
  465. void
  466. SaveFrameWorkerCallback
  467. #ifdef USE_OBSOLETE_FUNCS
  468. (
  469. IN PVOID Context
  470. )
  471. #else
  472. (
  473. PDEVICE_OBJECT pDeviceObject, IN PVOID Context
  474. )
  475. #endif
  476. {
  477. PAGED_CODE();
  478. ASSERT(Context);
  479. PSAVEWORKER_PARAM pParam = (PSAVEWORKER_PARAM) Context;
  480. PCSaveData pSaveData;
  481. IO_STATUS_BLOCK ioStatusBlock;
  482. DPF(D_VERBOSE, ("[SaveFrameWorkerCallback], %d", pParam->ulFrameNo));
  483. ASSERT(pParam->pSaveData);
  484. ASSERT(pParam->pSaveData->m_fFrameUsed);
  485. if (pParam->WorkItem)
  486. {
  487. pSaveData = pParam->pSaveData;
  488. if (NT_SUCCESS(pSaveData->FileOpen(FALSE)))
  489. {
  490. pSaveData->FileWrite(pParam->pData, pParam->ulDataSize);
  491. pSaveData->FileClose();
  492. }
  493. InterlockedExchange( (LONG *)&(pSaveData->m_fFrameUsed[pParam->ulFrameNo]), FALSE );
  494. }
  495. KeSetEvent(&pParam->EventDone, 0, FALSE);
  496. } // SaveFrameWorkerCallback
  497. //=============================================================================
  498. NTSTATUS
  499. CSaveData::SetDataFormat
  500. (
  501. IN PKSDATAFORMAT pDataFormat
  502. )
  503. {
  504. PAGED_CODE();
  505. NTSTATUS ntStatus = STATUS_SUCCESS;
  506. DPF_ENTER(("[CSaveData::SetDataFormat]"));
  507. ASSERT(pDataFormat);
  508. PWAVEFORMATEX pwfx = NULL;
  509. if (IsEqualGUIDAligned(pDataFormat->Specifier,
  510. KSDATAFORMAT_SPECIFIER_DSOUND))
  511. {
  512. pwfx =
  513. &(((PKSDATAFORMAT_DSOUND) pDataFormat)->BufferDesc.WaveFormatEx);
  514. }
  515. else if (IsEqualGUIDAligned(pDataFormat->Specifier,
  516. KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
  517. {
  518. pwfx = &((PKSDATAFORMAT_WAVEFORMATEX) pDataFormat)->WaveFormatEx;
  519. }
  520. if (pwfx)
  521. {
  522. // Free the previously allocated waveformat
  523. if (m_waveFormat)
  524. {
  525. ExFreePool(m_waveFormat);
  526. }
  527. m_waveFormat = (PWAVEFORMATEX)
  528. ExAllocatePoolWithTag
  529. (
  530. NonPagedPool,
  531. (pwfx->wFormatTag == WAVE_FORMAT_PCM) ?
  532. sizeof( PCMWAVEFORMAT ) :
  533. sizeof( WAVEFORMATEX ) + pwfx->cbSize,
  534. MSVAD_POOLTAG
  535. );
  536. if(m_waveFormat)
  537. {
  538. RtlCopyMemory( m_waveFormat,
  539. pwfx,
  540. (pwfx->wFormatTag == WAVE_FORMAT_PCM) ?
  541. sizeof( PCMWAVEFORMAT ) :
  542. sizeof( WAVEFORMATEX ) + pwfx->cbSize);
  543. }
  544. else
  545. {
  546. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  547. }
  548. }
  549. return ntStatus;
  550. } // SetDataFormat
  551. //=============================================================================
  552. void
  553. CSaveData::ReadData
  554. (
  555. IN PBYTE pBuffer,
  556. IN ULONG ulByteCount
  557. )
  558. {
  559. // Not implemented yet.
  560. } // ReadData
  561. //=============================================================================
  562. #pragma code_seg()
  563. void
  564. CSaveData::SaveFrame
  565. (
  566. IN ULONG ulFrameNo,
  567. IN ULONG ulDataSize
  568. )
  569. {
  570. PSAVEWORKER_PARAM pParam = NULL;
  571. DPF_ENTER(("[CSaveData::SaveFrame]"));
  572. pParam = GetNewWorkItem();
  573. if (pParam)
  574. {
  575. pParam->pSaveData = this;
  576. pParam->ulFrameNo = ulFrameNo;
  577. pParam->ulDataSize = ulDataSize;
  578. pParam->pData = m_pDataBuffer + ulFrameNo * m_ulFrameSize;
  579. KeResetEvent(&pParam->EventDone);
  580. #ifdef USE_OBSOLETE_FUNCS
  581. ExQueueWorkItem(&pParam->WorkItem, CriticalWorkQueue);
  582. #else
  583. IoQueueWorkItem(pParam->WorkItem, (PIO_WORKITEM_ROUTINE)SaveFrameWorkerCallback,
  584. CriticalWorkQueue, (PVOID)pParam);
  585. #endif
  586. }
  587. } // SaveFrame
  588. #pragma code_seg("PAGE")
  589. //=============================================================================
  590. void
  591. CSaveData::WaitAllWorkItems
  592. (
  593. void
  594. )
  595. {
  596. DPF_ENTER(("[CSaveData::WaitAllWorkItems]"));
  597. // Save the last partially-filled frame
  598. SaveFrame(m_ulFramePtr, m_ulBufferPtr - (m_ulFramePtr * m_ulFrameSize));
  599. for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++)
  600. {
  601. DPF(D_VERBOSE, ("[Waiting for WorkItem] %d", i));
  602. KeWaitForSingleObject
  603. (
  604. &(m_pWorkItems[i].EventDone),
  605. Executive,
  606. KernelMode,
  607. FALSE,
  608. NULL
  609. );
  610. }
  611. } // WaitAllWorkItems
  612. #pragma code_seg()
  613. //=============================================================================
  614. void
  615. CSaveData::WriteData
  616. (
  617. IN PBYTE pBuffer,
  618. IN ULONG ulByteCount
  619. )
  620. {
  621. ASSERT(pBuffer);
  622. ASSERT(ulByteCount);
  623. BOOL fSaveFrame = FALSE;
  624. ULONG ulSaveFramePtr;
  625. KIRQL OldIrql;
  626. LARGE_INTEGER timeOut = { 0 };
  627. // If stream writing is disabled, then exit.
  628. //
  629. if (m_fWriteDisabled)
  630. {
  631. return;
  632. }
  633. DPF_ENTER(("[CSaveData::WriteData ulByteCount=%lu]", ulByteCount));
  634. // Check to see if this frame is available.
  635. KeAcquireSpinLockAtDpcLevel( &m_FrameInUseSpinLock );
  636. if (!m_fFrameUsed[m_ulFramePtr])
  637. {
  638. KeReleaseSpinLockFromDpcLevel( &m_FrameInUseSpinLock );
  639. ULONG ulWriteBytes =
  640. (ulByteCount + m_ulBufferPtr < m_ulBufferSize) ?
  641. ulByteCount :
  642. (m_ulBufferSize - m_ulBufferPtr);
  643. RtlCopyMemory(m_pDataBuffer + m_ulBufferPtr, pBuffer, ulWriteBytes);
  644. m_ulBufferPtr += ulWriteBytes;
  645. // Check to see if we need to save this frame
  646. if (m_ulBufferPtr >= ((m_ulFramePtr + 1) * m_ulFrameSize))
  647. {
  648. fSaveFrame = TRUE;
  649. }
  650. // Loop the buffer, if we reached the end.
  651. if (m_ulBufferPtr == m_ulBufferSize)
  652. {
  653. fSaveFrame = TRUE;
  654. m_ulBufferPtr = 0;
  655. }
  656. if (fSaveFrame)
  657. {
  658. InterlockedExchange( (LONG *)&(m_fFrameUsed[m_ulFramePtr]), TRUE );
  659. ulSaveFramePtr = m_ulFramePtr;
  660. m_ulFramePtr = (m_ulFramePtr + 1) % m_ulFrameCount;
  661. }
  662. // Write the left over if the next frame is available.
  663. if (ulWriteBytes != ulByteCount)
  664. {
  665. KeAcquireSpinLockAtDpcLevel( &m_FrameInUseSpinLock );
  666. if (!m_fFrameUsed[m_ulFramePtr])
  667. {
  668. KeReleaseSpinLockFromDpcLevel( &m_FrameInUseSpinLock );
  669. RtlCopyMemory
  670. (
  671. m_pDataBuffer + m_ulBufferPtr,
  672. pBuffer,
  673. ulWriteBytes
  674. );
  675. }
  676. else
  677. {
  678. KeReleaseSpinLockFromDpcLevel( &m_FrameInUseSpinLock );
  679. DPF(D_BLAB, ("[Frame overflow, next frame is in use]"));
  680. }
  681. }
  682. if (fSaveFrame)
  683. {
  684. SaveFrame(ulSaveFramePtr, m_ulFrameSize);
  685. }
  686. }
  687. else
  688. {
  689. KeReleaseSpinLockFromDpcLevel( &m_FrameInUseSpinLock );
  690. DPF(D_BLAB, ("[Frame %d is in use]", m_ulFramePtr));
  691. }
  692. } // WriteData