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).
30 PUCHAR READ_DVD_STRUCTURE_FORMAT_STRINGS
[DvdMaxDescriptor
+1] = {
40 #define DEFAULT_CDROM_SECTORS_PER_TRACK 32
41 #define DEFAULT_TRACKS_PER_CYLINDER 64
45 CdRomDeviceControlDispatch(
46 IN PDEVICE_OBJECT DeviceObject
,
53 This is the NT device control handler for CDROMs.
57 DeviceObject - for this CDROM
59 Irp - IO Request packet
67 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
68 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
70 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
71 PIO_STACK_LOCATION nextStack
;
72 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
74 BOOLEAN use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
75 SCSI_REQUEST_BLOCK srb
;
76 PCDB cdb
= (PCDB
)srb
.Cdb
;
78 ULONG bytesTransferred
= 0;
90 // Zero the SRB on stack.
93 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
95 Irp
->IoStatus
.Information
= 0;
98 // if this is a class driver ioctl then we need to change the base code
99 // to IOCTL_CDROM_BASE so that the switch statement can handle it.
101 // WARNING - currently the scsi class ioctl function codes are between
102 // 0x200 & 0x300. this routine depends on that fact
105 ioctlCode
= irpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
106 baseCode
= ioctlCode
>> 16;
107 functionCode
= (ioctlCode
& (~0xffffc003)) >> 2;
109 TraceLog((CdromDebugTrace
,
110 "CdRomDeviceControl: Ioctl Code = %lx, Base Code = %lx,"
111 " Function Code = %lx\n",
117 if((functionCode
>= 0x200) && (functionCode
<= 0x300)) {
119 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_CDROM_BASE
, 0, 0, 0);
121 TraceLog((CdromDebugTrace
,
122 "CdRomDeviceControl: Class Code - new ioctl code is %lx\n",
125 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
131 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX
: {
133 PGET_MEDIA_TYPES mediaTypes
= Irp
->AssociatedIrp
.SystemBuffer
;
134 PDEVICE_MEDIA_INFO mediaInfo
= &mediaTypes
->MediaInfo
[0];
137 sizeNeeded
= sizeof(GET_MEDIA_TYPES
);
140 // IsMmc is static...
143 if (cdData
->Mmc
.IsMmc
) {
144 sizeNeeded
+= sizeof(DEVICE_MEDIA_INFO
) * 1; // return two media types
148 // Ensure that buffer is large enough.
151 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
158 Irp
->IoStatus
.Information
= sizeNeeded
;
159 status
= STATUS_BUFFER_TOO_SMALL
;
163 RtlZeroMemory(Irp
->AssociatedIrp
.SystemBuffer
, sizeNeeded
);
166 // ISSUE-2000/5/11-henrygab - need to update GET_MEDIA_TYPES_EX
169 mediaTypes
->DeviceType
= CdRomGetDeviceType(DeviceObject
);
171 mediaTypes
->MediaInfoCount
= 1;
172 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaType
= CD_ROM
;
173 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.NumberMediaSides
= 1;
174 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
= MEDIA_READ_ONLY
;
175 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.Cylinders
.QuadPart
= fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
;
176 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.TracksPerCylinder
= fdoExtension
->DiskGeometry
.TracksPerCylinder
;
177 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.SectorsPerTrack
= fdoExtension
->DiskGeometry
.SectorsPerTrack
;
178 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.BytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
180 if (cdData
->Mmc
.IsMmc
) {
183 // also report a removable disk
185 mediaTypes
->MediaInfoCount
+= 1;
188 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaType
= RemovableMedia
;
189 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.NumberMediaSides
= 1;
190 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
= MEDIA_READ_WRITE
;
191 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.Cylinders
.QuadPart
= fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
;
192 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.TracksPerCylinder
= fdoExtension
->DiskGeometry
.TracksPerCylinder
;
193 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.SectorsPerTrack
= fdoExtension
->DiskGeometry
.SectorsPerTrack
;
194 mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.BytesPerSector
= fdoExtension
->DiskGeometry
.BytesPerSector
;
200 // Status will either be success, if media is present, or no media.
201 // It would be optimal to base from density code and medium type, but not all devices
202 // have values for these fields.
206 // Send a TUR to determine if media is present.
211 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
214 // Set timeout value.
217 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
219 status
= ClassSendSrbSynchronous(DeviceObject
,
226 TraceLog((CdromDebugWarning
,
227 "CdRomDeviceControl: GET_MEDIA_TYPES status of TUR - %lx\n",
230 if (NT_SUCCESS(status
)) {
233 // set the disk's media as current if we can write to it.
236 if (cdData
->Mmc
.IsMmc
&& cdData
->Mmc
.WriteAllowed
) {
239 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
,
240 MEDIA_CURRENTLY_MOUNTED
);
246 SET_FLAG(mediaInfo
->DeviceSpecific
.RemovableDiskInfo
.MediaCharacteristics
,
247 MEDIA_CURRENTLY_MOUNTED
);
253 Irp
->IoStatus
.Information
= sizeNeeded
;
254 status
= STATUS_SUCCESS
;
259 case IOCTL_CDROM_RAW_READ
: {
261 LARGE_INTEGER startingOffset
;
262 ULONGLONG transferBytes
;
265 //ULONG startingSector;
266 PRAW_READ_INFO rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
269 // Ensure that XA reads are supported.
272 if (TEST_FLAG(cdData
->XAFlags
, XA_NOT_SUPPORTED
)) {
273 TraceLog((CdromDebugWarning
,
274 "CdRomDeviceControl: XA Reads not supported. Flags (%x)\n",
276 status
= STATUS_INVALID_DEVICE_REQUEST
;
281 // Check that ending sector is on disc and buffers are there and of
285 if (rawReadInfo
== NULL
) {
288 // Called from user space. Save the userbuffer in the
289 // Type3InputBuffer so we can reduce the number of code paths.
292 irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
=
293 Irp
->AssociatedIrp
.SystemBuffer
;
296 // Called from user space. Validate the buffers.
299 rawReadInfo
= (PRAW_READ_INFO
)irpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
301 if (rawReadInfo
== NULL
) {
303 TraceLog((CdromDebugWarning
,
304 "CdRomDeviceControl: Invalid I/O parameters for "
305 "XA Read (No extent info\n"));
306 status
= STATUS_INVALID_PARAMETER
;
311 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!=
312 sizeof(RAW_READ_INFO
)) {
314 TraceLog((CdromDebugWarning
,
315 "CdRomDeviceControl: Invalid I/O parameters for "
316 "XA Read (Invalid info buffer\n"));
317 status
= STATUS_INVALID_PARAMETER
;
324 // if they don't request any data, just fail the request
327 if (rawReadInfo
->SectorCount
== 0) {
329 status
= STATUS_INVALID_PARAMETER
;
334 startingOffset
.QuadPart
= rawReadInfo
->DiskOffset
.QuadPart
;
335 /* startingSector = (ULONG)(rawReadInfo->DiskOffset.QuadPart >>
336 fdoExtension->SectorShift); */
337 transferBytes
= (ULONGLONG
)rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
339 endOffset
= (ULONGLONG
)rawReadInfo
->SectorCount
* COOKED_SECTOR_SIZE
;
340 endOffset
+= startingOffset
.QuadPart
;
343 // check for overflows....
346 if (transferBytes
< (ULONGLONG
)(rawReadInfo
->SectorCount
)) {
347 TraceLog((CdromDebugWarning
,
348 "CdRomDeviceControl: Invalid I/O parameters for XA "
349 "Read (TransferBytes Overflow)\n"));
350 status
= STATUS_INVALID_PARAMETER
;
353 if (endOffset
< (ULONGLONG
)startingOffset
.QuadPart
) {
354 TraceLog((CdromDebugWarning
,
355 "CdRomDeviceControl: Invalid I/O parameters for XA "
356 "Read (EndingOffset Overflow)\n"));
357 status
= STATUS_INVALID_PARAMETER
;
360 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
362 TraceLog((CdromDebugWarning
,
363 "CdRomDeviceControl: Invalid I/O parameters for XA "
364 "Read (Bad buffer size)\n"));
365 status
= STATUS_INVALID_PARAMETER
;
368 if (endOffset
> (ULONGLONG
)commonExtension
->PartitionLength
.QuadPart
) {
369 TraceLog((CdromDebugWarning
,
370 "CdRomDeviceControl: Invalid I/O parameters for XA "
371 "Read (Request Out of Bounds)\n"));
372 status
= STATUS_INVALID_PARAMETER
;
377 // cannot validate the MdlAddress, since it is not included in any
378 // other location per the DDK and file system calls.
382 // validate the mdl describes at least the number of bytes
383 // requested from us.
386 mdlBytes
= (ULONGLONG
)MmGetMdlByteCount(Irp
->MdlAddress
);
387 if (mdlBytes
< transferBytes
) {
388 TraceLog((CdromDebugWarning
,
389 "CdRomDeviceControl: Invalid MDL %s, Irp %p\n",
391 status
= STATUS_INVALID_PARAMETER
;
396 // HACKHACK - REF #0001
397 // The retry count will be in this irp's IRP_MN function,
398 // as the new irp was freed, and we therefore cannot use
399 // this irp's next stack location for this function.
400 // This may be a good location to store this info for
401 // when we remove RAW_READ (mode switching), as we will
402 // no longer have the nextIrpStackLocation to play with
405 // once XA_READ is removed, then this hack can also be
408 irpStack
->MinorFunction
= MAXIMUM_RETRIES
; // HACKHACK - REF #0001
410 IoMarkIrpPending(Irp
);
411 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
413 return STATUS_PENDING
;
416 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
417 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
: {
418 TraceLog((CdromDebugTrace
,
419 "CdRomDeviceControl: Get drive geometryEx\n"));
420 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
421 FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
)) {
422 status
= STATUS_BUFFER_TOO_SMALL
;
423 Irp
->IoStatus
.Information
= FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
);
426 IoMarkIrpPending(Irp
);
427 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
428 return STATUS_PENDING
;
431 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
432 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
434 TraceLog((CdromDebugTrace
,
435 "CdRomDeviceControl: Get drive geometry\n"));
437 if ( irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
438 sizeof( DISK_GEOMETRY
) ) {
440 status
= STATUS_BUFFER_TOO_SMALL
;
441 Irp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
445 IoMarkIrpPending(Irp
);
446 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
448 return STATUS_PENDING
;
451 case IOCTL_CDROM_READ_TOC_EX
: {
453 PCDROM_READ_TOC_EX inputBuffer
;
455 if (CdRomIsPlayActive(DeviceObject
)) {
456 status
= STATUS_DEVICE_BUSY
;
460 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
461 sizeof(CDROM_READ_TOC_EX
)) {
462 status
= STATUS_INFO_LENGTH_MISMATCH
;
466 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
467 MINIMUM_CDROM_READ_TOC_EX_SIZE
) {
468 status
= STATUS_BUFFER_TOO_SMALL
;
469 Irp
->IoStatus
.Information
= MINIMUM_CDROM_READ_TOC_EX_SIZE
;
473 if (irpStack
->Parameters
.Read
.Length
> ((USHORT
)-1)) {
474 status
= STATUS_INVALID_PARAMETER
;
478 inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
480 if ((inputBuffer
->Reserved1
!= 0) ||
481 (inputBuffer
->Reserved2
!= 0) ||
482 (inputBuffer
->Reserved3
!= 0)) {
483 status
= STATUS_INVALID_PARAMETER
;
488 // NOTE: when adding new formats, ensure that first two bytes
489 // specify the amount of additional data available.
492 if ((inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_TOC
) ||
493 (inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_FULL_TOC
) ||
494 (inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_CDTEXT
)) {
496 // SessionTrack field is used
499 if ((inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_SESSION
) ||
500 (inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_PMA
) ||
501 (inputBuffer
->Format
== CDROM_READ_TOC_EX_FORMAT_ATIP
)) {
503 // SessionTrack field is reserved
505 if (inputBuffer
->SessionTrack
!= 0) {
506 status
= STATUS_INVALID_PARAMETER
;
511 status
= STATUS_INVALID_PARAMETER
;
515 IoMarkIrpPending(Irp
);
516 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
517 return STATUS_PENDING
;
520 case IOCTL_CDROM_GET_LAST_SESSION
: {
523 // If the cd is playing music then reject this request.
526 if (CdRomIsPlayActive(DeviceObject
)) {
527 status
= STATUS_DEVICE_BUSY
;
532 // Make sure the caller is requesting enough data to make this worth
536 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
537 sizeof(CDROM_TOC_SESSION_DATA
)) {
540 // they didn't request the entire TOC -- use _EX version
541 // for partial transfers and such.
544 status
= STATUS_BUFFER_TOO_SMALL
;
545 Irp
->IoStatus
.Information
= sizeof(CDROM_TOC_SESSION_DATA
);
549 IoMarkIrpPending(Irp
);
550 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
552 return STATUS_PENDING
;
555 case IOCTL_CDROM_READ_TOC
: {
558 // If the cd is playing music then reject this request.
561 if (CdRomIsPlayActive(DeviceObject
)) {
562 status
= STATUS_DEVICE_BUSY
;
567 // Make sure the caller is requesting enough data to make this worth
571 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
575 // they didn't request the entire TOC -- use _EX version
576 // for partial transfers and such.
579 status
= STATUS_BUFFER_TOO_SMALL
;
580 Irp
->IoStatus
.Information
= sizeof(CDROM_TOC
);
584 IoMarkIrpPending(Irp
);
585 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
587 return STATUS_PENDING
;
590 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
596 TraceLog((CdromDebugTrace
,
597 "CdRomDeviceControl: Play audio MSF\n"));
599 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
600 sizeof(CDROM_PLAY_AUDIO_MSF
)) {
603 // Indicate unsuccessful status.
606 status
= STATUS_INFO_LENGTH_MISMATCH
;
610 IoMarkIrpPending(Irp
);
611 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
613 return STATUS_PENDING
;
616 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
623 TraceLog((CdromDebugTrace
,
624 "CdRomDeviceControl: Seek audio MSF\n"));
626 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
627 sizeof(CDROM_SEEK_AUDIO_MSF
)) {
630 // Indicate unsuccessful status.
633 status
= STATUS_INFO_LENGTH_MISMATCH
;
637 IoMarkIrpPending(Irp
);
638 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
639 return STATUS_PENDING
;
643 case IOCTL_CDROM_PAUSE_AUDIO
: {
649 TraceLog((CdromDebugTrace
,
650 "CdRomDeviceControl: Pause audio\n"));
652 IoMarkIrpPending(Irp
);
653 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
655 return STATUS_PENDING
;
660 case IOCTL_CDROM_RESUME_AUDIO
: {
666 TraceLog((CdromDebugTrace
,
667 "CdRomDeviceControl: Resume audio\n"));
669 IoMarkIrpPending(Irp
);
670 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
672 return STATUS_PENDING
;
675 case IOCTL_CDROM_READ_Q_CHANNEL
: {
677 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
678 Irp
->AssociatedIrp
.SystemBuffer
;
680 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
681 sizeof(CDROM_SUB_Q_DATA_FORMAT
)) {
683 status
= STATUS_INFO_LENGTH_MISMATCH
;
688 // check for all valid types of request
691 if (inputBuffer
->Format
!= IOCTL_CDROM_CURRENT_POSITION
&&
692 inputBuffer
->Format
!= IOCTL_CDROM_MEDIA_CATALOG
&&
693 inputBuffer
->Format
!= IOCTL_CDROM_TRACK_ISRC
) {
694 status
= STATUS_INVALID_PARAMETER
;
695 Irp
->IoStatus
.Information
= 0;
699 IoMarkIrpPending(Irp
);
700 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
702 return STATUS_PENDING
;
705 case IOCTL_CDROM_GET_CONTROL
: {
707 TraceLog((CdromDebugTrace
,
708 "CdRomDeviceControl: Get audio control\n"));
711 // Verify user buffer is large enough for the data.
714 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
715 sizeof(CDROM_AUDIO_CONTROL
)) {
718 // Indicate unsuccessful status and no data transferred.
721 status
= STATUS_BUFFER_TOO_SMALL
;
722 Irp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
727 IoMarkIrpPending(Irp
);
728 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
730 return STATUS_PENDING
;
733 case IOCTL_CDROM_GET_VOLUME
: {
735 TraceLog((CdromDebugTrace
,
736 "CdRomDeviceControl: Get volume control\n"));
739 // Verify user buffer is large enough for data.
742 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
743 sizeof(VOLUME_CONTROL
)) {
746 // Indicate unsuccessful status and no data transferred.
749 status
= STATUS_BUFFER_TOO_SMALL
;
750 Irp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
755 IoMarkIrpPending(Irp
);
756 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
758 return STATUS_PENDING
;
761 case IOCTL_CDROM_SET_VOLUME
: {
763 TraceLog((CdromDebugTrace
,
764 "CdRomDeviceControl: Set volume control\n"));
766 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
767 sizeof(VOLUME_CONTROL
)) {
770 // Indicate unsuccessful status.
773 status
= STATUS_INFO_LENGTH_MISMATCH
;
778 IoMarkIrpPending(Irp
);
779 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
781 return STATUS_PENDING
;
784 case IOCTL_CDROM_STOP_AUDIO
: {
790 TraceLog((CdromDebugTrace
,
791 "CdRomDeviceControl: Stop audio\n"));
793 IoMarkIrpPending(Irp
);
794 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
796 return STATUS_PENDING
;
799 case IOCTL_STORAGE_CHECK_VERIFY
:
800 case IOCTL_DISK_CHECK_VERIFY
:
801 case IOCTL_CDROM_CHECK_VERIFY
: {
803 TraceLog((CdromDebugTrace
,
804 "CdRomDeviceControl: [%p] Check Verify\n", Irp
));
806 if((irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
) &&
807 (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))) {
809 TraceLog((CdromDebugWarning
,
810 "CdRomDeviceControl: Check Verify: media count "
811 "buffer too small\n"));
813 status
= STATUS_BUFFER_TOO_SMALL
;
814 Irp
->IoStatus
.Information
= sizeof(ULONG
);
818 IoMarkIrpPending(Irp
);
819 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
821 return STATUS_PENDING
;
824 case IOCTL_DVD_READ_STRUCTURE
: {
826 TraceLog((CdromDebugTrace
,
827 "DvdDeviceControl: [%p] IOCTL_DVD_READ_STRUCTURE\n", Irp
));
829 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
830 TraceLog((CdromDebugWarning
,
831 "DvdDeviceControl: License Failure\n"));
832 status
= STATUS_COPY_PROTECTION_FAILURE
;
836 if (cdData
->DvdRpc0Device
&& cdData
->Rpc0RetryRegistryCallback
) {
838 // if currently in-progress, this will just return.
839 // prevents looping by doing that interlockedExchange()
841 TraceLog((CdromDebugWarning
,
842 "DvdDeviceControl: PickRegion() from "
843 "READ_STRUCTURE\n"));
844 CdRomPickDvdRegion(DeviceObject
);
848 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
849 sizeof(DVD_READ_STRUCTURE
)) {
851 TraceLog((CdromDebugWarning
,
852 "DvdDeviceControl - READ_STRUCTURE: input buffer "
853 "length too small (was %d should be %d)\n",
854 irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
,
855 sizeof(DVD_READ_STRUCTURE
)));
856 status
= STATUS_INVALID_PARAMETER
;
860 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
861 sizeof(READ_DVD_STRUCTURES_HEADER
)) {
863 TraceLog((CdromDebugWarning
,
864 "DvdDeviceControl - READ_STRUCTURE: output buffer "
865 "cannot hold header information\n"));
866 status
= STATUS_BUFFER_TOO_SMALL
;
867 Irp
->IoStatus
.Information
= sizeof(READ_DVD_STRUCTURES_HEADER
);
871 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
>
875 // key length must fit in two bytes
877 TraceLog((CdromDebugWarning
,
878 "DvdDeviceControl - READ_STRUCTURE: output buffer "
880 status
= STATUS_INVALID_PARAMETER
;
884 IoMarkIrpPending(Irp
);
885 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
887 return STATUS_PENDING
;
890 case IOCTL_DVD_START_SESSION
: {
892 TraceLog((CdromDebugTrace
,
893 "DvdDeviceControl: [%p] IOCTL_DVD_START_SESSION\n", Irp
));
895 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
896 TraceLog((CdromDebugWarning
,
897 "DvdDeviceControl: License Failure\n"));
898 status
= STATUS_COPY_PROTECTION_FAILURE
;
902 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
903 sizeof(DVD_SESSION_ID
)) {
905 TraceLog((CdromDebugWarning
,
906 "DvdDeviceControl: DVD_START_SESSION - output "
907 "buffer too small\n"));
908 status
= STATUS_BUFFER_TOO_SMALL
;
909 Irp
->IoStatus
.Information
= sizeof(DVD_SESSION_ID
);
913 IoMarkIrpPending(Irp
);
914 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
916 return STATUS_PENDING
;
919 case IOCTL_DVD_SEND_KEY
:
920 case IOCTL_DVD_SEND_KEY2
: {
922 PDVD_COPY_PROTECT_KEY key
= Irp
->AssociatedIrp
.SystemBuffer
;
925 TraceLog((CdromDebugTrace
,
926 "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY\n", Irp
));
928 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
929 TraceLog((CdromDebugWarning
,
930 "DvdDeviceControl: License Failure\n"));
931 status
= STATUS_COPY_PROTECTION_FAILURE
;
935 if((irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
936 sizeof(DVD_COPY_PROTECT_KEY
)) ||
937 (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!=
941 // Key is too small to have a header or the key length doesn't
942 // match the input buffer length. Key must be invalid
945 TraceLog((CdromDebugWarning
,
946 "DvdDeviceControl: [%p] IOCTL_DVD_SEND_KEY - "
947 "key is too small or does not match KeyLength\n",
949 status
= STATUS_INVALID_PARAMETER
;
954 // allow only certain key type (non-destructive) to go through
955 // IOCTL_DVD_SEND_KEY (which only requires READ access to the device
957 if (ioctlCode
== IOCTL_DVD_SEND_KEY
) {
959 if ((key
->KeyType
!= DvdChallengeKey
) &&
960 (key
->KeyType
!= DvdBusKey2
) &&
961 (key
->KeyType
!= DvdInvalidateAGID
)) {
963 status
= STATUS_INVALID_PARAMETER
;
968 if (cdData
->DvdRpc0Device
) {
970 if (key
->KeyType
== DvdSetRpcKey
) {
972 PDVD_SET_RPC_KEY rpcKey
= (PDVD_SET_RPC_KEY
) key
->KeyData
;
974 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
975 DVD_SET_RPC_KEY_LENGTH
) {
977 status
= STATUS_INVALID_PARAMETER
;
982 // we have a request to set region code
983 // on a RPC0 device which doesn't support
986 // we have to fake it.
989 KeWaitForMutexObject(
990 &cdData
->Rpc0RegionMutex
,
997 if (cdData
->DvdRpc0Device
&& cdData
->Rpc0RetryRegistryCallback
) {
999 // if currently in-progress, this will just return.
1000 // prevents looping by doing that interlockedExchange()
1002 TraceLog((CdromDebugWarning
,
1003 "DvdDeviceControl: PickRegion() from "
1005 CdRomPickDvdRegion(DeviceObject
);
1008 if (cdData
->Rpc0SystemRegion
== rpcKey
->PreferredDriveRegionCode
) {
1011 // nothing to change
1013 TraceLog((CdromDebugWarning
,
1014 "DvdDeviceControl (%p) => not changing "
1015 "regions -- requesting current region\n",
1017 status
= STATUS_SUCCESS
;
1019 } else if (cdData
->Rpc0SystemRegionResetCount
== 0) {
1022 // not allowed to change it again
1025 TraceLog((CdromDebugWarning
,
1026 "DvdDeviceControl (%p) => no more region "
1027 "changes are allowed for this device\n",
1029 status
= STATUS_CSS_RESETS_EXHAUSTED
;
1036 PDVD_READ_STRUCTURE dvdReadStructure
;
1037 PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight
;
1038 IO_STATUS_BLOCK ioStatus
;
1039 UCHAR mediaRegionData
;
1041 mask
= ~rpcKey
->PreferredDriveRegionCode
;
1043 if (CountOfSetBitsUChar(mask
) != 1) {
1045 status
= STATUS_INVALID_DEVICE_REQUEST
;
1050 // this test will always be TRUE except during initial
1051 // automatic selection of the first region.
1054 if (cdData
->Rpc0SystemRegion
!= 0xff) {
1057 // make sure we have a media in the drive with the same
1058 // region code if the drive is already has a region set
1061 TraceLog((CdromDebugTrace
,
1062 "DvdDeviceControl (%p) => Checking "
1066 bufferLen
= max(sizeof(DVD_DESCRIPTOR_HEADER
) +
1067 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
1068 sizeof(DVD_READ_STRUCTURE
)
1071 dvdReadStructure
= (PDVD_READ_STRUCTURE
)
1072 ExAllocatePoolWithTag(PagedPool
,
1074 DVD_TAG_RPC2_CHECK
);
1076 if (dvdReadStructure
== NULL
) {
1077 status
= STATUS_INSUFFICIENT_RESOURCES
;
1078 KeReleaseMutex(&cdData
->Rpc0RegionMutex
,FALSE
);
1082 dvdCopyRight
= (PDVD_COPYRIGHT_DESCRIPTOR
)
1083 ((PDVD_DESCRIPTOR_HEADER
) dvdReadStructure
)->Data
;
1086 // check to see if we have a DVD device
1089 RtlZeroMemory (dvdReadStructure
, bufferLen
);
1090 dvdReadStructure
->Format
= DvdCopyrightDescriptor
;
1093 // Build a request for READ_KEY
1095 ClassSendDeviceIoControlSynchronous(
1096 IOCTL_DVD_READ_STRUCTURE
,
1099 sizeof(DVD_READ_STRUCTURE
),
1100 sizeof(DVD_DESCRIPTOR_HEADER
) +
1101 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
1106 // this is just to prevent bugs from creeping in
1107 // if status is not set later in development
1110 status
= ioStatus
.Status
;
1116 if (!NT_SUCCESS(status
)) {
1117 KeReleaseMutex(&cdData
->Rpc0RegionMutex
,FALSE
);
1118 ExFreePool(dvdReadStructure
);
1119 status
= STATUS_INVALID_DEVICE_REQUEST
;
1124 // save the mediaRegionData before freeing the
1129 dvdCopyRight
->RegionManagementInformation
;
1130 ExFreePool(dvdReadStructure
);
1132 TraceLog((CdromDebugWarning
,
1133 "DvdDeviceControl (%p) => new mask is %x"
1134 " MediaRegionData is %x\n", DeviceObject
,
1135 rpcKey
->PreferredDriveRegionCode
,
1139 // the media region must match the requested region
1140 // for RPC0 drives for initial region selection
1143 if (((UCHAR
)~(mediaRegionData
| rpcKey
->PreferredDriveRegionCode
)) == 0) {
1144 KeReleaseMutex(&cdData
->Rpc0RegionMutex
,FALSE
);
1145 status
= STATUS_CSS_REGION_MISMATCH
;
1152 // now try to set the region
1155 TraceLog((CdromDebugTrace
,
1156 "DvdDeviceControl (%p) => Soft-Setting "
1157 "region of RPC1 device to %x\n",
1159 rpcKey
->PreferredDriveRegionCode
1162 status
= CdRomSetRpc0Settings(DeviceObject
,
1163 rpcKey
->PreferredDriveRegionCode
);
1165 if (!NT_SUCCESS(status
)) {
1166 TraceLog((CdromDebugWarning
,
1167 "DvdDeviceControl (%p) => Could not "
1168 "set region code (%x)\n",
1169 DeviceObject
, status
1173 TraceLog((CdromDebugTrace
,
1174 "DvdDeviceControl (%p) => New region set "
1175 " for RPC1 drive\n", DeviceObject
));
1178 // if it worked, our extension is already updated.
1179 // release the mutex
1182 DebugPrint ((4, "DvdDeviceControl (%p) => DVD current "
1183 "region bitmap 0x%x\n", DeviceObject
,
1184 cdData
->Rpc0SystemRegion
));
1185 DebugPrint ((4, "DvdDeviceControl (%p) => DVD region "
1186 " reset Count 0x%x\n", DeviceObject
,
1187 cdData
->Rpc0SystemRegionResetCount
));
1192 KeReleaseMutex(&cdData
->Rpc0RegionMutex
,FALSE
);
1194 } // end of key->KeyType == DvdSetRpcKey
1195 } // end of Rpc0Device hacks
1197 IoMarkIrpPending(Irp
);
1198 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1199 return STATUS_PENDING
;
1202 case IOCTL_DVD_READ_KEY
: {
1204 PDVD_COPY_PROTECT_KEY keyParameters
= Irp
->AssociatedIrp
.SystemBuffer
;
1207 TraceLog((CdromDebugTrace
,
1208 "DvdDeviceControl: [%p] IOCTL_DVD_READ_KEY\n", Irp
));
1210 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
1211 TraceLog((CdromDebugWarning
,
1212 "DvdDeviceControl: License Failure\n"));
1213 status
= STATUS_COPY_PROTECTION_FAILURE
;
1217 if (cdData
->DvdRpc0Device
&& cdData
->Rpc0RetryRegistryCallback
) {
1218 TraceLog((CdromDebugWarning
,
1219 "DvdDeviceControl: PickRegion() from READ_KEY\n"));
1220 CdRomPickDvdRegion(DeviceObject
);
1224 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1225 sizeof(DVD_COPY_PROTECT_KEY
)) {
1227 TraceLog((CdromDebugWarning
,
1228 "DvdDeviceControl: EstablishDriveKey - challenge "
1229 "key buffer too small\n"));
1231 status
= STATUS_INVALID_PARAMETER
;
1237 switch(keyParameters
->KeyType
) {
1239 case DvdChallengeKey
:
1240 keyLength
= DVD_CHALLENGE_KEY_LENGTH
;
1246 keyLength
= DVD_BUS_KEY_LENGTH
;
1250 keyLength
= DVD_TITLE_KEY_LENGTH
;
1254 keyLength
= DVD_ASF_LENGTH
;
1258 keyLength
= DVD_DISK_KEY_LENGTH
;
1262 keyLength
= DVD_RPC_KEY_LENGTH
;
1266 keyLength
= sizeof(DVD_COPY_PROTECT_KEY
);
1270 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1273 TraceLog((CdromDebugWarning
,
1274 "DvdDeviceControl: EstablishDriveKey - output "
1275 "buffer too small\n"));
1276 status
= STATUS_BUFFER_TOO_SMALL
;
1277 Irp
->IoStatus
.Information
= keyLength
;
1281 if (keyParameters
->KeyType
== DvdGetRpcKey
) {
1283 CdRomPickDvdRegion(DeviceObject
);
1286 if ((keyParameters
->KeyType
== DvdGetRpcKey
) &&
1287 (cdData
->DvdRpc0Device
)) {
1289 PDVD_RPC_KEY rpcKey
;
1290 rpcKey
= (PDVD_RPC_KEY
)keyParameters
->KeyData
;
1291 RtlZeroMemory (rpcKey
, sizeof (*rpcKey
));
1293 KeWaitForMutexObject(
1294 &cdData
->Rpc0RegionMutex
,
1304 rpcKey
->UserResetsAvailable
= cdData
->Rpc0SystemRegionResetCount
;
1305 rpcKey
->ManufacturerResetsAvailable
= 0;
1306 if (cdData
->Rpc0SystemRegion
== 0xff) {
1307 rpcKey
->TypeCode
= 0;
1309 rpcKey
->TypeCode
= 1;
1311 rpcKey
->RegionMask
= (UCHAR
) cdData
->Rpc0SystemRegion
;
1312 rpcKey
->RpcScheme
= 1;
1315 &cdData
->Rpc0RegionMutex
,
1319 Irp
->IoStatus
.Information
= DVD_RPC_KEY_LENGTH
;
1320 status
= STATUS_SUCCESS
;
1323 } else if (keyParameters
->KeyType
== DvdDiskKey
) {
1325 PDVD_COPY_PROTECT_KEY keyHeader
;
1326 PDVD_READ_STRUCTURE readStructureRequest
;
1329 // Special case - build a request to get the dvd structure
1330 // so we can get the disk key.
1334 // save the key header so we can restore the interesting
1338 keyHeader
= ExAllocatePoolWithTag(NonPagedPool
,
1339 sizeof(DVD_COPY_PROTECT_KEY
),
1342 if(keyHeader
== NULL
) {
1345 // Can't save the context so return an error
1348 TraceLog((CdromDebugWarning
,
1349 "DvdDeviceControl - READ_KEY: unable to "
1350 "allocate context\n"));
1351 status
= STATUS_INSUFFICIENT_RESOURCES
;
1355 RtlCopyMemory(keyHeader
,
1356 Irp
->AssociatedIrp
.SystemBuffer
,
1357 sizeof(DVD_COPY_PROTECT_KEY
));
1359 IoCopyCurrentIrpStackLocationToNext(Irp
);
1361 nextStack
= IoGetNextIrpStackLocation(Irp
);
1363 nextStack
->Parameters
.DeviceIoControl
.IoControlCode
=
1364 IOCTL_DVD_READ_STRUCTURE
;
1366 readStructureRequest
= Irp
->AssociatedIrp
.SystemBuffer
;
1367 readStructureRequest
->Format
= DvdDiskKeyDescriptor
;
1368 readStructureRequest
->BlockByteOffset
.QuadPart
= 0;
1369 readStructureRequest
->LayerNumber
= 0;
1370 readStructureRequest
->SessionId
= keyHeader
->SessionId
;
1372 nextStack
->Parameters
.DeviceIoControl
.InputBufferLength
=
1373 sizeof(DVD_READ_STRUCTURE
);
1375 nextStack
->Parameters
.DeviceIoControl
.OutputBufferLength
=
1376 sizeof(READ_DVD_STRUCTURES_HEADER
) + sizeof(DVD_DISK_KEY_DESCRIPTOR
);
1378 IoSetCompletionRoutine(Irp
,
1379 CdRomDvdReadDiskKeyCompletion
,
1386 UCHAR uniqueAddress
;
1387 ClassAcquireRemoveLock(DeviceObject
, (PIRP
)&uniqueAddress
);
1388 ClassReleaseRemoveLock(DeviceObject
, Irp
);
1390 IoMarkIrpPending(Irp
);
1391 IoCallDriver(commonExtension
->DeviceObject
, Irp
);
1392 status
= STATUS_PENDING
;
1394 ClassReleaseRemoveLock(DeviceObject
, (PIRP
)&uniqueAddress
);
1397 return STATUS_PENDING
;
1401 IoMarkIrpPending(Irp
);
1402 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1405 return STATUS_PENDING
;
1408 case IOCTL_DVD_END_SESSION
: {
1410 PDVD_SESSION_ID sessionId
= Irp
->AssociatedIrp
.SystemBuffer
;
1412 TraceLog((CdromDebugTrace
,
1413 "DvdDeviceControl: [%p] END_SESSION\n", Irp
));
1415 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
1416 TraceLog((CdromDebugWarning
,
1417 "DvdDeviceControl: License Failure\n"));
1418 status
= STATUS_COPY_PROTECTION_FAILURE
;
1422 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1423 sizeof(DVD_SESSION_ID
)) {
1425 TraceLog((CdromDebugWarning
,
1426 "DvdDeviceControl: EndSession - input buffer too "
1428 status
= STATUS_INVALID_PARAMETER
;
1432 IoMarkIrpPending(Irp
);
1434 if(*sessionId
== DVD_END_ALL_SESSIONS
) {
1436 status
= CdRomDvdEndAllSessionsCompletion(DeviceObject
, Irp
, NULL
);
1438 if(status
== STATUS_SUCCESS
) {
1441 // Just complete the request - it was never issued to the
1449 return STATUS_PENDING
;
1454 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1456 return STATUS_PENDING
;
1459 case IOCTL_DVD_GET_REGION
: {
1461 PDVD_COPY_PROTECT_KEY copyProtectKey
;
1463 IO_STATUS_BLOCK ioStatus
;
1464 PDVD_DESCRIPTOR_HEADER dvdHeader
;
1465 PDVD_COPYRIGHT_DESCRIPTOR copyRightDescriptor
;
1466 PDVD_REGION dvdRegion
;
1467 PDVD_READ_STRUCTURE readStructure
;
1468 PDVD_RPC_KEY rpcKey
;
1470 TraceLog((CdromDebugTrace
,
1471 "DvdDeviceControl: [%p] IOCTL_DVD_GET_REGION\n", Irp
));
1473 if (cdData
->DvdRpc0Device
&& cdData
->DvdRpc0LicenseFailure
) {
1474 TraceLog((CdromDebugWarning
,
1475 "DvdDeviceControl: License Failure\n"));
1476 status
= STATUS_COPY_PROTECTION_FAILURE
;
1480 if(irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1481 sizeof(DVD_REGION
)) {
1483 TraceLog((CdromDebugWarning
,
1484 "DvdDeviceControl: output buffer DVD_REGION too small\n"));
1485 status
= STATUS_INVALID_PARAMETER
;
1490 // figure out how much data buffer we need
1493 keyLength
= max(sizeof(DVD_DESCRIPTOR_HEADER
) +
1494 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
1495 sizeof(DVD_READ_STRUCTURE
)
1497 keyLength
= max(keyLength
,
1502 // round the size to nearest ULONGLONG -- why?
1505 keyLength
+= sizeof(ULONGLONG
) - (keyLength
& (sizeof(ULONGLONG
) - 1));
1507 readStructure
= ExAllocatePoolWithTag(NonPagedPool
,
1510 if (readStructure
== NULL
) {
1511 status
= STATUS_INSUFFICIENT_RESOURCES
;
1515 RtlZeroMemory (readStructure
, keyLength
);
1516 readStructure
->Format
= DvdCopyrightDescriptor
;
1519 // Build a request for READ_STRUCTURE
1522 ClassSendDeviceIoControlSynchronous(
1523 IOCTL_DVD_READ_STRUCTURE
,
1527 sizeof(DVD_DESCRIPTOR_HEADER
) +
1528 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
1532 status
= ioStatus
.Status
;
1534 if (!NT_SUCCESS(status
)) {
1535 TraceLog((CdromDebugWarning
,
1536 "CdRomDvdGetRegion => read structure failed %x\n",
1538 ExFreePool(readStructure
);
1543 // we got the copyright descriptor, so now get the region if possible
1546 dvdHeader
= (PDVD_DESCRIPTOR_HEADER
) readStructure
;
1547 copyRightDescriptor
= (PDVD_COPYRIGHT_DESCRIPTOR
) dvdHeader
->Data
;
1550 // the original irp's systembuffer has a copy of the info that
1551 // should be passed down in the request
1554 dvdRegion
= Irp
->AssociatedIrp
.SystemBuffer
;
1556 dvdRegion
->CopySystem
= copyRightDescriptor
->CopyrightProtectionType
;
1557 dvdRegion
->RegionData
= copyRightDescriptor
->RegionManagementInformation
;
1560 // now reuse the buffer to request the copy protection info
1563 copyProtectKey
= (PDVD_COPY_PROTECT_KEY
) readStructure
;
1564 RtlZeroMemory (copyProtectKey
, DVD_RPC_KEY_LENGTH
);
1565 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
1566 copyProtectKey
->KeyType
= DvdGetRpcKey
;
1569 // send a request for READ_KEY
1572 ClassSendDeviceIoControlSynchronous(
1580 status
= ioStatus
.Status
;
1582 if (!NT_SUCCESS(status
)) {
1583 TraceLog((CdromDebugWarning
,
1584 "CdRomDvdGetRegion => read key failed %x\n",
1586 ExFreePool(readStructure
);
1591 // the request succeeded. if a supported scheme is returned,
1592 // then return the information to the caller
1595 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
1597 if (rpcKey
->RpcScheme
== 1) {
1599 if (rpcKey
->TypeCode
) {
1601 dvdRegion
->SystemRegion
= ~rpcKey
->RegionMask
;
1602 dvdRegion
->ResetCount
= rpcKey
->UserResetsAvailable
;
1607 // the drive has not been set for any region
1610 dvdRegion
->SystemRegion
= 0;
1611 dvdRegion
->ResetCount
= rpcKey
->UserResetsAvailable
;
1613 Irp
->IoStatus
.Information
= sizeof(DVD_REGION
);
1617 TraceLog((CdromDebugWarning
,
1618 "CdRomDvdGetRegion => rpcKey->RpcScheme != 1\n"));
1619 status
= STATUS_INVALID_DEVICE_REQUEST
;
1622 ExFreePool(readStructure
);
1627 case IOCTL_STORAGE_SET_READ_AHEAD
: {
1629 if(irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1630 sizeof(STORAGE_SET_READ_AHEAD
)) {
1632 TraceLog((CdromDebugWarning
,
1633 "DvdDeviceControl: SetReadAhead buffer too small\n"));
1634 status
= STATUS_INVALID_PARAMETER
;
1638 IoMarkIrpPending(Irp
);
1639 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1641 return STATUS_PENDING
;
1644 case IOCTL_DISK_IS_WRITABLE
: {
1646 IoMarkIrpPending(Irp
);
1647 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1649 return STATUS_PENDING
;
1653 case IOCTL_DISK_GET_DRIVE_LAYOUT
: {
1658 // we always fake zero or one partitions, and one partition
1659 // structure is included in DRIVE_LAYOUT_INFORMATION
1662 size
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
, PartitionEntry
[1]);
1665 TraceLog((CdromDebugTrace
,
1666 "CdRomDeviceControl: Get drive layout\n"));
1667 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< size
) {
1668 status
= STATUS_BUFFER_TOO_SMALL
;
1669 Irp
->IoStatus
.Information
= size
;
1673 IoMarkIrpPending(Irp
);
1674 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1675 return STATUS_PENDING
;
1679 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
: {
1684 // we always fake zero or one partitions, and one partition
1685 // structure is included in DRIVE_LAYOUT_INFORMATION_EX
1688 size
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
, PartitionEntry
[1]);
1690 TraceLog((CdromDebugTrace
,
1691 "CdRomDeviceControl: Get drive layout ex\n"));
1692 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< size
) {
1693 status
= STATUS_BUFFER_TOO_SMALL
;
1694 Irp
->IoStatus
.Information
= size
;
1698 IoMarkIrpPending(Irp
);
1699 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1700 return STATUS_PENDING
;
1705 case IOCTL_DISK_GET_PARTITION_INFO
: {
1708 // Check that the buffer is large enough.
1711 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1712 sizeof(PARTITION_INFORMATION
)) {
1714 status
= STATUS_BUFFER_TOO_SMALL
;
1715 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
1719 IoMarkIrpPending(Irp
);
1720 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1721 return STATUS_PENDING
;
1724 case IOCTL_DISK_GET_PARTITION_INFO_EX
: {
1726 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1727 sizeof(PARTITION_INFORMATION_EX
)) {
1729 status
= STATUS_BUFFER_TOO_SMALL
;
1730 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
1734 IoMarkIrpPending(Irp
);
1735 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1736 return STATUS_PENDING
;
1739 case IOCTL_DISK_VERIFY
: {
1741 TraceLog((CdromDebugTrace
,
1742 "IOCTL_DISK_VERIFY to device %p through irp %p\n",
1743 DeviceObject
, Irp
));
1746 // Validate buffer length.
1749 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
<
1750 sizeof(VERIFY_INFORMATION
)) {
1752 status
= STATUS_INFO_LENGTH_MISMATCH
;
1755 IoMarkIrpPending(Irp
);
1756 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1757 return STATUS_PENDING
;
1760 case IOCTL_DISK_GET_LENGTH_INFO
: {
1762 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1763 sizeof(GET_LENGTH_INFORMATION
)) {
1764 status
= STATUS_BUFFER_TOO_SMALL
;
1765 Irp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
1768 IoMarkIrpPending(Irp
);
1769 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1770 return STATUS_PENDING
;
1773 case IOCTL_CDROM_GET_CONFIGURATION
: {
1775 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer
;
1777 TraceLog((CdromDebugTrace
,
1778 "IOCTL_CDROM_GET_CONFIGURATION to via irp %p\n", Irp
));
1781 // Validate buffer length.
1784 if (irpStack
->Parameters
.DeviceIoControl
.InputBufferLength
!=
1785 sizeof(GET_CONFIGURATION_IOCTL_INPUT
)) {
1786 status
= STATUS_INFO_LENGTH_MISMATCH
;
1789 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
1790 sizeof(GET_CONFIGURATION_HEADER
)) {
1791 status
= STATUS_BUFFER_TOO_SMALL
;
1792 Irp
->IoStatus
.Information
= sizeof(GET_CONFIGURATION_HEADER
);
1795 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
> 0xffff) {
1796 // output buffer is too large
1797 status
= STATUS_INVALID_BUFFER_SIZE
;
1802 // also verify the arguments are reasonable.
1805 inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
1806 if (inputBuffer
->Feature
> 0xffff) {
1807 status
= STATUS_INVALID_PARAMETER
;
1810 if ((inputBuffer
->RequestType
!= SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE
) &&
1811 (inputBuffer
->RequestType
!= SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT
) &&
1812 (inputBuffer
->RequestType
!= SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL
)) {
1813 status
= STATUS_INVALID_PARAMETER
;
1816 if (inputBuffer
->Reserved
[0] || inputBuffer
->Reserved
[1]) {
1817 status
= STATUS_INVALID_PARAMETER
;
1821 IoMarkIrpPending(Irp
);
1822 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1823 return STATUS_PENDING
;
1829 BOOLEAN synchronize
= (KeGetCurrentIrql() == PASSIVE_LEVEL
);
1830 PKEVENT deviceControlEvent
;
1833 // If the ioctl has come in at passive level then we will synchronize
1834 // with our start-io routine when sending the ioctl. If the ioctl
1835 // has come in at a higher interrupt level and it was not handled
1836 // above then it's unlikely to be a request for the class DLL - however
1837 // we'll still use it's common code to forward the request through.
1842 deviceControlEvent
= ExAllocatePoolWithTag(NonPagedPool
,
1844 CDROM_TAG_DC_EVENT
);
1846 if (deviceControlEvent
== NULL
) {
1849 // must complete this irp unsuccessful here
1851 status
= STATUS_INSUFFICIENT_RESOURCES
;
1856 //PIO_STACK_LOCATION currentStack;
1858 KeInitializeEvent(deviceControlEvent
, NotificationEvent
, FALSE
);
1860 //currentStack = IoGetCurrentIrpStackLocation(Irp);
1861 nextStack
= IoGetNextIrpStackLocation(Irp
);
1864 // Copy the stack down a notch
1867 IoCopyCurrentIrpStackLocationToNext(Irp
);
1869 IoSetCompletionRoutine(
1871 CdRomClassIoctlCompletion
,
1878 IoSetNextIrpStackLocation(Irp
);
1880 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1881 Irp
->IoStatus
.Information
= 0;
1884 // Override volume verifies on this stack location so that we
1885 // will be forced through the synchronization. Once this
1886 // location goes away we get the old value back
1889 SET_FLAG(nextStack
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
);
1891 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
1894 // Wait for CdRomClassIoctlCompletion to set the event. This
1895 // ensures serialization remains intact for these unhandled device
1899 KeWaitForSingleObject(
1906 ExFreePool(deviceControlEvent
);
1908 TraceLog((CdromDebugTrace
,
1909 "CdRomDeviceControl: irp %p synchronized\n", Irp
));
1911 status
= Irp
->IoStatus
.Status
;
1915 status
= STATUS_SUCCESS
;
1919 // If an error occured then propagate that back up - we are no longer
1920 // guaranteed synchronization and the upper layers will have to
1923 // If no error occured, call down to the class driver directly
1924 // then start up the next request.
1927 if (NT_SUCCESS(status
)) {
1929 UCHAR uniqueAddress
;
1932 // The class device control routine will release the remove
1933 // lock for this Irp. We need to make sure we have one
1934 // available so that it's safe to call IoStartNextPacket
1939 ClassAcquireRemoveLock(DeviceObject
, (PIRP
)&uniqueAddress
);
1943 status
= ClassDeviceControl(DeviceObject
, Irp
);
1946 KeRaiseIrql(DISPATCH_LEVEL
, &irql
);
1947 IoStartNextPacket(DeviceObject
, FALSE
);
1949 ClassReleaseRemoveLock(DeviceObject
, (PIRP
)&uniqueAddress
);
1956 // an error occurred (either STATUS_INSUFFICIENT_RESOURCES from
1957 // attempting to synchronize or StartIo() error'd this one
1958 // out), so we need to finish the irp, which is
1959 // done at the end of this routine.
1963 } // end default case
1967 if (status
== STATUS_VERIFY_REQUIRED
) {
1970 // If the status is verified required and this request
1971 // should bypass verify required then retry the request.
1974 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
) {
1976 status
= STATUS_IO_DEVICE_ERROR
;
1982 if (IoIsErrorUserInduced(status
)) {
1984 if (Irp
->Tail
.Overlay
.Thread
) {
1985 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
1991 // Update IRP with completion status.
1994 Irp
->IoStatus
.Status
= status
;
1997 // Complete the request.
2000 ClassReleaseRemoveLock(DeviceObject
, Irp
);
2001 ClassCompleteRequest(DeviceObject
, Irp
, IO_DISK_INCREMENT
);
2002 TraceLog((CdromDebugTrace
,
2003 "CdRomDeviceControl: Status is %lx\n", status
));
2006 } // end CdRomDeviceControl()
2010 CdRomClassIoctlCompletion(
2011 IN PDEVICE_OBJECT DeviceObject
,
2017 Routine Description:
2019 This routine signals the event used by CdRomDeviceControl to synchronize
2020 class driver (and lower level driver) ioctls with cdrom's startio routine.
2021 The irp completion is short-circuited so that CdRomDeviceControlDispatch
2022 can reissue it once it wakes up.
2026 DeviceObject - the device object
2027 Irp - the request we are synchronizing
2028 Context - a PKEVENT that we need to signal
2036 PKEVENT syncEvent
= (PKEVENT
) Context
;
2038 TraceLog((CdromDebugTrace
,
2039 "CdRomClassIoctlCompletion: setting event for irp %p\n", Irp
));
2042 // We released the lock when we completed this request. Reacquire it.
2045 ClassAcquireRemoveLock(DeviceObject
, Irp
);
2047 KeSetEvent(syncEvent
, IO_DISK_INCREMENT
, FALSE
);
2049 return STATUS_MORE_PROCESSING_REQUIRED
;
2054 CdRomDeviceControlCompletion(
2055 IN PDEVICE_OBJECT DeviceObject
,
2060 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
2061 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
2063 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
2064 BOOLEAN use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
2066 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2067 PIO_STACK_LOCATION realIrpStack
;
2068 PIO_STACK_LOCATION realIrpNextStack
;
2070 PSCSI_REQUEST_BLOCK srb
= Context
;
2072 PIRP realIrp
= NULL
;
2079 // Extract the 'real' irp from the irpstack.
2082 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2083 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2084 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2087 // check that we've really got the correct irp
2090 ASSERT(realIrpNextStack
->Parameters
.Others
.Argument3
== Irp
);
2093 // Check SRB status for success of completing request.
2096 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2098 ULONG retryInterval
;
2100 TraceLog((CdromDebugTrace
,
2101 "CdRomDeviceControlCompletion: Irp %p, Srb %p Real Irp %p Status %lx\n",
2108 // Release the queue if it is frozen.
2111 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2112 TraceLog((CdromDebugTrace
,
2113 "CdRomDeviceControlCompletion: Releasing Queue\n"));
2114 ClassReleaseQueue(DeviceObject
);
2118 retry
= ClassInterpretSenseInfo(DeviceObject
,
2120 irpStack
->MajorFunction
,
2121 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2122 MAXIMUM_RETRIES
- ((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2126 TraceLog((CdromDebugTrace
,
2127 "CdRomDeviceControlCompletion: IRP will %sbe retried\n",
2128 (retry
? "" : "not ")));
2131 // Some of the Device Controls need special cases on non-Success status's.
2134 if (realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
2135 if ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_LAST_SESSION
) ||
2136 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC
) ||
2137 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_TOC_EX
) ||
2138 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_CONTROL
) ||
2139 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_GET_VOLUME
)) {
2141 if (status
== STATUS_DATA_OVERRUN
) {
2142 status
= STATUS_SUCCESS
;
2147 if (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_READ_Q_CHANNEL
) {
2148 PLAY_ACTIVE(fdoExtension
) = FALSE
;
2153 // If the status is verified required and the this request
2154 // should bypass verify required then retry the request.
2157 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2158 status
== STATUS_VERIFY_REQUIRED
) {
2160 // note: status gets overwritten here
2161 status
= STATUS_IO_DEVICE_ERROR
;
2164 if (((realIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) ||
2165 (realIrpStack
->MajorFunction
== IRP_MJ_INTERNAL_DEVICE_CONTROL
)
2167 ((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2168 IOCTL_CDROM_CHECK_VERIFY
) ||
2169 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2170 IOCTL_STORAGE_CHECK_VERIFY
) ||
2171 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2172 IOCTL_STORAGE_CHECK_VERIFY2
) ||
2173 (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2174 IOCTL_DISK_CHECK_VERIFY
)
2179 // Update the geometry information, as the media could have
2180 // changed. The completion routine for this will complete
2181 // the real irp and start the next packet.
2185 if (srb
->SenseInfoBuffer
) {
2186 ExFreePool(srb
->SenseInfoBuffer
);
2188 if (srb
->DataBuffer
) {
2189 ExFreePool(srb
->DataBuffer
);
2195 if (Irp
->MdlAddress
) {
2196 IoFreeMdl(Irp
->MdlAddress
);
2197 Irp
->MdlAddress
= NULL
;
2203 status
= CdRomUpdateCapacity(fdoExtension
, realIrp
, NULL
);
2204 TraceLog((CdromDebugTrace
,
2205 "CdRomDeviceControlCompletion: [%p] "
2206 "CdRomUpdateCapacity completed with status %lx\n",
2210 // needed to update the capacity.
2211 // the irp's already handed off to CdRomUpdateCapacity().
2212 // we've already free'd the current irp.
2213 // nothing left to do in this code path.
2216 return STATUS_MORE_PROCESSING_REQUIRED
;
2218 } // end of ioctls to update capacity
2223 // get current retry count
2225 retryCount
= PtrToUlong(realIrpNextStack
->Parameters
.Others
.Argument1
);
2227 if (retry
&& retryCount
) {
2230 // update retry count
2232 realIrpNextStack
->Parameters
.Others
.Argument1
= UlongToPtr(retryCount
-1);
2234 if (((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
2240 TraceLog((CdromDebugWarning
,
2241 "Retry request %p - Calling StartIo\n", Irp
));
2244 ExFreePool(srb
->SenseInfoBuffer
);
2245 if (srb
->DataBuffer
) {
2246 ExFreePool(srb
->DataBuffer
);
2249 if (Irp
->MdlAddress
) {
2250 IoFreeMdl(Irp
->MdlAddress
);
2253 realIrpNextStack
->Parameters
.Others
.Argument3
= (PVOID
)-1;
2256 CdRomRetryRequest(fdoExtension
, realIrp
, retryInterval
, FALSE
);
2257 return STATUS_MORE_PROCESSING_REQUIRED
;
2261 // Exhausted retries. Fall through and complete the request with
2262 // the appropriate status.
2269 // Set status for successful request.
2272 status
= STATUS_SUCCESS
;
2277 if (NT_SUCCESS(status
)) {
2282 switch (realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
2284 case IOCTL_CDROM_GET_CONFIGURATION
: {
2285 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
2287 srb
->DataTransferLength
);
2288 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2292 case IOCTL_DISK_GET_LENGTH_INFO
: {
2294 PGET_LENGTH_INFORMATION lengthInfo
;
2296 CdRomInterpretReadCapacity(DeviceObject
,
2297 (PREAD_CAPACITY_DATA
)srb
->DataBuffer
);
2299 lengthInfo
= (PGET_LENGTH_INFORMATION
)realIrp
->AssociatedIrp
.SystemBuffer
;
2300 lengthInfo
->Length
= commonExtension
->PartitionLength
;
2301 realIrp
->IoStatus
.Information
= sizeof(GET_LENGTH_INFORMATION
);
2302 status
= STATUS_SUCCESS
;
2306 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2307 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
: {
2309 PDISK_GEOMETRY_EX geometryEx
;
2311 CdRomInterpretReadCapacity(DeviceObject
,
2312 (PREAD_CAPACITY_DATA
)srb
->DataBuffer
);
2314 geometryEx
= (PDISK_GEOMETRY_EX
)(realIrp
->AssociatedIrp
.SystemBuffer
);
2315 geometryEx
->DiskSize
= commonExtension
->PartitionLength
;
2316 geometryEx
->Geometry
= fdoExtension
->DiskGeometry
;
2317 realIrp
->IoStatus
.Information
=
2318 FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
);
2322 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2323 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2325 PDISK_GEOMETRY geometry
;
2327 CdRomInterpretReadCapacity(DeviceObject
,
2328 (PREAD_CAPACITY_DATA
)srb
->DataBuffer
);
2330 geometry
= (PDISK_GEOMETRY
)(realIrp
->AssociatedIrp
.SystemBuffer
);
2331 *geometry
= fdoExtension
->DiskGeometry
;
2332 realIrp
->IoStatus
.Information
= sizeof(DISK_GEOMETRY
);
2336 case IOCTL_DISK_VERIFY
: {
2338 // nothing to do but return the status...
2343 case IOCTL_DISK_CHECK_VERIFY
:
2344 case IOCTL_STORAGE_CHECK_VERIFY
:
2345 case IOCTL_CDROM_CHECK_VERIFY
: {
2347 if((realIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_CHECK_VERIFY
) &&
2348 (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)) {
2350 *((PULONG
)realIrp
->AssociatedIrp
.SystemBuffer
) =
2351 commonExtension
->PartitionZeroExtension
->MediaChangeCount
;
2353 realIrp
->IoStatus
.Information
= sizeof(ULONG
);
2355 realIrp
->IoStatus
.Information
= 0;
2358 TraceLog((CdromDebugTrace
,
2359 "CdRomDeviceControlCompletion: [%p] completing "
2360 "CHECK_VERIFY buddy irp %p\n", realIrp
, Irp
));
2364 case IOCTL_CDROM_READ_TOC_EX
: {
2366 if (srb
->DataTransferLength
< MINIMUM_CDROM_READ_TOC_EX_SIZE
) {
2367 status
= STATUS_INVALID_DEVICE_REQUEST
;
2372 // Copy the returned info into the user buffer.
2375 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
2377 srb
->DataTransferLength
);
2380 // update information field.
2383 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2388 case IOCTL_CDROM_GET_LAST_SESSION
:
2389 case IOCTL_CDROM_READ_TOC
: {
2392 // Copy the returned info into the user buffer.
2395 RtlMoveMemory(realIrp
->AssociatedIrp
.SystemBuffer
,
2397 srb
->DataTransferLength
);
2400 // update information field.
2403 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2407 case IOCTL_DVD_READ_STRUCTURE
: {
2409 DVD_STRUCTURE_FORMAT format
= ((PDVD_READ_STRUCTURE
) realIrp
->AssociatedIrp
.SystemBuffer
)->Format
;
2411 PDVD_DESCRIPTOR_HEADER header
= realIrp
->AssociatedIrp
.SystemBuffer
;
2413 //FOUR_BYTE fourByte;
2414 //PTWO_BYTE twoByte;
2417 TraceLog((CdromDebugTrace
,
2418 "DvdDeviceControlCompletion - IOCTL_DVD_READ_STRUCTURE: completing irp %p (buddy %p)\n",
2422 TraceLog((CdromDebugTrace
,
2423 "DvdDCCompletion - READ_STRUCTURE: descriptor format of %d\n", format
));
2425 RtlMoveMemory(header
,
2427 srb
->DataTransferLength
);
2430 // Cook the data. There are a number of fields that really
2431 // should be byte-swapped for the caller.
2434 TraceLog((CdromDebugInfo
,
2435 "DvdDCCompletion - READ_STRUCTURE:\n"
2437 "\tDvdDCCompletion - READ_STRUCTURE: data at %p\n"
2438 "\tDataBuffer was at %p\n"
2439 "\tDataTransferLength was %lx\n",
2443 srb
->DataTransferLength
));
2446 // First the fields in the header
2449 TraceLog((CdromDebugInfo
, "READ_STRUCTURE: header->Length %lx -> ",
2451 REVERSE_SHORT(&header
->Length
);
2452 TraceLog((CdromDebugInfo
, "%lx\n", header
->Length
));
2455 // Now the fields in the descriptor
2458 if(format
== DvdPhysicalDescriptor
) {
2460 PDVD_LAYER_DESCRIPTOR layer
= (PDVD_LAYER_DESCRIPTOR
) &(header
->Data
[0]);
2462 TraceLog((CdromDebugInfo
, "READ_STRUCTURE: StartingDataSector %lx -> ",
2463 layer
->StartingDataSector
));
2464 REVERSE_LONG(&(layer
->StartingDataSector
));
2465 TraceLog((CdromDebugInfo
, "%lx\n", layer
->StartingDataSector
));
2467 TraceLog((CdromDebugInfo
, "READ_STRUCTURE: EndDataSector %lx -> ",
2468 layer
->EndDataSector
));
2469 REVERSE_LONG(&(layer
->EndDataSector
));
2470 TraceLog((CdromDebugInfo
, "%lx\n", layer
->EndDataSector
));
2472 TraceLog((CdromDebugInfo
, "READ_STRUCTURE: EndLayerZeroSector %lx -> ",
2473 layer
->EndLayerZeroSector
));
2474 REVERSE_LONG(&(layer
->EndLayerZeroSector
));
2475 TraceLog((CdromDebugInfo
, "%lx\n", layer
->EndLayerZeroSector
));
2478 TraceLog((CdromDebugTrace
, "Status is %lx\n", Irp
->IoStatus
.Status
));
2479 TraceLog((CdromDebugTrace
, "DvdDeviceControlCompletion - "
2480 "IOCTL_DVD_READ_STRUCTURE: data transfer length of %d\n",
2481 srb
->DataTransferLength
));
2483 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2487 case IOCTL_DVD_READ_KEY
: {
2489 PDVD_COPY_PROTECT_KEY copyProtectKey
= realIrp
->AssociatedIrp
.SystemBuffer
;
2491 PCDVD_KEY_HEADER keyHeader
= srb
->DataBuffer
;
2494 ULONG transferLength
=
2495 srb
->DataTransferLength
-
2496 FIELD_OFFSET(CDVD_KEY_HEADER
, Data
);
2499 // Adjust the data length to ignore the two reserved bytes in the
2503 dataLength
= (keyHeader
->DataLength
[0] << 8) +
2504 keyHeader
->DataLength
[1];
2508 // take the minimum of the transferred length and the
2509 // length as specified in the header.
2512 if(dataLength
< transferLength
) {
2513 transferLength
= dataLength
;
2516 TraceLog((CdromDebugTrace
,
2517 "DvdDeviceControlCompletion: [%p] - READ_KEY with "
2518 "transfer length of (%d or %d) bytes\n",
2521 srb
->DataTransferLength
- 2));
2524 // Copy the key data into the return buffer
2526 if(copyProtectKey
->KeyType
== DvdTitleKey
) {
2528 RtlMoveMemory(copyProtectKey
->KeyData
,
2529 keyHeader
->Data
+ 1,
2530 transferLength
- 1);
2531 copyProtectKey
->KeyData
[transferLength
- 1] = 0;
2534 // If this is a title key then we need to copy the CGMS flags
2537 copyProtectKey
->KeyFlags
= *(keyHeader
->Data
);
2541 RtlMoveMemory(copyProtectKey
->KeyData
,
2546 copyProtectKey
->KeyLength
= sizeof(DVD_COPY_PROTECT_KEY
);
2547 copyProtectKey
->KeyLength
+= transferLength
;
2549 realIrp
->IoStatus
.Information
= copyProtectKey
->KeyLength
;
2553 case IOCTL_DVD_START_SESSION
: {
2555 PDVD_SESSION_ID sessionId
= realIrp
->AssociatedIrp
.SystemBuffer
;
2557 PCDVD_KEY_HEADER keyHeader
= srb
->DataBuffer
;
2558 PCDVD_REPORT_AGID_DATA keyData
= (PCDVD_REPORT_AGID_DATA
) keyHeader
->Data
;
2560 *sessionId
= keyData
->AGID
;
2562 realIrp
->IoStatus
.Information
= sizeof(DVD_SESSION_ID
);
2567 case IOCTL_DVD_END_SESSION
:
2568 case IOCTL_DVD_SEND_KEY
:
2569 case IOCTL_DVD_SEND_KEY2
:
2572 // nothing to return
2574 realIrp
->IoStatus
.Information
= 0;
2577 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
2579 PLAY_ACTIVE(fdoExtension
) = TRUE
;
2583 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2585 PSUB_Q_CHANNEL_DATA userChannelData
= realIrp
->AssociatedIrp
.SystemBuffer
;
2586 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
= realIrp
->AssociatedIrp
.SystemBuffer
;
2587 PSUB_Q_CHANNEL_DATA subQPtr
= srb
->DataBuffer
;
2590 switch( inputBuffer
->Format
) {
2592 case IOCTL_CDROM_CURRENT_POSITION
:
2593 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->CurrentPosition
.Header
.AudioStatus
));
2594 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: ADR = 0x%x\n", subQPtr
->CurrentPosition
.ADR
));
2595 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Control = 0x%x\n", subQPtr
->CurrentPosition
.Control
));
2596 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Track = %u\n", subQPtr
->CurrentPosition
.TrackNumber
));
2597 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Index = %u\n", subQPtr
->CurrentPosition
.IndexNumber
));
2598 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Absolute Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.AbsoluteAddress
) ));
2599 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Relative Address = %x\n", *((PULONG
)subQPtr
->CurrentPosition
.TrackRelativeAddress
) ));
2602 case IOCTL_CDROM_MEDIA_CATALOG
:
2603 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->MediaCatalog
.Header
.AudioStatus
));
2604 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Mcval is %u\n", subQPtr
->MediaCatalog
.Mcval
));
2607 case IOCTL_CDROM_TRACK_ISRC
:
2608 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Audio Status is %u\n", subQPtr
->TrackIsrc
.Header
.AudioStatus
));
2609 TraceLog((CdromDebugTrace
,"CdRomDeviceControlCompletion: Tcval is %u\n", subQPtr
->TrackIsrc
.Tcval
));
2616 // Update the play active status.
2619 if (subQPtr
->CurrentPosition
.Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
2621 PLAY_ACTIVE(fdoExtension
) = TRUE
;
2625 PLAY_ACTIVE(fdoExtension
) = FALSE
;
2630 // Check if output buffer is large enough to contain
2634 if (realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
<
2635 srb
->DataTransferLength
) {
2637 srb
->DataTransferLength
=
2638 realIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
2642 // Copy our buffer into users.
2645 RtlMoveMemory(userChannelData
,
2647 srb
->DataTransferLength
);
2649 realIrp
->IoStatus
.Information
= srb
->DataTransferLength
;
2653 case IOCTL_CDROM_PAUSE_AUDIO
:
2655 PLAY_ACTIVE(fdoExtension
) = FALSE
;
2656 realIrp
->IoStatus
.Information
= 0;
2659 case IOCTL_CDROM_RESUME_AUDIO
:
2661 realIrp
->IoStatus
.Information
= 0;
2664 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
2666 realIrp
->IoStatus
.Information
= 0;
2669 case IOCTL_CDROM_STOP_AUDIO
:
2671 PLAY_ACTIVE(fdoExtension
) = FALSE
;
2672 realIrp
->IoStatus
.Information
= 0;
2675 case IOCTL_CDROM_GET_CONTROL
: {
2677 PCDROM_AUDIO_CONTROL audioControl
= srb
->DataBuffer
;
2678 PAUDIO_OUTPUT audioOutput
;
2679 ULONG bytesTransferred
;
2681 audioOutput
= ClassFindModePage((PCHAR
)audioControl
,
2682 srb
->DataTransferLength
,
2683 CDROM_AUDIO_CONTROL_PAGE
,
2686 // Verify the page is as big as expected.
2689 bytesTransferred
= (ULONG
)((PCHAR
) audioOutput
- (PCHAR
) audioControl
) +
2690 sizeof(AUDIO_OUTPUT
);
2692 if (audioOutput
!= NULL
&&
2693 srb
->DataTransferLength
>= bytesTransferred
) {
2695 audioControl
->LbaFormat
= audioOutput
->LbaFormat
;
2697 audioControl
->LogicalBlocksPerSecond
=
2698 (audioOutput
->LogicalBlocksPerSecond
[0] << (UCHAR
)8) |
2699 audioOutput
->LogicalBlocksPerSecond
[1];
2701 realIrp
->IoStatus
.Information
= sizeof(CDROM_AUDIO_CONTROL
);
2704 realIrp
->IoStatus
.Information
= 0;
2705 status
= STATUS_INVALID_DEVICE_REQUEST
;
2710 case IOCTL_CDROM_GET_VOLUME
: {
2712 PAUDIO_OUTPUT audioOutput
;
2713 PVOLUME_CONTROL volumeControl
= srb
->DataBuffer
;
2715 ULONG bytesTransferred
;
2717 audioOutput
= ClassFindModePage((PCHAR
)volumeControl
,
2718 srb
->DataTransferLength
,
2719 CDROM_AUDIO_CONTROL_PAGE
,
2723 // Verify the page is as big as expected.
2726 bytesTransferred
= (ULONG
)((PCHAR
) audioOutput
- (PCHAR
) volumeControl
) +
2727 sizeof(AUDIO_OUTPUT
);
2729 if (audioOutput
!= NULL
&&
2730 srb
->DataTransferLength
>= bytesTransferred
) {
2732 for (i
=0; i
<4; i
++) {
2733 volumeControl
->PortVolume
[i
] =
2734 audioOutput
->PortOutput
[i
].Volume
;
2738 // Set bytes transferred in IRP.
2741 realIrp
->IoStatus
.Information
= sizeof(VOLUME_CONTROL
);
2744 realIrp
->IoStatus
.Information
= 0;
2745 status
= STATUS_INVALID_DEVICE_REQUEST
;
2751 case IOCTL_CDROM_SET_VOLUME
:
2753 realIrp
->IoStatus
.Information
= 0;
2759 realIrp
->IoStatus
.Information
= 0;
2760 status
= STATUS_INVALID_DEVICE_REQUEST
;
2766 // Deallocate srb and sense buffer.
2770 if (srb
->DataBuffer
) {
2771 ExFreePool(srb
->DataBuffer
);
2773 if (srb
->SenseInfoBuffer
) {
2774 ExFreePool(srb
->SenseInfoBuffer
);
2779 if (realIrp
->PendingReturned
) {
2780 IoMarkIrpPending(realIrp
);
2783 if (Irp
->MdlAddress
) {
2784 IoFreeMdl(Irp
->MdlAddress
);
2790 // Set status in completing IRP.
2793 realIrp
->IoStatus
.Status
= status
;
2796 // Set the hard error if necessary.
2799 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
2802 // Store DeviceObject for filesystem, and clear
2803 // in IoStatus.Information field.
2806 TraceLog((CdromDebugWarning
,
2807 "CdRomDeviceCompletion - Setting Hard Error on realIrp %p\n",
2809 if (realIrp
->Tail
.Overlay
.Thread
) {
2810 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
2813 realIrp
->IoStatus
.Information
= 0;
2817 // note: must complete the realIrp, as the completed irp (above)
2818 // was self-allocated.
2821 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
2822 return STATUS_MORE_PROCESSING_REQUIRED
;
2827 CdRomSetVolumeIntermediateCompletion(
2828 IN PDEVICE_OBJECT DeviceObject
,
2833 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
2834 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
2836 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
2837 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
2838 BOOLEAN use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
2839 PIO_STACK_LOCATION realIrpStack
;
2840 PIO_STACK_LOCATION realIrpNextStack
;
2841 PSCSI_REQUEST_BLOCK srb
= Context
;
2842 PIRP realIrp
= NULL
;
2848 // Extract the 'real' irp from the irpstack.
2851 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
2852 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
2853 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
2856 // Check SRB status for success of completing request.
2859 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
2861 ULONG retryInterval
;
2863 TraceLog((CdromDebugTrace
,
2864 "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
2870 // Release the queue if it is frozen.
2873 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
2874 ClassReleaseQueue(DeviceObject
);
2878 retry
= ClassInterpretSenseInfo(DeviceObject
,
2880 irpStack
->MajorFunction
,
2881 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
2882 MAXIMUM_RETRIES
- ((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
2886 if (status
== STATUS_DATA_OVERRUN
) {
2887 status
= STATUS_SUCCESS
;
2892 // If the status is verified required and the this request
2893 // should bypass verify required then retry the request.
2896 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
2897 status
== STATUS_VERIFY_REQUIRED
) {
2899 status
= STATUS_IO_DEVICE_ERROR
;
2904 // get current retry count
2906 retryCount
= PtrToUlong(realIrpNextStack
->Parameters
.Others
.Argument1
);
2908 if (retry
&& retryCount
) {
2911 // update retry count
2913 realIrpNextStack
->Parameters
.Others
.Argument1
= UlongToPtr(retryCount
-1);
2916 if (((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
2922 TraceLog((CdromDebugWarning
,
2923 "Retry request %p - Calling StartIo\n", Irp
));
2926 ExFreePool(srb
->SenseInfoBuffer
);
2927 ExFreePool(srb
->DataBuffer
);
2929 if (Irp
->MdlAddress
) {
2930 IoFreeMdl(Irp
->MdlAddress
);
2935 CdRomRetryRequest(deviceExtension
,
2940 return STATUS_MORE_PROCESSING_REQUIRED
;
2945 // Exhausted retries. Fall through and complete the request with the appropriate status.
2952 // Set status for successful request.
2955 status
= STATUS_SUCCESS
;
2959 if (NT_SUCCESS(status
)) {
2961 PAUDIO_OUTPUT audioInput
= NULL
;
2962 PAUDIO_OUTPUT audioOutput
;
2963 PVOLUME_CONTROL volumeControl
= realIrp
->AssociatedIrp
.SystemBuffer
;
2964 ULONG i
,bytesTransferred
,headerLength
;
2968 audioInput
= ClassFindModePage((PCHAR
)srb
->DataBuffer
,
2969 srb
->DataTransferLength
,
2970 CDROM_AUDIO_CONTROL_PAGE
,
2974 // Check to make sure the mode sense data is valid before we go on
2977 if(audioInput
== NULL
) {
2979 TraceLog((CdromDebugWarning
,
2980 "Mode Sense Page %d not found\n",
2981 CDROM_AUDIO_CONTROL_PAGE
));
2983 realIrp
->IoStatus
.Information
= 0;
2984 realIrp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
2989 headerLength
= sizeof(MODE_PARAMETER_HEADER
);
2991 headerLength
= sizeof(MODE_PARAMETER_HEADER10
);
2994 bytesTransferred
= sizeof(AUDIO_OUTPUT
) + headerLength
;
2997 // Allocate a new buffer for the mode select.
3000 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3002 CDROM_TAG_VOLUME_INT
);
3005 realIrp
->IoStatus
.Information
= 0;
3006 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3010 RtlZeroMemory(dataBuffer
, bytesTransferred
);
3013 // Rebuild the data buffer to include the user requested values.
3016 audioOutput
= (PAUDIO_OUTPUT
) ((PCHAR
) dataBuffer
+ headerLength
);
3018 for (i
=0; i
<4; i
++) {
3019 audioOutput
->PortOutput
[i
].Volume
=
3020 volumeControl
->PortVolume
[i
];
3021 audioOutput
->PortOutput
[i
].ChannelSelection
=
3022 audioInput
->PortOutput
[i
].ChannelSelection
;
3025 audioOutput
->CodePage
= CDROM_AUDIO_CONTROL_PAGE
;
3026 audioOutput
->ParameterLength
= sizeof(AUDIO_OUTPUT
) - 2;
3027 audioOutput
->Immediate
= MODE_SELECT_IMMEDIATE
;
3030 // Free the old data buffer, mdl.
3033 IoFreeMdl(Irp
->MdlAddress
);
3034 Irp
->MdlAddress
= NULL
;
3035 ExFreePool(srb
->DataBuffer
);
3038 // set the data buffer to new allocation, so it can be
3039 // freed in the exit path
3042 srb
->DataBuffer
= dataBuffer
;
3048 cdb
= (PCDB
)srb
->Cdb
;
3049 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3051 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3052 srb
->SrbFlags
= deviceExtension
->SrbFlags
;
3053 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3054 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
3055 srb
->DataTransferLength
= bytesTransferred
;
3059 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
3060 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
) bytesTransferred
;
3061 cdb
->MODE_SELECT
.PFBit
= 1;
3065 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
3066 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
) (bytesTransferred
>> 8);
3067 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
) (bytesTransferred
& 0xFF);
3068 cdb
->MODE_SELECT10
.PFBit
= 1;
3069 srb
->CdbLength
= 10;
3076 Irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3082 if (!Irp
->MdlAddress
) {
3083 realIrp
->IoStatus
.Information
= 0;
3084 realIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3088 MmBuildMdlForNonPagedPool(Irp
->MdlAddress
);
3090 irpStack
= IoGetNextIrpStackLocation(Irp
);
3091 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
3092 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
3093 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3096 // reset the irp completion.
3099 IoSetCompletionRoutine(Irp
,
3100 CdRomDeviceControlCompletion
,
3106 // Call the port driver.
3109 IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
3111 return STATUS_MORE_PROCESSING_REQUIRED
;
3117 // Deallocate srb and sense buffer.
3121 if (srb
->DataBuffer
) {
3122 ExFreePool(srb
->DataBuffer
);
3124 if (srb
->SenseInfoBuffer
) {
3125 ExFreePool(srb
->SenseInfoBuffer
);
3130 if (Irp
->PendingReturned
) {
3131 IoMarkIrpPending(Irp
);
3134 if (realIrp
->PendingReturned
) {
3135 IoMarkIrpPending(realIrp
);
3138 if (Irp
->MdlAddress
) {
3139 IoFreeMdl(Irp
->MdlAddress
);
3145 // Set status in completing IRP.
3148 realIrp
->IoStatus
.Status
= status
;
3151 // Set the hard error if necessary.
3154 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3157 // Store DeviceObject for filesystem, and clear
3158 // in IoStatus.Information field.
3161 if (realIrp
->Tail
.Overlay
.Thread
) {
3162 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3164 realIrp
->IoStatus
.Information
= 0;
3167 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
3168 return STATUS_MORE_PROCESSING_REQUIRED
;
3173 CdRomDvdEndAllSessionsCompletion(
3174 IN PDEVICE_OBJECT DeviceObject
,
3181 Routine Description:
3183 This routine will setup the next stack location to issue an end session
3184 to the device. It will increment the session id in the system buffer
3185 and issue an END_SESSION for that AGID if the AGID is valid.
3187 When the new AGID is > 3 this routine will complete the request.
3191 DeviceObject - the device object for this drive
3199 STATUS_MORE_PROCESSING_REQUIRED if there is another AGID to clear
3205 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
3207 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
3209 PDVD_SESSION_ID sessionId
= Irp
->AssociatedIrp
.SystemBuffer
;
3213 if(++(*sessionId
) > MAX_COPY_PROTECT_AGID
) {
3216 // We're done here - just return success and let the io system
3217 // continue to complete it.
3220 return STATUS_SUCCESS
;
3224 IoCopyCurrentIrpStackLocationToNext(Irp
);
3226 IoSetCompletionRoutine(Irp
,
3227 CdRomDvdEndAllSessionsCompletion
,
3233 IoMarkIrpPending(Irp
);
3235 IoCallDriver(fdoExtension
->CommonExtension
.DeviceObject
, Irp
);
3238 // At this point we have to assume the irp may have already been
3239 // completed. Ignore the returned status and return.
3242 return STATUS_MORE_PROCESSING_REQUIRED
;
3247 CdRomDvdReadDiskKeyCompletion(
3248 IN PDEVICE_OBJECT DeviceObject
,
3255 Routine Description:
3257 This routine handles the completion of a request to obtain the disk
3258 key from the dvd media. It will transform the raw 2K of key data into
3259 a DVD_COPY_PROTECT_KEY structure and copy back the saved key parameters
3260 from the context pointer before returning.
3268 Context - a DVD_COPY_PROTECT_KEY pointer which contains the key
3269 parameters handed down by the caller.
3278 PDVD_COPY_PROTECT_KEY savedKey
= Context
;
3280 PREAD_DVD_STRUCTURES_HEADER rawKey
= Irp
->AssociatedIrp
.SystemBuffer
;
3281 PDVD_COPY_PROTECT_KEY outputKey
= Irp
->AssociatedIrp
.SystemBuffer
;
3283 if (NT_SUCCESS(Irp
->IoStatus
.Status
)) {
3286 // Shift the data down to its new position.
3289 RtlMoveMemory(outputKey
->KeyData
,
3291 sizeof(DVD_DISK_KEY_DESCRIPTOR
));
3293 RtlCopyMemory(outputKey
,
3295 sizeof(DVD_COPY_PROTECT_KEY
));
3297 outputKey
->KeyLength
= DVD_DISK_KEY_LENGTH
;
3299 Irp
->IoStatus
.Information
= DVD_DISK_KEY_LENGTH
;
3303 TraceLog((CdromDebugWarning
,
3304 "DiskKey Failed with status %x, %p (%x) bytes\n",
3305 Irp
->IoStatus
.Status
,
3306 (PVOID
)Irp
->IoStatus
.Information
,
3307 ((rawKey
->Length
[0] << 16) | rawKey
->Length
[1])
3313 // release the context block
3316 ExFreePool(Context
);
3318 return STATUS_SUCCESS
;
3324 IN PDEVICE_OBJECT DeviceObject
,
3331 Routine Description:
3333 This routine executes when the port driver has completed a request.
3334 It looks at the SRB status in the completing SRB and if not success
3335 it checks for valid request sense buffer information. If valid, the
3336 info is used to update status with more precise message of type of
3337 error. This routine deallocates the SRB.
3341 DeviceObject - Supplies the device object which represents the logical
3344 Irp - Supplies the Irp which has completed.
3346 Context - Supplies a pointer to the SRB.
3355 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3356 PSCSI_REQUEST_BLOCK srb
= Context
;
3357 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension
= DeviceObject
->DeviceExtension
;
3362 // Check SRB status for success of completing request.
3365 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3367 ULONG retryInterval
;
3369 TraceLog((CdromDebugTrace
, "CdromXAComplete: IRP %p SRB %p Status %x\n",
3370 Irp
, srb
, srb
->SrbStatus
));
3373 // Release the queue if it is frozen.
3376 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3377 ClassReleaseQueue(DeviceObject
);
3380 retry
= ClassInterpretSenseInfo(
3383 irpStack
->MajorFunction
,
3384 irpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
? irpStack
->Parameters
.DeviceIoControl
.IoControlCode
: 0,
3385 MAXIMUM_RETRIES
- irpStack
->MinorFunction
, // HACKHACK - REF #0001
3390 // If the status is verified required and the this request
3391 // should bypass verify required then retry the request.
3394 if (irpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3395 status
== STATUS_VERIFY_REQUIRED
) {
3397 status
= STATUS_IO_DEVICE_ERROR
;
3403 if (irpStack
->MinorFunction
!= 0) { // HACKHACK - REF #0001
3405 irpStack
->MinorFunction
--; // HACKHACK - REF #0001
3411 TraceLog((CdromDebugWarning
,
3412 "CdRomXACompletion: Retry request %p (%x) - "
3413 "Calling StartIo\n", Irp
, irpStack
->MinorFunction
));
3416 ExFreePool(srb
->SenseInfoBuffer
);
3420 // Call StartIo directly since IoStartNextPacket hasn't been called,
3421 // the serialisation is still intact.
3424 CdRomRetryRequest(deviceExtension
,
3429 return STATUS_MORE_PROCESSING_REQUIRED
;
3434 // Exhausted retries, fall through and complete the request
3435 // with the appropriate status
3438 TraceLog((CdromDebugWarning
,
3439 "CdRomXACompletion: Retries exhausted for irp %p\n",
3447 // Set status for successful request.
3450 status
= STATUS_SUCCESS
;
3452 } // end if (SRB_STATUS(srb->SrbStatus) ...
3455 // Return SRB to nonpaged pool.
3458 ExFreePool(srb
->SenseInfoBuffer
);
3462 // Set status in completing IRP.
3465 Irp
->IoStatus
.Status
= status
;
3468 // Set the hard error if necessary.
3471 if (!NT_SUCCESS(status
) &&
3472 IoIsErrorUserInduced(status
) &&
3473 Irp
->Tail
.Overlay
.Thread
!= NULL
) {
3476 // Store DeviceObject for filesystem, and clear
3477 // in IoStatus.Information field.
3480 IoSetHardErrorOrVerifyDevice(Irp
, DeviceObject
);
3481 Irp
->IoStatus
.Information
= 0;
3485 // If pending has be returned for this irp then mark the current stack as
3489 if (Irp
->PendingReturned
) {
3490 IoMarkIrpPending(Irp
);
3494 KIRQL oldIrql
= KeRaiseIrqlToDpcLevel();
3495 IoStartNextPacket(DeviceObject
, FALSE
);
3496 KeLowerIrql(oldIrql
);
3498 ClassReleaseRemoveLock(DeviceObject
, Irp
);
3505 CdRomDeviceControlDvdReadStructure(
3506 IN PDEVICE_OBJECT Fdo
,
3507 IN PIRP OriginalIrp
,
3509 IN PSCSI_REQUEST_BLOCK Srb
3512 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
3513 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3514 PCDB cdb
= (PCDB
)Srb
->Cdb
;
3517 PDVD_READ_STRUCTURE request
;
3520 PFOUR_BYTE fourByte
;
3523 (USHORT
)currentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
3525 request
= OriginalIrp
->AssociatedIrp
.SystemBuffer
;
3527 (ULONG
)(request
->BlockByteOffset
.QuadPart
>> fdoExtension
->SectorShift
);
3528 fourByte
= (PFOUR_BYTE
) &blockNumber
;
3530 Srb
->CdbLength
= 12;
3531 Srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3532 Srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3533 SET_FLAG(Srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3535 cdb
->READ_DVD_STRUCTURE
.OperationCode
= SCSIOP_READ_DVD_STRUCTURE
;
3536 cdb
->READ_DVD_STRUCTURE
.RMDBlockNumber
[0] = fourByte
->Byte3
;
3537 cdb
->READ_DVD_STRUCTURE
.RMDBlockNumber
[1] = fourByte
->Byte2
;
3538 cdb
->READ_DVD_STRUCTURE
.RMDBlockNumber
[2] = fourByte
->Byte1
;
3539 cdb
->READ_DVD_STRUCTURE
.RMDBlockNumber
[3] = fourByte
->Byte0
;
3540 cdb
->READ_DVD_STRUCTURE
.LayerNumber
= request
->LayerNumber
;
3541 cdb
->READ_DVD_STRUCTURE
.Format
= (UCHAR
)request
->Format
;
3545 if ((UCHAR
)request
->Format
> DvdMaxDescriptor
) {
3546 TraceLog((CdromDebugWarning
,
3547 "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
3548 (UCHAR
)request
->Format
,
3549 READ_DVD_STRUCTURE_FORMAT_STRINGS
[DvdMaxDescriptor
],
3553 TraceLog((CdromDebugWarning
,
3554 "READ_DVD_STRUCTURE format %x = %s (%x bytes)\n",
3555 (UCHAR
)request
->Format
,
3556 READ_DVD_STRUCTURE_FORMAT_STRINGS
[(UCHAR
)request
->Format
],
3563 if (request
->Format
== DvdDiskKeyDescriptor
) {
3565 cdb
->READ_DVD_STRUCTURE
.AGID
= (UCHAR
) request
->SessionId
;
3569 cdb
->READ_DVD_STRUCTURE
.AllocationLength
[0] = (UCHAR
)(dataLength
>> 8);
3570 cdb
->READ_DVD_STRUCTURE
.AllocationLength
[1] = (UCHAR
)(dataLength
& 0xff);
3571 Srb
->DataTransferLength
= dataLength
;
3575 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3577 DVD_TAG_READ_STRUCTURE
);
3580 ExFreePool(Srb
->SenseInfoBuffer
);
3583 OriginalIrp
->IoStatus
.Information
= 0;
3584 OriginalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3586 BAIL_OUT(OriginalIrp
);
3587 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
3590 RtlZeroMemory(dataBuffer
, dataLength
);
3592 NewIrp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3593 currentIrpStack
->Parameters
.Read
.Length
,
3598 if (NewIrp
->MdlAddress
== NULL
) {
3599 ExFreePool(dataBuffer
);
3600 ExFreePool(Srb
->SenseInfoBuffer
);
3603 OriginalIrp
->IoStatus
.Information
= 0;
3604 OriginalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3606 BAIL_OUT(OriginalIrp
);
3607 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
3615 MmBuildMdlForNonPagedPool(NewIrp
->MdlAddress
);
3617 Srb
->DataBuffer
= dataBuffer
;
3619 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, NewIrp
);
3626 CdRomDeviceControlDvdEndSession(
3627 IN PDEVICE_OBJECT Fdo
,
3628 IN PIRP OriginalIrp
,
3630 IN PSCSI_REQUEST_BLOCK Srb
3633 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
3634 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3635 PCDB cdb
= (PCDB
)Srb
->Cdb
;
3637 PDVD_SESSION_ID sessionId
= OriginalIrp
->AssociatedIrp
.SystemBuffer
;
3639 Srb
->CdbLength
= 12;
3640 Srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3641 Srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3642 SET_FLAG(Srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
3644 cdb
->SEND_KEY
.OperationCode
= SCSIOP_SEND_KEY
;
3645 cdb
->SEND_KEY
.AGID
= (UCHAR
) (*sessionId
);
3646 cdb
->SEND_KEY
.KeyFormat
= DVD_INVALIDATE_AGID
;
3648 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, NewIrp
);
3655 CdRomDeviceControlDvdStartSessionReadKey(
3656 IN PDEVICE_OBJECT Fdo
,
3657 IN PIRP OriginalIrp
,
3659 IN PSCSI_REQUEST_BLOCK Srb
3662 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
3663 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3664 PCDB cdb
= (PCDB
)Srb
->Cdb
;
3667 PDVD_COPY_PROTECT_KEY keyParameters
;
3668 PCDVD_KEY_HEADER keyBuffer
= NULL
;
3672 ULONG allocationLength
;
3673 PFOUR_BYTE fourByte
;
3676 // Both of these use REPORT_KEY commands.
3677 // Determine the size of the input buffer
3680 if(currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3681 IOCTL_DVD_READ_KEY
) {
3683 keyParameters
= OriginalIrp
->AssociatedIrp
.SystemBuffer
;
3685 keyLength
= sizeof(CDVD_KEY_HEADER
) +
3686 (currentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
-
3687 sizeof(DVD_COPY_PROTECT_KEY
));
3690 keyParameters
= NULL
;
3691 keyLength
= sizeof(CDVD_KEY_HEADER
) +
3692 sizeof(CDVD_REPORT_AGID_DATA
);
3697 keyBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3701 if(keyBuffer
== NULL
) {
3703 TraceLog((CdromDebugWarning
,
3704 "IOCTL_DVD_READ_KEY - couldn't allocate "
3705 "%d byte buffer for key\n",
3707 status
= STATUS_INSUFFICIENT_RESOURCES
;
3712 NewIrp
->MdlAddress
= IoAllocateMdl(keyBuffer
,
3718 if(NewIrp
->MdlAddress
== NULL
) {
3720 TraceLog((CdromDebugWarning
,
3721 "IOCTL_DVD_READ_KEY - couldn't create mdl\n"));
3722 status
= STATUS_INSUFFICIENT_RESOURCES
;
3726 MmBuildMdlForNonPagedPool(NewIrp
->MdlAddress
);
3728 Srb
->DataBuffer
= keyBuffer
;
3729 Srb
->CdbLength
= 12;
3731 cdb
->REPORT_KEY
.OperationCode
= SCSIOP_REPORT_KEY
;
3733 allocationLength
= keyLength
;
3734 fourByte
= (PFOUR_BYTE
) &allocationLength
;
3735 cdb
->REPORT_KEY
.AllocationLength
[0] = fourByte
->Byte1
;
3736 cdb
->REPORT_KEY
.AllocationLength
[1] = fourByte
->Byte0
;
3738 Srb
->DataTransferLength
= keyLength
;
3741 // set the specific parameters....
3744 if(currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
3745 IOCTL_DVD_READ_KEY
) {
3747 if(keyParameters
->KeyType
== DvdTitleKey
) {
3749 ULONG logicalBlockAddress
;
3751 logicalBlockAddress
= (ULONG
)
3752 (keyParameters
->Parameters
.TitleOffset
.QuadPart
>>
3753 fdoExtension
->SectorShift
);
3755 fourByte
= (PFOUR_BYTE
) &(logicalBlockAddress
);
3757 cdb
->REPORT_KEY
.LogicalBlockAddress
[0] = fourByte
->Byte3
;
3758 cdb
->REPORT_KEY
.LogicalBlockAddress
[1] = fourByte
->Byte2
;
3759 cdb
->REPORT_KEY
.LogicalBlockAddress
[2] = fourByte
->Byte1
;
3760 cdb
->REPORT_KEY
.LogicalBlockAddress
[3] = fourByte
->Byte0
;
3763 cdb
->REPORT_KEY
.KeyFormat
= (UCHAR
)keyParameters
->KeyType
;
3764 cdb
->REPORT_KEY
.AGID
= (UCHAR
) keyParameters
->SessionId
;
3765 TraceLog((CdromDebugWarning
,
3766 "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
3767 NewIrp
, OriginalIrp
, "READ_KEY"));
3771 cdb
->REPORT_KEY
.KeyFormat
= DVD_REPORT_AGID
;
3772 cdb
->REPORT_KEY
.AGID
= 0;
3773 TraceLog((CdromDebugWarning
,
3774 "CdRomDvdReadKey => sending irp %p for irp %p (%s)\n",
3775 NewIrp
, OriginalIrp
, "START_SESSION"));
3778 Srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3779 Srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3780 SET_FLAG(Srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3782 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, NewIrp
);
3784 status
= STATUS_SUCCESS
;
3788 if (!NT_SUCCESS(status
)) {
3791 // An error occured during setup - free resources and
3792 // complete this request.
3794 if (NewIrp
->MdlAddress
!= NULL
) {
3795 IoFreeMdl(NewIrp
->MdlAddress
);
3798 if (keyBuffer
!= NULL
) {
3799 ExFreePool(keyBuffer
);
3801 ExFreePool(Srb
->SenseInfoBuffer
);
3805 OriginalIrp
->IoStatus
.Information
= 0;
3806 OriginalIrp
->IoStatus
.Status
= status
;
3808 BAIL_OUT(OriginalIrp
);
3809 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
3811 } // end !NT_SUCCESS
3818 CdRomDeviceControlDvdSendKey(
3819 IN PDEVICE_OBJECT Fdo
,
3820 IN PIRP OriginalIrp
,
3822 IN PSCSI_REQUEST_BLOCK Srb
3825 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
3826 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3827 PCDB cdb
= (PCDB
)Srb
->Cdb
;
3829 PDVD_COPY_PROTECT_KEY key
;
3830 PCDVD_KEY_HEADER keyBuffer
= NULL
;
3834 PFOUR_BYTE fourByte
;
3836 key
= OriginalIrp
->AssociatedIrp
.SystemBuffer
;
3837 keyLength
= (key
->KeyLength
- sizeof(DVD_COPY_PROTECT_KEY
)) +
3838 sizeof(CDVD_KEY_HEADER
);
3842 keyBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3846 if(keyBuffer
== NULL
) {
3848 TraceLog((CdromDebugWarning
,
3849 "IOCTL_DVD_SEND_KEY - couldn't allocate "
3850 "%d byte buffer for key\n",
3852 status
= STATUS_INSUFFICIENT_RESOURCES
;
3856 RtlZeroMemory(keyBuffer
, keyLength
);
3859 // keylength is decremented here by two because the
3860 // datalength does not include the header, which is two
3861 // bytes. keylength is immediately incremented later
3862 // by the same amount.
3866 fourByte
= (PFOUR_BYTE
) &keyLength
;
3867 keyBuffer
->DataLength
[0] = fourByte
->Byte1
;
3868 keyBuffer
->DataLength
[1] = fourByte
->Byte0
;
3872 // copy the user's buffer to our own allocated buffer
3875 RtlMoveMemory(keyBuffer
->Data
,
3877 key
->KeyLength
- sizeof(DVD_COPY_PROTECT_KEY
));
3880 NewIrp
->MdlAddress
= IoAllocateMdl(keyBuffer
,
3886 if(NewIrp
->MdlAddress
== NULL
) {
3887 TraceLog((CdromDebugWarning
,
3888 "IOCTL_DVD_SEND_KEY - couldn't create mdl\n"));
3889 status
= STATUS_INSUFFICIENT_RESOURCES
;
3894 MmBuildMdlForNonPagedPool(NewIrp
->MdlAddress
);
3896 Srb
->CdbLength
= 12;
3897 Srb
->DataBuffer
= keyBuffer
;
3898 Srb
->DataTransferLength
= keyLength
;
3900 Srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3901 Srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3902 SET_FLAG(Srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
3904 cdb
->REPORT_KEY
.OperationCode
= SCSIOP_SEND_KEY
;
3906 fourByte
= (PFOUR_BYTE
) &keyLength
;
3908 cdb
->SEND_KEY
.ParameterListLength
[0] = fourByte
->Byte1
;
3909 cdb
->SEND_KEY
.ParameterListLength
[1] = fourByte
->Byte0
;
3910 cdb
->SEND_KEY
.KeyFormat
= (UCHAR
)key
->KeyType
;
3911 cdb
->SEND_KEY
.AGID
= (UCHAR
) key
->SessionId
;
3913 if (key
->KeyType
== DvdSetRpcKey
) {
3914 TraceLog((CdromDebugWarning
,
3915 "IOCTL_DVD_SEND_KEY - Setting RPC2 drive region\n"));
3917 TraceLog((CdromDebugWarning
,
3918 "IOCTL_DVD_SEND_KEY - key type %x\n", key
->KeyType
));
3921 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, NewIrp
);
3923 status
= STATUS_SUCCESS
;
3927 if (!NT_SUCCESS(status
)) {
3930 // An error occured during setup - free resources and
3931 // complete this request.
3934 if (NewIrp
->MdlAddress
!= NULL
) {
3935 IoFreeMdl(NewIrp
->MdlAddress
);
3938 if (keyBuffer
!= NULL
) {
3939 ExFreePool(keyBuffer
);
3942 ExFreePool(Srb
->SenseInfoBuffer
);
3946 OriginalIrp
->IoStatus
.Information
= 0;
3947 OriginalIrp
->IoStatus
.Status
= status
;
3949 BAIL_OUT(OriginalIrp
);
3950 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
3960 CdRomInterpretReadCapacity(
3961 IN PDEVICE_OBJECT Fdo
,
3962 IN PREAD_CAPACITY_DATA ReadCapacityBuffer
3965 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
3966 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
3972 ASSERT(ReadCapacityBuffer
);
3973 ASSERT(commonExtension
->IsFdo
);
3975 TraceLog((CdromDebugError
,
3976 "CdRomInterpretReadCapacity: Entering\n"));
3979 // Swizzle bytes from Read Capacity and translate into
3980 // the necessary geometry information in the device extension.
3983 tmp
= ReadCapacityBuffer
->BytesPerBlock
;
3984 ((PFOUR_BYTE
)&bps
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
3985 ((PFOUR_BYTE
)&bps
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
3986 ((PFOUR_BYTE
)&bps
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
3987 ((PFOUR_BYTE
)&bps
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
3990 // Insure that bps is a power of 2.
3991 // This corrects a problem with the HP 4020i CDR where it
3992 // returns an incorrect number for bytes per sector.
3998 lastBit
= (ULONG
) -1;
4006 fdoExtension
->DiskGeometry
.BytesPerSector
= bps
;
4008 TraceLog((CdromDebugTrace
, "CdRomInterpretReadCapacity: Calculated bps %#x\n",
4009 fdoExtension
->DiskGeometry
.BytesPerSector
));
4012 // Copy last sector in reverse byte order.
4015 tmp
= ReadCapacityBuffer
->LogicalBlockAddress
;
4016 ((PFOUR_BYTE
)&lastSector
)->Byte0
= ((PFOUR_BYTE
)&tmp
)->Byte3
;
4017 ((PFOUR_BYTE
)&lastSector
)->Byte1
= ((PFOUR_BYTE
)&tmp
)->Byte2
;
4018 ((PFOUR_BYTE
)&lastSector
)->Byte2
= ((PFOUR_BYTE
)&tmp
)->Byte1
;
4019 ((PFOUR_BYTE
)&lastSector
)->Byte3
= ((PFOUR_BYTE
)&tmp
)->Byte0
;
4022 // Calculate sector to byte shift.
4025 WHICH_BIT(bps
, fdoExtension
->SectorShift
);
4027 TraceLog((CdromDebugTrace
,"CdRomInterpretReadCapacity: Sector size is %d\n",
4028 fdoExtension
->DiskGeometry
.BytesPerSector
));
4030 TraceLog((CdromDebugTrace
,"CdRomInterpretReadCapacity: Number of Sectors is %d\n",
4034 // Calculate media capacity in bytes.
4037 commonExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(lastSector
+ 1);
4040 // we've defaulted to 32/64 forever. don't want to change this now...
4043 fdoExtension
->DiskGeometry
.TracksPerCylinder
= 0x40;
4044 fdoExtension
->DiskGeometry
.SectorsPerTrack
= 0x20;
4047 // Calculate number of cylinders.
4050 fdoExtension
->DiskGeometry
.Cylinders
.QuadPart
= (LONGLONG
)((lastSector
+ 1) / (32 * 64));
4052 commonExtension
->PartitionLength
.QuadPart
=
4053 (commonExtension
->PartitionLength
.QuadPart
<< fdoExtension
->SectorShift
);
4056 ASSERT(TEST_FLAG(Fdo
->Characteristics
, FILE_REMOVABLE_MEDIA
));
4059 // This device supports removable media.
4062 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;