Leaked source code of windows server 2003
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.

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