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.

1602 lines
44 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. RedBook.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 "ioctl.tmh"
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, RedBookCheckForDiscChangeAndFreeResources )
  20. #pragma alloc_text(PAGE, RedBookCompleteIoctl )
  21. #pragma alloc_text(PAGE, RedBookDCCheckVerify )
  22. #pragma alloc_text(PAGE, RedBookDCDefault )
  23. #pragma alloc_text(PAGE, RedBookDCGetVolume )
  24. #pragma alloc_text(PAGE, RedBookDCPause )
  25. #pragma alloc_text(PAGE, RedBookDCPlay )
  26. #pragma alloc_text(PAGE, RedBookDCReadQ )
  27. #pragma alloc_text(PAGE, RedBookDCResume )
  28. #pragma alloc_text(PAGE, RedBookDCSeek )
  29. #pragma alloc_text(PAGE, RedBookDCSetVolume )
  30. #pragma alloc_text(PAGE, RedBookDCStop )
  31. #pragma alloc_text(PAGE, RedBookThreadIoctlCompletionHandler )
  32. #pragma alloc_text(PAGE, RedBookThreadIoctlHandler )
  33. #pragma alloc_text(PAGE, WhichTrackContainsThisLBA )
  34. #endif // ALLOC_PRAGMA
  35. ////////////////////////////////////////////////////////////////////////////////
  36. NTSTATUS
  37. RedBookDeviceControl(
  38. PDEVICE_OBJECT DeviceObject,
  39. PIRP Irp
  40. )
  41. /*++
  42. Routine Description:
  43. This routine is called by the I/O subsystem for device controls.
  44. Arguments:
  45. DeviceObject
  46. Irp
  47. Return Value:
  48. NTSTATUS
  49. --*/
  50. {
  51. PREDBOOK_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  52. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation( Irp );
  53. ULONG cdromState;
  54. NTSTATUS status;
  55. BOOLEAN putOnQueue = FALSE;
  56. BOOLEAN completeRequest = FALSE;
  57. //
  58. // ioctls not guaranteed at passive, making this whole
  59. // section non-paged
  60. //
  61. //
  62. // Prevent a remove from occuring while IO pending
  63. //
  64. status = IoAcquireRemoveLock( &deviceExtension->RemoveLock, Irp );
  65. if ( !NT_SUCCESS(status) ) {
  66. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  67. "DeviceControl !! Unable to acquire remove lock %lx\n",
  68. status));
  69. Irp->IoStatus.Information = 0;
  70. Irp->IoStatus.Status = status;
  71. IoCompleteRequest( Irp, IO_CD_ROM_INCREMENT );
  72. return status;
  73. }
  74. #if DBG
  75. //
  76. // save some info for the last N device ioctls that came through
  77. //
  78. {
  79. ULONG index;
  80. ULONG sizeToCopy;
  81. ULONG stacksToCopy;
  82. PSAVED_IO savedIo;
  83. index = InterlockedIncrement(&deviceExtension->SavedIoCurrentIndex);
  84. index %= SAVED_IO_MAX;
  85. savedIo = &(deviceExtension->SavedIo[index]);
  86. //
  87. // copy as much of the irp as we can....
  88. //
  89. savedIo->OriginalIrp = Irp;
  90. if (Irp->StackCount > 7) {
  91. sizeToCopy = IoSizeOfIrp(8);
  92. RtlFillMemory(savedIo, sizeToCopy, 0xff);
  93. sizeToCopy -= sizeof(IO_STACK_LOCATION);
  94. RtlCopyMemory(savedIo, Irp, sizeToCopy);
  95. } else {
  96. sizeToCopy = IoSizeOfIrp(Irp->StackCount);
  97. RtlZeroMemory(savedIo, sizeof(SAVED_IO));
  98. RtlCopyMemory(savedIo, Irp, sizeToCopy);
  99. }
  100. } // end of saved io
  101. #endif // DBG
  102. //
  103. // if handled, just verify the paramters in this routine.
  104. //
  105. status = STATUS_UNSUCCESSFUL;
  106. cdromState = GetCdromState(deviceExtension);
  107. switch ( currentIrpStack->Parameters.DeviceIoControl.IoControlCode ) {
  108. case IOCTL_CDROM_PAUSE_AUDIO: {
  109. if (TEST_FLAG(cdromState, CD_STOPPED)) {
  110. Irp->IoStatus.Information = 0;
  111. status = STATUS_INVALID_DEVICE_REQUEST;
  112. completeRequest = TRUE;
  113. } else {
  114. putOnQueue = TRUE;
  115. }
  116. break;
  117. }
  118. case IOCTL_CDROM_STOP_AUDIO: {
  119. if (TEST_FLAG(cdromState, CD_STOPPED)) {
  120. Irp->IoStatus.Information = 0;
  121. status = STATUS_SUCCESS;
  122. completeRequest = TRUE;
  123. } else {
  124. putOnQueue = TRUE;
  125. }
  126. break;
  127. }
  128. case IOCTL_CDROM_RESUME_AUDIO: {
  129. if (TEST_FLAG(cdromState, CD_STOPPED)) {
  130. Irp->IoStatus.Information = 0;
  131. status = STATUS_INVALID_DEVICE_REQUEST;
  132. completeRequest = TRUE;
  133. } else {
  134. putOnQueue = TRUE;
  135. }
  136. break;
  137. }
  138. case IOCTL_CDROM_PLAY_AUDIO_MSF: {
  139. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  140. sizeof(CDROM_PLAY_AUDIO_MSF)) {
  141. Irp->IoStatus.Information = sizeof(CDROM_PLAY_AUDIO_MSF);
  142. status = STATUS_BUFFER_TOO_SMALL;
  143. completeRequest = TRUE;
  144. } else {
  145. putOnQueue = TRUE;
  146. }
  147. break;
  148. }
  149. case IOCTL_CDROM_SEEK_AUDIO_MSF: {
  150. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  151. sizeof(CDROM_SEEK_AUDIO_MSF)) {
  152. Irp->IoStatus.Information = sizeof(CDROM_SEEK_AUDIO_MSF);
  153. status = STATUS_BUFFER_TOO_SMALL;
  154. completeRequest = TRUE;
  155. } else if (TEST_FLAG(cdromState, CD_STOPPED)) {
  156. // default -- passthrough
  157. // REQUIRED to reduce latency for some drives.
  158. // drives may still fail the request
  159. } else {
  160. putOnQueue = TRUE;
  161. }
  162. break;
  163. }
  164. case IOCTL_CDROM_READ_Q_CHANNEL: {
  165. PCDROM_SUB_Q_DATA_FORMAT inputBuffer;
  166. inputBuffer = Irp->AssociatedIrp.SystemBuffer;
  167. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  168. sizeof(SUB_Q_CHANNEL_DATA)) {
  169. Irp->IoStatus.Information = sizeof(SUB_Q_CHANNEL_DATA);
  170. status = STATUS_BUFFER_TOO_SMALL;
  171. completeRequest = TRUE;
  172. } else if (inputBuffer->Format != IOCTL_CDROM_CURRENT_POSITION &&
  173. inputBuffer->Format != IOCTL_CDROM_MEDIA_CATALOG &&
  174. inputBuffer->Format != IOCTL_CDROM_TRACK_ISRC ) {
  175. Irp->IoStatus.Information = 0;
  176. status = STATUS_INVALID_PARAMETER;
  177. completeRequest = TRUE;
  178. } else if (TEST_FLAG(cdromState, CD_STOPPED)) {
  179. // default -- passthrough
  180. } else {
  181. putOnQueue = TRUE;
  182. }
  183. break;
  184. }
  185. case IOCTL_CDROM_SET_VOLUME: {
  186. if (currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  187. sizeof(VOLUME_CONTROL)) {
  188. Irp->IoStatus.Information = sizeof(VOLUME_CONTROL);
  189. status = STATUS_BUFFER_TOO_SMALL;
  190. completeRequest = TRUE;
  191. } else if (TEST_FLAG(cdromState, CD_STOPPED)) {
  192. // default -- passthrough
  193. // BUGBUG -- this should set our internal volume
  194. } else {
  195. putOnQueue = TRUE;
  196. }
  197. break;
  198. }
  199. case IOCTL_CDROM_GET_VOLUME: {
  200. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  201. sizeof(VOLUME_CONTROL)) {
  202. Irp->IoStatus.Information = sizeof(VOLUME_CONTROL);
  203. status = STATUS_BUFFER_TOO_SMALL;
  204. completeRequest = TRUE;
  205. } else if (TEST_FLAG(cdromState, CD_STOPPED)) {
  206. // default -- passthrough
  207. // BUGBUG -- this should return our internal volume
  208. } else {
  209. putOnQueue = TRUE;
  210. }
  211. break;
  212. }
  213. case IOCTL_STORAGE_CHECK_VERIFY2:
  214. case IOCTL_STORAGE_CHECK_VERIFY:
  215. case IOCTL_CDROM_CHECK_VERIFY:
  216. case IOCTL_DISK_CHECK_VERIFY: {
  217. if ((currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength) &&
  218. (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  219. sizeof(ULONG))) {
  220. Irp->IoStatus.Information = sizeof(ULONG);
  221. status = STATUS_BUFFER_TOO_SMALL;
  222. completeRequest = TRUE;
  223. } else if (TEST_FLAG(cdromState, CD_STOPPED)) {
  224. // default -- passthrough
  225. } else {
  226. putOnQueue = TRUE;
  227. }
  228. break;
  229. }
  230. default: {
  231. if (TEST_FLAG(cdromState, CD_STOPPED)) {
  232. // default -- passthrough
  233. } else {
  234. putOnQueue = TRUE;
  235. }
  236. break;
  237. }
  238. }
  239. if (putOnQueue) {
  240. PREDBOOK_THREAD_IOCTL_DATA ioctlData;
  241. ASSERT(completeRequest == FALSE);
  242. //
  243. // need to allocate some info for each ioctl we handle
  244. //
  245. ioctlData =
  246. (PREDBOOK_THREAD_IOCTL_DATA)ExAllocatePoolWithTag(
  247. NonPagedPool,
  248. sizeof(REDBOOK_THREAD_IOCTL_DATA),
  249. TAG_T_IOCTL);
  250. if (ioctlData == NULL) {
  251. Irp->IoStatus.Information = 0;
  252. Irp->IoStatus.Status = STATUS_NO_MEMORY;
  253. IoCompleteRequest(Irp, IO_CD_ROM_INCREMENT);
  254. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  255. return STATUS_NO_MEMORY;
  256. }
  257. RtlZeroMemory(ioctlData, sizeof(REDBOOK_THREAD_IOCTL_DATA));
  258. ioctlData->Irp = Irp;
  259. ioctlData->Irp->IoStatus.Status = STATUS_PENDING;
  260. IoMarkIrpPending(ioctlData->Irp);
  261. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  262. "DeviceControl => Queue Ioctl Irp %p (%p)\n",
  263. ioctlData->Irp, ioctlData));
  264. //
  265. // queue them, allow thread to handle request
  266. //
  267. ExInterlockedInsertTailList(&deviceExtension->Thread.IoctlList,
  268. &ioctlData->ListEntry,
  269. &deviceExtension->Thread.IoctlLock);
  270. KeSetEvent(deviceExtension->Thread.Events[EVENT_IOCTL],
  271. IO_NO_INCREMENT, FALSE);
  272. status = STATUS_PENDING;
  273. } else if (completeRequest) {
  274. ASSERT(putOnQueue == FALSE);
  275. //
  276. // some error, ie. invalid buffer length
  277. //
  278. if (!NT_SUCCESS(status)) {
  279. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  280. "DeviceControl => Completing Irp %p with error %x\n",
  281. Irp, status));
  282. } else {
  283. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  284. "DeviceControl => Completing Irp %p early?\n",
  285. Irp));
  286. }
  287. Irp->IoStatus.Status = status;
  288. IoCompleteRequest(Irp, IO_CD_ROM_INCREMENT);
  289. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  290. } else {
  291. //
  292. // pass it through
  293. //
  294. status = RedBookSendToNextDriver(DeviceObject, Irp);
  295. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  296. }
  297. return status;
  298. }
  299. ////////////////////////////////////////////////////////////////////////////////
  300. VOID
  301. RedBookThreadIoctlCompletionHandler(
  302. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  303. )
  304. {
  305. PIO_STACK_LOCATION irpStack;
  306. PREDBOOK_THREAD_IOCTL_DATA ioctlData;
  307. ULONG state;
  308. PAGED_CODE();
  309. VerifyCalledByThread(DeviceExtension);
  310. ioctlData = CONTAINING_RECORD(DeviceExtension->Thread.IoctlCurrent,
  311. REDBOOK_THREAD_IOCTL_DATA,
  312. ListEntry);
  313. state = GetCdromState(DeviceExtension);
  314. irpStack = IoGetCurrentIrpStackLocation(ioctlData->Irp);
  315. //
  316. // final state should be set by the digital handler
  317. //
  318. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  319. case IOCTL_CDROM_PAUSE_AUDIO: {
  320. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  321. "IoctlComp => Finishing pause %p\n", ioctlData->Irp));
  322. ASSERT(state == CD_PAUSED);
  323. ioctlData->Irp->IoStatus.Information = 0;
  324. ioctlData->Irp->IoStatus.Status = STATUS_SUCCESS;
  325. RedBookCompleteIoctl(DeviceExtension, ioctlData, FALSE);
  326. break;
  327. }
  328. case IOCTL_CDROM_SEEK_AUDIO_MSF: {
  329. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  330. "IoctlComp => Finishing seek %p\n", ioctlData->Irp));
  331. ASSERT(state == CD_PLAYING);
  332. DeviceExtension->Buffer.FirstPause = 1;
  333. KeSetEvent(DeviceExtension->Thread.Events[EVENT_DIGITAL],
  334. IO_CD_ROM_INCREMENT, FALSE);
  335. ioctlData->Irp->IoStatus.Information = 0;
  336. ioctlData->Irp->IoStatus.Status = STATUS_SUCCESS;
  337. RedBookCompleteIoctl(DeviceExtension, ioctlData, FALSE);
  338. break;
  339. }
  340. case IOCTL_CDROM_STOP_AUDIO: {
  341. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  342. "IoctlComp => Finishing stop %p\n", ioctlData->Irp));
  343. ASSERT(TEST_FLAG(state, CD_STOPPED));
  344. ioctlData->Irp->IoStatus.Information = 0;
  345. ioctlData->Irp->IoStatus.Status = STATUS_SUCCESS;
  346. RedBookCompleteIoctl(DeviceExtension, ioctlData, FALSE);
  347. break;
  348. }
  349. default: {
  350. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  351. "IoctlComp => Unhandled Irp %p\n", ioctlData->Irp));
  352. ASSERT(FALSE);
  353. ioctlData->Irp->IoStatus.Information = 0;
  354. ioctlData->Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  355. RedBookCompleteIoctl(DeviceExtension, ioctlData, FALSE);
  356. break;
  357. }
  358. }
  359. return;
  360. }
  361. NTSTATUS
  362. RedBookCompleteIoctl(
  363. IN PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  364. IN PREDBOOK_THREAD_IOCTL_DATA Context,
  365. IN BOOLEAN SendToLowerDriver
  366. )
  367. {
  368. PIRP irp = Context->Irp;
  369. //
  370. // only to be called from the thread
  371. //
  372. PAGED_CODE();
  373. VerifyCalledByThread(DeviceExtension);
  374. //
  375. // should be properly setup for completion
  376. //
  377. if (DeviceExtension->Thread.IoctlCurrent == &Context->ListEntry) {
  378. //
  379. // an ioctl that required post-processing is finished.
  380. // allow the next one to occur
  381. //
  382. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  383. "CompleteIoctl => state-changing Irp %p completed\n",
  384. irp));
  385. DeviceExtension->Thread.IoctlCurrent = NULL;
  386. }
  387. ExFreePool(Context);
  388. Context = NULL;
  389. if (SendToLowerDriver) {
  390. NTSTATUS status;
  391. status = RedBookSendToNextDriver(DeviceExtension->SelfDeviceObject, irp);
  392. IoReleaseRemoveLock(&DeviceExtension->RemoveLock, irp);
  393. return status;
  394. } else {
  395. IoCompleteRequest(irp, IO_CD_ROM_INCREMENT);
  396. IoReleaseRemoveLock(&DeviceExtension->RemoveLock, irp);
  397. return STATUS_SUCCESS;
  398. }
  399. }
  400. VOID
  401. RedBookThreadIoctlHandler(
  402. IN PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  403. IN PLIST_ENTRY ListEntry
  404. )
  405. {
  406. PREDBOOK_THREAD_IOCTL_DATA data;
  407. PIO_STACK_LOCATION currentIrpStack;
  408. PAGED_CODE();
  409. VerifyCalledByThread(DeviceExtension);
  410. //
  411. // should never happen if a state-changing ioctl is in progress
  412. //
  413. ASSERT(DeviceExtension->Thread.IoctlCurrent == NULL);
  414. //
  415. // don't use stale info
  416. //
  417. RedBookCheckForDiscChangeAndFreeResources(DeviceExtension);
  418. //
  419. // get the ioctl that set this event and
  420. // start working on state changes neccessary
  421. //
  422. data = CONTAINING_RECORD(ListEntry, REDBOOK_THREAD_IOCTL_DATA, ListEntry);
  423. currentIrpStack = IoGetCurrentIrpStackLocation(data->Irp);
  424. //
  425. // now guaranteed it's ok to run this ioctl
  426. // it's the responsibility of these routines to call RedBookCompleteIoctl()
  427. // *** OR *** to set DeviceExtension->Thread.IoctlCurrent to
  428. // Context->ListEntry if it requires post-processing, as this
  429. // is the mechanism used to determine the ioctl is still inprogress
  430. //
  431. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  432. case IOCTL_CDROM_PLAY_AUDIO_MSF: {
  433. RedBookDCPlay(DeviceExtension, data);
  434. break;
  435. }
  436. case IOCTL_CDROM_PAUSE_AUDIO: {
  437. RedBookDCPause(DeviceExtension, data);
  438. break;
  439. }
  440. case IOCTL_CDROM_RESUME_AUDIO: {
  441. RedBookDCResume(DeviceExtension, data);
  442. break;
  443. }
  444. case IOCTL_CDROM_STOP_AUDIO: {
  445. RedBookDCStop(DeviceExtension, data);
  446. break;
  447. }
  448. case IOCTL_CDROM_SEEK_AUDIO_MSF: {
  449. RedBookDCSeek(DeviceExtension, data);
  450. break;
  451. }
  452. case IOCTL_CDROM_READ_Q_CHANNEL: {
  453. RedBookDCReadQ(DeviceExtension, data);
  454. break;
  455. }
  456. case IOCTL_CDROM_SET_VOLUME: {
  457. RedBookDCSetVolume(DeviceExtension, data);
  458. break;
  459. }
  460. case IOCTL_CDROM_GET_VOLUME: {
  461. RedBookDCGetVolume(DeviceExtension, data);
  462. break;
  463. }
  464. case IOCTL_CDROM_CHECK_VERIFY:
  465. case IOCTL_DISK_CHECK_VERIFY:
  466. case IOCTL_STORAGE_CHECK_VERIFY:
  467. case IOCTL_STORAGE_CHECK_VERIFY2: {
  468. RedBookDCCheckVerify(DeviceExtension, data);
  469. break;
  470. }
  471. default: {
  472. data->Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  473. data->Irp->IoStatus.Information = 0;
  474. RedBookCompleteIoctl(DeviceExtension, data, TRUE);
  475. break;
  476. }
  477. }
  478. return;
  479. }
  480. ////////////////////////////////////////////////////////////////////////////////
  481. ////////////////////////////////////////////////////////////////////////////////
  482. VOID
  483. RedBookDCCheckVerify(
  484. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  485. PREDBOOK_THREAD_IOCTL_DATA Context
  486. )
  487. /*++
  488. Routine Description:
  489. Arguments:
  490. Return Value:
  491. --*/
  492. {
  493. PIO_STACK_LOCATION currentIrpStack;
  494. ULONG state;
  495. PAGED_CODE();
  496. VerifyCalledByThread(DeviceExtension);
  497. state = GetCdromState(DeviceExtension);
  498. currentIrpStack = IoGetCurrentIrpStackLocation(Context->Irp);
  499. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) { // !handling ioctls
  500. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  501. "DCCheckVerify => not playing\n"));
  502. RedBookCompleteIoctl(DeviceExtension, Context, TRUE);
  503. return;
  504. }
  505. //
  506. // data buffer is optional for this ioctl
  507. //
  508. if (currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength) {
  509. *((PULONG)Context->Irp->AssociatedIrp.SystemBuffer) =
  510. DeviceExtension->CDRom.CheckVerify;
  511. Context->Irp->IoStatus.Information = sizeof(ULONG);
  512. } else {
  513. Context->Irp->IoStatus.Information = 0;
  514. }
  515. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  516. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  517. return;
  518. }
  519. VOID
  520. RedBookDCDefault(
  521. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  522. PREDBOOK_THREAD_IOCTL_DATA Context
  523. )
  524. /*++
  525. Routine Description:
  526. Arguments:
  527. Return Value:
  528. --*/
  529. {
  530. ULONG state;
  531. PAGED_CODE();
  532. VerifyCalledByThread(DeviceExtension);
  533. state = GetCdromState(DeviceExtension);
  534. //
  535. // IOCTLs are not all guaranteed to be called at passive irql,
  536. // so this can never be paged code.
  537. // there is a window of opportunity to send an ioctl while playing
  538. // audio digitally, but it can be ignored. this allows much more
  539. // pagable code.
  540. //
  541. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) { // !handling ioctls
  542. RedBookCompleteIoctl(DeviceExtension, Context, TRUE);
  543. } else {
  544. //
  545. // Complete the Irp
  546. //
  547. Context->Irp->IoStatus.Information = 0;
  548. Context->Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  549. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  550. }
  551. return;
  552. }
  553. VOID
  554. RedBookDCGetVolume(
  555. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  556. PREDBOOK_THREAD_IOCTL_DATA Context
  557. )
  558. /*++
  559. Routine Description:
  560. Arguments:
  561. Return Value:
  562. --*/
  563. {
  564. PIO_STACK_LOCATION currentIrpStack;
  565. NTSTATUS status;
  566. PAGED_CODE();
  567. VerifyCalledByThread(DeviceExtension);
  568. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  569. "DCGetVolume => Entering %p\n", Context->Irp));
  570. //
  571. // guaranteed the volume info will not change
  572. //
  573. RtlCopyMemory(Context->Irp->AssociatedIrp.SystemBuffer, // to
  574. &DeviceExtension->CDRom.Volume, // from
  575. sizeof(VOLUME_CONTROL));
  576. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  577. "DCGetVolume => volume was:"
  578. " (hex) %2x %2x %2x %2x\n",
  579. DeviceExtension->CDRom.Volume.PortVolume[0],
  580. DeviceExtension->CDRom.Volume.PortVolume[1],
  581. DeviceExtension->CDRom.Volume.PortVolume[2],
  582. DeviceExtension->CDRom.Volume.PortVolume[3]));
  583. //
  584. // Complete the Irp (IoStatus.Information set above)
  585. //
  586. Context->Irp->IoStatus.Information = sizeof(VOLUME_CONTROL);
  587. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  588. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  589. return;
  590. }
  591. VOID
  592. RedBookDCPause(
  593. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  594. PREDBOOK_THREAD_IOCTL_DATA Context
  595. )
  596. /*++
  597. Routine Description:
  598. Arguments:
  599. Return Value:
  600. --*/
  601. {
  602. ULONG state;
  603. PAGED_CODE();
  604. VerifyCalledByThread(DeviceExtension);
  605. state = GetCdromState(DeviceExtension);
  606. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  607. "DCPause => Entering %p\n", Context->Irp));
  608. if (!TEST_FLAG(state, CD_PLAYING)) {
  609. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  610. "DCPause => Not playing\n"));
  611. Context->Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  612. Context->Irp->IoStatus.Information = 0;
  613. RedBookCompleteIoctl(DeviceExtension, Context, TRUE);
  614. return;
  615. }
  616. if (TEST_FLAG(state, CD_PAUSED)) {
  617. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  618. "DCPause => Already paused %p\n", Context->Irp));
  619. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  620. Context->Irp->IoStatus.Information = 0;
  621. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  622. return;
  623. } else {
  624. //
  625. // since setting to a temp state, it is not appropriate to
  626. // complete the irp until the operation itself completes.
  627. //
  628. ASSERT(!TEST_FLAG(state, CD_PAUSING));
  629. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  630. "DCPause => Starting pause %p\n", Context->Irp));
  631. DeviceExtension->Thread.IoctlCurrent = &Context->ListEntry;
  632. state = SetCdromState(DeviceExtension, state, state | CD_PAUSING);
  633. return;
  634. }
  635. }
  636. VOID
  637. RedBookDCPlay(
  638. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  639. PREDBOOK_THREAD_IOCTL_DATA Context
  640. )
  641. /*++
  642. Routine Description:
  643. Arguments:
  644. Return Value:
  645. --*/
  646. {
  647. PCDROM_PLAY_AUDIO_MSF inputBuffer;
  648. PIO_STACK_LOCATION thisIrpStack;
  649. PIO_STACK_LOCATION nextIrpStack;
  650. PREVENT_MEDIA_REMOVAL mediaRemoval;
  651. ULONG sector;
  652. ULONG i;
  653. ULONG state;
  654. NTSTATUS status;
  655. PAGED_CODE();
  656. VerifyCalledByThread(DeviceExtension);
  657. inputBuffer = Context->Irp->AssociatedIrp.SystemBuffer;
  658. thisIrpStack = IoGetCurrentIrpStackLocation(Context->Irp);
  659. nextIrpStack = IoGetNextIrpStackLocation(Context->Irp);
  660. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  661. "DCPlay => Entering %p\n", Context->Irp));
  662. status = RedBookCacheToc(DeviceExtension);
  663. if (!NT_SUCCESS(status)) {
  664. Context->Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  665. Context->Irp->IoStatus.Information = 0;
  666. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  667. return;
  668. }
  669. sector = MSF_TO_LBA(inputBuffer->EndingM,
  670. inputBuffer->EndingS,
  671. inputBuffer->EndingF);
  672. DeviceExtension->CDRom.EndPlay = sector;
  673. sector = MSF_TO_LBA(inputBuffer->StartingM,
  674. inputBuffer->StartingS,
  675. inputBuffer->StartingF);
  676. DeviceExtension->CDRom.NextToRead = sector;
  677. DeviceExtension->CDRom.NextToStream = sector;
  678. DeviceExtension->CDRom.FinishedStreaming = sector;
  679. //
  680. // Make sure the ending sector is within disc
  681. // bounds or return STATUS_INVALID_DEVICE_REQUEST?
  682. // this will prevent success on play, followed by an
  683. // immediate stop.
  684. //
  685. if (0) {
  686. PCDROM_TOC toc = DeviceExtension->CDRom.Toc;
  687. LONG track;
  688. LONG endTrack;
  689. //
  690. // ensure end has an lba greater than start
  691. //
  692. if (DeviceExtension->CDRom.EndPlay <=
  693. DeviceExtension->CDRom.NextToRead) {
  694. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  695. "Play => End sector (%x) must be more than start "
  696. "sector (%x)\n",
  697. DeviceExtension->CDRom.EndPlay,
  698. DeviceExtension->CDRom.NextToRead
  699. ));
  700. Context->Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  701. Context->Irp->IoStatus.Information = 0;
  702. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  703. return;
  704. }
  705. //
  706. // what track(s) are we playing?
  707. //
  708. track = WhichTrackContainsThisLBA(toc, DeviceExtension->CDRom.NextToRead);
  709. endTrack = WhichTrackContainsThisLBA(toc, DeviceExtension->CDRom.EndPlay);
  710. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  711. "Play => Playing sector %x to %x (track %x to %x)\n",
  712. DeviceExtension->CDRom.NextToRead,
  713. DeviceExtension->CDRom.EndPlay,
  714. track,
  715. endTrack));
  716. //
  717. // make sure the tracks are actually valid
  718. //
  719. if (track < 0 ||
  720. endTrack < 0 ||
  721. endTrack <= (toc->LastTrack - toc->FirstTrack)
  722. ) {
  723. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  724. "Play => Track %x is invalid\n", track));
  725. Context->Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  726. Context->Irp->IoStatus.Information = 0;
  727. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  728. return;
  729. }
  730. for (;track <= endTrack;track++) {
  731. if (toc->TrackData[track].Adr & AUDIO_DATA_TRACK) {
  732. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  733. "Play => Track %x is not audio\n", track));
  734. Context->Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  735. Context->Irp->IoStatus.Information = 0;
  736. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  737. return;
  738. }
  739. }
  740. }
  741. //
  742. // if not paused, then state must equal stopped, which means we need
  743. // to allocate the resources.
  744. //
  745. state = GetCdromState(DeviceExtension);
  746. if (TEST_FLAG(state, CD_PAUSED)) {
  747. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  748. "DCPlay => Resuming playback?\n"));
  749. } else {
  750. //
  751. // this function will allocate them iff they are not
  752. // already allocated.
  753. //
  754. status = RedBookAllocatePlayResources(DeviceExtension);
  755. if (!NT_SUCCESS(status)) {
  756. Context->Irp->IoStatus.Status = STATUS_NO_MEMORY;
  757. Context->Irp->IoStatus.Information = 0;
  758. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  759. return;
  760. }
  761. }
  762. //
  763. // Set the new device state (thread will begin playing)
  764. //
  765. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  766. "DCPlay => Setting state to CD_PLAYING\n"));
  767. state = SetCdromState(DeviceExtension, state, CD_PLAYING);
  768. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  769. "DCPlay => Exiting successfully\n"));
  770. //
  771. // finish the request if it's a user
  772. // request for a new play operation
  773. //
  774. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  775. Context->Irp->IoStatus.Information = 0;
  776. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  777. return;
  778. }
  779. VOID
  780. RedBookDCReadQ(
  781. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  782. PREDBOOK_THREAD_IOCTL_DATA Context
  783. )
  784. /*++
  785. Routine Description:
  786. Arguments:
  787. Return Value:
  788. --*/
  789. {
  790. PCDROM_SUB_Q_DATA_FORMAT inputBuffer;
  791. PIO_STACK_LOCATION currentIrpStack;
  792. UCHAR formatCode;
  793. ULONG state;
  794. NTSTATUS status;
  795. PAGED_CODE();
  796. VerifyCalledByThread(DeviceExtension);
  797. inputBuffer = Context->Irp->AssociatedIrp.SystemBuffer;
  798. currentIrpStack = IoGetCurrentIrpStackLocation(Context->Irp);
  799. state = GetCdromState(DeviceExtension);
  800. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) { // !handling ioctls
  801. //
  802. // no need to handle this irp
  803. //
  804. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  805. "DCReadQ => Not playing\n"));
  806. RedBookCompleteIoctl(DeviceExtension, Context, TRUE);
  807. return;
  808. }
  809. if (inputBuffer->Format != IOCTL_CDROM_CURRENT_POSITION) {
  810. Context->Irp->IoStatus.Information = 0;
  811. Context->Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  812. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  813. "DCReadQ => Bad Format %x\n", inputBuffer->Format));
  814. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  815. return;
  816. }
  817. //
  818. // we are in the midst of playback or pause. fake the information
  819. // a real cdrom would have returned if it was playing audio at the
  820. // same location that we are currently at.
  821. //
  822. {
  823. PSUB_Q_CURRENT_POSITION outputBuffer;
  824. PCDROM_TOC toc;
  825. ULONG lbaTrack;
  826. ULONG lbaRelative;
  827. ULONG instantLba;
  828. UCHAR timeAbsolute[3];
  829. UCHAR timeRelative[3];
  830. LONG trackNumber;
  831. outputBuffer = Context->Irp->AssociatedIrp.SystemBuffer;
  832. RtlZeroMemory(outputBuffer,
  833. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength);
  834. //
  835. // Still playing audio
  836. //
  837. outputBuffer->Header.Reserved = 0;
  838. if (TEST_FLAG(state, CD_PAUSED)) {
  839. outputBuffer->Header.AudioStatus = AUDIO_STATUS_PAUSED;
  840. } else if (TEST_FLAG(state, CD_PLAYING)) {
  841. outputBuffer->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
  842. } else {
  843. ASSERT(!"State was invalid?");
  844. outputBuffer->Header.AudioStatus = AUDIO_STATUS_IN_PROGRESS;
  845. }
  846. outputBuffer->Header.DataLength[0] =
  847. (sizeof(SUB_Q_CURRENT_POSITION) - sizeof(SUB_Q_HEADER)) >> 8;
  848. outputBuffer->Header.DataLength[1] =
  849. (sizeof(SUB_Q_CURRENT_POSITION) - sizeof(SUB_Q_HEADER)) & 0xFF;
  850. //
  851. // we are in the thread, which alloc's/dealloc's the toc
  852. //
  853. toc = DeviceExtension->CDRom.Toc;
  854. ASSERT(toc);
  855. //
  856. // we return the last played sector as a result per the spec
  857. //
  858. instantLba = DeviceExtension->CDRom.FinishedStreaming;
  859. trackNumber = WhichTrackContainsThisLBA(toc, instantLba);
  860. ASSERT(trackNumber >= 0);
  861. outputBuffer->FormatCode = IOCTL_CDROM_CURRENT_POSITION;
  862. outputBuffer->Control = toc->TrackData[trackNumber].Control;
  863. outputBuffer->ADR = toc->TrackData[trackNumber].Adr;
  864. outputBuffer->TrackNumber = toc->TrackData[trackNumber].TrackNumber;
  865. //
  866. // Get the track's LBA
  867. //
  868. lbaTrack = MSF_TO_LBA(toc->TrackData[trackNumber].Address[1],
  869. toc->TrackData[trackNumber].Address[2],
  870. toc->TrackData[trackNumber].Address[3]);
  871. //
  872. // Get the current play LBA
  873. //
  874. lbaRelative = instantLba;
  875. //
  876. // Subtract the track's LBA to get the relative LBA
  877. //
  878. lbaRelative -= lbaTrack;
  879. //
  880. // Finally convert it back to MSF
  881. //
  882. LBA_TO_MSF(instantLba,
  883. timeAbsolute[0],
  884. timeAbsolute[1],
  885. timeAbsolute[2]);
  886. LBA_TO_RELATIVE_MSF(lbaRelative,
  887. timeRelative[0],
  888. timeRelative[1],
  889. timeRelative[2]);
  890. outputBuffer->IndexNumber = (UCHAR)trackNumber;
  891. outputBuffer->AbsoluteAddress[0] = 0;
  892. outputBuffer->AbsoluteAddress[1] = timeAbsolute[0];
  893. outputBuffer->AbsoluteAddress[2] = timeAbsolute[1];
  894. outputBuffer->AbsoluteAddress[3] = timeAbsolute[2];
  895. outputBuffer->TrackRelativeAddress[0] = 0;
  896. outputBuffer->TrackRelativeAddress[1] = timeRelative[0];
  897. outputBuffer->TrackRelativeAddress[2] = timeRelative[1];
  898. outputBuffer->TrackRelativeAddress[3] = timeRelative[2];
  899. //
  900. // The one line debug info...
  901. //
  902. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctlV, "[redbook] "
  903. "ReadQ => "
  904. "Trk [%#02x] Indx [%#02x] "
  905. "Abs [%#02d:%#02d.%#02d] Rel [%#02d:%#02d.%#02d]\n",
  906. outputBuffer->TrackNumber,
  907. trackNumber,
  908. timeAbsolute[0], timeAbsolute[1], timeAbsolute[2],
  909. timeRelative[0], timeRelative[1], timeRelative[2]));
  910. }
  911. //
  912. // Complete the Irp
  913. //
  914. Context->Irp->IoStatus.Information = sizeof(SUB_Q_CURRENT_POSITION);
  915. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  916. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  917. return;
  918. }
  919. VOID
  920. RedBookDCResume(
  921. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  922. PREDBOOK_THREAD_IOCTL_DATA Context
  923. )
  924. /*++
  925. Routine Description:
  926. Arguments:
  927. Return Value:
  928. --*/
  929. {
  930. ULONG state;
  931. PAGED_CODE();
  932. VerifyCalledByThread(DeviceExtension);
  933. state = GetCdromState(DeviceExtension);
  934. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) { // !handling ioctls
  935. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  936. "DCResume => Not Playing\n"));
  937. RedBookCompleteIoctl(DeviceExtension, Context, TRUE);
  938. return;
  939. }
  940. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  941. "DCResume => Entering\n"));
  942. if (TEST_FLAG(state, CD_PAUSED)) {
  943. //
  944. // we need to start the resume operation
  945. //
  946. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  947. "DCResume => Resuming playback\n"));
  948. state = SetCdromState(DeviceExtension, state, CD_PLAYING);
  949. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  950. "DCResume => Resume succeeded\n"));
  951. } else {
  952. //
  953. // if not paused, return success
  954. //
  955. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  956. "DCResume => Not paused -- succeeded\n"));
  957. }
  958. //
  959. // always complete the Irp
  960. //
  961. Context->Irp->IoStatus.Information = 0;
  962. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  963. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  964. return;
  965. }
  966. VOID
  967. RedBookDCSeek(
  968. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  969. PREDBOOK_THREAD_IOCTL_DATA Context
  970. )
  971. /*++
  972. Routine Description:
  973. same as a IOCTL_CDROM_STOP
  974. Arguments:
  975. Return Value:
  976. --*/
  977. {
  978. NTSTATUS status;
  979. ULONG state;
  980. PAGED_CODE();
  981. VerifyCalledByThread(DeviceExtension);
  982. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  983. "DCSeek => Entering\n"));
  984. state = GetCdromState(DeviceExtension);
  985. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) { // !handling ioctls
  986. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  987. "DCSeek => Not Playing\n"));
  988. Context->Irp->IoStatus.Information = 0;
  989. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  990. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  991. return;
  992. }
  993. //
  994. // stop the stream if currently playing
  995. //
  996. if (TEST_FLAG(state, CD_PAUSED)) {
  997. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  998. "DCSeek => Paused, setting to stopped\n"));
  999. state = SetCdromState(DeviceExtension, state, CD_STOPPED);
  1000. Context->Irp->IoStatus.Information = 0;
  1001. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  1002. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  1003. return;
  1004. }
  1005. //
  1006. // since setting to a temp state, it is not appropriate to
  1007. // complete the irp until the operation itself completes.
  1008. //
  1009. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  1010. "DCSeek => stopping the stream\n"));
  1011. DeviceExtension->Thread.IoctlCurrent = &Context->ListEntry;
  1012. state = SetCdromState(DeviceExtension, state, state | CD_STOPPING);
  1013. return;
  1014. }
  1015. VOID
  1016. RedBookDCSetVolume(
  1017. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  1018. PREDBOOK_THREAD_IOCTL_DATA Context
  1019. )
  1020. /*++
  1021. Routine Description:
  1022. Arguments:
  1023. Return Value:
  1024. --*/
  1025. {
  1026. PIO_STACK_LOCATION currentIrpStack;
  1027. ULONG state;
  1028. NTSTATUS status;
  1029. PAGED_CODE();
  1030. VerifyCalledByThread(DeviceExtension);
  1031. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  1032. "DCSetVolume => Entering\n"));
  1033. //
  1034. // guaranteed the volume info will not change right now
  1035. //
  1036. RtlCopyMemory(&DeviceExtension->CDRom.Volume, // to
  1037. Context->Irp->AssociatedIrp.SystemBuffer, // from
  1038. sizeof(VOLUME_CONTROL));
  1039. state = GetCdromState(DeviceExtension);
  1040. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) { // !handling ioctls
  1041. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  1042. "DCSetVolume => Not Playing\n"));
  1043. RedBookCompleteIoctl(DeviceExtension, Context, TRUE);
  1044. return;
  1045. }
  1046. //
  1047. // not set above since don't have volume control
  1048. //
  1049. RedBookKsSetVolume(DeviceExtension);
  1050. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctlV, "[redbook] "
  1051. "DCSetVolume => volume set to:"
  1052. " (hex) %2x %2x %2x %2x\n",
  1053. DeviceExtension->CDRom.Volume.PortVolume[0],
  1054. DeviceExtension->CDRom.Volume.PortVolume[1],
  1055. DeviceExtension->CDRom.Volume.PortVolume[2],
  1056. DeviceExtension->CDRom.Volume.PortVolume[3]));
  1057. //
  1058. // Complete the Irp (IoStatus.Information set above)
  1059. //
  1060. Context->Irp->IoStatus.Information = 0;
  1061. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  1062. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  1063. return;
  1064. }
  1065. VOID
  1066. RedBookDCStop(
  1067. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  1068. PREDBOOK_THREAD_IOCTL_DATA Context
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. Arguments:
  1073. Return Value:
  1074. --*/
  1075. {
  1076. NTSTATUS status;
  1077. ULONG state;
  1078. PAGED_CODE();
  1079. VerifyCalledByThread(DeviceExtension);
  1080. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  1081. "DCStop => Entering %p\n", Context->Irp));
  1082. state = GetCdromState(DeviceExtension);
  1083. if (!TEST_FLAG(state, CD_PLAYING) && !TEST_FLAG(state, CD_PAUSED)) { // !handling ioctls
  1084. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  1085. "DCStop => Stop when already stopped\n"));
  1086. Context->Irp->IoStatus.Information = 0;
  1087. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  1088. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  1089. return;
  1090. }
  1091. //
  1092. // Still playing audio. if paused, just call the stop finish routine
  1093. //
  1094. if (TEST_FLAG(state, CD_PAUSED)) {
  1095. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  1096. "DCStop => Stop when paused\n"));
  1097. state = SetCdromState(DeviceExtension, state, CD_STOPPED);
  1098. Context->Irp->IoStatus.Information = 0;
  1099. Context->Irp->IoStatus.Status = STATUS_SUCCESS;
  1100. RedBookCompleteIoctl(DeviceExtension, Context, FALSE);
  1101. return;
  1102. }
  1103. //
  1104. // since setting to a temp state, it is not appropriate to
  1105. // complete the irp until the operation itself completes.
  1106. //
  1107. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugIoctl, "[redbook] "
  1108. "DCStop => stopping the stream\n"));
  1109. DeviceExtension->Thread.IoctlCurrent = &Context->ListEntry;
  1110. state = SetCdromState(DeviceExtension, state, state | CD_STOPPING);
  1111. return;
  1112. }
  1113. ////////////////////////////////////////////////////////////////////////////////
  1114. VOID
  1115. RedBookCheckForDiscChangeAndFreeResources(
  1116. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  1117. )
  1118. //
  1119. // if we've paused, and the disc has changed, don't
  1120. // want to be returning stale toc info when the player
  1121. // resumes playback.
  1122. //
  1123. {
  1124. PIRP irp;
  1125. PIO_STACK_LOCATION irpStack;
  1126. PULONG count;
  1127. ULONG state;
  1128. PAGED_CODE();
  1129. VerifyCalledByThread(DeviceExtension);
  1130. //
  1131. // only do this if we are in a PAUSED or STOPPED state
  1132. //
  1133. state = GetCdromState(DeviceExtension);
  1134. if ((!TEST_FLAG(state, CD_STOPPED)) &&
  1135. (!TEST_FLAG(state, CD_PAUSED))) {
  1136. return;
  1137. }
  1138. //
  1139. // resources might already be deallocated.
  1140. //
  1141. irp = DeviceExtension->Thread.CheckVerifyIrp;
  1142. if (irp == NULL) {
  1143. return;
  1144. }
  1145. irpStack = IoGetCurrentIrpStackLocation(irp);
  1146. #if DBG
  1147. {
  1148. //
  1149. // the irp must be setup when it's allocated. we rely on this.
  1150. //
  1151. ASSERT(irpStack->Parameters.DeviceIoControl.InputBufferLength == 0);
  1152. ASSERT(irpStack->Parameters.DeviceIoControl.OutputBufferLength ==
  1153. sizeof(ULONG));
  1154. ASSERT(irpStack->Parameters.DeviceIoControl.IoControlCode ==
  1155. IOCTL_CDROM_CHECK_VERIFY);
  1156. ASSERT(irpStack->Parameters.DeviceIoControl.Type3InputBuffer == NULL);
  1157. ASSERT(irp->AssociatedIrp.SystemBuffer != NULL);
  1158. }
  1159. #endif
  1160. count = (PULONG)(irp->AssociatedIrp.SystemBuffer);
  1161. *count = 0;
  1162. RedBookForwardIrpSynchronous(DeviceExtension, irp);
  1163. if (!NT_SUCCESS(irp->IoStatus.Status) ||
  1164. ((*count) != DeviceExtension->CDRom.CheckVerify)
  1165. ) {
  1166. //
  1167. // if the count has changed set the state to STOPPED.
  1168. // (old state is either STOPPED or PAUSED, so either one can
  1169. // seemlessly transition to the STOPPED state without any
  1170. // trouble.)
  1171. //
  1172. // also free currently held play resources
  1173. //
  1174. state = SetCdromState(DeviceExtension, state, CD_STOPPED);
  1175. RedBookDeallocatePlayResources(DeviceExtension);
  1176. }
  1177. return;
  1178. }
  1179. ULONG
  1180. WhichTrackContainsThisLBA(
  1181. PCDROM_TOC Toc,
  1182. ULONG Lba
  1183. )
  1184. //
  1185. // returns -1 if not found
  1186. //
  1187. {
  1188. LONG trackNumber;
  1189. UCHAR msf[3];
  1190. PAGED_CODE();
  1191. LBA_TO_MSF(Lba, msf[0], msf[1], msf[2]);
  1192. for (trackNumber = Toc->LastTrack - Toc->FirstTrack;
  1193. trackNumber >= 0;
  1194. trackNumber-- ) {
  1195. //
  1196. // we have found the track if
  1197. // Minutes is less or
  1198. // Minutes is equal and Seconds is less or
  1199. // Minutes and Seconds are equal Frame is less or
  1200. // Minutes, Seconds, and Frame are equal
  1201. //
  1202. // the compiler optimizes this nicely.
  1203. //
  1204. if (Toc->TrackData[trackNumber].Address[1] < msf[0] ) {
  1205. break;
  1206. } else
  1207. if (Toc->TrackData[trackNumber].Address[1] == msf[0] &&
  1208. Toc->TrackData[trackNumber].Address[2] < msf[1] ) {
  1209. break;
  1210. } else
  1211. if (Toc->TrackData[trackNumber].Address[1] == msf[0] &&
  1212. Toc->TrackData[trackNumber].Address[2] == msf[1] &&
  1213. Toc->TrackData[trackNumber].Address[3] < msf[2] ) {
  1214. break;
  1215. } else
  1216. if (Toc->TrackData[trackNumber].Address[1] == msf[0] &&
  1217. Toc->TrackData[trackNumber].Address[2] == msf[1] &&
  1218. Toc->TrackData[trackNumber].Address[3] == msf[2] ) {
  1219. break;
  1220. }
  1221. }
  1222. return trackNumber;
  1223. }