[CDFS_NEW] Force calling convention to allow build
[reactos.git] / drivers / filesystems / cdfs_new / deviosup.c
1 /*++
2
3 Copyright (c) 1989-2000 Microsoft Corporation
4
5 Module Name:
6
7 DevIoSup.c
8
9 Abstract:
10
11 This module implements the low lever disk read/write support for Cdfs.
12
13
14 --*/
15
16 #include "cdprocs.h"
17
18 //
19 // The Bug check file id for this module
20 //
21
22 #define BugCheckFileId (CDFS_BUG_CHECK_DEVIOSUP)
23
24 //
25 // Local structure definitions
26 //
27
28 //
29 // An array of these structures is passed to CdMultipleAsync describing
30 // a set of runs to execute in parallel.
31 //
32
33 typedef struct _IO_RUN {
34
35 //
36 // Disk offset to read from and number of bytes to read. These
37 // must be a multiple of 2048 and the disk offset is also a
38 // multiple of 2048.
39 //
40
41 LONGLONG DiskOffset;
42 ULONG DiskByteCount;
43
44 //
45 // Current position in user buffer. This is the final destination for
46 // this portion of the Io transfer.
47 //
48
49 PVOID UserBuffer;
50
51 //
52 // Buffer to perform the transfer to. If this is the same as the
53 // user buffer above then we are using the user's buffer. Otherwise
54 // we either allocated a temporary buffer or are using a different portion
55 // of the user's buffer.
56 //
57 // TransferBuffer - Read full sectors into this location. This can
58 // be a pointer into the user's buffer at the exact location the
59 // data should go. It can also be an earlier point in the user's
60 // buffer if the complete I/O doesn't start on a sector boundary.
61 // It may also be a pointer into an allocated buffer.
62 //
63 // TransferByteCount - Count of bytes to transfer to user's buffer. A
64 // value of zero indicates that we did do the transfer into the
65 // user's buffer directly.
66 //
67 // TransferBufferOffset - Offset in this buffer to begin the transfer
68 // to the user's buffer.
69 //
70
71 PVOID TransferBuffer;
72 ULONG TransferByteCount;
73 ULONG TransferBufferOffset;
74
75 //
76 // This is the Mdl describing the locked pages in memory. It may
77 // be allocated to describe the allocated buffer. Or it may be
78 // the Mdl in the originating Irp. The MdlOffset is the offset of
79 // the current buffer from the beginning of the buffer described by
80 // the Mdl below. If the TransferMdl is not the same as the Mdl
81 // in the user's Irp then we know we have allocated it.
82 //
83
84 PMDL TransferMdl;
85 PVOID TransferVirtualAddress;
86
87 //
88 // Associated Irp used to perform the Io.
89 //
90
91 PIRP SavedIrp;
92
93 } IO_RUN;
94 typedef IO_RUN *PIO_RUN;
95
96 #define MAX_PARALLEL_IOS 5
97
98 //
99 // Local support routines
100 //
101
102 BOOLEAN
103 CdPrepareBuffers (
104 IN PIRP_CONTEXT IrpContext,
105 IN PIRP Irp,
106 IN PFCB Fcb,
107 IN PVOID UserBuffer,
108 IN ULONG UserBufferOffset,
109 IN LONGLONG StartingOffset,
110 IN ULONG ByteCount,
111 IN PIO_RUN IoRuns,
112 IN PULONG RunCount,
113 IN PULONG ThisByteCount
114 );
115
116 VOID
117 CdPrepareXABuffers (
118 IN PIRP_CONTEXT IrpContext,
119 IN PIRP Irp,
120 IN PFCB Fcb,
121 IN PVOID UserBuffer,
122 IN ULONG UserBufferOffset,
123 IN LONGLONG StartingOffset,
124 IN ULONG ByteCount,
125 IN PIO_RUN IoRuns,
126 IN PULONG RunCount,
127 IN PULONG ThisByteCount
128 );
129
130 BOOLEAN
131 CdFinishBuffers (
132 IN PIRP_CONTEXT IrpContext,
133 IN PIO_RUN IoRuns,
134 IN ULONG RunCount,
135 IN BOOLEAN FinalCleanup,
136 IN BOOLEAN SaveXABuffer
137 );
138
139 VOID
140 CdMultipleAsync (
141 IN PIRP_CONTEXT IrpContext,
142 IN ULONG RunCount,
143 IN PIO_RUN IoRuns
144 );
145
146 VOID
147 CdMultipleXAAsync (
148 IN PIRP_CONTEXT IrpContext,
149 IN ULONG RunCount,
150 IN PIO_RUN IoRuns,
151 IN PRAW_READ_INFO RawReads,
152 IN TRACK_MODE_TYPE TrackMode
153 );
154
155 VOID
156 CdSingleAsync (
157 IN PIRP_CONTEXT IrpContext,
158 IN LONGLONG ByteOffset,
159 IN ULONG ByteCount
160 );
161
162 VOID
163 CdWaitSync (
164 IN PIRP_CONTEXT IrpContext
165 );
166
167 NTSTATUS
168 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
169 CdMultiSyncCompletionRoutine (
170 IN PDEVICE_OBJECT DeviceObject,
171 IN PIRP Irp,
172 IN PVOID Context
173 );
174
175 NTSTATUS
176 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
177 CdMultiAsyncCompletionRoutine (
178 IN PDEVICE_OBJECT DeviceObject,
179 IN PIRP Irp,
180 IN PVOID Context
181 );
182
183 NTSTATUS
184 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
185 CdSingleSyncCompletionRoutine (
186 IN PDEVICE_OBJECT DeviceObject,
187 IN PIRP Irp,
188 IN PVOID Context
189 );
190
191 NTSTATUS
192 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
193 CdSingleAsyncCompletionRoutine (
194 IN PDEVICE_OBJECT DeviceObject,
195 IN PIRP Irp,
196 IN PVOID Context
197 );
198
199 VOID
200 CdReadAudioSystemFile (
201 IN PIRP_CONTEXT IrpContext,
202 IN PFCB Fcb,
203 IN LONGLONG StartingOffset,
204 IN ULONG ByteCount,
205 IN PVOID SystemBuffer
206 );
207
208 #ifdef ALLOC_PRAGMA
209 #pragma alloc_text(PAGE, CdCreateUserMdl)
210 #pragma alloc_text(PAGE, CdMultipleAsync)
211 #pragma alloc_text(PAGE, CdMultipleXAAsync)
212 #pragma alloc_text(PAGE, CdNonCachedRead)
213 #pragma alloc_text(PAGE, CdNonCachedXARead)
214 #pragma alloc_text(PAGE, CdFinishBuffers)
215 #pragma alloc_text(PAGE, CdPerformDevIoCtrl)
216 #pragma alloc_text(PAGE, CdPrepareBuffers)
217 #pragma alloc_text(PAGE, CdReadAudioSystemFile)
218 #pragma alloc_text(PAGE, CdReadSectors)
219 #pragma alloc_text(PAGE, CdSingleAsync)
220 #pragma alloc_text(PAGE, CdWaitSync)
221 #endif
222
223 \f
224 __inline
225 TRACK_MODE_TYPE
226 CdFileTrackMode (
227 IN PFCB Fcb
228 )
229
230 /*++
231
232 Routine Description:
233
234 This routine converts FCB XA file type flags to the track mode
235 used by the device drivers.
236
237 Arguments:
238
239 Fcb - Fcb representing the file to read.
240
241 Return Value:
242
243 TrackMode of the file represented by the Fcb.
244
245 --*/
246 {
247 ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE |
248 FCB_STATE_MODE2_FILE |
249 FCB_STATE_DA_FILE ));
250
251 if (FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) {
252
253 return XAForm2;
254
255 } else if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) {
256
257 return CDDA;
258
259 }
260
261 //
262 // FCB_STATE_MODE2_FILE
263 //
264
265 return YellowMode2;
266 }
267
268 \f
269 NTSTATUS
270 CdNonCachedRead (
271 IN PIRP_CONTEXT IrpContext,
272 IN PFCB Fcb,
273 IN LONGLONG StartingOffset,
274 IN ULONG ByteCount
275 )
276
277 /*++
278
279 Routine Description:
280
281 This routine performs the non-cached reads to 'cooked' sectors (2048 bytes
282 per sector). This is done by performing the following in a loop.
283
284 Fill in the IoRuns array for the next block of Io.
285 Send the Io to the device.
286 Perform any cleanup on the Io runs array.
287
288 We will not do async Io to any request that generates non-aligned Io.
289 Also we will not perform async Io if it will exceed the size of our
290 IoRuns array. These should be the unusual cases but we will raise
291 or return CANT_WAIT in this routine if we detect this case.
292
293 Arguments:
294
295 Fcb - Fcb representing the file to read.
296
297 StartingOffset - Logical offset in the file to read from.
298
299 ByteCount - Number of bytes to read.
300
301 Return Value:
302
303 NTSTATUS - Status indicating the result of the operation.
304
305 --*/
306
307 {
308 NTSTATUS Status = STATUS_SUCCESS;
309
310 IO_RUN IoRuns[MAX_PARALLEL_IOS];
311 ULONG RunCount = 0;
312 ULONG CleanupRunCount = 0;
313
314 PVOID UserBuffer;
315 ULONG UserBufferOffset = 0;
316 LONGLONG CurrentOffset = StartingOffset;
317 ULONG RemainingByteCount = ByteCount;
318 ULONG ThisByteCount;
319
320 BOOLEAN Unaligned;
321 BOOLEAN FlushIoBuffers = FALSE;
322 BOOLEAN FirstPass = TRUE;
323
324 PAGED_CODE();
325
326 //
327 // We want to make sure the user's buffer is locked in all cases.
328 //
329
330 if (IrpContext->Irp->MdlAddress == NULL) {
331
332 CdCreateUserMdl( IrpContext, ByteCount, TRUE );
333 }
334
335 CdMapUserBuffer( IrpContext, &UserBuffer);
336
337 //
338 // Special case the root directory and path table for a music volume.
339 //
340
341 if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK ) &&
342 ((SafeNodeType( Fcb ) == CDFS_NTC_FCB_INDEX) ||
343 (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE))) {
344
345 CdReadAudioSystemFile( IrpContext,
346 Fcb,
347 StartingOffset,
348 ByteCount,
349 UserBuffer );
350
351 return STATUS_SUCCESS;
352 }
353
354 //
355 // Use a try-finally to perform the final cleanup.
356 //
357
358 try {
359
360 //
361 // Loop while there are more bytes to transfer.
362 //
363
364 do {
365
366 //
367 // Call prepare buffers to set up the next entries
368 // in the IoRuns array. Remember if there are any
369 // unaligned entries. This routine will raise CANT_WAIT
370 // if there are unaligned entries for an async request.
371 //
372
373 RtlZeroMemory( IoRuns, sizeof( IoRuns ));
374
375 Unaligned = CdPrepareBuffers( IrpContext,
376 IrpContext->Irp,
377 Fcb,
378 UserBuffer,
379 UserBufferOffset,
380 CurrentOffset,
381 RemainingByteCount,
382 IoRuns,
383 &CleanupRunCount,
384 &ThisByteCount );
385
386
387 RunCount = CleanupRunCount;
388
389 //
390 // If this is an async request and there aren't enough entries
391 // in the Io array then post the request.
392 //
393
394 if ((ThisByteCount < RemainingByteCount) &&
395 !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
396
397 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
398 }
399
400 //
401 // If the entire Io is contained in a single run then
402 // we can pass the Io down to the driver. Send the driver down
403 // and wait on the result if this is synchronous.
404 //
405
406 if ((RunCount == 1) && !Unaligned && FirstPass) {
407
408 CdSingleAsync( IrpContext,
409 IoRuns[0].DiskOffset,
410 IoRuns[0].DiskByteCount );
411
412 //
413 // No cleanup needed for the IoRuns array here.
414 //
415
416 CleanupRunCount = 0;
417
418 //
419 // Wait if we are synchronous, otherwise return
420 //
421
422 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
423
424 CdWaitSync( IrpContext );
425
426 Status = IrpContext->Irp->IoStatus.Status;
427
428 //
429 // Our completion routine will free the Io context but
430 // we do want to return STATUS_PENDING.
431 //
432
433 } else {
434
435 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
436 Status = STATUS_PENDING;
437 }
438
439 try_return( NOTHING );
440 }
441
442 //
443 // Otherwise we will perform multiple Io to read in the data.
444 //
445
446 CdMultipleAsync( IrpContext, RunCount, IoRuns );
447
448 //
449 // If this is a synchronous request then perform any necessary
450 // post-processing.
451 //
452
453 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
454
455 //
456 // Wait for the request to complete.
457 //
458
459 CdWaitSync( IrpContext );
460
461 Status = IrpContext->Irp->IoStatus.Status;
462
463 //
464 // Exit this loop if there is an error.
465 //
466
467 if (!NT_SUCCESS( Status )) {
468
469 try_return( NOTHING );
470 }
471
472 //
473 // Perform post read operations on the IoRuns if
474 // necessary.
475 //
476
477 if (Unaligned &&
478 CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, FALSE )) {
479
480 FlushIoBuffers = TRUE;
481 }
482
483 CleanupRunCount = 0;
484
485 //
486 // Exit this loop if there are no more bytes to transfer
487 // or we have any error.
488 //
489
490 RemainingByteCount -= ThisByteCount;
491 CurrentOffset += ThisByteCount;
492 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
493 UserBufferOffset += ThisByteCount;
494
495 //
496 // Otherwise this is an asynchronous request. Always return
497 // STATUS_PENDING.
498 //
499
500 } else {
501
502 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ALLOC_IO );
503 CleanupRunCount = 0;
504 try_return( Status = STATUS_PENDING );
505 break;
506 }
507
508 FirstPass = FALSE;
509 } while (RemainingByteCount != 0);
510
511 //
512 // Flush the hardware cache if we performed any copy operations.
513 //
514
515 if (FlushIoBuffers) {
516
517 KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
518 }
519
520 try_exit: NOTHING;
521 } finally {
522
523 //
524 // Perform final cleanup on the IoRuns if necessary.
525 //
526
527 if (CleanupRunCount != 0) {
528
529 CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
530 }
531 }
532
533 return Status;
534 }
535
536 \f
537 NTSTATUS
538 CdNonCachedXARead (
539 IN PIRP_CONTEXT IrpContext,
540 IN PFCB Fcb,
541 IN LONGLONG StartingOffset,
542 IN ULONG ByteCount
543 )
544
545 /*++
546
547 Routine Description:
548
549 This routine performs the non-cached reads for 'raw' sectors (2352 bytes
550 per sector). We also prepend a hard-coded RIFF header of 44 bytes to the file.
551 All of this is already reflected in the file size.
552
553 We start by checking whether to prepend any portion of the RIFF header. Then we check
554 if the last raw sector read was from the beginning portion of this file, deallocating
555 that buffer if necessary. Finally we do the following in a loop.
556
557 Fill the IoRuns array for the next block of Io.
558 Send the Io to the device driver.
559 Perform any cleanup necessary on the IoRuns array.
560
561 We will not do any async request in this path. The request would have been
562 posted to a worker thread before getting to this point.
563
564 Arguments:
565
566 Fcb - Fcb representing the file to read.
567
568 StartingOffset - Logical offset in the file to read from.
569
570 ByteCount - Number of bytes to read.
571
572 Return Value:
573
574 NTSTATUS - Status indicating the result of the operation.
575
576 --*/
577
578 {
579 NTSTATUS Status = STATUS_SUCCESS;
580
581 RIFF_HEADER LocalRiffHeader;
582 PRIFF_HEADER RiffHeader;
583
584 RAW_READ_INFO RawReads[MAX_PARALLEL_IOS];
585 IO_RUN IoRuns[MAX_PARALLEL_IOS];
586 ULONG RunCount = 0;
587 ULONG CleanupRunCount = 0;
588
589 PVOID UserBuffer;
590 ULONG UserBufferOffset = 0;
591 LONGLONG CurrentOffset = StartingOffset;
592 ULONG RemainingByteCount = ByteCount;
593 ULONG ThisByteCount;
594
595 BOOLEAN TryingYellowbookMode2 = FALSE;
596
597 TRACK_MODE_TYPE TrackMode;
598
599 PAGED_CODE();
600
601 //
602 // We want to make sure the user's buffer is locked in all cases.
603 //
604
605 if (IrpContext->Irp->MdlAddress == NULL) {
606
607 CdCreateUserMdl( IrpContext, ByteCount, TRUE );
608 }
609
610 //
611 // The byte count was rounded up to a logical sector boundary. It has
612 // nothing to do with the raw sectors on disk. Limit the remaining
613 // byte count to file size.
614 //
615
616 if (CurrentOffset + RemainingByteCount > Fcb->FileSize.QuadPart) {
617
618 RemainingByteCount = (ULONG) (Fcb->FileSize.QuadPart - CurrentOffset);
619 }
620
621 CdMapUserBuffer( IrpContext, &UserBuffer);
622
623 //
624 // Use a try-finally to perform the final cleanup.
625 //
626
627 try {
628
629 //
630 // If the initial offset lies within the RIFF header then copy the
631 // necessary bytes to the user's buffer.
632 //
633
634 if (CurrentOffset < sizeof( RIFF_HEADER )) {
635
636 //
637 // Copy the appropriate RIFF header.
638 //
639
640 if (FlagOn( Fcb->FcbState, FCB_STATE_DA_FILE )) {
641
642 //
643 // Create the pseudo entries for a music disk.
644 //
645
646 if (FlagOn( Fcb->Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
647
648 PAUDIO_PLAY_HEADER AudioPlayHeader;
649 PTRACK_DATA TrackData;
650 ULONG SectorCount;
651
652 AudioPlayHeader = (PAUDIO_PLAY_HEADER) &LocalRiffHeader;
653 TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber];
654
655 //
656 // Copy the data header into our local buffer.
657 //
658
659 RtlCopyMemory( AudioPlayHeader,
660 CdAudioPlayHeader,
661 sizeof( AUDIO_PLAY_HEADER ));
662
663 //
664 // Copy the serial number into the Id field. Also
665 // the track number in the TOC.
666 //
667
668 AudioPlayHeader->DiskID = Fcb->Vcb->Vpb->SerialNumber;
669 AudioPlayHeader->TrackNumber = TrackData->TrackNumber;
670
671 //
672 // TOC contains MSF (Minute/Second/Frame) addresses. This is very
673 // arcane, and we wind up having to bias around by the size of the
674 // leadins and other such silliness to find real live sector addrs.
675 //
676 // One frame == One sector.
677 // One second == 75 frames (winds up being a 44.1khz sample)
678 //
679
680 //
681 // Fill in the address and length fields.
682 //
683
684 AudioPlayHeader->TrackAddress[2] = TrackData->Address[1];
685 AudioPlayHeader->TrackAddress[1] = TrackData->Address[2];
686 AudioPlayHeader->TrackAddress[0] = TrackData->Address[3];
687
688 AudioPlayHeader->StartingSector = TrackData->Address[3];
689 AudioPlayHeader->StartingSector += (TrackData->Address[2] * 75);
690 AudioPlayHeader->StartingSector += (TrackData->Address[1] * 60 * 75);
691
692 //
693 // Subtract 2 seconds for the block number.
694 //
695
696 AudioPlayHeader->StartingSector -= 150;
697
698 //
699 // Go to the next track and find the starting point.
700 //
701
702 TrackData = &Fcb->Vcb->CdromToc->TrackData[Fcb->XAFileNumber + 1];
703
704 AudioPlayHeader->SectorCount = TrackData->Address[3];
705 AudioPlayHeader->SectorCount += (TrackData->Address[2] * 75);
706 AudioPlayHeader->SectorCount += (TrackData->Address[1] * 60 * 75);
707
708 //
709 // Bias the sector count by 2 seconds.
710 // Check that the offset is at least two seconds.
711 //
712
713 if (AudioPlayHeader->SectorCount < 150) {
714
715 AudioPlayHeader->SectorCount = 0;
716
717 } else {
718
719 AudioPlayHeader->SectorCount -= 150;
720 }
721
722 //
723 // Now compute the difference. If there is an error then use
724 // a length of zero.
725 //
726
727 if (AudioPlayHeader->SectorCount < AudioPlayHeader->StartingSector) {
728
729 AudioPlayHeader->SectorCount = 0;
730
731 } else {
732
733 AudioPlayHeader->SectorCount -= AudioPlayHeader->StartingSector;
734 }
735
736 //
737 // Use the sector count to determine the MSF length.
738 //
739
740 SectorCount = AudioPlayHeader->SectorCount;
741
742 AudioPlayHeader->TrackLength[0] = (UCHAR) (SectorCount % 75);
743 SectorCount /= 75;
744
745 AudioPlayHeader->TrackLength[1] = (UCHAR) (SectorCount % 60);
746 SectorCount /= 60;
747
748 AudioPlayHeader->TrackLength[2] = (UCHAR) (SectorCount % 60);
749
750 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
751
752 RtlCopyMemory( UserBuffer,
753 Add2Ptr( AudioPlayHeader,
754 sizeof( RIFF_HEADER ) - ThisByteCount,
755 PCHAR ),
756 ThisByteCount );
757
758 //
759 // CD-XA CDDA
760 //
761
762 } else {
763
764 //
765 // The WAVE header format is actually much closer to an audio play
766 // header in format but we only need to modify the filesize fields.
767 //
768
769 RiffHeader = &LocalRiffHeader;
770
771 //
772 // Copy the data header into our local buffer and add the file size to it.
773 //
774
775 RtlCopyMemory( RiffHeader,
776 CdXAAudioPhileHeader,
777 sizeof( RIFF_HEADER ));
778
779 RiffHeader->ChunkSize += Fcb->FileSize.LowPart;
780 RiffHeader->RawSectors += Fcb->FileSize.LowPart;
781
782 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
783 RtlCopyMemory( UserBuffer,
784 Add2Ptr( RiffHeader,
785 sizeof( RIFF_HEADER ) - ThisByteCount,
786 PCHAR ),
787 ThisByteCount );
788 }
789
790 //
791 // CD-XA non-audio
792 //
793
794 } else {
795
796 ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MODE2_FILE | FCB_STATE_MODE2FORM2_FILE ));
797
798 RiffHeader = &LocalRiffHeader;
799
800 //
801 // Copy the data header into our local buffer and add the file size to it.
802 //
803
804 RtlCopyMemory( RiffHeader,
805 CdXAFileHeader,
806 sizeof( RIFF_HEADER ));
807
808 RiffHeader->ChunkSize += Fcb->FileSize.LowPart;
809 RiffHeader->RawSectors += Fcb->FileSize.LowPart;
810
811 RiffHeader->Attributes = (USHORT) Fcb->XAAttributes;
812 RiffHeader->FileNumber = (UCHAR) Fcb->XAFileNumber;
813
814 ThisByteCount = sizeof( RIFF_HEADER ) - (ULONG) CurrentOffset;
815 RtlCopyMemory( UserBuffer,
816 Add2Ptr( RiffHeader,
817 sizeof( RIFF_HEADER ) - ThisByteCount,
818 PCHAR ),
819 ThisByteCount );
820 }
821
822 //
823 // Adjust the starting offset and byte count to reflect that
824 // we copied over the RIFF bytes.
825 //
826
827 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
828 UserBufferOffset += ThisByteCount;
829 CurrentOffset += ThisByteCount;
830 RemainingByteCount -= ThisByteCount;
831 }
832
833 //
834 // Set up the appropriate trackmode
835 //
836
837 TrackMode = CdFileTrackMode(Fcb);
838
839 //
840 // Loop while there are more bytes to transfer.
841 //
842
843 while (RemainingByteCount != 0) {
844
845 //
846 // Call prepare buffers to set up the next entries
847 // in the IoRuns array. Remember if there are any
848 // unaligned entries. If we're just retrying the previous
849 // runs with a different track mode, then don't do anything here.
850 //
851
852 if (!TryingYellowbookMode2) {
853
854 RtlZeroMemory( IoRuns, sizeof( IoRuns ));
855 RtlZeroMemory( RawReads, sizeof( RawReads ));
856
857 CdPrepareXABuffers( IrpContext,
858 IrpContext->Irp,
859 Fcb,
860 UserBuffer,
861 UserBufferOffset,
862 CurrentOffset,
863 RemainingByteCount,
864 IoRuns,
865 &CleanupRunCount,
866 &ThisByteCount );
867 }
868
869 //
870 // Perform multiple Io to read in the data. Note that
871 // there may be no Io to do if we were able to use an
872 // existing buffer from the Vcb.
873 //
874
875 if (CleanupRunCount != 0) {
876
877 RunCount = CleanupRunCount;
878
879 CdMultipleXAAsync( IrpContext,
880 RunCount,
881 IoRuns,
882 RawReads,
883 TrackMode );
884 //
885 // Wait for the request to complete.
886 //
887
888 CdWaitSync( IrpContext );
889
890 Status = IrpContext->Irp->IoStatus.Status;
891
892 //
893 // Exit this loop if there is an error.
894 //
895
896 if (!NT_SUCCESS( Status )) {
897
898 if (!TryingYellowbookMode2 &&
899 FlagOn( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE )) {
900
901 //
902 // There are wacky cases where someone has mastered as CD-XA
903 // but the sectors they claim are Mode2Form2 are really, according
904 // to ATAPI devices, Yellowbook Mode2. We will try once more
905 // with these. Kodak PHOTO-CD has been observed to do this.
906 //
907
908 TryingYellowbookMode2 = TRUE;
909 TrackMode = YellowMode2;
910
911 //
912 // Clear our 'cumulative' error status value
913 //
914
915 IrpContext->IoContext->Status = STATUS_SUCCESS;
916
917 continue;
918 }
919
920 try_return( NOTHING );
921 }
922
923 CleanupRunCount = 0;
924
925 if (TryingYellowbookMode2) {
926
927 //
928 // We successfully got data when we tried switching the trackmode,
929 // so change the state of the FCB to remember that.
930 //
931
932 SetFlag( Fcb->FcbState, FCB_STATE_MODE2_FILE );
933 ClearFlag( Fcb->FcbState, FCB_STATE_MODE2FORM2_FILE );
934
935 TryingYellowbookMode2 = FALSE;
936 }
937
938 //
939 // Perform post read operations on the IoRuns if
940 // necessary.
941 //
942
943 CdFinishBuffers( IrpContext, IoRuns, RunCount, FALSE, TRUE );
944 }
945
946 //
947 // Adjust our loop variants.
948 //
949
950 RemainingByteCount -= ThisByteCount;
951 CurrentOffset += ThisByteCount;
952 UserBuffer = Add2Ptr( UserBuffer, ThisByteCount, PVOID );
953 UserBufferOffset += ThisByteCount;
954 }
955
956 //
957 // Always flush the hardware cache.
958 //
959
960 KeFlushIoBuffers( IrpContext->Irp->MdlAddress, TRUE, FALSE );
961
962 try_exit: NOTHING;
963 } finally {
964
965 //
966 // Perform final cleanup on the IoRuns if necessary.
967 //
968
969 if (CleanupRunCount != 0) {
970
971 CdFinishBuffers( IrpContext, IoRuns, CleanupRunCount, TRUE, FALSE );
972 }
973 }
974
975 return Status;
976 }
977
978 \f
979 BOOLEAN
980 CdReadSectors (
981 IN PIRP_CONTEXT IrpContext,
982 IN LONGLONG StartingOffset,
983 IN ULONG ByteCount,
984 IN BOOLEAN ReturnError,
985 IN OUT PVOID Buffer,
986 IN PDEVICE_OBJECT TargetDeviceObject
987 )
988
989 /*++
990
991 Routine Description:
992
993 This routine is called to transfer sectors from the disk to a
994 specified buffer. It is used for mount and volume verify operations.
995
996 This routine is synchronous, it will not return until the operation
997 is complete or until the operation fails.
998
999 The routine allocates an IRP and then passes this IRP to a lower
1000 level driver. Errors may occur in the allocation of this IRP or
1001 in the operation of the lower driver.
1002
1003 Arguments:
1004
1005 StartingOffset - Logical offset on the disk to start the read. This
1006 must be on a sector boundary, no check is made here.
1007
1008 ByteCount - Number of bytes to read. This is an integral number of
1009 2K sectors, no check is made here to confirm this.
1010
1011 ReturnError - Indicates whether we should return TRUE or FALSE
1012 to indicate an error or raise an error condition. This only applies
1013 to the result of the IO. Any other error may cause a raise.
1014
1015 Buffer - Buffer to transfer the disk data into.
1016
1017 TargetDeviceObject - The device object for the volume to be read.
1018
1019 Return Value:
1020
1021 BOOLEAN - Depending on 'RaiseOnError' flag above. TRUE if operation
1022 succeeded, FALSE otherwise.
1023
1024 --*/
1025
1026 {
1027 NTSTATUS Status;
1028 KEVENT Event;
1029 PIRP Irp;
1030
1031 PAGED_CODE();
1032
1033 //
1034 // Initialize the event.
1035 //
1036
1037 KeInitializeEvent( &Event, NotificationEvent, FALSE );
1038
1039 //
1040 // Attempt to allocate the IRP. If unsuccessful, raise
1041 // STATUS_INSUFFICIENT_RESOURCES.
1042 //
1043
1044 Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
1045 TargetDeviceObject,
1046 Buffer,
1047 ByteCount,
1048 (PLARGE_INTEGER) &StartingOffset,
1049 &Event,
1050 &IrpContext->Irp->IoStatus );
1051
1052 if (Irp == NULL) {
1053
1054 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
1055 }
1056
1057 //
1058 // Ignore the change line (verify) for mount and verify requests
1059 //
1060
1061 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
1062
1063 //
1064 // Send the request down to the driver. If an error occurs return
1065 // it to the caller.
1066 //
1067
1068 Status = IoCallDriver( TargetDeviceObject, Irp );
1069
1070 //
1071 // If the status was STATUS_PENDING then wait on the event.
1072 //
1073
1074 if (Status == STATUS_PENDING) {
1075
1076 Status = KeWaitForSingleObject( &Event,
1077 Executive,
1078 KernelMode,
1079 FALSE,
1080 NULL );
1081
1082 //
1083 // On a successful wait pull the status out of the IoStatus block.
1084 //
1085
1086 if (NT_SUCCESS( Status )) {
1087
1088 Status = IrpContext->Irp->IoStatus.Status;
1089 }
1090 }
1091
1092 //
1093 // Check whether we should raise in the error case.
1094 //
1095
1096 if (!NT_SUCCESS( Status )) {
1097
1098 if (!ReturnError) {
1099
1100 CdNormalizeAndRaiseStatus( IrpContext, Status );
1101 }
1102
1103 //
1104 // We don't raise, but return FALSE to indicate an error.
1105 //
1106
1107 return FALSE;
1108
1109 //
1110 // The operation completed successfully.
1111 //
1112
1113 } else {
1114
1115 return TRUE;
1116 }
1117 }
1118
1119 \f
1120 NTSTATUS
1121 CdCreateUserMdl (
1122 IN PIRP_CONTEXT IrpContext,
1123 IN ULONG BufferLength,
1124 IN BOOLEAN RaiseOnError
1125 )
1126
1127 /*++
1128
1129 Routine Description:
1130
1131 This routine locks the specified buffer for read access (we only write into
1132 the buffer). The file system requires this routine since it does not
1133 ask the I/O system to lock its buffers for direct I/O. This routine
1134 may only be called from the Fsd while still in the user context.
1135
1136 This routine is only called if there is not already an Mdl.
1137
1138 Arguments:
1139
1140 BufferLength - Length of user buffer.
1141
1142 RaiseOnError - Indicates if our caller wants this routine to raise on
1143 an error condition.
1144
1145 Return Value:
1146
1147 NTSTATUS - Status from this routine. Error status only returned if
1148 RaiseOnError is FALSE.
1149
1150 --*/
1151
1152 {
1153 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
1154 PMDL Mdl;
1155
1156 PAGED_CODE();
1157
1158 ASSERT_IRP_CONTEXT( IrpContext );
1159 ASSERT_IRP( IrpContext->Irp );
1160 ASSERT( IrpContext->Irp->MdlAddress == NULL );
1161
1162 //
1163 // Allocate the Mdl, and Raise if we fail.
1164 //
1165
1166 Mdl = IoAllocateMdl( IrpContext->Irp->UserBuffer,
1167 BufferLength,
1168 FALSE,
1169 FALSE,
1170 IrpContext->Irp );
1171
1172 if (Mdl != NULL) {
1173
1174 //
1175 // Now probe the buffer described by the Irp. If we get an exception,
1176 // deallocate the Mdl and return the appropriate "expected" status.
1177 //
1178
1179 try {
1180
1181 MmProbeAndLockPages( Mdl, IrpContext->Irp->RequestorMode, IoWriteAccess );
1182
1183 Status = STATUS_SUCCESS;
1184
1185 } except(EXCEPTION_EXECUTE_HANDLER) {
1186
1187 Status = GetExceptionCode();
1188
1189 IoFreeMdl( Mdl );
1190 IrpContext->Irp->MdlAddress = NULL;
1191
1192 if (!FsRtlIsNtstatusExpected( Status )) {
1193
1194 Status = STATUS_INVALID_USER_BUFFER;
1195 }
1196 }
1197 }
1198
1199 //
1200 // Check if we are to raise or return
1201 //
1202
1203 if (Status != STATUS_SUCCESS) {
1204
1205 if (RaiseOnError) {
1206
1207 CdRaiseStatus( IrpContext, Status );
1208 }
1209 }
1210
1211 //
1212 // Return the status code.
1213 //
1214
1215 return Status;
1216 }
1217
1218 \f
1219 NTSTATUS
1220 CdPerformDevIoCtrl (
1221 IN PIRP_CONTEXT IrpContext,
1222 IN ULONG IoControlCode,
1223 IN PDEVICE_OBJECT Device,
1224 OUT PVOID OutputBuffer OPTIONAL,
1225 IN ULONG OutputBufferLength,
1226 IN BOOLEAN InternalDeviceIoControl,
1227 IN BOOLEAN OverrideVerify,
1228 OUT PIO_STATUS_BLOCK Iosb OPTIONAL
1229 )
1230
1231 /*++
1232
1233 Routine Description:
1234
1235 This routine is called to perform DevIoCtrl functions internally within
1236 the filesystem. We take the status from the driver and return it to our
1237 caller.
1238
1239 Arguments:
1240
1241 IoControlCode - Code to send to driver.
1242
1243 Device - This is the device to send the request to.
1244
1245 OutPutBuffer - Pointer to output buffer.
1246
1247 OutputBufferLength - Length of output buffer above.
1248
1249 InternalDeviceIoControl - Indicates if this is an internal or external
1250 Io control code.
1251
1252 OverrideVerify - Indicates if we should tell the driver not to return
1253 STATUS_VERIFY_REQUIRED for mount and verify.
1254
1255 Iosb - If specified, we return the results of the operation here.
1256
1257 Return Value:
1258
1259 NTSTATUS - Status returned by next lower driver.
1260
1261 --*/
1262
1263 {
1264 NTSTATUS Status;
1265 PIRP Irp;
1266 KEVENT Event;
1267 IO_STATUS_BLOCK LocalIosb;
1268 PIO_STATUS_BLOCK IosbToUse = &LocalIosb;
1269
1270 PAGED_CODE();
1271
1272 //
1273 // Check if the user gave us an Iosb.
1274 //
1275
1276 if (ARGUMENT_PRESENT( Iosb )) {
1277
1278 IosbToUse = Iosb;
1279 }
1280
1281 IosbToUse->Status = 0;
1282 IosbToUse->Information = 0;
1283
1284 KeInitializeEvent( &Event, NotificationEvent, FALSE );
1285
1286 Irp = IoBuildDeviceIoControlRequest( IoControlCode,
1287 Device,
1288 NULL,
1289 0,
1290 OutputBuffer,
1291 OutputBufferLength,
1292 InternalDeviceIoControl,
1293 &Event,
1294 IosbToUse );
1295
1296 if (Irp == NULL) {
1297
1298 return STATUS_INSUFFICIENT_RESOURCES;
1299 }
1300
1301 if (OverrideVerify) {
1302
1303 SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
1304 }
1305
1306 Status = IoCallDriver( Device, Irp );
1307
1308 //
1309 // We check for device not ready by first checking Status
1310 // and then if status pending was returned, the Iosb status
1311 // value.
1312 //
1313
1314 if (Status == STATUS_PENDING) {
1315
1316 (VOID) KeWaitForSingleObject( &Event,
1317 Executive,
1318 KernelMode,
1319 FALSE,
1320 (PLARGE_INTEGER)NULL );
1321
1322 Status = IosbToUse->Status;
1323 }
1324
1325 ASSERT( !(OverrideVerify && (STATUS_VERIFY_REQUIRED == Status)));
1326
1327 return Status;
1328 }
1329
1330 \f
1331 //
1332 // Local support routine
1333 //
1334
1335 BOOLEAN
1336 CdPrepareBuffers (
1337 IN PIRP_CONTEXT IrpContext,
1338 IN PIRP Irp,
1339 IN PFCB Fcb,
1340 IN PVOID UserBuffer,
1341 IN ULONG UserBufferOffset,
1342 IN LONGLONG StartingOffset,
1343 IN ULONG ByteCount,
1344 IN PIO_RUN IoRuns,
1345 IN PULONG RunCount,
1346 IN PULONG ThisByteCount
1347 )
1348
1349 /*++
1350
1351 Routine Description:
1352
1353 This routine is the worker routine which looks up each run of an IO
1354 request and stores an entry for it in the IoRuns array. If the run
1355 begins on an unaligned disk boundary then we will allocate a buffer
1356 and Mdl for the unaligned portion and put it in the IoRuns entry.
1357
1358 This routine will raise CANT_WAIT if an unaligned transfer is encountered
1359 and this request can't wait.
1360
1361 Arguments:
1362
1363 Irp - Originating Irp for this request.
1364
1365 Fcb - This is the Fcb for this data stream. It may be a file, directory,
1366 path table or the volume file.
1367
1368 UserBuffer - Current position in the user's buffer.
1369
1370 UserBufferOffset - Offset from the start of the original user buffer.
1371
1372 StartingOffset - Offset in the stream to begin the read.
1373
1374 ByteCount - Number of bytes to read. We will fill the IoRuns array up
1375 to this point. We will stop early if we exceed the maximum number
1376 of parallel Ios we support.
1377
1378 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1379 this routine is called.
1380
1381 RunCount - Number of entries in the IoRuns array filled here.
1382
1383 ThisByteCount - Number of bytes described by the IoRun entries. Will
1384 not exceed the ByteCount passed in.
1385
1386 Return Value:
1387
1388 BOOLEAN - TRUE if one of the entries in an unaligned buffer (provided
1389 this is synchronous). FALSE otherwise.
1390
1391 --*/
1392
1393 {
1394 BOOLEAN FoundUnaligned = FALSE;
1395 PIO_RUN ThisIoRun = IoRuns;
1396
1397 //
1398 // Following indicate where we are in the current transfer. Current
1399 // position in the file and number of bytes yet to transfer from
1400 // this position.
1401 //
1402
1403 ULONG RemainingByteCount = ByteCount;
1404 LONGLONG CurrentFileOffset = StartingOffset;
1405
1406 //
1407 // Following indicate the state of the user's buffer. We have
1408 // the destination of the next transfer and its offset in the
1409 // buffer. We also have the next available position in the buffer
1410 // available for a scratch buffer. We will align this up to a sector
1411 // boundary.
1412 //
1413
1414 PVOID CurrentUserBuffer = UserBuffer;
1415 ULONG CurrentUserBufferOffset = UserBufferOffset;
1416
1417 PVOID ScratchUserBuffer = UserBuffer;
1418 ULONG ScratchUserBufferOffset = UserBufferOffset;
1419
1420 //
1421 // The following is the next contiguous bytes on the disk to
1422 // transfer. Read from the allocation package.
1423 //
1424
1425 LONGLONG DiskOffset;
1426 ULONG CurrentByteCount;
1427
1428 PAGED_CODE();
1429
1430 //
1431 // Initialize the RunCount and ByteCount.
1432 //
1433
1434 *RunCount = 0;
1435 *ThisByteCount = 0;
1436
1437 //
1438 // Loop while there are more bytes to process or there are
1439 // available entries in the IoRun array.
1440 //
1441
1442 while (TRUE) {
1443
1444 *RunCount += 1;
1445
1446 //
1447 // Initialize the current position in the IoRuns array.
1448 // Find the user's buffer for this portion of the transfer.
1449 //
1450
1451 ThisIoRun->UserBuffer = CurrentUserBuffer;
1452
1453 //
1454 // Find the allocation information for the current offset in the
1455 // stream.
1456 //
1457
1458 CdLookupAllocation( IrpContext,
1459 Fcb,
1460 CurrentFileOffset,
1461 &DiskOffset,
1462 &CurrentByteCount );
1463
1464 //
1465 // Limit ourselves to the data requested.
1466 //
1467
1468 if (CurrentByteCount > RemainingByteCount) {
1469
1470 CurrentByteCount = RemainingByteCount;
1471 }
1472
1473 //
1474 // Handle the case where this is an unaligned transfer. The
1475 // following must all be true for this to be an aligned transfer.
1476 //
1477 // Disk offset on a 2048 byte boundary (Start of transfer)
1478 //
1479 // Byte count is a multiple of 2048 (Length of transfer)
1480 //
1481 // Current buffer offset is also on a 2048 byte boundary.
1482 //
1483 // If the ByteCount is at least one sector then do the
1484 // unaligned transfer only for the tail. We can use the
1485 // user's buffer for the aligned portion.
1486 //
1487
1488 if (FlagOn( (ULONG) DiskOffset, SECTOR_MASK ) ||
1489 FlagOn( CurrentUserBufferOffset, SECTOR_MASK ) ||
1490 (FlagOn( (ULONG) CurrentByteCount, SECTOR_MASK ) &&
1491 (CurrentByteCount < SECTOR_SIZE))) {
1492
1493 //
1494 // If we can't wait then raise.
1495 //
1496
1497 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
1498
1499 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
1500 }
1501
1502 //
1503 // Remember the offset and the number of bytes out of
1504 // the transfer buffer to copy into the user's buffer.
1505 // We will truncate the current read to end on a sector
1506 // boundary.
1507 //
1508
1509 ThisIoRun->TransferBufferOffset = SectorOffset( DiskOffset );
1510
1511 //
1512 // Make sure this transfer ends on a sector boundary.
1513 //
1514
1515 ThisIoRun->DiskOffset = LlSectorTruncate( DiskOffset );
1516
1517 //
1518 // Check if we can use a free portion of the user's buffer.
1519 // If we can copy the bytes to an earlier portion of the
1520 // buffer then read into that location and slide the bytes
1521 // up.
1522 //
1523 // We can use the user's buffer if:
1524 //
1525 // The temporary location in the buffer is before the
1526 // final destination.
1527 //
1528 // There is at least one sector of data to read.
1529 //
1530
1531 if ((ScratchUserBufferOffset + ThisIoRun->TransferBufferOffset < CurrentUserBufferOffset) &&
1532 (ThisIoRun->TransferBufferOffset + CurrentByteCount >= SECTOR_SIZE)) {
1533
1534 ThisIoRun->DiskByteCount = SectorTruncate( ThisIoRun->TransferBufferOffset + CurrentByteCount );
1535 CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
1536 ThisIoRun->TransferByteCount = CurrentByteCount;
1537
1538 //
1539 // Point to the user's buffer and Mdl for this transfer.
1540 //
1541
1542 ThisIoRun->TransferBuffer = ScratchUserBuffer;
1543 ThisIoRun->TransferMdl = Irp->MdlAddress;
1544 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
1545 ScratchUserBufferOffset,
1546 PVOID );
1547
1548 ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
1549 ThisIoRun->DiskByteCount,
1550 PVOID );
1551
1552 ScratchUserBufferOffset += ThisIoRun->DiskByteCount;
1553
1554 //
1555 // Otherwise we need to allocate an auxiliary buffer for the next sector.
1556 //
1557
1558 } else {
1559
1560 //
1561 // Read up to a page containing the partial data
1562 //
1563
1564 ThisIoRun->DiskByteCount = SectorAlign( ThisIoRun->TransferBufferOffset + CurrentByteCount );
1565
1566 if (ThisIoRun->DiskByteCount > PAGE_SIZE) {
1567
1568 ThisIoRun->DiskByteCount = PAGE_SIZE;
1569 }
1570
1571 if (ThisIoRun->TransferBufferOffset + CurrentByteCount > ThisIoRun->DiskByteCount) {
1572
1573 CurrentByteCount = ThisIoRun->DiskByteCount - ThisIoRun->TransferBufferOffset;
1574 }
1575
1576 ThisIoRun->TransferByteCount = CurrentByteCount;
1577
1578 //
1579 // Allocate a buffer for the non-aligned transfer.
1580 //
1581
1582 ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
1583
1584 //
1585 // Allocate and build the Mdl to describe this buffer.
1586 //
1587
1588 ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
1589 PAGE_SIZE,
1590 FALSE,
1591 FALSE,
1592 NULL );
1593
1594 ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
1595
1596 if (ThisIoRun->TransferMdl == NULL) {
1597
1598 IrpContext->Irp->IoStatus.Information = 0;
1599 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
1600 }
1601
1602 MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
1603 }
1604
1605 //
1606 // Remember we found an unaligned transfer.
1607 //
1608
1609 FoundUnaligned = TRUE;
1610
1611 //
1612 // Otherwise we use the buffer and Mdl from the original request.
1613 //
1614
1615 } else {
1616
1617 //
1618 // Truncate the read length to a sector-aligned value. We know
1619 // the length must be at least one sector or we wouldn't be
1620 // here now.
1621 //
1622
1623 CurrentByteCount = SectorTruncate( CurrentByteCount );
1624
1625 //
1626 // Read these sectors from the disk.
1627 //
1628
1629 ThisIoRun->DiskOffset = DiskOffset;
1630 ThisIoRun->DiskByteCount = CurrentByteCount;
1631
1632 //
1633 // Use the user's buffer and Mdl as our transfer buffer
1634 // and Mdl.
1635 //
1636
1637 ThisIoRun->TransferBuffer = CurrentUserBuffer;
1638 ThisIoRun->TransferMdl = Irp->MdlAddress;
1639 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
1640 CurrentUserBufferOffset,
1641 PVOID );
1642
1643 ScratchUserBuffer = Add2Ptr( CurrentUserBuffer,
1644 CurrentByteCount,
1645 PVOID );
1646
1647 ScratchUserBufferOffset += CurrentByteCount;
1648 }
1649
1650 //
1651 // Update our position in the transfer and the RunCount and
1652 // ByteCount for the user.
1653 //
1654
1655 RemainingByteCount -= CurrentByteCount;
1656
1657 //
1658 // Break out if no more positions in the IoRuns array or
1659 // we have all of the bytes accounted for.
1660 //
1661
1662 *ThisByteCount += CurrentByteCount;
1663
1664 if ((RemainingByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
1665
1666 break;
1667 }
1668
1669 //
1670 // Update our pointers for the user's buffer.
1671 //
1672
1673 ThisIoRun += 1;
1674 CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentByteCount, PVOID );
1675 CurrentUserBufferOffset += CurrentByteCount;
1676 CurrentFileOffset += CurrentByteCount;
1677 }
1678
1679 return FoundUnaligned;
1680 }
1681
1682 \f
1683 //
1684 // Local support routine
1685 //
1686
1687 VOID
1688 CdPrepareXABuffers (
1689 IN PIRP_CONTEXT IrpContext,
1690 IN PIRP Irp,
1691 IN PFCB Fcb,
1692 IN PVOID UserBuffer,
1693 IN ULONG UserBufferOffset,
1694 IN LONGLONG StartingOffset,
1695 IN ULONG ByteCount,
1696 IN PIO_RUN IoRuns,
1697 IN PULONG RunCount,
1698 IN PULONG ThisByteCount
1699 )
1700
1701 /*++
1702
1703 Routine Description:
1704
1705 This routine is the worker routine which looks up the individual runs
1706 of an IO request and stores an entry for it in the IoRuns array. The
1707 worker routine is for XA files where we need to convert the raw offset
1708 in the file to logical cooked sectors. We store one raw sector in
1709 the Vcb. If the current read is to that sector then we can simply copy
1710 whatever bytes are needed from that sector.
1711
1712 Arguments:
1713
1714 Irp - Originating Irp for this request.
1715
1716 Fcb - This is the Fcb for this data stream. It must be a data stream.
1717
1718 UserBuffer - Current position in the user's buffer.
1719
1720 UserBufferOffset - Offset of this buffer from the beginning of the user's
1721 buffer for the original request.
1722
1723 StartingOffset - Offset in the stream to begin the read.
1724
1725 ByteCount - Number of bytes to read. We will fill the IoRuns array up
1726 to this point. We will stop early if we exceed the maximum number
1727 of parallel Ios we support.
1728
1729 IoRuns - Pointer to the IoRuns array. The entire array is zeroes when
1730 this routine is called.
1731
1732 RunCount - Number of entries in the IoRuns array filled here.
1733
1734 ThisByteCount - Number of bytes described by the IoRun entries. Will
1735 not exceed the ByteCount passed in.
1736
1737 Return Value:
1738
1739 None
1740
1741 --*/
1742
1743 {
1744 PIO_RUN ThisIoRun = IoRuns;
1745 BOOLEAN PerformedCopy;
1746
1747 //
1748 // The following deal with where we are in the range of raw sectors.
1749 // Note that we will bias the input file offset by the RIFF header
1750 // to deal directly with the raw sectors.
1751 //
1752
1753 ULONG RawSectorOffset;
1754 ULONG RemainingRawByteCount = ByteCount;
1755 LONGLONG CurrentRawOffset = StartingOffset - sizeof( RIFF_HEADER );
1756
1757 //
1758 // The following is the offset into the cooked sectors for the file.
1759 //
1760
1761 LONGLONG CurrentCookedOffset;
1762 ULONG RemainingCookedByteCount;
1763
1764 //
1765 // Following indicate the state of the user's buffer. We have
1766 // the destination of the next transfer and its offset in the
1767 // buffer. We also have the next available position in the buffer
1768 // available for a scratch buffer.
1769 //
1770
1771 PVOID CurrentUserBuffer = UserBuffer;
1772 ULONG CurrentUserBufferOffset = UserBufferOffset;
1773
1774 PVOID ScratchUserBuffer = UserBuffer;
1775 ULONG ScratchUserBufferOffset = UserBufferOffset;
1776 BOOLEAN RoundScratchBuffer = TRUE;
1777
1778 //
1779 // The following is the next contiguous bytes on the disk to
1780 // transfer. These are represented by cooked byte offset and length.
1781 // We also compute the number of raw bytes in the current transfer.
1782 //
1783
1784 LONGLONG DiskOffset;
1785 ULONG CurrentCookedByteCount;
1786 ULONG CurrentRawByteCount;
1787
1788 PAGED_CODE();
1789
1790 //
1791 // We need to maintain our position as we walk through the sectors on the disk.
1792 // We keep separate values for the cooked offset as well as the raw offset.
1793 // These are initialized on sector boundaries and we move through these
1794 // the file sector-by-sector.
1795 //
1796 // Try to do 32-bit math.
1797 //
1798
1799 if (((PLARGE_INTEGER) &CurrentRawOffset)->HighPart == 0) {
1800
1801 //
1802 // Prefix/fast: Note that the following are safe since we only
1803 // take this path for 32bit offsets.
1804 //
1805
1806 CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset / RAW_SECTOR_SIZE);
1807
1808 CurrentCookedOffset = (LONGLONG) ((ULONG) CurrentRawOffset << SECTOR_SHIFT );
1809
1810 CurrentRawOffset = (LONGLONG) ((ULONG) CurrentRawOffset * RAW_SECTOR_SIZE);
1811
1812 //
1813 // Otherwise we need to do 64-bit math (sigh).
1814 //
1815
1816 } else {
1817
1818 CurrentRawOffset /= RAW_SECTOR_SIZE;
1819
1820 CurrentCookedOffset = CurrentRawOffset << SECTOR_SHIFT;
1821
1822 CurrentRawOffset *= RAW_SECTOR_SIZE;
1823 }
1824
1825 //
1826 // Now compute the full number of sectors to be read. Count all of the raw
1827 // sectors that need to be read and convert to cooked bytes.
1828 //
1829
1830 RawSectorOffset = (ULONG) ( StartingOffset - CurrentRawOffset) - sizeof( RIFF_HEADER );
1831 CurrentRawByteCount = (RawSectorOffset + RemainingRawByteCount + RAW_SECTOR_SIZE - 1) / RAW_SECTOR_SIZE;
1832
1833 RemainingCookedByteCount = CurrentRawByteCount << SECTOR_SHIFT;
1834
1835 //
1836 // Initialize the RunCount and ByteCount.
1837 //
1838
1839 *RunCount = 0;
1840 *ThisByteCount = 0;
1841
1842 //
1843 // Loop while there are more bytes to process or there are
1844 // available entries in the IoRun array.
1845 //
1846
1847 while (TRUE) {
1848
1849 PerformedCopy = FALSE;
1850 *RunCount += 1;
1851
1852 //
1853 // Round the scratch buffer up to a sector boundary for alignment.
1854 //
1855
1856 if (RoundScratchBuffer) {
1857
1858 if (SectorOffset( ScratchUserBuffer ) != 0) {
1859
1860 CurrentRawByteCount = SECTOR_SIZE - SectorOffset( ScratchUserBuffer );
1861
1862 ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
1863 CurrentRawByteCount,
1864 PVOID );
1865
1866 ScratchUserBufferOffset += CurrentRawByteCount;
1867 }
1868
1869 RoundScratchBuffer = FALSE;
1870 }
1871
1872 //
1873 // Initialize the current position in the IoRuns array. Find the
1874 // eventual destination in the user's buffer for this portion of the transfer.
1875 //
1876
1877 ThisIoRun->UserBuffer = CurrentUserBuffer;
1878
1879 //
1880 // Find the allocation information for the current offset in the
1881 // stream.
1882 //
1883
1884 CdLookupAllocation( IrpContext,
1885 Fcb,
1886 CurrentCookedOffset,
1887 &DiskOffset,
1888 &CurrentCookedByteCount );
1889 //
1890 // Maybe we got lucky and this is the same sector as in the
1891 // Vcb.
1892 //
1893
1894 if (DiskOffset == Fcb->Vcb->XADiskOffset) {
1895
1896 //
1897 // We will perform safe synchronization. Check again that
1898 // this is the correct sector.
1899 //
1900
1901 CdLockVcb( IrpContext, Fcb->Vcb );
1902
1903 if ((DiskOffset == Fcb->Vcb->XADiskOffset) &&
1904 (Fcb->Vcb->XASector != NULL)) {
1905
1906 //
1907 // Copy any bytes we can from the current sector.
1908 //
1909
1910 CurrentRawByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
1911
1912 //
1913 // Check whether we don't go to the end of the sector.
1914 //
1915
1916 if (CurrentRawByteCount > RemainingRawByteCount) {
1917
1918 CurrentRawByteCount = RemainingRawByteCount;
1919 }
1920
1921 RtlCopyMemory( CurrentUserBuffer,
1922 Add2Ptr( Fcb->Vcb->XASector, RawSectorOffset, PCHAR ),
1923 CurrentRawByteCount );
1924
1925 CdUnlockVcb( IrpContext, Fcb->Vcb );
1926
1927 //
1928 // Adjust the run count and pointer in the IoRuns array
1929 // to show that we didn't use a position.
1930 //
1931
1932 *RunCount -= 1;
1933 ThisIoRun -= 1;
1934
1935 //
1936 // Remember that we performed a copy operation and update
1937 // the next available position in the scratch buffer.
1938 //
1939
1940 PerformedCopy = TRUE;
1941
1942 ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
1943 CurrentRawByteCount,
1944 PVOID );
1945
1946 ScratchUserBufferOffset += CurrentRawByteCount;
1947
1948 CurrentCookedByteCount = SECTOR_SIZE;
1949
1950 //
1951 // Set the flag indicating we want to round the scratch buffer
1952 // to a sector boundary.
1953 //
1954
1955 RoundScratchBuffer = TRUE;
1956
1957 } else {
1958
1959 //
1960 // The safe test showed no available buffer. Drop down to common code to
1961 // perform the Io.
1962 //
1963
1964 CdUnlockVcb( IrpContext, Fcb->Vcb );
1965 }
1966 }
1967
1968 //
1969 // No work in this pass if we did a copy operation.
1970 //
1971
1972 if (!PerformedCopy) {
1973
1974 //
1975 // Limit ourselves by the number of remaining cooked bytes.
1976 //
1977
1978 if (CurrentCookedByteCount > RemainingCookedByteCount) {
1979
1980 CurrentCookedByteCount = RemainingCookedByteCount;
1981 }
1982
1983 ThisIoRun->DiskOffset = DiskOffset;
1984 ThisIoRun->TransferBufferOffset = RawSectorOffset;
1985
1986 //
1987 // We will always need to perform copy operations for XA files.
1988 // We allocate an auxillary buffer to read the start of the
1989 // transfer. Then we can use a range of the user's buffer to
1990 // perform the next range of the transfer. Finally we may
1991 // need to allocate a buffer for the tail of the transfer.
1992 //
1993 // We can use the user's buffer (at the current scratch buffer) if the
1994 // following are true:
1995 //
1996 // If we are to store the beginning of the raw sector in the user's buffer.
1997 // The current scratch buffer precedes the destination in the user's buffer
1998 // (and hence also lies within it)
1999 // There are enough bytes remaining in the buffer for at least one
2000 // raw sector.
2001 //
2002
2003 if ((RawSectorOffset == 0) &&
2004 (ScratchUserBufferOffset <= CurrentUserBufferOffset) &&
2005 (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount >= RAW_SECTOR_SIZE)) {
2006
2007 //
2008 // We can use the scratch buffer. We must ensure we don't send down reads
2009 // greater than the device can handle, since the driver is unable to split
2010 // raw requests.
2011 //
2012
2013 if (CurrentCookedByteCount <= Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE) {
2014
2015 CurrentRawByteCount = (SectorAlign( CurrentCookedByteCount) >> SECTOR_SHIFT) * RAW_SECTOR_SIZE;
2016
2017 } else {
2018
2019 CurrentCookedByteCount = Fcb->Vcb->MaximumTransferRawSectors * SECTOR_SIZE;
2020 CurrentRawByteCount = Fcb->Vcb->MaximumTransferRawSectors * RAW_SECTOR_SIZE;
2021 }
2022
2023 //
2024 // Now make sure we are within the page transfer limit.
2025 //
2026
2027 while (ADDRESS_AND_SIZE_TO_SPAN_PAGES(ScratchUserBuffer, RawSectorAlign( CurrentRawByteCount)) >
2028 Fcb->Vcb->MaximumPhysicalPages ) {
2029
2030 CurrentRawByteCount -= RAW_SECTOR_SIZE;
2031 CurrentCookedByteCount -= SECTOR_SIZE;
2032 }
2033
2034 //
2035 // Trim the number of bytes to read if it won't fit into the current buffer. Take
2036 // account of the fact that we must read in whole raw sector multiples.
2037 //
2038
2039 while ( RawSectorAlign( CurrentRawByteCount) >
2040 (CurrentUserBufferOffset - ScratchUserBufferOffset + RemainingRawByteCount) ) {
2041
2042 CurrentRawByteCount -= RAW_SECTOR_SIZE;
2043 CurrentCookedByteCount -= SECTOR_SIZE;
2044 }
2045
2046 //
2047 // Now trim the maximum number of raw bytes to the remaining bytes.
2048 //
2049
2050 if (CurrentRawByteCount > RemainingRawByteCount) {
2051
2052 CurrentRawByteCount = RemainingRawByteCount;
2053 }
2054
2055 //
2056 // Update the IO run array. We point to the scratch buffer as
2057 // well as the buffer and Mdl in the original Irp.
2058 //
2059
2060 ThisIoRun->DiskByteCount = SectorAlign( CurrentCookedByteCount);
2061
2062 //
2063 // Store the number of bytes which we actually care about from this transfer
2064 //
2065
2066 ThisIoRun->TransferByteCount = CurrentRawByteCount;
2067
2068 //
2069 // Point to the user's buffer and Mdl for this transfer.
2070 //
2071
2072 ThisIoRun->TransferBuffer = ScratchUserBuffer;
2073 ThisIoRun->TransferMdl = Irp->MdlAddress;
2074 ThisIoRun->TransferVirtualAddress = Add2Ptr( Irp->UserBuffer,
2075 ScratchUserBufferOffset,
2076 PVOID);
2077 //
2078 // Update the scratch buffer pointer. Note that since the underlying
2079 // driver stack will always transfer in multiples of raw sectors,
2080 // we must round up here rather than simply advancing by the length of the
2081 // of the data which we actually care about.
2082 //
2083
2084 ScratchUserBuffer = Add2Ptr( ScratchUserBuffer,
2085 RawSectorAlign( CurrentRawByteCount),
2086 PVOID );
2087
2088 ScratchUserBufferOffset += RawSectorAlign( CurrentRawByteCount);
2089
2090 //
2091 // Set the flag indicating we want to round the scratch buffer
2092 // to a cooked sector boundary.
2093 //
2094
2095 RoundScratchBuffer = TRUE;
2096
2097 } else {
2098
2099 //
2100 // We need to determine the number of bytes to transfer and the
2101 // offset into this page to begin the transfer.
2102 //
2103 // We will transfer only one raw sector.
2104 //
2105
2106 ThisIoRun->DiskByteCount = SECTOR_SIZE;
2107
2108 CurrentCookedByteCount = SECTOR_SIZE;
2109
2110 ThisIoRun->TransferByteCount = RAW_SECTOR_SIZE - RawSectorOffset;
2111 ThisIoRun->TransferBufferOffset = RawSectorOffset;
2112
2113 if (ThisIoRun->TransferByteCount > RemainingRawByteCount) {
2114
2115 ThisIoRun->TransferByteCount = RemainingRawByteCount;
2116 }
2117
2118 CurrentRawByteCount = ThisIoRun->TransferByteCount;
2119
2120 //
2121 // We need to allocate an auxillary buffer. We will allocate
2122 // a single page. Then we will build an Mdl to describe the buffer.
2123 //
2124
2125 ThisIoRun->TransferBuffer = FsRtlAllocatePoolWithTag( CdNonPagedPool, PAGE_SIZE, TAG_IO_BUFFER );
2126
2127 //
2128 // Allocate and build the Mdl to describe this buffer.
2129 //
2130
2131 ThisIoRun->TransferMdl = IoAllocateMdl( ThisIoRun->TransferBuffer,
2132 PAGE_SIZE,
2133 FALSE,
2134 FALSE,
2135 NULL );
2136
2137 ThisIoRun->TransferVirtualAddress = ThisIoRun->TransferBuffer;
2138
2139 if (ThisIoRun->TransferMdl == NULL) {
2140
2141 IrpContext->Irp->IoStatus.Information = 0;
2142 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2143 }
2144
2145 MmBuildMdlForNonPagedPool( ThisIoRun->TransferMdl );
2146 }
2147 }
2148
2149 //
2150 // Update the byte count for our caller.
2151 //
2152
2153 RemainingRawByteCount -= CurrentRawByteCount;
2154 *ThisByteCount += CurrentRawByteCount;
2155
2156 //
2157 // Break out if no more positions in the IoRuns array or
2158 // we have all of the bytes accounted for.
2159 //
2160
2161 if ((RemainingRawByteCount == 0) || (*RunCount == MAX_PARALLEL_IOS)) {
2162
2163 break;
2164 }
2165
2166 //
2167 // Update our local pointers to allow for the current range of bytes.
2168 //
2169
2170 ThisIoRun += 1;
2171
2172 CurrentUserBuffer = Add2Ptr( CurrentUserBuffer, CurrentRawByteCount, PVOID );
2173 CurrentUserBufferOffset += CurrentRawByteCount;
2174
2175 RawSectorOffset = 0;
2176
2177 CurrentCookedOffset += CurrentCookedByteCount;
2178 RemainingCookedByteCount -= CurrentCookedByteCount;
2179 }
2180
2181 return;
2182 }
2183
2184 \f
2185 //
2186 // Local support routine
2187 //
2188
2189 BOOLEAN
2190 CdFinishBuffers (
2191 IN PIRP_CONTEXT IrpContext,
2192 IN PIO_RUN IoRuns,
2193 IN ULONG RunCount,
2194 IN BOOLEAN FinalCleanup,
2195 IN BOOLEAN SaveXABuffer
2196 )
2197
2198 /*++
2199
2200 Routine Description:
2201
2202 This routine is called to perform any data transferred required for
2203 unaligned Io or to perform the final cleanup of the IoRuns array.
2204
2205 In all cases this is where we will deallocate any buffer and mdl
2206 allocated to perform the unaligned transfer. If this is not the
2207 final cleanup then we also transfer the bytes to the user buffer
2208 and flush the hardware cache.
2209
2210 We walk backwards through the run array because we may be shifting data
2211 in the user's buffer. Typical case is where we allocated a buffer for
2212 the first part of a read and then used the user's buffer for the
2213 next section (but stored it at the beginning of the buffer.
2214
2215 Arguments:
2216
2217 IoRuns - Pointer to the IoRuns array.
2218
2219 RunCount - Number of entries in the IoRuns array filled here.
2220
2221 FinalCleanup - Indicates if we should be deallocating temporary buffers
2222 (TRUE) or transferring bytes for a unaligned transfers and
2223 deallocating the buffers (FALSE). Flush the system cache if
2224 transferring data.
2225
2226 SaveXABuffer - TRUE if we should try to save an XA buffer, FALSE otherwise
2227
2228 Return Value:
2229
2230 BOOLEAN - TRUE if this request needs the Io buffers to be flushed, FALSE otherwise.
2231
2232 --*/
2233
2234 {
2235 BOOLEAN FlushIoBuffers = FALSE;
2236
2237 ULONG RemainingEntries = RunCount;
2238 PIO_RUN ThisIoRun = &IoRuns[RunCount - 1];
2239 PVCB Vcb;
2240
2241 PAGED_CODE();
2242
2243 //
2244 // Walk through each entry in the IoRun array.
2245 //
2246
2247 while (RemainingEntries != 0) {
2248
2249 //
2250 // We only need to deal with the case of an unaligned transfer.
2251 //
2252
2253 if (ThisIoRun->TransferByteCount != 0) {
2254
2255 //
2256 // If not the final cleanup then transfer the data to the
2257 // user's buffer and remember that we will need to flush
2258 // the user's buffer to memory.
2259 //
2260
2261 if (!FinalCleanup) {
2262
2263 //
2264 // If we are shifting in the user's buffer then use
2265 // MoveMemory.
2266 //
2267
2268 if (ThisIoRun->TransferMdl == IrpContext->Irp->MdlAddress) {
2269
2270 RtlMoveMemory( ThisIoRun->UserBuffer,
2271 Add2Ptr( ThisIoRun->TransferBuffer,
2272 ThisIoRun->TransferBufferOffset,
2273 PVOID ),
2274 ThisIoRun->TransferByteCount );
2275
2276 } else {
2277
2278 RtlCopyMemory( ThisIoRun->UserBuffer,
2279 Add2Ptr( ThisIoRun->TransferBuffer,
2280 ThisIoRun->TransferBufferOffset,
2281 PVOID ),
2282 ThisIoRun->TransferByteCount );
2283 }
2284
2285 FlushIoBuffers = TRUE;
2286 }
2287
2288 //
2289 // Free any Mdl we may have allocated. If the Mdl isn't
2290 // present then we must have failed during the allocation
2291 // phase.
2292 //
2293
2294 if (ThisIoRun->TransferMdl != IrpContext->Irp->MdlAddress) {
2295
2296 if (ThisIoRun->TransferMdl != NULL) {
2297
2298 IoFreeMdl( ThisIoRun->TransferMdl );
2299 }
2300
2301 //
2302 // Now free any buffer we may have allocated. If the Mdl
2303 // doesn't match the original Mdl then free the buffer.
2304 //
2305
2306 if (ThisIoRun->TransferBuffer != NULL) {
2307
2308 //
2309 // If this is the final buffer for an XA read then store this buffer
2310 // into the Vcb so that we will have it when reading any remaining
2311 // portion of this buffer.
2312 //
2313
2314 if (SaveXABuffer) {
2315
2316 Vcb = IrpContext->Vcb;
2317
2318 CdLockVcb( IrpContext, Vcb );
2319
2320 if (Vcb->XASector != NULL) {
2321
2322 CdFreePool( &Vcb->XASector );
2323 }
2324
2325 Vcb->XASector = ThisIoRun->TransferBuffer;
2326 Vcb->XADiskOffset = ThisIoRun->DiskOffset;
2327
2328 SaveXABuffer = FALSE;
2329
2330 CdUnlockVcb( IrpContext, Vcb );
2331
2332 //
2333 // Otherwise just free the buffer.
2334 //
2335
2336 } else {
2337
2338 CdFreePool( &ThisIoRun->TransferBuffer );
2339 }
2340 }
2341 }
2342 }
2343
2344 //
2345 // Now handle the case where we failed in the process
2346 // of allocating associated Irps and Mdls.
2347 //
2348
2349 if (ThisIoRun->SavedIrp != NULL) {
2350
2351 if (ThisIoRun->SavedIrp->MdlAddress != NULL) {
2352
2353 IoFreeMdl( ThisIoRun->SavedIrp->MdlAddress );
2354 }
2355
2356 IoFreeIrp( ThisIoRun->SavedIrp );
2357 }
2358
2359 //
2360 // Move to the previous IoRun entry.
2361 //
2362
2363 ThisIoRun -= 1;
2364 RemainingEntries -= 1;
2365 }
2366
2367 //
2368 // If we copied any data then flush the Io buffers.
2369 //
2370
2371 return FlushIoBuffers;
2372 }
2373
2374 \f
2375 //
2376 // Local support routine
2377 //
2378
2379 VOID
2380 CdMultipleAsync (
2381 IN PIRP_CONTEXT IrpContext,
2382 IN ULONG RunCount,
2383 IN PIO_RUN IoRuns
2384 )
2385
2386 /*++
2387
2388 Routine Description:
2389
2390 This routine first does the initial setup required of a Master IRP that is
2391 going to be completed using associated IRPs. This routine should not
2392 be used if only one async request is needed, instead the single read
2393 async routines should be called.
2394
2395 A context parameter is initialized, to serve as a communications area
2396 between here and the common completion routine.
2397
2398 Next this routine reads or writes one or more contiguous sectors from
2399 a device asynchronously, and is used if there are multiple reads for a
2400 master IRP. A completion routine is used to synchronize with the
2401 completion of all of the I/O requests started by calls to this routine.
2402
2403 Also, prior to calling this routine the caller must initialize the
2404 IoStatus field in the Context, with the correct success status and byte
2405 count which are expected if all of the parallel transfers complete
2406 successfully. After return this status will be unchanged if all requests
2407 were, in fact, successful. However, if one or more errors occur, the
2408 IoStatus will be modified to reflect the error status and byte count
2409 from the first run (by Vbo) which encountered an error. I/O status
2410 from all subsequent runs will not be indicated.
2411
2412 Arguments:
2413
2414 RunCount - Supplies the number of multiple async requests
2415 that will be issued against the master irp.
2416
2417 IoRuns - Supplies an array containing the Offset and ByteCount for the
2418 separate requests.
2419
2420 Return Value:
2421
2422 None.
2423
2424 --*/
2425
2426 {
2427 PIO_COMPLETION_ROUTINE CompletionRoutine;
2428 PIO_STACK_LOCATION IrpSp;
2429 PMDL Mdl;
2430 PIRP Irp;
2431 PIRP MasterIrp;
2432 ULONG UnwindRunCount;
2433
2434 PAGED_CODE();
2435
2436 //
2437 // Set up things according to whether this is truely async.
2438 //
2439
2440 CompletionRoutine = CdMultiSyncCompletionRoutine;
2441
2442 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
2443
2444 CompletionRoutine = CdMultiAsyncCompletionRoutine;
2445 }
2446
2447 //
2448 // Initialize some local variables.
2449 //
2450
2451 MasterIrp = IrpContext->Irp;
2452
2453 //
2454 // Iterate through the runs, doing everything that can fail.
2455 // We let the cleanup in CdFinishBuffers clean up on error.
2456 //
2457
2458 for (UnwindRunCount = 0;
2459 UnwindRunCount < RunCount;
2460 UnwindRunCount += 1) {
2461
2462 //
2463 // Create an associated IRP, making sure there is one stack entry for
2464 // us, as well.
2465 //
2466
2467 IoRuns[UnwindRunCount].SavedIrp =
2468 Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
2469
2470 if (Irp == NULL) {
2471
2472 IrpContext->Irp->IoStatus.Information = 0;
2473 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2474 }
2475
2476 //
2477 // Allocate and build a partial Mdl for the request.
2478 //
2479
2480 Mdl = IoAllocateMdl( IoRuns[UnwindRunCount].TransferVirtualAddress,
2481 IoRuns[UnwindRunCount].DiskByteCount,
2482 FALSE,
2483 FALSE,
2484 Irp );
2485
2486 if (Mdl == NULL) {
2487
2488 IrpContext->Irp->IoStatus.Information = 0;
2489 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2490 }
2491
2492 IoBuildPartialMdl( IoRuns[UnwindRunCount].TransferMdl,
2493 Mdl,
2494 IoRuns[UnwindRunCount].TransferVirtualAddress,
2495 IoRuns[UnwindRunCount].DiskByteCount );
2496
2497 //
2498 // Get the first IRP stack location in the associated Irp
2499 //
2500
2501 IoSetNextIrpStackLocation( Irp );
2502 IrpSp = IoGetCurrentIrpStackLocation( Irp );
2503
2504 //
2505 // Setup the Stack location to describe our read.
2506 //
2507
2508 IrpSp->MajorFunction = IRP_MJ_READ;
2509 IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
2510 IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
2511
2512 //
2513 // Set up the completion routine address in our stack frame.
2514 //
2515
2516 IoSetCompletionRoutine( Irp,
2517 CompletionRoutine,
2518 IrpContext->IoContext,
2519 TRUE,
2520 TRUE,
2521 TRUE );
2522
2523 //
2524 // Setup the next IRP stack location in the associated Irp for the disk
2525 // driver beneath us.
2526 //
2527
2528 IrpSp = IoGetNextIrpStackLocation( Irp );
2529
2530 //
2531 // Setup the Stack location to do a read from the disk driver.
2532 //
2533
2534 IrpSp->MajorFunction = IRP_MJ_READ;
2535 IrpSp->Parameters.Read.Length = IoRuns[UnwindRunCount].DiskByteCount;
2536 IrpSp->Parameters.Read.ByteOffset.QuadPart = IoRuns[UnwindRunCount].DiskOffset;
2537 }
2538
2539 //
2540 // We only need to set the associated IRP count in the master irp to
2541 // make it a master IRP. But we set the count to one more than our
2542 // caller requested, because we do not want the I/O system to complete
2543 // the I/O. We also set our own count.
2544 //
2545
2546 IrpContext->IoContext->IrpCount = RunCount;
2547 IrpContext->IoContext->MasterIrp = MasterIrp;
2548
2549 //
2550 // We set the count in the master Irp to 1 since typically we
2551 // will clean up the associated irps ourselves. Setting this to one
2552 // means completing the last associated Irp with SUCCESS (in the async
2553 // case) will complete the master irp.
2554 //
2555
2556 MasterIrp->AssociatedIrp.IrpCount = 1;
2557
2558 //
2559 // Now that all the dangerous work is done, issue the Io requests
2560 //
2561
2562 for (UnwindRunCount = 0;
2563 UnwindRunCount < RunCount;
2564 UnwindRunCount++) {
2565
2566 Irp = IoRuns[UnwindRunCount].SavedIrp;
2567 IoRuns[UnwindRunCount].SavedIrp = NULL;
2568
2569 //
2570 // If IoCallDriver returns an error, it has completed the Irp
2571 // and the error will be caught by our completion routines
2572 // and dealt with as a normal IO error.
2573 //
2574
2575 (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
2576 }
2577
2578 return;
2579 }
2580
2581 \f
2582 //
2583 // Local support routine
2584 //
2585
2586 VOID
2587 CdMultipleXAAsync (
2588 IN PIRP_CONTEXT IrpContext,
2589 IN ULONG RunCount,
2590 IN PIO_RUN IoRuns,
2591 IN PRAW_READ_INFO RawReads,
2592 IN TRACK_MODE_TYPE TrackMode
2593 )
2594
2595 /*++
2596
2597 Routine Description:
2598
2599 This routine first does the initial setup required of a Master IRP that is
2600 going to be completed using associated IRPs. This routine is used to generate
2601 the associated Irps used to read raw sectors from the disk.
2602
2603 A context parameter is initialized, to serve as a communications area
2604 between here and the common completion routine.
2605
2606 Next this routine reads or writes one or more contiguous sectors from
2607 a device asynchronously, and is used if there are multiple reads for a
2608 master IRP. A completion routine is used to synchronize with the
2609 completion of all of the I/O requests started by calls to this routine.
2610
2611 Also, prior to calling this routine the caller must initialize the
2612 IoStatus field in the Context, with the correct success status and byte
2613 count which are expected if all of the parallel transfers complete
2614 successfully. After return this status will be unchanged if all requests
2615 were, in fact, successful. However, if one or more errors occur, the
2616 IoStatus will be modified to reflect the error status and byte count
2617 from the first run (by Vbo) which encountered an error. I/O status
2618 from all subsequent runs will not be indicated.
2619
2620 Arguments:
2621
2622 RunCount - Supplies the number of multiple async requests
2623 that will be issued against the master irp.
2624
2625 IoRuns - Supplies an array containing the Offset and ByteCount for the
2626 separate requests.
2627
2628 RawReads - Supplies an array of structures to store in the Irps passed to the
2629 device driver to perform the low-level Io.
2630
2631 TrackMode - Supplies the recording mode of sectors in these IoRuns
2632
2633 Return Value:
2634
2635 None.
2636
2637 --*/
2638
2639 {
2640 PIO_STACK_LOCATION IrpSp;
2641 PMDL Mdl;
2642 PIRP Irp;
2643 PIRP MasterIrp;
2644 ULONG UnwindRunCount;
2645 ULONG RawByteCount;
2646
2647 PIO_RUN ThisIoRun = IoRuns;
2648 PRAW_READ_INFO ThisRawRead = RawReads;
2649
2650 PAGED_CODE();
2651
2652 //
2653 // Initialize some local variables.
2654 //
2655
2656 MasterIrp = IrpContext->Irp;
2657
2658 //
2659 // Iterate through the runs, doing everything that can fail.
2660 // We let the cleanup in CdFinishBuffers clean up on error.
2661 //
2662
2663 for (UnwindRunCount = 0;
2664 UnwindRunCount < RunCount;
2665 UnwindRunCount += 1, ThisIoRun += 1, ThisRawRead += 1) {
2666
2667 //
2668 // Create an associated IRP, making sure there is one stack entry for
2669 // us, as well.
2670 //
2671
2672 ThisIoRun->SavedIrp =
2673 Irp = IoMakeAssociatedIrp( MasterIrp, (CCHAR)(IrpContext->Vcb->TargetDeviceObject->StackSize + 1) );
2674
2675 if (Irp == NULL) {
2676
2677 IrpContext->Irp->IoStatus.Information = 0;
2678 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2679 }
2680
2681 //
2682 // Should have been passed a byte count of at least one sector, and
2683 // must be a multiple of sector size
2684 //
2685
2686 ASSERT( ThisIoRun->DiskByteCount && !SectorOffset(ThisIoRun->DiskByteCount));
2687
2688 RawByteCount = SectorsFromBytes( ThisIoRun->DiskByteCount) * RAW_SECTOR_SIZE;
2689
2690 //
2691 // Allocate and build a partial Mdl for the request.
2692 //
2693
2694 Mdl = IoAllocateMdl( ThisIoRun->TransferVirtualAddress,
2695 RawByteCount,
2696 FALSE,
2697 FALSE,
2698 Irp );
2699
2700 if (Mdl == NULL) {
2701
2702 IrpContext->Irp->IoStatus.Information = 0;
2703 CdRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
2704 }
2705
2706 IoBuildPartialMdl( ThisIoRun->TransferMdl,
2707 Mdl,
2708 ThisIoRun->TransferVirtualAddress,
2709 RawByteCount);
2710 //
2711 // Get the first IRP stack location in the associated Irp
2712 //
2713
2714 IoSetNextIrpStackLocation( Irp );
2715 IrpSp = IoGetCurrentIrpStackLocation( Irp );
2716
2717 //
2718 // Setup the Stack location to describe our read (using cooked values)
2719 // These values won't be used for the raw read in any case.
2720 //
2721
2722 IrpSp->MajorFunction = IRP_MJ_READ;
2723 IrpSp->Parameters.Read.Length = ThisIoRun->DiskByteCount;
2724 IrpSp->Parameters.Read.ByteOffset.QuadPart = ThisIoRun->DiskOffset;
2725
2726 //
2727 // Set up the completion routine address in our stack frame.
2728 //
2729
2730 IoSetCompletionRoutine( Irp,
2731 CdMultiSyncCompletionRoutine,
2732 IrpContext->IoContext,
2733 TRUE,
2734 TRUE,
2735 TRUE );
2736
2737 //
2738 // Setup the next IRP stack location in the associated Irp for the disk
2739 // driver beneath us.
2740 //
2741
2742 IrpSp = IoGetNextIrpStackLocation( Irp );
2743
2744 //
2745 // Setup the stack location to do a read of raw sectors at this location.
2746 // Note that the storage stack always reads multiples of whole XA sectors.
2747 //
2748
2749 ThisRawRead->DiskOffset.QuadPart = ThisIoRun->DiskOffset;
2750 ThisRawRead->SectorCount = ThisIoRun->DiskByteCount >> SECTOR_SHIFT;
2751 ThisRawRead->TrackMode = TrackMode;
2752
2753 IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
2754
2755 IrpSp->Parameters.DeviceIoControl.OutputBufferLength = ThisRawRead->SectorCount * RAW_SECTOR_SIZE;
2756 Irp->UserBuffer = ThisIoRun->TransferVirtualAddress;
2757
2758 IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof( RAW_READ_INFO );
2759 IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = ThisRawRead;
2760
2761 IrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_CDROM_RAW_READ;
2762 }
2763
2764 //
2765 // We only need to set the associated IRP count in the master irp to
2766 // make it a master IRP. But we set the count to one more than our
2767 // caller requested, because we do not want the I/O system to complete
2768 // the I/O. We also set our own count.
2769 //
2770
2771 IrpContext->IoContext->IrpCount = RunCount;
2772 IrpContext->IoContext->MasterIrp = MasterIrp;
2773
2774 //
2775 // We set the count in the master Irp to 1 since typically we
2776 // will clean up the associated irps ourselves. Setting this to one
2777 // means completing the last associated Irp with SUCCESS (in the async
2778 // case) will complete the master irp.
2779 //
2780
2781 MasterIrp->AssociatedIrp.IrpCount = 1;
2782
2783 //
2784 // Now that all the dangerous work is done, issue the Io requests
2785 //
2786
2787 for (UnwindRunCount = 0;
2788 UnwindRunCount < RunCount;
2789 UnwindRunCount++) {
2790
2791 Irp = IoRuns[UnwindRunCount].SavedIrp;
2792 IoRuns[UnwindRunCount].SavedIrp = NULL;
2793
2794 //
2795 //
2796 // If IoCallDriver returns an error, it has completed the Irp
2797 // and the error will be caught by our completion routines
2798 // and dealt with as a normal IO error.
2799 //
2800
2801 (VOID) IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp );
2802 }
2803
2804 return;
2805 }
2806
2807 \f
2808 //
2809 // Local support routine
2810 //
2811
2812 VOID
2813 CdSingleAsync (
2814 IN PIRP_CONTEXT IrpContext,
2815 IN LONGLONG ByteOffset,
2816 IN ULONG ByteCount
2817 )
2818
2819 /*++
2820
2821 Routine Description:
2822
2823 This routine reads one or more contiguous sectors from a device
2824 asynchronously, and is used if there is only one read necessary to
2825 complete the IRP. It implements the read by simply filling
2826 in the next stack frame in the Irp, and passing it on. The transfer
2827 occurs to the single buffer originally specified in the user request.
2828
2829 Arguments:
2830
2831 ByteOffset - Supplies the starting Logical Byte Offset to begin reading from
2832
2833 ByteCount - Supplies the number of bytes to read from the device
2834
2835 Return Value:
2836
2837 None.
2838
2839 --*/
2840
2841 {
2842 PIO_STACK_LOCATION IrpSp;
2843 PIO_COMPLETION_ROUTINE CompletionRoutine;
2844
2845 PAGED_CODE();
2846
2847 //
2848 // Set up things according to whether this is truely async.
2849 //
2850
2851 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
2852
2853 CompletionRoutine = CdSingleSyncCompletionRoutine;
2854
2855 } else {
2856
2857 CompletionRoutine = CdSingleAsyncCompletionRoutine;
2858 }
2859
2860 //
2861 // Set up the completion routine address in our stack frame.
2862 //
2863
2864 IoSetCompletionRoutine( IrpContext->Irp,
2865 CompletionRoutine,
2866 IrpContext->IoContext,
2867 TRUE,
2868 TRUE,
2869 TRUE );
2870
2871 //
2872 // Setup the next IRP stack location in the associated Irp for the disk
2873 // driver beneath us.
2874 //
2875
2876 IrpSp = IoGetNextIrpStackLocation( IrpContext->Irp );
2877
2878 //
2879 // Setup the Stack location to do a read from the disk driver.
2880 //
2881
2882 IrpSp->MajorFunction = IRP_MJ_READ;
2883 IrpSp->Parameters.Read.Length = ByteCount;
2884 IrpSp->Parameters.Read.ByteOffset.QuadPart = ByteOffset;
2885
2886 //
2887 // Issue the Io request
2888 //
2889
2890 //
2891 // If IoCallDriver returns an error, it has completed the Irp
2892 // and the error will be caught by our completion routines
2893 // and dealt with as a normal IO error.
2894 //
2895
2896 (VOID)IoCallDriver( IrpContext->Vcb->TargetDeviceObject, IrpContext->Irp );
2897
2898 //
2899 // And return to our caller
2900 //
2901
2902 return;
2903 }
2904
2905 \f
2906 //
2907 // Local support routine
2908 //
2909
2910 VOID
2911 CdWaitSync (
2912 IN PIRP_CONTEXT IrpContext
2913 )
2914
2915 /*++
2916
2917 Routine Description:
2918
2919 This routine waits for one or more previously started I/O requests
2920 from the above routines, by simply waiting on the event.
2921
2922 Arguments:
2923
2924 Return Value:
2925
2926 None
2927
2928 --*/
2929
2930 {
2931 PAGED_CODE();
2932
2933 KeWaitForSingleObject( &IrpContext->IoContext->SyncEvent,
2934 Executive,
2935 KernelMode,
2936 FALSE,
2937 NULL );
2938
2939 KeClearEvent( &IrpContext->IoContext->SyncEvent );
2940
2941 return;
2942 }
2943
2944 \f
2945 //
2946 // Local support routine
2947 //
2948
2949 NTSTATUS
2950 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
2951 CdMultiSyncCompletionRoutine (
2952 IN PDEVICE_OBJECT DeviceObject,
2953 IN PIRP Irp,
2954 IN PVOID Context
2955 )
2956
2957 /*++
2958
2959 Routine Description:
2960
2961 This is the completion routine for all synchronous reads
2962 started via CdMultipleAsynch.
2963
2964 The completion routine has has the following responsibilities:
2965
2966 If the individual request was completed with an error, then
2967 this completion routine must see if this is the first error
2968 and remember the error status in the Context.
2969
2970 If the IrpCount goes to 1, then it sets the event in the Context
2971 parameter to signal the caller that all of the asynch requests
2972 are done.
2973
2974 Arguments:
2975
2976 DeviceObject - Pointer to the file system device object.
2977
2978 Irp - Pointer to the associated Irp which is being completed. (This
2979 Irp will no longer be accessible after this routine returns.)
2980
2981 Context - The context parameter which was specified for all of
2982 the multiple asynch I/O requests for this MasterIrp.
2983
2984 Return Value:
2985
2986 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
2987 immediately complete the Master Irp without being in a race condition
2988 with the IoCompleteRequest thread trying to decrement the IrpCount in
2989 the Master Irp.
2990
2991 --*/
2992
2993 {
2994 PCD_IO_CONTEXT IoContext = Context;
2995
2996 AssertVerifyDeviceIrp( Irp );
2997
2998 //
2999 // If we got an error (or verify required), remember it in the Irp
3000 //
3001
3002 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3003
3004 InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
3005 IoContext->MasterIrp->IoStatus.Information = 0;
3006 }
3007
3008 //
3009 // We must do this here since IoCompleteRequest won't get a chance
3010 // on this associated Irp.
3011 //
3012
3013 IoFreeMdl( Irp->MdlAddress );
3014 IoFreeIrp( Irp );
3015
3016 if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
3017
3018 //
3019 // Update the Master Irp with any error status from the associated Irps.
3020 //
3021
3022 IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
3023 KeSetEvent( &IoContext->SyncEvent, 0, FALSE );
3024 }
3025
3026 UNREFERENCED_PARAMETER( DeviceObject );
3027
3028 return STATUS_MORE_PROCESSING_REQUIRED;
3029 }
3030
3031 \f
3032 //
3033 // Local support routine
3034 //
3035
3036 NTSTATUS
3037 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3038 CdMultiAsyncCompletionRoutine (
3039 IN PDEVICE_OBJECT DeviceObject,
3040 IN PIRP Irp,
3041 IN PVOID Context
3042 )
3043
3044 /*++
3045
3046 Routine Description:
3047
3048 This is the completion routine for all asynchronous reads
3049 started via CdMultipleAsynch.
3050
3051 The completion routine has has the following responsibilities:
3052
3053 If the individual request was completed with an error, then
3054 this completion routine must see if this is the first error
3055 and remember the error status in the Context.
3056
3057 Arguments:
3058
3059 DeviceObject - Pointer to the file system device object.
3060
3061 Irp - Pointer to the associated Irp which is being completed. (This
3062 Irp will no longer be accessible after this routine returns.)
3063
3064 Context - The context parameter which was specified for all of
3065 the multiple asynch I/O requests for this MasterIrp.
3066
3067 Return Value:
3068
3069 Currently always returns STATUS_SUCCESS.
3070
3071 --*/
3072
3073 {
3074 PCD_IO_CONTEXT IoContext = Context;
3075 /* ReactOS Change: GCC Unused Variable */
3076 //PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
3077
3078 AssertVerifyDeviceIrp( Irp );
3079
3080 //
3081 // If we got an error (or verify required), remember it in the Irp
3082 //
3083
3084 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3085
3086 InterlockedExchange( &IoContext->Status, Irp->IoStatus.Status );
3087 }
3088
3089 //
3090 // Decrement IrpCount and see if it goes to zero.
3091 //
3092
3093 if (InterlockedDecrement( &IoContext->IrpCount ) == 0) {
3094
3095 //
3096 // Mark the master Irp pending
3097 //
3098
3099 IoMarkIrpPending( IoContext->MasterIrp );
3100
3101 //
3102 // Update the Master Irp with any error status from the associated Irps.
3103 //
3104
3105 IoContext->MasterIrp->IoStatus.Status = IoContext->Status;
3106
3107 //
3108 // Update the information field with the correct value.
3109 //
3110
3111 IoContext->MasterIrp->IoStatus.Information = 0;
3112
3113 if (NT_SUCCESS( IoContext->MasterIrp->IoStatus.Status )) {
3114
3115 IoContext->MasterIrp->IoStatus.Information = IoContext->RequestedByteCount;
3116 }
3117
3118 //
3119 // Now release the resource
3120 //
3121
3122 ExReleaseResourceForThreadLite( IoContext->Resource,
3123 IoContext->ResourceThreadId );
3124
3125 //
3126 // and finally, free the context record.
3127 //
3128
3129 CdFreeIoContext( IoContext );
3130
3131 //
3132 // Return success in this case.
3133 //
3134
3135 return STATUS_SUCCESS;
3136
3137 } else {
3138
3139 //
3140 // We need to cleanup the associated Irp and its Mdl.
3141 //
3142
3143 IoFreeMdl( Irp->MdlAddress );
3144 IoFreeIrp( Irp );
3145
3146 return STATUS_MORE_PROCESSING_REQUIRED;
3147 }
3148
3149 UNREFERENCED_PARAMETER( DeviceObject );
3150 }
3151
3152 \f
3153 //
3154 // Local support routine
3155 //
3156
3157 NTSTATUS
3158 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3159 CdSingleSyncCompletionRoutine (
3160 IN PDEVICE_OBJECT DeviceObject,
3161 IN PIRP Irp,
3162 IN PVOID Context
3163 )
3164
3165 /*++
3166
3167 Routine Description:
3168
3169 This is the completion routine for all reads started via CdSingleAsynch.
3170
3171 The completion routine has has the following responsibilities:
3172
3173 It sets the event in the Context parameter to signal the caller
3174 that all of the asynch requests are done.
3175
3176 Arguments:
3177
3178 DeviceObject - Pointer to the file system device object.
3179
3180 Irp - Pointer to the Irp for this request. (This Irp will no longer
3181 be accessible after this routine returns.)
3182
3183 Context - The context parameter which was specified in the call to
3184 CdSingleAsynch.
3185
3186 Return Value:
3187
3188 The routine returns STATUS_MORE_PROCESSING_REQUIRED so that we can
3189 immediately complete the Master Irp without being in a race condition
3190 with the IoCompleteRequest thread trying to decrement the IrpCount in
3191 the Master Irp.
3192
3193 --*/
3194
3195 {
3196 AssertVerifyDeviceIrp( Irp );
3197
3198 //
3199 // Store the correct information field into the Irp.
3200 //
3201
3202 if (!NT_SUCCESS( Irp->IoStatus.Status )) {
3203
3204 Irp->IoStatus.Information = 0;
3205 }
3206
3207 KeSetEvent( &((PCD_IO_CONTEXT)Context)->SyncEvent, 0, FALSE );
3208
3209 return STATUS_MORE_PROCESSING_REQUIRED;
3210 }
3211
3212 \f
3213 //
3214 // Local support routine
3215 //
3216
3217 NTSTATUS
3218 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
3219 CdSingleAsyncCompletionRoutine (
3220 IN PDEVICE_OBJECT DeviceObject,
3221 IN PIRP Irp,
3222 IN PVOID Context
3223 )
3224
3225 /*++
3226
3227 Routine Description:
3228
3229 This is the completion routine for all asynchronous reads
3230 started via CdSingleAsynch.
3231
3232 Arguments:
3233
3234 DeviceObject - Pointer to the file system device object.
3235
3236 Irp - Pointer to the Irp for this request. (This Irp will no longer
3237 be accessible after this routine returns.)
3238
3239 Context - The context parameter which was specified in the call to
3240 CdSingleAsynch.
3241
3242 Return Value:
3243
3244 Currently always returns STATUS_SUCCESS.
3245
3246 --*/
3247
3248 {
3249 AssertVerifyDeviceIrp( Irp );
3250
3251 //
3252 // Update the information field with the correct value for bytes read.
3253 //
3254
3255 Irp->IoStatus.Information = 0;
3256
3257 if (NT_SUCCESS( Irp->IoStatus.Status )) {
3258
3259 Irp->IoStatus.Information = ((PCD_IO_CONTEXT) Context)->RequestedByteCount;
3260 }
3261
3262 //
3263 // Mark the Irp pending
3264 //
3265
3266 IoMarkIrpPending( Irp );
3267
3268 //
3269 // Now release the resource
3270 //
3271
3272 ExReleaseResourceForThreadLite( ((PCD_IO_CONTEXT) Context)->Resource,
3273 ((PCD_IO_CONTEXT) Context)->ResourceThreadId );
3274
3275 //
3276 // and finally, free the context record.
3277 //
3278
3279 CdFreeIoContext( Context ); /* ReactOS Change: GCC "error: invalid lvalue in unary '&'" */
3280 return STATUS_SUCCESS;
3281
3282 UNREFERENCED_PARAMETER( DeviceObject );
3283 }
3284
3285 \f
3286 //
3287 // Local support routine
3288 //
3289
3290 VOID
3291 CdReadAudioSystemFile (
3292 IN PIRP_CONTEXT IrpContext,
3293 IN PFCB Fcb,
3294 IN LONGLONG StartingOffset,
3295 IN ULONG ByteCount,
3296 IN PVOID SystemBuffer
3297 )
3298
3299 /*++
3300
3301 Routine Description:
3302
3303 This routine is called to read the pseudo root directory and path
3304 table for a music disk. We build the individual elements on the
3305 stack and copy into the cache buffer.
3306
3307 Arguments:
3308
3309 Fcb - Fcb representing the file to read.
3310
3311 StartingOffset - Logical offset in the file to read from.
3312
3313 ByteCount - Number of bytes to read.
3314
3315 SystemBuffer - Pointer to buffer to fill in. This will always be page
3316 aligned.
3317
3318 Return Value:
3319
3320 None.
3321
3322 --*/
3323
3324 {
3325 PRAW_PATH_ISO RawPath;
3326 PRAW_DIRENT RawDirent;
3327
3328 ULONG CurrentTrack;
3329 ULONG SectorOffset;
3330 ULONG EntryCount;
3331 UCHAR TrackOnes;
3332 UCHAR TrackTens;
3333 PTRACK_DATA ThisTrack;
3334
3335 LONGLONG CurrentOffset;
3336
3337 PVOID CurrentSector;
3338
3339 PSYSTEM_USE_XA SystemUse;
3340
3341 ULONG BytesToCopy;
3342
3343 UCHAR LocalBuffer[FIELD_OFFSET( RAW_DIRENT, FileId ) + 12];
3344
3345 PAGED_CODE();
3346
3347 //
3348 // If this is the path table then we just need a single entry.
3349 //
3350
3351 if (SafeNodeType( Fcb ) == CDFS_NTC_FCB_PATH_TABLE) {
3352
3353 //
3354 // Sanity check that the offset is zero.
3355 //
3356
3357 ASSERT( StartingOffset == 0 );
3358
3359 //
3360 // Store a pseudo path entry in our local buffer.
3361 //
3362
3363 RawPath = (PRAW_PATH_ISO) LocalBuffer;
3364
3365 RtlZeroMemory( RawPath, sizeof( LocalBuffer ));
3366
3367 RawPath->DirIdLen = 1;
3368 RawPath->ParentNum = 1;
3369 RawPath->DirId[0] = '\0';
3370
3371 //
3372 // Now copy to the user's buffer.
3373 //
3374
3375 BytesToCopy = FIELD_OFFSET( RAW_PATH_ISO, DirId ) + 2;
3376
3377 if (BytesToCopy > ByteCount) {
3378
3379 BytesToCopy = ByteCount;
3380 }
3381
3382 RtlCopyMemory( SystemBuffer,
3383 RawPath,
3384 BytesToCopy );
3385
3386 //
3387 // We need to deal with the multiple sector case for the root directory.
3388 //
3389
3390 } else {
3391
3392 //
3393 // Initialize the first track to return to our caller.
3394 //
3395
3396 CurrentTrack = 0;
3397
3398 //
3399 // If the offset is zero then store the entries for the self and parent
3400 // entries.
3401 //
3402
3403 if (StartingOffset == 0) {
3404
3405 RawDirent = SystemBuffer;
3406
3407 //
3408 // Clear all of the fields initially.
3409 //
3410
3411 RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
3412
3413 //
3414 // Now fill in the interesting fields.
3415 //
3416
3417 RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
3418 RawDirent->FileIdLen = 1;
3419 RawDirent->FileId[0] = '\0';
3420 SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
3421
3422 //
3423 // Set the time stamp to be Jan 1, 1995
3424 //
3425
3426 RawDirent->RecordTime[0] = 95;
3427 RawDirent->RecordTime[1] = 1;
3428 RawDirent->RecordTime[2] = 1;
3429
3430 SectorOffset = RawDirent->DirLen;
3431
3432 RawDirent = Add2Ptr( RawDirent, SectorOffset, PRAW_DIRENT );
3433
3434 //
3435 // Clear all of the fields initially.
3436 //
3437
3438 RtlZeroMemory( RawDirent, FIELD_OFFSET( RAW_DIRENT, FileId ));
3439
3440 //
3441 // Now fill in the interesting fields.
3442 //
3443
3444 RawDirent->DirLen = FIELD_OFFSET( RAW_DIRENT, FileId ) + 1;
3445 RawDirent->FileIdLen = 1;
3446 RawDirent->FileId[0] = '\1';
3447 SetFlag( RawDirent->FlagsISO, CD_ATTRIBUTE_DIRECTORY );
3448
3449 //
3450 // Set the time stamp to be Jan 1, 1995
3451 //
3452
3453 RawDirent->RecordTime[0] = 95;
3454 RawDirent->RecordTime[1] = 1;
3455 RawDirent->RecordTime[2] = 1;
3456
3457 SectorOffset += RawDirent->DirLen;
3458 EntryCount = 2;
3459
3460 //
3461 // Otherwise compute the starting track to write to the buffer.
3462 //
3463
3464 } else {
3465
3466 //
3467 // Count the tracks in each preceding sector.
3468 //
3469
3470 CurrentOffset = 0;
3471
3472 do {
3473
3474 CurrentTrack += CdAudioDirentsPerSector;
3475 CurrentOffset += SECTOR_SIZE;
3476
3477 } while (CurrentOffset < StartingOffset);
3478
3479 //
3480 // Bias the track count to reflect the two default entries.
3481 //
3482
3483 CurrentTrack -= 2;
3484
3485 SectorOffset = 0;
3486 EntryCount = 0;
3487 }
3488
3489 //
3490 // We now know the first track to return as well as where we are in
3491 // the current sector. We will walk through sector by sector adding
3492 // the entries for the separate tracks in the TOC. We will zero
3493 // any sectors or partial sectors without data.
3494 //
3495
3496 CurrentSector = SystemBuffer;
3497 BytesToCopy = SECTOR_SIZE;
3498
3499 //
3500 // Loop for each sector.
3501 //
3502
3503 do {
3504
3505 //
3506 // Add entries until we reach our threshold for each sector.
3507 //
3508
3509 do {
3510
3511 //
3512 // If we are beyond the entries in the TOC then exit.
3513 //
3514
3515 if (CurrentTrack >= IrpContext->Vcb->TrackCount) {
3516
3517 break;
3518 }
3519
3520 ThisTrack = &IrpContext->Vcb->CdromToc->TrackData[CurrentTrack];
3521
3522 //
3523 // Point to the current position in the buffer.
3524 //
3525
3526 RawDirent = Add2Ptr( CurrentSector, SectorOffset, PRAW_DIRENT );
3527
3528 //
3529 // Clear all of the fields initially.
3530 //
3531
3532 RtlZeroMemory( RawDirent, CdAudioDirentSize );
3533
3534 //
3535 // Now fill in the interesting fields.
3536 //
3537
3538 RawDirent->DirLen = (UCHAR) CdAudioDirentSize;
3539 RawDirent->FileIdLen = CdAudioFileNameLength;
3540
3541 RtlCopyMemory( RawDirent->FileId,
3542 CdAudioFileName,
3543 CdAudioFileNameLength );
3544
3545 //
3546 // Set the time stamp to be Jan 1, 1995
3547 //
3548
3549 RawDirent->RecordTime[0] = 95;
3550 RawDirent->RecordTime[1] = 1;
3551 RawDirent->RecordTime[2] = 1;
3552
3553 //
3554 // Now bias by the values in the TOC.
3555 //
3556
3557 RawDirent->RecordTime[4] = ThisTrack->Address[1] % 60;
3558 RawDirent->RecordTime[5] = ThisTrack->Address[2] % 60;
3559
3560 //
3561 // Put the track number into the file name.
3562 //
3563
3564 TrackTens = TrackOnes = ThisTrack->TrackNumber;
3565
3566 TrackOnes = (TrackOnes % 10) + '0';
3567
3568 TrackTens /= 10;
3569 TrackTens = (TrackTens % 10) + '0';
3570
3571 RawDirent->FileId[AUDIO_NAME_TENS_OFFSET] = TrackTens;
3572 RawDirent->FileId[AUDIO_NAME_ONES_OFFSET] = TrackOnes;
3573
3574 SystemUse = Add2Ptr( RawDirent, CdAudioSystemUseOffset, PSYSTEM_USE_XA );
3575
3576 SystemUse->Attributes = SYSTEM_USE_XA_DA;
3577 SystemUse->Signature = SYSTEM_XA_SIGNATURE;
3578
3579 //
3580 // Store the track number as the file number.
3581 //
3582
3583 SystemUse->FileNumber = (UCHAR) CurrentTrack;
3584
3585 EntryCount += 1;
3586 SectorOffset += CdAudioDirentSize;
3587 CurrentTrack += 1;
3588
3589 } while (EntryCount < CdAudioDirentsPerSector);
3590
3591 //
3592 // Zero the remaining portion of this buffer.
3593 //
3594
3595 RtlZeroMemory( Add2Ptr( CurrentSector, SectorOffset, PVOID ),
3596 SECTOR_SIZE - SectorOffset );
3597
3598 //
3599 // Prepare for the next sector.
3600 //
3601
3602 EntryCount = 0;
3603 BytesToCopy += SECTOR_SIZE;
3604 SectorOffset = 0;
3605 CurrentSector = Add2Ptr( CurrentSector, SECTOR_SIZE, PVOID );
3606
3607 } while (BytesToCopy <= ByteCount);
3608 }
3609
3610 return;
3611 }
3612