Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3611 lines
103 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. //
  1301. // Prefix/fast: Note that the following are safe since we only
  1302. // take this path for 32bit offsets.
  1303. //
  1304. CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE);
  1305. CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT );
  1306. CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE);
  1307. //
  1308. // Otherwise we need to do 64-bit math (sigh).
  1309. //
  1310. } else {
  1311. CurrentRawOffset /= RAW_SECTOR_SIZE;
  1312. CurrentCookedOffset = CurrentRawOffset << SECTOR_SHIFT;
  1313. CurrentRawOffset *= RAW_SECTOR_SIZE;
  1314. }
  1315. //
  1316. // Now compute the full number of sectors to be read. Count all of the raw
  1317. // sectors that need to be read and convert to cooked bytes.
  1318. //
  1319. RawSectorOffset = (ULONG) ( StartingOffset - CurrentRawOffset) - sizeof( RIFF_HEADER );
  1320. CurrentRawByteCount = (RawSectorOffset + RemainingRawByteCount + RAW_SECTOR_SIZE - 1) / RAW_SECTOR_SIZE;
  1321. RemainingCookedByteCount = CurrentRawByteCount << SECTOR_SHIFT;
  1322. //
  1323. // Initialize the RunCount and ByteCount.
  1324. //
  1325. *RunCount = 0;
  1326. *ThisByteCount = 0;
  1327. //
  1328. // Loop while there are more bytes to process or there are
  1329. // available entries in the IoRun array.
  1330. //
  1331. while (TRUE) {
  1332. PerformedCopy = FALSE;
  1333. *RunCount += 1;
  1334. //
  1335. // Round the scratch buffer up to a sector boundary for alignment.
  1336. //
  1337. if (RoundScratchBuffer) {
  1338. if (SectorOffset( ScratchUserBuffer ) != 0) {
  1339. CurrentRawByteCount = SECTOR_SIZE - SectorOffset( ScratchUserBuffer );
  1340. ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
  1341. CurrentRawByteCount,
  1342. PVOID );
  1343. ScratchUserBufferOffset += CurrentRawByteCount;
  1344. }
  1345. RoundScratchBuffer = FALSE;
  1346. }
  1347. //
  1348. // Initialize the current position in the IoRuns array. Find the
  1349. // eventual destination in the user's buffer for this portion of the transfer.
  1350. //
  1351. ThisIoRun->UserBuffer = CurrentUserBuffer;
  1352. //
  1353. // Find the allocation information for the current offset in the
  1354. // stream.
  1355. //
  1356. CdLookupAllocation( IrpContext,
  1357. Fcb,
  1358. CurrentCookedOffset,
  1359. &DiskOffset,
  1360. &CurrentCookedByteCount );
  1361. //
  1362. // Maybe we got lucky and this is the same sector as in the
  1363. // Vcb.
  1364. //
  1365. if (DiskOffset == Fcb->Vcb->XADiskOffset) {
  1366. //
  1367. // We will perform safe synchronization. Check again that
  1368. // this is the correct sector.
  1369. //
  1370. CdLockVcb( IrpContext, Fcb->Vcb );
  1371. if ((DiskOffset == Fcb->Vcb->XADiskOffset) &&
  1372. (Fcb->Vcb->XASector != NULL)) {
  1373. //
  1374. // Copy any bytes we can from the current sector.
  1375. //
  1376. CurrentRawByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
  1377. //
  1378. // Check whether we don't go to the end of the sector.
  1379. //
  1380. if (CurrentRawByteCount > RemainingRawByteCount) {
  1381. CurrentRawByteCount = RemainingRawByteCount;
  1382. }
  1383. RtlCopyMemory( CurrentUserBuffer,
  1384. Add2Ptr( Fcb->Vcb->XASector, RawSectorOffset, PCHAR ),
  1385. CurrentRawByteCount );
  1386. CdUnlockVcb( IrpContext, Fcb->Vcb );
  1387. //
  1388. // Adjust the run count and pointer in the IoRuns array
  1389. // to show that we didn't use a position.
  1390. //
  1391. *RunCount -= 1;
  1392. ThisIoRun -= 1;
  1393. //
  1394. // Remember that we performed a copy operation and update
  1395. // the next available position in the scratch buffer.
  1396. //
  1397. PerformedCopy = TRUE;
  1398. ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
  1399. CurrentRawByteCount,
  1400. PVOID );
  1401. ScratchUserBufferOffset += CurrentRawByteCount;
  1402. CurrentCookedByteCount = SECTOR_SIZE;
  1403. //
  1404. // Set the flag indicating we want to round the scratch buffer
  1405. // to a sector boundary.
  1406. //
  1407. RoundScratchBuffer = TRUE;
  1408. } else {
  1409. //
  1410. // The safe test showed no available buffer. Drop down to common code to
  1411. // perform the Io.
  1412. //
  1413. CdUnlockVcb( IrpContext, Fcb->Vcb );
  1414. }
  1415. }
  1416. //
  1417. // No work in this pass if we did a copy operation.
  1418. //
  1419. if (!PerformedCopy) {
  1420. //
  1421. // Limit ourselves by the number of remaining cooked bytes.
  1422. //
  1423. if (CurrentCookedByteCount > RemainingCookedByteCount) {
  1424. CurrentCookedByteCount = RemainingCookedByteCount;
  1425. }
  1426. ThisIoRun->DiskOffset = DiskOffset;
  1427. ThisIoRun->TransferBufferOffset = RawSectorOffset;
  1428. //
  1429. // We will always need to perform copy operations for XA files.
  1430. // We allocate an auxillary buffer to read the start of the
  1431. // transfer. Then we can use a range of the user's buffer to
  1432. // perform the next range of the transfer. Finally we may
  1433. // need to allocate a buffer for the tail of the transfer.
  1434. //
  1435. // We can use the user's buffer (at the current scratch buffer) if the
  1436. // following are true:
  1437. //
  1438. // If we are to store the beginning of the raw sector in the user's buffer.
  1439. // The current scratch buffer precedes the destination in the user's buffer
  1440. // (and hence also lies within it)
  1441. // There are enough bytes remaining in the buffer for at least one
  1442. // raw sector.
  1443. //
  1444. if ((RawSectorOffset == 0) &&
  1445. (ScratchUserBufferOffset <= CurrentUserBufferOffset) &&
  1446. (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount >= RAW_SECTOR_SIZE)) {
  1447. //
  1448. // We can use the scratch buffer. We must ensure we don't send down reads
  1449. // greater than the device can handle, since the driver is unable to split
  1450. // raw requests.
  1451. //
  1452. if (CurrentCookedByteCount <= Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE) {
  1453. CurrentRawByteCount = (SectorAlign( CurrentCookedByteCount) >> SECTOR_SHIFT) * RAW_SECTOR_SIZE;
  1454. } else {
  1455. CurrentCookedByteCount = Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE;
  1456. CurrentRawByteCount = Fcb->Vcb->MaximumTransferRawSectors * RAW_SECTOR_SIZE;
  1457. }
  1458. //
  1459. // Now make sure we are within the page transfer limit.
  1460. //
  1461. while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(ScratchUserBuffer, RawSectorAlign( CurrentRawByteCount)) >
  1462. Fcb->Vcb->MaximumPhysicalPages ) {
  1463. CurrentRawByteCount -= RAW_SECTOR_SIZE;
  1464. CurrentCookedByteCount -= SECTOR_SIZE;
  1465. }
  1466. //
  1467. // Trim the number of bytes to read if it won't fit into the current buffer. Take
  1468. // account of the fact that we must read in whole raw sector multiples.
  1469. //
  1470. while ( RawSectorAlign( CurrentRawByteCount) >
  1471. (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount) ) {
  1472. CurrentRawByteCount -= RAW_SECTOR_SIZE;
  1473. CurrentCookedByteCount -= SECTOR_SIZE;
  1474. }
  1475. //
  1476. // Now trim the maximum number of raw bytes to the remaining bytes.
  1477. //
  1478. if (CurrentRawByteCount > RemainingRawByteCount) {
  1479. CurrentRawByteCount = RemainingRawByteCount;
  1480. }
  1481. //
  1482. // Update the IO run array. We point to the scratch buffer as
  1483. // well as the buffer and Mdl in the original Irp.
  1484. //
  1485. ThisIoRun->DiskByteCount = SectorAlign( CurrentCookedByteCount);
  1486. //
  1487. // Store the number of bytes which we actually care about from this transfer
  1488. //
  1489. ThisIoRun->TransferByteCount = CurrentRawByteCount;
  1490. //
  1491. // Point to the user's buffer and Mdl for this transfer.
  1492. //
  1493. ThisIoRun->TransferBuffer = ScratchUserBuffer;
  1494. ThisIoRun->TransferMdl = Irp->MdlAddress;
  1495. ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
  1496. ScratchUserBufferOffset,
  1497. PVOID);
  1498. //
  1499. // Update the scratch buffer pointer. Note that since the underlying
  1500. // driver stack will always transfer in multiples of raw sectors,
  1501. // we must round up here rather than simply advancing by the length of the
  1502. // of the data which we actually care about.
  1503. //
  1504. ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
  1505. RawSectorAlign( CurrentRawByteCount),
  1506. PVOID );
  1507. ScratchUserBufferOffset += RawSectorAlign( CurrentRawByteCount);;
  1508. //
  1509. // Set the flag indicating we want to round the scratch buffer
  1510. // to a cooked sector boundary.
  1511. //
  1512. RoundScratchBuffer = TRUE;
  1513. } else {
  1514. //
  1515. // We need to determine the number of bytes to transfer and the
  1516. // offset into this page to begin the transfer.
  1517. //
  1518. // We will transfer only one raw sector.
  1519. //
  1520. ThisIoRun->DiskByteCount = SECTOR_SIZE;
  1521. CurrentCookedByteCount = SECTOR_SIZE;
  1522. ThisIoRun->TransferByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
  1523. ThisIoRun->TransferBufferOffset = RawSectorOffset;
  1524. if (ThisIoRun->TransferByteCount > RemainingRawByteCount) {
  1525. ThisIoRun->TransferByteCount = RemainingRawByteCount;
  1526. }
  1527. CurrentRawByteCount = ThisIoRun->TransferByteCount;
  1528. //
  1529. // We need to allocate an auxillary buffer. We will allocate
  1530. // a single page. Then we will build an Mdl to describe the buffer.
  1531. //
  1532. ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
  1533. //
  1534. // Allocate and build the Mdl to describe this buffer.
  1535. //
  1536. ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
  1537. PAGE_SIZE,
  1538. FALSE,
  1539. FALSE,
  1540. NULL );
  1541. ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
  1542. if (ThisIoRun->TransferMdl == NULL) {
  1543. IrpContext->Irp->IoStatus.Information = 0;
  1544. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1545. }
  1546. MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
  1547. }
  1548. }
  1549. //
  1550. // Update the byte count for our caller.
  1551. //
  1552. RemainingRawByteCount -= CurrentRawByteCount;
  1553. *ThisByteCount += CurrentRawByteCount;
  1554. //
  1555. // Break out if no more positions in the IoRuns array or
  1556. // we have all of the bytes accounted for.
  1557. //
  1558. if ((RemainingRawByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
  1559. break;
  1560. }
  1561. //
  1562. // Update our local pointers to allow for the current range of bytes.
  1563. //
  1564. ThisIoRun += 1;
  1565. CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentRawByteCount, PVOID );
  1566. CurrentUserBufferOffset += CurrentRawByteCount;
  1567. RawSectorOffset = 0;
  1568. CurrentCookedOffset += CurrentCookedByteCount;
  1569. RemainingCookedByteCount -= CurrentCookedByteCount;
  1570. }
  1571. return;
  1572. }
  1573. //
  1574. // Local support routine
  1575. //
  1576. BOOLEAN
  1577. CdFinishBuffers (
  1578. IN PIRP_CONTEXT IrpContext,
  1579. IN PIO_RUN IoRuns,
  1580. IN ULONG RunCount,
  1581. IN BOOLEAN FinalCleanup,
  1582. IN BOOLEAN SaveXABuffer
  1583. )
  1584. /*++
  1585. Routine Description:
  1586. This routine is called to perform any data transferred required for
  1587. unaligned Io or to perform the final cleanup of the IoRuns array.
  1588. In all cases this is where we will deallocate any buffer and mdl
  1589. allocated to perform the unaligned transfer. If this is not the
  1590. final cleanup then we also transfer the bytes to the user buffer
  1591. and flush the hardware cache.
  1592. We walk backwards through the run array because we may be shifting data
  1593. in the user's buffer. Typical case is where we allocated a buffer for
  1594. the first part of a read and then used the user's buffer for the
  1595. next section (but stored it at the beginning of the buffer.
  1596. Arguments:
  1597. IoRuns - Pointer to the IoRuns array.
  1598. RunCount - Number of entries in the IoRuns array filled here.
  1599. FinalCleanup - Indicates if we should be deallocating temporary buffers
  1600. (TRUE) or transferring bytes for a unaligned transfers and
  1601. deallocating the buffers (FALSE). Flush the system cache if
  1602. transferring data.
  1603. SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise
  1604. Return Value:
  1605. BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
  1606. --*/
  1607. {
  1608. BOOLEAN FlushIoBuffers = FALSE;
  1609. ULONG RemainingEntries = RunCount;
  1610. PIO_RUN ThisIoRun = &IoRuns[RunCount - 1];
  1611. PVCB Vcb;
  1612. PAGED_CODE();
  1613. //
  1614. // Walk through each entry in the IoRun array.
  1615. //
  1616. while (RemainingEntries != 0) {
  1617. //
  1618. // We only need to deal with the case of an unaligned transfer.
  1619. //
  1620. if (ThisIoRun->TransferByteCount != 0) {
  1621. //
  1622. // If not the final cleanup then transfer the data to the
  1623. // user's buffer and remember that we will need to flush
  1624. // the user's buffer to memory.
  1625. //
  1626. if (!FinalCleanup) {
  1627. //
  1628. // If we are shifting in the user's buffer then use
  1629. // MoveMemory.
  1630. //
  1631. if (ThisIoRun->TransferMdl == IrpContext->Irp->MdlAddress) {
  1632. RtlMoveMemory( ThisIoRun->UserBuffer,
  1633. Add2Ptr( ThisIoRun->TransferBuffer,
  1634. ThisIoRun->TransferBufferOffset,
  1635. PVOID ),
  1636. ThisIoRun->TransferByteCount );
  1637. } else {
  1638. RtlCopyMemory( ThisIoRun->UserBuffer,
  1639. Add2Ptr( ThisIoRun->TransferBuffer,
  1640. ThisIoRun->TransferBufferOffset,
  1641. PVOID ),
  1642. ThisIoRun->TransferByteCount );
  1643. }
  1644. FlushIoBuffers = TRUE;
  1645. }
  1646. //
  1647. // Free any Mdl we may have allocated. If the Mdl isn't
  1648. // present then we must have failed during the allocation
  1649. // phase.
  1650. //
  1651. if (ThisIoRun->TransferMdl != IrpContext->Irp->MdlAddress) {
  1652. if (ThisIoRun->TransferMdl != NULL) {
  1653. IoFreeMdl( ThisIoRun->TransferMdl );
  1654. }
  1655. //
  1656. // Now free any buffer we may have allocated. If the Mdl
  1657. // doesn't match the original Mdl then free the buffer.
  1658. //
  1659. if (ThisIoRun->TransferBuffer != NULL) {
  1660. //
  1661. // If this is the final buffer for an XA read then store this buffer
  1662. // into the Vcb so that we will have it when reading any remaining
  1663. // portion of this buffer.
  1664. //
  1665. if (SaveXABuffer) {
  1666. Vcb = IrpContext->Vcb;
  1667. CdLockVcb( IrpContext, Vcb );
  1668. if (Vcb->XASector != NULL) {
  1669. CdFreePool( &Vcb->XASector );
  1670. }
  1671. Vcb->XASector = ThisIoRun->TransferBuffer;
  1672. Vcb->XADiskOffset = ThisIoRun->DiskOffset;
  1673. SaveXABuffer = FALSE;
  1674. CdUnlockVcb( IrpContext, Vcb );
  1675. //
  1676. // Otherwise just free the buffer.
  1677. //
  1678. } else {
  1679. CdFreePool( &ThisIoRun->TransferBuffer );
  1680. }
  1681. }
  1682. }
  1683. }
  1684. //
  1685. // Now handle the case where we failed in the process
  1686. // of allocating associated Irps and Mdls.
  1687. //
  1688. if (ThisIoRun->SavedIrp != NULL) {
  1689. if (ThisIoRun->SavedIrp->MdlAddress != NULL) {
  1690. IoFreeMdl( ThisIoRun->SavedIrp->MdlAddress );
  1691. }
  1692. IoFreeIrp( ThisIoRun->SavedIrp );
  1693. }
  1694. //
  1695. // Move to the previous IoRun entry.
  1696. //
  1697. ThisIoRun -= 1;
  1698. RemainingEntries -= 1;
  1699. }
  1700. //
  1701. // If we copied any data then flush the Io buffers.
  1702. //
  1703. return FlushIoBuffers;
  1704. }
  1705. //
  1706. // Local support routine
  1707. //
  1708. VOID
  1709. CdMultipleAsync (
  1710. IN PIRP_CONTEXT IrpContext,
  1711. IN ULONG RunCount,
  1712. IN PIO_RUN IoRuns
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. This routine first does the initial setup required of a Master IRP that is
  1717. going to be completed using associated IRPs. This routine should not
  1718. be used if only one async request is needed, instead the single read
  1719. async routines should be called.
  1720. A context parameter is initialized, to serve as a communications area
  1721. between here and the common completion routine.
  1722. Next this routine reads or writes one or more contiguous sectors from
  1723. a device asynchronously, and is used if there are multiple reads for a
  1724. master IRP. A completion routine is used to synchronize with the
  1725. completion of all of the I/O requests started by calls to this routine.
  1726. Also, prior to calling this routine the caller must initialize the
  1727. IoStatus field in the Context, with the correct success status and byte
  1728. count which are expected if all of the parallel transfers complete
  1729. successfully. After return this status will be unchanged if all requests
  1730. were, in fact, successful. However, if one or more errors occur, the
  1731. IoStatus will be modified to reflect the error status and byte count
  1732. from the first run (by Vbo) which encountered an error. I/O status
  1733. from all subsequent runs will not be indicated.
  1734. Arguments:
  1735. RunCount - Supplies the number of multiple async requests
  1736. that will be issued against the master irp.
  1737. IoRuns - Supplies an array containing the Offset and ByteCount for the
  1738. separate requests.
  1739. Return Value:
  1740. None.
  1741. --*/
  1742. {
  1743. PIO_COMPLETION_ROUTINE CompletionRoutine;
  1744. PIO_STACK_LOCATION IrpSp;
  1745. PMDL Mdl;
  1746. PIRP Irp;
  1747. PIRP MasterIrp;
  1748. ULONG UnwindRunCount;
  1749. PAGED_CODE();
  1750. //
  1751. // Set up things according to whether this is truely async.
  1752. //
  1753. CompletionRoutine = CdMultiSyncCompletionRoutine;
  1754. if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  1755. CompletionRoutine = CdMultiAsyncCompletionRoutine;
  1756. }
  1757. //
  1758. // Initialize some local variables.
  1759. //
  1760. MasterIrp = IrpContext->Irp;
  1761. //
  1762. // Itterate through the runs, doing everything that can fail.
  1763. // We let the cleanup in CdFinishBuffers clean up on error.
  1764. //
  1765. for (UnwindRunCount = 0;
  1766. UnwindRunCount < RunCount;
  1767. UnwindRunCount += 1) {
  1768. //
  1769. // Create an associated IRP, making sure there is one stack entry for
  1770. // us, as well.
  1771. //
  1772. IoRuns[UnwindRunCount].SavedIrp =
  1773. Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
  1774. if (Irp == NULL) {
  1775. IrpContext->Irp->IoStatus.Information = 0;
  1776. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1777. }
  1778. //
  1779. // Allocate and build a partial Mdl for the request.
  1780. //
  1781. Mdl = IoAllocateMdl( IoRuns[UnwindRunCount].TransferVirtualAddress,
  1782. IoRuns[UnwindRunCount].DiskByteCount,
  1783. FALSE,
  1784. FALSE,
  1785. Irp );
  1786. if (Mdl == NULL) {
  1787. IrpContext->Irp->IoStatus.Information = 0;
  1788. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1789. }
  1790. IoBuildPartialMdl( IoRuns[UnwindRunCount].TransferMdl,
  1791. Mdl,
  1792. IoRuns[UnwindRunCount].TransferVirtualAddress,
  1793. IoRuns[UnwindRunCount].DiskByteCount );
  1794. //
  1795. // Get the first IRP stack location in the associated Irp
  1796. //
  1797. IoSetNextIrpStackLocation( Irp );
  1798. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1799. //
  1800. // Setup the Stack location to describe our read.
  1801. //
  1802. IrpSp->MajorFunction = IRP_MJ_READ;
  1803. IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
  1804. IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
  1805. //
  1806. // Set up the completion routine address in our stack frame.
  1807. //
  1808. IoSetCompletionRoutine( Irp,
  1809. CompletionRoutine,
  1810. IrpContext->IoContext,
  1811. TRUE,
  1812. TRUE,
  1813. TRUE );
  1814. //
  1815. // Setup the next IRP stack location in the associated Irp for the disk
  1816. // driver beneath us.
  1817. //
  1818. IrpSp = IoGetNextIrpStackLocation( Irp );
  1819. //
  1820. // Setup the Stack location to do a read from the disk driver.
  1821. //
  1822. IrpSp->MajorFunction = IRP_MJ_READ;
  1823. IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
  1824. IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
  1825. }
  1826. //
  1827. // We only need to set the associated IRP count in the master irp to
  1828. // make it a master IRP. But we set the count to one more than our
  1829. // caller requested, because we do not want the I/O system to complete
  1830. // the I/O. We also set our own count.
  1831. //
  1832. IrpContext->IoContext->IrpCount = RunCount;
  1833. IrpContext->IoContext->MasterIrp = MasterIrp;
  1834. //
  1835. // We set the count in the master Irp to 1 since typically we
  1836. // will clean up the associated irps ourselves. Setting this to one
  1837. // means completing the last associated Irp with SUCCESS (in the async
  1838. // case) will complete the master irp.
  1839. //
  1840. MasterIrp->AssociatedIrp.IrpCount = 1;
  1841. //
  1842. // Now that all the dangerous work is done, issue the Io requests
  1843. //
  1844. for (UnwindRunCount = 0;
  1845. UnwindRunCount < RunCount;
  1846. UnwindRunCount++) {
  1847. Irp = IoRuns[UnwindRunCount].SavedIrp;
  1848. IoRuns[UnwindRunCount].SavedIrp = NULL;
  1849. //
  1850. // If IoCallDriver returns an error, it has completed the Irp
  1851. // and the error will be caught by our completion routines
  1852. // and dealt with as a normal IO error.
  1853. //
  1854. (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
  1855. }
  1856. return;
  1857. }
  1858. //
  1859. // Local support routine
  1860. //
  1861. VOID
  1862. CdMultipleXAAsync (
  1863. IN PIRP_CONTEXT IrpContext,
  1864. IN ULONG RunCount,
  1865. IN PIO_RUN IoRuns,
  1866. IN PRAW_READ_INFO RawReads,
  1867. IN TRACK_MODE_TYPE TrackMode
  1868. )
  1869. /*++
  1870. Routine Description:
  1871. This routine first does the initial setup required of a Master IRP that is
  1872. going to be completed using associated IRPs. This routine is used to generate
  1873. the associated Irps used to read raw sectors from the disk.
  1874. A context parameter is initialized, to serve as a communications area
  1875. between here and the common completion routine.
  1876. Next this routine reads or writes one or more contiguous sectors from
  1877. a device asynchronously, and is used if there are multiple reads for a
  1878. master IRP. A completion routine is used to synchronize with the
  1879. completion of all of the I/O requests started by calls to this routine.
  1880. Also, prior to calling this routine the caller must initialize the
  1881. IoStatus field in the Context, with the correct success status and byte
  1882. count which are expected if all of the parallel transfers complete
  1883. successfully. After return this status will be unchanged if all requests
  1884. were, in fact, successful. However, if one or more errors occur, the
  1885. IoStatus will be modified to reflect the error status and byte count
  1886. from the first run (by Vbo) which encountered an error. I/O status
  1887. from all subsequent runs will not be indicated.
  1888. Arguments:
  1889. RunCount - Supplies the number of multiple async requests
  1890. that will be issued against the master irp.
  1891. IoRuns - Supplies an array containing the Offset and ByteCount for the
  1892. separate requests.
  1893. RawReads - Supplies an array of structures to store in the Irps passed to the
  1894. device driver to perform the low-level Io.
  1895. TrackMode - Supplies the recording mode of sectors in these IoRuns
  1896. Return Value:
  1897. None.
  1898. --*/
  1899. {
  1900. PIO_STACK_LOCATION IrpSp;
  1901. PMDL Mdl;
  1902. PIRP Irp;
  1903. PIRP MasterIrp;
  1904. ULONG UnwindRunCount;
  1905. ULONG RawByteCount;
  1906. PIO_RUN ThisIoRun = IoRuns;
  1907. PRAW_READ_INFO ThisRawRead = RawReads;
  1908. PAGED_CODE();
  1909. //
  1910. // Initialize some local variables.
  1911. //
  1912. MasterIrp = IrpContext->Irp;
  1913. //
  1914. // Itterate through the runs, doing everything that can fail.
  1915. // We let the cleanup in CdFinishBuffers clean up on error.
  1916. //
  1917. for (UnwindRunCount = 0;
  1918. UnwindRunCount < RunCount;
  1919. UnwindRunCount += 1, ThisIoRun += 1, ThisRawRead += 1) {
  1920. //
  1921. // Create an associated IRP, making sure there is one stack entry for
  1922. // us, as well.
  1923. //
  1924. ThisIoRun->SavedIrp =
  1925. Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
  1926. if (Irp == NULL) {
  1927. IrpContext->Irp->IoStatus.Information = 0;
  1928. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1929. }
  1930. //
  1931. // Should have been passed a byte count of at least one sector, and
  1932. // must be a multiple of sector size
  1933. //
  1934. ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount));
  1935. RawByteCount = SectorsFromBytes( ThisIoRun->DiskByteCount) * RAW_SECTOR_SIZE;
  1936. //
  1937. // Allocate and build a partial Mdl for the request.
  1938. //
  1939. Mdl = IoAllocateMdl( ThisIoRun->TransferVirtualAddress,
  1940. RawByteCount,
  1941. FALSE,
  1942. FALSE,
  1943. Irp );
  1944. if (Mdl == NULL) {
  1945. IrpContext->Irp->IoStatus.Information = 0;
  1946. CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
  1947. }
  1948. IoBuildPartialMdl( ThisIoRun->TransferMdl,
  1949. Mdl,
  1950. ThisIoRun->TransferVirtualAddress,
  1951. RawByteCount);
  1952. //
  1953. // Get the first IRP stack location in the associated Irp
  1954. //
  1955. IoSetNextIrpStackLocation( Irp );
  1956. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1957. //
  1958. // Setup the Stack location to describe our read (using cooked values)
  1959. // These values won't be used for the raw read in any case.
  1960. //
  1961. IrpSp->MajorFunction = IRP_MJ_READ;
  1962. IrpSp->Parameters.Read.Length = ThisIoRun->DiskByteCount;
  1963. IrpSp->Parameters.Read.ByteOffset.QuadPart = ThisIoRun->DiskOffset;
  1964. //
  1965. // Set up the completion routine address in our stack frame.
  1966. //
  1967. IoSetCompletionRoutine( Irp,
  1968. CdMultiSyncCompletionRoutine,
  1969. IrpContext->IoContext,
  1970. TRUE,
  1971. TRUE,
  1972. TRUE );
  1973. //
  1974. // Setup the next IRP stack location in the associated Irp for the disk
  1975. // driver beneath us.
  1976. //
  1977. IrpSp = IoGetNextIrpStackLocation( Irp );
  1978. //
  1979. // Setup the stack location to do a read of raw sectors at this location.
  1980. // Note that the storage stack always reads multiples of whole XA sectors.
  1981. //
  1982. ThisRawRead->DiskOffset.QuadPart = ThisIoRun->DiskOffset;
  1983. ThisRawRead->SectorCount = ThisIoRun->DiskByteCount >> SECTOR_SHIFT;
  1984. ThisRawRead->TrackMode = TrackMode;
  1985. IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  1986. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = ThisRawRead->SectorCount * RAW_SECTOR_SIZE;
  1987. Irp->UserBuffer = ThisIoRun->TransferVirtualAddress;
  1988. IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof( RAW_READ_INFO );
  1989. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ThisRawRead;
  1990. IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_CDROM_RAW_READ;
  1991. }
  1992. //
  1993. // We only need to set the associated IRP count in the master irp to
  1994. // make it a master IRP. But we set the count to one more than our
  1995. // caller requested, because we do not want the I/O system to complete
  1996. // the I/O. We also set our own count.
  1997. //
  1998. IrpContext->IoContext->IrpCount = RunCount;
  1999. IrpContext->IoContext->MasterIrp = MasterIrp;
  2000. //
  2001. // We set the count in the master Irp to 1 since typically we
  2002. // will clean up the associated irps ourselves. Setting this to one
  2003. // means completing the last associated Irp with SUCCESS (in the async
  2004. // case) will complete the master irp.
  2005. //
  2006. MasterIrp->AssociatedIrp.IrpCount = 1;
  2007. //
  2008. // Now that all the dangerous work is done, issue the Io requests
  2009. //
  2010. for (UnwindRunCount = 0;
  2011. UnwindRunCount < RunCount;
  2012. UnwindRunCount++) {
  2013. Irp = IoRuns[UnwindRunCount].SavedIrp;
  2014. IoRuns[UnwindRunCount].SavedIrp = NULL;
  2015. //
  2016. //
  2017. // If IoCallDriver returns an error, it has completed the Irp
  2018. // and the error will be caught by our completion routines
  2019. // and dealt with as a normal IO error.
  2020. //
  2021. (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
  2022. }
  2023. return;
  2024. }
  2025. //
  2026. // Local support routine
  2027. //
  2028. VOID
  2029. CdSingleAsync (
  2030. IN PIRP_CONTEXT IrpContext,
  2031. IN LONGLONG ByteOffset,
  2032. IN ULONG ByteCount
  2033. )
  2034. /*++
  2035. Routine Description:
  2036. This routine reads one or more contiguous sectors from a device
  2037. asynchronously, and is used if there is only one read necessary to
  2038. complete the IRP. It implements the read by simply filling
  2039. in the next stack frame in the Irp, and passing it on. The transfer
  2040. occurs to the single buffer originally specified in the user request.
  2041. Arguments:
  2042. ByteOffset - Supplies the starting Logical Byte Offset to begin reading from
  2043. ByteCount - Supplies the number of bytes to read from the device
  2044. Return Value:
  2045. None.
  2046. --*/
  2047. {
  2048. PIO_STACK_LOCATION IrpSp;
  2049. PIO_COMPLETION_ROUTINE CompletionRoutine;
  2050. PAGED_CODE();
  2051. //
  2052. // Set up things according to whether this is truely async.
  2053. //
  2054. if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
  2055. CompletionRoutine = CdSingleSyncCompletionRoutine;
  2056. } else {
  2057. CompletionRoutine = CdSingleAsyncCompletionRoutine;
  2058. }
  2059. //
  2060. // Set up the completion routine address in our stack frame.
  2061. //
  2062. IoSetCompletionRoutine( IrpContext->Irp,
  2063. CompletionRoutine,
  2064. IrpContext->IoContext,
  2065. TRUE,
  2066. TRUE,
  2067. TRUE );
  2068. //
  2069. // Setup the next IRP stack location in the associated Irp for the disk
  2070. // driver beneath us.
  2071. //
  2072. IrpSp = IoGetNextIrpStackLocation( IrpContext->Irp );
  2073. //
  2074. // Setup the Stack location to do a read from the disk driver.
  2075. //
  2076. IrpSp->MajorFunction = IRP_MJ_READ;
  2077. IrpSp->Parameters.Read.Length = ByteCount;
  2078. IrpSp->Parameters.Read.ByteOffset.QuadPart = ByteOffset;
  2079. //
  2080. // Issue the Io request
  2081. //
  2082. //
  2083. // If IoCallDriver returns an error, it has completed the Irp
  2084. // and the error will be caught by our completion routines
  2085. // and dealt with as a normal IO error.
  2086. //
  2087. (VOID)IoCallDriver( IrpContext->Vcb->TargetDeviceObject, IrpContext->Irp );
  2088. //
  2089. // And return to our caller
  2090. //
  2091. return;
  2092. }
  2093. //
  2094. // Local support routine
  2095. //
  2096. VOID
  2097. CdWaitSync (
  2098. IN PIRP_CONTEXT IrpContext
  2099. )
  2100. /*++
  2101. Routine Description:
  2102. This routine waits for one or more previously started I/O requests
  2103. from the above routines, by simply waiting on the event.
  2104. Arguments:
  2105. Return Value:
  2106. None
  2107. --*/
  2108. {
  2109. PAGED_CODE();
  2110. KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent,
  2111. Executive,
  2112. KernelMode,
  2113. FALSE,
  2114. NULL );
  2115. KeClearEvent( &IrpContext->IoContext->SyncEvent );
  2116. return;
  2117. }
  2118. //
  2119. // Local support routine
  2120. //
  2121. NTSTATUS
  2122. CdMultiSyncCompletionRoutine (
  2123. IN PDEVICE_OBJECT DeviceObject,
  2124. IN PIRP Irp,
  2125. IN PVOID Context
  2126. )
  2127. /*++
  2128. Routine Description:
  2129. This is the completion routine for all synchronous reads
  2130. started via CdMultipleAsynch.
  2131. The completion routine has has the following responsibilities:
  2132. If the individual request was completed with an error, then
  2133. this completion routine must see if this is the first error
  2134. and remember the error status in the Context.
  2135. If the IrpCount goes to 1, then it sets the event in the Context
  2136. parameter to signal the caller that all of the asynch requests
  2137. are done.
  2138. Arguments:
  2139. DeviceObject - Pointer to the file system device object.
  2140. Irp - Pointer to the associated Irp which is being completed. (This
  2141. Irp will no longer be accessible after this routine returns.)
  2142. Context - The context parameter which was specified for all of
  2143. the multiple asynch I/O requests for this MasterIrp.
  2144. Return Value:
  2145. The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
  2146. immediately complete the Master Irp without being in a race condition
  2147. with the IoCompleteRequest thread trying to decrement the IrpCount in
  2148. the Master Irp.
  2149. --*/
  2150. {
  2151. PCD_IO_CONTEXT IoContext = Context;
  2152. AssertVerifyDeviceIrp( Irp );
  2153. //
  2154. // If we got an error (or verify required), remember it in the Irp
  2155. //
  2156. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  2157. InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
  2158. IoContext->MasterIrp->IoStatus.Information = 0;
  2159. }
  2160. //
  2161. // We must do this here since IoCompleteRequest won't get a chance
  2162. // on this associated Irp.
  2163. //
  2164. IoFreeMdl( Irp->MdlAddress );
  2165. IoFreeIrp( Irp );
  2166. if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
  2167. //
  2168. // Update the Master Irp with any error status from the associated Irps.
  2169. //
  2170. IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
  2171. KeSetEvent( &IoContext->SyncEvent, 0, FALSE );
  2172. }
  2173. UNREFERENCED_PARAMETER( DeviceObject );
  2174. return STATUS_MORE_PROCESSING_REQUIRED;
  2175. }
  2176. //
  2177. // Local support routine
  2178. //
  2179. NTSTATUS
  2180. CdMultiAsyncCompletionRoutine (
  2181. IN PDEVICE_OBJECT DeviceObject,
  2182. IN PIRP Irp,
  2183. IN PVOID Context
  2184. )
  2185. /*++
  2186. Routine Description:
  2187. This is the completion routine for all asynchronous reads
  2188. started via CdMultipleAsynch.
  2189. The completion routine has has the following responsibilities:
  2190. If the individual request was completed with an error, then
  2191. this completion routine must see if this is the first error
  2192. and remember the error status in the Context.
  2193. Arguments:
  2194. DeviceObject - Pointer to the file system device object.
  2195. Irp - Pointer to the associated Irp which is being completed. (This
  2196. Irp will no longer be accessible after this routine returns.)
  2197. Context - The context parameter which was specified for all of
  2198. the multiple asynch I/O requests for this MasterIrp.
  2199. Return Value:
  2200. Currently always returns STATUS_SUCCESS.
  2201. --*/
  2202. {
  2203. PCD_IO_CONTEXT IoContext = Context;
  2204. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2205. AssertVerifyDeviceIrp( Irp );
  2206. //
  2207. // If we got an error (or verify required), remember it in the Irp
  2208. //
  2209. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  2210. InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
  2211. }
  2212. //
  2213. // Decrement IrpCount and see if it goes to zero.
  2214. //
  2215. if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
  2216. //
  2217. // Mark the master Irp pending
  2218. //
  2219. IoMarkIrpPending( IoContext->MasterIrp );
  2220. //
  2221. // Update the Master Irp with any error status from the associated Irps.
  2222. //
  2223. IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
  2224. //
  2225. // Update the information field with the correct value.
  2226. //
  2227. IoContext->MasterIrp->IoStatus.Information = 0;
  2228. if (NT_SUCCESS( IoContext->MasterIrp->IoStatus.Status )) {
  2229. IoContext->MasterIrp->IoStatus.Information = IoContext->RequestedByteCount;
  2230. }
  2231. //
  2232. // Now release the resource
  2233. //
  2234. ExReleaseResourceForThreadLite( IoContext->Resource,
  2235. IoContext->ResourceThreadId );
  2236. //
  2237. // and finally, free the context record.
  2238. //
  2239. CdFreeIoContext( IoContext );
  2240. //
  2241. // Return success in this case.
  2242. //
  2243. return STATUS_SUCCESS;
  2244. } else {
  2245. //
  2246. // We need to cleanup the associated Irp and its Mdl.
  2247. //
  2248. IoFreeMdl( Irp->MdlAddress );
  2249. IoFreeIrp( Irp );
  2250. return STATUS_MORE_PROCESSING_REQUIRED;
  2251. }
  2252. UNREFERENCED_PARAMETER( DeviceObject );
  2253. }
  2254. //
  2255. // Local support routine
  2256. //
  2257. NTSTATUS
  2258. CdSingleSyncCompletionRoutine (
  2259. IN PDEVICE_OBJECT DeviceObject,
  2260. IN PIRP Irp,
  2261. IN PVOID Context
  2262. )
  2263. /*++
  2264. Routine Description:
  2265. This is the completion routine for all reads started via CdSingleAsynch.
  2266. The completion routine has has the following responsibilities:
  2267. It sets the event in the Context parameter to signal the caller
  2268. that all of the asynch requests are done.
  2269. Arguments:
  2270. DeviceObject - Pointer to the file system device object.
  2271. Irp - Pointer to the Irp for this request. (This Irp will no longer
  2272. be accessible after this routine returns.)
  2273. Context - The context parameter which was specified in the call to
  2274. CdSingleAsynch.
  2275. Return Value:
  2276. The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
  2277. immediately complete the Master Irp without being in a race condition
  2278. with the IoCompleteRequest thread trying to decrement the IrpCount in
  2279. the Master Irp.
  2280. --*/
  2281. {
  2282. AssertVerifyDeviceIrp( Irp );
  2283. //
  2284. // Store the correct information field into the Irp.
  2285. //
  2286. if (!NT_SUCCESS( Irp->IoStatus.Status )) {
  2287. Irp->IoStatus.Information = 0;
  2288. }
  2289. KeSetEvent( &((PCD_IO_CONTEXT)Context)->SyncEvent, 0, FALSE );
  2290. return STATUS_MORE_PROCESSING_REQUIRED;
  2291. }
  2292. //
  2293. // Local support routine
  2294. //
  2295. NTSTATUS
  2296. CdSingleAsyncCompletionRoutine (
  2297. IN PDEVICE_OBJECT DeviceObject,
  2298. IN PIRP Irp,
  2299. IN PVOID Context
  2300. )
  2301. /*++
  2302. Routine Description:
  2303. This is the completion routine for all asynchronous reads
  2304. started via CdSingleAsynch.
  2305. Arguments:
  2306. DeviceObject - Pointer to the file system device object.
  2307. Irp - Pointer to the Irp for this request. (This Irp will no longer
  2308. be accessible after this routine returns.)
  2309. Context - The context parameter which was specified in the call to
  2310. CdSingleAsynch.
  2311. Return Value:
  2312. Currently always returns STATUS_SUCCESS.
  2313. --*/
  2314. {
  2315. AssertVerifyDeviceIrp( Irp );
  2316. //
  2317. // Update the information field with the correct value for bytes read.
  2318. //
  2319. Irp->IoStatus.Information = 0;
  2320. if (NT_SUCCESS( Irp->IoStatus.Status )) {
  2321. Irp->IoStatus.Information = ((PCD_IO_CONTEXT) Context)->RequestedByteCount;
  2322. }
  2323. //
  2324. // Mark the Irp pending
  2325. //
  2326. IoMarkIrpPending( Irp );
  2327. //
  2328. // Now release the resource
  2329. //
  2330. ExReleaseResourceForThreadLite( ((PCD_IO_CONTEXT) Context)->Resource,
  2331. ((PCD_IO_CONTEXT) Context)->ResourceThreadId );
  2332. //
  2333. // and finally, free the context record.
  2334. //
  2335. CdFreeIoContext( (PCD_IO_CONTEXT) Context );
  2336. return STATUS_SUCCESS;
  2337. UNREFERENCED_PARAMETER( DeviceObject );
  2338. }
  2339. //
  2340. // Local support routine
  2341. //
  2342. VOID
  2343. CdReadAudioSystemFile (
  2344. IN PIRP_CONTEXT IrpContext,
  2345. IN PFCB Fcb,
  2346. IN LONGLONG StartingOffset,
  2347. IN ULONG ByteCount,
  2348. IN PVOID SystemBuffer
  2349. )
  2350. /*++
  2351. Routine Description:
  2352. This routine is called to read the pseudo root directory and path
  2353. table for a music disk. We build the individual elements on the
  2354. stack and copy into the cache buffer.
  2355. Arguments:
  2356. Fcb - Fcb representing the file to read.
  2357. StartingOffset - Logical offset in the file to read from.
  2358. ByteCount - Number of bytes to read.
  2359. SystemBuffer - Pointer to buffer to fill in. This will always be page
  2360. aligned.
  2361. Return Value:
  2362. None.
  2363. --*/
  2364. {
  2365. PRAW_PATH_ISO RawPath;
  2366. PRAW_DIRENT RawDirent;
  2367. ULONG CurrentTrack;
  2368. ULONG SectorOffset;
  2369. ULONG EntryCount;
  2370. UCHAR TrackOnes;
  2371. UCHAR TrackTens;
  2372. PTRACK_DATA ThisTrack;
  2373. LONGLONG CurrentOffset;
  2374. PVOID CurrentSector;
  2375. PSYSTEM_USE_XA SystemUse;
  2376. ULONG BytesToCopy;
  2377. UCHAR LocalBuffer[FIELD_OFFSET( RAW_DIRENT, FileId ) + 12];
  2378. PAGED_CODE();
  2379. //
  2380. // If this is the path table then we just need a single entry.
  2381. //
  2382. if (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE) {
  2383. //
  2384. // Sanity check that the offset is zero.
  2385. //
  2386. ASSERT( StartingOffset == 0 );
  2387. //
  2388. // Store a pseudo path entry in our local buffer.
  2389. //
  2390. RawPath = (PRAW_PATH_ISO) LocalBuffer;
  2391. RtlZeroMemory( RawPath, sizeof( LocalBuffer ));
  2392. RawPath->DirIdLen = 1;
  2393. RawPath->ParentNum = 1;
  2394. RawPath->DirId[0] = '\0';
  2395. //
  2396. // Now copy to the user's buffer.
  2397. //
  2398. BytesToCopy = FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2;
  2399. if (BytesToCopy > ByteCount) {
  2400. BytesToCopy = ByteCount;
  2401. }
  2402. RtlCopyMemory( SystemBuffer,
  2403. RawPath,
  2404. BytesToCopy );
  2405. //
  2406. // We need to deal with the multiple sector case for the root directory.
  2407. //
  2408. } else {
  2409. //
  2410. // Initialize the first track to return to our caller.
  2411. //
  2412. CurrentTrack = 0;
  2413. //
  2414. // If the offset is zero then store the entries for the self and parent
  2415. // entries.
  2416. //
  2417. if (StartingOffset == 0) {
  2418. RawDirent = SystemBuffer;
  2419. //
  2420. // Clear all of the fields initially.
  2421. //
  2422. RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
  2423. //
  2424. // Now fill in the interesting fields.
  2425. //
  2426. RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
  2427. RawDirent->FileIdLen = 1;
  2428. RawDirent->FileId[0] = '\0';
  2429. SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
  2430. //
  2431. // Set the time stamp to be Jan 1, 1995
  2432. //
  2433. RawDirent->RecordTime[0] = 95;
  2434. RawDirent->RecordTime[1] = 1;
  2435. RawDirent->RecordTime[2] = 1;
  2436. SectorOffset = RawDirent->DirLen;
  2437. RawDirent = Add2Ptr( RawDirent, SectorOffset, PRAW_DIRENT );
  2438. //
  2439. // Clear all of the fields initially.
  2440. //
  2441. RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
  2442. //
  2443. // Now fill in the interesting fields.
  2444. //
  2445. RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
  2446. RawDirent->FileIdLen = 1;
  2447. RawDirent->FileId[0] = '\1';
  2448. SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
  2449. //
  2450. // Set the time stamp to be Jan 1, 1995
  2451. //
  2452. RawDirent->RecordTime[0] = 95;
  2453. RawDirent->RecordTime[1] = 1;
  2454. RawDirent->RecordTime[2] = 1;
  2455. SectorOffset += RawDirent->DirLen;
  2456. EntryCount = 2;
  2457. //
  2458. // Otherwise compute the starting track to write to the buffer.
  2459. //
  2460. } else {
  2461. //
  2462. // Count the tracks in each preceding sector.
  2463. //
  2464. CurrentOffset = 0;
  2465. do {
  2466. CurrentTrack += CdAudioDirentsPerSector;
  2467. CurrentOffset += SECTOR_SIZE;
  2468. } while (CurrentOffset < StartingOffset);
  2469. //
  2470. // Bias the track count to reflect the two default entries.
  2471. //
  2472. CurrentTrack -= 2;
  2473. SectorOffset = 0;
  2474. EntryCount = 0;
  2475. }
  2476. //
  2477. // We now know the first track to return as well as where we are in
  2478. // the current sector. We will walk through sector by sector adding
  2479. // the entries for the separate tracks in the TOC. We will zero
  2480. // any sectors or partial sectors without data.
  2481. //
  2482. CurrentSector = SystemBuffer;
  2483. BytesToCopy = SECTOR_SIZE;
  2484. //
  2485. // Loop for each sector.
  2486. //
  2487. do {
  2488. //
  2489. // Add entries until we reach our threshold for each sector.
  2490. //
  2491. do {
  2492. //
  2493. // If we are beyond the entries in the TOC then exit.
  2494. //
  2495. if (CurrentTrack >= IrpContext->Vcb->TrackCount) {
  2496. break;
  2497. }
  2498. ThisTrack = &IrpContext->Vcb->CdromToc->TrackData[CurrentTrack];
  2499. //
  2500. // Point to the current position in the buffer.
  2501. //
  2502. RawDirent = Add2Ptr( CurrentSector, SectorOffset, PRAW_DIRENT );
  2503. //
  2504. // Clear all of the fields initially.
  2505. //
  2506. RtlZeroMemory( RawDirent, CdAudioDirentSize );
  2507. //
  2508. // Now fill in the interesting fields.
  2509. //
  2510. RawDirent->DirLen = (UCHAR) CdAudioDirentSize;
  2511. RawDirent->FileIdLen = CdAudioFileNameLength;
  2512. RtlCopyMemory( RawDirent->FileId,
  2513. CdAudioFileName,
  2514. CdAudioFileNameLength );
  2515. //
  2516. // Set the time stamp to be Jan 1, 1995
  2517. //
  2518. RawDirent->RecordTime[0] = 95;
  2519. RawDirent->RecordTime[1] = 1;
  2520. RawDirent->RecordTime[2] = 1;
  2521. //
  2522. // Now bias by the values in the TOC.
  2523. //
  2524. RawDirent->RecordTime[4] = ThisTrack->Address[1] % 60;
  2525. RawDirent->RecordTime[5] = ThisTrack->Address[2] % 60;
  2526. //
  2527. // Put the track number into the file name.
  2528. //
  2529. TrackTens = TrackOnes = ThisTrack->TrackNumber;
  2530. TrackOnes = (TrackOnes % 10) + '0';
  2531. TrackTens /= 10;
  2532. TrackTens = (TrackTens % 10) + '0';
  2533. RawDirent->FileId[AUDIO_NAME_TENS_OFFSET] = TrackTens;
  2534. RawDirent->FileId[AUDIO_NAME_ONES_OFFSET] = TrackOnes;
  2535. SystemUse = Add2Ptr( RawDirent, CdAudioSystemUseOffset, PSYSTEM_USE_XA );
  2536. SystemUse->Attributes = SYSTEM_USE_XA_DA;
  2537. SystemUse->Signature = SYSTEM_XA_SIGNATURE;
  2538. //
  2539. // Store the track number as the file number.
  2540. //
  2541. SystemUse->FileNumber = (UCHAR) CurrentTrack;
  2542. EntryCount += 1;
  2543. SectorOffset += CdAudioDirentSize;
  2544. CurrentTrack += 1;
  2545. } while (EntryCount < CdAudioDirentsPerSector);
  2546. //
  2547. // Zero the remaining portion of this buffer.
  2548. //
  2549. RtlZeroMemory( Add2Ptr( CurrentSector, SectorOffset, PVOID ),
  2550. SECTOR_SIZE - SectorOffset );
  2551. //
  2552. // Prepare for the next sector.
  2553. //
  2554. EntryCount = 0;
  2555. BytesToCopy += SECTOR_SIZE;
  2556. SectorOffset = 0;
  2557. CurrentSector = Add2Ptr( CurrentSector, SECTOR_SIZE, PVOID );
  2558. } while (BytesToCopy <= ByteCount);
  2559. }
  2560. return;
  2561. }