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.

3606 lines
99 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. DevIoSup.c
  5. Abstract:
  6. This module implements the low lever disk read/write support for Cdfs.
  7. // @@BEGIN_DDKSPLIT
  8. Author:
  9. Brian Andrew [BrianAn] 01-July-1995
  10. Revision History:
  11. // @@END_DDKSPLIT
  12. --*/
  13. #include "CdProcs.h"
  14. //
  15. // The Bug check file id for this module
  16. //
  17. #define BugCheckFileId (CDFS_BUG_CHECK_DEVIOSUP)
  18. //
  19. // Local structure definitions
  20. //
  21. //
  22. // An array of these structures is passed to CdMultipleAsync describing
  23. // a set of runs to execute in parallel.
  24. //
  25. typedef struct _IO_RUN {
  26. //
  27. // Disk offset to read from and number of bytes to read. These
  28. // must be a multiple of 2048 and the disk offset is also a
  29. // multiple of 2048.
  30. //
  31. LONGLONG DiskOffset;
  32. ULONG DiskByteCount;
  33. //
  34. // Current position in user buffer. This is the final destination for
  35. // this portion of the Io transfer.
  36. //
  37. PVOID UserBuffer;
  38. //
  39. // Buffer to perform the transfer to. If this is the same as the
  40. // user buffer above then we are using the user's buffer. Otherwise
  41. // we either allocated a temporary buffer or are using a different portion
  42. // of the user's buffer.
  43. //
  44. // TransferBuffer - Read full sectors into this location. This can
  45. // be a pointer into the user's buffer at the exact location the
  46. // data should go. It can also be an earlier point in the user's
  47. // buffer if the complete I/O doesn't start on a sector boundary.
  48. // It may also be a pointer into an allocated buffer.
  49. //
  50. // TransferByteCount - Count of bytes to transfer to user's buffer. A
  51. // value of zero indicates that we did do the transfer into the
  52. // user's buffer directly.
  53. //
  54. // TransferBufferOffset - Offset in this buffer to begin the transfer
  55. // to the user's buffer.
  56. //
  57. PVOID TransferBuffer;
  58. ULONG TransferByteCount;
  59. ULONG TransferBufferOffset;
  60. //
  61. // This is the Mdl describing the locked pages in memory. It may
  62. // be allocated to describe the allocated buffer. Or it may be
  63. // the Mdl in the originating Irp. The MdlOffset is the offset of
  64. // the current buffer from the beginning of the buffer described by
  65. // the Mdl below. If the TransferMdl is not the same as the Mdl
  66. // in the user's Irp then we know we have allocated it.
  67. //
  68. PMDL TransferMdl;
  69. PVOID TransferVirtualAddress;
  70. //
  71. // Associated Irp used to perform the Io.
  72. //
  73. PIRP SavedIrp;
  74. } IO_RUN;
  75. typedef IO_RUN *PIO_RUN;
  76. #define MAX_PARALLEL_IOS 5
  77. //
  78. // Local support routines
  79. //
  80. BOOLEAN
  81. CdPrepareBuffers (
  82. IN PIRP_CONTEXT IrpContext,
  83. IN PIRP Irp,
  84. IN PFCB Fcb,
  85. IN PVOID UserBuffer,
  86. IN ULONG UserBufferOffset,
  87. IN LONGLONG StartingOffset,
  88. IN ULONG ByteCount,
  89. IN PIO_RUN IoRuns,
  90. IN PULONG RunCount,
  91. IN PULONG ThisByteCount
  92. );
  93. VOID
  94. CdPrepareXABuffers (
  95. IN PIRP_CONTEXT IrpContext,
  96. IN PIRP Irp,
  97. IN PFCB Fcb,
  98. IN PVOID UserBuffer,
  99. IN ULONG UserBufferOffset,
  100. IN LONGLONG StartingOffset,
  101. IN ULONG ByteCount,
  102. IN PIO_RUN IoRuns,
  103. IN PULONG RunCount,
  104. IN PULONG ThisByteCount
  105. );
  106. BOOLEAN
  107. CdFinishBuffers (
  108. IN PIRP_CONTEXT IrpContext,
  109. IN PIO_RUN IoRuns,
  110. IN ULONG RunCount,
  111. IN BOOLEAN FinalCleanup,
  112. IN BOOLEAN SaveXABuffer
  113. );
  114. VOID
  115. CdMultipleAsync (
  116. IN PIRP_CONTEXT IrpContext,
  117. IN ULONG RunCount,
  118. IN PIO_RUN IoRuns
  119. );
  120. VOID
  121. CdMultipleXAAsync (
  122. IN PIRP_CONTEXT IrpContext,
  123. IN ULONG RunCount,
  124. IN PIO_RUN IoRuns,
  125. IN PRAW_READ_INFO RawReads,
  126. IN TRACK_MODE_TYPE TrackMode
  127. );
  128. VOID
  129. CdSingleAsync (
  130. IN PIRP_CONTEXT IrpContext,
  131. IN LONGLONG ByteOffset,
  132. IN ULONG ByteCount
  133. );
  134. VOID
  135. CdWaitSync (
  136. IN PIRP_CONTEXT IrpContext
  137. );
  138. NTSTATUS
  139. CdMultiSyncCompletionRoutine (
  140. IN PDEVICE_OBJECT DeviceObject,
  141. IN PIRP Irp,
  142. IN PVOID Context
  143. );
  144. NTSTATUS
  145. CdMultiAsyncCompletionRoutine (
  146. IN PDEVICE_OBJECT DeviceObject,
  147. IN PIRP Irp,
  148. IN PVOID Context
  149. );
  150. NTSTATUS
  151. CdSingleSyncCompletionRoutine (
  152. IN PDEVICE_OBJECT DeviceObject,
  153. IN PIRP Irp,
  154. IN PVOID Context
  155. );
  156. NTSTATUS
  157. CdSingleAsyncCompletionRoutine (
  158. IN PDEVICE_OBJECT DeviceObject,
  159. IN PIRP Irp,
  160. IN PVOID Context
  161. );
  162. VOID
  163. CdReadAudioSystemFile (
  164. IN PIRP_CONTEXT IrpContext,
  165. IN PFCB Fcb,
  166. IN LONGLONG StartingOffset,
  167. IN ULONG ByteCount,
  168. IN PVOID SystemBuffer
  169. );
  170. #ifdef ALLOC_PRAGMA
  171. #pragma alloc_text(PAGE, CdCreateUserMdl)
  172. #pragma alloc_text(PAGE, CdMultipleAsync)
  173. #pragma alloc_text(PAGE, CdMultipleXAAsync)
  174. #pragma alloc_text(PAGE, CdNonCachedRead)
  175. #pragma alloc_text(PAGE, CdNonCachedXARead)
  176. #pragma alloc_text(PAGE, CdFinishBuffers)
  177. #pragma alloc_text(PAGE, CdPerformDevIoCtrl)
  178. #pragma alloc_text(PAGE, CdPrepareBuffers)
  179. #pragma alloc_text(PAGE, CdReadAudioSystemFile)
  180. #pragma alloc_text(PAGE, CdReadSectors)
  181. #pragma alloc_text(PAGE, CdSingleAsync)
  182. #pragma alloc_text(PAGE, CdWaitSync)
  183. #endif
  184. __inline
  185. TRACK_MODE_TYPE
  186. CdFileTrackMode (
  187. IN PFCB Fcb
  188. )
  189. /*++
  190. Routine Description:
  191. This routine converts FCB XA file type flags to the track mode
  192. used by the device drivers.
  193. Arguments:
  194. Fcb - Fcb representing the file to read.
  195. Return Value:
  196. TrackMode of the file represented by the Fcb.
  197. --*/
  198. {
  199. ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE |
  200. FCB_STATE_MODE2_FILE |
  201. FCB_STATE_DA_FILE ));
  202. if (FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) {
  203. return XAForm2;
  204. } else if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) {
  205. return CDDA;
  206. }
  207. //
  208. // FCB_STATE_MODE2_FILE
  209. //
  210. return YellowMode2;
  211. }
  212. NTSTATUS
  213. CdNonCachedRead (
  214. IN PIRP_CONTEXT IrpContext,
  215. IN PFCB Fcb,
  216. IN LONGLONG StartingOffset,
  217. IN ULONG ByteCount
  218. )
  219. /*++
  220. Routine Description:
  221. This routine performs the non-cached reads to 'cooked' sectors (2048 bytes
  222. per sector). This is done by performing the following in a loop.
  223. Fill in the IoRuns array for the next block of Io.
  224. Send the Io to the device.
  225. Perform any cleanup on the Io runs array.
  226. We will not do async Io to any request that generates non-aligned Io.
  227. Also we will not perform async Io if it will exceed the size of our
  228. IoRuns array. These should be the unusual cases but we will raise
  229. or return CANT_WAIT in this routine if we detect this case.
  230. Arguments:
  231. Fcb - Fcb representing the file to read.
  232. StartingOffset - Logical offset in the file to read from.
  233. ByteCount - Number of bytes to read.
  234. Return Value:
  235. NTSTATUS - Status indicating the result of the operation.
  236. --*/
  237. {
  238. NTSTATUS Status = STATUS_SUCCESS;
  239. IO_RUN IoRuns[MAX_PARALLEL_IOS];
  240. ULONG RunCount = 0;
  241. ULONG CleanupRunCount = 0;
  242. PVOID UserBuffer;
  243. ULONG UserBufferOffset = 0;
  244. LONGLONG CurrentOffset = StartingOffset;
  245. ULONG RemainingByteCount = ByteCount;
  246. ULONG ThisByteCount;
  247. BOOLEAN Unaligned;
  248. BOOLEAN FlushIoBuffers = FALSE;
  249. BOOLEAN FirstPass = TRUE;
  250. PAGED_CODE();
  251. //
  252. // We want to make sure the user's buffer is locked in all cases.
  253. //
  254. if (IrpContext->Irp->MdlAddress == NULL) {
  255. CdCreateUserMdl( IrpContext, ByteCount, TRUE );
  256. }
  257. CdMapUserBuffer( IrpContext, &UserBuffer);
  258. //
  259. // Special case the root directory and path table for a music volume.
  260. //
  261. if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK ) &&
  262. ((SafeNodeType( Fcb ) == CDFS_NTC_FCB_INDEX) ||
  263. (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE))) {
  264. CdReadAudioSystemFile( IrpContext,
  265. Fcb,
  266. StartingOffset,
  267. ByteCount,
  268. UserBuffer );
  269. return STATUS_SUCCESS;
  270. }
  271. //
  272. // Use a try-finally to perform the final cleanup.
  273. //
  274. try {
  275. //
  276. // Loop while there are more bytes to transfer.
  277. //
  278. do {
  279. //
  280. // Call prepare buffers to set up the next entries
  281. // in the IoRuns array. Remember if there are any
  282. // unaligned entries. This routine will raise CANT_WAIT
  283. // if there are unaligned entries for an async request.
  284. //
  285. RtlZeroMemory( IoRuns, sizeof( IoRuns ));
  286. Unaligned = CdPrepareBuffers( IrpContext,
  287. IrpContext->Irp,
  288. Fcb,
  289. UserBuffer,
  290. UserBufferOffset,
  291. CurrentOffset,
  292. RemainingByteCount,
  293. IoRuns,
  294. &CleanupRunCount,
  295. &ThisByteCount );
  296. RunCount = CleanupRunCount;
  297. //
  298. // If this is an async request and there aren't enough entries
  299. // in the Io array then post the request.
  300. //
  301. if ((ThisByteCount < RemainingByteCount) &&
  302. !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  303. CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  304. }
  305. //
  306. // If the entire Io is contained in a single run then
  307. // we can pass the Io down to the driver. Send the driver down
  308. // and wait on the result if this is synchronous.
  309. //
  310. if ((RunCount == 1) && !Unaligned && FirstPass) {
  311. CdSingleAsync( IrpContext,
  312. IoRuns[0].DiskOffset,
  313. IoRuns[0].DiskByteCount );
  314. //
  315. // No cleanup needed for the IoRuns array here.
  316. //
  317. CleanupRunCount = 0;
  318. //
  319. // Wait if we are synchronous, otherwise return
  320. //
  321. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  322. CdWaitSync( IrpContext );
  323. Status = IrpContext->Irp->IoStatus.Status;
  324. //
  325. // Our completion routine will free the Io context but
  326. // we do want to return STATUS_PENDING.
  327. //
  328. } else {
  329. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
  330. Status = STATUS_PENDING;
  331. }
  332. try_return( NOTHING );
  333. }
  334. //
  335. // Otherwise we will perform multiple Io to read in the data.
  336. //
  337. CdMultipleAsync( IrpContext, RunCount, IoRuns );
  338. //
  339. // If this is a synchronous request then perform any necessary
  340. // post-processing.
  341. //
  342. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  343. //
  344. // Wait for the request to complete.
  345. //
  346. CdWaitSync( IrpContext );
  347. Status = IrpContext->Irp->IoStatus.Status;
  348. //
  349. // Exit this loop if there is an error.
  350. //
  351. if (!NT_SUCCESS( Status )) {
  352. try_return( NOTHING );
  353. }
  354. //
  355. // Perform post read operations on the IoRuns if
  356. // necessary.
  357. //
  358. if (Unaligned &&
  359. CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, FALSE )) {
  360. FlushIoBuffers = TRUE;
  361. }
  362. CleanupRunCount = 0;
  363. //
  364. // Exit this loop if there are no more bytes to transfer
  365. // or we have any error.
  366. //
  367. RemainingByteCount -= ThisByteCount;
  368. CurrentOffset += ThisByteCount;
  369. UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
  370. UserBufferOffset += ThisByteCount;
  371. //
  372. // Otherwise this is an asynchronous request. Always return
  373. // STATUS_PENDING.
  374. //
  375. } else {
  376. ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
  377. CleanupRunCount = 0;
  378. try_return( Status = STATUS_PENDING );
  379. break;
  380. }
  381. FirstPass = FALSE;
  382. } while (RemainingByteCount != 0);
  383. //
  384. // Flush the hardware cache if we performed any copy operations.
  385. //
  386. if (FlushIoBuffers) {
  387. KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
  388. }
  389. try_exit: NOTHING;
  390. } finally {
  391. //
  392. // Perform final cleanup on the IoRuns if necessary.
  393. //
  394. if (CleanupRunCount != 0) {
  395. CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
  396. }
  397. }
  398. return Status;
  399. }
  400. NTSTATUS
  401. CdNonCachedXARead (
  402. IN PIRP_CONTEXT IrpContext,
  403. IN PFCB Fcb,
  404. IN LONGLONG StartingOffset,
  405. IN ULONG ByteCount
  406. )
  407. /*++
  408. Routine Description:
  409. This routine performs the non-cached reads for 'raw' sectors (2352 bytes
  410. per sector). We also prepend a hard-coded RIFF header of 44 bytes to the file.
  411. All of this is already reflected in the file size.
  412. We start by checking whether to prepend any portion of the RIFF header. Then we check
  413. if the last raw sector read was from the beginning portion of this file, deallocating
  414. that buffer if necessary. Finally we do the following in a loop.
  415. Fill the IoRuns array for the next block of Io.
  416. Send the Io to the device driver.
  417. Perform any cleanup necessary on the IoRuns array.
  418. We will not do any async request in this path. The request would have been
  419. posted to a worker thread before getting to this point.
  420. Arguments:
  421. Fcb - Fcb representing the file to read.
  422. StartingOffset - Logical offset in the file to read from.
  423. ByteCount - Number of bytes to read.
  424. Return Value:
  425. NTSTATUS - Status indicating the result of the operation.
  426. --*/
  427. {
  428. NTSTATUS Status = STATUS_SUCCESS;
  429. RIFF_HEADER LocalRiffHeader;
  430. PRIFF_HEADER RiffHeader;
  431. RAW_READ_INFO RawReads[MAX_PARALLEL_IOS];
  432. IO_RUN IoRuns[MAX_PARALLEL_IOS];
  433. ULONG RunCount = 0;
  434. ULONG CleanupRunCount = 0;
  435. PVOID UserBuffer;
  436. ULONG UserBufferOffset = 0;
  437. LONGLONG CurrentOffset = StartingOffset;
  438. ULONG RemainingByteCount = ByteCount;
  439. ULONG ThisByteCount;
  440. BOOLEAN TryingYellowbookMode2 = FALSE;
  441. TRACK_MODE_TYPE TrackMode;
  442. PAGED_CODE();
  443. //
  444. // We want to make sure the user's buffer is locked in all cases.
  445. //
  446. if (IrpContext->Irp->MdlAddress == NULL) {
  447. CdCreateUserMdl( IrpContext, ByteCount, TRUE );
  448. }
  449. //
  450. // The byte count was rounded up to a logical sector boundary. It has
  451. // nothing to do with the raw sectors on disk. Limit the remaining
  452. // byte count to file size.
  453. //
  454. if (CurrentOffset + RemainingByteCount > Fcb->FileSize.QuadPart) {
  455. RemainingByteCount = (ULONG) (Fcb->FileSize.QuadPart - CurrentOffset);
  456. }
  457. CdMapUserBuffer( IrpContext, &UserBuffer);
  458. //
  459. // Use a try-finally to perform the final cleanup.
  460. //
  461. try {
  462. //
  463. // If the initial offset lies within the RIFF header then copy the
  464. // necessary bytes to the user's buffer.
  465. //
  466. if (CurrentOffset < sizeof( RIFF_HEADER )) {
  467. //
  468. // Copy the appropriate RIFF header.
  469. //
  470. if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) {
  471. //
  472. // Create the pseudo entries for a music disk.
  473. //
  474. if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
  475. PAUDIO_PLAY_HEADER AudioPlayHeader;
  476. PTRACK_DATA TrackData;
  477. ULONG SectorCount;
  478. AudioPlayHeader = (PAUDIO_PLAY_HEADER) &LocalRiffHeader;
  479. TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber];
  480. //
  481. // Copy the data header into our local buffer.
  482. //
  483. RtlCopyMemory( AudioPlayHeader,
  484. CdAudioPlayHeader,
  485. sizeof( AUDIO_PLAY_HEADER ));
  486. //
  487. // Copy the serial number into the Id field. Also
  488. // the track number in the TOC.
  489. //
  490. AudioPlayHeader->DiskID = Fcb->Vcb->Vpb->SerialNumber;
  491. AudioPlayHeader->TrackNumber = TrackData->TrackNumber;
  492. //
  493. // TOC contains MSF (Minute/Second/Frame) addresses. This is very
  494. // arcane, and we wind up having to bias around by the size of the
  495. // leadins and other such silliness to find real live sector addrs.
  496. //
  497. // One frame == One sector.
  498. // One second == 75 frames (winds up being a 44.1khz sample)
  499. //
  500. //
  501. // Fill in the address and length fields.
  502. //
  503. AudioPlayHeader->TrackAddress[2] = TrackData->Address[1];
  504. AudioPlayHeader->TrackAddress[1] = TrackData->Address[2];
  505. AudioPlayHeader->TrackAddress[0] = TrackData->Address[3];
  506. AudioPlayHeader->StartingSector = TrackData->Address[3];
  507. AudioPlayHeader->StartingSector += (TrackData->Address[2] * 75);
  508. AudioPlayHeader->StartingSector += (TrackData->Address[1] * 60 * 75);
  509. //
  510. // Subtract 2 seconds for the block number.
  511. //
  512. AudioPlayHeader->StartingSector -= 150;
  513. //
  514. // Go to the next track and find the starting point.
  515. //
  516. TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber + 1];
  517. AudioPlayHeader->SectorCount = TrackData->Address[3];
  518. AudioPlayHeader->SectorCount += (TrackData->Address[2] * 75);
  519. AudioPlayHeader->SectorCount += (TrackData->Address[1] * 60 * 75);
  520. //
  521. // Bias the sector count by 2 seconds.
  522. // Check that the offset is at least two seconds.
  523. //
  524. if (AudioPlayHeader->SectorCount < 150) {
  525. AudioPlayHeader->SectorCount = 0;
  526. } else {
  527. AudioPlayHeader->SectorCount -= 150;
  528. }
  529. //
  530. // Now compute the difference. If there is an error then use
  531. // a length of zero.
  532. //
  533. if (AudioPlayHeader->SectorCount < AudioPlayHeader->StartingSector) {
  534. AudioPlayHeader->SectorCount = 0;
  535. } else {
  536. AudioPlayHeader->SectorCount -= AudioPlayHeader->StartingSector;
  537. }
  538. //
  539. // Use the sector count to determine the MSF length.
  540. //
  541. SectorCount = AudioPlayHeader->SectorCount;
  542. AudioPlayHeader->TrackLength[0] = (UCHAR) (SectorCount % 75);
  543. SectorCount /= 75;
  544. AudioPlayHeader->TrackLength[1] = (UCHAR) (SectorCount % 60);
  545. SectorCount /= 60;
  546. AudioPlayHeader->TrackLength[2] = (UCHAR) (SectorCount % 60);
  547. ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
  548. RtlCopyMemory( UserBuffer,
  549. Add2Ptr( AudioPlayHeader,
  550. sizeof( RIFF_HEADER ) - ThisByteCount,
  551. PCHAR ),
  552. ThisByteCount );
  553. //
  554. // CD-XA CDDA
  555. //
  556. } else {
  557. //
  558. // The WAVE header format is actually much closer to an audio play
  559. // header in format but we only need to modify the filesize fields.
  560. //
  561. RiffHeader = &LocalRiffHeader;
  562. //
  563. // Copy the data header into our local buffer and add the file size to it.
  564. //
  565. RtlCopyMemory( RiffHeader,
  566. CdXAAudioPhileHeader,
  567. sizeof( RIFF_HEADER ));
  568. RiffHeader->ChunkSize += Fcb->FileSize.LowPart;
  569. RiffHeader->RawSectors += Fcb->FileSize.LowPart;
  570. ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
  571. RtlCopyMemory( UserBuffer,
  572. Add2Ptr( RiffHeader,
  573. sizeof( RIFF_HEADER ) - ThisByteCount,
  574. PCHAR ),
  575. ThisByteCount );
  576. }
  577. //
  578. // CD-XA non-audio
  579. //
  580. } else {
  581. ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2_FILE | FCB_STATE_MODE2FORM2_FILE ));
  582. RiffHeader = &LocalRiffHeader;
  583. //
  584. // Copy the data header into our local buffer and add the file size to it.
  585. //
  586. RtlCopyMemory( RiffHeader,
  587. CdXAFileHeader,
  588. sizeof( RIFF_HEADER ));
  589. RiffHeader->ChunkSize += Fcb->FileSize.LowPart;
  590. RiffHeader->RawSectors += Fcb->FileSize.LowPart;
  591. RiffHeader->Attributes = (USHORT) Fcb->XAAttributes;
  592. RiffHeader->FileNumber = (UCHAR) Fcb->XAFileNumber;
  593. ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
  594. RtlCopyMemory( UserBuffer,
  595. Add2Ptr( RiffHeader,
  596. sizeof( RIFF_HEADER ) - ThisByteCount,
  597. PCHAR ),
  598. ThisByteCount );
  599. }
  600. //
  601. // Adjust the starting offset and byte count to reflect that
  602. // we copied over the RIFF bytes.
  603. //
  604. UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
  605. UserBufferOffset += ThisByteCount;
  606. CurrentOffset += ThisByteCount;
  607. RemainingByteCount -= ThisByteCount;
  608. }
  609. //
  610. // Set up the appropriate trackmode
  611. //
  612. TrackMode = CdFileTrackMode(Fcb);
  613. //
  614. // Loop while there are more bytes to transfer.
  615. //
  616. while (RemainingByteCount != 0) {
  617. //
  618. // Call prepare buffers to set up the next entries
  619. // in the IoRuns array. Remember if there are any
  620. // unaligned entries. If we're just retrying the previous
  621. // runs with a different track mode, then don't do anything here.
  622. //
  623. if (!TryingYellowbookMode2) {
  624. RtlZeroMemory( IoRuns, sizeof( IoRuns ));
  625. RtlZeroMemory( RawReads, sizeof( RawReads ));
  626. CdPrepareXABuffers( IrpContext,
  627. IrpContext->Irp,
  628. Fcb,
  629. UserBuffer,
  630. UserBufferOffset,
  631. CurrentOffset,
  632. RemainingByteCount,
  633. IoRuns,
  634. &CleanupRunCount,
  635. &ThisByteCount );
  636. }
  637. //
  638. // Perform multiple Io to read in the data. Note that
  639. // there may be no Io to do if we were able to use an
  640. // existing buffer from the Vcb.
  641. //
  642. if (CleanupRunCount != 0) {
  643. RunCount = CleanupRunCount;
  644. CdMultipleXAAsync( IrpContext,
  645. RunCount,
  646. IoRuns,
  647. RawReads,
  648. TrackMode );
  649. //
  650. // Wait for the request to complete.
  651. //
  652. CdWaitSync( IrpContext );
  653. Status = IrpContext->Irp->IoStatus.Status;
  654. //
  655. // Exit this loop if there is an error.
  656. //
  657. if (!NT_SUCCESS( Status )) {
  658. if (!TryingYellowbookMode2 &&
  659. FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) {
  660. //
  661. // There are wacky cases where someone has mastered as CD-XA
  662. // but the sectors they claim are Mode2Form2 are really, according
  663. // to ATAPI devices, Yellowbook Mode2. We will try once more
  664. // with these. Kodak PHOTO-CD has been observed to do this.
  665. //
  666. TryingYellowbookMode2 = TRUE;
  667. TrackMode = YellowMode2;
  668. //
  669. // Clear our 'cumulative' error status value
  670. //
  671. IrpContext->IoContext->Status = STATUS_SUCCESS;
  672. continue;
  673. }
  674. try_return( NOTHING );
  675. }
  676. CleanupRunCount = 0;
  677. if (TryingYellowbookMode2) {
  678. //
  679. // We succesfully got data when we tried switching the trackmode,
  680. // so change the state of the FCB to remember that.
  681. //
  682. SetFlag( Fcb->FcbState, FCB_STATE_MODE2_FILE );
  683. ClearFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE );
  684. TryingYellowbookMode2 = FALSE;
  685. }
  686. //
  687. // Perform post read operations on the IoRuns if
  688. // necessary.
  689. //
  690. CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, TRUE );
  691. }
  692. //
  693. // Adjust our loop variants.
  694. //
  695. RemainingByteCount -= ThisByteCount;
  696. CurrentOffset += ThisByteCount;
  697. UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
  698. UserBufferOffset += ThisByteCount;
  699. }
  700. //
  701. // Always flush the hardware cache.
  702. //
  703. KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
  704. try_exit: NOTHING;
  705. } finally {
  706. //
  707. // Perform final cleanup on the IoRuns if necessary.
  708. //
  709. if (CleanupRunCount != 0) {
  710. CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
  711. }
  712. }
  713. return Status;
  714. }
  715. BOOLEAN
  716. CdReadSectors (
  717. IN PIRP_CONTEXT IrpContext,
  718. IN LONGLONG StartingOffset,
  719. IN ULONG ByteCount,
  720. IN BOOLEAN ReturnError,
  721. IN OUT PVOID Buffer,
  722. IN PDEVICE_OBJECT TargetDeviceObject
  723. )
  724. /*++
  725. Routine Description:
  726. This routine is called to transfer sectors from the disk to a
  727. specified buffer. It is used for mount and volume verify operations.
  728. This routine is synchronous, it will not return until the operation
  729. is complete or until the operation fails.
  730. The routine allocates an IRP and then passes this IRP to a lower
  731. level driver. Errors may occur in the allocation of this IRP or
  732. in the operation of the lower driver.
  733. Arguments:
  734. StartingOffset - Logical offset on the disk to start the read. This
  735. must be on a sector boundary, no check is made here.
  736. ByteCount - Number of bytes to read. This is an integral number of
  737. 2K sectors, no check is made here to confirm this.
  738. ReturnError - Indicates whether we should return TRUE or FALSE
  739. to indicate an error or raise an error condition. This only applies
  740. to the result of the IO. Any other error may cause a raise.
  741. Buffer - Buffer to transfer the disk data into.
  742. TargetDeviceObject - The device object for the volume to be read.
  743. Return Value:
  744. BOOLEAN - Depending on 'RaiseOnError' flag above. TRUE if operation
  745. succeeded, FALSE otherwise.
  746. --*/
  747. {
  748. NTSTATUS Status;
  749. KEVENT Event;
  750. PIRP Irp;
  751. PAGED_CODE();
  752. //
  753. // Initialize the event.
  754. //
  755. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  756. //
  757. // Attempt to allocate the IRP. If unsuccessful, raise
  758. // STATUS_INSUFFICIENT_RESOURCES.
  759. //
  760. Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
  761. TargetDeviceObject,
  762. Buffer,
  763. ByteCount,
  764. (PLARGE_INTEGER) &StartingOffset,
  765. &Event,
  766. &IrpContext->Irp->IoStatus );
  767. if (Irp == NULL) {
  768. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  769. }
  770. //
  771. // Ignore the change line (verify) for mount and verify requests
  772. //
  773. SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  774. //
  775. // Send the request down to the driver. If an error occurs return
  776. // it to the caller.
  777. //
  778. Status = IoCallDriver( TargetDeviceObject, Irp );
  779. //
  780. // If the status was STATUS_PENDING then wait on the event.
  781. //
  782. if (Status == STATUS_PENDING) {
  783. Status = KeWaitForSingleObject( &Event,
  784. Executive,
  785. KernelMode,
  786. FALSE,
  787. NULL );
  788. //
  789. // On a successful wait pull the status out of the IoStatus block.
  790. //
  791. if (NT_SUCCESS( Status )) {
  792. Status = IrpContext->Irp->IoStatus.Status;
  793. }
  794. }
  795. //
  796. // Check whether we should raise in the error case.
  797. //
  798. if (!NT_SUCCESS( Status )) {
  799. if (!ReturnError) {
  800. CdNormalizeAndRaiseStatus( IrpContext, Status );
  801. }
  802. //
  803. // We don't raise, but return FALSE to indicate an error.
  804. //
  805. return FALSE;
  806. //
  807. // The operation completed successfully.
  808. //
  809. } else {
  810. return TRUE;
  811. }
  812. }
  813. NTSTATUS
  814. CdCreateUserMdl (
  815. IN PIRP_CONTEXT IrpContext,
  816. IN ULONG BufferLength,
  817. IN BOOLEAN RaiseOnError
  818. )
  819. /*++
  820. Routine Description:
  821. This routine locks the specified buffer for read access (we only write into
  822. the buffer). The file system requires this routine since it does not
  823. ask the I/O system to lock its buffers for direct I/O. This routine
  824. may only be called from the Fsd while still in the user context.
  825. This routine is only called if there is not already an Mdl.
  826. Arguments:
  827. BufferLength - Length of user buffer.
  828. RaiseOnError - Indicates if our caller wants this routine to raise on
  829. an error condition.
  830. Return Value:
  831. NTSTATUS - Status from this routine. Error status only returned if
  832. RaiseOnError is FALSE.
  833. --*/
  834. {
  835. NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
  836. PMDL Mdl;
  837. PAGED_CODE();
  838. ASSERT_IRP_CONTEXT( IrpContext );
  839. ASSERT_IRP( IrpContext->Irp );
  840. ASSERT( IrpContext->Irp->MdlAddress == NULL );
  841. //
  842. // Allocate the Mdl, and Raise if we fail.
  843. //
  844. Mdl = IoAllocateMdl( IrpContext->Irp->UserBuffer,
  845. BufferLength,
  846. FALSE,
  847. FALSE,
  848. IrpContext->Irp );
  849. if (Mdl != NULL) {
  850. //
  851. // Now probe the buffer described by the Irp. If we get an exception,
  852. // deallocate the Mdl and return the appropriate "expected" status.
  853. //
  854. try {
  855. MmProbeAndLockPages( Mdl, IrpContext->Irp->RequestorMode, IoWriteAccess );
  856. Status = STATUS_SUCCESS;
  857. } except(EXCEPTION_EXECUTE_HANDLER) {
  858. Status = GetExceptionCode();
  859. IoFreeMdl( Mdl );
  860. IrpContext->Irp->MdlAddress = NULL;
  861. if (!FsRtlIsNtstatusExpected( Status )) {
  862. Status = STATUS_INVALID_USER_BUFFER;
  863. }
  864. }
  865. }
  866. //
  867. // Check if we are to raise or return
  868. //
  869. if (Status != STATUS_SUCCESS) {
  870. if (RaiseOnError) {
  871. CdRaiseStatus( IrpContext, Status );
  872. }
  873. }
  874. //
  875. // Return the status code.
  876. //
  877. return Status;
  878. }
  879. NTSTATUS
  880. CdPerformDevIoCtrl (
  881. IN PIRP_CONTEXT IrpContext,
  882. IN ULONG IoControlCode,
  883. IN PDEVICE_OBJECT Device,
  884. OUT PVOID OutputBuffer OPTIONAL,
  885. IN ULONG OutputBufferLength,
  886. IN BOOLEAN InternalDeviceIoControl,
  887. IN BOOLEAN OverrideVerify,
  888. OUT PIO_STATUS_BLOCK Iosb OPTIONAL
  889. )
  890. /*++
  891. Routine Description:
  892. This routine is called to perform DevIoCtrl functions internally within
  893. the filesystem. We take the status from the driver and return it to our
  894. caller.
  895. Arguments:
  896. IoControlCode - Code to send to driver.
  897. Device - This is the device to send the request to.
  898. OutPutBuffer - Pointer to output buffer.
  899. OutputBufferLength - Length of output buffer above.
  900. InternalDeviceIoControl - Indicates if this is an internal or external
  901. Io control code.
  902. OverrideVerify - Indicates if we should tell the driver not to return
  903. STATUS_VERIFY_REQUIRED for mount and verify.
  904. Iosb - If specified, we return the results of the operation here.
  905. Return Value:
  906. NTSTATUS - Status returned by next lower driver.
  907. --*/
  908. {
  909. NTSTATUS Status;
  910. PIRP Irp;
  911. KEVENT Event;
  912. IO_STATUS_BLOCK LocalIosb;
  913. PIO_STATUS_BLOCK IosbToUse = &LocalIosb;
  914. PAGED_CODE();
  915. //
  916. // Check if the user gave us an Iosb.
  917. //
  918. if (ARGUMENT_PRESENT( Iosb )) {
  919. IosbToUse = Iosb;
  920. }
  921. IosbToUse->Status = 0;
  922. IosbToUse->Information = 0;
  923. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  924. Irp = IoBuildDeviceIoControlRequest( IoControlCode,
  925. Device,
  926. NULL,
  927. 0,
  928. OutputBuffer,
  929. OutputBufferLength,
  930. InternalDeviceIoControl,
  931. &Event,
  932. IosbToUse );
  933. if (Irp == NULL) {
  934. return STATUS_INSUFFICIENT_RESOURCES;
  935. }
  936. if (OverrideVerify) {
  937. SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
  938. }
  939. Status = IoCallDriver( Device, Irp );
  940. //
  941. // We check for device not ready by first checking Status
  942. // and then if status pending was returned, the Iosb status
  943. // value.
  944. //
  945. if (Status == STATUS_PENDING) {
  946. (VOID) KeWaitForSingleObject( &Event,
  947. Executive,
  948. KernelMode,
  949. FALSE,
  950. (PLARGE_INTEGER)NULL );
  951. Status = IosbToUse->Status;
  952. }
  953. ASSERT( !(OverrideVerify && (STATUS_VERIFY_REQUIRED == Status)));
  954. return Status;
  955. }
  956. //
  957. // Local support routine
  958. //
  959. BOOLEAN
  960. CdPrepareBuffers (
  961. IN PIRP_CONTEXT IrpContext,
  962. IN PIRP Irp,
  963. IN PFCB Fcb,
  964. IN PVOID UserBuffer,
  965. IN ULONG UserBufferOffset,
  966. IN LONGLONG StartingOffset,
  967. IN ULONG ByteCount,
  968. IN PIO_RUN IoRuns,
  969. IN PULONG RunCount,
  970. IN PULONG ThisByteCount
  971. )
  972. /*++
  973. Routine Description:
  974. This routine is the worker routine which looks up each run of an IO
  975. request and stores an entry for it in the IoRuns array. If the run
  976. begins on an unaligned disk boundary then we will allocate a buffer
  977. and Mdl for the unaligned portion and put it in the IoRuns entry.
  978. This routine will raise CANT_WAIT if an unaligned transfer is encountered
  979. and this request can't wait.
  980. Arguments:
  981. Irp - Originating Irp for this request.
  982. Fcb - This is the Fcb for this data stream. It may be a file, directory,
  983. path table or the volume file.
  984. UserBuffer - Current position in the user's buffer.
  985. UserBufferOffset - Offset from the start of the original user buffer.
  986. StartingOffset - Offset in the stream to begin the read.
  987. ByteCount - Number of bytes to read. We will fill the IoRuns array up
  988. to this point. We will stop early if we exceed the maximum number
  989. of parallel Ios we support.
  990. IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
  991. this routine is called.
  992. RunCount - Number of entries in the IoRuns array filled here.
  993. ThisByteCount - Number of bytes described by the IoRun entries. Will
  994. not exceed the ByteCount passed in.
  995. Return Value:
  996. BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided
  997. this is synchronous). FALSE otherwise.
  998. --*/
  999. {
  1000. BOOLEAN FoundUnaligned = FALSE;
  1001. PIO_RUN ThisIoRun = IoRuns;
  1002. //
  1003. // Following indicate where we are in the current transfer. Current
  1004. // position in the file and number of bytes yet to transfer from
  1005. // this position.
  1006. //
  1007. ULONG RemainingByteCount = ByteCount;
  1008. LONGLONG CurrentFileOffset = StartingOffset;
  1009. //
  1010. // Following indicate the state of the user's buffer. We have
  1011. // the destination of the next transfer and its offset in the
  1012. // buffer. We also have the next available position in the buffer
  1013. // available for a scratch buffer. We will align this up to a sector
  1014. // boundary.
  1015. //
  1016. PVOID CurrentUserBuffer = UserBuffer;
  1017. ULONG CurrentUserBufferOffset = UserBufferOffset;
  1018. PVOID ScratchUserBuffer = UserBuffer;
  1019. ULONG ScratchUserBufferOffset = UserBufferOffset;
  1020. //
  1021. // The following is the next contiguous bytes on the disk to
  1022. // transfer. Read from the allocation package.
  1023. //
  1024. LONGLONG DiskOffset;
  1025. ULONG CurrentByteCount;
  1026. PAGED_CODE();
  1027. //
  1028. // Initialize the RunCount and ByteCount.
  1029. //
  1030. *RunCount = 0;
  1031. *ThisByteCount = 0;
  1032. //
  1033. // Loop while there are more bytes to process or there are
  1034. // available entries in the IoRun array.
  1035. //
  1036. while (TRUE) {
  1037. *RunCount += 1;
  1038. //
  1039. // Initialize the current position in the IoRuns array.
  1040. // Find the user's buffer for this portion of the transfer.
  1041. //
  1042. ThisIoRun->UserBuffer = CurrentUserBuffer;
  1043. //
  1044. // Find the allocation information for the current offset in the
  1045. // stream.
  1046. //
  1047. CdLookupAllocation( IrpContext,
  1048. Fcb,
  1049. CurrentFileOffset,
  1050. &DiskOffset,
  1051. &CurrentByteCount );
  1052. //
  1053. // Limit ourselves to the data requested.
  1054. //
  1055. if (CurrentByteCount > RemainingByteCount) {
  1056. CurrentByteCount = RemainingByteCount;
  1057. }
  1058. //
  1059. // Handle the case where this is an unaligned transfer. The
  1060. // following must all be true for this to be an aligned transfer.
  1061. //
  1062. // Disk offset on a 2048 byte boundary (Start of transfer)
  1063. //
  1064. // Byte count is a multiple of 2048 (Length of transfer)
  1065. //
  1066. // Current buffer offset is also on a 2048 byte boundary.
  1067. //
  1068. // If the ByteCount is at least one sector then do the
  1069. // unaligned transfer only for the tail. We can use the
  1070. // user's buffer for the aligned portion.
  1071. //
  1072. if (FlagOn( (ULONG) DiskOffset, SECTOR_MASK ) ||
  1073. FlagOn( CurrentUserBufferOffset, SECTOR_MASK ) ||
  1074. (FlagOn( (ULONG) CurrentByteCount, SECTOR_MASK ) &&
  1075. (CurrentByteCount < SECTOR_SIZE))) {
  1076. //
  1077. // If we can't wait then raise.
  1078. //
  1079. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  1080. CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
  1081. }
  1082. //
  1083. // Remember the offset and the number of bytes out of
  1084. // the transfer buffer to copy into the user's buffer.
  1085. // We will truncate the current read to end on a sector
  1086. // boundary.
  1087. //
  1088. ThisIoRun->TransferBufferOffset = SectorOffset( DiskOffset );
  1089. //
  1090. // Make sure this transfer ends on a sector boundary.
  1091. //
  1092. ThisIoRun->DiskOffset = LlSectorTruncate( DiskOffset );
  1093. //
  1094. // Check if we can use a free portion of the user's buffer.
  1095. // If we can copy the bytes to an earlier portion of the
  1096. // buffer then read into that location and slide the bytes
  1097. // up.
  1098. //
  1099. // We can use the user's buffer if:
  1100. //
  1101. // The temporary location in the buffer is before the
  1102. // final destination.
  1103. //
  1104. // There is at least one sector of data to read.
  1105. //
  1106. if ((ScratchUserBufferOffset + ThisIoRun->TransferBufferOffset < CurrentUserBufferOffset) &&
  1107. (ThisIoRun->TransferBufferOffset + CurrentByteCount >= SECTOR_SIZE)) {
  1108. ThisIoRun->DiskByteCount = SectorTruncate( ThisIoRun->TransferBufferOffset + CurrentByteCount );
  1109. CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
  1110. ThisIoRun->TransferByteCount = CurrentByteCount;
  1111. //
  1112. // Point to the user's buffer and Mdl for this transfer.
  1113. //
  1114. ThisIoRun->TransferBuffer = ScratchUserBuffer;
  1115. ThisIoRun->TransferMdl = Irp->MdlAddress;
  1116. ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
  1117. ScratchUserBufferOffset,
  1118. PVOID );
  1119. ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
  1120. ThisIoRun->DiskByteCount,
  1121. PVOID );
  1122. ScratchUserBufferOffset += ThisIoRun->DiskByteCount;
  1123. //
  1124. // Otherwise we need to allocate an auxilary buffer for the next sector.
  1125. //
  1126. } else {
  1127. //
  1128. // Read up to a page containing the partial data
  1129. //
  1130. ThisIoRun->DiskByteCount = SectorAlign( ThisIoRun->TransferBufferOffset + CurrentByteCount );
  1131. if (ThisIoRun->DiskByteCount > PAGE_SIZE) {
  1132. ThisIoRun->DiskByteCount = PAGE_SIZE;
  1133. }
  1134. if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) {
  1135. CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
  1136. }
  1137. ThisIoRun->TransferByteCount = CurrentByteCount;
  1138. //
  1139. // Allocate a buffer for the non-aligned transfer.
  1140. //
  1141. ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
  1142. //
  1143. // Allocate and build the Mdl to describe this buffer.
  1144. //
  1145. ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
  1146. PAGE_SIZE,
  1147. FALSE,
  1148. FALSE,
  1149. NULL );
  1150. ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
  1151. if (ThisIoRun->TransferMdl == NULL) {
  1152. IrpContext->Irp->IoStatus.Information = 0;
  1153. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1154. }
  1155. MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
  1156. }
  1157. //
  1158. // Remember we found an unaligned transfer.
  1159. //
  1160. FoundUnaligned = TRUE;
  1161. //
  1162. // Otherwise we use the buffer and Mdl from the original request.
  1163. //
  1164. } else {
  1165. //
  1166. // Truncate the read length to a sector-aligned value. We know
  1167. // the length must be at least one sector or we wouldn't be
  1168. // here now.
  1169. //
  1170. CurrentByteCount = SectorTruncate( CurrentByteCount );
  1171. //
  1172. // Read these sectors from the disk.
  1173. //
  1174. ThisIoRun->DiskOffset = DiskOffset;
  1175. ThisIoRun->DiskByteCount = CurrentByteCount;
  1176. //
  1177. // Use the user's buffer and Mdl as our transfer buffer
  1178. // and Mdl.
  1179. //
  1180. ThisIoRun->TransferBuffer = CurrentUserBuffer;
  1181. ThisIoRun->TransferMdl = Irp->MdlAddress;
  1182. ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
  1183. CurrentUserBufferOffset,
  1184. PVOID );
  1185. ScratchUserBuffer = Add2Ptr( CurrentUserBuffer,
  1186. CurrentByteCount,
  1187. PVOID );
  1188. ScratchUserBufferOffset += CurrentByteCount;
  1189. }
  1190. //
  1191. // Update our position in the transfer and the RunCount and
  1192. // ByteCount for the user.
  1193. //
  1194. RemainingByteCount -= CurrentByteCount;
  1195. //
  1196. // Break out if no more positions in the IoRuns array or
  1197. // we have all of the bytes accounted for.
  1198. //
  1199. *ThisByteCount += CurrentByteCount;
  1200. if ((RemainingByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
  1201. break;
  1202. }
  1203. //
  1204. // Update our pointers for the user's buffer.
  1205. //
  1206. ThisIoRun += 1;
  1207. CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentByteCount, PVOID );
  1208. CurrentUserBufferOffset += CurrentByteCount;
  1209. CurrentFileOffset += CurrentByteCount;
  1210. }
  1211. return FoundUnaligned;
  1212. }
  1213. //
  1214. // Local support routine
  1215. //
  1216. VOID
  1217. CdPrepareXABuffers (
  1218. IN PIRP_CONTEXT IrpContext,
  1219. IN PIRP Irp,
  1220. IN PFCB Fcb,
  1221. IN PVOID UserBuffer,
  1222. IN ULONG UserBufferOffset,
  1223. IN LONGLONG StartingOffset,
  1224. IN ULONG ByteCount,
  1225. IN PIO_RUN IoRuns,
  1226. IN PULONG RunCount,
  1227. IN PULONG ThisByteCount
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. This routine is the worker routine which looks up the individual runs
  1232. of an IO request and stores an entry for it in the IoRuns array. The
  1233. worker routine is for XA files where we need to convert the raw offset
  1234. in the file to logical cooked sectors. We store one raw sector in
  1235. the Vcb. If the current read is to that sector then we can simply copy
  1236. whatever bytes are needed from that sector.
  1237. Arguments:
  1238. Irp - Originating Irp for this request.
  1239. Fcb - This is the Fcb for this data stream. It must be a data stream.
  1240. UserBuffer - Current position in the user's buffer.
  1241. UserBufferOffset - Offset of this buffer from the beginning of the user's
  1242. buffer for the original request.
  1243. StartingOffset - Offset in the stream to begin the read.
  1244. ByteCount - Number of bytes to read. We will fill the IoRuns array up
  1245. to this point. We will stop early if we exceed the maximum number
  1246. of parallel Ios we support.
  1247. IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
  1248. this routine is called.
  1249. RunCount - Number of entries in the IoRuns array filled here.
  1250. ThisByteCount - Number of bytes described by the IoRun entries. Will
  1251. not exceed the ByteCount passed in.
  1252. Return Value:
  1253. None
  1254. --*/
  1255. {
  1256. PIO_RUN ThisIoRun = IoRuns;
  1257. BOOLEAN PerformedCopy;
  1258. //
  1259. // The following deal with where we are in the range of raw sectors.
  1260. // Note that we will bias the input file offset by the RIFF header
  1261. // to deal directly with the raw sectors.
  1262. //
  1263. ULONG RawSectorOffset;
  1264. ULONG RemainingRawByteCount = ByteCount;
  1265. LONGLONG CurrentRawOffset = StartingOffset - sizeof( RIFF_HEADER );
  1266. //
  1267. // The following is the offset into the cooked sectors for the file.
  1268. //
  1269. LONGLONG CurrentCookedOffset;
  1270. ULONG RemainingCookedByteCount;
  1271. //
  1272. // Following indicate the state of the user's buffer. We have
  1273. // the destination of the next transfer and its offset in the
  1274. // buffer. We also have the next available position in the buffer
  1275. // available for a scratch buffer.
  1276. //
  1277. PVOID CurrentUserBuffer = UserBuffer;
  1278. ULONG CurrentUserBufferOffset = UserBufferOffset;
  1279. PVOID ScratchUserBuffer = UserBuffer;
  1280. ULONG ScratchUserBufferOffset = UserBufferOffset;
  1281. BOOLEAN RoundScratchBuffer = TRUE;
  1282. //
  1283. // The following is the next contiguous bytes on the disk to
  1284. // transfer. These are represented by cooked byte offset and length.
  1285. // We also compute the number of raw bytes in the current transfer.
  1286. //
  1287. LONGLONG DiskOffset;
  1288. ULONG CurrentCookedByteCount;
  1289. ULONG CurrentRawByteCount;
  1290. PAGED_CODE();
  1291. //
  1292. // We need to maintain our position as we walk through the sectors on the disk.
  1293. // We keep separate values for the cooked offset as well as the raw offset.
  1294. // These are initialized on sector boundaries and we move through these
  1295. // the file sector-by-sector.
  1296. //
  1297. // Try to do 32-bit math.
  1298. //
  1299. if (((PLARGE_INTEGER) &CurrentRawOffset)->HighPart == 0) {
  1300. CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE);
  1301. CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT );
  1302. CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE);
  1303. //
  1304. // Otherwise we need to do 64-bit math (sigh).
  1305. //
  1306. } else {
  1307. CurrentRawOffset /= RAW_SECTOR_SIZE;
  1308. CurrentCookedOffset = CurrentRawOffset << SECTOR_SHIFT;
  1309. CurrentRawOffset *= RAW_SECTOR_SIZE;
  1310. }
  1311. //
  1312. // Now compute the full number of sectors to be read. Count all of the raw
  1313. // sectors that need to be read and convert to cooked bytes.
  1314. //
  1315. RawSectorOffset = (ULONG) ( StartingOffset - CurrentRawOffset) - sizeof( RIFF_HEADER );
  1316. CurrentRawByteCount = (RawSectorOffset + RemainingRawByteCount + RAW_SECTOR_SIZE - 1) / RAW_SECTOR_SIZE;
  1317. RemainingCookedByteCount = CurrentRawByteCount << SECTOR_SHIFT;
  1318. //
  1319. // Initialize the RunCount and ByteCount.
  1320. //
  1321. *RunCount = 0;
  1322. *ThisByteCount = 0;
  1323. //
  1324. // Loop while there are more bytes to process or there are
  1325. // available entries in the IoRun array.
  1326. //
  1327. while (TRUE) {
  1328. PerformedCopy = FALSE;
  1329. *RunCount += 1;
  1330. //
  1331. // Round the scratch buffer up to a sector boundary for alignment.
  1332. //
  1333. if (RoundScratchBuffer) {
  1334. if (SectorOffset( ScratchUserBuffer ) != 0) {
  1335. CurrentRawByteCount = SECTOR_SIZE - SectorOffset( ScratchUserBuffer );
  1336. ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
  1337. CurrentRawByteCount,
  1338. PVOID );
  1339. ScratchUserBufferOffset += CurrentRawByteCount;
  1340. }
  1341. RoundScratchBuffer = FALSE;
  1342. }
  1343. //
  1344. // Initialize the current position in the IoRuns array. Find the
  1345. // eventual destination in the user's buffer for this portion of the transfer.
  1346. //
  1347. ThisIoRun->UserBuffer = CurrentUserBuffer;
  1348. //
  1349. // Find the allocation information for the current offset in the
  1350. // stream.
  1351. //
  1352. CdLookupAllocation( IrpContext,
  1353. Fcb,
  1354. CurrentCookedOffset,
  1355. &DiskOffset,
  1356. &CurrentCookedByteCount );
  1357. //
  1358. // Maybe we got lucky and this is the same sector as in the
  1359. // Vcb.
  1360. //
  1361. if (DiskOffset == Fcb->Vcb->XADiskOffset) {
  1362. //
  1363. // We will perform safe synchronization. Check again that
  1364. // this is the correct sector.
  1365. //
  1366. CdLockVcb( IrpContext, Fcb->Vcb );
  1367. if ((DiskOffset == Fcb->Vcb->XADiskOffset) &&
  1368. (Fcb->Vcb->XASector != NULL)) {
  1369. //
  1370. // Copy any bytes we can from the current sector.
  1371. //
  1372. CurrentRawByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
  1373. //
  1374. // Check whether we don't go to the end of the sector.
  1375. //
  1376. if (CurrentRawByteCount > RemainingRawByteCount) {
  1377. CurrentRawByteCount = RemainingRawByteCount;
  1378. }
  1379. RtlCopyMemory( CurrentUserBuffer,
  1380. Add2Ptr( Fcb->Vcb->XASector, RawSectorOffset, PCHAR ),
  1381. CurrentRawByteCount );
  1382. CdUnlockVcb( IrpContext, Fcb->Vcb );
  1383. //
  1384. // Adjust the run count and pointer in the IoRuns array
  1385. // to show that we didn't use a position.
  1386. //
  1387. *RunCount -= 1;
  1388. ThisIoRun -= 1;
  1389. //
  1390. // Remember that we performed a copy operation and update
  1391. // the next available position in the scratch buffer.
  1392. //
  1393. PerformedCopy = TRUE;
  1394. ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
  1395. CurrentRawByteCount,
  1396. PVOID );
  1397. ScratchUserBufferOffset += CurrentRawByteCount;
  1398. CurrentCookedByteCount = SECTOR_SIZE;
  1399. //
  1400. // Set the flag indicating we want to round the scratch buffer
  1401. // to a sector boundary.
  1402. //
  1403. RoundScratchBuffer = TRUE;
  1404. } else {
  1405. //
  1406. // The safe test showed no available buffer. Drop down to common code to
  1407. // perform the Io.
  1408. //
  1409. CdUnlockVcb( IrpContext, Fcb->Vcb );
  1410. }
  1411. }
  1412. //
  1413. // No work in this pass if we did a copy operation.
  1414. //
  1415. if (!PerformedCopy) {
  1416. //
  1417. // Limit ourselves by the number of remaining cooked bytes.
  1418. //
  1419. if (CurrentCookedByteCount > RemainingCookedByteCount) {
  1420. CurrentCookedByteCount = RemainingCookedByteCount;
  1421. }
  1422. ThisIoRun->DiskOffset = DiskOffset;
  1423. ThisIoRun->TransferBufferOffset = RawSectorOffset;
  1424. //
  1425. // We will always need to perform copy operations for XA files.
  1426. // We allocate an auxillary buffer to read the start of the
  1427. // transfer. Then we can use a range of the user's buffer to
  1428. // perform the next range of the transfer. Finally we may
  1429. // need to allocate a buffer for the tail of the transfer.
  1430. //
  1431. // We can use the user's buffer (at the current scratch buffer) if the
  1432. // following are true:
  1433. //
  1434. // If we are to store the beginning of the raw sector in the user's buffer.
  1435. // The current scratch buffer precedes the destination in the user's buffer
  1436. // (and hence also lies within it)
  1437. // There are enough bytes remaining in the buffer for at least one
  1438. // raw sector.
  1439. //
  1440. if ((RawSectorOffset == 0) &&
  1441. (ScratchUserBufferOffset <= CurrentUserBufferOffset) &&
  1442. (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount >= RAW_SECTOR_SIZE)) {
  1443. //
  1444. // We can use the scratch buffer. We must ensure we don't send down reads
  1445. // greater than the device can handle, since the driver is unable to split
  1446. // raw requests.
  1447. //
  1448. if (CurrentCookedByteCount <= Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE) {
  1449. CurrentRawByteCount = (SectorAlign( CurrentCookedByteCount) >> SECTOR_SHIFT) * RAW_SECTOR_SIZE;
  1450. } else {
  1451. CurrentCookedByteCount = Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE;
  1452. CurrentRawByteCount = Fcb->Vcb->MaximumTransferRawSectors * RAW_SECTOR_SIZE;
  1453. }
  1454. //
  1455. // Now make sure we are within the page transfer limit.
  1456. //
  1457. while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(ScratchUserBuffer, RawSectorAlign( CurrentRawByteCount)) >
  1458. Fcb->Vcb->MaximumPhysicalPages ) {
  1459. CurrentRawByteCount -= RAW_SECTOR_SIZE;
  1460. CurrentCookedByteCount -= SECTOR_SIZE;
  1461. }
  1462. //
  1463. // Trim the number of bytes to read if it won't fit into the current buffer. Take
  1464. // account of the fact that we must read in whole raw sector multiples.
  1465. //
  1466. while ( RawSectorAlign( CurrentRawByteCount) >
  1467. (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount) ) {
  1468. CurrentRawByteCount -= RAW_SECTOR_SIZE;
  1469. CurrentCookedByteCount -= SECTOR_SIZE;
  1470. }
  1471. //
  1472. // Now trim the maximum number of raw bytes to the remaining bytes.
  1473. //
  1474. if (CurrentRawByteCount > RemainingRawByteCount) {
  1475. CurrentRawByteCount = RemainingRawByteCount;
  1476. }
  1477. //
  1478. // Update the IO run array. We point to the scratch buffer as
  1479. // well as the buffer and Mdl in the original Irp.
  1480. //
  1481. ThisIoRun->DiskByteCount = SectorAlign( CurrentCookedByteCount);
  1482. //
  1483. // Store the number of bytes which we actually care about from this transfer
  1484. //
  1485. ThisIoRun->TransferByteCount = CurrentRawByteCount;
  1486. //
  1487. // Point to the user's buffer and Mdl for this transfer.
  1488. //
  1489. ThisIoRun->TransferBuffer = ScratchUserBuffer;
  1490. ThisIoRun->TransferMdl = Irp->MdlAddress;
  1491. ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
  1492. ScratchUserBufferOffset,
  1493. PVOID);
  1494. //
  1495. // Update the scratch buffer pointer. Note that since the underlying
  1496. // driver stack will always transfer in multiples of raw sectors,
  1497. // we must round up here rather than simply advancing by the length of the
  1498. // of the data which we actually care about.
  1499. //
  1500. ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
  1501. RawSectorAlign( CurrentRawByteCount),
  1502. PVOID );
  1503. ScratchUserBufferOffset += RawSectorAlign( CurrentRawByteCount);;
  1504. //
  1505. // Set the flag indicating we want to round the scratch buffer
  1506. // to a cooked sector boundary.
  1507. //
  1508. RoundScratchBuffer = TRUE;
  1509. } else {
  1510. //
  1511. // We need to determine the number of bytes to transfer and the
  1512. // offset into this page to begin the transfer.
  1513. //
  1514. // We will transfer only one raw sector.
  1515. //
  1516. ThisIoRun->DiskByteCount = SECTOR_SIZE;
  1517. CurrentCookedByteCount = SECTOR_SIZE;
  1518. ThisIoRun->TransferByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
  1519. ThisIoRun->TransferBufferOffset = RawSectorOffset;
  1520. if (ThisIoRun->TransferByteCount > RemainingRawByteCount) {
  1521. ThisIoRun->TransferByteCount = RemainingRawByteCount;
  1522. }
  1523. CurrentRawByteCount = ThisIoRun->TransferByteCount;
  1524. //
  1525. // We need to allocate an auxillary buffer. We will allocate
  1526. // a single page. Then we will build an Mdl to describe the buffer.
  1527. //
  1528. ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
  1529. //
  1530. // Allocate and build the Mdl to describe this buffer.
  1531. //
  1532. ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
  1533. PAGE_SIZE,
  1534. FALSE,
  1535. FALSE,
  1536. NULL );
  1537. ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
  1538. if (ThisIoRun->TransferMdl == NULL) {
  1539. IrpContext->Irp->IoStatus.Information = 0;
  1540. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1541. }
  1542. MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
  1543. }
  1544. }
  1545. //
  1546. // Update the byte count for our caller.
  1547. //
  1548. RemainingRawByteCount -= CurrentRawByteCount;
  1549. *ThisByteCount += CurrentRawByteCount;
  1550. //
  1551. // Break out if no more positions in the IoRuns array or
  1552. // we have all of the bytes accounted for.
  1553. //
  1554. if ((RemainingRawByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
  1555. break;
  1556. }
  1557. //
  1558. // Update our local pointers to allow for the current range of bytes.
  1559. //
  1560. ThisIoRun += 1;
  1561. CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentRawByteCount, PVOID );
  1562. CurrentUserBufferOffset += CurrentRawByteCount;
  1563. RawSectorOffset = 0;
  1564. CurrentCookedOffset += CurrentCookedByteCount;
  1565. RemainingCookedByteCount -= CurrentCookedByteCount;
  1566. }
  1567. return;
  1568. }
  1569. //
  1570. // Local support routine
  1571. //
  1572. BOOLEAN
  1573. CdFinishBuffers (
  1574. IN PIRP_CONTEXT IrpContext,
  1575. IN PIO_RUN IoRuns,
  1576. IN ULONG RunCount,
  1577. IN BOOLEAN FinalCleanup,
  1578. IN BOOLEAN SaveXABuffer
  1579. )
  1580. /*++
  1581. Routine Description:
  1582. This routine is called to perform any data transferred required for
  1583. unaligned Io or to perform the final cleanup of the IoRuns array.
  1584. In all cases this is where we will deallocate any buffer and mdl
  1585. allocated to perform the unaligned transfer. If this is not the
  1586. final cleanup then we also transfer the bytes to the user buffer
  1587. and flush the hardware cache.
  1588. We walk backwards through the run array because we may be shifting data
  1589. in the user's buffer. Typical case is where we allocated a buffer for
  1590. the first part of a read and then used the user's buffer for the
  1591. next section (but stored it at the beginning of the buffer.
  1592. Arguments:
  1593. IoRuns - Pointer to the IoRuns array.
  1594. RunCount - Number of entries in the IoRuns array filled here.
  1595. FinalCleanup - Indicates if we should be deallocating temporary buffers
  1596. (TRUE) or transferring bytes for a unaligned transfers and
  1597. deallocating the buffers (FALSE). Flush the system cache if
  1598. transferring data.
  1599. SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise
  1600. Return Value:
  1601. BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
  1602. --*/
  1603. {
  1604. BOOLEAN FlushIoBuffers = FALSE;
  1605. ULONG RemainingEntries = RunCount;
  1606. PIO_RUN ThisIoRun = &IoRuns[RunCount - 1];
  1607. PVCB Vcb;
  1608. PAGED_CODE();
  1609. //
  1610. // Walk through each entry in the IoRun array.
  1611. //
  1612. while (RemainingEntries != 0) {
  1613. //
  1614. // We only need to deal with the case of an unaligned transfer.
  1615. //
  1616. if (ThisIoRun->TransferByteCount != 0) {
  1617. //
  1618. // If not the final cleanup then transfer the data to the
  1619. // user's buffer and remember that we will need to flush
  1620. // the user's buffer to memory.
  1621. //
  1622. if (!FinalCleanup) {
  1623. //
  1624. // If we are shifting in the user's buffer then use
  1625. // MoveMemory.
  1626. //
  1627. if (ThisIoRun->TransferMdl == IrpContext->Irp->MdlAddress) {
  1628. RtlMoveMemory( ThisIoRun->UserBuffer,
  1629. Add2Ptr( ThisIoRun->TransferBuffer,
  1630. ThisIoRun->TransferBufferOffset,
  1631. PVOID ),
  1632. ThisIoRun->TransferByteCount );
  1633. } else {
  1634. RtlCopyMemory( ThisIoRun->UserBuffer,
  1635. Add2Ptr( ThisIoRun->TransferBuffer,
  1636. ThisIoRun->TransferBufferOffset,
  1637. PVOID ),
  1638. ThisIoRun->TransferByteCount );
  1639. }
  1640. FlushIoBuffers = TRUE;
  1641. }
  1642. //
  1643. // Free any Mdl we may have allocated. If the Mdl isn't
  1644. // present then we must have failed during the allocation
  1645. // phase.
  1646. //
  1647. if (ThisIoRun->TransferMdl != IrpContext->Irp->MdlAddress) {
  1648. if (ThisIoRun->TransferMdl != NULL) {
  1649. IoFreeMdl( ThisIoRun->TransferMdl );
  1650. }
  1651. //
  1652. // Now free any buffer we may have allocated. If the Mdl
  1653. // doesn't match the original Mdl then free the buffer.
  1654. //
  1655. if (ThisIoRun->TransferBuffer != NULL) {
  1656. //
  1657. // If this is the final buffer for an XA read then store this buffer
  1658. // into the Vcb so that we will have it when reading any remaining
  1659. // portion of this buffer.
  1660. //
  1661. if (SaveXABuffer) {
  1662. Vcb = IrpContext->Vcb;
  1663. CdLockVcb( IrpContext, Vcb );
  1664. if (Vcb->XASector != NULL) {
  1665. ExFreePool( Vcb->XASector );
  1666. }
  1667. Vcb->XASector = ThisIoRun->TransferBuffer;
  1668. Vcb->XADiskOffset = ThisIoRun->DiskOffset;
  1669. SaveXABuffer = FALSE;
  1670. CdUnlockVcb( IrpContext, Vcb );
  1671. //
  1672. // Otherwise just free the buffer.
  1673. //
  1674. } else {
  1675. ExFreePool( ThisIoRun->TransferBuffer );
  1676. }
  1677. }
  1678. }
  1679. }
  1680. //
  1681. // Now handle the case where we failed in the process
  1682. // of allocating associated Irps and Mdls.
  1683. //
  1684. if (ThisIoRun->SavedIrp != NULL) {
  1685. if (ThisIoRun->SavedIrp->MdlAddress != NULL) {
  1686. IoFreeMdl( ThisIoRun->SavedIrp->MdlAddress );
  1687. }
  1688. IoFreeIrp( ThisIoRun->SavedIrp );
  1689. }
  1690. //
  1691. // Move to the previous IoRun entry.
  1692. //
  1693. ThisIoRun -= 1;
  1694. RemainingEntries -= 1;
  1695. }
  1696. //
  1697. // If we copied any data then flush the Io buffers.
  1698. //
  1699. return FlushIoBuffers;
  1700. }
  1701. //
  1702. // Local support routine
  1703. //
  1704. VOID
  1705. CdMultipleAsync (
  1706. IN PIRP_CONTEXT IrpContext,
  1707. IN ULONG RunCount,
  1708. IN PIO_RUN IoRuns
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. This routine first does the initial setup required of a Master IRP that is
  1713. going to be completed using associated IRPs. This routine should not
  1714. be used if only one async request is needed, instead the single read
  1715. async routines should be called.
  1716. A context parameter is initialized, to serve as a communications area
  1717. between here and the common completion routine.
  1718. Next this routine reads or writes one or more contiguous sectors from
  1719. a device asynchronously, and is used if there are multiple reads for a
  1720. master IRP. A completion routine is used to synchronize with the
  1721. completion of all of the I/O requests started by calls to this routine.
  1722. Also, prior to calling this routine the caller must initialize the
  1723. IoStatus field in the Context, with the correct success status and byte
  1724. count which are expected if all of the parallel transfers complete
  1725. successfully. After return this status will be unchanged if all requests
  1726. were, in fact, successful. However, if one or more errors occur, the
  1727. IoStatus will be modified to reflect the error status and byte count
  1728. from the first run (by Vbo) which encountered an error. I/O status
  1729. from all subsequent runs will not be indicated.
  1730. Arguments:
  1731. RunCount - Supplies the number of multiple async requests
  1732. that will be issued against the master irp.
  1733. IoRuns - Supplies an array containing the Offset and ByteCount for the
  1734. separate requests.
  1735. Return Value:
  1736. None.
  1737. --*/
  1738. {
  1739. PIO_COMPLETION_ROUTINE CompletionRoutine;
  1740. PIO_STACK_LOCATION IrpSp;
  1741. PMDL Mdl;
  1742. PIRP Irp;
  1743. PIRP MasterIrp;
  1744. ULONG UnwindRunCount;
  1745. PAGED_CODE();
  1746. //
  1747. // Set up things according to whether this is truely async.
  1748. //
  1749. CompletionRoutine = CdMultiSyncCompletionRoutine;
  1750. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  1751. CompletionRoutine = CdMultiAsyncCompletionRoutine;
  1752. }
  1753. //
  1754. // Initialize some local variables.
  1755. //
  1756. MasterIrp = IrpContext->Irp;
  1757. //
  1758. // Itterate through the runs, doing everything that can fail.
  1759. // We let the cleanup in CdFinishBuffers clean up on error.
  1760. //
  1761. for (UnwindRunCount = 0;
  1762. UnwindRunCount < RunCount;
  1763. UnwindRunCount += 1) {
  1764. //
  1765. // Create an associated IRP, making sure there is one stack entry for
  1766. // us, as well.
  1767. //
  1768. IoRuns[UnwindRunCount].SavedIrp =
  1769. Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
  1770. if (Irp == NULL) {
  1771. IrpContext->Irp->IoStatus.Information = 0;
  1772. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1773. }
  1774. //
  1775. // Allocate and build a partial Mdl for the request.
  1776. //
  1777. Mdl = IoAllocateMdl( IoRuns[UnwindRunCount].TransferVirtualAddress,
  1778. IoRuns[UnwindRunCount].DiskByteCount,
  1779. FALSE,
  1780. FALSE,
  1781. Irp );
  1782. if (Mdl == NULL) {
  1783. IrpContext->Irp->IoStatus.Information = 0;
  1784. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1785. }
  1786. IoBuildPartialMdl( IoRuns[UnwindRunCount].TransferMdl,
  1787. Mdl,
  1788. IoRuns[UnwindRunCount].TransferVirtualAddress,
  1789. IoRuns[UnwindRunCount].DiskByteCount );
  1790. //
  1791. // Get the first IRP stack location in the associated Irp
  1792. //
  1793. IoSetNextIrpStackLocation( Irp );
  1794. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1795. //
  1796. // Setup the Stack location to describe our read.
  1797. //
  1798. IrpSp->MajorFunction = IRP_MJ_READ;
  1799. IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
  1800. IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
  1801. //
  1802. // Set up the completion routine address in our stack frame.
  1803. //
  1804. IoSetCompletionRoutine( Irp,
  1805. CompletionRoutine,
  1806. IrpContext->IoContext,
  1807. TRUE,
  1808. TRUE,
  1809. TRUE );
  1810. //
  1811. // Setup the next IRP stack location in the associated Irp for the disk
  1812. // driver beneath us.
  1813. //
  1814. IrpSp = IoGetNextIrpStackLocation( Irp );
  1815. //
  1816. // Setup the Stack location to do a read from the disk driver.
  1817. //
  1818. IrpSp->MajorFunction = IRP_MJ_READ;
  1819. IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
  1820. IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
  1821. }
  1822. //
  1823. // We only need to set the associated IRP count in the master irp to
  1824. // make it a master IRP. But we set the count to one more than our
  1825. // caller requested, because we do not want the I/O system to complete
  1826. // the I/O. We also set our own count.
  1827. //
  1828. IrpContext->IoContext->IrpCount = RunCount;
  1829. IrpContext->IoContext->MasterIrp = MasterIrp;
  1830. //
  1831. // We set the count in the master Irp to 1 since typically we
  1832. // will clean up the associated irps ourselves. Setting this to one
  1833. // means completing the last associated Irp with SUCCESS (in the async
  1834. // case) will complete the master irp.
  1835. //
  1836. MasterIrp->AssociatedIrp.IrpCount = 1;
  1837. //
  1838. // Now that all the dangerous work is done, issue the Io requests
  1839. //
  1840. for (UnwindRunCount = 0;
  1841. UnwindRunCount < RunCount;
  1842. UnwindRunCount++) {
  1843. Irp = IoRuns[UnwindRunCount].SavedIrp;
  1844. IoRuns[UnwindRunCount].SavedIrp = NULL;
  1845. //
  1846. // If IoCallDriver returns an error, it has completed the Irp
  1847. // and the error will be caught by our completion routines
  1848. // and dealt with as a normal IO error.
  1849. //
  1850. (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
  1851. }
  1852. return;
  1853. }
  1854. //
  1855. // Local support routine
  1856. //
  1857. VOID
  1858. CdMultipleXAAsync (
  1859. IN PIRP_CONTEXT IrpContext,
  1860. IN ULONG RunCount,
  1861. IN PIO_RUN IoRuns,
  1862. IN PRAW_READ_INFO RawReads,
  1863. IN TRACK_MODE_TYPE TrackMode
  1864. )
  1865. /*++
  1866. Routine Description:
  1867. This routine first does the initial setup required of a Master IRP that is
  1868. going to be completed using associated IRPs. This routine is used to generate
  1869. the associated Irps used to read raw sectors from the disk.
  1870. A context parameter is initialized, to serve as a communications area
  1871. between here and the common completion routine.
  1872. Next this routine reads or writes one or more contiguous sectors from
  1873. a device asynchronously, and is used if there are multiple reads for a
  1874. master IRP. A completion routine is used to synchronize with the
  1875. completion of all of the I/O requests started by calls to this routine.
  1876. Also, prior to calling this routine the caller must initialize the
  1877. IoStatus field in the Context, with the correct success status and byte
  1878. count which are expected if all of the parallel transfers complete
  1879. successfully. After return this status will be unchanged if all requests
  1880. were, in fact, successful. However, if one or more errors occur, the
  1881. IoStatus will be modified to reflect the error status and byte count
  1882. from the first run (by Vbo) which encountered an error. I/O status
  1883. from all subsequent runs will not be indicated.
  1884. Arguments:
  1885. RunCount - Supplies the number of multiple async requests
  1886. that will be issued against the master irp.
  1887. IoRuns - Supplies an array containing the Offset and ByteCount for the
  1888. separate requests.
  1889. RawReads - Supplies an array of structures to store in the Irps passed to the
  1890. device driver to perform the low-level Io.
  1891. TrackMode - Supplies the recording mode of sectors in these IoRuns
  1892. Return Value:
  1893. None.
  1894. --*/
  1895. {
  1896. PIO_STACK_LOCATION IrpSp;
  1897. PMDL Mdl;
  1898. PIRP Irp;
  1899. PIRP MasterIrp;
  1900. ULONG UnwindRunCount;
  1901. ULONG RawByteCount;
  1902. PIO_RUN ThisIoRun = IoRuns;
  1903. PRAW_READ_INFO ThisRawRead = RawReads;
  1904. PAGED_CODE();
  1905. //
  1906. // Initialize some local variables.
  1907. //
  1908. MasterIrp = IrpContext->Irp;
  1909. //
  1910. // Itterate through the runs, doing everything that can fail.
  1911. // We let the cleanup in CdFinishBuffers clean up on error.
  1912. //
  1913. for (UnwindRunCount = 0;
  1914. UnwindRunCount < RunCount;
  1915. UnwindRunCount += 1, ThisIoRun += 1, ThisRawRead += 1) {
  1916. //
  1917. // Create an associated IRP, making sure there is one stack entry for
  1918. // us, as well.
  1919. //
  1920. ThisIoRun->SavedIrp =
  1921. Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
  1922. if (Irp == NULL) {
  1923. IrpContext->Irp->IoStatus.Information = 0;
  1924. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1925. }
  1926. //
  1927. // Should have been passed a byte count of at least one sector, and
  1928. // must be a multiple of sector size
  1929. //
  1930. ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount));
  1931. RawByteCount = SectorsFromBytes( ThisIoRun->DiskByteCount) * RAW_SECTOR_SIZE;
  1932. //
  1933. // Allocate and build a partial Mdl for the request.
  1934. //
  1935. Mdl = IoAllocateMdl( ThisIoRun->TransferVirtualAddress,
  1936. RawByteCount,
  1937. FALSE,
  1938. FALSE,
  1939. Irp );
  1940. if (Mdl == NULL) {
  1941. IrpContext->Irp->IoStatus.Information = 0;
  1942. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1943. }
  1944. IoBuildPartialMdl( ThisIoRun->TransferMdl,
  1945. Mdl,
  1946. ThisIoRun->TransferVirtualAddress,
  1947. RawByteCount);
  1948. //
  1949. // Get the first IRP stack location in the associated Irp
  1950. //
  1951. IoSetNextIrpStackLocation( Irp );
  1952. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1953. //
  1954. // Setup the Stack location to describe our read (using cooked values)
  1955. // These values won't be used for the raw read in any case.
  1956. //
  1957. IrpSp->MajorFunction = IRP_MJ_READ;
  1958. IrpSp->Parameters.Read.Length = ThisIoRun->DiskByteCount;
  1959. IrpSp->Parameters.Read.ByteOffset.QuadPart = ThisIoRun->DiskOffset;
  1960. //
  1961. // Set up the completion routine address in our stack frame.
  1962. //
  1963. IoSetCompletionRoutine( Irp,
  1964. CdMultiSyncCompletionRoutine,
  1965. IrpContext->IoContext,
  1966. TRUE,
  1967. TRUE,
  1968. TRUE );
  1969. //
  1970. // Setup the next IRP stack location in the associated Irp for the disk
  1971. // driver beneath us.
  1972. //
  1973. IrpSp = IoGetNextIrpStackLocation( Irp );
  1974. //
  1975. // Setup the stack location to do a read of raw sectors at this location.
  1976. // Note that the storage stack always reads multiples of whole XA sectors.
  1977. //
  1978. ThisRawRead->DiskOffset.QuadPart = ThisIoRun->DiskOffset;
  1979. ThisRawRead->SectorCount = ThisIoRun->DiskByteCount >> SECTOR_SHIFT;
  1980. ThisRawRead->TrackMode = TrackMode;
  1981. IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1982. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = ThisRawRead->SectorCount * RAW_SECTOR_SIZE;
  1983. Irp->UserBuffer = ThisIoRun->TransferVirtualAddress;
  1984. IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof( RAW_READ_INFO );
  1985. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ThisRawRead;
  1986. IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_CDROM_RAW_READ;
  1987. }
  1988. //
  1989. // We only need to set the associated IRP count in the master irp to
  1990. // make it a master IRP. But we set the count to one more than our
  1991. // caller requested, because we do not want the I/O system to complete
  1992. // the I/O. We also set our own count.
  1993. //
  1994. IrpContext->IoContext->IrpCount = RunCount;
  1995. IrpContext->IoContext->MasterIrp = MasterIrp;
  1996. //
  1997. // We set the count in the master Irp to 1 since typically we
  1998. // will clean up the associated irps ourselves. Setting this to one
  1999. // means completing the last associated Irp with SUCCESS (in the async
  2000. // case) will complete the master irp.
  2001. //
  2002. MasterIrp->AssociatedIrp.IrpCount = 1;
  2003. //
  2004. // Now that all the dangerous work is done, issue the Io requests
  2005. //
  2006. for (UnwindRunCount = 0;
  2007. UnwindRunCount < RunCount;
  2008. UnwindRunCount++) {
  2009. Irp = IoRuns[UnwindRunCount].SavedIrp;
  2010. IoRuns[UnwindRunCount].SavedIrp = NULL;
  2011. //
  2012. //
  2013. // If IoCallDriver returns an error, it has completed the Irp
  2014. // and the error will be caught by our completion routines
  2015. // and dealt with as a normal IO error.
  2016. //
  2017. (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
  2018. }
  2019. return;
  2020. }
  2021. //
  2022. // Local support routine
  2023. //
  2024. VOID
  2025. CdSingleAsync (
  2026. IN PIRP_CONTEXT IrpContext,
  2027. IN LONGLONG ByteOffset,
  2028. IN ULONG ByteCount
  2029. )
  2030. /*++
  2031. Routine Description:
  2032. This routine reads one or more contiguous sectors from a device
  2033. asynchronously, and is used if there is only one read necessary to
  2034. complete the IRP. It implements the read by simply filling
  2035. in the next stack frame in the Irp, and passing it on. The transfer
  2036. occurs to the single buffer originally specified in the user request.
  2037. Arguments:
  2038. ByteOffset - Supplies the starting Logical Byte Offset to begin reading from
  2039. ByteCount - Supplies the number of bytes to read from the device
  2040. Return Value:
  2041. None.
  2042. --*/
  2043. {
  2044. PIO_STACK_LOCATION IrpSp;
  2045. PIO_COMPLETION_ROUTINE CompletionRoutine;
  2046. PAGED_CODE();
  2047. //
  2048. // Set up things according to whether this is truely async.
  2049. //
  2050. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  2051. CompletionRoutine = CdSingleSyncCompletionRoutine;
  2052. } else {
  2053. CompletionRoutine = CdSingleAsyncCompletionRoutine;
  2054. }
  2055. //
  2056. // Set up the completion routine address in our stack frame.
  2057. //
  2058. IoSetCompletionRoutine( IrpContext->Irp,
  2059. CompletionRoutine,
  2060. IrpContext->IoContext,
  2061. TRUE,
  2062. TRUE,
  2063. TRUE );
  2064. //
  2065. // Setup the next IRP stack location in the associated Irp for the disk
  2066. // driver beneath us.
  2067. //
  2068. IrpSp = IoGetNextIrpStackLocation( IrpContext->Irp );
  2069. //
  2070. // Setup the Stack location to do a read from the disk driver.
  2071. //
  2072. IrpSp->MajorFunction = IRP_MJ_READ;
  2073. IrpSp->Parameters.Read.Length = ByteCount;
  2074. IrpSp->Parameters.Read.ByteOffset.QuadPart = ByteOffset;
  2075. //
  2076. // Issue the Io request
  2077. //
  2078. //
  2079. // If IoCallDriver returns an error, it has completed the Irp
  2080. // and the error will be caught by our completion routines
  2081. // and dealt with as a normal IO error.
  2082. //
  2083. (VOID)IoCallDriver( IrpContext->Vcb->TargetDeviceObject, IrpContext->Irp );
  2084. //
  2085. // And return to our caller
  2086. //
  2087. return;
  2088. }
  2089. //
  2090. // Local support routine
  2091. //
  2092. VOID
  2093. CdWaitSync (
  2094. IN PIRP_CONTEXT IrpContext
  2095. )
  2096. /*++
  2097. Routine Description:
  2098. This routine waits for one or more previously started I/O requests
  2099. from the above routines, by simply waiting on the event.
  2100. Arguments:
  2101. Return Value:
  2102. None
  2103. --*/
  2104. {
  2105. PAGED_CODE();
  2106. KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent,
  2107. Executive,
  2108. KernelMode,
  2109. FALSE,
  2110. NULL );
  2111. KeClearEvent( &IrpContext->IoContext->SyncEvent );
  2112. return;
  2113. }
  2114. //
  2115. // Local support routine
  2116. //
  2117. NTSTATUS
  2118. CdMultiSyncCompletionRoutine (
  2119. IN PDEVICE_OBJECT DeviceObject,
  2120. IN PIRP Irp,
  2121. IN PVOID Context
  2122. )
  2123. /*++
  2124. Routine Description:
  2125. This is the completion routine for all synchronous reads
  2126. started via CdMultipleAsynch.
  2127. The completion routine has has the following responsibilities:
  2128. If the individual request was completed with an error, then
  2129. this completion routine must see if this is the first error
  2130. and remember the error status in the Context.
  2131. If the IrpCount goes to 1, then it sets the event in the Context
  2132. parameter to signal the caller that all of the asynch requests
  2133. are done.
  2134. Arguments:
  2135. DeviceObject - Pointer to the file system device object.
  2136. Irp - Pointer to the associated Irp which is being completed. (This
  2137. Irp will no longer be accessible after this routine returns.)
  2138. Context - The context parameter which was specified for all of
  2139. the multiple asynch I/O requests for this MasterIrp.
  2140. Return Value:
  2141. The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
  2142. immediately complete the Master Irp without being in a race condition
  2143. with the IoCompleteRequest thread trying to decrement the IrpCount in
  2144. the Master Irp.
  2145. --*/
  2146. {
  2147. PCD_IO_CONTEXT IoContext = Context;
  2148. AssertVerifyDeviceIrp( Irp );
  2149. //
  2150. // If we got an error (or verify required), remember it in the Irp
  2151. //
  2152. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  2153. InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
  2154. IoContext->MasterIrp->IoStatus.Information = 0;
  2155. }
  2156. //
  2157. // We must do this here since IoCompleteRequest won't get a chance
  2158. // on this associated Irp.
  2159. //
  2160. IoFreeMdl( Irp->MdlAddress );
  2161. IoFreeIrp( Irp );
  2162. if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
  2163. //
  2164. // Update the Master Irp with any error status from the associated Irps.
  2165. //
  2166. IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
  2167. KeSetEvent( &IoContext->SyncEvent, 0, FALSE );
  2168. }
  2169. UNREFERENCED_PARAMETER( DeviceObject );
  2170. return STATUS_MORE_PROCESSING_REQUIRED;
  2171. }
  2172. //
  2173. // Local support routine
  2174. //
  2175. NTSTATUS
  2176. CdMultiAsyncCompletionRoutine (
  2177. IN PDEVICE_OBJECT DeviceObject,
  2178. IN PIRP Irp,
  2179. IN PVOID Context
  2180. )
  2181. /*++
  2182. Routine Description:
  2183. This is the completion routine for all asynchronous reads
  2184. started via CdMultipleAsynch.
  2185. The completion routine has has the following responsibilities:
  2186. If the individual request was completed with an error, then
  2187. this completion routine must see if this is the first error
  2188. and remember the error status in the Context.
  2189. Arguments:
  2190. DeviceObject - Pointer to the file system device object.
  2191. Irp - Pointer to the associated Irp which is being completed. (This
  2192. Irp will no longer be accessible after this routine returns.)
  2193. Context - The context parameter which was specified for all of
  2194. the multiple asynch I/O requests for this MasterIrp.
  2195. Return Value:
  2196. Currently always returns STATUS_SUCCESS.
  2197. --*/
  2198. {
  2199. PCD_IO_CONTEXT IoContext = Context;
  2200. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2201. AssertVerifyDeviceIrp( Irp );
  2202. //
  2203. // If we got an error (or verify required), remember it in the Irp
  2204. //
  2205. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  2206. InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
  2207. }
  2208. //
  2209. // Decrement IrpCount and see if it goes to zero.
  2210. //
  2211. if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
  2212. //
  2213. // Mark the master Irp pending
  2214. //
  2215. IoMarkIrpPending( IoContext->MasterIrp );
  2216. //
  2217. // Update the Master Irp with any error status from the associated Irps.
  2218. //
  2219. IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
  2220. //
  2221. // Update the information field with the correct value.
  2222. //
  2223. IoContext->MasterIrp->IoStatus.Information = 0;
  2224. if (NT_SUCCESS( IoContext->MasterIrp->IoStatus.Status )) {
  2225. IoContext->MasterIrp->IoStatus.Information = IoContext->RequestedByteCount;
  2226. }
  2227. //
  2228. // Now release the resource
  2229. //
  2230. ExReleaseResourceForThreadLite( IoContext->Resource,
  2231. IoContext->ResourceThreadId );
  2232. //
  2233. // and finally, free the context record.
  2234. //
  2235. CdFreeIoContext( IoContext );
  2236. //
  2237. // Return success in this case.
  2238. //
  2239. return STATUS_SUCCESS;
  2240. } else {
  2241. //
  2242. // We need to cleanup the associated Irp and its Mdl.
  2243. //
  2244. IoFreeMdl( Irp->MdlAddress );
  2245. IoFreeIrp( Irp );
  2246. return STATUS_MORE_PROCESSING_REQUIRED;
  2247. }
  2248. UNREFERENCED_PARAMETER( DeviceObject );
  2249. }
  2250. //
  2251. // Local support routine
  2252. //
  2253. NTSTATUS
  2254. CdSingleSyncCompletionRoutine (
  2255. IN PDEVICE_OBJECT DeviceObject,
  2256. IN PIRP Irp,
  2257. IN PVOID Context
  2258. )
  2259. /*++
  2260. Routine Description:
  2261. This is the completion routine for all reads started via CdSingleAsynch.
  2262. The completion routine has has the following responsibilities:
  2263. It sets the event in the Context parameter to signal the caller
  2264. that all of the asynch requests are done.
  2265. Arguments:
  2266. DeviceObject - Pointer to the file system device object.
  2267. Irp - Pointer to the Irp for this request. (This Irp will no longer
  2268. be accessible after this routine returns.)
  2269. Context - The context parameter which was specified in the call to
  2270. CdSingleAsynch.
  2271. Return Value:
  2272. The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
  2273. immediately complete the Master Irp without being in a race condition
  2274. with the IoCompleteRequest thread trying to decrement the IrpCount in
  2275. the Master Irp.
  2276. --*/
  2277. {
  2278. AssertVerifyDeviceIrp( Irp );
  2279. //
  2280. // Store the correct information field into the Irp.
  2281. //
  2282. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  2283. Irp->IoStatus.Information = 0;
  2284. }
  2285. KeSetEvent( &((PCD_IO_CONTEXT)Context)->SyncEvent, 0, FALSE );
  2286. return STATUS_MORE_PROCESSING_REQUIRED;
  2287. }
  2288. //
  2289. // Local support routine
  2290. //
  2291. NTSTATUS
  2292. CdSingleAsyncCompletionRoutine (
  2293. IN PDEVICE_OBJECT DeviceObject,
  2294. IN PIRP Irp,
  2295. IN PVOID Context
  2296. )
  2297. /*++
  2298. Routine Description:
  2299. This is the completion routine for all asynchronous reads
  2300. started via CdSingleAsynch.
  2301. Arguments:
  2302. DeviceObject - Pointer to the file system device object.
  2303. Irp - Pointer to the Irp for this request. (This Irp will no longer
  2304. be accessible after this routine returns.)
  2305. Context - The context parameter which was specified in the call to
  2306. CdSingleAsynch.
  2307. Return Value:
  2308. Currently always returns STATUS_SUCCESS.
  2309. --*/
  2310. {
  2311. AssertVerifyDeviceIrp( Irp );
  2312. //
  2313. // Update the information field with the correct value for bytes read.
  2314. //
  2315. Irp->IoStatus.Information = 0;
  2316. if (NT_SUCCESS( Irp->IoStatus.Status )) {
  2317. Irp->IoStatus.Information = ((PCD_IO_CONTEXT) Context)->RequestedByteCount;
  2318. }
  2319. //
  2320. // Mark the Irp pending
  2321. //
  2322. IoMarkIrpPending( Irp );
  2323. //
  2324. // Now release the resource
  2325. //
  2326. ExReleaseResourceForThreadLite( ((PCD_IO_CONTEXT) Context)->Resource,
  2327. ((PCD_IO_CONTEXT) Context)->ResourceThreadId );
  2328. //
  2329. // and finally, free the context record.
  2330. //
  2331. CdFreeIoContext( (PCD_IO_CONTEXT) Context );
  2332. return STATUS_SUCCESS;
  2333. UNREFERENCED_PARAMETER( DeviceObject );
  2334. }
  2335. //
  2336. // Local support routine
  2337. //
  2338. VOID
  2339. CdReadAudioSystemFile (
  2340. IN PIRP_CONTEXT IrpContext,
  2341. IN PFCB Fcb,
  2342. IN LONGLONG StartingOffset,
  2343. IN ULONG ByteCount,
  2344. IN PVOID SystemBuffer
  2345. )
  2346. /*++
  2347. Routine Description:
  2348. This routine is called to read the pseudo root directory and path
  2349. table for a music disk. We build the individual elements on the
  2350. stack and copy into the cache buffer.
  2351. Arguments:
  2352. Fcb - Fcb representing the file to read.
  2353. StartingOffset - Logical offset in the file to read from.
  2354. ByteCount - Number of bytes to read.
  2355. SystemBuffer - Pointer to buffer to fill in. This will always be page
  2356. aligned.
  2357. Return Value:
  2358. None.
  2359. --*/
  2360. {
  2361. PRAW_PATH_ISO RawPath;
  2362. PRAW_DIRENT RawDirent;
  2363. ULONG CurrentTrack;
  2364. ULONG SectorOffset;
  2365. ULONG EntryCount;
  2366. UCHAR TrackOnes;
  2367. UCHAR TrackTens;
  2368. PTRACK_DATA ThisTrack;
  2369. LONGLONG CurrentOffset;
  2370. PVOID CurrentSector;
  2371. PSYSTEM_USE_XA SystemUse;
  2372. ULONG BytesToCopy;
  2373. UCHAR LocalBuffer[FIELD_OFFSET( RAW_DIRENT, FileId ) + 12];
  2374. PAGED_CODE();
  2375. //
  2376. // If this is the path table then we just need a single entry.
  2377. //
  2378. if (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE) {
  2379. //
  2380. // Sanity check that the offset is zero.
  2381. //
  2382. ASSERT( StartingOffset == 0 );
  2383. //
  2384. // Store a pseudo path entry in our local buffer.
  2385. //
  2386. RawPath = (PRAW_PATH_ISO) LocalBuffer;
  2387. RtlZeroMemory( RawPath, sizeof( LocalBuffer ));
  2388. RawPath->DirIdLen = 1;
  2389. RawPath->ParentNum = 1;
  2390. RawPath->DirId[0] = '\0';
  2391. //
  2392. // Now copy to the user's buffer.
  2393. //
  2394. BytesToCopy = FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2;
  2395. if (BytesToCopy > ByteCount) {
  2396. BytesToCopy = ByteCount;
  2397. }
  2398. RtlCopyMemory( SystemBuffer,
  2399. RawPath,
  2400. BytesToCopy );
  2401. //
  2402. // We need to deal with the multiple sector case for the root directory.
  2403. //
  2404. } else {
  2405. //
  2406. // Initialize the first track to return to our caller.
  2407. //
  2408. CurrentTrack = 0;
  2409. //
  2410. // If the offset is zero then store the entries for the self and parent
  2411. // entries.
  2412. //
  2413. if (StartingOffset == 0) {
  2414. RawDirent = SystemBuffer;
  2415. //
  2416. // Clear all of the fields initially.
  2417. //
  2418. RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
  2419. //
  2420. // Now fill in the interesting fields.
  2421. //
  2422. RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
  2423. RawDirent->FileIdLen = 1;
  2424. RawDirent->FileId[0] = '\0';
  2425. SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
  2426. //
  2427. // Set the time stamp to be Jan 1, 1995
  2428. //
  2429. RawDirent->RecordTime[0] = 95;
  2430. RawDirent->RecordTime[1] = 1;
  2431. RawDirent->RecordTime[2] = 1;
  2432. SectorOffset = RawDirent->DirLen;
  2433. RawDirent = Add2Ptr( RawDirent, SectorOffset, PRAW_DIRENT );
  2434. //
  2435. // Clear all of the fields initially.
  2436. //
  2437. RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
  2438. //
  2439. // Now fill in the interesting fields.
  2440. //
  2441. RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
  2442. RawDirent->FileIdLen = 1;
  2443. RawDirent->FileId[0] = '\1';
  2444. SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
  2445. //
  2446. // Set the time stamp to be Jan 1, 1995
  2447. //
  2448. RawDirent->RecordTime[0] = 95;
  2449. RawDirent->RecordTime[1] = 1;
  2450. RawDirent->RecordTime[2] = 1;
  2451. SectorOffset += RawDirent->DirLen;
  2452. EntryCount = 2;
  2453. //
  2454. // Otherwise compute the starting track to write to the buffer.
  2455. //
  2456. } else {
  2457. //
  2458. // Count the tracks in each preceding sector.
  2459. //
  2460. CurrentOffset = 0;
  2461. do {
  2462. CurrentTrack += CdAudioDirentsPerSector;
  2463. CurrentOffset += SECTOR_SIZE;
  2464. } while (CurrentOffset < StartingOffset);
  2465. //
  2466. // Bias the track count to reflect the two default entries.
  2467. //
  2468. CurrentTrack -= 2;
  2469. SectorOffset = 0;
  2470. EntryCount = 0;
  2471. }
  2472. //
  2473. // We now know the first track to return as well as where we are in
  2474. // the current sector. We will walk through sector by sector adding
  2475. // the entries for the separate tracks in the TOC. We will zero
  2476. // any sectors or partial sectors without data.
  2477. //
  2478. CurrentSector = SystemBuffer;
  2479. BytesToCopy = SECTOR_SIZE;
  2480. //
  2481. // Loop for each sector.
  2482. //
  2483. do {
  2484. //
  2485. // Add entries until we reach our threshold for each sector.
  2486. //
  2487. do {
  2488. //
  2489. // If we are beyond the entries in the TOC then exit.
  2490. //
  2491. if (CurrentTrack >= IrpContext->Vcb->TrackCount) {
  2492. break;
  2493. }
  2494. ThisTrack = &IrpContext->Vcb->CdromToc->TrackData[CurrentTrack];
  2495. //
  2496. // Point to the current position in the buffer.
  2497. //
  2498. RawDirent = Add2Ptr( CurrentSector, SectorOffset, PRAW_DIRENT );
  2499. //
  2500. // Clear all of the fields initially.
  2501. //
  2502. RtlZeroMemory( RawDirent, CdAudioDirentSize );
  2503. //
  2504. // Now fill in the interesting fields.
  2505. //
  2506. RawDirent->DirLen = (UCHAR) CdAudioDirentSize;
  2507. RawDirent->FileIdLen = CdAudioFileNameLength;
  2508. RtlCopyMemory( RawDirent->FileId,
  2509. CdAudioFileName,
  2510. CdAudioFileNameLength );
  2511. //
  2512. // Set the time stamp to be Jan 1, 1995
  2513. //
  2514. RawDirent->RecordTime[0] = 95;
  2515. RawDirent->RecordTime[1] = 1;
  2516. RawDirent->RecordTime[2] = 1;
  2517. //
  2518. // Now bias by the values in the TOC.
  2519. //
  2520. RawDirent->RecordTime[4] = ThisTrack->Address[1] % 60;
  2521. RawDirent->RecordTime[5] = ThisTrack->Address[2] % 60;
  2522. //
  2523. // Put the track number into the file name.
  2524. //
  2525. TrackTens = TrackOnes = ThisTrack->TrackNumber;
  2526. TrackOnes = (TrackOnes % 10) + '0';
  2527. TrackTens /= 10;
  2528. TrackTens = (TrackTens % 10) + '0';
  2529. RawDirent->FileId[AUDIO_NAME_TENS_OFFSET] = TrackTens;
  2530. RawDirent->FileId[AUDIO_NAME_ONES_OFFSET] = TrackOnes;
  2531. SystemUse = Add2Ptr( RawDirent, CdAudioSystemUseOffset, PSYSTEM_USE_XA );
  2532. SystemUse->Attributes = SYSTEM_USE_XA_DA;
  2533. SystemUse->Signature = SYSTEM_XA_SIGNATURE;
  2534. //
  2535. // Store the track number as the file number.
  2536. //
  2537. SystemUse->FileNumber = (UCHAR) CurrentTrack;
  2538. EntryCount += 1;
  2539. SectorOffset += CdAudioDirentSize;
  2540. CurrentTrack += 1;
  2541. } while (EntryCount < CdAudioDirentsPerSector);
  2542. //
  2543. // Zero the remaining portion of this buffer.
  2544. //
  2545. RtlZeroMemory( Add2Ptr( CurrentSector, SectorOffset, PVOID ),
  2546. SECTOR_SIZE - SectorOffset );
  2547. //
  2548. // Prepare for the next sector.
  2549. //
  2550. EntryCount = 0;
  2551. BytesToCopy += SECTOR_SIZE;
  2552. SectorOffset = 0;
  2553. CurrentSector = Add2Ptr( CurrentSector, SECTOR_SIZE, PVOID );
  2554. } while (BytesToCopy <= ByteCount);
  2555. }
  2556. return;
  2557. }