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.

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