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.

2166 lines
67 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. thread.c
  5. Abstract:
  6. Author:
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "redbook.h"
  13. #include "ntddredb.h"
  14. #include "proto.h"
  15. #include <scsi.h> // for SetKnownGoodDrive()
  16. #include <stdio.h> // vsprintf()
  17. #include "thread.tmh"
  18. //
  19. // this is how many seconds until resources are free'd from
  20. // a play, and also how long (in seconds) before a frozen state
  21. // is detected (and a fix attempted).
  22. //
  23. #define REDBOOK_THREAD_FIXUP_SECONDS 10
  24. #define REDBOOK_THREAD_SYSAUDIO_CACHE_SECONDS 2
  25. #define REDBOOK_PERFORM_STUTTER_CONTROL 0
  26. #if DBG
  27. //
  28. // allows me to send silence to ks as needed
  29. //
  30. ULONG RedBookForceSilence = FALSE;
  31. #endif
  32. #ifdef ALLOC_PRAGMA
  33. #pragma alloc_text(PAGE, RedBookAllocatePlayResources )
  34. #pragma alloc_text(PAGE, RedBookCacheToc )
  35. #pragma alloc_text(PAGE, RedBookDeallocatePlayResources )
  36. #pragma alloc_text(PAGERW, RedBookReadRaw )
  37. #pragma alloc_text(PAGERW, RedBookStream )
  38. #pragma alloc_text(PAGE, RedBookSystemThread )
  39. #pragma alloc_text(PAGE, RedBookCheckForAudioDeviceRemoval )
  40. #pragma alloc_text(PAGE, RedBookThreadDigitalHandler )
  41. /*
  42. but last two CANNOT be unlocked when playing,
  43. so they are (temporarily) commented out.
  44. eventually will only have them locked when playing
  45. #pragma alloc_text(PAGERW, RedBookReadRawCompletion )
  46. #pragma alloc_text(PAGERW, RedBookStreamCompletion )
  47. */
  48. #endif ALLOC_PRAGMA
  49. VOID
  50. RedBookSystemThread(
  51. PVOID Context
  52. )
  53. /*++
  54. Routine Description:
  55. This system thread will wait on events,
  56. sending buffers to Kernel Streaming as they
  57. become available.
  58. Arguments:
  59. Context - deviceExtension
  60. Return Value:
  61. status
  62. --*/
  63. {
  64. PREDBOOK_DEVICE_EXTENSION deviceExtension = Context;
  65. LARGE_INTEGER timeout;
  66. NTSTATUS waitStatus;
  67. NTSTATUS status;
  68. ULONG i;
  69. ULONG timeouts;
  70. LARGE_INTEGER stopTime;
  71. //
  72. // some per-thread state
  73. //
  74. BOOLEAN killed = FALSE;
  75. PAGED_CODE();
  76. deviceExtension->Thread.SelfPointer = PsGetCurrentThread();
  77. //
  78. // perf fix -- run at low realtime priority
  79. //
  80. KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
  81. timeouts = 0;
  82. stopTime.QuadPart = 0;
  83. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  84. "Thread => UpdateMixerPin at %p\n",
  85. &deviceExtension->Stream.UpdateMixerPin));
  86. //
  87. // Just loop waiting for events.
  88. //
  89. //waitForNextEvent:
  90. while ( 1 ) {
  91. //
  92. // if are killed, just wait on singular event--EVENT_DIGITAL until
  93. // can finish processing. there should not be anything left in the
  94. // IOCTL_LIST (since the kill calls RemoveLockAndWait() first)
  95. //
  96. // this also implies that a kill will never occur while ioctls are
  97. // still being processed. this does not guarantee the state will
  98. // be STOPPED, just that no IO will be occurring.
  99. //
  100. //
  101. // nanosecond is 10^-9, units is 100 nanoseconds
  102. // so seconds is 10,000,000 units
  103. // must wait in relative time, which requires negative numbers
  104. //
  105. timeout.QuadPart = (LONGLONG)(-1 * 10 * 1000 * (LONGLONG)1000);
  106. //
  107. // note: we are using a timeout mechanism mostly to catch bugs
  108. // where the state would lock up. we also "auto adjust"
  109. // our internal state if things get too wierd, basically
  110. // auto-fixing ourselves. note that this does cause the
  111. // thread's stack to be swapped in, so this shouldn't
  112. // be done when we're 100% stopped.
  113. //
  114. if (deviceExtension->Thread.IoctlCurrent == NULL) {
  115. //
  116. // wait on an ioctl, but not the ioctl completion event
  117. //
  118. ULONG state = GetCdromState(deviceExtension);
  119. if ((state == CD_STOPPED) &&
  120. (!RedBookArePlayResourcesAllocated(deviceExtension))
  121. ) {
  122. //
  123. // if we've got no current ioctl and we haven't allocated
  124. // any resources, there're no need to timeout.
  125. // this will prevent this stack from getting swapped in
  126. // needlessly, reducing effective footprint a bit
  127. //
  128. stopTime.QuadPart = 0;
  129. waitStatus = KeWaitForMultipleObjects(EVENT_MAXIMUM - 1,
  130. (PVOID)(&deviceExtension->Thread.Events[0]),
  131. WaitAny,
  132. Executive,
  133. UserMode,
  134. FALSE, // Alertable
  135. NULL,
  136. deviceExtension->Thread.EventBlock
  137. );
  138. } else {
  139. //
  140. // we've got no current ioctl, but we're also not stopped.
  141. // it is also possible to be waiting to cleanup resources here.
  142. // even if we're paused, we want to keep track of what's
  143. // going on, since it's possible for the state to get
  144. // messed up here.
  145. //
  146. waitStatus = KeWaitForMultipleObjects(EVENT_MAXIMUM - 1,
  147. (PVOID)(&deviceExtension->Thread.Events[0]),
  148. WaitAny,
  149. Executive,
  150. UserMode,
  151. FALSE, // Alertable
  152. &timeout,
  153. deviceExtension->Thread.EventBlock
  154. );
  155. }
  156. } else {
  157. //
  158. // wait on the ioctl completion, but not the ioctl event
  159. //
  160. waitStatus = KeWaitForMultipleObjects(EVENT_MAXIMUM - 1,
  161. (PVOID)(&deviceExtension->Thread.Events[1]),
  162. WaitAny,
  163. Executive,
  164. UserMode,
  165. FALSE, // Alertable
  166. &timeout,
  167. deviceExtension->Thread.EventBlock
  168. );
  169. if (waitStatus != STATUS_TIMEOUT) {
  170. waitStatus ++; // to account for offset
  171. }
  172. }
  173. //
  174. // need to check if we are stopped for too long -- if so, free
  175. // the resources.
  176. //
  177. {
  178. ULONG state = GetCdromState(deviceExtension);
  179. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) {
  180. LARGE_INTEGER now;
  181. // not playing,
  182. if (stopTime.QuadPart == 0) {
  183. LONGLONG offset;
  184. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  185. "StopTime => Determining when to dealloc\n"));
  186. // query the time
  187. KeQueryTickCount( &stopTime );
  188. // add appropriate offset
  189. // nanosecond is 10^-9, units is 100 nanoseconds
  190. // so seconds is 10,000,000 units
  191. //
  192. offset = REDBOOK_THREAD_SYSAUDIO_CACHE_SECONDS;
  193. offset *= (LONGLONG)(10 * 1000 * (LONGLONG)1000);
  194. // divide offset by time increment
  195. offset /= (LONGLONG)KeQueryTimeIncrement();
  196. // add those ticks to store when we should release
  197. // our resources
  198. stopTime.QuadPart += offset;
  199. }
  200. KeQueryTickCount(&now);
  201. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  202. "StopTime => Is %I64x >= %I64x?\n",
  203. now.QuadPart,
  204. stopTime.QuadPart
  205. ));
  206. if (now.QuadPart >= stopTime.QuadPart) {
  207. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  208. "StopTime => Deallocating resources\n"));
  209. RedBookDeallocatePlayResources(deviceExtension);
  210. }
  211. } else {
  212. stopTime.QuadPart = 0;
  213. }
  214. }
  215. RedBookCheckForAudioDeviceRemoval(deviceExtension);
  216. //
  217. // To enable a single thread for multiple cdroms, just set events
  218. // at offset of (DEVICE_ID * EVENT_MAX) + EVENT_TO_SET
  219. // set deviceExtension = waitStatus / EVENT_MAX
  220. // switch ( waitStatus % EVENT_MAX )
  221. //
  222. if (waitStatus == EVENT_DIGITAL) {
  223. timeouts = 0;
  224. }
  225. switch ( waitStatus ) {
  226. case EVENT_IOCTL: {
  227. PLIST_ENTRY listEntry;
  228. while ((listEntry = ExInterlockedRemoveHeadList(
  229. &deviceExtension->Thread.IoctlList,
  230. &deviceExtension->Thread.IoctlLock)) != NULL) {
  231. RedBookThreadIoctlHandler(deviceExtension, listEntry);
  232. if (deviceExtension->Thread.IoctlCurrent) {
  233. // special case
  234. break;
  235. }
  236. }
  237. break;
  238. }
  239. case EVENT_COMPLETE: {
  240. RedBookThreadIoctlCompletionHandler(deviceExtension);
  241. break;
  242. }
  243. case EVENT_WMI: {
  244. PLIST_ENTRY listEntry;
  245. while ((listEntry = ExInterlockedRemoveHeadList(
  246. &deviceExtension->Thread.WmiList,
  247. &deviceExtension->Thread.WmiLock)) != NULL) {
  248. RedBookThreadWmiHandler(deviceExtension, listEntry);
  249. }
  250. break;
  251. }
  252. case EVENT_DIGITAL: {
  253. PLIST_ENTRY listEntry;
  254. while ((listEntry = ExInterlockedRemoveHeadList(
  255. &deviceExtension->Thread.DigitalList,
  256. &deviceExtension->Thread.DigitalLock)) != NULL) {
  257. RedBookThreadDigitalHandler(deviceExtension, listEntry);
  258. }
  259. break;
  260. }
  261. case EVENT_KILL_THREAD: {
  262. ULONG state = GetCdromState(deviceExtension);
  263. killed = TRUE;
  264. //
  265. // i don't think this can occur with outstanding io, since
  266. // the remove lock is taken first. nonetheless, it's better
  267. // to be safe than sorry.
  268. //
  269. if (!TEST_FLAG(state, CD_STOPPED)) {
  270. state = SetCdromState(deviceExtension, state, CD_STOPPING);
  271. break;
  272. }
  273. RedBookDeallocatePlayResources(deviceExtension);
  274. //
  275. // else we can safely terminate.
  276. //
  277. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  278. "STExit => Thread was killed\n"));
  279. ASSERT(deviceExtension->Thread.PendingRead == 0);
  280. ASSERT(deviceExtension->Thread.PendingStream == 0);
  281. PsTerminateSystemThread(STATUS_SUCCESS);
  282. ASSERT(!"[redbook] Thread should never reach past self-terminate code");
  283. break;
  284. }
  285. case STATUS_TIMEOUT: {
  286. ULONG state = GetCdromState(deviceExtension);
  287. timeouts++;
  288. if (timeouts < REDBOOK_THREAD_FIXUP_SECONDS) {
  289. break;
  290. } else {
  291. timeouts = 0;
  292. }
  293. //
  294. // these tests all occur once every ten seconds.
  295. // the most basic case is where we want to deallocate
  296. // our cached TOC, but we also perform lots of
  297. // sanity testing here -- ASSERTing on CHK builds and
  298. // trying to fix ourselves up when possible.
  299. //
  300. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) { // !handling ioctls
  301. // not playing, so free resources
  302. RedBookDeallocatePlayResources(deviceExtension);
  303. } else if (TEST_FLAG(state, CD_STOPPING)) {
  304. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  305. "STTime !! %x seconds inactivity\n",
  306. REDBOOK_THREAD_FIXUP_SECONDS));
  307. if (IsListEmpty(&deviceExtension->Thread.DigitalList)) {
  308. if ((deviceExtension->Thread.PendingRead == 0) &&
  309. (deviceExtension->Thread.PendingStream == 0) &&
  310. (deviceExtension->Thread.IoctlCurrent != NULL)) {
  311. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError,
  312. "[redbook] "
  313. "STTime !! No Reads, No Streams, In a temp "
  314. "state (%x) and have STOP irp %p "
  315. "pending?!\n",
  316. state,
  317. ((PREDBOOK_THREAD_IOCTL_DATA)deviceExtension->Thread.IoctlCurrent)->Irp
  318. ));
  319. ASSERT(!"STTime !! CD_STOPPING Fixup with no reads nor streams but STOP pending\n");
  320. SetCdromState(deviceExtension, state, CD_STOPPED);
  321. KeSetEvent(deviceExtension->Thread.Events[EVENT_COMPLETE],
  322. IO_NO_INCREMENT, FALSE);
  323. } else {
  324. ASSERT(!"STTime !! CD_STOPPING Fixup with empty list and no pending ioctl?\n");
  325. }
  326. } else {
  327. ASSERT(!"STTime !! CD_STOPPING Fixup with list items\n");
  328. KeSetEvent(deviceExtension->Thread.Events[EVENT_DIGITAL],
  329. IO_NO_INCREMENT, FALSE);
  330. }
  331. } else if (TEST_FLAG(state, CD_PAUSING)) {
  332. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  333. "STTime !! %x seconds inactivity\n",
  334. REDBOOK_THREAD_FIXUP_SECONDS));
  335. if (IsListEmpty(&deviceExtension->Thread.DigitalList)) {
  336. if ((deviceExtension->Thread.PendingRead == 0) &&
  337. (deviceExtension->Thread.PendingStream == 0) &&
  338. (deviceExtension->Thread.IoctlCurrent != NULL)) {
  339. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError,
  340. "[redbook] "
  341. "STTime !! No Reads, No Streams, In a temp "
  342. "state (%x) and have PAUSE irp %p "
  343. "pending?!\n",
  344. state,
  345. ((PREDBOOK_THREAD_IOCTL_DATA)deviceExtension->Thread.IoctlCurrent)->Irp
  346. ));
  347. ASSERT(!"STTime !! CD_PAUSING Fixup with no reads nor streams but PAUSE pending\n");
  348. SetCdromState(deviceExtension, state, CD_PAUSED);
  349. KeSetEvent(deviceExtension->Thread.Events[EVENT_COMPLETE],
  350. IO_NO_INCREMENT, FALSE);
  351. } else {
  352. ASSERT(!"STTime !! CD_PAUSING Fixup with empty list and no pending ioctl?\n");
  353. }
  354. } else {
  355. ASSERT(!"STTime !! CD_PAUSING Fixup with list items\n");
  356. KeSetEvent(deviceExtension->Thread.Events[EVENT_DIGITAL],
  357. IO_NO_INCREMENT, FALSE);
  358. }
  359. } else if (TEST_FLAG(state, CD_PAUSED)) {
  360. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  361. "STTime => Still paused\n"));
  362. } else {
  363. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  364. "STTime !! %x seconds inactivity\n",
  365. REDBOOK_THREAD_FIXUP_SECONDS));
  366. if (IsListEmpty(&deviceExtension->Thread.DigitalList)) {
  367. ASSERT(!"STTime !! CD_PLAYING Fixup with empty list\n");
  368. } else {
  369. ASSERT(!"STTime !! CD_PLAYING Fixup with list items\n");
  370. KeSetEvent(deviceExtension->Thread.Events[EVENT_DIGITAL],
  371. IO_NO_INCREMENT, FALSE);
  372. }
  373. }
  374. break;
  375. }
  376. default: {
  377. if (waitStatus > 0 && waitStatus < EVENT_MAXIMUM) {
  378. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  379. "ST !! Unhandled event: %lx\n",
  380. waitStatus));
  381. } else {
  382. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  383. "ST !! event too large/small: %lx\n",
  384. waitStatus));
  385. }
  386. ASSERT(!"[redbook] ST !! Unhandled event");
  387. break;
  388. }
  389. } // end of the huge case statement.
  390. //
  391. // check if ioctl waiting or killed. if so, and state is no longer
  392. // in an intermediate state, set the appropriate event.
  393. // ordered to short-curcuit quickly.
  394. //
  395. {
  396. ULONG state = GetCdromState(deviceExtension);
  397. if (killed &&
  398. deviceExtension->Thread.PendingRead == 0 &&
  399. deviceExtension->Thread.PendingStream == 0) {
  400. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  401. "ST => Killing Thread %p\n",
  402. deviceExtension->Thread.SelfPointer));
  403. ASSERT(!TEST_FLAG(state, CD_MASK_TEMP));
  404. state = SetCdromState(deviceExtension, state, CD_STOPPED);
  405. KeSetEvent(deviceExtension->Thread.Events[EVENT_KILL_THREAD],
  406. IO_NO_INCREMENT, FALSE);
  407. }
  408. }
  409. continue;
  410. } // while(1) loop
  411. ASSERT(!"[redbook] ST !! somehow broke out of while(1) loop?");
  412. }
  413. VOID
  414. RedBookReadRaw(
  415. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  416. PREDBOOK_COMPLETION_CONTEXT Context
  417. )
  418. /*++
  419. Routine Description:
  420. Reads raw audio data off the cdrom.
  421. Must either reinsert Context into queue and set an event
  422. or set a completion routine which will do so.
  423. Arguments:
  424. DeviceObject - CDROM class driver object or lower level filter
  425. Return Value:
  426. status
  427. --*/
  428. {
  429. NTSTATUS status;
  430. PIO_STACK_LOCATION nextIrpStack;
  431. PRAW_READ_INFO readInfo;
  432. PAGED_CODE();
  433. VerifyCalledByThread(DeviceExtension);
  434. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalR, "[redbook] "
  435. "ReadRaw => Entering\n"));
  436. status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Context->Irp);
  437. if (!NT_SUCCESS(status)) {
  438. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalR, "[redbook] "
  439. "ReadRaw !! RemoveLock failed %lx\n", status));
  440. // end of thread loop will check for no outstanding io
  441. // and on too many errors set stopping
  442. // don't forget perf info
  443. Context->TimeReadSent.QuadPart = 0; // special value
  444. Context->Irp->IoStatus.Status = status;
  445. Context->Reason = REDBOOK_CC_READ_COMPLETE;
  446. //
  447. // put it on the queue and set the event
  448. //
  449. ExInterlockedInsertTailList(&DeviceExtension->Thread.DigitalList,
  450. &Context->ListEntry,
  451. &DeviceExtension->Thread.DigitalLock);
  452. KeSetEvent(DeviceExtension->Thread.Events[EVENT_DIGITAL],
  453. IO_CD_ROM_INCREMENT, FALSE);
  454. return;
  455. }
  456. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalR, "[redbook] "
  457. "ReadRaw => Index %x sending Irp %p\n",
  458. Context->Index, Context->Irp));
  459. //
  460. // (no failure from this point forward)
  461. //
  462. IoReuseIrp(Context->Irp, STATUS_UNSUCCESSFUL);
  463. Context->Irp->MdlAddress = Context->Mdl;
  464. //
  465. // irp is from kernel mode
  466. //
  467. Context->Irp->AssociatedIrp.SystemBuffer = NULL;
  468. //
  469. // fill in the completion context
  470. //
  471. ASSERT(Context->DeviceExtension == DeviceExtension);
  472. //
  473. // setup the irpstack for the raw read
  474. //
  475. nextIrpStack = IoGetNextIrpStackLocation(Context->Irp);
  476. SET_FLAG(nextIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
  477. nextIrpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  478. nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
  479. IOCTL_CDROM_RAW_READ;
  480. nextIrpStack->Parameters.DeviceIoControl.Type3InputBuffer =
  481. Context->Buffer;
  482. nextIrpStack->Parameters.DeviceIoControl.InputBufferLength =
  483. sizeof(RAW_READ_INFO);
  484. nextIrpStack->Parameters.DeviceIoControl.OutputBufferLength =
  485. (RAW_SECTOR_SIZE * DeviceExtension->WmiData.SectorsPerRead);
  486. //
  487. // setup the read info (uses same buffer)
  488. //
  489. readInfo = (PRAW_READ_INFO)(Context->Buffer);
  490. readInfo->DiskOffset.QuadPart =
  491. (ULONGLONG)(DeviceExtension->CDRom.NextToRead)*COOKED_SECTOR_SIZE;
  492. readInfo->SectorCount = DeviceExtension->WmiData.SectorsPerRead;
  493. readInfo->TrackMode = CDDA;
  494. //
  495. // send it.
  496. //
  497. IoSetCompletionRoutine(Context->Irp, RedBookReadRawCompletion, Context,
  498. TRUE, TRUE, TRUE);
  499. KeQueryTickCount(&Context->TimeReadSent);
  500. IoCallDriver(DeviceExtension->TargetDeviceObject, Context->Irp);
  501. return;
  502. }
  503. NTSTATUS
  504. RedBookReadRawCompletion(
  505. PVOID UnusableParameter,
  506. PIRP Irp,
  507. PREDBOOK_COMPLETION_CONTEXT Context
  508. )
  509. /*++
  510. Routine Description:
  511. When a read completes, use zero'd buffer if error occurred.
  512. Make buffer available to ks, then set ks event.
  513. Arguments:
  514. DeviceObject - NULL, due to being originator of IRP
  515. Irp - pointer to buffer to send to KS
  516. must check error to increment/clear error count
  517. Context - REDBOOK_COMPLETION_CONTEXT
  518. Return Value:
  519. STATUS_MORE_PROCESSING_REQUIRED
  520. --*/
  521. {
  522. PREDBOOK_DEVICE_EXTENSION deviceExtension = Context->DeviceExtension;
  523. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalR, "[redbook] "
  524. "ReadRaw => Completed Irp %p\n", Irp));
  525. KeQueryTickCount(&Context->TimeStreamReady);
  526. Context->Reason = REDBOOK_CC_READ_COMPLETE;
  527. ExInterlockedInsertTailList(&deviceExtension->Thread.DigitalList,
  528. &Context->ListEntry,
  529. &deviceExtension->Thread.DigitalLock);
  530. KeSetEvent(deviceExtension->Thread.Events[EVENT_DIGITAL],
  531. IO_CD_ROM_INCREMENT, FALSE);
  532. //
  533. // safe to release it since we wait for thread termination
  534. //
  535. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Context->Irp);
  536. return STATUS_MORE_PROCESSING_REQUIRED;
  537. }
  538. VOID
  539. RedBookStream(
  540. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  541. PREDBOOK_COMPLETION_CONTEXT Context
  542. )
  543. /*++
  544. Routine Description:
  545. Send buffer to KS.
  546. Must either reinsert Context into queue and set an event
  547. or set a completion routine which will do so.
  548. Arguments:
  549. Context - DeviceExtension
  550. Return Value:
  551. status
  552. --*/
  553. {
  554. NTSTATUS status;
  555. PIO_STACK_LOCATION nextIrpStack;
  556. PUCHAR buffer;
  557. PKSSTREAM_HEADER header;
  558. ULONG bufferSize;
  559. PULONG streamOk;
  560. PAGED_CODE();
  561. VerifyCalledByThread(DeviceExtension);
  562. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalS, "[redbook] "
  563. "Stream => Entering\n"));
  564. bufferSize = DeviceExtension->WmiData.SectorsPerRead * RAW_SECTOR_SIZE;
  565. status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Context->Irp);
  566. if (!NT_SUCCESS(status)) {
  567. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalS, "[redbook] "
  568. "Stream !! RemoveLock failed %lx\n", status));
  569. // end of thread loop will check for no outstanding io
  570. // and on too many errors set CD_STOPPING
  571. // don't forget perf info
  572. Context->TimeReadSent.QuadPart = 0; // special value
  573. Context->Irp->IoStatus.Status = status;
  574. Context->Reason = REDBOOK_CC_STREAM_COMPLETE;
  575. //
  576. // put it on the queue and set the event
  577. //
  578. ExInterlockedInsertTailList(&DeviceExtension->Thread.DigitalList,
  579. &Context->ListEntry,
  580. &DeviceExtension->Thread.DigitalLock);
  581. KeSetEvent(DeviceExtension->Thread.Events[EVENT_DIGITAL],
  582. IO_CD_ROM_INCREMENT, FALSE);
  583. return;
  584. }
  585. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalS, "[redbook] "
  586. "Stream => Index %x sending Irp %p\n",
  587. Context->Index, Context->Irp));
  588. //
  589. // CONSIDER - how does STOPPED occur?
  590. // SUGGEST - out of loop, if no error and none pending, set to STOPPED?
  591. //
  592. //
  593. // (no failure from this point forward)
  594. //
  595. //
  596. // use a zero'd buffer if an error occurred during the read
  597. //
  598. if (NT_SUCCESS(Context->Irp->IoStatus.Status)) {
  599. IoReuseIrp(Context->Irp, STATUS_SUCCESS);
  600. buffer = Context->Buffer; // good data
  601. Context->Irp->MdlAddress = Context->Mdl;
  602. } else {
  603. IoReuseIrp(Context->Irp, STATUS_SUCCESS);
  604. buffer = DeviceExtension->Buffer.SilentBuffer; // zero'd data
  605. Context->Irp->MdlAddress = DeviceExtension->Buffer.SilentMdl;
  606. }
  607. #if DBG
  608. if (RedBookForceSilence) {
  609. buffer = DeviceExtension->Buffer.SilentBuffer; // zero'd data
  610. Context->Irp->MdlAddress = DeviceExtension->Buffer.SilentMdl;
  611. }
  612. #endif // RedBookUseSilence
  613. nextIrpStack = IoGetNextIrpStackLocation(Context->Irp);
  614. //
  615. // get and fill in the context
  616. //
  617. ASSERT(Context->DeviceExtension == DeviceExtension);
  618. //
  619. // setup the irpstack for streaming the buffer
  620. //
  621. nextIrpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  622. nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
  623. IOCTL_KS_WRITE_STREAM;
  624. nextIrpStack->Parameters.DeviceIoControl.OutputBufferLength =
  625. sizeof(KSSTREAM_HEADER);
  626. nextIrpStack->Parameters.DeviceIoControl.InputBufferLength =
  627. sizeof(KSSTREAM_HEADER);
  628. nextIrpStack->FileObject = DeviceExtension->Stream.PinFileObject;
  629. Context->Header.FrameExtent = bufferSize;
  630. Context->Header.DataUsed = bufferSize;
  631. Context->Header.Size = sizeof(KSSTREAM_HEADER);
  632. Context->Header.TypeSpecificFlags = 0;
  633. Context->Header.Data = buffer;
  634. Context->Header.OptionsFlags = 0;
  635. Context->Irp->AssociatedIrp.SystemBuffer = &Context->Header;
  636. #if REDBOOK_PERFORM_STUTTER_CONTROL
  637. #if REDBOOK_WMI_BUFFERS_MIN < 3
  638. #error "The minimum number of buffers must be at least three due to the method used to prevent stuttering"
  639. #endif // REDBOOK_WMI_BUFFERS_MIN < 3
  640. //
  641. // perform my own pausing to prevent stuttering
  642. //
  643. if (DeviceExtension->Thread.PendingStream <= 3 &&
  644. DeviceExtension->Buffer.Paused == 0) {
  645. //
  646. // only one buffer (or less) was pending play,
  647. // so pause the output to prevent horrible
  648. // stuttering.
  649. // since this is serialized from a thread,
  650. // can set a simple boolean in the extension
  651. //
  652. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalS, "[redbook] "
  653. "Stream => Pausing, few buffers pending\n"));
  654. if (DeviceExtension->Buffer.FirstPause == 0) {
  655. RedBookLogError(DeviceExtension,
  656. REDBOOK_ERR_INSUFFICIENT_DATA_STREAM_PAUSED,
  657. STATUS_SUCCESS
  658. );
  659. InterlockedIncrement(&DeviceExtension->WmiPerf.StreamPausedCount);
  660. } else {
  661. DeviceExtension->Buffer.FirstPause = 0;
  662. }
  663. DeviceExtension->Buffer.Paused = 1;
  664. SetNextDeviceState(DeviceExtension, KSSTATE_PAUSE);
  665. } else if (DeviceExtension->Buffer.Paused == 1 &&
  666. DeviceExtension->Thread.PendingStream ==
  667. DeviceExtension->WmiData.NumberOfBuffers ) {
  668. ULONG i;
  669. //
  670. // are now using the maximum number of buffers,
  671. // all pending stream. this allows smooth play again.
  672. //
  673. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalS, "[redbook] "
  674. "Stream => Resuming, %d buffers pending\n",
  675. DeviceExtension->WmiData.NumberOfBuffers));
  676. DeviceExtension->Buffer.Paused = 0;
  677. //
  678. // prevent these statistics from being added.
  679. //
  680. for (i=0;i<DeviceExtension->WmiData.NumberOfBuffers;i++) {
  681. (DeviceExtension->Buffer.Contexts + i)->TimeReadSent.QuadPart = 0;
  682. }
  683. //
  684. // let the irps go!
  685. //
  686. SetNextDeviceState(DeviceExtension, KSSTATE_RUN);
  687. } // end of stutter prevention
  688. #endif // REDBOOK_PERFORM_STUTTER_CONTROL
  689. //
  690. // get perf counters at last possible second
  691. //
  692. KeQueryTickCount(&Context->TimeStreamSent);
  693. IoSetCompletionRoutine(Context->Irp, RedBookStreamCompletion, Context,
  694. TRUE, TRUE, TRUE);
  695. IoCallDriver(DeviceExtension->Stream.PinDeviceObject, Context->Irp);
  696. return;
  697. }
  698. NTSTATUS
  699. RedBookStreamCompletion(
  700. PVOID UnusableParameter,
  701. PIRP Irp,
  702. PREDBOOK_COMPLETION_CONTEXT Context
  703. )
  704. /*++
  705. Routine Description:
  706. Arguments:
  707. DeviceObject - CDROM class driver object or lower level filter
  708. Irp - pointer to buffer to send to KS
  709. must check error to increment/clear error count
  710. Context - sector of disk (ordered number)
  711. Return Value:
  712. status
  713. --*/
  714. {
  715. PREDBOOK_DEVICE_EXTENSION deviceExtension = Context->DeviceExtension;
  716. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugDigitalS, "[redbook] "
  717. "Stream => Completed Irp %p\n", Irp));
  718. KeQueryTickCount(&Context->TimeReadReady);
  719. Context->Reason = REDBOOK_CC_STREAM_COMPLETE;
  720. ExInterlockedInsertTailList(&deviceExtension->Thread.DigitalList,
  721. &Context->ListEntry,
  722. &deviceExtension->Thread.DigitalLock);
  723. KeSetEvent(deviceExtension->Thread.Events[EVENT_DIGITAL],
  724. IO_CD_ROM_INCREMENT, FALSE);
  725. //
  726. // safe to release it since we wait for thread termination
  727. //
  728. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Context->Irp);
  729. return STATUS_MORE_PROCESSING_REQUIRED;
  730. }
  731. #if DBG
  732. VOID
  733. ValidateCdromState(ULONG State)
  734. {
  735. ULONG temp;
  736. if (State == 0) {
  737. ASSERT(!"Invalid Cdrom State");
  738. } else
  739. if (TEST_FLAG(State, ~CD_MASK_ALL)) {
  740. ASSERT(!"Invalid Cdrom State");
  741. }
  742. temp = State & CD_MASK_TEMP;
  743. if (temp & (temp - 1)) { // see if zero or one bits are set
  744. ASSERT(!"Invalid Cdrom State");
  745. }
  746. temp = State & CD_MASK_STATE;
  747. if (temp == 0) { // dis-allow zero bits for STATE
  748. ASSERT(!"Invalid Cdrom State");
  749. } else
  750. if (temp & (temp - 1)) { // see if zero or one bits are set
  751. ASSERT(!"Invalid Cdrom State");
  752. }
  753. return;
  754. }
  755. #else
  756. VOID ValidateCdromState(ULONG State) {return;}
  757. #endif
  758. ULONG
  759. GetCdromState(
  760. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  761. )
  762. {
  763. //
  764. // this routine may be called by anyone, whether in the thread's
  765. // context or not. setting the state is restricted, however.
  766. //
  767. ULONG state;
  768. state = InterlockedCompareExchange(&DeviceExtension->CDRom.StateNow,0,0);
  769. ValidateCdromState(state);
  770. return state;
  771. }
  772. LONG
  773. SetCdromState(
  774. IN PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  775. IN LONG ExpectedOldState,
  776. IN LONG NewState
  777. )
  778. {
  779. LONG trueOldState;
  780. PAGED_CODE();
  781. VerifyCalledByThread(DeviceExtension);
  782. // ensure when set to: also setting:
  783. // CD_PAUSING CD_PLAYING
  784. // CD_STOPPING CD_PLAYING
  785. if (TEST_FLAG(NewState, CD_PAUSING)) {
  786. SET_FLAG(NewState, CD_PLAYING);
  787. }
  788. if (TEST_FLAG(NewState, CD_STOPPING)) {
  789. SET_FLAG(NewState, CD_PLAYING);
  790. }
  791. ValidateCdromState(ExpectedOldState);
  792. ValidateCdromState(NewState);
  793. //attempt to change it
  794. trueOldState = InterlockedCompareExchange(
  795. &DeviceExtension->CDRom.StateNow,
  796. NewState,
  797. ExpectedOldState
  798. );
  799. ASSERTMSG("State set outside of thread",
  800. trueOldState == ExpectedOldState);
  801. //
  802. // see if an event should be fired, volume set, and/or
  803. // stream state set
  804. //
  805. if (ExpectedOldState == NewState) {
  806. //
  807. // if state is not changing, don't do anything
  808. //
  809. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  810. "Setting state to same as expected?! %x == %x\n",
  811. ExpectedOldState, NewState));
  812. } else if (TEST_FLAG(ExpectedOldState, CD_MASK_TEMP)) {
  813. //
  814. // should not go from temp state to temp state
  815. //
  816. ASSERT(!TEST_FLAG(NewState, CD_MASK_TEMP));
  817. //
  818. // ioctl is being processed, and state is no longer
  819. // in a temp state, so should process the ioctl again
  820. //
  821. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  822. "SetState => EVENT_COMPLETE should be set soon "
  823. "for %p\n", DeviceExtension->Thread.IoctlCurrent));
  824. } else if (TEST_FLAG(NewState, CD_MASK_TEMP)) {
  825. //
  826. // going to either pausing or stopping, both of which must
  827. // be specially handled by stopping the KS stream also.
  828. //
  829. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  830. "SetState => %s, setting device state "
  831. "to KSSTATE_STOP\n",
  832. (TEST_FLAG(NewState, CD_STOPPING) ? "STOP" : "PAUSE")));
  833. SetNextDeviceState(DeviceExtension, KSSTATE_STOP);
  834. } else if (TEST_FLAG(NewState, CD_PAUSED)) {
  835. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  836. "SetState => Finishing a PAUSE operation\n"));
  837. } else if (TEST_FLAG(NewState, CD_PLAYING)) {
  838. ULONG i;
  839. PREDBOOK_COMPLETION_CONTEXT context;
  840. ASSERT(NewState == CD_PLAYING);
  841. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  842. "SetState => Starting a PLAY operation\n"));
  843. //
  844. // not same state, not from temp state,
  845. // so must either be paused or stopped.
  846. //
  847. ASSERT(TEST_FLAG(ExpectedOldState,CD_STOPPED) ||
  848. TEST_FLAG(ExpectedOldState,CD_PAUSED));
  849. //
  850. // set some deviceextension stuff
  851. //
  852. RtlZeroMemory(&DeviceExtension->WmiPerf,
  853. sizeof(REDBOOK_WMI_PERF_DATA));
  854. DeviceExtension->CDRom.ReadErrors = 0;
  855. DeviceExtension->CDRom.StreamErrors = 0;
  856. DeviceExtension->Buffer.Paused = 0;
  857. DeviceExtension->Buffer.FirstPause = 1;
  858. DeviceExtension->Buffer.IndexToRead = 0;
  859. DeviceExtension->Buffer.IndexToStream = 0;
  860. //
  861. // reset the buffer state
  862. //
  863. ASSERT(DeviceExtension->Buffer.Contexts);
  864. context = DeviceExtension->Buffer.Contexts;
  865. for (i=0; i<DeviceExtension->WmiData.NumberOfBuffers;i++) {
  866. *(DeviceExtension->Buffer.ReadOk_X + i) = 0;
  867. *(DeviceExtension->Buffer.StreamOk_X + i) = 0;
  868. context->Reason = REDBOOK_CC_READ;
  869. context->Irp->IoStatus.Status = STATUS_SUCCESS;
  870. ExInterlockedInsertTailList(&DeviceExtension->Thread.DigitalList,
  871. &context->ListEntry,
  872. &DeviceExtension->Thread.DigitalLock);
  873. context++; // pointer arithmetic
  874. }
  875. context = NULL;
  876. //
  877. // start the digital playback
  878. //
  879. SetNextDeviceState(DeviceExtension, KSSTATE_RUN);
  880. RedBookKsSetVolume(DeviceExtension);
  881. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  882. "SetState => Setting DIGITAL event\n"));
  883. KeSetEvent(DeviceExtension->Thread.Events[EVENT_DIGITAL],
  884. IO_CD_ROM_INCREMENT, FALSE);
  885. } else {
  886. //
  887. // ReadQ Channel or some such nonsense
  888. //
  889. }
  890. return GetCdromState(DeviceExtension);
  891. }
  892. VOID
  893. RedBookDeallocatePlayResources(
  894. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  895. )
  896. {
  897. PREDBOOK_COMPLETION_CONTEXT context;
  898. ULONG i;
  899. BOOLEAN freedSomething = FALSE;
  900. PAGED_CODE();
  901. VerifyCalledByThread(DeviceExtension);
  902. #if DBG
  903. {
  904. ULONG state = GetCdromState(DeviceExtension);
  905. ASSERT(!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED));
  906. }
  907. #endif
  908. //
  909. // free all resources
  910. //
  911. if (DeviceExtension->Buffer.StreamOk_X) {
  912. freedSomething = TRUE;
  913. ExFreePool(DeviceExtension->Buffer.StreamOk_X);
  914. DeviceExtension->Buffer.StreamOk_X = NULL;
  915. }
  916. if (DeviceExtension->Buffer.ReadOk_X) {
  917. freedSomething = TRUE;
  918. ExFreePool(DeviceExtension->Buffer.ReadOk_X);
  919. DeviceExtension->Buffer.ReadOk_X = NULL;
  920. }
  921. if (DeviceExtension->Buffer.Contexts) {
  922. context = DeviceExtension->Buffer.Contexts;
  923. for (i=0;i<DeviceExtension->WmiData.NumberOfBuffers;i++) {
  924. if (context->Irp) {
  925. IoFreeIrp(context->Irp);
  926. }
  927. if (context->Mdl) {
  928. IoFreeMdl(context->Mdl);
  929. }
  930. context++; // pointer arithmetic
  931. }
  932. context = NULL;
  933. freedSomething = TRUE;
  934. ExFreePool(DeviceExtension->Buffer.Contexts);
  935. DeviceExtension->Buffer.Contexts = NULL;
  936. }
  937. if (DeviceExtension->Buffer.SilentMdl) {
  938. freedSomething = TRUE;
  939. IoFreeMdl(DeviceExtension->Buffer.SilentMdl);
  940. DeviceExtension->Buffer.SilentMdl = NULL;
  941. }
  942. if (DeviceExtension->Buffer.SkipBuffer) {
  943. freedSomething = TRUE;
  944. ExFreePool(DeviceExtension->Buffer.SkipBuffer);
  945. DeviceExtension->Buffer.SkipBuffer = NULL;
  946. }
  947. if (DeviceExtension->Thread.CheckVerifyIrp) {
  948. PIRP irp = DeviceExtension->Thread.CheckVerifyIrp;
  949. freedSomething = TRUE;
  950. if (irp->MdlAddress) {
  951. IoFreeMdl(irp->MdlAddress);
  952. }
  953. if (irp->AssociatedIrp.SystemBuffer) {
  954. ExFreePool(irp->AssociatedIrp.SystemBuffer);
  955. }
  956. IoFreeIrp(DeviceExtension->Thread.CheckVerifyIrp);
  957. DeviceExtension->Thread.CheckVerifyIrp = NULL;
  958. }
  959. if (DeviceExtension->Stream.PinFileObject) {
  960. freedSomething = TRUE;
  961. CloseSysAudio(DeviceExtension);
  962. }
  963. if (DeviceExtension->CDRom.Toc) {
  964. freedSomething = TRUE;
  965. ExFreePool(DeviceExtension->CDRom.Toc);
  966. DeviceExtension->CDRom.Toc = NULL;
  967. }
  968. if (freedSomething) {
  969. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  970. "DeallocatePlay => Deallocated play resources\n"));
  971. }
  972. return;
  973. }
  974. BOOLEAN
  975. RedBookArePlayResourcesAllocated(
  976. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  977. )
  978. //
  979. // just choose one, since it's all done in a batch in
  980. // one thread context it's always safe.
  981. //
  982. {
  983. PAGED_CODE();
  984. VerifyCalledByThread(DeviceExtension);
  985. return (DeviceExtension->Stream.PinFileObject != NULL);
  986. }
  987. NTSTATUS
  988. RedBookAllocatePlayResources(
  989. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  990. )
  991. //
  992. // allocate resources if they are not already allocated
  993. //
  994. {
  995. PREDBOOK_COMPLETION_CONTEXT context;
  996. NTSTATUS status;
  997. KEVENT event;
  998. ULONG numBufs;
  999. ULONG numSectors;
  1000. ULONG bufSize;
  1001. ULONG i;
  1002. CCHAR maxStack;
  1003. BOOLEAN sysAudioOpened = FALSE;
  1004. PAGED_CODE();
  1005. VerifyCalledByThread(DeviceExtension);
  1006. //
  1007. // NOTE:
  1008. // The call to update the mixer Id may de-allocate all play
  1009. // resources, since the stack sizes may change. it must
  1010. // therefore be the first call within this routine.
  1011. //
  1012. if (DeviceExtension->Stream.MixerPinId == -1) {
  1013. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1014. "AllocatePlay => No mixer set?\n"));
  1015. return STATUS_UNSUCCESSFUL;
  1016. }
  1017. if (DeviceExtension->Buffer.Contexts != NULL) {
  1018. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1019. "AllocatePlay => Using existing resources\n"));
  1020. return STATUS_SUCCESS;
  1021. }
  1022. #if DBG
  1023. {
  1024. ULONG state = GetCdromState(DeviceExtension);
  1025. ASSERT(!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED));
  1026. }
  1027. #endif
  1028. ASSERT(DeviceExtension->Buffer.Contexts == NULL);
  1029. ASSERT(DeviceExtension->Buffer.SkipBuffer == NULL);
  1030. numBufs = DeviceExtension->WmiData.NumberOfBuffers;
  1031. numSectors = DeviceExtension->WmiData.SectorsPerRead;
  1032. bufSize = RAW_SECTOR_SIZE * numSectors;
  1033. TRY {
  1034. ASSERT(DeviceExtension->Stream.MixerPinId != -1);
  1035. //
  1036. // may need to allocate the CheckVerifyIrp
  1037. //
  1038. {
  1039. PIO_STACK_LOCATION irpStack;
  1040. PIRP irp;
  1041. irp = DeviceExtension->Thread.CheckVerifyIrp;
  1042. if (irp == NULL) {
  1043. irp = IoAllocateIrp(
  1044. (CCHAR)(DeviceExtension->SelfDeviceObject->StackSize+1),
  1045. FALSE);
  1046. }
  1047. if (irp == NULL) {
  1048. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1049. "AllocatePlay => No CheckVerifyIrp\n"));
  1050. status = STATUS_NO_MEMORY;
  1051. LEAVE;
  1052. }
  1053. irp->AssociatedIrp.SystemBuffer = irp->MdlAddress = NULL;
  1054. irp->AssociatedIrp.SystemBuffer =
  1055. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1056. sizeof(ULONG),
  1057. TAG_CV_BUFFER);
  1058. if (irp->AssociatedIrp.SystemBuffer == NULL) {
  1059. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1060. "AllocatePlay => No CheckVerify Buffer\n"));
  1061. status = STATUS_NO_MEMORY;
  1062. LEAVE;
  1063. }
  1064. irp->MdlAddress = IoAllocateMdl(irp->AssociatedIrp.SystemBuffer,
  1065. sizeof(ULONG),
  1066. FALSE, FALSE, NULL);
  1067. if (irp->MdlAddress == NULL) {
  1068. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1069. "AllocatePlay => No CheckVerify Mdl\n"));
  1070. status = STATUS_NO_MEMORY;
  1071. LEAVE;
  1072. }
  1073. MmBuildMdlForNonPagedPool(irp->MdlAddress);
  1074. IoSetNextIrpStackLocation(irp);
  1075. irpStack = IoGetCurrentIrpStackLocation(irp);
  1076. irpStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1077. irpStack->Parameters.DeviceIoControl.InputBufferLength =
  1078. 0;
  1079. irpStack->Parameters.DeviceIoControl.OutputBufferLength =
  1080. sizeof(ULONG);
  1081. irpStack->Parameters.DeviceIoControl.IoControlCode =
  1082. IOCTL_CDROM_CHECK_VERIFY;
  1083. DeviceExtension->Thread.CheckVerifyIrp = irp;
  1084. }
  1085. //
  1086. // connect to sysaudio
  1087. //
  1088. {
  1089. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1090. "AllocatePlay => Preparing to open sysaudio\n"));
  1091. ASSERT(DeviceExtension->Stream.MixerPinId != MAXULONG);
  1092. status = OpenSysAudio(DeviceExtension);
  1093. if ( !NT_SUCCESS(status) ) {
  1094. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  1095. "AllocatePlay !! Unable to open sysaudio %lx\n",
  1096. status));
  1097. LEAVE;
  1098. }
  1099. // else the pin is open
  1100. sysAudioOpened = TRUE;
  1101. }
  1102. maxStack = MAX(DeviceExtension->TargetDeviceObject->StackSize,
  1103. DeviceExtension->Stream.PinDeviceObject->StackSize);
  1104. DeviceExtension->Buffer.MaxIrpStack = maxStack;
  1105. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1106. "AllocateePlay => Stacks: Cdrom %x Stream %x\n",
  1107. DeviceExtension->TargetDeviceObject->StackSize,
  1108. DeviceExtension->Stream.PinDeviceObject->StackSize));
  1109. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1110. "AllocateePlay => Allocating %x stacks per irp\n",
  1111. maxStack));
  1112. DeviceExtension->Buffer.SkipBuffer =
  1113. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1114. bufSize * (numBufs + 1),
  1115. TAG_BUFFER);
  1116. if (DeviceExtension->Buffer.SkipBuffer == NULL) {
  1117. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1118. "AllocatePlay => No Skipbuffer\n"));
  1119. status = STATUS_NO_MEMORY;
  1120. LEAVE;
  1121. }
  1122. RtlZeroMemory(DeviceExtension->Buffer.SkipBuffer,
  1123. bufSize * (numBufs + 1));
  1124. DeviceExtension->Buffer.Contexts =
  1125. ExAllocatePoolWithTag(NonPagedPool,
  1126. sizeof(REDBOOK_COMPLETION_CONTEXT) * numBufs,
  1127. TAG_CC);
  1128. if (DeviceExtension->Buffer.Contexts == NULL) {
  1129. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1130. "AllocatePlay => No Contexts\n"));
  1131. status = STATUS_NO_MEMORY;
  1132. LEAVE;
  1133. }
  1134. RtlZeroMemory(DeviceExtension->Buffer.Contexts,
  1135. sizeof(REDBOOK_COMPLETION_CONTEXT) * numBufs);
  1136. context = DeviceExtension->Buffer.Contexts;
  1137. for (i=0;i<numBufs;i++) {
  1138. context->DeviceExtension = DeviceExtension;
  1139. context->Reason = REDBOOK_CC_READ;
  1140. context->Index = i;
  1141. context->Buffer = DeviceExtension->Buffer.SkipBuffer +
  1142. (bufSize * i); // pointer arithmetic of UCHARS
  1143. //
  1144. // allocate irp, mdl
  1145. //
  1146. context->Irp = IoAllocateIrp(maxStack, FALSE);
  1147. context->Mdl = IoAllocateMdl(context->Buffer, bufSize,
  1148. FALSE, FALSE, NULL);
  1149. if (context->Irp == NULL ||
  1150. context->Mdl == NULL) {
  1151. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1152. "AllocatePlay => Irp/Mdl %x failed\n", i));
  1153. status = STATUS_NO_MEMORY;
  1154. LEAVE;
  1155. }
  1156. MmBuildMdlForNonPagedPool(context->Mdl);
  1157. context++; // pointer arithmetic of CONTEXTS
  1158. }
  1159. context = NULL; // safety
  1160. //
  1161. // allocated above as part of SkipBuffer
  1162. //
  1163. DeviceExtension->Buffer.SilentBuffer =
  1164. DeviceExtension->Buffer.SkipBuffer + (bufSize * numBufs);
  1165. DeviceExtension->Buffer.SilentMdl =
  1166. IoAllocateMdl(DeviceExtension->Buffer.SkipBuffer, bufSize,
  1167. FALSE, FALSE, NULL);
  1168. if (DeviceExtension->Buffer.SilentMdl == NULL) {
  1169. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1170. "AllocatePlay => Silent Mdl failed\n"));
  1171. status = STATUS_NO_MEMORY;
  1172. LEAVE;
  1173. }
  1174. DeviceExtension->Buffer.ReadOk_X =
  1175. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1176. sizeof(ULONG) * numBufs,
  1177. TAG_READX);
  1178. if (DeviceExtension->Buffer.ReadOk_X == NULL) {
  1179. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1180. "AllocatePlay => ReadOk_X failed\n"));
  1181. status = STATUS_NO_MEMORY;
  1182. LEAVE;
  1183. }
  1184. RtlZeroMemory(DeviceExtension->Buffer.ReadOk_X,
  1185. sizeof(ULONG) * numBufs);
  1186. DeviceExtension->Buffer.StreamOk_X =
  1187. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1188. sizeof(ULONG) * numBufs,
  1189. TAG_STREAMX);
  1190. if (DeviceExtension->Buffer.StreamOk_X == NULL) {
  1191. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1192. "AllocatePlay => ReadOk_X failed\n"));
  1193. status = STATUS_NO_MEMORY;
  1194. LEAVE;
  1195. }
  1196. RtlZeroMemory(DeviceExtension->Buffer.StreamOk_X,
  1197. sizeof(ULONG) * numBufs);
  1198. MmBuildMdlForNonPagedPool(DeviceExtension->Buffer.SilentMdl);
  1199. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1200. "AllocatePlay => Allocated All Resources\n"));
  1201. status = STATUS_SUCCESS;
  1202. } FINALLY {
  1203. if (!NT_SUCCESS(status)) {
  1204. RedBookDeallocatePlayResources(DeviceExtension);
  1205. return status;
  1206. }
  1207. }
  1208. //
  1209. // else all resources allocated
  1210. //
  1211. return STATUS_SUCCESS;
  1212. }
  1213. NTSTATUS
  1214. RedBookCacheToc(
  1215. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  1216. )
  1217. {
  1218. PCDROM_TOC newToc;
  1219. PIRP irp;
  1220. ULONG mediaChangeCount;
  1221. IO_STATUS_BLOCK ioStatus;
  1222. KEVENT event;
  1223. NTSTATUS status;
  1224. PAGED_CODE();
  1225. VerifyCalledByThread(DeviceExtension);
  1226. //
  1227. // cache the number of times the media has changed
  1228. // use this to prevent redundant reads of the toc
  1229. // and to return Q channel info during playback
  1230. //
  1231. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1232. //
  1233. // first get the mediaChangeCount to see if we've already
  1234. // cached this toc
  1235. //
  1236. irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_CHECK_VERIFY,
  1237. DeviceExtension->TargetDeviceObject,
  1238. NULL, 0,
  1239. &mediaChangeCount, sizeof(ULONG),
  1240. FALSE,
  1241. &event, &ioStatus);
  1242. if (irp == NULL) {
  1243. return STATUS_NO_MEMORY;
  1244. }
  1245. SET_FLAG(IoGetNextIrpStackLocation(irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
  1246. status = IoCallDriver(DeviceExtension->TargetDeviceObject, irp);
  1247. if (status == STATUS_PENDING) {
  1248. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1249. status = ioStatus.Status;
  1250. }
  1251. if (!NT_SUCCESS(status)) {
  1252. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1253. "CacheToc !! CheckVerify failed %lx\n", status));
  1254. return status;
  1255. }
  1256. //
  1257. // read TOC only we don't have the correct copy cached
  1258. //
  1259. if (DeviceExtension->CDRom.Toc != NULL &&
  1260. DeviceExtension->CDRom.CheckVerify == mediaChangeCount) {
  1261. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1262. "CacheToc => Using cached toc\n"));
  1263. return STATUS_SUCCESS;
  1264. }
  1265. //
  1266. // Allocate for the cached TOC
  1267. //
  1268. newToc = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1269. sizeof(CDROM_TOC),
  1270. TAG_TOC);
  1271. if (newToc == NULL) {
  1272. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1273. "CacheToc !! Unable to allocate new TOC\n"));
  1274. return STATUS_NO_MEMORY;
  1275. }
  1276. KeClearEvent(&event);
  1277. irp = IoBuildDeviceIoControlRequest(IOCTL_CDROM_READ_TOC,
  1278. DeviceExtension->TargetDeviceObject,
  1279. NULL, 0,
  1280. newToc, sizeof(CDROM_TOC),
  1281. FALSE,
  1282. &event, &ioStatus);
  1283. if (irp == NULL) {
  1284. ExFreePool(newToc);
  1285. newToc = NULL;
  1286. return STATUS_NO_MEMORY;
  1287. }
  1288. SET_FLAG(IoGetNextIrpStackLocation(irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
  1289. status = IoCallDriver(DeviceExtension->TargetDeviceObject, irp);
  1290. if (status == STATUS_PENDING) {
  1291. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1292. status = ioStatus.Status;
  1293. }
  1294. //
  1295. // set the new toc, or if error free it
  1296. // return the status
  1297. //
  1298. if (!NT_SUCCESS(status)) {
  1299. ExFreePool(newToc);
  1300. newToc = NULL;
  1301. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1302. "CacheToc !! Failed to get TOC %lx\n", status));
  1303. } else {
  1304. if (DeviceExtension->CDRom.Toc) {
  1305. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugAllocPlay, "[redbook] "
  1306. "CacheToc => Freeing old toc %p\n",
  1307. DeviceExtension->CDRom.Toc));
  1308. ExFreePool(DeviceExtension->CDRom.Toc);
  1309. }
  1310. DeviceExtension->CDRom.Toc = newToc;
  1311. DeviceExtension->CDRom.CheckVerify = mediaChangeCount;
  1312. }
  1313. return status;
  1314. }
  1315. VOID
  1316. RedBookThreadDigitalHandler(
  1317. IN PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  1318. IN PLIST_ENTRY ListEntry
  1319. )
  1320. //
  1321. // DECREMENT StreamPending/ReadPending if it's a completion
  1322. // SET stopped, error, etc. states
  1323. // INCREMENT StreamPending/ReadPending if it's to be sent again
  1324. //
  1325. {
  1326. PREDBOOK_COMPLETION_CONTEXT Context;
  1327. ULONG index;
  1328. ULONG mod;
  1329. ULONG state;
  1330. PAGED_CODE();
  1331. VerifyCalledByThread(DeviceExtension);
  1332. ASSERT(DeviceExtension->WmiData.NumberOfBuffers);
  1333. ASSERT(DeviceExtension->Buffer.SkipBuffer);
  1334. //
  1335. // Increment/Decrement PendingRead/PendingStream
  1336. //
  1337. Context = CONTAINING_RECORD(ListEntry, REDBOOK_COMPLETION_CONTEXT, ListEntry);
  1338. index = Context->Index;
  1339. mod = DeviceExtension->WmiData.NumberOfBuffers;
  1340. state = GetCdromState(DeviceExtension);
  1341. //
  1342. // decrement the number reading/streaming if needed
  1343. //
  1344. if (Context->Reason == REDBOOK_CC_READ_COMPLETE) {
  1345. if (!NT_SUCCESS(Context->Irp->IoStatus.Status)) {
  1346. if (IoIsErrorUserInduced(Context->Irp->IoStatus.Status)) {
  1347. DeviceExtension->CDRom.ReadErrors = REDBOOK_MAX_CONSECUTIVE_ERRORS;
  1348. } else {
  1349. DeviceExtension->CDRom.ReadErrors++;
  1350. }
  1351. } else {
  1352. DeviceExtension->CDRom.ReadErrors = 0;
  1353. }
  1354. DeviceExtension->Thread.PendingRead--;
  1355. Context->Reason = REDBOOK_CC_STREAM;
  1356. } else if (Context->Reason == REDBOOK_CC_STREAM_COMPLETE) {
  1357. if (!NT_SUCCESS(Context->Irp->IoStatus.Status)) {
  1358. DeviceExtension->CDRom.StreamErrors++;
  1359. } else {
  1360. DeviceExtension->CDRom.StreamErrors = 0;
  1361. }
  1362. //
  1363. // if stream succeeded OR we are _NOT_ stopping audio,
  1364. // increment FinishedStreaming and save wmi stats
  1365. //
  1366. if (NT_SUCCESS(Context->Irp->IoStatus.Status) ||
  1367. !TEST_FLAG(state, CD_MASK_TEMP)) {
  1368. DeviceExtension->CDRom.FinishedStreaming +=
  1369. DeviceExtension->WmiData.SectorsPerRead;
  1370. AddWmiStats(DeviceExtension, Context);
  1371. }
  1372. DeviceExtension->Thread.PendingStream--;
  1373. Context->Reason = REDBOOK_CC_READ;
  1374. }
  1375. if (DeviceExtension->CDRom.StreamErrors >= REDBOOK_MAX_CONSECUTIVE_ERRORS &&
  1376. !TEST_FLAG(state, CD_MASK_TEMP)) {
  1377. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1378. "Digital => Too many stream errors, beginning STOP\n"));
  1379. ASSERT(!TEST_FLAG(state, CD_STOPPED));
  1380. ASSERT(!TEST_FLAG(state, CD_PAUSED));
  1381. state = SetCdromState(DeviceExtension, state, CD_STOPPING);
  1382. }
  1383. if (DeviceExtension->CDRom.ReadErrors >= REDBOOK_MAX_CONSECUTIVE_ERRORS &&
  1384. !TEST_FLAG(state, CD_MASK_TEMP)) {
  1385. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1386. "Digital => Too many read errors, beginning STOP\n"));
  1387. state = SetCdromState(DeviceExtension, state, CD_STOPPING);
  1388. }
  1389. //
  1390. // if stopping/pausing/etc, and no reads/streams are pending,
  1391. // set the new state and return.
  1392. // the while() loop in the thread will do the right thing
  1393. // when there is no more outstanding io--it will call the ioctl
  1394. // completion handler to do whatever post-processing is needed.
  1395. //
  1396. if (TEST_FLAG(state, CD_MASK_TEMP)) {
  1397. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1398. "Digital => Temp state %x, not continuing (%d, %d)\n",
  1399. state,
  1400. DeviceExtension->Thread.PendingRead,
  1401. DeviceExtension->Thread.PendingStream
  1402. ));
  1403. if (DeviceExtension->Thread.PendingRead == 0 &&
  1404. DeviceExtension->Thread.PendingStream == 0) {
  1405. //
  1406. // Set NextToRead and NextToStream to FinishedStreaming
  1407. //
  1408. DeviceExtension->CDRom.NextToRead =
  1409. DeviceExtension->CDRom.NextToStream =
  1410. DeviceExtension->CDRom.FinishedStreaming;
  1411. if (TEST_FLAG(state, CD_PAUSING)) {
  1412. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1413. "Digital => completing PAUSED\n"));
  1414. state = SetCdromState(DeviceExtension, state, CD_PAUSED);
  1415. } else if (TEST_FLAG(state, CD_STOPPING)) {
  1416. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1417. "Digital => completing STOPPED\n"));
  1418. state = SetCdromState(DeviceExtension, state, CD_STOPPED);
  1419. } else {
  1420. ASSERT(!"Unknown state?");
  1421. }
  1422. if (DeviceExtension->Thread.IoctlCurrent) {
  1423. KeSetEvent(DeviceExtension->Thread.Events[EVENT_COMPLETE],
  1424. IO_CD_ROM_INCREMENT, FALSE);
  1425. }
  1426. }
  1427. return;
  1428. }
  1429. if (DeviceExtension->CDRom.NextToRead >= DeviceExtension->CDRom.EndPlay &&
  1430. Context->Reason == REDBOOK_CC_READ) {
  1431. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1432. "Digital => End play, ignoring READ\n"));
  1433. if (DeviceExtension->Thread.PendingRead == 0 &&
  1434. DeviceExtension->Thread.PendingStream == 0) {
  1435. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1436. "Digital => All IO done, setting STOPPED\n"));
  1437. state = SetCdromState(DeviceExtension, state, CD_STOPPED);
  1438. }
  1439. return;
  1440. }
  1441. if (DeviceExtension->CDRom.NextToStream >= DeviceExtension->CDRom.EndPlay &&
  1442. Context->Reason == REDBOOK_CC_STREAM) {
  1443. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1444. "Digital => End play, ignoring STREAM\n"));
  1445. if (DeviceExtension->Thread.PendingRead == 0 &&
  1446. DeviceExtension->Thread.PendingStream == 0) {
  1447. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1448. "Digital => All IO done, setting STOPPED\n"));
  1449. state = SetCdromState(DeviceExtension, state, CD_STOPPED);
  1450. }
  1451. return;
  1452. }
  1453. switch(Context->Reason) {
  1454. case REDBOOK_CC_READ: {
  1455. // mark this buffer as off the queue/usable
  1456. ASSERT(DeviceExtension->Buffer.ReadOk_X[index] == 0);
  1457. DeviceExtension->Buffer.ReadOk_X[index] = 1;
  1458. if (index != DeviceExtension->Buffer.IndexToRead) {
  1459. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1460. "Digital => Delaying read, index %x\n", index));
  1461. return;
  1462. }
  1463. if (DeviceExtension->CDRom.NextToRead >
  1464. DeviceExtension->CDRom.EndPlay) {
  1465. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1466. "Digital => End of Play\n"));
  1467. return;
  1468. }
  1469. for (index = Context->Index;
  1470. DeviceExtension->Buffer.ReadOk_X[index] != 0;
  1471. index = (index + 1) % mod) {
  1472. // mark this buffer as in use BEFORE attempting to read
  1473. DeviceExtension->Buffer.ReadOk_X[index] = 0;
  1474. DeviceExtension->Thread.PendingRead++;
  1475. RedBookReadRaw(DeviceExtension,
  1476. &DeviceExtension->Buffer.Contexts[index]);
  1477. // increment where reading from AFTER attempting to read
  1478. DeviceExtension->CDRom.NextToRead +=
  1479. DeviceExtension->WmiData.SectorsPerRead;
  1480. // inc/mod the index AFTER attempting to read
  1481. DeviceExtension->Buffer.IndexToRead++;
  1482. DeviceExtension->Buffer.IndexToRead %= mod;
  1483. }
  1484. break;
  1485. }
  1486. case REDBOOK_CC_STREAM: {
  1487. // mark this buffer as off the queue/usable
  1488. ASSERT(DeviceExtension->Buffer.StreamOk_X[index] == 0);
  1489. DeviceExtension->Buffer.StreamOk_X[index] = 1;
  1490. if (index != DeviceExtension->Buffer.IndexToStream) {
  1491. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugThread, "[redbook] "
  1492. "Delaying stream of index %x\n", index));
  1493. return;
  1494. }
  1495. for (index = Context->Index;
  1496. DeviceExtension->Buffer.StreamOk_X[index] != 0;
  1497. index = (index + 1) % mod) {
  1498. // mark this buffer as in use BEFORE attempting to read
  1499. DeviceExtension->Buffer.StreamOk_X[index] = 0;
  1500. DeviceExtension->Thread.PendingStream++;
  1501. RedBookStream(DeviceExtension,
  1502. &DeviceExtension->Buffer.Contexts[index]);
  1503. // increment where reading from AFTER attempting to read
  1504. DeviceExtension->CDRom.NextToStream +=
  1505. DeviceExtension->WmiData.SectorsPerRead;
  1506. // inc/mod the index AFTER attempting to read
  1507. DeviceExtension->Buffer.IndexToStream++;
  1508. DeviceExtension->Buffer.IndexToStream %= mod;
  1509. }
  1510. break;
  1511. }
  1512. default: {
  1513. ASSERT(!"Unhandled Context->Reason\n");
  1514. break;
  1515. }
  1516. } // end switch (Context->Reason)
  1517. return;
  1518. }
  1519. VOID
  1520. AddWmiStats(
  1521. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  1522. PREDBOOK_COMPLETION_CONTEXT Context
  1523. )
  1524. {
  1525. KIRQL oldIrql;
  1526. ULONG timeIncrement;
  1527. if (Context->TimeReadSent.QuadPart == 0) {
  1528. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWmi, "[redbook] "
  1529. "Not Saving WMI Stats for REASON:\n"));
  1530. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWmi, "[redbook] "
  1531. "(ReadError, StreamError, Paused?)\n"));
  1532. return;
  1533. }
  1534. timeIncrement = KeQueryTimeIncrement(); // amount of time for each tick
  1535. KeAcquireSpinLock(&DeviceExtension->WmiPerfLock, &oldIrql);
  1536. DeviceExtension->WmiPerf.TimeReadDelay +=
  1537. (Context->TimeReadSent.QuadPart -
  1538. Context->TimeReadReady.QuadPart ) *
  1539. timeIncrement;
  1540. DeviceExtension->WmiPerf.TimeReading +=
  1541. (Context->TimeStreamReady.QuadPart -
  1542. Context->TimeReadSent.QuadPart ) *
  1543. timeIncrement;
  1544. DeviceExtension->WmiPerf.TimeStreamDelay +=
  1545. (Context->TimeStreamSent.QuadPart -
  1546. Context->TimeStreamReady.QuadPart ) *
  1547. timeIncrement;
  1548. DeviceExtension->WmiPerf.TimeStreaming +=
  1549. (Context->TimeReadReady.QuadPart -
  1550. Context->TimeStreamSent.QuadPart ) *
  1551. timeIncrement;
  1552. DeviceExtension->WmiPerf.DataProcessed +=
  1553. DeviceExtension->WmiData.SectorsPerRead * RAW_SECTOR_SIZE;
  1554. KeReleaseSpinLock( &DeviceExtension->WmiPerfLock, oldIrql );
  1555. return;
  1556. }
  1557. ////////////////////////////////////////////////////////////////////////////////
  1558. VOID
  1559. RedBookCheckForAudioDeviceRemoval(
  1560. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  1561. )
  1562. {
  1563. ULONG state = GetCdromState(DeviceExtension);
  1564. PAGED_CODE();
  1565. VerifyCalledByThread(DeviceExtension);
  1566. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  1567. "STCheckForRemoval => Checking if audio device changed\n"));
  1568. if (TEST_FLAG(state, CD_MASK_TEMP)) {
  1569. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  1570. "STCheckForRemoval => delaying -- temp state\n"));
  1571. return;
  1572. }
  1573. if (DeviceExtension->Stream.UpdateMixerPin == 0) {
  1574. return;
  1575. }
  1576. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  1577. "STCheckForRemoval => Audio Device may have changed\n"));
  1578. if (TEST_FLAG(state, CD_PLAYING)) {
  1579. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  1580. "STCheckForRemoval => playing, so stopping\n"));
  1581. state = SetCdromState(DeviceExtension, state, CD_STOPPING);
  1582. return;
  1583. }
  1584. if (TEST_FLAG(state, CD_STOPPED)) {
  1585. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  1586. "STCheckForRemoval => stopped, updating\n"));
  1587. } else if (TEST_FLAG(state, CD_PAUSED)) {
  1588. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  1589. "STCheckForRemoval => paused, updating\n"));
  1590. //
  1591. // ISSUE-2000/5/24-henrygab - may not need to stop
  1592. // unless mixer becomes -1,
  1593. // since we could then send
  1594. // to the new audio device.
  1595. //
  1596. state = SetCdromState(DeviceExtension, state, CD_STOPPED);
  1597. }
  1598. ASSERT(TEST_FLAG(GetCdromState(DeviceExtension), CD_STOPPED));
  1599. //
  1600. // set the value to zero (iff the value was one)
  1601. // check if the value was one, and if so, update the mixerpin
  1602. //
  1603. if (InterlockedCompareExchange(&DeviceExtension->Stream.UpdateMixerPin,
  1604. 0, 1) == 1) {
  1605. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  1606. "STCheckForRemoval => Updating MixerPin\n"));
  1607. //
  1608. // free any in-use play resources
  1609. //
  1610. RedBookDeallocatePlayResources(DeviceExtension);
  1611. if (DeviceExtension->Stream.MixerPinId != -1) {
  1612. UninitializeVirtualSource(DeviceExtension);
  1613. }
  1614. InitializeVirtualSource(DeviceExtension);
  1615. if (DeviceExtension->Stream.MixerPinId == -1) {
  1616. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  1617. "STCheckForRemoval => Update of mixerpin "
  1618. "failed -- will retry later\n"));
  1619. InterlockedExchange(&DeviceExtension->Stream.UpdateMixerPin, 1);
  1620. return;
  1621. }
  1622. }
  1623. return;
  1624. }