3 Copyright (C) Microsoft Corporation, 1999 - 1999
11 The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
12 and sends them to its devices through the port driver.
20 SCSI Tape, CDRom and Disk class drivers share common routines
21 that can be found in the CLASS directory (..\ntos\dd\class).
41 PUCHAR READ_DVD_STRUCTURE_FORMAT_STRINGS
[DvdMaxDescriptor
+1] = {
51 #define DEFAULT_CDROM_SECTORS_PER_TRACK 32
52 #define DEFAULT_TRACKS_PER_CYLINDER 64
57 CdRomDeviceControlDispatch(
58 IN PDEVICE_OBJECT DeviceObject
,
65 This is the NT device control handler for CDROMs.
69 DeviceObject - for this CDROM
71 Irp - IO Request packet
79 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
80 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
82 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
83 PIO_STACK_LOCATION nextStack
;
84 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
86 BOOLEAN use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
87 SCSI_REQUEST_BLOCK srb
;
88 PCDB cdb
= (PCDB
)srb
.Cdb
;
90 ULONG bytesTransferred
= 0;
102 // Zero the SRB on stack.
105 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
107 Irp
->IoStatus
.Information
= 0;
110 // if this is a class driver ioctl then we need to change the base code
111 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
113 // WARNING - currently the scsi class ioctl function codes are between
114 // 0x200 & 0x300. this routine depends on that fact
117 ioctlCode
= irpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
118 baseCode
= ioctlCode
>> 16;
119 functionCode
= (ioctlCode
& (~0xffffc003)) >> 2;
121 TraceLog((CdromDebugTrace
,
122 "CdRomDeviceControl: Ioctl Code = %lx, Base Code = %lx,"
123 " Function Code = %lx\n",
129 if((functionCode
>= 0x200) && (functionCode
<= 0x300)) {
131 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE
, 0, 0, 0);
133 TraceLog((CdromDebugTrace
,
134 "CdRomDeviceControl: Class Code - new ioctl code is %lx\n",
137 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
143 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX
: {
145 PGET_MEDIA_TYPES mediaTypes
= Irp
->AssociatedIrp
.SystemBuffer
;
146 PDEVICE_MEDIA_INFO mediaInfo
= &mediaTypes
->MediaInfo
[0];
149 sizeNeeded
= sizeof(GET_MEDIA_TYPES
);
152 // IsMmc is static...
155 if (cdData
->Mmc
.IsMmc
) {
156 sizeNeeded
+= sizeof(DEVICE_MEDIA_INFO
) * 1; // return two media types
160 // Ensure that buffer is large enough.
163 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
170 Irp
->IoStatus
.Information
= sizeNeeded
;
171 status
= STATUS_BUFFER_TOO_SMALL
;
175 RtlZeroMemory(Irp
->AssociatedIrp
.SystemBuffer
, sizeNeeded
);
178 // ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX
181 mediaTypes
->DeviceType
= CdRomGetDeviceType(DeviceObject
);
183 mediaTypes
->MediaInfoCount
= 1;
184 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaType
= CD_ROM
;
185 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.NumberMediaSides
= 1;
186 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
= MEDIA_READ_ONLY
;
187 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.Cylinders
.QuadPart
= fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
;
188 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.TracksPerCylinder
= fdoExtension
->DiskGeometry
.TracksPerCylinder
;
189 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.SectorsPerTrack
= fdoExtension
->DiskGeometry
.SectorsPerTrack
;
190 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.BytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
192 if (cdData
->Mmc
.IsMmc
) {
195 // also report a removable disk
197 mediaTypes
->MediaInfoCount
+= 1;
200 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaType
= RemovableMedia
;
201 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.NumberMediaSides
= 1;
202 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
= MEDIA_READ_WRITE
;
203 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.Cylinders
.QuadPart
= fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
;
204 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.TracksPerCylinder
= fdoExtension
->DiskGeometry
.TracksPerCylinder
;
205 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.SectorsPerTrack
= fdoExtension
->DiskGeometry
.SectorsPerTrack
;
206 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.BytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
212 // Status will either be success, if media is present, or no media.
213 // It would be optimal to base from density code and medium type, but not all devices
214 // have values for these fields.
218 // Send a TUR to determine if media is present.
223 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
226 // Set timeout value.
229 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
231 status
= ClassSendSrbSynchronous(DeviceObject
,
238 TraceLog((CdromDebugWarning
,
239 "CdRomDeviceControl: GET_MEDIA_TYPES status of TUR - %lx\n",
242 if (NT_SUCCESS(status
)) {
245 // set the disk's media as current if we can write to it.
248 if (cdData
->Mmc
.IsMmc
&& cdData
->Mmc
.WriteAllowed
) {
251 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
,
252 MEDIA_CURRENTLY_MOUNTED
);
258 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
,
259 MEDIA_CURRENTLY_MOUNTED
);
265 Irp
->IoStatus
.Information
= sizeNeeded
;
266 status
= STATUS_SUCCESS
;
271 case IOCTL_CDROM_RAW_READ
: {
273 LARGE_INTEGER startingOffset
;
274 ULONGLONG transferBytes
;
277 ULONG startingSector
;
278 PRAW_READ_INFO rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
281 // Ensure that XA reads are supported.
284 if (TEST_FLAG(cdData
->XAFlags
, XA_NOT_SUPPORTED
)) {
285 TraceLog((CdromDebugWarning
,
286 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
288 status
= STATUS_INVALID_DEVICE_REQUEST
;
293 // Check that ending sector is on disc and buffers are there and of
297 if (rawReadInfo
== NULL
) {
300 // Called from user space. Save the userbuffer in the
301 // Type3InputBuffer so we can reduce the number of code paths.
304 irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
=
305 Irp
->AssociatedIrp
.SystemBuffer
;
308 // Called from user space. Validate the buffers.
311 rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
313 if (rawReadInfo
== NULL
) {
315 TraceLog((CdromDebugWarning
,
316 "CdRomDeviceControl: Invalid I/O parameters for "
317 "XA Read (No extent info\n"));
318 status
= STATUS_INVALID_PARAMETER
;
323 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!=
324 sizeof(RAW_READ_INFO
)) {
326 TraceLog((CdromDebugWarning
,
327 "CdRomDeviceControl: Invalid I/O parameters for "
328 "XA Read (Invalid info buffer\n"));
329 status
= STATUS_INVALID_PARAMETER
;
336 // if they don't request any data, just fail the request
339 if (rawReadInfo
->SectorCount
== 0) {
341 status
= STATUS_INVALID_PARAMETER
;
346 startingOffset
.QuadPart
= rawReadInfo
->DiskOffset
.QuadPart
;
347 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>>
348 fdoExtension
->SectorShift
);
349 transferBytes
= (ULONGLONG
)rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
351 endOffset
= (ULONGLONG
)rawReadInfo
->SectorCount
* COOKED_SECTOR_SIZE
;
352 endOffset
+= startingOffset
.QuadPart
;
355 // check for overflows....
358 if (transferBytes
< (ULONGLONG
)(rawReadInfo
->SectorCount
)) {
359 TraceLog((CdromDebugWarning
,
360 "CdRomDeviceControl: Invalid I/O parameters for XA "
361 "Read (TransferBytes Overflow)\n"));
362 status
= STATUS_INVALID_PARAMETER
;
365 if (endOffset
< (ULONGLONG
)startingOffset
.QuadPart
) {
366 TraceLog((CdromDebugWarning
,
367 "CdRomDeviceControl: Invalid I/O parameters for XA "
368 "Read (EndingOffset Overflow)\n"));
369 status
= STATUS_INVALID_PARAMETER
;
372 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
374 TraceLog((CdromDebugWarning
,
375 "CdRomDeviceControl: Invalid I/O parameters for XA "
376 "Read (Bad buffer size)\n"));
377 status
= STATUS_INVALID_PARAMETER
;
380 if (endOffset
> (ULONGLONG
)commonExtension
->PartitionLength
.QuadPart
) {
381 TraceLog((CdromDebugWarning
,
382 "CdRomDeviceControl: Invalid I/O parameters for XA "
383 "Read (Request Out of Bounds)\n"));
384 status
= STATUS_INVALID_PARAMETER
;
389 // cannot validate the MdlAddress, since it is not included in any
390 // other location per the DDK and file system calls.
394 // validate the mdl describes at least the number of bytes
395 // requested from us.
398 mdlBytes
= (ULONGLONG
)MmGetMdlByteCount(Irp
->MdlAddress
);
399 if (mdlBytes
< transferBytes
) {
400 TraceLog((CdromDebugWarning
,
401 "CdRomDeviceControl: Invalid MDL %s, Irp %p\n",
403 status
= STATUS_INVALID_PARAMETER
;
408 // HACKHACK - REF #0001
409 // The retry count will be in this irp's IRP_MN function,
410 // as the new irp was freed, and we therefore cannot use
411 // this irp's next stack location for this function.
412 // This may be a good location to store this info for
413 // when we remove RAW_READ (mode switching), as we will
414 // no longer have the nextIrpStackLocation to play with
417 // once XA_READ is removed, then this hack can also be
420 irpStack
->MinorFunction
= MAXIMUM_RETRIES
; // HACKHACK - REF #0001
422 IoMarkIrpPending(Irp
);
423 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
425 return STATUS_PENDING
;
428 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
429 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
: {
430 TraceLog((CdromDebugTrace
,
431 "CdRomDeviceControl: Get drive geometryEx\n"));
432 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
433 FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
)) {
434 status
= STATUS_BUFFER_TOO_SMALL
;
435 Irp
->IoStatus
.Information
= FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
);
438 IoMarkIrpPending(Irp
);
439 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
440 return STATUS_PENDING
;
443 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
444 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
446 TraceLog((CdromDebugTrace
,
447 "CdRomDeviceControl: Get drive geometry\n"));
449 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
450 sizeof( DISK_GEOMETRY
) ) {
452 status
= STATUS_BUFFER_TOO_SMALL
;
453 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
457 IoMarkIrpPending(Irp
);
458 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
460 return STATUS_PENDING
;
463 case IOCTL_CDROM_READ_TOC_EX
: {
465 PCDROM_READ_TOC_EX inputBuffer
;
467 if (CdRomIsPlayActive(DeviceObject
)) {
468 status
= STATUS_DEVICE_BUSY
;
472 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
473 sizeof(CDROM_READ_TOC_EX
)) {
474 status
= STATUS_INFO_LENGTH_MISMATCH
;
478 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
479 MINIMUM_CDROM_READ_TOC_EX_SIZE
) {
480 status
= STATUS_BUFFER_TOO_SMALL
;
481 Irp
->IoStatus
.Information
= MINIMUM_CDROM_READ_TOC_EX_SIZE
;
485 if (irpStack
->Parameters
.Read
.Length
> ((USHORT
)-1)) {
486 status
= STATUS_INVALID_PARAMETER
;
490 inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
492 if ((inputBuffer
->Reserved1
!= 0) ||
493 (inputBuffer
->Reserved2
!= 0) ||
494 (inputBuffer
->Reserved3
!= 0)) {
495 status
= STATUS_INVALID_PARAMETER
;
500 // NOTE: when adding new formats, ensure that first two bytes
501 // specify the amount of additional data available.
504 if ((inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_TOC
) ||
505 (inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_FULL_TOC
) ||
506 (inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_CDTEXT
)) {
508 // SessionTrack field is used
511 if ((inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_SESSION
) ||
512 (inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_PMA
) ||
513 (inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_ATIP
)) {
515 // SessionTrack field is reserved
517 if (inputBuffer
->SessionTrack
!= 0) {
518 status
= STATUS_INVALID_PARAMETER
;
523 status
= STATUS_INVALID_PARAMETER
;
527 IoMarkIrpPending(Irp
);
528 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
529 return STATUS_PENDING
;
532 case IOCTL_CDROM_GET_LAST_SESSION
: {
535 // If the cd is playing music then reject this request.
538 if (CdRomIsPlayActive(DeviceObject
)) {
539 status
= STATUS_DEVICE_BUSY
;
544 // Make sure the caller is requesting enough data to make this worth
548 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
549 sizeof(CDROM_TOC_SESSION_DATA
)) {
552 // they didn't request the entire TOC -- use _EX version
553 // for partial transfers and such.
556 status
= STATUS_BUFFER_TOO_SMALL
;
557 Irp
->IoStatus
.Information
= sizeof(CDROM_TOC_SESSION_DATA
);
561 IoMarkIrpPending(Irp
);
562 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
564 return STATUS_PENDING
;
567 case IOCTL_CDROM_READ_TOC
: {
570 // If the cd is playing music then reject this request.
573 if (CdRomIsPlayActive(DeviceObject
)) {
574 status
= STATUS_DEVICE_BUSY
;
579 // Make sure the caller is requesting enough data to make this worth
583 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
587 // they didn't request the entire TOC -- use _EX version
588 // for partial transfers and such.
591 status
= STATUS_BUFFER_TOO_SMALL
;
592 Irp
->IoStatus
.Information
= sizeof(CDROM_TOC
);
596 IoMarkIrpPending(Irp
);
597 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
599 return STATUS_PENDING
;
602 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
608 TraceLog((CdromDebugTrace
,
609 "CdRomDeviceControl: Play audio MSF\n"));
611 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
612 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
615 // Indicate unsuccessful status.
618 status
= STATUS_INFO_LENGTH_MISMATCH
;
622 IoMarkIrpPending(Irp
);
623 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
625 return STATUS_PENDING
;
628 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
635 TraceLog((CdromDebugTrace
,
636 "CdRomDeviceControl: Seek audio MSF\n"));
638 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
639 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
642 // Indicate unsuccessful status.
645 status
= STATUS_INFO_LENGTH_MISMATCH
;
649 IoMarkIrpPending(Irp
);
650 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
651 return STATUS_PENDING
;
655 case IOCTL_CDROM_PAUSE_AUDIO
: {
661 TraceLog((CdromDebugTrace
,
662 "CdRomDeviceControl: Pause audio\n"));
664 IoMarkIrpPending(Irp
);
665 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
667 return STATUS_PENDING
;
672 case IOCTL_CDROM_RESUME_AUDIO
: {
678 TraceLog((CdromDebugTrace
,
679 "CdRomDeviceControl: Resume audio\n"));
681 IoMarkIrpPending(Irp
);
682 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
684 return STATUS_PENDING
;
687 case IOCTL_CDROM_READ_Q_CHANNEL
: {
689 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
690 Irp
->AssociatedIrp
.SystemBuffer
;
692 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
693 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
695 status
= STATUS_INFO_LENGTH_MISMATCH
;
700 // check for all valid types of request
703 if (inputBuffer
->Format
!= IOCTL_CDROM_CURRENT_POSITION
&&
704 inputBuffer
->Format
!= IOCTL_CDROM_MEDIA_CATALOG
&&
705 inputBuffer
->Format
!= IOCTL_CDROM_TRACK_ISRC
) {
706 status
= STATUS_INVALID_PARAMETER
;
707 Irp
->IoStatus
.Information
= 0;
711 IoMarkIrpPending(Irp
);
712 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
714 return STATUS_PENDING
;
717 case IOCTL_CDROM_GET_CONTROL
: {
719 TraceLog((CdromDebugTrace
,
720 "CdRomDeviceControl: Get audio control\n"));
723 // Verify user buffer is large enough for the data.
726 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
727 sizeof(CDROM_AUDIO_CONTROL
)) {
730 // Indicate unsuccessful status and no data transferred.
733 status
= STATUS_BUFFER_TOO_SMALL
;
734 Irp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
739 IoMarkIrpPending(Irp
);
740 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
742 return STATUS_PENDING
;
745 case IOCTL_CDROM_GET_VOLUME
: {
747 TraceLog((CdromDebugTrace
,
748 "CdRomDeviceControl: Get volume control\n"));
751 // Verify user buffer is large enough for data.
754 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
755 sizeof(VOLUME_CONTROL
)) {
758 // Indicate unsuccessful status and no data transferred.
761 status
= STATUS_BUFFER_TOO_SMALL
;
762 Irp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
767 IoMarkIrpPending(Irp
);
768 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
770 return STATUS_PENDING
;
773 case IOCTL_CDROM_SET_VOLUME
: {
775 TraceLog((CdromDebugTrace
,
776 "CdRomDeviceControl: Set volume control\n"));
778 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
779 sizeof(VOLUME_CONTROL
)) {
782 // Indicate unsuccessful status.
785 status
= STATUS_INFO_LENGTH_MISMATCH
;
790 IoMarkIrpPending(Irp
);
791 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
793 return STATUS_PENDING
;
796 case IOCTL_CDROM_STOP_AUDIO
: {
802 TraceLog((CdromDebugTrace
,
803 "CdRomDeviceControl: Stop audio\n"));
805 IoMarkIrpPending(Irp
);
806 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
808 return STATUS_PENDING
;
811 case IOCTL_STORAGE_CHECK_VERIFY
:
812 case IOCTL_DISK_CHECK_VERIFY
:
813 case IOCTL_CDROM_CHECK_VERIFY
: {
815 TraceLog((CdromDebugTrace
,
816 "CdRomDeviceControl: [%p] Check Verify\n", Irp
));
818 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
819 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
821 TraceLog((CdromDebugWarning
,
822 "CdRomDeviceControl: Check Verify: media count "
823 "buffer too small\n"));
825 status
= STATUS_BUFFER_TOO_SMALL
;
826 Irp
->IoStatus
.Information
= sizeof(ULONG
);
830 IoMarkIrpPending(Irp
);
831 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
833 return STATUS_PENDING
;
836 case IOCTL_DVD_READ_STRUCTURE
: {
838 TraceLog((CdromDebugTrace
,
839 "DvdDeviceControl: [%p] IOCTL_DVD_READ_STRUCTURE\n", Irp
));
841 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
842 TraceLog((CdromDebugWarning
,
843 "DvdDeviceControl: License Failure\n"));
844 status
= STATUS_COPY_PROTECTION_FAILURE
;
848 if (cdData
->DvdRpc0Device
&& cdData
->Rpc0RetryRegistryCallback
) {
850 // if currently in-progress, this will just return.
851 // prevents looping by doing that interlockedExchange()
853 TraceLog((CdromDebugWarning
,
854 "DvdDeviceControl: PickRegion() from "
855 "READ_STRUCTURE\n"));
856 CdRomPickDvdRegion(DeviceObject
);
860 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
861 sizeof(DVD_READ_STRUCTURE
)) {
863 TraceLog((CdromDebugWarning
,
864 "DvdDeviceControl - READ_STRUCTURE: input buffer "
865 "length too small (was %d should be %d)\n",
866 irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
867 sizeof(DVD_READ_STRUCTURE
)));
868 status
= STATUS_INVALID_PARAMETER
;
872 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
873 sizeof(READ_DVD_STRUCTURES_HEADER
)) {
875 TraceLog((CdromDebugWarning
,
876 "DvdDeviceControl - READ_STRUCTURE: output buffer "
877 "cannot hold header information\n"));
878 status
= STATUS_BUFFER_TOO_SMALL
;
879 Irp
->IoStatus
.Information
= sizeof(READ_DVD_STRUCTURES_HEADER
);
883 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>
887 // key length must fit in two bytes
889 TraceLog((CdromDebugWarning
,
890 "DvdDeviceControl - READ_STRUCTURE: output buffer "
892 status
= STATUS_INVALID_PARAMETER
;
896 IoMarkIrpPending(Irp
);
897 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
899 return STATUS_PENDING
;
902 case IOCTL_DVD_START_SESSION
: {
904 TraceLog((CdromDebugTrace
,
905 "DvdDeviceControl: [%p] IOCTL_DVD_START_SESSION\n", Irp
));
907 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
908 TraceLog((CdromDebugWarning
,
909 "DvdDeviceControl: License Failure\n"));
910 status
= STATUS_COPY_PROTECTION_FAILURE
;
914 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
915 sizeof(DVD_SESSION_ID
)) {
917 TraceLog((CdromDebugWarning
,
918 "DvdDeviceControl: DVD_START_SESSION - output "
919 "buffer too small\n"));
920 status
= STATUS_BUFFER_TOO_SMALL
;
921 Irp
->IoStatus
.Information
= sizeof(DVD_SESSION_ID
);
925 IoMarkIrpPending(Irp
);
926 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
928 return STATUS_PENDING
;
931 case IOCTL_DVD_SEND_KEY
:
932 case IOCTL_DVD_SEND_KEY2
: {
934 PDVD_COPY_PROTECT_KEY key
= Irp
->AssociatedIrp
.SystemBuffer
;
937 TraceLog((CdromDebugTrace
,
938 "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY\n", Irp
));
940 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
941 TraceLog((CdromDebugWarning
,
942 "DvdDeviceControl: License Failure\n"));
943 status
= STATUS_COPY_PROTECTION_FAILURE
;
947 if((irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
948 sizeof(DVD_COPY_PROTECT_KEY
)) ||
949 (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!=
953 // Key is too small to have a header or the key length doesn't
954 // match the input buffer length. Key must be invalid
957 TraceLog((CdromDebugWarning
,
958 "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY - "
959 "key is too small or does not match KeyLength\n",
961 status
= STATUS_INVALID_PARAMETER
;
966 // allow only certain key type (non-destructive) to go through
967 // IOCTL_DVD_SEND_KEY (which only requires READ access to the device
969 if (ioctlCode
== IOCTL_DVD_SEND_KEY
) {
971 if ((key
->KeyType
!= DvdChallengeKey
) &&
972 (key
->KeyType
!= DvdBusKey2
) &&
973 (key
->KeyType
!= DvdInvalidateAGID
)) {
975 status
= STATUS_INVALID_PARAMETER
;
980 if (cdData
->DvdRpc0Device
) {
982 if (key
->KeyType
== DvdSetRpcKey
) {
984 PDVD_SET_RPC_KEY rpcKey
= (PDVD_SET_RPC_KEY
) key
->KeyData
;
986 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
987 DVD_SET_RPC_KEY_LENGTH
) {
989 status
= STATUS_INVALID_PARAMETER
;
994 // we have a request to set region code
995 // on a RPC0 device which doesn't support
998 // we have to fake it.
1001 KeWaitForMutexObject(
1002 &cdData
->Rpc0RegionMutex
,
1009 if (cdData
->DvdRpc0Device
&& cdData
->Rpc0RetryRegistryCallback
) {
1011 // if currently in-progress, this will just return.
1012 // prevents looping by doing that interlockedExchange()
1014 TraceLog((CdromDebugWarning
,
1015 "DvdDeviceControl: PickRegion() from "
1017 CdRomPickDvdRegion(DeviceObject
);
1020 if (cdData
->Rpc0SystemRegion
== rpcKey
->PreferredDriveRegionCode
) {
1023 // nothing to change
1025 TraceLog((CdromDebugWarning
,
1026 "DvdDeviceControl (%p) => not changing "
1027 "regions -- requesting current region\n",
1029 status
= STATUS_SUCCESS
;
1031 } else if (cdData
->Rpc0SystemRegionResetCount
== 0) {
1034 // not allowed to change it again
1037 TraceLog((CdromDebugWarning
,
1038 "DvdDeviceControl (%p) => no more region "
1039 "changes are allowed for this device\n",
1041 status
= STATUS_CSS_RESETS_EXHAUSTED
;
1048 PDVD_READ_STRUCTURE dvdReadStructure
;
1049 PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight
;
1050 IO_STATUS_BLOCK ioStatus
;
1051 UCHAR mediaRegionData
;
1053 mask
= ~rpcKey
->PreferredDriveRegionCode
;
1055 if (CountOfSetBitsUChar(mask
) != 1) {
1057 status
= STATUS_INVALID_DEVICE_REQUEST
;
1062 // this test will always be TRUE except during initial
1063 // automatic selection of the first region.
1066 if (cdData
->Rpc0SystemRegion
!= 0xff) {
1069 // make sure we have a media in the drive with the same
1070 // region code if the drive is already has a region set
1073 TraceLog((CdromDebugTrace
,
1074 "DvdDeviceControl (%p) => Checking "
1078 bufferLen
= max(sizeof(DVD_DESCRIPTOR_HEADER
) +
1079 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
1080 sizeof(DVD_READ_STRUCTURE
)
1083 dvdReadStructure
= (PDVD_READ_STRUCTURE
)
1084 ExAllocatePoolWithTag(PagedPool
,
1086 DVD_TAG_RPC2_CHECK
);
1088 if (dvdReadStructure
== NULL
) {
1089 status
= STATUS_INSUFFICIENT_RESOURCES
;
1090 KeReleaseMutex(&cdData
->Rpc0RegionMutex
,FALSE
);
1094 dvdCopyRight
= (PDVD_COPYRIGHT_DESCRIPTOR
)
1095 ((PDVD_DESCRIPTOR_HEADER
) dvdReadStructure
)->Data
;
1098 // check to see if we have a DVD device
1101 RtlZeroMemory (dvdReadStructure
, bufferLen
);
1102 dvdReadStructure
->Format
= DvdCopyrightDescriptor
;
1105 // Build a request for READ_KEY
1107 ClassSendDeviceIoControlSynchronous(
1108 IOCTL_DVD_READ_STRUCTURE
,
1111 sizeof(DVD_READ_STRUCTURE
),
1112 sizeof(DVD_DESCRIPTOR_HEADER
) +
1113 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
1118 // this is just to prevent bugs from creeping in
1119 // if status is not set later in development
1122 status
= ioStatus
.Status
;
1128 if (!NT_SUCCESS(status
)) {
1129 KeReleaseMutex(&cdData
->Rpc0RegionMutex
,FALSE
);
1130 ExFreePool(dvdReadStructure
);
1131 status
= STATUS_INVALID_DEVICE_REQUEST
;
1136 // save the mediaRegionData before freeing the
1141 dvdCopyRight
->RegionManagementInformation
;
1142 ExFreePool(dvdReadStructure
);
1144 TraceLog((CdromDebugWarning
,
1145 "DvdDeviceControl (%p) => new mask is %x"
1146 " MediaRegionData is %x\n", DeviceObject
,
1147 rpcKey
->PreferredDriveRegionCode
,
1151 // the media region must match the requested region
1152 // for RPC0 drives for initial region selection
1155 if (((UCHAR
)~(mediaRegionData
| rpcKey
->PreferredDriveRegionCode
)) == 0) {
1156 KeReleaseMutex(&cdData
->Rpc0RegionMutex
,FALSE
);
1157 status
= STATUS_CSS_REGION_MISMATCH
;
1164 // now try to set the region
1167 TraceLog((CdromDebugTrace
,
1168 "DvdDeviceControl (%p) => Soft-Setting "
1169 "region of RPC1 device to %x\n",
1171 rpcKey
->PreferredDriveRegionCode
1174 status
= CdRomSetRpc0Settings(DeviceObject
,
1175 rpcKey
->PreferredDriveRegionCode
);
1177 if (!NT_SUCCESS(status
)) {
1178 TraceLog((CdromDebugWarning
,
1179 "DvdDeviceControl (%p) => Could not "
1180 "set region code (%x)\n",
1181 DeviceObject
, status
1185 TraceLog((CdromDebugTrace
,
1186 "DvdDeviceControl (%p) => New region set "
1187 " for RPC1 drive\n", DeviceObject
));
1190 // if it worked, our extension is already updated.
1191 // release the mutex
1194 DebugPrint ((4, "DvdDeviceControl (%p) => DVD current "
1195 "region bitmap 0x%x\n", DeviceObject
,
1196 cdData
->Rpc0SystemRegion
));
1197 DebugPrint ((4, "DvdDeviceControl (%p) => DVD region "
1198 " reset Count 0x%x\n", DeviceObject
,
1199 cdData
->Rpc0SystemRegionResetCount
));
1204 KeReleaseMutex(&cdData
->Rpc0RegionMutex
,FALSE
);
1206 } // end of key->KeyType == DvdSetRpcKey
1207 } // end of Rpc0Device hacks
1209 IoMarkIrpPending(Irp
);
1210 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1211 return STATUS_PENDING
;
1215 case IOCTL_DVD_READ_KEY
: {
1217 PDVD_COPY_PROTECT_KEY keyParameters
= Irp
->AssociatedIrp
.SystemBuffer
;
1220 TraceLog((CdromDebugTrace
,
1221 "DvdDeviceControl: [%p] IOCTL_DVD_READ_KEY\n", Irp
));
1223 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
1224 TraceLog((CdromDebugWarning
,
1225 "DvdDeviceControl: License Failure\n"));
1226 status
= STATUS_COPY_PROTECTION_FAILURE
;
1230 if (cdData
->DvdRpc0Device
&& cdData
->Rpc0RetryRegistryCallback
) {
1231 TraceLog((CdromDebugWarning
,
1232 "DvdDeviceControl: PickRegion() from READ_KEY\n"));
1233 CdRomPickDvdRegion(DeviceObject
);
1237 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1238 sizeof(DVD_COPY_PROTECT_KEY
)) {
1240 TraceLog((CdromDebugWarning
,
1241 "DvdDeviceControl: EstablishDriveKey - challenge "
1242 "key buffer too small\n"));
1244 status
= STATUS_INVALID_PARAMETER
;
1250 switch(keyParameters
->KeyType
) {
1252 case DvdChallengeKey
:
1253 keyLength
= DVD_CHALLENGE_KEY_LENGTH
;
1259 keyLength
= DVD_BUS_KEY_LENGTH
;
1263 keyLength
= DVD_TITLE_KEY_LENGTH
;
1267 keyLength
= DVD_ASF_LENGTH
;
1271 keyLength
= DVD_DISK_KEY_LENGTH
;
1275 keyLength
= DVD_RPC_KEY_LENGTH
;
1279 keyLength
= sizeof(DVD_COPY_PROTECT_KEY
);
1283 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1286 TraceLog((CdromDebugWarning
,
1287 "DvdDeviceControl: EstablishDriveKey - output "
1288 "buffer too small\n"));
1289 status
= STATUS_BUFFER_TOO_SMALL
;
1290 Irp
->IoStatus
.Information
= keyLength
;
1294 if (keyParameters
->KeyType
== DvdGetRpcKey
) {
1296 CdRomPickDvdRegion(DeviceObject
);
1299 if ((keyParameters
->KeyType
== DvdGetRpcKey
) &&
1300 (cdData
->DvdRpc0Device
)) {
1302 PDVD_RPC_KEY rpcKey
;
1303 rpcKey
= (PDVD_RPC_KEY
)keyParameters
->KeyData
;
1304 RtlZeroMemory (rpcKey
, sizeof (*rpcKey
));
1306 KeWaitForMutexObject(
1307 &cdData
->Rpc0RegionMutex
,
1317 rpcKey
->UserResetsAvailable
= cdData
->Rpc0SystemRegionResetCount
;
1318 rpcKey
->ManufacturerResetsAvailable
= 0;
1319 if (cdData
->Rpc0SystemRegion
== 0xff) {
1320 rpcKey
->TypeCode
= 0;
1322 rpcKey
->TypeCode
= 1;
1324 rpcKey
->RegionMask
= (UCHAR
) cdData
->Rpc0SystemRegion
;
1325 rpcKey
->RpcScheme
= 1;
1328 &cdData
->Rpc0RegionMutex
,
1332 Irp
->IoStatus
.Information
= DVD_RPC_KEY_LENGTH
;
1333 status
= STATUS_SUCCESS
;
1336 } else if (keyParameters
->KeyType
== DvdDiskKey
) {
1338 PDVD_COPY_PROTECT_KEY keyHeader
;
1339 PDVD_READ_STRUCTURE readStructureRequest
;
1342 // Special case - build a request to get the dvd structure
1343 // so we can get the disk key.
1347 // save the key header so we can restore the interesting
1351 keyHeader
= ExAllocatePoolWithTag(NonPagedPool
,
1352 sizeof(DVD_COPY_PROTECT_KEY
),
1355 if(keyHeader
== NULL
) {
1358 // Can't save the context so return an error
1361 TraceLog((CdromDebugWarning
,
1362 "DvdDeviceControl - READ_KEY: unable to "
1363 "allocate context\n"));
1364 status
= STATUS_INSUFFICIENT_RESOURCES
;
1368 RtlCopyMemory(keyHeader
,
1369 Irp
->AssociatedIrp
.SystemBuffer
,
1370 sizeof(DVD_COPY_PROTECT_KEY
));
1372 IoCopyCurrentIrpStackLocationToNext(Irp
);
1374 nextStack
= IoGetNextIrpStackLocation(Irp
);
1376 nextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
1377 IOCTL_DVD_READ_STRUCTURE
;
1379 readStructureRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
1380 readStructureRequest
->Format
= DvdDiskKeyDescriptor
;
1381 readStructureRequest
->BlockByteOffset
.QuadPart
= 0;
1382 readStructureRequest
->LayerNumber
= 0;
1383 readStructureRequest
->SessionId
= keyHeader
->SessionId
;
1385 nextStack
->Parameters
.DeviceIoControl
.InputBufferLength
=
1386 sizeof(DVD_READ_STRUCTURE
);
1388 nextStack
->Parameters
.DeviceIoControl
.OutputBufferLength
=
1389 sizeof(READ_DVD_STRUCTURES_HEADER
) + sizeof(DVD_DISK_KEY_DESCRIPTOR
);
1391 IoSetCompletionRoutine(Irp
,
1392 CdRomDvdReadDiskKeyCompletion
,
1399 UCHAR uniqueAddress
;
1400 ClassAcquireRemoveLock(DeviceObject
, (PIRP
)&uniqueAddress
);
1401 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1403 IoMarkIrpPending(Irp
);
1404 IoCallDriver(commonExtension
->DeviceObject
, Irp
);
1405 status
= STATUS_PENDING
;
1407 ClassReleaseRemoveLock(DeviceObject
, (PIRP
)&uniqueAddress
);
1410 return STATUS_PENDING
;
1414 IoMarkIrpPending(Irp
);
1415 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1418 return STATUS_PENDING
;
1421 case IOCTL_DVD_END_SESSION
: {
1423 PDVD_SESSION_ID sessionId
= Irp
->AssociatedIrp
.SystemBuffer
;
1425 TraceLog((CdromDebugTrace
,
1426 "DvdDeviceControl: [%p] END_SESSION\n", Irp
));
1428 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
1429 TraceLog((CdromDebugWarning
,
1430 "DvdDeviceControl: License Failure\n"));
1431 status
= STATUS_COPY_PROTECTION_FAILURE
;
1435 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1436 sizeof(DVD_SESSION_ID
)) {
1438 TraceLog((CdromDebugWarning
,
1439 "DvdDeviceControl: EndSession - input buffer too "
1441 status
= STATUS_INVALID_PARAMETER
;
1445 IoMarkIrpPending(Irp
);
1447 if(*sessionId
== DVD_END_ALL_SESSIONS
) {
1449 status
= CdRomDvdEndAllSessionsCompletion(DeviceObject
, Irp
, NULL
);
1451 if(status
== STATUS_SUCCESS
) {
1454 // Just complete the request - it was never issued to the
1462 return STATUS_PENDING
;
1467 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1469 return STATUS_PENDING
;
1472 case IOCTL_DVD_GET_REGION
: {
1474 PDVD_COPY_PROTECT_KEY copyProtectKey
;
1476 IO_STATUS_BLOCK ioStatus
;
1477 PDVD_DESCRIPTOR_HEADER dvdHeader
;
1478 PDVD_COPYRIGHT_DESCRIPTOR copyRightDescriptor
;
1479 PDVD_REGION dvdRegion
;
1480 PDVD_READ_STRUCTURE readStructure
;
1481 PDVD_RPC_KEY rpcKey
;
1483 TraceLog((CdromDebugTrace
,
1484 "DvdDeviceControl: [%p] IOCTL_DVD_GET_REGION\n", Irp
));
1486 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
1487 TraceLog((CdromDebugWarning
,
1488 "DvdDeviceControl: License Failure\n"));
1489 status
= STATUS_COPY_PROTECTION_FAILURE
;
1493 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1494 sizeof(DVD_REGION
)) {
1496 TraceLog((CdromDebugWarning
,
1497 "DvdDeviceControl: output buffer DVD_REGION too small\n"));
1498 status
= STATUS_INVALID_PARAMETER
;
1503 // figure out how much data buffer we need
1506 keyLength
= max(sizeof(DVD_DESCRIPTOR_HEADER
) +
1507 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
1508 sizeof(DVD_READ_STRUCTURE
)
1510 keyLength
= max(keyLength
,
1515 // round the size to nearest ULONGLONG -- why?
1518 keyLength
+= sizeof(ULONGLONG
) - (keyLength
& (sizeof(ULONGLONG
) - 1));
1520 readStructure
= ExAllocatePoolWithTag(NonPagedPool
,
1523 if (readStructure
== NULL
) {
1524 status
= STATUS_INSUFFICIENT_RESOURCES
;
1528 RtlZeroMemory (readStructure
, keyLength
);
1529 readStructure
->Format
= DvdCopyrightDescriptor
;
1532 // Build a request for READ_STRUCTURE
1535 ClassSendDeviceIoControlSynchronous(
1536 IOCTL_DVD_READ_STRUCTURE
,
1540 sizeof(DVD_DESCRIPTOR_HEADER
) +
1541 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
1545 status
= ioStatus
.Status
;
1547 if (!NT_SUCCESS(status
)) {
1548 TraceLog((CdromDebugWarning
,
1549 "CdRomDvdGetRegion => read structure failed %x\n",
1551 ExFreePool(readStructure
);
1556 // we got the copyright descriptor, so now get the region if possible
1559 dvdHeader
= (PDVD_DESCRIPTOR_HEADER
) readStructure
;
1560 copyRightDescriptor
= (PDVD_COPYRIGHT_DESCRIPTOR
) dvdHeader
->Data
;
1563 // the original irp's systembuffer has a copy of the info that
1564 // should be passed down in the request
1567 dvdRegion
= Irp
->AssociatedIrp
.SystemBuffer
;
1569 dvdRegion
->CopySystem
= copyRightDescriptor
->CopyrightProtectionType
;
1570 dvdRegion
->RegionData
= copyRightDescriptor
->RegionManagementInformation
;
1573 // now reuse the buffer to request the copy protection info
1576 copyProtectKey
= (PDVD_COPY_PROTECT_KEY
) readStructure
;
1577 RtlZeroMemory (copyProtectKey
, DVD_RPC_KEY_LENGTH
);
1578 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
1579 copyProtectKey
->KeyType
= DvdGetRpcKey
;
1582 // send a request for READ_KEY
1585 ClassSendDeviceIoControlSynchronous(
1593 status
= ioStatus
.Status
;
1595 if (!NT_SUCCESS(status
)) {
1596 TraceLog((CdromDebugWarning
,
1597 "CdRomDvdGetRegion => read key failed %x\n",
1599 ExFreePool(readStructure
);
1604 // the request succeeded. if a supported scheme is returned,
1605 // then return the information to the caller
1608 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
1610 if (rpcKey
->RpcScheme
== 1) {
1612 if (rpcKey
->TypeCode
) {
1614 dvdRegion
->SystemRegion
= ~rpcKey
->RegionMask
;
1615 dvdRegion
->ResetCount
= rpcKey
->UserResetsAvailable
;
1620 // the drive has not been set for any region
1623 dvdRegion
->SystemRegion
= 0;
1624 dvdRegion
->ResetCount
= rpcKey
->UserResetsAvailable
;
1626 Irp
->IoStatus
.Information
= sizeof(DVD_REGION
);
1630 TraceLog((CdromDebugWarning
,
1631 "CdRomDvdGetRegion => rpcKey->RpcScheme != 1\n"));
1632 status
= STATUS_INVALID_DEVICE_REQUEST
;
1635 ExFreePool(readStructure
);
1640 case IOCTL_STORAGE_SET_READ_AHEAD
: {
1642 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1643 sizeof(STORAGE_SET_READ_AHEAD
)) {
1645 TraceLog((CdromDebugWarning
,
1646 "DvdDeviceControl: SetReadAhead buffer too small\n"));
1647 status
= STATUS_INVALID_PARAMETER
;
1651 IoMarkIrpPending(Irp
);
1652 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1654 return STATUS_PENDING
;
1657 case IOCTL_DISK_IS_WRITABLE
: {
1659 IoMarkIrpPending(Irp
);
1660 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1662 return STATUS_PENDING
;
1666 case IOCTL_DISK_GET_DRIVE_LAYOUT
: {
1671 // we always fake zero or one partitions, and one partition
1672 // structure is included in DRIVE_LAYOUT_INFORMATION
1675 size
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
, PartitionEntry
[1]);
1678 TraceLog((CdromDebugTrace
,
1679 "CdRomDeviceControl: Get drive layout\n"));
1680 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< size
) {
1681 status
= STATUS_BUFFER_TOO_SMALL
;
1682 Irp
->IoStatus
.Information
= size
;
1686 IoMarkIrpPending(Irp
);
1687 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1688 return STATUS_PENDING
;
1692 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
: {
1697 // we always fake zero or one partitions, and one partition
1698 // structure is included in DRIVE_LAYOUT_INFORMATION_EX
1701 size
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
, PartitionEntry
[1]);
1703 TraceLog((CdromDebugTrace
,
1704 "CdRomDeviceControl: Get drive layout ex\n"));
1705 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< size
) {
1706 status
= STATUS_BUFFER_TOO_SMALL
;
1707 Irp
->IoStatus
.Information
= size
;
1711 IoMarkIrpPending(Irp
);
1712 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1713 return STATUS_PENDING
;
1718 case IOCTL_DISK_GET_PARTITION_INFO
: {
1721 // Check that the buffer is large enough.
1724 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1725 sizeof(PARTITION_INFORMATION
)) {
1727 status
= STATUS_BUFFER_TOO_SMALL
;
1728 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
1732 IoMarkIrpPending(Irp
);
1733 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1734 return STATUS_PENDING
;
1737 case IOCTL_DISK_GET_PARTITION_INFO_EX
: {
1739 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1740 sizeof(PARTITION_INFORMATION_EX
)) {
1742 status
= STATUS_BUFFER_TOO_SMALL
;
1743 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
1747 IoMarkIrpPending(Irp
);
1748 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1749 return STATUS_PENDING
;
1752 case IOCTL_DISK_VERIFY
: {
1754 TraceLog((CdromDebugTrace
,
1755 "IOCTL_DISK_VERIFY to device %p through irp %p\n",
1756 DeviceObject
, Irp
));
1759 // Validate buffer length.
1762 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1763 sizeof(VERIFY_INFORMATION
)) {
1765 status
= STATUS_INFO_LENGTH_MISMATCH
;
1768 IoMarkIrpPending(Irp
);
1769 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1770 return STATUS_PENDING
;
1773 case IOCTL_DISK_GET_LENGTH_INFO
: {
1775 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1776 sizeof(GET_LENGTH_INFORMATION
)) {
1777 status
= STATUS_BUFFER_TOO_SMALL
;
1778 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
1781 IoMarkIrpPending(Irp
);
1782 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1783 return STATUS_PENDING
;
1786 case IOCTL_CDROM_GET_CONFIGURATION
: {
1788 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer
;
1790 TraceLog((CdromDebugTrace
,
1791 "IOCTL_CDROM_GET_CONFIGURATION to via irp %p\n", Irp
));
1794 // Validate buffer length.
1797 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!=
1798 sizeof(GET_CONFIGURATION_IOCTL_INPUT
)) {
1799 status
= STATUS_INFO_LENGTH_MISMATCH
;
1802 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1803 sizeof(GET_CONFIGURATION_HEADER
)) {
1804 status
= STATUS_BUFFER_TOO_SMALL
;
1805 Irp
->IoStatus
.Information
= sizeof(GET_CONFIGURATION_HEADER
);
1808 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
> 0xffff) {
1809 // output buffer is too large
1810 status
= STATUS_INVALID_BUFFER_SIZE
;
1815 // also verify the arguments are reasonable.
1818 inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
1819 if (inputBuffer
->Feature
> 0xffff) {
1820 status
= STATUS_INVALID_PARAMETER
;
1823 if ((inputBuffer
->RequestType
!= SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE
) &&
1824 (inputBuffer
->RequestType
!= SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT
) &&
1825 (inputBuffer
->RequestType
!= SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL
)) {
1826 status
= STATUS_INVALID_PARAMETER
;
1829 if (inputBuffer
->Reserved
[0] || inputBuffer
->Reserved
[1]) {
1830 status
= STATUS_INVALID_PARAMETER
;
1834 IoMarkIrpPending(Irp
);
1835 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1836 return STATUS_PENDING
;
1842 BOOLEAN synchronize
= (KeGetCurrentIrql() == PASSIVE_LEVEL
);
1843 PKEVENT deviceControlEvent
;
1846 // If the ioctl has come in at passive level then we will synchronize
1847 // with our start-io routine when sending the ioctl. If the ioctl
1848 // has come in at a higher interrupt level and it was not handled
1849 // above then it's unlikely to be a request for the class DLL - however
1850 // we'll still use it's common code to forward the request through.
1855 deviceControlEvent
= ExAllocatePoolWithTag(NonPagedPool
,
1857 CDROM_TAG_DC_EVENT
);
1859 if (deviceControlEvent
== NULL
) {
1862 // must complete this irp unsuccessful here
1864 status
= STATUS_INSUFFICIENT_RESOURCES
;
1869 PIO_STACK_LOCATION currentStack
;
1871 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
1873 currentStack
= IoGetCurrentIrpStackLocation(Irp
);
1874 nextStack
= IoGetNextIrpStackLocation(Irp
);
1877 // Copy the stack down a notch
1880 IoCopyCurrentIrpStackLocationToNext(Irp
);
1882 IoSetCompletionRoutine(
1884 CdRomClassIoctlCompletion
,
1891 IoSetNextIrpStackLocation(Irp
);
1893 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1894 Irp
->IoStatus
.Information
= 0;
1897 // Override volume verifies on this stack location so that we
1898 // will be forced through the synchronization. Once this
1899 // location goes away we get the old value back
1902 SET_FLAG(nextStack
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
1904 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1907 // Wait for CdRomClassIoctlCompletion to set the event. This
1908 // ensures serialization remains intact for these unhandled device
1912 KeWaitForSingleObject(
1919 ExFreePool(deviceControlEvent
);
1921 TraceLog((CdromDebugTrace
,
1922 "CdRomDeviceControl: irp %p synchronized\n", Irp
));
1924 status
= Irp
->IoStatus
.Status
;
1928 status
= STATUS_SUCCESS
;
1932 // If an error occured then propagate that back up - we are no longer
1933 // guaranteed synchronization and the upper layers will have to
1936 // If no error occured, call down to the class driver directly
1937 // then start up the next request.
1940 if (NT_SUCCESS(status
)) {
1942 UCHAR uniqueAddress
;
1945 // The class device control routine will release the remove
1946 // lock for this Irp. We need to make sure we have one
1947 // available so that it's safe to call IoStartNextPacket
1952 ClassAcquireRemoveLock(DeviceObject
, (PIRP
)&uniqueAddress
);
1956 status
= ClassDeviceControl(DeviceObject
, Irp
);
1959 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
1960 IoStartNextPacket(DeviceObject
, FALSE
);
1962 ClassReleaseRemoveLock(DeviceObject
, (PIRP
)&uniqueAddress
);
1969 // an error occurred (either STATUS_INSUFFICIENT_RESOURCES from
1970 // attempting to synchronize or StartIo() error'd this one
1971 // out), so we need to finish the irp, which is
1972 // done at the end of this routine.
1976 } // end default case
1980 if (status
== STATUS_VERIFY_REQUIRED
) {
1983 // If the status is verified required and this request
1984 // should bypass verify required then retry the request.
1987 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
1989 status
= STATUS_IO_DEVICE_ERROR
;
1995 if (IoIsErrorUserInduced(status
)) {
1997 if (Irp
->Tail
.Overlay
.Thread
) {
1998 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
2004 // Update IRP with completion status.
2007 Irp
->IoStatus
.Status
= status
;
2010 // Complete the request.
2013 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2014 ClassCompleteRequest(DeviceObject
, Irp
, IO_DISK_INCREMENT
);
2015 TraceLog((CdromDebugTrace
,
2016 "CdRomDeviceControl: Status is %lx\n", status
));
2019 } // end CdRomDeviceControl()
2023 CdRomClassIoctlCompletion(
2024 IN PDEVICE_OBJECT DeviceObject
,
2030 Routine Description:
2032 This routine signals the event used by CdRomDeviceControl to synchronize
2033 class driver (and lower level driver) ioctls with cdrom's startio routine.
2034 The irp completion is short-circuited so that CdRomDeviceControlDispatch
2035 can reissue it once it wakes up.
2039 DeviceObject - the device object
2040 Irp - the request we are synchronizing
2041 Context - a PKEVENT that we need to signal
2049 PKEVENT syncEvent
= (PKEVENT
) Context
;
2051 TraceLog((CdromDebugTrace
,
2052 "CdRomClassIoctlCompletion: setting event for irp %p\n", Irp
));
2055 // We released the lock when we completed this request. Reacquire it.
2058 ClassAcquireRemoveLock(DeviceObject
, Irp
);
2060 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
2062 return STATUS_MORE_PROCESSING_REQUIRED
;
2067 CdRomDeviceControlCompletion(
2068 IN PDEVICE_OBJECT DeviceObject
,
2073 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
2074 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
2076 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
2077 BOOLEAN use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
2079 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2080 PIO_STACK_LOCATION realIrpStack
;
2081 PIO_STACK_LOCATION realIrpNextStack
;
2083 PSCSI_REQUEST_BLOCK srb
= Context
;
2085 PIRP realIrp
= NULL
;
2091 // Extract the 'real' irp from the irpstack.
2094 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2095 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2096 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2099 // check that we've really got the correct irp
2102 ASSERT(realIrpNextStack
->Parameters
.Others
.Argument3
== Irp
);
2105 // Check SRB status for success of completing request.
2108 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2110 ULONG retryInterval
;
2112 TraceLog((CdromDebugTrace
,
2113 "CdRomDeviceControlCompletion: Irp %p, Srb %p Real Irp %p Status %lx\n",
2120 // Release the queue if it is frozen.
2123 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2124 TraceLog((CdromDebugTrace
,
2125 "CdRomDeviceControlCompletion: Releasing Queue\n"));
2126 ClassReleaseQueue(DeviceObject
);
2130 retry
= ClassInterpretSenseInfo(DeviceObject
,
2132 irpStack
->MajorFunction
,
2133 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2134 MAXIMUM_RETRIES
- ((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2138 TraceLog((CdromDebugTrace
,
2139 "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2140 (retry
? "" : "not ")));
2143 // Some of the Device Controls need special cases on non-Success status's.
2146 if (realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
2147 if ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_LAST_SESSION
) ||
2148 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) ||
2149 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC_EX
) ||
2150 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_CONTROL
) ||
2151 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_VOLUME
)) {
2153 if (status
== STATUS_DATA_OVERRUN
) {
2154 status
= STATUS_SUCCESS
;
2159 if (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_Q_CHANNEL
) {
2160 PLAY_ACTIVE(fdoExtension
) = FALSE
;
2165 // If the status is verified required and the this request
2166 // should bypass verify required then retry the request.
2169 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2170 status
== STATUS_VERIFY_REQUIRED
) {
2172 // note: status gets overwritten here
2173 status
= STATUS_IO_DEVICE_ERROR
;
2176 if (((realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) ||
2177 (realIrpStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)
2179 ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2180 IOCTL_CDROM_CHECK_VERIFY
) ||
2181 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2182 IOCTL_STORAGE_CHECK_VERIFY
) ||
2183 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2184 IOCTL_STORAGE_CHECK_VERIFY2
) ||
2185 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2186 IOCTL_DISK_CHECK_VERIFY
)
2191 // Update the geometry information, as the media could have
2192 // changed. The completion routine for this will complete
2193 // the real irp and start the next packet.
2197 if (srb
->SenseInfoBuffer
) {
2198 ExFreePool(srb
->SenseInfoBuffer
);
2200 if (srb
->DataBuffer
) {
2201 ExFreePool(srb
->DataBuffer
);
2207 if (Irp
->MdlAddress
) {
2208 IoFreeMdl(Irp
->MdlAddress
);
2209 Irp
->MdlAddress
= NULL
;
2215 status
= CdRomUpdateCapacity(fdoExtension
, realIrp
, NULL
);
2216 TraceLog((CdromDebugTrace
,
2217 "CdRomDeviceControlCompletion: [%p] "
2218 "CdRomUpdateCapacity completed with status %lx\n",
2222 // needed to update the capacity.
2223 // the irp's already handed off to CdRomUpdateCapacity().
2224 // we've already free'd the current irp.
2225 // nothing left to do in this code path.
2228 return STATUS_MORE_PROCESSING_REQUIRED
;
2230 } // end of ioctls to update capacity
2234 if (retry
&& realIrpNextStack
->Parameters
.Others
.Argument1
--) {
2236 if (((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
2242 TraceLog((CdromDebugWarning
,
2243 "Retry request %p - Calling StartIo\n", Irp
));
2246 ExFreePool(srb
->SenseInfoBuffer
);
2247 if (srb
->DataBuffer
) {
2248 ExFreePool(srb
->DataBuffer
);
2251 if (Irp
->MdlAddress
) {
2252 IoFreeMdl(Irp
->MdlAddress
);
2255 realIrpNextStack
->Parameters
.Others
.Argument3
= (PVOID
)-1;
2258 CdRomRetryRequest(fdoExtension
, realIrp
, retryInterval
, FALSE
);
2259 return STATUS_MORE_PROCESSING_REQUIRED
;
2263 // Exhausted retries. Fall through and complete the request with
2264 // the appropriate status.
2271 // Set status for successful request.
2274 status
= STATUS_SUCCESS
;
2279 if (NT_SUCCESS(status
)) {
2284 switch (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
2286 case IOCTL_CDROM_GET_CONFIGURATION
: {
2287 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
2289 srb
->DataTransferLength
);
2290 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2294 case IOCTL_DISK_GET_LENGTH_INFO
: {
2296 PGET_LENGTH_INFORMATION lengthInfo
;
2298 CdRomInterpretReadCapacity(DeviceObject
,
2299 (PREAD_CAPACITY_DATA
)srb
->DataBuffer
);
2301 lengthInfo
= (PGET_LENGTH_INFORMATION
)realIrp
->AssociatedIrp
.SystemBuffer
;
2302 lengthInfo
->Length
= commonExtension
->PartitionLength
;
2303 realIrp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2304 status
= STATUS_SUCCESS
;
2308 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2309 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
: {
2311 PDISK_GEOMETRY_EX geometryEx
;
2313 CdRomInterpretReadCapacity(DeviceObject
,
2314 (PREAD_CAPACITY_DATA
)srb
->DataBuffer
);
2316 geometryEx
= (PDISK_GEOMETRY_EX
)(realIrp
->AssociatedIrp
.SystemBuffer
);
2317 geometryEx
->DiskSize
= commonExtension
->PartitionLength
;
2318 geometryEx
->Geometry
= fdoExtension
->DiskGeometry
;
2319 realIrp
->IoStatus
.Information
=
2320 FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
);
2324 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2325 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2327 PDISK_GEOMETRY geometry
;
2329 CdRomInterpretReadCapacity(DeviceObject
,
2330 (PREAD_CAPACITY_DATA
)srb
->DataBuffer
);
2332 geometry
= (PDISK_GEOMETRY
)(realIrp
->AssociatedIrp
.SystemBuffer
);
2333 *geometry
= fdoExtension
->DiskGeometry
;
2334 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
2338 case IOCTL_DISK_VERIFY
: {
2340 // nothing to do but return the status...
2345 case IOCTL_DISK_CHECK_VERIFY
:
2346 case IOCTL_STORAGE_CHECK_VERIFY
:
2347 case IOCTL_CDROM_CHECK_VERIFY
: {
2349 if((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
) &&
2350 (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)) {
2352 *((PULONG
)realIrp
->AssociatedIrp
.SystemBuffer
) =
2353 commonExtension
->PartitionZeroExtension
->MediaChangeCount
;
2355 realIrp
->IoStatus
.Information
= sizeof(ULONG
);
2357 realIrp
->IoStatus
.Information
= 0;
2360 TraceLog((CdromDebugTrace
,
2361 "CdRomDeviceControlCompletion: [%p] completing "
2362 "CHECK_VERIFY buddy irp %p\n", realIrp
, Irp
));
2366 case IOCTL_CDROM_READ_TOC_EX
: {
2368 if (srb
->DataTransferLength
< MINIMUM_CDROM_READ_TOC_EX_SIZE
) {
2369 status
= STATUS_INVALID_DEVICE_REQUEST
;
2374 // Copy the returned info into the user buffer.
2377 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
2379 srb
->DataTransferLength
);
2382 // update information field.
2385 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2390 case IOCTL_CDROM_GET_LAST_SESSION
:
2391 case IOCTL_CDROM_READ_TOC
: {
2394 // Copy the returned info into the user buffer.
2397 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
2399 srb
->DataTransferLength
);
2402 // update information field.
2405 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2409 case IOCTL_DVD_READ_STRUCTURE
: {
2411 DVD_STRUCTURE_FORMAT format
= ((PDVD_READ_STRUCTURE
) realIrp
->AssociatedIrp
.SystemBuffer
)->Format
;
2413 PDVD_DESCRIPTOR_HEADER header
= realIrp
->AssociatedIrp
.SystemBuffer
;
2419 TraceLog((CdromDebugTrace
,
2420 "DvdDeviceControlCompletion - IOCTL_DVD_READ_STRUCTURE: completing irp %p (buddy %p)\n",
2424 TraceLog((CdromDebugTrace
,
2425 "DvdDCCompletion - READ_STRUCTURE: descriptor format of %d\n", format
));
2427 RtlMoveMemory(header
,
2429 srb
->DataTransferLength
);
2432 // Cook the data. There are a number of fields that really
2433 // should be byte-swapped for the caller.
2436 TraceLog((CdromDebugInfo
,
2437 "DvdDCCompletion - READ_STRUCTURE:\n"
2439 "\tDvdDCCompletion - READ_STRUCTURE: data at %p\n"
2440 "\tDataBuffer was at %p\n"
2441 "\tDataTransferLength was %lx\n",
2445 srb
->DataTransferLength
));
2448 // First the fields in the header
2451 TraceLog((CdromDebugInfo
, "READ_STRUCTURE: header->Length %lx -> ",
2453 REVERSE_SHORT(&header
->Length
);
2454 TraceLog((CdromDebugInfo
, "%lx\n", header
->Length
));
2457 // Now the fields in the descriptor
2460 if(format
== DvdPhysicalDescriptor
) {
2462 PDVD_LAYER_DESCRIPTOR layer
= (PDVD_LAYER_DESCRIPTOR
) &(header
->Data
[0]);
2464 TraceLog((CdromDebugInfo
, "READ_STRUCTURE: StartingDataSector %lx -> ",
2465 layer
->StartingDataSector
));
2466 REVERSE_LONG(&(layer
->StartingDataSector
));
2467 TraceLog((CdromDebugInfo
, "%lx\n", layer
->StartingDataSector
));
2469 TraceLog((CdromDebugInfo
, "READ_STRUCTURE: EndDataSector %lx -> ",
2470 layer
->EndDataSector
));
2471 REVERSE_LONG(&(layer
->EndDataSector
));
2472 TraceLog((CdromDebugInfo
, "%lx\n", layer
->EndDataSector
));
2474 TraceLog((CdromDebugInfo
, "READ_STRUCTURE: EndLayerZeroSector %lx -> ",
2475 layer
->EndLayerZeroSector
));
2476 REVERSE_LONG(&(layer
->EndLayerZeroSector
));
2477 TraceLog((CdromDebugInfo
, "%lx\n", layer
->EndLayerZeroSector
));
2480 TraceLog((CdromDebugTrace
, "Status is %lx\n", Irp
->IoStatus
.Status
));
2481 TraceLog((CdromDebugTrace
, "DvdDeviceControlCompletion - "
2482 "IOCTL_DVD_READ_STRUCTURE: data transfer length of %d\n",
2483 srb
->DataTransferLength
));
2485 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2489 case IOCTL_DVD_READ_KEY
: {
2491 PDVD_COPY_PROTECT_KEY copyProtectKey
= realIrp
->AssociatedIrp
.SystemBuffer
;
2493 PCDVD_KEY_HEADER keyHeader
= srb
->DataBuffer
;
2496 ULONG transferLength
=
2497 srb
->DataTransferLength
-
2498 FIELD_OFFSET(CDVD_KEY_HEADER
, Data
);
2501 // Adjust the data length to ignore the two reserved bytes in the
2505 dataLength
= (keyHeader
->DataLength
[0] << 8) +
2506 keyHeader
->DataLength
[1];
2510 // take the minimum of the transferred length and the
2511 // length as specified in the header.
2514 if(dataLength
< transferLength
) {
2515 transferLength
= dataLength
;
2518 TraceLog((CdromDebugTrace
,
2519 "DvdDeviceControlCompletion: [%p] - READ_KEY with "
2520 "transfer length of (%d or %d) bytes\n",
2523 srb
->DataTransferLength
- 2));
2526 // Copy the key data into the return buffer
2528 if(copyProtectKey
->KeyType
== DvdTitleKey
) {
2530 RtlMoveMemory(copyProtectKey
->KeyData
,
2531 keyHeader
->Data
+ 1,
2532 transferLength
- 1);
2533 copyProtectKey
->KeyData
[transferLength
- 1] = 0;
2536 // If this is a title key then we need to copy the CGMS flags
2539 copyProtectKey
->KeyFlags
= *(keyHeader
->Data
);
2543 RtlMoveMemory(copyProtectKey
->KeyData
,
2548 copyProtectKey
->KeyLength
= sizeof(DVD_COPY_PROTECT_KEY
);
2549 copyProtectKey
->KeyLength
+= transferLength
;
2551 realIrp
->IoStatus
.Information
= copyProtectKey
->KeyLength
;
2555 case IOCTL_DVD_START_SESSION
: {
2557 PDVD_SESSION_ID sessionId
= realIrp
->AssociatedIrp
.SystemBuffer
;
2559 PCDVD_KEY_HEADER keyHeader
= srb
->DataBuffer
;
2560 PCDVD_REPORT_AGID_DATA keyData
= (PCDVD_REPORT_AGID_DATA
) keyHeader
->Data
;
2562 *sessionId
= keyData
->AGID
;
2564 realIrp
->IoStatus
.Information
= sizeof(DVD_SESSION_ID
);
2569 case IOCTL_DVD_END_SESSION
:
2570 case IOCTL_DVD_SEND_KEY
:
2571 case IOCTL_DVD_SEND_KEY2
:
2574 // nothing to return
2576 realIrp
->IoStatus
.Information
= 0;
2579 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
2581 PLAY_ACTIVE(fdoExtension
) = TRUE
;
2585 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2587 PSUB_Q_CHANNEL_DATA userChannelData
= realIrp
->AssociatedIrp
.SystemBuffer
;
2588 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
= realIrp
->AssociatedIrp
.SystemBuffer
;
2589 PSUB_Q_CHANNEL_DATA subQPtr
= srb
->DataBuffer
;
2592 switch( inputBuffer
->Format
) {
2594 case IOCTL_CDROM_CURRENT_POSITION
:
2595 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->CurrentPosition
.Header
.AudioStatus
));
2596 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr
->CurrentPosition
.ADR
));
2597 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr
->CurrentPosition
.Control
));
2598 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr
->CurrentPosition
.TrackNumber
));
2599 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr
->CurrentPosition
.IndexNumber
));
2600 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.AbsoluteAddress
) ));
2601 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.TrackRelativeAddress
) ));
2604 case IOCTL_CDROM_MEDIA_CATALOG
:
2605 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->MediaCatalog
.Header
.AudioStatus
));
2606 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr
->MediaCatalog
.Mcval
));
2609 case IOCTL_CDROM_TRACK_ISRC
:
2610 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->TrackIsrc
.Header
.AudioStatus
));
2611 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr
->TrackIsrc
.Tcval
));
2618 // Update the play active status.
2621 if (subQPtr
->CurrentPosition
.Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
2623 PLAY_ACTIVE(fdoExtension
) = TRUE
;
2627 PLAY_ACTIVE(fdoExtension
) = FALSE
;
2632 // Check if output buffer is large enough to contain
2636 if (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2637 srb
->DataTransferLength
) {
2639 srb
->DataTransferLength
=
2640 realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
2644 // Copy our buffer into users.
2647 RtlMoveMemory(userChannelData
,
2649 srb
->DataTransferLength
);
2651 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2655 case IOCTL_CDROM_PAUSE_AUDIO
:
2657 PLAY_ACTIVE(fdoExtension
) = FALSE
;
2658 realIrp
->IoStatus
.Information
= 0;
2661 case IOCTL_CDROM_RESUME_AUDIO
:
2663 realIrp
->IoStatus
.Information
= 0;
2666 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
2668 realIrp
->IoStatus
.Information
= 0;
2671 case IOCTL_CDROM_STOP_AUDIO
:
2673 PLAY_ACTIVE(fdoExtension
) = FALSE
;
2674 realIrp
->IoStatus
.Information
= 0;
2677 case IOCTL_CDROM_GET_CONTROL
: {
2679 PCDROM_AUDIO_CONTROL audioControl
= srb
->DataBuffer
;
2680 PAUDIO_OUTPUT audioOutput
;
2681 ULONG bytesTransferred
;
2683 audioOutput
= ClassFindModePage((PCHAR
)audioControl
,
2684 srb
->DataTransferLength
,
2685 CDROM_AUDIO_CONTROL_PAGE
,
2688 // Verify the page is as big as expected.
2691 bytesTransferred
= (ULONG
)((PCHAR
) audioOutput
- (PCHAR
) audioControl
) +
2692 sizeof(AUDIO_OUTPUT
);
2694 if (audioOutput
!= NULL
&&
2695 srb
->DataTransferLength
>= bytesTransferred
) {
2697 audioControl
->LbaFormat
= audioOutput
->LbaFormat
;
2699 audioControl
->LogicalBlocksPerSecond
=
2700 (audioOutput
->LogicalBlocksPerSecond
[0] << (UCHAR
)8) |
2701 audioOutput
->LogicalBlocksPerSecond
[1];
2703 realIrp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
2706 realIrp
->IoStatus
.Information
= 0;
2707 status
= STATUS_INVALID_DEVICE_REQUEST
;
2712 case IOCTL_CDROM_GET_VOLUME
: {
2714 PAUDIO_OUTPUT audioOutput
;
2715 PVOLUME_CONTROL volumeControl
= srb
->DataBuffer
;
2717 ULONG bytesTransferred
;
2719 audioOutput
= ClassFindModePage((PCHAR
)volumeControl
,
2720 srb
->DataTransferLength
,
2721 CDROM_AUDIO_CONTROL_PAGE
,
2725 // Verify the page is as big as expected.
2728 bytesTransferred
= (ULONG
)((PCHAR
) audioOutput
- (PCHAR
) volumeControl
) +
2729 sizeof(AUDIO_OUTPUT
);
2731 if (audioOutput
!= NULL
&&
2732 srb
->DataTransferLength
>= bytesTransferred
) {
2734 for (i
=0; i
<4; i
++) {
2735 volumeControl
->PortVolume
[i
] =
2736 audioOutput
->PortOutput
[i
].Volume
;
2740 // Set bytes transferred in IRP.
2743 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
2746 realIrp
->IoStatus
.Information
= 0;
2747 status
= STATUS_INVALID_DEVICE_REQUEST
;
2753 case IOCTL_CDROM_SET_VOLUME
:
2755 realIrp
->IoStatus
.Information
= 0;
2761 realIrp
->IoStatus
.Information
= 0;
2762 status
= STATUS_INVALID_DEVICE_REQUEST
;
2768 // Deallocate srb and sense buffer.
2772 if (srb
->DataBuffer
) {
2773 ExFreePool(srb
->DataBuffer
);
2775 if (srb
->SenseInfoBuffer
) {
2776 ExFreePool(srb
->SenseInfoBuffer
);
2781 if (realIrp
->PendingReturned
) {
2782 IoMarkIrpPending(realIrp
);
2785 if (Irp
->MdlAddress
) {
2786 IoFreeMdl(Irp
->MdlAddress
);
2792 // Set status in completing IRP.
2795 realIrp
->IoStatus
.Status
= status
;
2798 // Set the hard error if necessary.
2801 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2804 // Store DeviceObject for filesystem, and clear
2805 // in IoStatus.Information field.
2808 TraceLog((CdromDebugWarning
,
2809 "CdRomDeviceCompletion - Setting Hard Error on realIrp %p\n",
2811 if (realIrp
->Tail
.Overlay
.Thread
) {
2812 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
2815 realIrp
->IoStatus
.Information
= 0;
2819 // note: must complete the realIrp, as the completed irp (above)
2820 // was self-allocated.
2823 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
2824 return STATUS_MORE_PROCESSING_REQUIRED
;
2829 CdRomSetVolumeIntermediateCompletion(
2830 IN PDEVICE_OBJECT DeviceObject
,
2835 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2836 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
2838 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2839 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
2840 BOOLEAN use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
2841 PIO_STACK_LOCATION realIrpStack
;
2842 PIO_STACK_LOCATION realIrpNextStack
;
2843 PSCSI_REQUEST_BLOCK srb
= Context
;
2844 PIRP realIrp
= NULL
;
2849 // Extract the 'real' irp from the irpstack.
2852 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2853 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2854 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2857 // Check SRB status for success of completing request.
2860 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2862 ULONG retryInterval
;
2864 TraceLog((CdromDebugTrace
,
2865 "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
2871 // Release the queue if it is frozen.
2874 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2875 ClassReleaseQueue(DeviceObject
);
2879 retry
= ClassInterpretSenseInfo(DeviceObject
,
2881 irpStack
->MajorFunction
,
2882 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2883 MAXIMUM_RETRIES
- ((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2887 if (status
== STATUS_DATA_OVERRUN
) {
2888 status
= STATUS_SUCCESS
;
2893 // If the status is verified required and the this request
2894 // should bypass verify required then retry the request.
2897 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2898 status
== STATUS_VERIFY_REQUIRED
) {
2900 status
= STATUS_IO_DEVICE_ERROR
;
2904 if (retry
&& realIrpNextStack
->Parameters
.Others
.Argument1
--) {
2906 if (((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
2912 TraceLog((CdromDebugWarning
,
2913 "Retry request %p - Calling StartIo\n", Irp
));
2916 ExFreePool(srb
->SenseInfoBuffer
);
2917 ExFreePool(srb
->DataBuffer
);
2919 if (Irp
->MdlAddress
) {
2920 IoFreeMdl(Irp
->MdlAddress
);
2925 CdRomRetryRequest(deviceExtension
,
2930 return STATUS_MORE_PROCESSING_REQUIRED
;
2935 // Exhausted retries. Fall through and complete the request with the appropriate status.
2942 // Set status for successful request.
2945 status
= STATUS_SUCCESS
;
2949 if (NT_SUCCESS(status
)) {
2951 PAUDIO_OUTPUT audioInput
= NULL
;
2952 PAUDIO_OUTPUT audioOutput
;
2953 PVOLUME_CONTROL volumeControl
= realIrp
->AssociatedIrp
.SystemBuffer
;
2954 ULONG i
,bytesTransferred
,headerLength
;
2958 audioInput
= ClassFindModePage((PCHAR
)srb
->DataBuffer
,
2959 srb
->DataTransferLength
,
2960 CDROM_AUDIO_CONTROL_PAGE
,
2964 // Check to make sure the mode sense data is valid before we go on
2967 if(audioInput
== NULL
) {
2969 TraceLog((CdromDebugWarning
,
2970 "Mode Sense Page %d not found\n",
2971 CDROM_AUDIO_CONTROL_PAGE
));
2973 realIrp
->IoStatus
.Information
= 0;
2974 realIrp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
2979 headerLength
= sizeof(MODE_PARAMETER_HEADER
);
2981 headerLength
= sizeof(MODE_PARAMETER_HEADER10
);
2984 bytesTransferred
= sizeof(AUDIO_OUTPUT
) + headerLength
;
2987 // Allocate a new buffer for the mode select.
2990 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2992 CDROM_TAG_VOLUME_INT
);
2995 realIrp
->IoStatus
.Information
= 0;
2996 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3000 RtlZeroMemory(dataBuffer
, bytesTransferred
);
3003 // Rebuild the data buffer to include the user requested values.
3006 audioOutput
= (PAUDIO_OUTPUT
) ((PCHAR
) dataBuffer
+ headerLength
);
3008 for (i
=0; i
<4; i
++) {
3009 audioOutput
->PortOutput
[i
].Volume
=
3010 volumeControl
->PortVolume
[i
];
3011 audioOutput
->PortOutput
[i
].ChannelSelection
=
3012 audioInput
->PortOutput
[i
].ChannelSelection
;
3015 audioOutput
->CodePage
= CDROM_AUDIO_CONTROL_PAGE
;
3016 audioOutput
->ParameterLength
= sizeof(AUDIO_OUTPUT
) - 2;
3017 audioOutput
->Immediate
= MODE_SELECT_IMMEDIATE
;
3020 // Free the old data buffer, mdl.
3023 IoFreeMdl(Irp
->MdlAddress
);
3024 Irp
->MdlAddress
= NULL
;
3025 ExFreePool(srb
->DataBuffer
);
3028 // set the data buffer to new allocation, so it can be
3029 // freed in the exit path
3032 srb
->DataBuffer
= dataBuffer
;
3038 cdb
= (PCDB
)srb
->Cdb
;
3039 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3041 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3042 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3043 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3044 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
3045 srb
->DataTransferLength
= bytesTransferred
;
3049 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3050 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
) bytesTransferred
;
3051 cdb
->MODE_SELECT
.PFBit
= 1;
3055 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
3056 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
) (bytesTransferred
>> 8);
3057 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
) (bytesTransferred
& 0xFF);
3058 cdb
->MODE_SELECT10
.PFBit
= 1;
3059 srb
->CdbLength
= 10;
3066 Irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3072 if (!Irp
->MdlAddress
) {
3073 realIrp
->IoStatus
.Information
= 0;
3074 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3078 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3080 irpStack
= IoGetNextIrpStackLocation(Irp
);
3081 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
3082 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
3083 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3086 // reset the irp completion.
3089 IoSetCompletionRoutine(Irp
,
3090 CdRomDeviceControlCompletion
,
3096 // Call the port driver.
3099 IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
3101 return STATUS_MORE_PROCESSING_REQUIRED
;
3107 // Deallocate srb and sense buffer.
3111 if (srb
->DataBuffer
) {
3112 ExFreePool(srb
->DataBuffer
);
3114 if (srb
->SenseInfoBuffer
) {
3115 ExFreePool(srb
->SenseInfoBuffer
);
3120 if (Irp
->PendingReturned
) {
3121 IoMarkIrpPending(Irp
);
3124 if (realIrp
->PendingReturned
) {
3125 IoMarkIrpPending(realIrp
);
3128 if (Irp
->MdlAddress
) {
3129 IoFreeMdl(Irp
->MdlAddress
);
3135 // Set status in completing IRP.
3138 realIrp
->IoStatus
.Status
= status
;
3141 // Set the hard error if necessary.
3144 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3147 // Store DeviceObject for filesystem, and clear
3148 // in IoStatus.Information field.
3151 if (realIrp
->Tail
.Overlay
.Thread
) {
3152 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3154 realIrp
->IoStatus
.Information
= 0;
3157 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
3158 return STATUS_MORE_PROCESSING_REQUIRED
;
3162 CdRomDvdEndAllSessionsCompletion(
3163 IN PDEVICE_OBJECT DeviceObject
,
3170 Routine Description:
3172 This routine will setup the next stack location to issue an end session
3173 to the device. It will increment the session id in the system buffer
3174 and issue an END_SESSION for that AGID if the AGID is valid.
3176 When the new AGID is > 3 this routine will complete the request.
3180 DeviceObject - the device object for this drive
3188 STATUS_MORE_PROCESSING_REQUIRED if there is another AGID to clear
3194 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
3196 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3198 PDVD_SESSION_ID sessionId
= Irp
->AssociatedIrp
.SystemBuffer
;
3202 if(++(*sessionId
) > MAX_COPY_PROTECT_AGID
) {
3205 // We're done here - just return success and let the io system
3206 // continue to complete it.
3209 return STATUS_SUCCESS
;
3213 IoCopyCurrentIrpStackLocationToNext(Irp
);
3215 IoSetCompletionRoutine(Irp
,
3216 CdRomDvdEndAllSessionsCompletion
,
3222 IoMarkIrpPending(Irp
);
3224 IoCallDriver(fdoExtension
->CommonExtension
.DeviceObject
, Irp
);
3227 // At this point we have to assume the irp may have already been
3228 // completed. Ignore the returned status and return.
3231 return STATUS_MORE_PROCESSING_REQUIRED
;
3235 CdRomDvdReadDiskKeyCompletion(
3236 IN PDEVICE_OBJECT DeviceObject
,
3243 Routine Description:
3245 This routine handles the completion of a request to obtain the disk
3246 key from the dvd media. It will transform the raw 2K of key data into
3247 a DVD_COPY_PROTECT_KEY structure and copy back the saved key parameters
3248 from the context pointer before returning.
3256 Context - a DVD_COPY_PROTECT_KEY pointer which contains the key
3257 parameters handed down by the caller.
3266 PDVD_COPY_PROTECT_KEY savedKey
= Context
;
3268 PREAD_DVD_STRUCTURES_HEADER rawKey
= Irp
->AssociatedIrp
.SystemBuffer
;
3269 PDVD_COPY_PROTECT_KEY outputKey
= Irp
->AssociatedIrp
.SystemBuffer
;
3271 if (NT_SUCCESS(Irp
->IoStatus
.Status
)) {
3274 // Shift the data down to its new position.
3277 RtlMoveMemory(outputKey
->KeyData
,
3279 sizeof(DVD_DISK_KEY_DESCRIPTOR
));
3281 RtlCopyMemory(outputKey
,
3283 sizeof(DVD_COPY_PROTECT_KEY
));
3285 outputKey
->KeyLength
= DVD_DISK_KEY_LENGTH
;
3287 Irp
->IoStatus
.Information
= DVD_DISK_KEY_LENGTH
;
3291 TraceLog((CdromDebugWarning
,
3292 "DiskKey Failed with status %x, %p (%x) bytes\n",
3293 Irp
->IoStatus
.Status
,
3294 (PVOID
)Irp
->IoStatus
.Information
,
3295 ((rawKey
->Length
[0] << 16) | rawKey
->Length
[1])
3301 // release the context block
3304 ExFreePool(Context
);
3306 return STATUS_SUCCESS
;
3311 IN PDEVICE_OBJECT DeviceObject
,
3318 Routine Description:
3320 This routine executes when the port driver has completed a request.
3321 It looks at the SRB status in the completing SRB and if not success
3322 it checks for valid request sense buffer information. If valid, the
3323 info is used to update status with more precise message of type of
3324 error. This routine deallocates the SRB.
3328 DeviceObject - Supplies the device object which represents the logical
3331 Irp - Supplies the Irp which has completed.
3333 Context - Supplies a pointer to the SRB.
3342 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3343 PSCSI_REQUEST_BLOCK srb
= Context
;
3344 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3349 // Check SRB status for success of completing request.
3352 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3354 ULONG retryInterval
;
3356 TraceLog((CdromDebugTrace
, "CdromXAComplete: IRP %p SRB %p Status %x\n",
3357 Irp
, srb
, srb
->SrbStatus
));
3360 // Release the queue if it is frozen.
3363 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3364 ClassReleaseQueue(DeviceObject
);
3367 retry
= ClassInterpretSenseInfo(
3370 irpStack
->MajorFunction
,
3371 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
3372 MAXIMUM_RETRIES
- irpStack
->MinorFunction
, // HACKHACK - REF #0001
3377 // If the status is verified required and the this request
3378 // should bypass verify required then retry the request.
3381 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3382 status
== STATUS_VERIFY_REQUIRED
) {
3384 status
= STATUS_IO_DEVICE_ERROR
;
3390 if (irpStack
->MinorFunction
!= 0) { // HACKHACK - REF #0001
3392 irpStack
->MinorFunction
--; // HACKHACK - REF #0001
3398 TraceLog((CdromDebugWarning
,
3399 "CdRomXACompletion: Retry request %p (%x) - "
3400 "Calling StartIo\n", Irp
, irpStack
->MinorFunction
));
3403 ExFreePool(srb
->SenseInfoBuffer
);
3407 // Call StartIo directly since IoStartNextPacket hasn't been called,
3408 // the serialisation is still intact.
3411 CdRomRetryRequest(deviceExtension
,
3416 return STATUS_MORE_PROCESSING_REQUIRED
;
3421 // Exhausted retries, fall through and complete the request
3422 // with the appropriate status
3425 TraceLog((CdromDebugWarning
,
3426 "CdRomXACompletion: Retries exhausted for irp %p\n",
3434 // Set status for successful request.
3437 status
= STATUS_SUCCESS
;
3439 } // end if (SRB_STATUS(srb->SrbStatus) ...
3442 // Return SRB to nonpaged pool.
3445 ExFreePool(srb
->SenseInfoBuffer
);
3449 // Set status in completing IRP.
3452 Irp
->IoStatus
.Status
= status
;
3455 // Set the hard error if necessary.
3458 if (!NT_SUCCESS(status
) &&
3459 IoIsErrorUserInduced(status
) &&
3460 Irp
->Tail
.Overlay
.Thread
!= NULL
) {
3463 // Store DeviceObject for filesystem, and clear
3464 // in IoStatus.Information field.
3467 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
3468 Irp
->IoStatus
.Information
= 0;
3472 // If pending has be returned for this irp then mark the current stack as
3476 if (Irp
->PendingReturned
) {
3477 IoMarkIrpPending(Irp
);
3481 KIRQL oldIrql
= KeRaiseIrqlToDpcLevel();
3482 IoStartNextPacket(DeviceObject
, FALSE
);
3483 KeLowerIrql(oldIrql
);
3485 ClassReleaseRemoveLock(DeviceObject
, Irp
);
3492 CdRomDeviceControlDvdReadStructure(
3493 IN PDEVICE_OBJECT Fdo
,
3494 IN PIRP OriginalIrp
,
3496 IN PSCSI_REQUEST_BLOCK Srb
3499 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
3500 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3501 PCDB cdb
= (PCDB
)Srb
->Cdb
;
3504 PDVD_READ_STRUCTURE request
;
3507 PFOUR_BYTE fourByte
;
3510 (USHORT
)currentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
3512 request
= OriginalIrp
->AssociatedIrp
.SystemBuffer
;
3514 (ULONG
)(request
->BlockByteOffset
.QuadPart
>> fdoExtension
->SectorShift
);
3515 fourByte
= (PFOUR_BYTE
) &blockNumber
;
3517 Srb
->CdbLength
= 12;
3518 Srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3519 Srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3520 SET_FLAG(Srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3522 cdb
->READ_DVD_STRUCTURE
.OperationCode
= SCSIOP_READ_DVD_STRUCTURE
;
3523 cdb
->READ_DVD_STRUCTURE
.RMDBlockNumber
[0] = fourByte
->Byte3
;
3524 cdb
->READ_DVD_STRUCTURE
.RMDBlockNumber
[1] = fourByte
->Byte2
;
3525 cdb
->READ_DVD_STRUCTURE
.RMDBlockNumber
[2] = fourByte
->Byte1
;
3526 cdb
->READ_DVD_STRUCTURE
.RMDBlockNumber
[3] = fourByte
->Byte0
;
3527 cdb
->READ_DVD_STRUCTURE
.LayerNumber
= request
->LayerNumber
;
3528 cdb
->READ_DVD_STRUCTURE
.Format
= (UCHAR
)request
->Format
;
3532 if ((UCHAR
)request
->Format
> DvdMaxDescriptor
) {
3533 TraceLog((CdromDebugWarning
,
3534 "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
3535 (UCHAR
)request
->Format
,
3536 READ_DVD_STRUCTURE_FORMAT_STRINGS
[DvdMaxDescriptor
],
3540 TraceLog((CdromDebugWarning
,
3541 "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
3542 (UCHAR
)request
->Format
,
3543 READ_DVD_STRUCTURE_FORMAT_STRINGS
[(UCHAR
)request
->Format
],
3550 if (request
->Format
== DvdDiskKeyDescriptor
) {
3552 cdb
->READ_DVD_STRUCTURE
.AGID
= (UCHAR
) request
->SessionId
;
3556 cdb
->READ_DVD_STRUCTURE
.AllocationLength
[0] = (UCHAR
)(dataLength
>> 8);
3557 cdb
->READ_DVD_STRUCTURE
.AllocationLength
[1] = (UCHAR
)(dataLength
& 0xff);
3558 Srb
->DataTransferLength
= dataLength
;
3562 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3564 DVD_TAG_READ_STRUCTURE
);
3567 ExFreePool(Srb
->SenseInfoBuffer
);
3570 OriginalIrp
->IoStatus
.Information
= 0;
3571 OriginalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3573 BAIL_OUT(OriginalIrp
);
3574 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
3577 RtlZeroMemory(dataBuffer
, dataLength
);
3579 NewIrp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3580 currentIrpStack
->Parameters
.Read
.Length
,
3585 if (NewIrp
->MdlAddress
== NULL
) {
3586 ExFreePool(dataBuffer
);
3587 ExFreePool(Srb
->SenseInfoBuffer
);
3590 OriginalIrp
->IoStatus
.Information
= 0;
3591 OriginalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3593 BAIL_OUT(OriginalIrp
);
3594 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
3602 MmBuildMdlForNonPagedPool(NewIrp
->MdlAddress
);
3604 Srb
->DataBuffer
= dataBuffer
;
3606 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, NewIrp
);
3613 CdRomDeviceControlDvdEndSession(
3614 IN PDEVICE_OBJECT Fdo
,
3615 IN PIRP OriginalIrp
,
3617 IN PSCSI_REQUEST_BLOCK Srb
3620 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
3621 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3622 PCDB cdb
= (PCDB
)Srb
->Cdb
;
3624 PDVD_SESSION_ID sessionId
= OriginalIrp
->AssociatedIrp
.SystemBuffer
;
3626 Srb
->CdbLength
= 12;
3627 Srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3628 Srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3629 SET_FLAG(Srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
3631 cdb
->SEND_KEY
.OperationCode
= SCSIOP_SEND_KEY
;
3632 cdb
->SEND_KEY
.AGID
= (UCHAR
) (*sessionId
);
3633 cdb
->SEND_KEY
.KeyFormat
= DVD_INVALIDATE_AGID
;
3635 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, NewIrp
);
3642 CdRomDeviceControlDvdStartSessionReadKey(
3643 IN PDEVICE_OBJECT Fdo
,
3644 IN PIRP OriginalIrp
,
3646 IN PSCSI_REQUEST_BLOCK Srb
3649 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
3650 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3651 PCDB cdb
= (PCDB
)Srb
->Cdb
;
3654 PDVD_COPY_PROTECT_KEY keyParameters
;
3655 PCDVD_KEY_HEADER keyBuffer
= NULL
;
3659 ULONG allocationLength
;
3660 PFOUR_BYTE fourByte
;
3663 // Both of these use REPORT_KEY commands.
3664 // Determine the size of the input buffer
3667 if(currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3668 IOCTL_DVD_READ_KEY
) {
3670 keyParameters
= OriginalIrp
->AssociatedIrp
.SystemBuffer
;
3672 keyLength
= sizeof(CDVD_KEY_HEADER
) +
3673 (currentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
-
3674 sizeof(DVD_COPY_PROTECT_KEY
));
3677 keyParameters
= NULL
;
3678 keyLength
= sizeof(CDVD_KEY_HEADER
) +
3679 sizeof(CDVD_REPORT_AGID_DATA
);
3684 keyBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3688 if(keyBuffer
== NULL
) {
3690 TraceLog((CdromDebugWarning
,
3691 "IOCTL_DVD_READ_KEY - couldn't allocate "
3692 "%d byte buffer for key\n",
3694 status
= STATUS_INSUFFICIENT_RESOURCES
;
3699 NewIrp
->MdlAddress
= IoAllocateMdl(keyBuffer
,
3705 if(NewIrp
->MdlAddress
== NULL
) {
3707 TraceLog((CdromDebugWarning
,
3708 "IOCTL_DVD_READ_KEY - couldn't create mdl\n"));
3709 status
= STATUS_INSUFFICIENT_RESOURCES
;
3713 MmBuildMdlForNonPagedPool(NewIrp
->MdlAddress
);
3715 Srb
->DataBuffer
= keyBuffer
;
3716 Srb
->CdbLength
= 12;
3718 cdb
->REPORT_KEY
.OperationCode
= SCSIOP_REPORT_KEY
;
3720 allocationLength
= keyLength
;
3721 fourByte
= (PFOUR_BYTE
) &allocationLength
;
3722 cdb
->REPORT_KEY
.AllocationLength
[0] = fourByte
->Byte1
;
3723 cdb
->REPORT_KEY
.AllocationLength
[1] = fourByte
->Byte0
;
3725 Srb
->DataTransferLength
= keyLength
;
3728 // set the specific parameters....
3731 if(currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3732 IOCTL_DVD_READ_KEY
) {
3734 if(keyParameters
->KeyType
== DvdTitleKey
) {
3736 ULONG logicalBlockAddress
;
3738 logicalBlockAddress
= (ULONG
)
3739 (keyParameters
->Parameters
.TitleOffset
.QuadPart
>>
3740 fdoExtension
->SectorShift
);
3742 fourByte
= (PFOUR_BYTE
) &(logicalBlockAddress
);
3744 cdb
->REPORT_KEY
.LogicalBlockAddress
[0] = fourByte
->Byte3
;
3745 cdb
->REPORT_KEY
.LogicalBlockAddress
[1] = fourByte
->Byte2
;
3746 cdb
->REPORT_KEY
.LogicalBlockAddress
[2] = fourByte
->Byte1
;
3747 cdb
->REPORT_KEY
.LogicalBlockAddress
[3] = fourByte
->Byte0
;
3750 cdb
->REPORT_KEY
.KeyFormat
= (UCHAR
)keyParameters
->KeyType
;
3751 cdb
->REPORT_KEY
.AGID
= (UCHAR
) keyParameters
->SessionId
;
3752 TraceLog((CdromDebugWarning
,
3753 "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
3754 NewIrp
, OriginalIrp
, "READ_KEY"));
3758 cdb
->REPORT_KEY
.KeyFormat
= DVD_REPORT_AGID
;
3759 cdb
->REPORT_KEY
.AGID
= 0;
3760 TraceLog((CdromDebugWarning
,
3761 "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
3762 NewIrp
, OriginalIrp
, "START_SESSION"));
3765 Srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3766 Srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3767 SET_FLAG(Srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3769 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, NewIrp
);
3771 status
= STATUS_SUCCESS
;
3775 if (!NT_SUCCESS(status
)) {
3778 // An error occured during setup - free resources and
3779 // complete this request.
3781 if (NewIrp
->MdlAddress
!= NULL
) {
3782 IoFreeMdl(NewIrp
->MdlAddress
);
3785 if (keyBuffer
!= NULL
) {
3786 ExFreePool(keyBuffer
);
3788 ExFreePool(Srb
->SenseInfoBuffer
);
3792 OriginalIrp
->IoStatus
.Information
= 0;
3793 OriginalIrp
->IoStatus
.Status
= status
;
3795 BAIL_OUT(OriginalIrp
);
3796 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
3798 } // end !NT_SUCCESS
3805 CdRomDeviceControlDvdSendKey(
3806 IN PDEVICE_OBJECT Fdo
,
3807 IN PIRP OriginalIrp
,
3809 IN PSCSI_REQUEST_BLOCK Srb
3812 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
3813 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3814 PCDB cdb
= (PCDB
)Srb
->Cdb
;
3816 PDVD_COPY_PROTECT_KEY key
;
3817 PCDVD_KEY_HEADER keyBuffer
= NULL
;
3821 PFOUR_BYTE fourByte
;
3823 key
= OriginalIrp
->AssociatedIrp
.SystemBuffer
;
3824 keyLength
= (key
->KeyLength
- sizeof(DVD_COPY_PROTECT_KEY
)) +
3825 sizeof(CDVD_KEY_HEADER
);
3829 keyBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3833 if(keyBuffer
== NULL
) {
3835 TraceLog((CdromDebugWarning
,
3836 "IOCTL_DVD_SEND_KEY - couldn't allocate "
3837 "%d byte buffer for key\n",
3839 status
= STATUS_INSUFFICIENT_RESOURCES
;
3843 RtlZeroMemory(keyBuffer
, keyLength
);
3846 // keylength is decremented here by two because the
3847 // datalength does not include the header, which is two
3848 // bytes. keylength is immediately incremented later
3849 // by the same amount.
3853 fourByte
= (PFOUR_BYTE
) &keyLength
;
3854 keyBuffer
->DataLength
[0] = fourByte
->Byte1
;
3855 keyBuffer
->DataLength
[1] = fourByte
->Byte0
;
3859 // copy the user's buffer to our own allocated buffer
3862 RtlMoveMemory(keyBuffer
->Data
,
3864 key
->KeyLength
- sizeof(DVD_COPY_PROTECT_KEY
));
3867 NewIrp
->MdlAddress
= IoAllocateMdl(keyBuffer
,
3873 if(NewIrp
->MdlAddress
== NULL
) {
3874 TraceLog((CdromDebugWarning
,
3875 "IOCTL_DVD_SEND_KEY - couldn't create mdl\n"));
3876 status
= STATUS_INSUFFICIENT_RESOURCES
;
3881 MmBuildMdlForNonPagedPool(NewIrp
->MdlAddress
);
3883 Srb
->CdbLength
= 12;
3884 Srb
->DataBuffer
= keyBuffer
;
3885 Srb
->DataTransferLength
= keyLength
;
3887 Srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3888 Srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3889 SET_FLAG(Srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
3891 cdb
->REPORT_KEY
.OperationCode
= SCSIOP_SEND_KEY
;
3893 fourByte
= (PFOUR_BYTE
) &keyLength
;
3895 cdb
->SEND_KEY
.ParameterListLength
[0] = fourByte
->Byte1
;
3896 cdb
->SEND_KEY
.ParameterListLength
[1] = fourByte
->Byte0
;
3897 cdb
->SEND_KEY
.KeyFormat
= (UCHAR
)key
->KeyType
;
3898 cdb
->SEND_KEY
.AGID
= (UCHAR
) key
->SessionId
;
3900 if (key
->KeyType
== DvdSetRpcKey
) {
3901 TraceLog((CdromDebugWarning
,
3902 "IOCTL_DVD_SEND_KEY - Setting RPC2 drive region\n"));
3904 TraceLog((CdromDebugWarning
,
3905 "IOCTL_DVD_SEND_KEY - key type %x\n", key
->KeyType
));
3908 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, NewIrp
);
3910 status
= STATUS_SUCCESS
;
3914 if (!NT_SUCCESS(status
)) {
3917 // An error occured during setup - free resources and
3918 // complete this request.
3921 if (NewIrp
->MdlAddress
!= NULL
) {
3922 IoFreeMdl(NewIrp
->MdlAddress
);
3925 if (keyBuffer
!= NULL
) {
3926 ExFreePool(keyBuffer
);
3929 ExFreePool(Srb
->SenseInfoBuffer
);
3933 OriginalIrp
->IoStatus
.Information
= 0;
3934 OriginalIrp
->IoStatus
.Status
= status
;
3936 BAIL_OUT(OriginalIrp
);
3937 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
3947 CdRomInterpretReadCapacity(
3948 IN PDEVICE_OBJECT Fdo
,
3949 IN PREAD_CAPACITY_DATA ReadCapacityBuffer
3952 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3953 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
3959 ASSERT(ReadCapacityBuffer
);
3960 ASSERT(commonExtension
->IsFdo
);
3962 TraceLog((CdromDebugError
,
3963 "CdRomInterpretReadCapacity: Entering\n"));
3966 // Swizzle bytes from Read Capacity and translate into
3967 // the necessary geometry information in the device extension.
3970 tmp
= ReadCapacityBuffer
->BytesPerBlock
;
3971 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3972 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3973 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3974 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3977 // Insure that bps is a power of 2.
3978 // This corrects a problem with the HP 4020i CDR where it
3979 // returns an incorrect number for bytes per sector.
3985 lastBit
= (ULONG
) -1;
3993 fdoExtension
->DiskGeometry
.BytesPerSector
= bps
;
3995 TraceLog((CdromDebugTrace
, "CdRomInterpretReadCapacity: Calculated bps %#x\n",
3996 fdoExtension
->DiskGeometry
.BytesPerSector
));
3999 // Copy last sector in reverse byte order.
4002 tmp
= ReadCapacityBuffer
->LogicalBlockAddress
;
4003 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
4004 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
4005 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
4006 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
4009 // Calculate sector to byte shift.
4012 WHICH_BIT(bps
, fdoExtension
->SectorShift
);
4014 TraceLog((CdromDebugTrace
,"CdRomInterpretReadCapacity: Sector size is %d\n",
4015 fdoExtension
->DiskGeometry
.BytesPerSector
));
4017 TraceLog((CdromDebugTrace
,"CdRomInterpretReadCapacity: Number of Sectors is %d\n",
4021 // Calculate media capacity in bytes.
4024 commonExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
4027 // we've defaulted to 32/64 forever. don't want to change this now...
4030 fdoExtension
->DiskGeometry
.TracksPerCylinder
= 0x40;
4031 fdoExtension
->DiskGeometry
.SectorsPerTrack
= 0x20;
4034 // Calculate number of cylinders.
4037 fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1) / (32 * 64));
4039 commonExtension
->PartitionLength
.QuadPart
=
4040 (commonExtension
->PartitionLength
.QuadPart
<< fdoExtension
->SectorShift
);
4043 ASSERT(TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
));
4046 // This device supports removable media.
4049 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;