3 Copyright (C) Microsoft Corporation, 1991 - 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 #pragma alloc_text(INIT, DriverEntry)
43 #pragma alloc_text(PAGE, CdRomUnload)
44 #pragma alloc_text(PAGE, CdRomAddDevice)
45 #pragma alloc_text(PAGE, CdRomCreateDeviceObject)
46 #pragma alloc_text(PAGE, CdRomStartDevice)
47 #pragma alloc_text(PAGE, ScanForSpecial)
48 #pragma alloc_text(PAGE, ScanForSpecialHandler)
49 #pragma alloc_text(PAGE, CdRomRemoveDevice)
50 #pragma alloc_text(PAGE, CdRomGetDeviceType)
51 #pragma alloc_text(PAGE, CdRomReadWriteVerification)
52 #pragma alloc_text(PAGE, CdRomGetDeviceParameter)
53 #pragma alloc_text(PAGE, CdRomSetDeviceParameter)
54 #pragma alloc_text(PAGE, CdRomPickDvdRegion)
55 #pragma alloc_text(PAGE, CdRomIsPlayActive)
57 #pragma alloc_text(PAGEHITA, HitachiProcessError)
58 #pragma alloc_text(PAGEHIT2, HitachiProcessErrorGD2000)
60 #pragma alloc_text(PAGETOSH, ToshibaProcessErrorCompletion)
61 #pragma alloc_text(PAGETOSH, ToshibaProcessError)
65 #define IS_WRITE_REQUEST(irpStack) \
66 (irpStack->MajorFunction == IRP_MJ_WRITE)
68 #define IS_READ_WRITE_REQUEST(irpStack) \
69 ((irpStack->MajorFunction == IRP_MJ_READ) || \
70 (irpStack->MajorFunction == IRP_MJ_WRITE) || \
71 ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) && \
72 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_RAW_READ)))
80 IN PDRIVER_OBJECT DriverObject
,
81 IN PUNICODE_STRING RegistryPath
88 This routine initializes the cdrom class driver.
92 DriverObject - Pointer to driver object created by system.
94 RegistryPath - Pointer to the name of the services node for this driver.
98 The function value is the final status from the initialization operation.
103 CLASS_INIT_DATA InitializationData
;
104 PCDROM_DRIVER_EXTENSION driverExtension
;
109 WPP_INIT_TRACING(DriverObject
, RegistryPath
);
111 TraceLog((CdromDebugTrace
,
112 "CDROM.SYS DriverObject %p loading\n", DriverObject
));
114 status
= IoAllocateDriverObjectExtension(DriverObject
,
115 CDROM_DRIVER_EXTENSION_ID
,
116 sizeof(CDROM_DRIVER_EXTENSION
),
119 if (!NT_SUCCESS(status
)) {
120 TraceLog((CdromDebugWarning
,
121 "DriverEntry !! no DriverObjectExtension %x\n", status
));
126 // always zero the memory, since we are now reloading the driver.
129 RtlZeroMemory(driverExtension
, sizeof(CDROM_DRIVER_EXTENSION
));
135 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
141 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
143 InitializationData
.FdoData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
145 InitializationData
.FdoData
.DeviceType
= FILE_DEVICE_CD_ROM
;
146 InitializationData
.FdoData
.DeviceCharacteristics
=
147 FILE_REMOVABLE_MEDIA
| FILE_DEVICE_SECURE_OPEN
;
153 InitializationData
.FdoData
.ClassError
= CdRomErrorHandler
;
154 InitializationData
.FdoData
.ClassInitDevice
= CdRomInitDevice
;
155 InitializationData
.FdoData
.ClassStartDevice
= CdRomStartDevice
;
156 InitializationData
.FdoData
.ClassStopDevice
= CdRomStopDevice
;
157 InitializationData
.FdoData
.ClassRemoveDevice
= CdRomRemoveDevice
;
159 InitializationData
.FdoData
.ClassReadWriteVerification
= CdRomReadWriteVerification
;
160 InitializationData
.FdoData
.ClassDeviceControl
= CdRomDeviceControlDispatch
;
162 InitializationData
.FdoData
.ClassPowerDevice
= ClassSpinDownPowerHandler
;
163 InitializationData
.FdoData
.ClassShutdownFlush
= CdRomShutdownFlush
;
164 InitializationData
.FdoData
.ClassCreateClose
= NULL
;
166 InitializationData
.ClassStartIo
= CdRomStartIo
;
167 InitializationData
.ClassAddDevice
= CdRomAddDevice
;
169 InitializationData
.ClassTick
= CdRomTickHandler
;
170 InitializationData
.ClassUnload
= CdRomUnload
;
173 // Call the class init routine
175 return ClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
177 } // end DriverEntry()
182 IN PDRIVER_OBJECT DriverObject
186 UNREFERENCED_PARAMETER(DriverObject
);
187 TraceLog((CdromDebugTrace
,
188 "CDROM.SYS DriverObject %p unloading\n", DriverObject
));
189 WPP_CLEANUP(DriverObject
);
191 } // end CdRomUnload()
196 IN PDRIVER_OBJECT DriverObject
,
197 IN PDEVICE_OBJECT PhysicalDeviceObject
204 This routine creates and initializes a new FDO for the corresponding
205 PDO. It may perform property queries on the FDO but cannot do any
206 media access operations.
210 DriverObject - CDROM class driver object.
212 Pdo - the physical device object we are being added to
226 // Get the address of the count of the number of cdroms already initialized.
228 DbgPrint("add device\n");
230 status
= CdRomCreateDeviceObject(DriverObject
,
231 PhysicalDeviceObject
);
234 // Note: this always increments driver extension counter
235 // it will eventually wrap, and fail additions
236 // if an existing cdrom has the given number.
237 // so unlikely that we won't even bother considering
238 // this case, since the cure is quite likely worse
239 // than the symptoms.
242 if(NT_SUCCESS(status
)) {
245 // keep track of the total number of active cdroms in IoGet(),
246 // as some programs use this to determine when they have found
247 // all the cdroms in the system.
250 TraceLog((CdromDebugTrace
, "CDROM.SYS Add succeeded\n"));
251 IoGetConfigurationInformation()->CdRomCount
++;
255 TraceLog((CdromDebugWarning
,
256 "CDROM.SYS Add failed! %x\n", status
));
265 CdRomCreateDeviceObject(
266 IN PDRIVER_OBJECT DriverObject
,
267 IN PDEVICE_OBJECT PhysicalDeviceObject
274 This routine creates an object for the device and then calls the
275 SCSI port driver for media capacity and sector size.
279 DriverObject - Pointer to driver object created by system.
280 PortDeviceObject - to connect to SCSI port driver.
281 DeviceCount - Number of previously installed CDROMs.
282 PortCapabilities - Pointer to structure returned by SCSI port
283 driver describing adapter capabilites (and limitations).
284 LunInfo - Pointer to configuration information for this device.
292 UCHAR ntNameBuffer
[64];
296 PDEVICE_OBJECT lowerDevice
= NULL
;
297 PDEVICE_OBJECT deviceObject
= NULL
;
298 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= NULL
;
299 PCDROM_DATA cdData
= NULL
;
300 PCDROM_DRIVER_EXTENSION driverExtension
= NULL
;
303 CCHAR dosNameBuffer
[64];
304 CCHAR deviceNameBuffer
[64];
305 STRING deviceNameString
;
307 UNICODE_STRING dosUnicodeString
;
308 UNICODE_STRING unicodeString
;
313 // Claim the device. Note that any errors after this
314 // will goto the generic handler, where the device will
318 lowerDevice
= IoGetAttachedDeviceReference(PhysicalDeviceObject
);
320 status
= ClassClaimDevice(lowerDevice
, FALSE
);
322 if(!NT_SUCCESS(status
)) {
325 // Someone already had this device - we're in trouble
328 ObDereferenceObject(lowerDevice
);
333 // Create device object for this device by first getting a unique name
334 // for the device and then creating it.
337 driverExtension
= IoGetDriverObjectExtension(DriverObject
,
338 CDROM_DRIVER_EXTENSION_ID
);
339 ASSERT(driverExtension
!= NULL
);
342 // InterlockedCdRomCounter is biased by 1.
345 deviceNumber
= InterlockedIncrement(&driverExtension
->InterlockedCdRomCounter
) - 1;
346 sprintf(ntNameBuffer
, "\\Device\\CdRom%d", deviceNumber
);
349 status
= ClassCreateDeviceObject(DriverObject
,
351 PhysicalDeviceObject
,
355 if (!NT_SUCCESS(status
)) {
356 TraceLog((CdromDebugWarning
,
357 "CreateCdRomDeviceObjects: Can not create device %s\n",
360 goto CreateCdRomDeviceObjectExit
;
364 // Indicate that IRPs should include MDLs.
367 SET_FLAG(deviceObject
->Flags
, DO_DIRECT_IO
);
369 fdoExtension
= deviceObject
->DeviceExtension
;
372 // Back pointer to device object.
375 fdoExtension
->CommonExtension
.DeviceObject
= deviceObject
;
378 // This is the physical device.
381 fdoExtension
->CommonExtension
.PartitionZeroExtension
= fdoExtension
;
384 // Initialize lock count to zero. The lock count is used to
385 // disable the ejection mechanism when media is mounted.
388 fdoExtension
->LockCount
= 0;
391 // Save system cdrom number
394 fdoExtension
->DeviceNumber
= deviceNumber
;
397 // Set the alignment requirements for the device based on the
398 // host adapter requirements
401 if (lowerDevice
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
402 deviceObject
->AlignmentRequirement
= lowerDevice
->AlignmentRequirement
;
406 // Save the device descriptors
409 fdoExtension
->AdapterDescriptor
= NULL
;
411 fdoExtension
->DeviceDescriptor
= NULL
;
414 // Clear the SrbFlags and disable synchronous transfers
417 fdoExtension
->SrbFlags
= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
420 // Finally, attach to the PDO
423 fdoExtension
->LowerPdo
= PhysicalDeviceObject
;
425 fdoExtension
->CommonExtension
.LowerDeviceObject
=
426 IoAttachDeviceToDeviceStack(deviceObject
, PhysicalDeviceObject
);
428 if(fdoExtension
->CommonExtension
.LowerDeviceObject
== NULL
) {
431 // Uh - oh, we couldn't attach
432 // cleanup and return
435 status
= STATUS_UNSUCCESSFUL
;
436 goto CreateCdRomDeviceObjectExit
;
440 // CdRom uses an extra stack location for synchronizing it's start io
444 deviceObject
->StackSize
++;
447 // cdData is used a few times below
450 cdData
= fdoExtension
->CommonExtension
.DriverData
;
453 // For NTMS to be able to easily determine drives-drv. letter matches.
456 status
= CdRomCreateWellKnownName( deviceObject
);
458 if (!NT_SUCCESS(status
)) {
459 TraceLog((CdromDebugWarning
,
460 "CdromCreateDeviceObjects: unable to create symbolic "
461 "link for device %wZ\n", &fdoExtension
->CommonExtension
.DeviceName
));
462 TraceLog((CdromDebugWarning
,
463 "CdromCreateDeviceObjects: (non-fatal error)\n"));
466 ClassUpdateInformationInRegistry(deviceObject
, "CdRom",
467 fdoExtension
->DeviceNumber
, NULL
, 0);
470 // from above IoGetAttachedDeviceReference
473 ObDereferenceObject(lowerDevice
);
476 // need to init timerlist here in case a remove occurs
477 // without a start, since we check the list is empty on remove.
480 cdData
->DelayedRetryIrp
= NULL
;
481 cdData
->DelayedRetryInterval
= 0;
484 // need this to be initialized for RPC Phase 1 drives (rpc0)
487 KeInitializeMutex(&cdData
->Rpc0RegionMutex
, 0);
490 // The device is initialized properly - mark it as such.
493 CLEAR_FLAG(deviceObject
->Flags
, DO_DEVICE_INITIALIZING
);
495 return(STATUS_SUCCESS
);
497 CreateCdRomDeviceObjectExit
:
500 // Release the device since an error occured.
503 // ClassClaimDevice(PortDeviceObject,
509 // from above IoGetAttachedDeviceReference
512 ObDereferenceObject(lowerDevice
);
514 if (deviceObject
!= NULL
) {
515 IoDeleteDevice(deviceObject
);
520 } // end CreateCdRomDeviceObject()
525 IN PDEVICE_OBJECT Fdo
532 This routine will complete the cd-rom initialization. This includes
533 allocating sense info buffers and srb s-lists, reading drive capacity
534 and setting up Media Change Notification (autorun).
536 This routine will not clean up allocate resources if it fails - that
537 is left for device stop/removal
541 Fdo - a pointer to the functional device object for this device
550 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
551 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
552 PCLASS_DRIVER_EXTENSION driverExtension
= ClassGetDriverExtension(
555 PVOID senseData
= NULL
;
560 BOOLEAN changerDevice
;
561 BOOLEAN isMmcDevice
= FALSE
;
572 // Build the lookaside list for srb's for the physical disk. Should only
576 ClassInitializeSrbLookasideList(&(fdoExtension
->CommonExtension
),
577 CDROM_SRB_LIST_SIZE
);
580 // Allocate request sense buffer.
583 senseData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
585 CDROM_TAG_SENSE_INFO
);
587 if (senseData
== NULL
) {
590 // The buffer cannot be allocated.
593 status
= STATUS_INSUFFICIENT_RESOURCES
;
594 goto CdRomInitDeviceExit
;
598 // Set the sense data pointer in the device extension.
601 fdoExtension
->SenseData
= senseData
;
604 // CDROMs are not partitionable so starting offset is 0.
607 commonExtension
->StartingOffset
.LowPart
= 0;
608 commonExtension
->StartingOffset
.HighPart
= 0;
611 // Set timeout value in seconds.
614 timeOut
= ClassQueryTimeOutRegistryValue(Fdo
);
616 fdoExtension
->TimeOutValue
= timeOut
;
618 fdoExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
621 cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
624 // Set up media change support defaults.
627 KeInitializeSpinLock(&cddata
->DelayedRetrySpinLock
);
629 cddata
->DelayedRetryIrp
= NULL
;
630 cddata
->DelayedRetryInterval
= 0;
631 cddata
->Mmc
.WriteAllowed
= FALSE
;
634 // Scan for controllers that require special processing.
640 // Determine if the drive is MMC-Capable
643 CdRomIsDeviceMmcDevice(Fdo
, &isMmcDevice
);
647 SET_FLAG(Fdo
->Characteristics
, FILE_READ_ONLY_DEVICE
);
652 // the drive supports at least a subset of MMC commands
653 // (and therefore supports READ_CD, etc...)
656 cddata
->Mmc
.IsMmc
= TRUE
;
659 // allocate a buffer for all the capabilities and such
662 status
= CdRomAllocateMmcResources(Fdo
);
663 if (!NT_SUCCESS(status
)) {
664 goto CdRomInitDeviceExit
;
670 // determine all the various media types from the profiles feature
673 PFEATURE_DATA_PROFILE_LIST profileHeader
;
674 ULONG mediaTypes
= 0;
677 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
678 "Checking all profiles for media types supported.\n"
681 profileHeader
= CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
682 cddata
->Mmc
.CapabilitiesBufferSize
,
684 if (profileHeader
== NULL
) {
687 // if profiles don't exist, there is something seriously
688 // wrong with this command -- it's either not a cdrom or
689 // one that hasn't implemented the spec correctly. exit
690 // now while we have the chance to do so safely.
692 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
693 "CdromDevice supports GET_CONFIGURATION, but "
694 "doesn't provide profiles for PDO %p!\n",
695 fdoExtension
->LowerPdo
));
696 status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
697 goto CdRomInitDeviceExit
;
701 for (i
= 0; i
< MAX_CDROM_MEDIA_TYPES
; i
++) {
703 BOOLEAN profileFound
;
704 CdRomFindProfileInProfiles(profileHeader
,
705 MediaProfileMatch
[i
].Profile
,
709 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
710 "CdromInit -> Found Profile %x => Media %x "
712 MediaProfileMatch
[i
].Profile
,
713 MediaProfileMatch
[i
].Media
,
717 cddata
->Mmc
.MediaProfileMatches
[mediaTypes
] =
718 MediaProfileMatch
[i
];
725 if (mediaTypes
== 0) {
728 // if profiles don't exist, there is something seriously
729 // wrong with this command -- it's either not a cdrom or
730 // one that hasn't implemented the spec correctly. exit
731 // now while we have the chance to do so safely.
733 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
734 "CdromDevice supports GET_CONFIGURATION, but "
735 "doesn't support any of the standard profiles "
736 "for PDO %p!\n", fdoExtension
->LowerPdo
));
737 status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
738 goto CdRomInitDeviceExit
;
742 cddata
->Mmc
.MediaTypes
= mediaTypes
;
746 #endif // media checks, and all failure paths due to bad firmware.
749 // if the drive supports target defect management and sector-addressable
750 // writes, then we should allow writes to the media.
753 if (CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
754 cddata
->Mmc
.CapabilitiesBufferSize
,
755 FeatureDefectManagement
) &&
756 CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
757 cddata
->Mmc
.CapabilitiesBufferSize
,
758 FeatureRandomWritable
)) {
761 // the drive is target defect managed, and supports random writes
762 // on sector-aligment. allow writes to occur by setting the error
763 // handler to point to a private media change detection handler.
766 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
767 "Found a WRITE capable device: %p\n", Fdo
));
770 // the write specific pages have been found --
771 // set the error handler and set it to require an update!
774 cddata
->Mmc
.UpdateState
= CdromMmcUpdateRequired
;
775 cddata
->ErrorHandler
= CdRomMmcErrorHandler
;
780 // ISSUE-2000/4/4-henrygab - mmc-compliant compliant drives should
781 // be initialized based upon reported
782 // capabilities, such as CSS, Analogue Audio,
783 // READ_CD capabilities, and (possibly) even
784 // drive capacity information.
787 TraceLog((CdromDebugWarning
,
788 "Defaulting to READ_CD because device %p is MMC compliant\n",
790 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
791 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
797 // Set the default geometry for the cdrom to match what NT 4 used.
798 // Classpnp will use these values to compute the cylinder count rather
799 // than using it's NT 5.0 defaults.
802 fdoExtension
->DiskGeometry
.TracksPerCylinder
= 0x40;
803 fdoExtension
->DiskGeometry
.SectorsPerTrack
= 0x20;
806 // Do READ CAPACITY. This SCSI command returns the last sector address
807 // on the device and the bytes per sector. These are used to calculate
808 // the drive capacity in bytes.
810 // NOTE: This should be change to send the Srb synchronously, then
811 // call CdRomInterpretReadCapacity() to properly setup the defaults.
814 status
= ClassReadDriveCapacity(Fdo
);
816 bps
= fdoExtension
->DiskGeometry
.BytesPerSector
;
818 if (!NT_SUCCESS(status
) || !bps
) {
820 TraceLog((CdromDebugWarning
,
821 "CdRomStartDevice: Can't read capacity for device %wZ\n",
822 &(fdoExtension
->CommonExtension
.DeviceName
)));
825 // Set disk geometry to default values (per ISO 9660).
829 fdoExtension
->SectorShift
= 11;
830 commonExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
835 // Insure that bytes per sector is a power of 2
836 // This corrects a problem with the HP 4020i CDR where it
837 // returns an incorrect number for bytes per sector.
840 lastBit
= (ULONG
) -1;
848 fdoExtension
->DiskGeometry
.BytesPerSector
= bps
;
849 TraceLog((CdromDebugTrace
, "CdRomInitDevice: Calc'd bps = %x\n", bps
));
852 ClassInitializeMediaChangeDetection(fdoExtension
, "CdRom");
856 // test for audio read capabilities
859 TraceLog((CdromDebugWarning
,
860 "Detecting XA_READ capabilities\n"));
862 if (CdRomGetDeviceType(Fdo
) == FILE_DEVICE_DVD
) {
864 TraceLog((CdromDebugWarning
,
865 "CdRomInitDevice: DVD Devices require START_UNIT\n"));
869 // all DVD devices must support the READ_CD command
872 TraceLog((CdromDebugWarning
,
873 "CdRomDetermineRawReadCapabilities: DVD devices "
874 "support READ_CD command for FDO %p\n", Fdo
));
875 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
876 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
879 status
= STATUS_SUCCESS
;
881 } else if ((fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeScsi
) &&
882 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeAta
) &&
883 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeAtapi
) &&
884 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeUnknown
)
888 // devices on the newer busses must support READ_CD command
891 TraceLog((CdromDebugWarning
,
892 "CdRomDetermineRawReadCapabilities: Devices for newer "
893 "busses must support READ_CD command for FDO %p, Bus %x\n",
894 Fdo
, fdoExtension
->DeviceDescriptor
->BusType
));
895 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
896 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
901 // now clear all our READ_CD flags if the drive should have supported
902 // it, but we are not sure it actually does. we still won't query
903 // the drive more than one time if it supports the command.
906 if (TEST_FLAG(cddata
->HackFlags
, CDROM_HACK_FORCE_READ_CD_DETECTION
)) {
908 TraceLog((CdromDebugWarning
,
909 "Forcing detection of READ_CD for FDO %p because "
910 "testing showed some firmware did not properly support it\n",
912 CLEAR_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
918 // read our READ_CD support in the registry if it was seeded.
921 ULONG readCdSupported
= 0;
923 ClassGetDeviceParameter(fdoExtension
,
929 if (readCdSupported
!= 0) {
931 TraceLog((CdromDebugWarning
,
932 "Defaulting to READ_CD because previously detected "
933 "that the device supports it for Fdo %p.\n",
936 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
944 // backwards-compatible hackish attempt to determine if the drive
945 // supports any method of reading digital audio from the disc.
948 if (!TEST_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
)) {
950 SCSI_REQUEST_BLOCK srb
;
953 PUCHAR buffer
= NULL
;
957 // ISSUE-2000/07/05-henrygab - use the mode page to determine
958 // READ_CD support, then fall back on the below
959 // (unreliable?) hack.
963 // Build the MODE SENSE CDB. The data returned will be kept in the
964 // device extension and used to set block size.
967 length
= max(sizeof(ERROR_RECOVERY_DATA
),sizeof(ERROR_RECOVERY_DATA10
));
969 buffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
971 CDROM_TAG_MODE_DATA
);
974 TraceLog((CdromDebugWarning
,
975 "CdRomDetermineRawReadCapabilities: cannot allocate "
976 "buffer, so leaving for FDO %p\n", Fdo
));
977 status
= STATUS_INSUFFICIENT_RESOURCES
;
978 goto CdRomInitDeviceExit
;
981 for (count
= 0; count
< 2; count
++) {
984 length
= sizeof(ERROR_RECOVERY_DATA
);
986 length
= sizeof(ERROR_RECOVERY_DATA10
);
989 RtlZeroMemory(buffer
, length
);
990 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
993 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
997 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
998 cdb
->MODE_SENSE
.PageCode
= 0x1;
999 // note: not setting DBD in order to get the block descriptor!
1000 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
1003 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
1004 cdb
->MODE_SENSE10
.PageCode
= 0x1;
1005 // note: not setting DBD in order to get the block descriptor!
1006 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
1007 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1010 status
= ClassSendSrbSynchronous(Fdo
,
1017 if (NT_SUCCESS(status
) || (status
== STATUS_DATA_OVERRUN
)) {
1020 // STATUS_DATA_OVERRUN means it's a newer drive with more info
1021 // to tell us, so it's probably able to support READ_CD
1024 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
1027 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1029 status
= ClassSendSrbSynchronous(Fdo
,
1035 if (NT_SUCCESS(status
) ||
1036 (status
== STATUS_NO_MEDIA_IN_DEVICE
) ||
1037 (status
== STATUS_NONEXISTENT_SECTOR
) ||
1038 (status
== STATUS_UNRECOGNIZED_MEDIA
)
1045 TraceLog((CdromDebugWarning
,
1046 "CdRomDetermineRawReadCapabilities: Using "
1047 "READ_CD for FDO %p due to status %x\n",
1050 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
1053 // ignore errors in saving this info
1056 ClassSetDeviceParameter(fdoExtension
,
1063 break; // out of the for loop
1067 TraceLog((CdromDebugWarning
,
1068 "CdRomDetermineRawReadCapabilities: Using "
1069 "%s-byte mode switching for FDO %p due to status "
1070 "%x returned for READ_CD\n",
1071 ((count
== 0) ? "6" : "10"), Fdo
, status
));
1074 SET_FLAG(cddata
->XAFlags
, XA_USE_6_BYTE
);
1075 RtlCopyMemory(&cddata
->Header
,
1077 sizeof(ERROR_RECOVERY_DATA
));
1078 cddata
->Header
.ModeDataLength
= 0;
1080 SET_FLAG(cddata
->XAFlags
, XA_USE_10_BYTE
);
1081 RtlCopyMemory(&cddata
->Header10
,
1083 sizeof(ERROR_RECOVERY_DATA10
));
1084 cddata
->Header10
.ModeDataLength
[0] = 0;
1085 cddata
->Header10
.ModeDataLength
[1] = 0;
1087 break; // out of for loop
1090 TraceLog((CdromDebugWarning
,
1091 "FDO %p failed %x byte mode sense, status %x\n",
1093 ((count
== 0) ? 6 : 10),
1098 // mode sense failed
1101 } // end of for loop to try 6 and 10-byte mode sense
1106 // nothing worked. we probably cannot support digital
1107 // audio extraction from this drive
1110 TraceLog((CdromDebugWarning
,
1111 "CdRomDetermineRawReadCapabilities: FDO %p "
1112 "cannot support READ_CD\n", Fdo
));
1113 CLEAR_FLAG(cddata
->XAFlags
, XA_PLEXTOR_CDDA
);
1114 CLEAR_FLAG(cddata
->XAFlags
, XA_NEC_CDDA
);
1115 SET_FLAG(cddata
->XAFlags
, XA_NOT_SUPPORTED
);
1117 } // end of count == 2
1120 // free our resources
1126 // set a successful status
1127 // (in case someone later checks this)
1130 status
= STATUS_SUCCESS
;
1135 // Register interfaces for this device.
1139 UNICODE_STRING interfaceName
;
1141 RtlInitUnicodeString(&interfaceName
, NULL
);
1143 status
= IoRegisterDeviceInterface(fdoExtension
->LowerPdo
,
1144 (LPGUID
) &CdRomClassGuid
,
1148 if(NT_SUCCESS(status
)) {
1150 cddata
->CdromInterfaceString
= interfaceName
;
1152 status
= IoSetDeviceInterfaceState(
1156 if(!NT_SUCCESS(status
)) {
1158 TraceLog((CdromDebugWarning
,
1159 "CdromInitDevice: Unable to register cdrom "
1160 "DCA for fdo %p [%lx]\n",
1166 return(STATUS_SUCCESS
);
1168 CdRomInitDeviceExit
:
1170 CdRomDeAllocateMmcResources(Fdo
);
1171 RtlZeroMemory(&(cddata
->Mmc
), sizeof(CDROM_MMC_EXTENSION
));
1180 IN PDEVICE_OBJECT Fdo
1184 Routine Description:
1186 This routine starts the timer for the cdrom
1190 Fdo - a pointer to the functional device object for this device
1199 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1200 PCDROM_DATA cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
1201 PDVD_COPY_PROTECT_KEY copyProtectKey
;
1202 PDVD_RPC_KEY rpcKey
;
1203 IO_STATUS_BLOCK ioStatus
;
1206 // CdRomCreateWellKnownName(Fdo);
1209 // if we have a DVD-ROM
1210 // if we have a rpc0 device
1211 // fake a rpc2 device
1212 // if device does not have a dvd region set
1213 // select a dvd region for the user
1216 cddata
->DvdRpc0Device
= FALSE
;
1219 // since StartIo() will call IoStartNextPacket() on error, allowing
1220 // StartIo() to be non-recursive prevents stack overflow bugchecks in
1221 // severe error cases (such as fault-injection in the verifier).
1223 // the only difference is that the thread context may be different
1224 // in StartIo() than in the caller of IoStartNextPacket().
1227 IoSetStartIoAttributes(Fdo
, TRUE
, TRUE
);
1230 // check to see if we have a DVD device
1233 if (CdRomGetDeviceType(Fdo
) != FILE_DEVICE_DVD
) {
1234 return STATUS_SUCCESS
;
1238 // we got a DVD drive.
1239 // now, figure out if we have a RPC0 device
1242 bufferLen
= DVD_RPC_KEY_LENGTH
;
1244 (PDVD_COPY_PROTECT_KEY
)ExAllocatePoolWithTag(PagedPool
,
1246 DVD_TAG_RPC2_CHECK
);
1248 if (copyProtectKey
== NULL
) {
1249 return STATUS_INSUFFICIENT_RESOURCES
;
1253 // get the device region
1255 RtlZeroMemory (copyProtectKey
, bufferLen
);
1256 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
1257 copyProtectKey
->KeyType
= DvdGetRpcKey
;
1260 // Build a request for READ_KEY
1262 ClassSendDeviceIoControlSynchronous(
1272 if (!NT_SUCCESS(ioStatus
.Status
)) {
1275 // we have a rpc0 device
1277 // NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
1280 cddata
->DvdRpc0Device
= TRUE
;
1282 TraceLog((CdromDebugWarning
,
1283 "CdromStartDevice (%p): RPC Phase 1 drive detected\n",
1287 // note: we could force this chosen now, but it's better to reduce
1288 // the number of code paths that could be taken. always delay to
1289 // increase the percentage code coverage.
1292 TraceLog((CdromDebugWarning
,
1293 "CdromStartDevice (%p): Delay DVD Region Selection\n",
1296 cddata
->Rpc0SystemRegion
= 0xff;
1297 cddata
->Rpc0SystemRegionResetCount
= DVD_MAX_REGION_RESET_COUNT
;
1298 cddata
->PickDvdRegion
= 1;
1299 cddata
->Rpc0RetryRegistryCallback
= 1;
1300 ExFreePool(copyProtectKey
);
1301 return STATUS_SUCCESS
;
1305 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
1308 // TypeCode of zero means that no region has been set.
1311 if (rpcKey
->TypeCode
== 0) {
1312 TraceLog((CdromDebugWarning
,
1313 "CdromStartDevice (%p): must choose DVD region\n",
1315 cddata
->PickDvdRegion
= 1;
1316 CdRomPickDvdRegion(Fdo
);
1320 ExFreePool (copyProtectKey
);
1322 return STATUS_SUCCESS
;
1328 IN PDEVICE_OBJECT DeviceObject
,
1332 return STATUS_SUCCESS
;
1338 IN PDEVICE_OBJECT Fdo
,
1343 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
1344 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1346 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1347 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1348 PIO_STACK_LOCATION irpStack
;
1352 ULONG transferPages
;
1353 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1354 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1356 PSCSI_REQUEST_BLOCK srb
= NULL
;
1358 PUCHAR senseBuffer
= NULL
;
1364 // Mark IRP with status pending.
1367 IoMarkIrpPending(Irp
);
1369 cdData
= (PCDROM_DATA
)(fdoExtension
->CommonExtension
.DriverData
);
1370 use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
1373 // if this test is true, then we will exit the routine within this
1374 // code block, queueing the irp for later completion.
1377 if ((cdData
->Mmc
.IsMmc
) &&
1378 (cdData
->Mmc
.UpdateState
!= CdromMmcUpdateComplete
)
1382 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1383 "CdRomStartIo: [%p] Device needs to update capabilities\n",
1385 ASSERT(cdData
->Mmc
.IsMmc
);
1386 ASSERT(cdData
->Mmc
.CapabilitiesIrp
!= NULL
);
1387 ASSERT(cdData
->Mmc
.CapabilitiesIrp
!= Irp
);
1392 // the state was either UpdateRequired (which means we will
1393 // have to start the work item) or UpdateStarted (which means
1394 // we have already started the work item at least once -- may
1395 // transparently change to UpdateComplete).
1397 // if it's update required, we just queue it, change to UpdateStarted,
1398 // start the workitem, and start the next packet.
1400 // else, we must queue the item and check the queue depth. if the
1401 // queue depth is equal to 1, that means the worker item from the
1402 // previous attempt has already de-queued the items, so we should
1403 // call this routine again (retry) as an optimization rather than
1404 // re-add it this irp to the queue. since this is tail recursion,
1405 // it won't take much/any stack to do this.
1407 // NOTE: This presumes the following items are true:
1409 // we only add to the list from CdRomStartIo(), which is serialized.
1410 // we only set to UpdateStarted from CdRomStartIo(), and only if
1411 // the state was UpdateRequired.
1412 // we only set to UpdateRequired from CdRomMmcErrorHandler(), and
1413 // only if the state was UpdateComplete.
1414 // we only set to UpdateComplete from the workitem, and assert the
1415 // state was UpdateStarted.
1416 // we flush the entire queue in one atomic operation in the workitem,
1417 // except in the special case described above when we dequeue
1418 // the request immediately.
1420 // order of operations is vitally important: queue, then test the depth
1421 // this will prevent lost irps.
1424 ExInterlockedPushEntrySList(&(cdData
->Mmc
.DelayedIrps
),
1425 (PSINGLE_LIST_ENTRY
)&(Irp
->Tail
.Overlay
.DriverContext
[0]),
1426 &(cdData
->Mmc
.DelayedLock
));
1428 queueDepth
= ExQueryDepthSList(&(cdData
->Mmc
.DelayedIrps
));
1429 if (queueDepth
== 1) {
1431 if (cdData
->Mmc
.UpdateState
== CdromMmcUpdateRequired
) {
1435 // should free any old partition list info that
1436 // we've previously saved away and then start the WorkItem
1439 oldState
= InterlockedExchange(&cdData
->Mmc
.UpdateState
,
1440 CdromMmcUpdateStarted
);
1441 ASSERT(oldState
== CdromMmcUpdateRequired
);
1443 IoQueueWorkItem(cdData
->Mmc
.CapabilitiesWorkItem
,
1444 CdRomUpdateMmcDriveCapabilities
,
1451 // they *just* finished updating, so we should flush the list
1452 // back onto the StartIo queue and start the next packet.
1455 CdRompFlushDelayedList(Fdo
, &(cdData
->Mmc
), STATUS_SUCCESS
, FALSE
);
1462 // start the next packet so we don't deadlock....
1465 IoStartNextPacket(Fdo
, FALSE
);
1471 // If the flag is set in the device object
1472 // force a verify for READ, WRITE and RAW_READ requests
1473 // Note that ioctls are passed through....
1476 if (TEST_FLAG(Fdo
->Flags
, DO_VERIFY_VOLUME
) &&
1477 IS_READ_WRITE_REQUEST(currentIrpStack
)) {
1479 TraceLog((CdromDebugTrace
,
1480 "CdRomStartIo: [%p] Volume needs verified\n", Irp
));
1482 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1484 if (Irp
->Tail
.Overlay
.Thread
) {
1485 IoSetHardErrorOrVerifyDevice(Irp
, Fdo
);
1488 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1490 TraceLog((CdromDebugTrace
,
1491 "CdRomStartIo: [%p] Calling UpdateCapcity - "
1492 "ioctl event = %p\n",
1494 nextIrpStack
->Parameters
.Others
.Argument1
1498 // our device control dispatch routine stores an event in the next
1499 // stack location to signal when startio has completed. We need to
1500 // pass this in so that the update capacity completion routine can
1501 // set it rather than completing the Irp.
1504 status
= CdRomUpdateCapacity(fdoExtension
,
1506 nextIrpStack
->Parameters
.Others
.Argument1
1509 TraceLog((CdromDebugTrace
,
1510 "CdRomStartIo: [%p] UpdateCapacity returned %lx\n",
1517 // fail writes if they are not allowed...
1520 if ((currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) &&
1521 !(cdData
->Mmc
.WriteAllowed
)) {
1523 TraceLog((CdromDebugError
,
1524 "CdRomStartIo: [%p] Device %p failing write request\n",
1527 Irp
->IoStatus
.Information
= 0;
1528 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1530 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1534 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
1535 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
1537 ULONG maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
1540 // Add partition byte offset to make starting byte relative to
1541 // beginning of disk.
1544 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+=
1545 (fdoExtension
->CommonExtension
.StartingOffset
.QuadPart
);
1548 // Calculate number of pages in this transfer.
1551 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1552 currentIrpStack
->Parameters
.Read
.Length
);
1555 // Check if request length is greater than the maximum number of
1556 // bytes that the hardware can transfer.
1559 if (cdData
->RawAccess
) {
1562 // a writable device must be MMC compliant, which supports
1563 // READ_CD commands.
1566 ASSERT(currentIrpStack
->MajorFunction
!= IRP_MJ_WRITE
);
1568 ASSERT(!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
));
1571 // Fire off a mode select to switch back to cooked sectors.
1574 irp2
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1), FALSE
);
1577 Irp
->IoStatus
.Information
= 0;
1578 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1581 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1585 srb
= ExAllocatePoolWithTag(NonPagedPool
,
1586 sizeof(SCSI_REQUEST_BLOCK
),
1590 Irp
->IoStatus
.Information
= 0;
1591 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1594 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1598 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1600 cdb
= (PCDB
)srb
->Cdb
;
1603 // Allocate sense buffer.
1606 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1608 CDROM_TAG_SENSE_INFO
);
1613 Irp
->IoStatus
.Information
= 0;
1614 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1617 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1625 IoSetNextIrpStackLocation(irp2
);
1626 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1627 irp2
->IoStatus
.Information
= 0;
1629 irp2
->UserBuffer
= NULL
;
1632 // Save the device object and irp in a private stack location.
1635 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1636 irpStack
->DeviceObject
= Fdo
;
1637 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1640 // The retry count will be in the real Irp, as the retry logic will
1641 // recreate our private irp.
1644 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1647 // Only jam this in if it doesn't exist. The completion routines can
1648 // call StartIo directly in the case of retries and resetting it will
1649 // cause infinite loops.
1652 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1656 // Construct the IRP stack for the lower level driver.
1659 irpStack
= IoGetNextIrpStackLocation(irp2
);
1660 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1661 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1662 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1664 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1665 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1666 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1668 srb
->OriginalRequest
= irp2
;
1669 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1670 srb
->SenseInfoBuffer
= senseBuffer
;
1672 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1674 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1679 ExFreePool(senseBuffer
);
1682 Irp
->IoStatus
.Information
= 0;
1683 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1686 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1691 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1697 if (!irp2
->MdlAddress
) {
1698 ExFreePool(senseBuffer
);
1700 ExFreePool(dataBuffer
);
1702 Irp
->IoStatus
.Information
= 0;
1703 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1706 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1714 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1716 srb
->DataBuffer
= dataBuffer
;
1719 // Set the new block size in the descriptor.
1723 cdData
->BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1724 cdData
->BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1725 cdData
->BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1727 cdData
->BlockDescriptor10
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1728 cdData
->BlockDescriptor10
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1729 cdData
->BlockDescriptor10
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1733 // Move error page into dataBuffer.
1736 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, transferByteCount
);
1739 // Build and send a mode select to switch into raw mode.
1742 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
1743 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
1744 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
1745 srb
->DataTransferLength
= transferByteCount
;
1746 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
1750 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1751 cdb
->MODE_SELECT
.PFBit
= 1;
1752 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1754 srb
->CdbLength
= 10;
1755 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1756 cdb
->MODE_SELECT10
.PFBit
= 1;
1757 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1758 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1762 // Update completion routine.
1765 IoSetCompletionRoutine(irp2
,
1766 CdRomSwitchModeCompletion
,
1772 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
1778 // Request needs to be split. Completion of each portion of the
1779 // request will fire off the next portion. The final request will
1780 // signal Io to send a new request.
1784 fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
- 1;
1786 if(maximumTransferLength
> (transferPages
<< PAGE_SHIFT
)) {
1787 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1791 // Check that the maximum transfer size is not zero
1794 if(maximumTransferLength
== 0) {
1795 maximumTransferLength
= PAGE_SIZE
;
1798 ClassSplitRequest(Fdo
, Irp
, maximumTransferLength
);
1801 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1804 // Allocate an irp, srb and associated structures.
1807 irp2
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1),
1811 Irp
->IoStatus
.Information
= 0;
1812 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1815 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1819 srb
= ExAllocatePoolWithTag(NonPagedPool
,
1820 sizeof(SCSI_REQUEST_BLOCK
),
1824 Irp
->IoStatus
.Information
= 0;
1825 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1828 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1832 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1834 cdb
= (PCDB
)srb
->Cdb
;
1837 // Allocate sense buffer.
1840 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1842 CDROM_TAG_SENSE_INFO
);
1847 Irp
->IoStatus
.Information
= 0;
1848 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1851 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1855 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
1861 IoSetNextIrpStackLocation(irp2
);
1862 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1863 irp2
->IoStatus
.Information
= 0;
1865 irp2
->UserBuffer
= NULL
;
1868 // Save the device object and irp in a private stack location.
1871 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1872 irpStack
->DeviceObject
= Fdo
;
1873 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1876 // The retry count will be in the real Irp, as the retry logic will
1877 // recreate our private irp.
1880 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1883 // Only jam this in if it doesn't exist. The completion routines can
1884 // call StartIo directly in the case of retries and resetting it will
1885 // cause infinite loops.
1888 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1892 // keep track of the new irp as Argument3
1895 nextIrpStack
->Parameters
.Others
.Argument3
= irp2
;
1899 // Construct the IRP stack for the lower level driver.
1902 irpStack
= IoGetNextIrpStackLocation(irp2
);
1903 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1904 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1905 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1907 IoSetCompletionRoutine(irp2
,
1908 CdRomDeviceControlCompletion
,
1914 // Setup those fields that are generic to all requests.
1917 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1918 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1919 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1921 srb
->OriginalRequest
= irp2
;
1922 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1923 srb
->SenseInfoBuffer
= senseBuffer
;
1925 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1928 case IOCTL_CDROM_RAW_READ
: {
1931 // Determine whether the drive is currently in raw or cooked mode,
1932 // and which command to use to read the data.
1935 if (!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
)) {
1937 PRAW_READ_INFO rawReadInfo
=
1938 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1939 ULONG maximumTransferLength
;
1940 ULONG transferPages
;
1942 if (cdData
->RawAccess
) {
1944 ULONG startingSector
;
1945 UCHAR min
, sec
, frame
;
1948 // Free the recently allocated irp, as we don't need it.
1953 cdb
= (PCDB
)srb
->Cdb
;
1954 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
1957 // Calculate starting offset.
1960 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
1961 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1962 maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
1963 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1967 // Determine if request is within limits imposed by miniport.
1969 if (transferByteCount
> maximumTransferLength
||
1970 transferPages
> fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
) {
1973 // The claim is that this won't happen, and is backed up by
1974 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1975 // we get only 4 sector requests.
1978 ExFreePool(senseBuffer
);
1981 Irp
->IoStatus
.Information
= 0;
1982 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1985 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1990 srb
->OriginalRequest
= Irp
;
1991 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
1992 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
1993 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
1994 srb
->DataTransferLength
= transferByteCount
;
1995 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
1996 srb
->CdbLength
= 10;
1997 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1999 if (rawReadInfo
->TrackMode
== CDDA
) {
2000 if (TEST_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
)) {
2002 srb
->CdbLength
= 12;
2004 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
2005 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
2006 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
2007 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
2009 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2010 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2011 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
2012 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
2014 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
2015 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
2017 } else if (TEST_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
)) {
2019 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
2020 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
2021 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
2022 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
2024 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2025 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2027 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
2031 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2032 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2034 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
2035 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
2036 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
2037 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
2039 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
2042 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2044 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2045 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2047 // HACKHACK - REF #0001
2050 // Set up IoCompletion routine address.
2053 IoSetCompletionRoutine(Irp
,
2060 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, Irp
);
2065 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
2066 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2070 ExFreePool(senseBuffer
);
2073 Irp
->IoStatus
.Information
= 0;
2074 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2077 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2082 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2088 if (!irp2
->MdlAddress
) {
2089 ExFreePool(senseBuffer
);
2091 ExFreePool(dataBuffer
);
2093 Irp
->IoStatus
.Information
= 0;
2094 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2097 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2105 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2107 srb
->DataBuffer
= dataBuffer
;
2110 // Set the new block size in the descriptor.
2111 // This will set the block read size to RAW_SECTOR_SIZE
2112 // TODO: Set density code, based on operation
2116 cdData
->BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2117 cdData
->BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2118 cdData
->BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2119 cdData
->BlockDescriptor
.DensityCode
= 0;
2121 cdData
->BlockDescriptor10
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2122 cdData
->BlockDescriptor10
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2123 cdData
->BlockDescriptor10
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2124 cdData
->BlockDescriptor10
.DensityCode
= 0;
2128 // Move error page into dataBuffer.
2131 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, transferByteCount
);
2135 // Build and send a mode select to switch into raw mode.
2138 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2139 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2140 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
2141 srb
->DataTransferLength
= transferByteCount
;
2142 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
2146 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2147 cdb
->MODE_SELECT
.PFBit
= 1;
2148 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2151 srb
->CdbLength
= 10;
2152 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2153 cdb
->MODE_SELECT10
.PFBit
= 1;
2154 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2155 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2159 // Update completion routine.
2162 IoSetCompletionRoutine(irp2
,
2163 CdRomSwitchModeCompletion
,
2173 PRAW_READ_INFO rawReadInfo
=
2174 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2175 ULONG startingSector
;
2178 // Free the recently allocated irp, as we don't need it.
2183 cdb
= (PCDB
)srb
->Cdb
;
2184 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
2188 // Calculate starting offset.
2191 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
2192 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2194 srb
->OriginalRequest
= Irp
;
2195 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2196 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2197 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2198 srb
->DataTransferLength
= transferByteCount
;
2199 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2200 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2201 srb
->CdbLength
= 12;
2202 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2205 // Fill in CDB fields.
2208 cdb
= (PCDB
)srb
->Cdb
;
2211 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2212 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2213 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2216 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2217 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2218 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2219 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2222 // Setup cdb depending upon the sector type we want.
2225 switch (rawReadInfo
->TrackMode
) {
2228 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2229 cdb
->READ_CD
.IncludeUserData
= 1;
2230 cdb
->READ_CD
.HeaderCode
= 3;
2231 cdb
->READ_CD
.IncludeSyncData
= 1;
2236 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2237 cdb
->READ_CD
.IncludeUserData
= 1;
2238 cdb
->READ_CD
.HeaderCode
= 1;
2239 cdb
->READ_CD
.IncludeSyncData
= 1;
2244 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2245 cdb
->READ_CD
.IncludeUserData
= 1;
2246 cdb
->READ_CD
.HeaderCode
= 3;
2247 cdb
->READ_CD
.IncludeSyncData
= 1;
2251 ExFreePool(senseBuffer
);
2253 Irp
->IoStatus
.Information
= 0;
2254 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2257 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2261 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2263 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2264 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2266 // HACKHACK - REF #0001
2269 // Set up IoCompletion routine address.
2272 IoSetCompletionRoutine(Irp
,
2279 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, Irp
);
2284 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2289 // the _EX version does the same thing on the front end
2292 case IOCTL_DISK_GET_LENGTH_INFO
:
2293 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2294 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2295 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
:
2296 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2299 // Issue ReadCapacity to update device extension
2300 // with information for current media.
2303 TraceLog((CdromDebugError
,
2304 "CdRomStartIo: Get drive geometry/length "
2305 "info (%p)\n", Irp
));
2308 // setup remaining srb and cdb parameters.
2311 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2312 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2313 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2314 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2315 srb
->CdbLength
= 10;
2316 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2318 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2319 sizeof(READ_CAPACITY_DATA
),
2320 CDROM_TAG_READ_CAP
);
2322 ExFreePool(senseBuffer
);
2325 Irp
->IoStatus
.Information
= 0;
2326 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2329 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2334 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2335 sizeof(READ_CAPACITY_DATA
),
2340 if (!irp2
->MdlAddress
) {
2341 ExFreePool(senseBuffer
);
2343 ExFreePool(dataBuffer
);
2345 Irp
->IoStatus
.Information
= 0;
2346 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2349 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2357 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2359 srb
->DataBuffer
= dataBuffer
;
2360 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2362 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2366 case IOCTL_CDROM_GET_CONFIGURATION
: {
2368 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer
;
2370 TraceLog((CdromDebugError
,
2371 "CdRomStartIo: Get configuration (%p)\n", Irp
));
2373 if (!cdData
->Mmc
.IsMmc
) {
2374 ExFreePool(senseBuffer
);
2377 Irp
->IoStatus
.Information
= 0;
2378 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
2380 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2384 transferByteCount
= currentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
2386 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2388 CDROM_TAG_GET_CONFIG
);
2390 ExFreePool(senseBuffer
);
2393 Irp
->IoStatus
.Information
= 0;
2394 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2396 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2400 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2405 if (!irp2
->MdlAddress
) {
2406 ExFreePool(dataBuffer
);
2407 ExFreePool(senseBuffer
);
2410 Irp
->IoStatus
.Information
= 0;
2411 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2413 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2417 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2420 // setup remaining srb and cdb parameters
2423 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2424 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2425 srb
->DataTransferLength
= transferByteCount
;
2426 srb
->CdbLength
= 10;
2427 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2428 srb
->DataBuffer
= dataBuffer
;
2430 cdb
->GET_CONFIGURATION
.OperationCode
= SCSIOP_GET_CONFIGURATION
;
2431 cdb
->GET_CONFIGURATION
.AllocationLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2432 cdb
->GET_CONFIGURATION
.AllocationLength
[1] = (UCHAR
)(transferByteCount
& 0xff);
2434 inputBuffer
= (PGET_CONFIGURATION_IOCTL_INPUT
)Irp
->AssociatedIrp
.SystemBuffer
;
2435 cdb
->GET_CONFIGURATION
.StartingFeature
[0] = (UCHAR
)(inputBuffer
->Feature
>> 8);
2436 cdb
->GET_CONFIGURATION
.StartingFeature
[1] = (UCHAR
)(inputBuffer
->Feature
& 0xff);
2437 cdb
->GET_CONFIGURATION
.RequestType
= (UCHAR
)(inputBuffer
->RequestType
);
2439 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2443 case IOCTL_DISK_VERIFY
: {
2445 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2446 LARGE_INTEGER byteOffset
;
2450 if (!cdData
->Mmc
.WriteAllowed
) {
2451 ExFreePool(senseBuffer
);
2454 Irp
->IoStatus
.Information
= 0;
2455 Irp
->IoStatus
.Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2457 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2464 srb
->CdbLength
= 10;
2466 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2469 // Add disk offset to starting sector.
2472 byteOffset
.QuadPart
= commonExtension
->StartingOffset
.QuadPart
+
2473 verifyInfo
->StartingOffset
.QuadPart
;
2476 // Convert byte offset to sector offset.
2479 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> fdoExtension
->SectorShift
);
2482 // Convert ULONG byte count to USHORT sector count.
2485 sectorCount
= (USHORT
)(verifyInfo
->Length
>> fdoExtension
->SectorShift
);
2488 // Move little endian values into CDB in big endian format.
2491 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2492 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2493 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2494 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2496 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2497 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2500 // The verify command is used by the NT FORMAT utility and
2501 // requests are sent down for 5% of the volume size. The
2502 // request timeout value is calculated based on the number of
2503 // sectors verified.
2506 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2507 fdoExtension
->TimeOutValue
;
2509 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2513 case IOCTL_STORAGE_CHECK_VERIFY
:
2514 case IOCTL_DISK_CHECK_VERIFY
:
2515 case IOCTL_CDROM_CHECK_VERIFY
: {
2518 // Since a test unit ready is about to be performed, reset the
2519 // timer value to decrease the opportunities for it to race with
2523 ClassResetMediaChangeTimer(fdoExtension
);
2526 // Set up the SRB/CDB
2530 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2531 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
2532 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2533 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2534 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2537 TraceLog((CdromDebugTrace
,
2538 "CdRomStartIo: [%p] Sending CHECK_VERIFY irp %p\n",
2540 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2544 case IOCTL_DVD_READ_STRUCTURE
: {
2546 CdRomDeviceControlDvdReadStructure(Fdo
, Irp
, irp2
, srb
);
2551 case IOCTL_DVD_END_SESSION
: {
2552 CdRomDeviceControlDvdEndSession(Fdo
, Irp
, irp2
, srb
);
2556 case IOCTL_DVD_START_SESSION
:
2557 case IOCTL_DVD_READ_KEY
: {
2559 CdRomDeviceControlDvdStartSessionReadKey(Fdo
, Irp
, irp2
, srb
);
2565 case IOCTL_DVD_SEND_KEY
:
2566 case IOCTL_DVD_SEND_KEY2
: {
2568 CdRomDeviceControlDvdSendKey (Fdo
, Irp
, irp2
, srb
);
2574 case IOCTL_CDROM_READ_TOC_EX
: {
2576 PCDROM_READ_TOC_EX inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2578 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2580 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2584 ExFreePool(senseBuffer
);
2587 Irp
->IoStatus
.Information
= 0;
2588 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2591 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2596 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2602 if (!irp2
->MdlAddress
) {
2603 ExFreePool(senseBuffer
);
2605 ExFreePool(dataBuffer
);
2607 Irp
->IoStatus
.Information
= 0;
2608 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2611 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2616 // setup the request per user request
2617 // do validity checking in devctl dispatch, not here
2620 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2621 cdb
->READ_TOC
.Msf
= inputBuffer
->Msf
;
2622 cdb
->READ_TOC
.Format2
= inputBuffer
->Format
;
2623 cdb
->READ_TOC
.StartingTrack
= inputBuffer
->SessionTrack
;
2624 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2625 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
)(transferByteCount
& 0xff);
2631 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2634 // do the standard stuff....
2637 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2638 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2639 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2640 srb
->DataTransferLength
= transferByteCount
;
2641 srb
->CdbLength
= 10;
2642 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2643 srb
->DataBuffer
= dataBuffer
;
2645 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2649 case IOCTL_CDROM_GET_LAST_SESSION
:
2650 case IOCTL_CDROM_READ_TOC
: {
2652 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2653 IOCTL_CDROM_GET_LAST_SESSION
) {
2656 // Set format to return first and last session numbers.
2659 cdb
->READ_TOC
.Format
= CDROM_READ_TOC_EX_FORMAT_SESSION
;
2664 // Use MSF addressing
2667 cdb
->READ_TOC
.Msf
= 1;
2673 currentIrpStack
->Parameters
.Read
.Length
>
2674 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2675 currentIrpStack
->Parameters
.Read
.Length
;
2678 // Set size of TOC structure.
2681 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2682 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2685 // setup remaining srb and cdb parameters.
2688 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2689 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2690 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2691 srb
->DataTransferLength
= transferByteCount
;
2692 srb
->CdbLength
= 10;
2693 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2695 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2699 ExFreePool(senseBuffer
);
2702 Irp
->IoStatus
.Information
= 0;
2703 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2706 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2711 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2717 if (!irp2
->MdlAddress
) {
2718 ExFreePool(senseBuffer
);
2720 ExFreePool(dataBuffer
);
2722 Irp
->IoStatus
.Information
= 0;
2723 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2726 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2734 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2736 srb
->DataBuffer
= dataBuffer
;
2737 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2739 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2744 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2746 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2749 // Set up the SRB/CDB
2752 srb
->CdbLength
= 10;
2753 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2755 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2756 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2757 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2759 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2760 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2761 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2763 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2764 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2765 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2766 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2768 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2773 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2775 PSUB_Q_CHANNEL_DATA userChannelData
=
2776 Irp
->AssociatedIrp
.SystemBuffer
;
2777 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2778 Irp
->AssociatedIrp
.SystemBuffer
;
2781 // Allocate buffer for subq channel information.
2784 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2785 sizeof(SUB_Q_CHANNEL_DATA
),
2789 ExFreePool(senseBuffer
);
2792 Irp
->IoStatus
.Information
= 0;
2793 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2796 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2801 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2802 sizeof(SUB_Q_CHANNEL_DATA
),
2807 if (!irp2
->MdlAddress
) {
2808 ExFreePool(senseBuffer
);
2810 ExFreePool(dataBuffer
);
2812 Irp
->IoStatus
.Information
= 0;
2813 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2816 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2824 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2826 srb
->DataBuffer
= dataBuffer
;
2829 // Always logical unit 0, but only use MSF addressing
2830 // for IOCTL_CDROM_CURRENT_POSITION
2833 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2834 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2837 // Return subchannel data
2840 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2843 // Specify format of informatin to return
2846 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2849 // Specify which track to access (only used by Track ISRC reads)
2852 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2853 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2857 // Set size of channel data -- however, this is dependent on
2858 // what information we are requesting (which Format)
2861 switch( inputBuffer
->Format
) {
2863 case IOCTL_CDROM_CURRENT_POSITION
:
2864 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2867 case IOCTL_CDROM_MEDIA_CATALOG
:
2868 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2871 case IOCTL_CDROM_TRACK_ISRC
:
2872 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2876 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2877 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2878 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2879 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2880 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2881 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2882 srb
->DataTransferLength
= transferByteCount
;
2883 srb
->CdbLength
= 10;
2884 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2886 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2891 case IOCTL_CDROM_PAUSE_AUDIO
: {
2893 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2894 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2896 srb
->CdbLength
= 10;
2897 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2898 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2899 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2900 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2902 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2906 case IOCTL_CDROM_RESUME_AUDIO
: {
2908 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2909 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2911 srb
->CdbLength
= 10;
2912 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2913 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2914 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2915 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2917 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2921 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2923 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2924 ULONG logicalBlockAddress
;
2926 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2928 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2929 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2930 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2931 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2932 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2934 srb
->CdbLength
= 10;
2935 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2936 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2937 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2938 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2940 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2945 case IOCTL_CDROM_STOP_AUDIO
: {
2947 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2948 cdb
->START_STOP
.Immediate
= 1;
2949 cdb
->START_STOP
.Start
= 0;
2950 cdb
->START_STOP
.LoadEject
= 0;
2953 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2955 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2956 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2957 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2959 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2963 case IOCTL_CDROM_GET_CONTROL
: {
2965 PAUDIO_OUTPUT audioOutput
;
2966 PCDROM_AUDIO_CONTROL audioControl
= Irp
->AssociatedIrp
.SystemBuffer
;
2969 // Allocate buffer for volume control information.
2972 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2977 ExFreePool(senseBuffer
);
2980 Irp
->IoStatus
.Information
= 0;
2981 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2984 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2989 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2995 if (!irp2
->MdlAddress
) {
2996 ExFreePool(senseBuffer
);
2998 ExFreePool(dataBuffer
);
3000 Irp
->IoStatus
.Information
= 0;
3001 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3004 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3012 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
3013 srb
->DataBuffer
= dataBuffer
;
3015 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
3018 // Setup for either 6 or 10 byte CDBs.
3023 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3024 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3025 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
3028 // Disable block descriptors.
3031 cdb
->MODE_SENSE
.Dbd
= TRUE
;
3036 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
3037 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3038 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
3039 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
3042 // Disable block descriptors.
3045 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
3047 srb
->CdbLength
= 10;
3050 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3051 srb
->DataTransferLength
= MODE_DATA_SIZE
;
3052 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3053 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3054 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3056 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3061 case IOCTL_CDROM_GET_VOLUME
:
3062 case IOCTL_CDROM_SET_VOLUME
: {
3064 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3069 ExFreePool(senseBuffer
);
3072 Irp
->IoStatus
.Information
= 0;
3073 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3076 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3080 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3086 if (!irp2
->MdlAddress
) {
3087 ExFreePool(senseBuffer
);
3089 ExFreePool(dataBuffer
);
3091 Irp
->IoStatus
.Information
= 0;
3092 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3095 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3103 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
3104 srb
->DataBuffer
= dataBuffer
;
3106 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
3111 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3112 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3113 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
3119 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
3120 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3121 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
3122 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
3124 srb
->CdbLength
= 10;
3127 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3128 srb
->DataTransferLength
= MODE_DATA_SIZE
;
3129 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3130 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3131 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3133 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
3136 // Setup a different completion routine as the mode sense data is needed in order
3137 // to send the mode select.
3140 IoSetCompletionRoutine(irp2
,
3141 CdRomSetVolumeIntermediateCompletion
,
3149 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3154 case IOCTL_STORAGE_SET_READ_AHEAD
: {
3156 PSTORAGE_SET_READ_AHEAD readAhead
= Irp
->AssociatedIrp
.SystemBuffer
;
3159 PFOUR_BYTE fourByte
= (PFOUR_BYTE
) &blockAddress
;
3162 // setup the SRB for a set readahead command
3165 cdb
->SET_READ_AHEAD
.OperationCode
= SCSIOP_SET_READ_AHEAD
;
3167 blockAddress
= (ULONG
) (readAhead
->TriggerAddress
.QuadPart
>>
3168 fdoExtension
->SectorShift
);
3170 cdb
->SET_READ_AHEAD
.TriggerLBA
[0] = fourByte
->Byte3
;
3171 cdb
->SET_READ_AHEAD
.TriggerLBA
[1] = fourByte
->Byte2
;
3172 cdb
->SET_READ_AHEAD
.TriggerLBA
[2] = fourByte
->Byte1
;
3173 cdb
->SET_READ_AHEAD
.TriggerLBA
[3] = fourByte
->Byte0
;
3175 blockAddress
= (ULONG
) (readAhead
->TargetAddress
.QuadPart
>>
3176 fdoExtension
->SectorShift
);
3178 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[0] = fourByte
->Byte3
;
3179 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[1] = fourByte
->Byte2
;
3180 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[2] = fourByte
->Byte1
;
3181 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[3] = fourByte
->Byte0
;
3183 srb
->CdbLength
= 12;
3184 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3186 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3187 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3188 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
3190 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3194 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
3195 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
:
3196 case IOCTL_DISK_GET_PARTITION_INFO
:
3197 case IOCTL_DISK_GET_PARTITION_INFO_EX
: {
3200 ASSERT(senseBuffer
);
3204 ExFreePool(senseBuffer
);
3208 // NOTE: should probably update the media's capacity first...
3211 CdromFakePartitionInfo(commonExtension
, Irp
);
3215 case IOCTL_DISK_IS_WRITABLE
: {
3217 TraceLog((CdromDebugWarning
,
3218 "CdRomStartIo: DiskIsWritable (%p) - returning %s\n",
3219 Irp
, (cdData
->Mmc
.WriteAllowed
? "TRUE" : "false")));
3222 ASSERT(senseBuffer
);
3226 ExFreePool(senseBuffer
);
3229 Irp
->IoStatus
.Information
= 0;
3230 if (cdData
->Mmc
.WriteAllowed
) {
3231 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3233 Irp
->IoStatus
.Status
= STATUS_MEDIA_WRITE_PROTECTED
;
3235 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3241 UCHAR uniqueAddress
;
3244 // Just complete the request - CdRomClassIoctlCompletion will take
3245 // care of it for us
3247 // NOTE: THIS IS A SYNCHRONIZATION METHOD!!!
3251 // Acquire a new copy of the lock so that ClassCompleteRequest
3252 // doesn't get confused when we complete the other request while
3253 // holding the lock.
3257 // NOTE: CdRomDeviceControlDispatch/CdRomDeviceControlCompletion
3258 // wait for the event and eventually calls
3259 // IoStartNextPacket()
3263 ASSERT(senseBuffer
);
3267 ExFreePool(senseBuffer
);
3272 ClassAcquireRemoveLock(Fdo
, (PIRP
)&uniqueAddress
);
3273 ClassReleaseRemoveLock(Fdo
, Irp
);
3274 ClassCompleteRequest(Fdo
, Irp
, IO_NO_INCREMENT
);
3275 ClassReleaseRemoveLock(Fdo
, (PIRP
)&uniqueAddress
);
3280 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
||
3281 currentIrpStack
->MajorFunction
== IRP_MJ_FLUSH_BUFFERS
) {
3283 currentIrpStack
->Parameters
.Others
.Argument1
= 0;
3284 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3285 CdRomShutdownFlushCompletion(Fdo
, NULL
, Irp
);
3291 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
3292 // are expected and composed of AutoRun Irps, at present.
3295 IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
3301 CdRomReadWriteVerification(
3302 IN PDEVICE_OBJECT DeviceObject
,
3308 Routine Description:
3310 This is the entry called by the I/O system for read requests.
3311 It builds the SRB and sends it to the port driver.
3315 DeviceObject - the system object for the device.
3325 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
3326 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3328 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3329 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
3330 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3332 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3334 SCSI_REQUEST_BLOCK srb
;
3335 PCDB cdb
= (PCDB
)srb
.Cdb
;
3341 // note: we are no longer failing write commands immediately
3342 // they are now failed in StartIo based upon media ability
3346 // If the cd is playing music then reject this request.
3349 if (PLAY_ACTIVE(fdoExtension
)) {
3350 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
3351 return STATUS_DEVICE_BUSY
;
3355 // Verify parameters of this request.
3356 // Check that ending sector is on disc and
3357 // that number of bytes to transfer is a multiple of
3361 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
3364 if (!fdoExtension
->DiskGeometry
.BytesPerSector
) {
3365 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
3368 if ((startingOffset
.QuadPart
> commonExtension
->PartitionLength
.QuadPart
) ||
3369 (transferByteCount
& fdoExtension
->DiskGeometry
.BytesPerSector
- 1)) {
3372 // Fail request with status of invalid parameters.
3375 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3377 return STATUS_INVALID_PARAMETER
;
3381 return STATUS_SUCCESS
;
3383 } // end CdRomReadWriteVerification()
3387 CdRomSwitchModeCompletion(
3388 IN PDEVICE_OBJECT DeviceObject
,
3393 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
3394 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3396 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3397 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3398 BOOLEAN use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
3399 PIO_STACK_LOCATION realIrpStack
;
3400 PIO_STACK_LOCATION realIrpNextStack
;
3401 PSCSI_REQUEST_BLOCK srb
= Context
;
3402 PIRP realIrp
= NULL
;
3407 // Extract the 'real' irp from the irpstack.
3410 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3411 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3412 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3415 // Check SRB status for success of completing request.
3418 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3420 ULONG retryInterval
;
3422 TraceLog((CdromDebugTrace
,
3423 "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
3429 // Release the queue if it is frozen.
3432 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3433 ClassReleaseQueue(DeviceObject
);
3437 retry
= ClassInterpretSenseInfo(DeviceObject
,
3439 irpStack
->MajorFunction
,
3440 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3441 MAXIMUM_RETRIES
- ((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3446 // If the status is verified required and the this request
3447 // should bypass verify required then retry the request.
3450 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3451 status
== STATUS_VERIFY_REQUIRED
) {
3453 status
= STATUS_IO_DEVICE_ERROR
;
3457 if (retry
&& realIrpNextStack
->Parameters
.Others
.Argument1
--) {
3459 if (((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3465 TraceLog((CdromDebugWarning
,
3466 "Retry request %p - Calling StartIo\n", Irp
));
3469 ExFreePool(srb
->SenseInfoBuffer
);
3470 ExFreePool(srb
->DataBuffer
);
3472 if (Irp
->MdlAddress
) {
3473 IoFreeMdl(Irp
->MdlAddress
);
3479 // Call StartIo directly since IoStartNextPacket hasn't been called,
3480 // the serialisation is still intact.
3483 CdRomRetryRequest(fdoExtension
,
3488 return STATUS_MORE_PROCESSING_REQUIRED
;
3493 // Exhausted retries. Fall through and complete the request with the appropriate status.
3499 // Set status for successful request.
3502 status
= STATUS_SUCCESS
;
3506 if (NT_SUCCESS(status
)) {
3508 ULONG sectorSize
, startingSector
, transferByteCount
;
3512 // Update device ext. to show which mode we are currently using.
3515 sectorSize
= cdData
->BlockDescriptor
.BlockLength
[0] << 16;
3516 sectorSize
|= (cdData
->BlockDescriptor
.BlockLength
[1] << 8);
3517 sectorSize
|= (cdData
->BlockDescriptor
.BlockLength
[2]);
3519 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
3522 // Free the old data buffer, mdl.
3523 // reuse the SenseInfoBuffer and Srb
3526 ExFreePool(srb
->DataBuffer
);
3527 IoFreeMdl(Irp
->MdlAddress
);
3534 cdb
= (PCDB
)srb
->Cdb
;
3535 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3538 if (cdData
->RawAccess
) {
3540 PRAW_READ_INFO rawReadInfo
=
3541 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
3543 ULONG maximumTransferLength
;
3544 ULONG transferPages
;
3545 UCHAR min
, sec
, frame
;
3548 // Calculate starting offset.
3551 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
3552 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
3553 maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
3554 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3558 // Determine if request is within limits imposed by miniport.
3559 // If the request is larger than the miniport's capabilities, split it.
3562 if (transferByteCount
> maximumTransferLength
||
3563 transferPages
> fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
) {
3566 ExFreePool(srb
->SenseInfoBuffer
);
3568 realIrp
->IoStatus
.Information
= 0;
3569 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3572 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
3573 return STATUS_MORE_PROCESSING_REQUIRED
;
3576 srb
->OriginalRequest
= realIrp
;
3577 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3578 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3579 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3581 srb
->DataTransferLength
= transferByteCount
;
3582 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3583 srb
->CdbLength
= 10;
3584 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
3586 if (rawReadInfo
->TrackMode
== CDDA
) {
3587 if (TEST_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
)) {
3589 srb
->CdbLength
= 12;
3591 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3592 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3593 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3594 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3596 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3597 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3598 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
3599 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
3601 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
3602 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
3604 } else if (TEST_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
)) {
3606 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3607 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3608 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3609 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3611 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3612 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3614 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
3617 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3618 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3620 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3621 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3622 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3623 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3625 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3628 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3631 irpStack
= IoGetNextIrpStackLocation(realIrp
);
3632 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3633 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3635 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
3638 // Only jam this in if it doesn't exist. The completion routines can
3639 // call StartIo directly in the case of retries and resetting it will
3640 // cause infinite loops.
3643 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
3647 // Set up IoCompletion routine address.
3650 IoSetCompletionRoutine(realIrp
,
3658 PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor
;
3659 ULONG maximumTransferLength
;
3660 ULONG transferPages
;
3663 // a writable device must be MMC compliant, which supports
3664 // READ_CD commands, so writes and mode switching should
3665 // never occur on the same device.
3668 ASSERT(realIrpStack
->MajorFunction
!= IRP_MJ_WRITE
);
3671 // free the SRB and SenseInfoBuffer since they aren't used
3672 // by either ClassBuildRequest() nor ClassSplitRequest().
3675 ExFreePool(srb
->SenseInfoBuffer
);
3679 // Back to cooked sectors. Build and send a normal read.
3680 // The real work for setting offsets was done in startio.
3684 commonExtension
->PartitionZeroExtension
->AdapterDescriptor
;
3685 maximumTransferLength
= adapterDescriptor
->MaximumTransferLength
;
3686 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3687 MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3688 realIrpStack
->Parameters
.Read
.Length
);
3690 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
3691 (transferPages
> adapterDescriptor
->MaximumPhysicalPages
)) {
3693 ULONG maxPages
= adapterDescriptor
->MaximumPhysicalPages
;
3695 if (maxPages
!= 0) {
3696 maxPages
--; // to account for page boundaries
3699 TraceLog((CdromDebugTrace
,
3700 "CdromSwitchModeCompletion: Request greater than "
3702 TraceLog((CdromDebugTrace
,
3703 "CdromSwitchModeCompletion: Maximum is %lx\n",
3704 maximumTransferLength
));
3705 TraceLog((CdromDebugTrace
,
3706 "CdromSwitchModeCompletion: Byte count is %lx\n",
3707 realIrpStack
->Parameters
.Read
.Length
));
3710 // Check that the maximum transfer length fits within
3711 // the maximum number of pages the device can handle.
3714 if (maximumTransferLength
> maxPages
<< PAGE_SHIFT
) {
3715 maximumTransferLength
= maxPages
<< PAGE_SHIFT
;
3719 // Check that maximum transfer size is not zero
3722 if (maximumTransferLength
== 0) {
3723 maximumTransferLength
= PAGE_SIZE
;
3727 // Request needs to be split. Completion of each portion
3728 // of the request will fire off the next portion. The final
3729 // request will signal Io to send a new request.
3732 ClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
3733 return STATUS_MORE_PROCESSING_REQUIRED
;
3738 // Build SRB and CDB for this IRP.
3741 ClassBuildRequest(DeviceObject
, realIrp
);
3747 // Call the port driver.
3750 IoCallDriver(commonExtension
->LowerDeviceObject
, realIrp
);
3752 return STATUS_MORE_PROCESSING_REQUIRED
;
3756 // Update device Extension flags to indicate that XA isn't supported.
3759 TraceLog((CdromDebugWarning
,
3760 "Device Cannot Support CDDA (but tested positive) "
3761 "Now Clearing CDDA flags for FDO %p\n", DeviceObject
));
3762 SET_FLAG(cdData
->XAFlags
, XA_NOT_SUPPORTED
);
3763 CLEAR_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
);
3764 CLEAR_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
);
3767 // Deallocate srb and sense buffer.
3771 if (srb
->DataBuffer
) {
3772 ExFreePool(srb
->DataBuffer
);
3774 if (srb
->SenseInfoBuffer
) {
3775 ExFreePool(srb
->SenseInfoBuffer
);
3780 if (Irp
->PendingReturned
) {
3781 IoMarkIrpPending(Irp
);
3784 if (realIrp
->PendingReturned
) {
3785 IoMarkIrpPending(realIrp
);
3788 if (Irp
->MdlAddress
) {
3789 IoFreeMdl(Irp
->MdlAddress
);
3795 // Set status in completing IRP.
3798 realIrp
->IoStatus
.Status
= status
;
3801 // Set the hard error if necessary.
3804 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3807 // Store DeviceObject for filesystem, and clear
3808 // in IoStatus.Information field.
3811 if (realIrp
->Tail
.Overlay
.Thread
) {
3812 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3814 realIrp
->IoStatus
.Information
= 0;
3817 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
3819 return STATUS_MORE_PROCESSING_REQUIRED
;
3824 ScanForSpecialHandler(
3825 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
3829 PCOMMON_DEVICE_EXTENSION commonExtension
;
3834 CLEAR_FLAG(HackFlags
, CDROM_HACK_INVALID_FLAGS
);
3836 commonExtension
= &(FdoExtension
->CommonExtension
);
3837 cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3838 cdData
->HackFlags
= HackFlags
;
3845 PDEVICE_OBJECT DeviceObject
3850 Routine Description:
3852 This function checks to see if an SCSI logical unit requires an special
3853 initialization or error processing.
3857 DeviceObject - Supplies the device object to be tested.
3859 InquiryData - Supplies the inquiry data returned by the device of interest.
3861 PortCapabilities - Supplies the capabilities of the device object.
3870 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
3871 PCOMMON_DEVICE_EXTENSION commonExtension
;
3876 fdoExtension
= DeviceObject
->DeviceExtension
;
3877 commonExtension
= DeviceObject
->DeviceExtension
;
3878 cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3882 // set our hack flags
3885 ClassScanForSpecial(fdoExtension
, CdromHackItems
, ScanForSpecialHandler
);
3888 // All CDRom's can ignore the queue lock failure for power operations
3889 // and do not require handling the SpinUp case (unknown result of sending
3890 // a cdrom a START_UNIT command -- may eject disks?)
3892 // We send the stop command mostly to stop outstanding asynch operations
3893 // (like audio playback) from running when the system is powered off.
3894 // Because of this and the unlikely chance that a PLAY command will be
3895 // sent in the window between the STOP and the time the machine powers down
3896 // we don't require queue locks. This is important because without them
3897 // classpnp's power routines will send the START_STOP_UNIT command to the
3898 // device whether or not it supports locking (atapi does not support locking
3899 // and if we requested them we would end up not stopping audio on atapi
3903 SET_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_SPIN_UP
);
3904 SET_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_NO_QUEUE_LOCK
);
3906 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_1750
)
3907 && ( fdoExtension
->AdapterDescriptor
->AdapterUsesPio
)
3911 // Read-ahead must be disabled in order to get this cdrom drive
3912 // to work on scsi adapters that use PIO.
3916 TraceLog((CdromDebugWarning
,
3917 "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
3920 // Setup an error handler to reinitialize the cd rom after it is reset.
3923 cdData
->ErrorHandler
= HitachiProcessError
;
3926 // Lock down the hitachi error processing code.
3929 MmLockPagableCodeSection(HitachiProcessError
);
3930 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
3933 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_SD_W1101
)) {
3935 TraceLog((CdromDebugError
,
3936 "CdRom ScanForSpecial: Found Toshiba SD-W1101 DVD-RAM "
3937 "-- This drive will *NOT* support DVD-ROM playback.\n"));
3939 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_GD_2000
)) {
3941 TraceLog((CdromDebugWarning
,
3942 "CdRom ScanForSpecial: Found Hitachi GD-2000\n"));
3945 // Setup an error handler to spin up the drive when it idles out
3946 // since it seems to like to fail to spin itself back up on its
3947 // own for a REPORT_KEY command. It may also lose the AGIDs that
3948 // it has given, which will result in DVD playback failures.
3949 // This routine will just do what it can...
3952 cdData
->ErrorHandler
= HitachiProcessErrorGD2000
;
3955 // this drive may require START_UNIT commands to spin
3956 // the drive up when it's spun itself down.
3959 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
3962 // Lock down the hitachi error processing code.
3965 MmLockPagableCodeSection(HitachiProcessErrorGD2000
);
3966 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
3968 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_FUJITSU_FMCD_10x
)) {
3971 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
3972 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
3976 fdoExtension
->TimeOutValue
= 20;
3978 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_DEC_RRD
)) {
3980 PMODE_PARM_READ_WRITE_DATA modeParameters
;
3981 SCSI_REQUEST_BLOCK srb
;
3986 TraceLog((CdromDebugWarning
,
3987 "CdRom ScanForSpecial: Found DEC RRD.\n"));
3989 cdData
->IsDecRrd
= TRUE
;
3992 // Setup an error handler to reinitialize the cd rom after it is reset?
3994 //commonExtension->DevInfo->ClassError = DecRrdProcessError;
3997 // Found a DEC RRD cd-rom. These devices do not pass MS HCT
3998 // multi-media tests because the DEC firmware modifieds the block
3999 // from the PC-standard 2K to 512. Change the block transfer size
4000 // back to the PC-standard 2K by using a mode select command.
4003 modeParameters
= ExAllocatePoolWithTag(NonPagedPool
,
4004 sizeof(MODE_PARM_READ_WRITE_DATA
),
4007 if (modeParameters
== NULL
) {
4011 RtlZeroMemory(modeParameters
, sizeof(MODE_PARM_READ_WRITE_DATA
));
4012 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4015 // Set the block length to 2K.
4018 modeParameters
->ParameterListHeader
.BlockDescriptorLength
=
4019 sizeof(MODE_PARAMETER_BLOCK
);
4022 // Set block length to 2K (0x0800) in Parameter Block.
4025 modeParameters
->ParameterListBlock
.BlockLength
[0] = 0x00; //MSB
4026 modeParameters
->ParameterListBlock
.BlockLength
[1] = 0x08;
4027 modeParameters
->ParameterListBlock
.BlockLength
[2] = 0x00; //LSB
4030 // Build the mode select CDB.
4034 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4036 cdb
= (PCDB
)srb
.Cdb
;
4037 cdb
->MODE_SELECT
.PFBit
= 1;
4038 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4039 cdb
->MODE_SELECT
.ParameterListLength
= HITACHI_MODE_DATA_SIZE
;
4042 // Send the request to the device.
4045 status
= ClassSendSrbSynchronous(DeviceObject
,
4048 sizeof(MODE_PARM_READ_WRITE_DATA
),
4051 if (!NT_SUCCESS(status
)) {
4052 TraceLog((CdromDebugWarning
,
4053 "CdRom ScanForSpecial: Setting DEC RRD to 2K block"
4054 "size failed [%x]\n", status
));
4056 ExFreePool(modeParameters
);
4058 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_XM_3xx
)) {
4060 SCSI_REQUEST_BLOCK srb
;
4067 // Set the density code and the error handler.
4070 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
4072 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4075 // Build the MODE SENSE CDB.
4079 cdb
= (PCDB
)srb
.Cdb
;
4082 // Set timeout value from device extension.
4085 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4087 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
4088 cdb
->MODE_SENSE
.PageCode
= 0x1;
4089 // NOTE: purposely not setting DBD because it is what is needed.
4090 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
4092 buffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4093 (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
),
4094 CDROM_TAG_MODE_DATA
);
4099 status
= ClassSendSrbSynchronous(DeviceObject
,
4105 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
4106 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
4108 RtlCopyMemory(&cdData
->Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
4110 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4113 // Build the MODE SENSE CDB.
4117 cdb
= (PCDB
)srb
.Cdb
;
4120 // Set timeout value from device extension.
4123 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4125 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4126 cdb
->MODE_SELECT
.PFBit
= 1;
4127 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4129 status
= ClassSendSrbSynchronous(DeviceObject
,
4135 if (!NT_SUCCESS(status
)) {
4136 TraceLog((CdromDebugWarning
,
4137 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4141 cdData
->ErrorHandler
= ToshibaProcessError
;
4144 // Lock down the toshiba error section.
4147 MmLockPagableCodeSection(ToshibaProcessError
);
4148 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
4155 // Determine special CD-DA requirements.
4158 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_READ_CD_SUPPORTED
)) {
4160 SET_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
);
4162 } else if (!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
)) {
4164 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_PLEXTOR_CDDA
)) {
4165 SET_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
);
4166 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_NEC_CDDA
)) {
4167 SET_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
);
4172 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
)) {
4173 KdPrintEx((DPFLTR_SYSTEM_ID
, DPFLTR_ERROR_LEVEL
,
4174 "Locking pages for error handler\n"));
4183 HitachiProcessErrorGD2000(
4185 PSCSI_REQUEST_BLOCK OriginalSrb
,
4191 Routine Description:
4193 This routine checks the type of error. If the error suggests that the
4194 drive has spun down and cannot reinitialize itself, send a
4195 START_UNIT or READ to the device. This will force the drive to spin
4196 up. This drive also loses the AGIDs it has granted when it spins down,
4197 which may result in playback failure the first time around.
4201 DeviceObject - Supplies a pointer to the device object.
4203 Srb - Supplies a pointer to the failing Srb.
4205 Status - return the final status for this command?
4207 Retry - return if the command should be retried.
4215 PSENSE_DATA senseBuffer
= OriginalSrb
->SenseInfoBuffer
;
4217 UNREFERENCED_PARAMETER(Status
);
4218 UNREFERENCED_PARAMETER(Retry
);
4220 if (!TEST_FLAG(OriginalSrb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
4224 if (((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_HARDWARE_ERROR
) &&
4225 (senseBuffer
->AdditionalSenseCode
== 0x44)) {
4227 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
4229 PIO_STACK_LOCATION irpStack
;
4230 PCOMPLETION_CONTEXT context
;
4231 PSCSI_REQUEST_BLOCK newSrb
;
4234 TraceLog((CdromDebugWarning
,
4235 "HitachiProcessErrorGD2000 (%p) => Internal Target "
4236 "Failure Detected -- spinning up drive\n", Fdo
));
4239 // the request should be retried because the device isn't ready
4243 *Status
= STATUS_DEVICE_NOT_READY
;
4246 // send a START_STOP unit to spin up the drive
4247 // NOTE: this temporarily violates the StartIo serialization
4248 // mechanism, but the completion routine on this will NOT
4249 // call StartNextPacket(), so it's a temporary disruption
4250 // of the serialization only.
4253 ClassSendStartUnit(Fdo
);
4262 HitachiProcessError(
4263 PDEVICE_OBJECT DeviceObject
,
4264 PSCSI_REQUEST_BLOCK Srb
,
4270 Routine Description:
4272 This routine checks the type of error. If the error indicates CD-ROM the
4273 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
4274 device. This command disables read-ahead for the device.
4278 DeviceObject - Supplies a pointer to the device object.
4280 Srb - Supplies a pointer to the failing Srb.
4293 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4294 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
4295 LARGE_INTEGER largeInt
;
4297 PIO_STACK_LOCATION irpStack
;
4299 PSCSI_REQUEST_BLOCK srb
;
4300 PCOMPLETION_CONTEXT context
;
4302 ULONG_PTR alignment
;
4304 UNREFERENCED_PARAMETER(Status
);
4305 UNREFERENCED_PARAMETER(Retry
);
4307 largeInt
.QuadPart
= (LONGLONG
) 1;
4310 // Check the status. The initialization command only needs to be sent
4311 // if UNIT ATTENTION is returned.
4314 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
4317 // The drive does not require reinitialization.
4324 // Found an HITACHI cd-rom that does not work with PIO
4325 // adapters when read-ahead is enabled. Read-ahead is disabled by
4326 // a mode select command. The mode select page code is zero and the
4327 // length is 6 bytes. All of the other bytes should be zero.
4330 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
4332 TraceLog((CdromDebugWarning
,
4333 "HitachiProcessError: Reinitializing the CD-ROM.\n"));
4336 // Send the special mode select command to disable read-ahead
4337 // on the CD-ROM reader.
4340 alignment
= DeviceObject
->AlignmentRequirement
?
4341 DeviceObject
->AlignmentRequirement
: 1;
4343 context
= ExAllocatePoolWithTag(
4345 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ (ULONG
)alignment
,
4346 CDROM_TAG_HITACHI_ERROR
4349 if (context
== NULL
) {
4352 // If there is not enough memory to fulfill this request,
4353 // simply return. A subsequent retry will fail and another
4354 // chance to start the unit.
4360 context
->DeviceObject
= DeviceObject
;
4361 srb
= &context
->Srb
;
4363 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4366 // Write length to SRB.
4369 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4372 // Set up SCSI bus address.
4375 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4376 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
4379 // Set the transfer length.
4382 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
4383 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
4384 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
4385 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_AUTOSENSE
);
4386 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
4389 // The data buffer must be aligned.
4392 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
4397 // Build the HITACHI read-ahead mode select CDB.
4401 cdb
= (PCDB
)srb
->Cdb
;
4402 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
4403 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
4404 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
4407 // Initialize the mode sense data.
4410 modePage
= srb
->DataBuffer
;
4412 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
4415 // Set the page length field to 6.
4421 // Build the asynchronous request to be sent to the port driver.
4424 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
4427 srb
->DataTransferLength
,
4434 // If there is not enough memory to fulfill this request,
4435 // simply return. A subsequent retry will fail and another
4436 // chance to start the unit.
4439 ExFreePool(context
);
4443 ClassAcquireRemoveLock(DeviceObject
, irp
);
4445 IoSetCompletionRoutine(irp
,
4446 (PIO_COMPLETION_ROUTINE
)ClassAsynchronousCompletion
,
4452 irpStack
= IoGetNextIrpStackLocation(irp
);
4454 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4456 srb
->OriginalRequest
= irp
;
4459 // Save SRB address in next stack for port driver.
4462 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
4465 // Set up IRP Address.
4468 (VOID
)IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp
);
4475 ToshibaProcessErrorCompletion(
4476 PDEVICE_OBJECT DeviceObject
,
4483 Routine Description:
4485 Completion routine for the ClassError routine to handle older Toshiba units
4486 that require setting the density code.
4490 DeviceObject - Supplies a pointer to the device object.
4492 Irp - Pointer to irp created to set the density code.
4494 Context - Supplies a pointer to the Mode Select Srb.
4499 STATUS_MORE_PROCESSING_REQUIRED
4505 PSCSI_REQUEST_BLOCK srb
= Context
;
4508 // Free all of the allocations.
4511 ClassReleaseRemoveLock(DeviceObject
, Irp
);
4513 ExFreePool(srb
->DataBuffer
);
4515 IoFreeMdl(Irp
->MdlAddress
);
4519 // Indicate the I/O system should stop processing the Irp completion.
4522 return STATUS_MORE_PROCESSING_REQUIRED
;
4527 ToshibaProcessError(
4528 PDEVICE_OBJECT DeviceObject
,
4529 PSCSI_REQUEST_BLOCK Srb
,
4536 Routine Description:
4538 This routine checks the type of error. If the error indicates a unit attention,
4539 the density code needs to be set via a Mode select command.
4543 DeviceObject - Supplies a pointer to the device object.
4545 Srb - Supplies a pointer to the failing Srb.
4558 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4559 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
4561 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
4562 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
4563 PIO_STACK_LOCATION irpStack
;
4565 PSCSI_REQUEST_BLOCK srb
;
4571 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
4576 // The Toshiba's require the density code to be set on power up and media changes.
4579 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
4582 irp
= IoAllocateIrp((CCHAR
)(DeviceObject
->StackSize
+1),
4589 srb
= ExAllocatePoolWithTag(NonPagedPool
,
4590 sizeof(SCSI_REQUEST_BLOCK
),
4591 CDROM_TAG_TOSHIBA_ERROR
);
4598 length
= sizeof(ERROR_RECOVERY_DATA
);
4599 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4601 CDROM_TAG_TOSHIBA_ERROR
);
4608 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
4614 if (!irp
->MdlAddress
) {
4616 ExFreePool(dataBuffer
);
4625 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
4627 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
4629 srb
->DataBuffer
= dataBuffer
;
4630 cdb
= (PCDB
)srb
->Cdb
;
4636 IoSetNextIrpStackLocation(irp
);
4637 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4638 irp
->IoStatus
.Information
= 0;
4640 irp
->UserBuffer
= NULL
;
4643 // Save the device object and irp in a private stack location.
4646 irpStack
= IoGetCurrentIrpStackLocation(irp
);
4647 irpStack
->DeviceObject
= DeviceObject
;
4650 // Construct the IRP stack for the lower level driver.
4653 irpStack
= IoGetNextIrpStackLocation(irp
);
4654 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
4655 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
4656 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4658 IoSetCompletionRoutine(irp
,
4659 ToshibaProcessErrorCompletion
,
4665 ClassAcquireRemoveLock(DeviceObject
, irp
);
4667 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4668 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4669 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
4671 srb
->OriginalRequest
= irp
;
4672 srb
->SenseInfoBufferLength
= 0;
4675 // Set the transfer length.
4678 srb
->DataTransferLength
= length
;
4679 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
4680 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
4681 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_AUTOSENSE
);
4682 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
4683 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
4687 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4688 cdb
->MODE_SELECT
.PFBit
= 1;
4689 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4692 // Copy the Mode page into the databuffer.
4695 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, length
);
4698 // Set the density code.
4701 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
4703 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp
);
4710 IN PDEVICE_OBJECT DeviceObject
4715 Routine Description:
4717 This routine determines if the cd is currently playing music.
4721 DeviceObject - Device object to test.
4725 TRUE if the device is playing music.
4729 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4730 IO_STATUS_BLOCK ioStatus
;
4731 PSUB_Q_CURRENT_POSITION currentBuffer
;
4736 // if we don't think it is playing audio, don't bother checking.
4739 if (!PLAY_ACTIVE(fdoExtension
)) {
4743 currentBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4744 sizeof(SUB_Q_CURRENT_POSITION
),
4745 CDROM_TAG_PLAY_ACTIVE
);
4747 if (currentBuffer
== NULL
) {
4751 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
4752 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
4755 // Build the synchronous request to be sent to ourself
4756 // to perform the request.
4759 ClassSendDeviceIoControlSynchronous(
4760 IOCTL_CDROM_READ_Q_CHANNEL
,
4763 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
4764 sizeof(SUB_Q_CURRENT_POSITION
),
4768 if (!NT_SUCCESS(ioStatus
.Status
)) {
4769 ExFreePool(currentBuffer
);
4774 // should update the playactive flag here.
4777 if (currentBuffer
->Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
4778 PLAY_ACTIVE(fdoExtension
) = TRUE
;
4780 PLAY_ACTIVE(fdoExtension
) = FALSE
;
4783 ExFreePool(currentBuffer
);
4785 return(PLAY_ACTIVE(fdoExtension
));
4792 IN PDEVICE_OBJECT DeviceObject
4797 Routine Description:
4799 This routine handles the once per second timer provided by the
4800 Io subsystem. It is used to do delayed retries for cdroms.
4804 DeviceObject - what to check.
4813 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4814 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
4823 PLIST_ENTRY listEntry
;
4825 PIO_STACK_LOCATION irpStack
;
4826 UCHAR uniqueAddress
;
4828 isRemoved
= ClassAcquireRemoveLock(DeviceObject
, (PIRP
) &uniqueAddress
);
4831 // We stop the timer before deleting the device. It's safe to keep going
4832 // if the flag value is REMOVE_PENDING because the removal thread will be
4833 // blocked trying to stop the timer.
4836 ASSERT(isRemoved
!= REMOVE_COMPLETE
);
4839 // This routine is reasonably safe even if the device object has a pending
4842 cddata
= commonExtension
->DriverData
;
4845 // Since cdrom is completely synchronized there can never be more than one
4846 // irp delayed for retry at any time.
4849 KeAcquireSpinLock(&(cddata
->DelayedRetrySpinLock
), &oldIrql
);
4851 if(cddata
->DelayedRetryIrp
!= NULL
) {
4853 PIRP irp
= cddata
->DelayedRetryIrp
;
4856 // If we've got a delayed retry at this point then there had beter
4857 // be an interval for it.
4860 ASSERT(cddata
->DelayedRetryInterval
!= 0);
4861 cddata
->DelayedRetryInterval
--;
4866 // This device is removed - flush the timer queue
4869 cddata
->DelayedRetryIrp
= NULL
;
4870 cddata
->DelayedRetryInterval
= 0;
4872 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4874 ClassReleaseRemoveLock(DeviceObject
, irp
);
4875 ClassCompleteRequest(DeviceObject
, irp
, IO_CD_ROM_INCREMENT
);
4877 } else if (cddata
->DelayedRetryInterval
== 0) {
4880 // Submit this IRP to the lower driver. This IRP does not
4881 // need to be remembered here. It will be handled again when
4885 cddata
->DelayedRetryIrp
= NULL
;
4887 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4889 TraceLog((CdromDebugWarning
,
4890 "CdRomTickHandler: Reissuing request %p (thread = %p)\n",
4892 irp
->Tail
.Overlay
.Thread
));
4895 // feed this to the appropriate port driver
4898 CdRomRerunRequest(fdoExtension
, irp
, cddata
->DelayedRetryResend
);
4900 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4903 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4906 ClassReleaseRemoveLock(DeviceObject
, (PIRP
) &uniqueAddress
);
4911 CdRomUpdateGeometryCompletion(
4912 PDEVICE_OBJECT DeviceObject
,
4919 Routine Description:
4921 This routine andles the completion of the test unit ready irps
4922 used to determine if the media has changed. If the media has
4923 changed, this code signals the named event to wake up other
4924 system services that react to media change (aka AutoPlay).
4928 DeviceObject - the object for the completion
4929 Irp - the IRP being completed
4930 Context - the SRB from the IRP
4939 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
4940 PCOMMON_DEVICE_EXTENSION commonExtension
;
4942 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
4943 PREAD_CAPACITY_DATA readCapacityBuffer
;
4944 PIO_STACK_LOCATION irpStack
;
4951 UCHAR uniqueAddress
;
4954 // Get items saved in the private IRP stack location.
4957 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4958 retryCount
= (ULONG
)(ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
4959 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
4961 if (!DeviceObject
) {
4962 DeviceObject
= irpStack
->DeviceObject
;
4964 ASSERT(DeviceObject
);
4966 fdoExtension
= DeviceObject
->DeviceExtension
;
4967 commonExtension
= DeviceObject
->DeviceExtension
;
4968 cddata
= commonExtension
->DriverData
;
4969 readCapacityBuffer
= srb
->DataBuffer
;
4971 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
4973 CdRomInterpretReadCapacity(DeviceObject
, readCapacityBuffer
);
4977 ULONG retryInterval
;
4979 TraceLog((CdromDebugWarning
,
4980 "CdRomUpdateGeometryCompletion: [%p] unsuccessful "
4981 "completion of buddy-irp %p (status - %lx)\n",
4982 originalIrp
, Irp
, Irp
->IoStatus
.Status
));
4984 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4985 ClassReleaseQueue(DeviceObject
);
4988 retry
= ClassInterpretSenseInfo(DeviceObject
,
4997 if ((retryCount
) && (commonExtension
->IsRemoved
== NO_REMOVE
)) {
5000 TraceLog((CdromDebugWarning
,
5001 "CdRomUpdateGeometryCompletion: [%p] Retrying "
5002 "request %p .. thread is %p\n",
5003 originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
5006 // set up a one shot timer to get this process started over
5009 irpStack
->Parameters
.Others
.Argument1
= ULongToPtr( retryCount
);
5010 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
5011 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
5014 // Setup the IRP to be submitted again in the timer routine.
5017 irpStack
= IoGetNextIrpStackLocation(Irp
);
5018 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5019 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
5020 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5021 IoSetCompletionRoutine(Irp
,
5022 CdRomUpdateGeometryCompletion
,
5029 // Set up the SRB for read capacity.
5032 srb
->CdbLength
= 10;
5033 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
5034 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5036 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5037 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5038 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
5039 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
5040 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
5041 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
5047 cdb
= (PCDB
) &srb
->Cdb
[0];
5048 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
5051 // Requests queued onto this list will be sent to the
5052 // lower level driver during CdRomTickHandler
5055 CdRomRetryRequest(fdoExtension
, Irp
, retryInterval
, TRUE
);
5057 return STATUS_MORE_PROCESSING_REQUIRED
;
5060 if (commonExtension
->IsRemoved
!= NO_REMOVE
) {
5063 // We cannot retry the request. Fail it.
5066 originalIrp
->IoStatus
.Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
5071 // This has been bounced for a number of times. Error the
5072 // original request.
5075 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
5076 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5077 sizeof(DISK_GEOMETRY
));
5078 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5079 fdoExtension
->SectorShift
= 11;
5080 commonExtension
->PartitionLength
.QuadPart
=
5081 (LONGLONG
)(0x7fffffff);
5082 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5087 // Set up reasonable defaults
5090 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5091 sizeof(DISK_GEOMETRY
));
5092 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5093 fdoExtension
->SectorShift
= 11;
5094 commonExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
5095 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5100 // Free resources held.
5103 ExFreePool(srb
->SenseInfoBuffer
);
5104 ExFreePool(srb
->DataBuffer
);
5106 if (Irp
->MdlAddress
) {
5107 IoFreeMdl(Irp
->MdlAddress
);
5112 if (originalIrp
->Tail
.Overlay
.Thread
) {
5114 TraceLog((CdromDebugTrace
,
5115 "CdRomUpdateGeometryCompletion: [%p] completing "
5116 "original IRP\n", originalIrp
));
5120 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
5121 "CdRomUpdateGeometryCompletion: completing irp %p which has "
5122 "no thread\n", originalIrp
));
5127 // NOTE: should the original irp be sent down to the device object?
5128 // it probably should if the SL_OVERRIDER_VERIFY_VOLUME flag
5131 PIO_STACK_LOCATION realIrpStack
;
5133 realIrpStack
= IoGetCurrentIrpStackLocation(originalIrp
);
5134 oldIrql
= KeRaiseIrqlToDpcLevel();
5136 if (TEST_FLAG(realIrpStack
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
)) {
5137 CdRomStartIo(DeviceObject
, originalIrp
);
5139 originalIrp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
5140 originalIrp
->IoStatus
.Information
= 0;
5141 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, originalIrp
);
5143 KeLowerIrql(oldIrql
);
5146 return STATUS_MORE_PROCESSING_REQUIRED
;
5151 CdRomUpdateCapacity(
5152 IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension
,
5153 IN PIRP IrpToComplete
,
5154 IN OPTIONAL PKEVENT IoctlEvent
5159 Routine Description:
5161 This routine updates the capacity of the disk as recorded in the device extension.
5162 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
5163 when a media change has occurred and it is necessary to determine the capacity of the
5164 new media prior to the next access.
5168 DeviceExtension - the device to update
5169 IrpToComplete - the request that needs to be completed when done.
5178 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
) DeviceExtension
;
5179 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
) DeviceExtension
;
5183 PSCSI_REQUEST_BLOCK srb
;
5184 PREAD_CAPACITY_DATA capacityBuffer
;
5185 PIO_STACK_LOCATION irpStack
;
5189 irp
= IoAllocateIrp((CCHAR
)(commonExtension
->DeviceObject
->StackSize
+1),
5194 srb
= ExAllocatePoolWithTag(NonPagedPool
,
5195 sizeof(SCSI_REQUEST_BLOCK
),
5196 CDROM_TAG_UPDATE_CAP
);
5198 capacityBuffer
= ExAllocatePoolWithTag(
5199 NonPagedPoolCacheAligned
,
5200 sizeof(READ_CAPACITY_DATA
),
5201 CDROM_TAG_UPDATE_CAP
);
5203 if (capacityBuffer
) {
5206 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
5208 CDROM_TAG_UPDATE_CAP
);
5212 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
5213 sizeof(READ_CAPACITY_DATA
),
5218 if (irp
->MdlAddress
) {
5221 // Have all resources. Set up the IRP to send for the capacity.
5224 IoSetNextIrpStackLocation(irp
);
5225 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5226 irp
->IoStatus
.Information
= 0;
5228 irp
->UserBuffer
= NULL
;
5231 // Save the device object and retry count in a private stack location.
5234 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5235 irpStack
->DeviceObject
= commonExtension
->DeviceObject
;
5236 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
5237 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
5240 // Construct the IRP stack for the lower level driver.
5243 irpStack
= IoGetNextIrpStackLocation(irp
);
5244 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5245 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
5246 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5247 IoSetCompletionRoutine(irp
,
5248 CdRomUpdateGeometryCompletion
,
5257 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5261 // Set up the SRB for read capacity.
5264 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5265 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
5266 srb
->CdbLength
= 10;
5267 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
5268 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5270 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5271 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5272 srb
->SrbFlags
= DeviceExtension
->SrbFlags
;
5273 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
5274 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
5275 srb
->DataBuffer
= capacityBuffer
;
5276 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
5277 srb
->OriginalRequest
= irp
;
5278 srb
->SenseInfoBuffer
= senseBuffer
;
5279 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
5285 cdb
= (PCDB
) &srb
->Cdb
[0];
5286 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
5289 // Set the return value in the IRP that will be completed
5290 // upon completion of the read capacity.
5293 IrpToComplete
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
5294 IoMarkIrpPending(IrpToComplete
);
5296 IoCallDriver(commonExtension
->LowerDeviceObject
, irp
);
5299 // status is not checked because the completion routine for this
5300 // IRP will always get called and it will free the resources.
5303 return STATUS_PENDING
;
5306 ExFreePool(senseBuffer
);
5307 ExFreePool(capacityBuffer
);
5312 ExFreePool(capacityBuffer
);
5326 // complete the original irp with a failure.
5327 // ISSUE-2000/07/05-henrygab - find a way to avoid failure.
5330 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5331 sizeof(DISK_GEOMETRY
));
5332 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5333 fdoExtension
->SectorShift
= 11;
5334 commonExtension
->PartitionLength
.QuadPart
=
5335 (LONGLONG
)(0x7fffffff);
5336 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5338 IrpToComplete
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
5339 IrpToComplete
->IoStatus
.Information
= 0;
5341 BAIL_OUT(IrpToComplete
);
5342 CdRomCompleteIrpAndStartNextPacketSafely(commonExtension
->DeviceObject
,
5344 return STATUS_INSUFFICIENT_RESOURCES
;
5350 IN PDEVICE_OBJECT DeviceObject
,
5356 Routine Description:
5358 This routine is responsible for releasing any resources in use by the
5359 cdrom driver and shutting down it's timer routine. This routine is called
5360 when all outstanding requests have been completed and the device has
5361 disappeared - no requests may be issued to the lower drivers.
5365 DeviceObject - the device object being removed
5369 none - this routine may not fail
5374 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension
=
5375 DeviceObject
->DeviceExtension
;
5377 PCDROM_DATA cdData
= deviceExtension
->CommonExtension
.DriverData
;
5381 if((Type
== IRP_MN_QUERY_REMOVE_DEVICE
) ||
5382 (Type
== IRP_MN_CANCEL_REMOVE_DEVICE
)) {
5383 return STATUS_SUCCESS
;
5386 if(cdData
->DelayedRetryIrp
!= NULL
) {
5387 cdData
->DelayedRetryInterval
= 1;
5388 CdRomTickHandler(DeviceObject
);
5391 CdRomDeAllocateMmcResources(DeviceObject
);
5393 if (deviceExtension
->DeviceDescriptor
) {
5394 ExFreePool(deviceExtension
->DeviceDescriptor
);
5395 deviceExtension
->DeviceDescriptor
= NULL
;
5398 if (deviceExtension
->AdapterDescriptor
) {
5399 ExFreePool(deviceExtension
->AdapterDescriptor
);
5400 deviceExtension
->AdapterDescriptor
= NULL
;
5403 if (deviceExtension
->SenseData
) {
5404 ExFreePool(deviceExtension
->SenseData
);
5405 deviceExtension
->SenseData
= NULL
;
5408 ClassDeleteSrbLookasideList(&deviceExtension
->CommonExtension
);
5410 if(cdData
->CdromInterfaceString
.Buffer
!= NULL
) {
5411 IoSetDeviceInterfaceState(
5412 &(cdData
->CdromInterfaceString
),
5414 RtlFreeUnicodeString(&(cdData
->CdromInterfaceString
));
5415 RtlInitUnicodeString(&(cdData
->CdromInterfaceString
), NULL
);
5418 if(cdData
->VolumeInterfaceString
.Buffer
!= NULL
) {
5419 IoSetDeviceInterfaceState(
5420 &(cdData
->VolumeInterfaceString
),
5422 RtlFreeUnicodeString(&(cdData
->VolumeInterfaceString
));
5423 RtlInitUnicodeString(&(cdData
->VolumeInterfaceString
), NULL
);
5426 CdRomDeleteWellKnownName(DeviceObject
);
5428 ASSERT(cdData
->DelayedRetryIrp
== NULL
);
5430 if(Type
== IRP_MN_REMOVE_DEVICE
) {
5432 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
)) {
5435 // unlock locked pages by locking (to get Mm pointer)
5436 // and then unlocking twice.
5441 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_1750
)) {
5443 locked
= MmLockPagableCodeSection(HitachiProcessError
);
5445 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_GD_2000
)) {
5447 locked
= MmLockPagableCodeSection(HitachiProcessErrorGD2000
);
5449 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_XM_3xx
)) {
5451 locked
= MmLockPagableCodeSection(ToshibaProcessError
);
5455 // this is a problem!
5456 // workaround by locking this twice, once for us and
5457 // once for the non-existant locker from ScanForSpecial
5458 ASSERT(!"hack flags show locked section, but none exists?");
5459 locked
= MmLockPagableCodeSection(CdRomRemoveDevice
);
5460 locked
= MmLockPagableCodeSection(CdRomRemoveDevice
);
5465 MmUnlockPagableImageSection(locked
);
5466 MmUnlockPagableImageSection(locked
);
5471 // keep the system-wide count accurate, as
5472 // programs use this info to know when they
5473 // have found all the cdroms in a system.
5476 TraceLog((CdromDebugTrace
,
5477 "CDROM.SYS Remove device\n"));
5478 IoGetConfigurationInformation()->CdRomCount
--;
5482 // so long, and thanks for all the fish!
5485 return STATUS_SUCCESS
;
5491 IN PDEVICE_OBJECT DeviceObject
5495 Routine Description:
5497 This routine figures out the real device type
5498 by checking CDVD_CAPABILITIES_PAGE
5506 FILE_DEVICE_CD_ROM or FILE_DEVICE_DVD
5511 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
5512 PCDROM_DATA cdromExtension
;
5514 SCSI_REQUEST_BLOCK srb
;
5516 PMODE_PARAMETER_HEADER10 modePageHeader
;
5517 PCDVD_CAPABILITIES_PAGE capPage
;
5518 ULONG capPageOffset
;
5519 DEVICE_TYPE deviceType
;
5526 // NOTE: don't cache this until understand how it affects GetMediaTypes()
5530 // default device type
5533 deviceType
= FILE_DEVICE_CD_ROM
;
5535 fdoExtension
= DeviceObject
->DeviceExtension
;
5537 cdromExtension
= fdoExtension
->CommonExtension
.DriverData
;
5539 use6Byte
= TEST_FLAG(cdromExtension
->XAFlags
, XA_USE_6_BYTE
);
5541 RtlZeroMemory(&srb
, sizeof(srb
));
5542 cdb
= (PCDB
)srb
.Cdb
;
5545 // Build the MODE SENSE CDB. The data returned will be kept in the
5546 // device extension and used to set block size.
5550 bufLength
= sizeof(CDVD_CAPABILITIES_PAGE
) +
5551 sizeof(MODE_PARAMETER_HEADER
);
5553 capPageOffset
= sizeof(MODE_PARAMETER_HEADER
);
5555 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
5556 cdb
->MODE_SENSE
.Dbd
= 1;
5557 cdb
->MODE_SENSE
.PageCode
= MODE_PAGE_CAPABILITIES
;
5558 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)bufLength
;
5562 bufLength
= sizeof(CDVD_CAPABILITIES_PAGE
) +
5563 sizeof(MODE_PARAMETER_HEADER10
);
5565 capPageOffset
= sizeof(MODE_PARAMETER_HEADER10
);
5567 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
5568 cdb
->MODE_SENSE10
.Dbd
= 1;
5569 cdb
->MODE_SENSE10
.PageCode
= MODE_PAGE_CAPABILITIES
;
5570 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(bufLength
>> 8);
5571 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(bufLength
>> 0);
5576 // Set timeout value from device extension.
5578 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
5580 modePageHeader
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
5582 CDROM_TAG_MODE_DATA
);
5583 if (modePageHeader
) {
5585 RtlZeroMemory(modePageHeader
, bufLength
);
5587 status
= ClassSendSrbSynchronous(
5594 if (NT_SUCCESS(status
) ||
5595 (status
== STATUS_DATA_OVERRUN
) ||
5596 (status
== STATUS_BUFFER_OVERFLOW
)
5599 capPage
= (PCDVD_CAPABILITIES_PAGE
) (((PUCHAR
) modePageHeader
) + capPageOffset
);
5601 if ((capPage
->PageCode
== MODE_PAGE_CAPABILITIES
) &&
5602 (capPage
->DVDROMRead
|| capPage
->DVDRRead
||
5603 capPage
->DVDRAMRead
|| capPage
->DVDRWrite
||
5604 capPage
->DVDRAMWrite
)) {
5606 deviceType
= FILE_DEVICE_DVD
;
5609 ExFreePool (modePageHeader
);
5617 CdRomCreateWellKnownName(
5618 IN PDEVICE_OBJECT DeviceObject
5622 Routine Description:
5624 This routine creates a symbolic link to the cdrom device object
5625 under \dosdevices. The number of the cdrom device does not neccessarily
5626 match between \dosdevices and \device, but usually will be the same.
5640 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
5641 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
5642 PCDROM_DATA cdromData
= commonExtension
->DriverData
;
5644 UNICODE_STRING unicodeLinkName
;
5645 WCHAR wideLinkName
[64];
5648 LONG cdromNumber
= fdoExtension
->DeviceNumber
;
5653 // if already linked, assert then return
5656 if (cdromData
->WellKnownName
.Buffer
!= NULL
) {
5658 TraceLog((CdromDebugError
,
5659 "CdRomCreateWellKnownName: link already exists %p\n",
5660 cdromData
->WellKnownName
.Buffer
));
5662 return STATUS_UNSUCCESSFUL
;
5667 // find an unused CdRomNN to link to
5672 swprintf(wideLinkName
, L
"\\DosDevices\\CdRom%d", cdromNumber
);
5673 RtlInitUnicodeString(&unicodeLinkName
, wideLinkName
);
5674 status
= IoCreateSymbolicLink(&unicodeLinkName
,
5675 &(commonExtension
->DeviceName
));
5679 } while((status
== STATUS_OBJECT_NAME_COLLISION
) ||
5680 (status
== STATUS_OBJECT_NAME_EXISTS
));
5682 if (!NT_SUCCESS(status
)) {
5684 TraceLog((CdromDebugWarning
,
5685 "CdRomCreateWellKnownName: Error %lx linking %wZ to "
5689 &(commonExtension
->DeviceName
)));
5694 TraceLog((CdromDebugWarning
,
5695 "CdRomCreateWellKnownName: successfully linked %wZ "
5698 &(commonExtension
->DeviceName
)));
5701 // Save away the symbolic link name in the driver data block. We need
5702 // it so we can delete the link when the device is removed.
5705 savedName
= ExAllocatePoolWithTag(PagedPool
,
5706 unicodeLinkName
.MaximumLength
,
5709 if (savedName
== NULL
) {
5710 IoDeleteSymbolicLink(&unicodeLinkName
);
5711 return STATUS_INSUFFICIENT_RESOURCES
;
5714 RtlCopyMemory(savedName
,
5715 unicodeLinkName
.Buffer
,
5716 unicodeLinkName
.MaximumLength
);
5718 RtlInitUnicodeString(&(cdromData
->WellKnownName
), savedName
);
5721 // the name was saved and the link created
5724 return STATUS_SUCCESS
;
5729 CdRomDeleteWellKnownName(
5730 IN PDEVICE_OBJECT DeviceObject
5733 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
5734 PCDROM_DATA cdromData
= commonExtension
->DriverData
;
5736 if(cdromData
->WellKnownName
.Buffer
!= NULL
) {
5738 IoDeleteSymbolicLink(&(cdromData
->WellKnownName
));
5739 ExFreePool(cdromData
->WellKnownName
.Buffer
);
5740 cdromData
->WellKnownName
.Buffer
= NULL
;
5741 cdromData
->WellKnownName
.Length
= 0;
5742 cdromData
->WellKnownName
.MaximumLength
= 0;
5750 CdRomGetDeviceParameter (
5751 IN PDEVICE_OBJECT Fdo
,
5752 IN PWSTR ParameterName
,
5753 IN OUT PULONG ParameterValue
5757 Routine Description:
5759 retrieve a devnode registry parameter
5763 DeviceObject - Cdrom Device Object
5765 ParameterName - parameter name to look up
5767 ParameterValuse - default parameter value
5775 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
5777 HANDLE deviceParameterHandle
;
5778 RTL_QUERY_REGISTRY_TABLE queryTable
[2];
5779 ULONG defaultParameterValue
;
5784 // open the given parameter
5786 status
= IoOpenDeviceRegistryKey(fdoExtension
->LowerPdo
,
5787 PLUGPLAY_REGKEY_DRIVER
,
5789 &deviceParameterHandle
);
5791 if(NT_SUCCESS(status
)) {
5793 RtlZeroMemory(queryTable
, sizeof(queryTable
));
5795 defaultParameterValue
= *ParameterValue
;
5797 queryTable
->Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
5798 queryTable
->Name
= ParameterName
;
5799 queryTable
->EntryContext
= ParameterValue
;
5800 queryTable
->DefaultType
= REG_NONE
;
5801 queryTable
->DefaultData
= NULL
;
5802 queryTable
->DefaultLength
= 0;
5804 status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
5805 (PWSTR
) deviceParameterHandle
,
5809 if (!NT_SUCCESS(status
)) {
5811 *ParameterValue
= defaultParameterValue
;
5815 // close what we open
5817 ZwClose(deviceParameterHandle
);
5822 } // CdRomGetDeviceParameter
5826 CdRomSetDeviceParameter (
5827 IN PDEVICE_OBJECT Fdo
,
5828 IN PWSTR ParameterName
,
5829 IN ULONG ParameterValue
5833 Routine Description:
5835 save a devnode registry parameter
5839 DeviceObject - Cdrom Device Object
5841 ParameterName - parameter name
5843 ParameterValuse - parameter value
5851 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
5853 HANDLE deviceParameterHandle
;
5858 // open the given parameter
5860 status
= IoOpenDeviceRegistryKey(fdoExtension
->LowerPdo
,
5861 PLUGPLAY_REGKEY_DRIVER
,
5862 KEY_READ
| KEY_WRITE
,
5863 &deviceParameterHandle
);
5865 if(NT_SUCCESS(status
)) {
5867 status
= RtlWriteRegistryValue(
5868 RTL_REGISTRY_HANDLE
,
5869 (PWSTR
) deviceParameterHandle
,
5873 sizeof (ParameterValue
));
5876 // close what we open
5878 ZwClose(deviceParameterHandle
);
5883 } // CdromSetDeviceParameter
5888 IN PDEVICE_OBJECT Fdo
5892 Routine Description:
5894 pick a default dvd region
5898 DeviceObject - Cdrom Device Object
5906 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
5907 PCDROM_DATA cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
5910 // these five pointers all point to dvdReadStructure or part of
5911 // its data, so don't deallocate them more than once!
5914 PDVD_READ_STRUCTURE dvdReadStructure
;
5915 PDVD_COPY_PROTECT_KEY copyProtectKey
;
5916 PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight
;
5917 PDVD_RPC_KEY rpcKey
;
5918 PDVD_SET_RPC_KEY dvdRpcKey
;
5920 IO_STATUS_BLOCK ioStatus
;
5923 ULONG pickDvdRegion
;
5924 ULONG defaultDvdRegion
;
5929 if ((pickDvdRegion
= InterlockedExchange(&cddata
->PickDvdRegion
, 0)) == 0) {
5932 // it was non-zero, so either another thread will do this, or
5933 // we no longer need to pick a region
5940 // short-circuit if license agreement violated
5943 if (cddata
->DvdRpc0LicenseFailure
) {
5944 TraceLog((CdromDebugWarning
,
5945 "DVD License failure. Refusing to pick a region\n"));
5946 InterlockedExchange(&cddata
->PickDvdRegion
, 0);
5953 a
= max(sizeof(DVD_DESCRIPTOR_HEADER
) +
5954 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
5955 sizeof(DVD_READ_STRUCTURE
)
5957 b
= max(DVD_RPC_KEY_LENGTH
,
5958 DVD_SET_RPC_KEY_LENGTH
5960 bufferLen
= max(a
, b
);
5962 dvdReadStructure
= (PDVD_READ_STRUCTURE
)
5963 ExAllocatePoolWithTag(PagedPool
, bufferLen
, DVD_TAG_DVD_REGION
);
5965 if (dvdReadStructure
== NULL
) {
5966 InterlockedExchange(&cddata
->PickDvdRegion
, pickDvdRegion
);
5970 if (cddata
->DvdRpc0Device
&& cddata
->Rpc0RetryRegistryCallback
) {
5972 TraceLog((CdromDebugWarning
,
5973 "CdRomPickDvdRegion (%p): now retrying RPC0 callback\n",
5977 // get the registry settings again
5980 ioStatus
.Status
= CdRomGetRpc0Settings(Fdo
);
5982 if (ioStatus
.Status
== STATUS_LICENSE_VIOLATION
) {
5985 // if this is the returned error, then
5986 // the routine should have set this!
5989 ASSERT(cddata
->DvdRpc0LicenseFailure
);
5990 cddata
->DvdRpc0LicenseFailure
= 1;
5991 TraceLog((CdromDebugWarning
,
5992 "CdRomPickDvdRegion (%p): "
5993 "setting to fail all dvd ioctls due to CSS licensing "
5994 "failure.\n", Fdo
));
6002 // get the device region, again
6005 copyProtectKey
= (PDVD_COPY_PROTECT_KEY
)dvdReadStructure
;
6006 RtlZeroMemory(copyProtectKey
, bufferLen
);
6007 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
6008 copyProtectKey
->KeyType
= DvdGetRpcKey
;
6011 // Build a request for READ_KEY
6014 ClassSendDeviceIoControlSynchronous(
6023 if (!NT_SUCCESS(ioStatus
.Status
)) {
6024 TraceLog((CdromDebugWarning
,
6025 "CdRomPickDvdRegion: Unable to get "
6026 "device RPC data (%x)\n", ioStatus
.Status
));
6032 // now that we have gotten the device's RPC data,
6033 // we have set the device extension to usable data.
6034 // no need to call back into this section of code again
6037 cddata
->Rpc0RetryRegistryCallback
= 0;
6040 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
6043 // TypeCode of zero means that no region has been set.
6046 if (rpcKey
->TypeCode
!= 0) {
6047 TraceLog((CdromDebugWarning
,
6048 "CdRomPickDvdRegion (%p): DVD Region already "
6054 TraceLog((CdromDebugWarning
,
6055 "CdRomPickDvdRegion (%p): must choose initial DVD "
6061 copyProtectKey
= (PDVD_COPY_PROTECT_KEY
) dvdReadStructure
;
6063 dvdCopyRight
= (PDVD_COPYRIGHT_DESCRIPTOR
)
6064 ((PDVD_DESCRIPTOR_HEADER
) dvdReadStructure
)->Data
;
6067 // get the media region
6070 RtlZeroMemory (dvdReadStructure
, bufferLen
);
6071 dvdReadStructure
->Format
= DvdCopyrightDescriptor
;
6074 // Build and send a request for READ_KEY
6077 TraceLog((CdromDebugTrace
,
6078 "CdRomPickDvdRegion (%p): Getting Copyright Descriptor\n",
6081 ClassSendDeviceIoControlSynchronous(
6082 IOCTL_DVD_READ_STRUCTURE
,
6085 sizeof(DVD_READ_STRUCTURE
),
6086 sizeof (DVD_DESCRIPTOR_HEADER
) +
6087 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
6091 TraceLog((CdromDebugTrace
,
6092 "CdRomPickDvdRegion (%p): Got Copyright Descriptor %x\n",
6093 Fdo
, ioStatus
.Status
));
6095 if ((NT_SUCCESS(ioStatus
.Status
)) &&
6096 (dvdCopyRight
->CopyrightProtectionType
== 0x01)
6100 // keep the media region bitmap around
6101 // a 1 means ok to play
6104 if (dvdCopyRight
->RegionManagementInformation
== 0xff) {
6105 TraceLog((CdromDebugError
,
6106 "CdRomPickDvdRegion (%p): RegionManagementInformation "
6107 "is set to dis-allow playback for all regions. This is "
6108 "most likely a poorly authored disc. defaulting to all "
6109 "region disc for purpose of choosing initial region\n",
6111 dvdCopyRight
->RegionManagementInformation
= 0;
6115 mediaRegion
= ~dvdCopyRight
->RegionManagementInformation
;
6120 // could be media, can't set the device region
6123 if (!cddata
->DvdRpc0Device
) {
6126 // can't automatically pick a default region on a rpc2 drive
6127 // without media, so just exit
6129 TraceLog((CdromDebugWarning
,
6130 "CdRomPickDvdRegion (%p): failed to auto-choose "
6131 "a region due to status %x getting copyright "
6132 "descriptor\n", Fdo
, ioStatus
.Status
));
6138 // for an RPC0 drive, we can try to pick a region for
6148 // get the device region
6151 RtlZeroMemory (copyProtectKey
, bufferLen
);
6152 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
6153 copyProtectKey
->KeyType
= DvdGetRpcKey
;
6156 // Build and send a request for READ_KEY for RPC key
6159 TraceLog((CdromDebugTrace
,
6160 "CdRomPickDvdRegion (%p): Getting RpcKey\n",
6162 ClassSendDeviceIoControlSynchronous(
6171 TraceLog((CdromDebugTrace
,
6172 "CdRomPickDvdRegion (%p): Got RpcKey %x\n",
6173 Fdo
, ioStatus
.Status
));
6175 if (!NT_SUCCESS(ioStatus
.Status
)) {
6177 TraceLog((CdromDebugWarning
,
6178 "CdRomPickDvdRegion (%p): failed to get RpcKey from "
6179 "a DVD Device\n", Fdo
));
6185 // so we now have what we can get for the media region and the
6186 // drive region. we will not set a region if the drive has one
6187 // set already (mask is not all 1's), nor will we set a region
6188 // if there are no more user resets available.
6191 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
6194 if (rpcKey
->RegionMask
!= 0xff) {
6195 TraceLog((CdromDebugWarning
,
6196 "CdRomPickDvdRegion (%p): not picking a region since "
6197 "it is already chosen\n", Fdo
));
6201 if (rpcKey
->UserResetsAvailable
<= 1) {
6202 TraceLog((CdromDebugWarning
,
6203 "CdRomPickDvdRegion (%p): not picking a region since "
6204 "only one change remains\n", Fdo
));
6208 defaultDvdRegion
= 0;
6211 // the proppage dvd class installer sets
6212 // this key based upon the system locale
6215 CdRomGetDeviceParameter (
6221 if (defaultDvdRegion
> DVD_MAX_REGION
) {
6224 // the registry has a bogus default
6227 TraceLog((CdromDebugWarning
,
6228 "CdRomPickDvdRegion (%p): registry has a bogus default "
6229 "region value of %x\n", Fdo
, defaultDvdRegion
));
6230 defaultDvdRegion
= 0;
6235 // if defaultDvdRegion == 0, it means no default.
6239 // we will select the initial dvd region for the user
6242 if ((defaultDvdRegion
!= 0) &&
6244 (1 << (defaultDvdRegion
- 1))
6250 // the media has region that matches
6251 // the default dvd region.
6254 dvdRegion
= (1 << (defaultDvdRegion
- 1));
6256 TraceLog((CdromDebugWarning
,
6257 "CdRomPickDvdRegion (%p): Choice #1: media matches "
6258 "drive's default, chose region %x\n", Fdo
, dvdRegion
));
6261 } else if (mediaRegion
) {
6265 // pick the lowest region number
6273 while (mediaRegion
&& !dvdRegion
) {
6276 // pick the lowest bit
6278 dvdRegion
= mediaRegion
& mask
;
6282 TraceLog((CdromDebugWarning
,
6283 "CdRomPickDvdRegion (%p): Choice #2: choosing lowest "
6284 "media region %x\n", Fdo
, dvdRegion
));
6286 } else if (defaultDvdRegion
) {
6290 // default dvd region from the dvd class installer
6293 dvdRegion
= (1 << (defaultDvdRegion
- 1));
6294 TraceLog((CdromDebugWarning
,
6295 "CdRomPickDvdRegion (%p): Choice #3: using default "
6296 "region for this install %x\n", Fdo
, dvdRegion
));
6301 // unable to pick one for the user -- this should rarely
6302 // happen, since the proppage dvd class installer sets
6303 // the key based upon the system locale
6305 TraceLog((CdromDebugWarning
,
6306 "CdRomPickDvdRegion (%p): Choice #4: failed to choose "
6307 "a media region\n", Fdo
));
6313 // now that we've chosen a region, set the region by sending the
6314 // appropriate request to the drive
6317 RtlZeroMemory (copyProtectKey
, bufferLen
);
6318 copyProtectKey
->KeyLength
= DVD_SET_RPC_KEY_LENGTH
;
6319 copyProtectKey
->KeyType
= DvdSetRpcKey
;
6320 dvdRpcKey
= (PDVD_SET_RPC_KEY
) copyProtectKey
->KeyData
;
6321 dvdRpcKey
->PreferredDriveRegionCode
= (UCHAR
) ~dvdRegion
;
6324 // Build and send request for SEND_KEY
6326 TraceLog((CdromDebugTrace
,
6327 "CdRomPickDvdRegion (%p): Sending new Rpc Key to region %x\n",
6330 ClassSendDeviceIoControlSynchronous(
6331 IOCTL_DVD_SEND_KEY2
,
6334 DVD_SET_RPC_KEY_LENGTH
,
6338 TraceLog((CdromDebugTrace
,
6339 "CdRomPickDvdRegion (%p): Sent new Rpc Key %x\n",
6340 Fdo
, ioStatus
.Status
));
6342 if (!NT_SUCCESS(ioStatus
.Status
)) {
6343 DebugPrint ((1, "CdRomPickDvdRegion (%p): unable to set dvd initial "
6344 " region code (%p)\n", Fdo
, ioStatus
.Status
));
6346 DebugPrint ((1, "CdRomPickDvdRegion (%p): Successfully set dvd "
6347 "initial region\n", Fdo
));
6352 if (dvdReadStructure
) {
6353 ExFreePool (dvdReadStructure
);
6357 // update the new PickDvdRegion value
6360 InterlockedExchange(&cddata
->PickDvdRegion
, pickDvdRegion
);
6368 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
6371 IN BOOLEAN ResendIrp
6378 return CdRomRerunRequest(FdoExtension
, Irp
, ResendIrp
);
6381 cdData
= FdoExtension
->CommonExtension
.DriverData
;
6383 KeAcquireSpinLock(&(cdData
->DelayedRetrySpinLock
), &oldIrql
);
6385 ASSERT(cdData
->DelayedRetryIrp
== NULL
);
6386 ASSERT(cdData
->DelayedRetryInterval
== 0);
6388 cdData
->DelayedRetryIrp
= Irp
;
6389 cdData
->DelayedRetryInterval
= Delay
;
6390 cdData
->DelayedRetryResend
= ResendIrp
;
6392 KeReleaseSpinLock(&(cdData
->DelayedRetrySpinLock
), oldIrql
);
6394 return STATUS_PENDING
;
6400 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
6401 IN OPTIONAL PIRP Irp
,
6402 IN BOOLEAN ResendIrp
6406 return IoCallDriver(FdoExtension
->CommonExtension
.LowerDeviceObject
,
6411 oldIrql
= KeRaiseIrqlToDpcLevel();
6412 CdRomStartIo(FdoExtension
->DeviceObject
, Irp
);
6413 KeLowerIrql(oldIrql
);
6414 return STATUS_MORE_PROCESSING_REQUIRED
;
6421 Routine Description:
6423 This routine just checks for media change sense/asc/ascq and
6424 also for other events, such as bus resets. this is used to
6425 determine if the device behaviour has changed, to allow for
6426 read and write operations to be allowed and/or disallowed.
6430 ISSUE-2000/3/30-henrygab - not fully doc'd
6438 CdRomMmcErrorHandler(
6439 IN PDEVICE_OBJECT Fdo
,
6440 IN PSCSI_REQUEST_BLOCK Srb
,
6441 OUT PNTSTATUS Status
,
6445 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
6446 BOOLEAN queryCapabilities
= FALSE
;
6448 if (TEST_FLAG(Srb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
6450 PCDROM_DATA cddata
= (PCDROM_DATA
)commonExtension
->DriverData
;
6451 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
6454 // the following sense keys could indicate a change in
6459 // we used to expect this to be serialized, and only hit from our
6460 // own routine. we now allow some requests to continue during our
6461 // processing of the capabilities update in order to allow
6462 // IoReadPartitionTable() to succeed.
6465 switch (senseBuffer
->SenseKey
& 0xf) {
6467 case SCSI_SENSE_NOT_READY
: {
6468 if (senseBuffer
->AdditionalSenseCode
==
6469 SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
) {
6471 if (cddata
->Mmc
.WriteAllowed
) {
6472 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6473 "CdromErrorHandler: media removed, writes will be "
6474 "failed until new media detected\n"));
6478 cddata
->Mmc
.WriteAllowed
= FALSE
;
6480 if ((senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
6481 (senseBuffer
->AdditionalSenseCodeQualifier
==
6482 SCSI_SENSEQ_BECOMING_READY
)) {
6483 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6484 "CdromErrorHandler: media becoming ready, "
6485 "SHOULD notify shell of change time by sending "
6486 "GESN request immediately!\n"));
6489 } // end SCSI_SENSE_NOT_READY
6491 case SCSI_SENSE_UNIT_ATTENTION
: {
6492 switch (senseBuffer
->AdditionalSenseCode
) {
6493 case SCSI_ADSENSE_MEDIUM_CHANGED
: {
6496 // always update if the medium may have changed
6500 cddata
->Mmc
.WriteAllowed
= FALSE
;
6501 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6502 CdromMmcUpdateRequired
,
6503 CdromMmcUpdateComplete
);
6505 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6506 "CdromErrorHandler: media change detected, need to "
6507 "update drive capabilities\n"));
6510 } // end SCSI_ADSENSE_MEDIUM_CHANGED
6512 case SCSI_ADSENSE_BUS_RESET
: {
6515 cddata
->Mmc
.WriteAllowed
= FALSE
;
6516 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6517 CdromMmcUpdateRequired
,
6518 CdromMmcUpdateComplete
);
6520 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6521 "CdromErrorHandler: bus reset detected, need to "
6522 "update drive capabilities\n"));
6525 } // end SCSI_ADSENSE_BUS_RESET
6527 case SCSI_ADSENSE_OPERATOR_REQUEST
: {
6531 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
6532 case SCSI_SENSEQ_MEDIUM_REMOVAL
: {
6535 // eject notification currently handled by classpnp
6538 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6539 "CdromErrorHandler: Eject requested by user\n"));
6541 *Status
= STATUS_DEVICE_BUSY
;
6545 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE
:
6547 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE
: {
6549 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6550 "CdromErrorHandler: Write protect %s requested "
6552 (b
? "disable" : "enable")));
6554 *Status
= STATUS_DEVICE_BUSY
;
6556 cddata
->Mmc
.WriteAllowed
= FALSE
;
6557 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6558 CdromMmcUpdateRequired
,
6559 CdromMmcUpdateComplete
);
6563 } // end of AdditionalSenseCodeQualifier switch
6568 } // end SCSI_ADSENSE_OPERATOR_REQUEST
6571 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6572 "CdromErrorHandler: Unit attention %02x/%02x\n",
6573 senseBuffer
->AdditionalSenseCode
,
6574 senseBuffer
->AdditionalSenseCodeQualifier
));
6578 } // end of AdditionSenseCode switch
6581 } // end SCSI_SENSE_UNIT_ATTENTION
6583 case SCSI_SENSE_ILLEGAL_REQUEST
: {
6584 if (senseBuffer
->AdditionalSenseCode
==
6585 SCSI_ADSENSE_WRITE_PROTECT
) {
6587 if (cddata
->Mmc
.WriteAllowed
) {
6588 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6589 "CdromErrorHandler: media was writable, but "
6590 "failed request with WRITE_PROTECT error...\n"));
6593 // do not update all the capabilities just because
6594 // we can't write to the disc.
6595 cddata
->Mmc
.WriteAllowed
= FALSE
;
6598 } // end SCSI_SENSE_ILLEGAL_REQUEST
6600 } // end of SenseKey switch
6602 } // end of SRB_STATUS_AUTOSENSE_VALID
6604 return STATUS_SUCCESS
;
6609 Routine Description:
6611 This routine checks for a device-specific error handler
6612 and calls it if it exists. This allows multiple drives
6613 that require their own error handler to co-exist.
6618 PDEVICE_OBJECT DeviceObject
,
6619 PSCSI_REQUEST_BLOCK Srb
,
6624 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
6625 PCDROM_DATA cddata
= (PCDROM_DATA
)commonExtension
->DriverData
;
6626 PSENSE_DATA sense
= Srb
->SenseInfoBuffer
;
6628 if ((Srb
->SenseInfoBufferLength
>=
6629 RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA
,AdditionalSenseCodeQualifier
)) &&
6630 TEST_FLAG(Srb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
6633 // Many non-WHQL certified drives (mostly CD-RW) return
6634 // 2/4/0 when they have no media instead of the obvious
6637 // SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
6639 // These drives should not pass WHQL certification due
6640 // to this discrepency.
6642 // However, we have to retry on 2/4/0 (Not ready, LUN not ready,
6643 // no info) and also 3/2/0 (no seek complete).
6645 // These conditions occur when the shell tries to examine an
6646 // injected CD (e.g. for autoplay) before the CD is spun up.
6648 // The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
6649 // (0x01) in order to comply with WHQL standards.
6651 // The default retry timeout of one second is acceptable to balance
6652 // these discrepencies. don't modify the status, though....
6655 if (((sense
->SenseKey
& 0xf) == SCSI_SENSE_NOT_READY
) &&
6656 (sense
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
6657 (sense
->AdditionalSenseCodeQualifier
== SCSI_SENSEQ_CAUSE_NOT_REPORTABLE
)
6662 } else if (((sense
->SenseKey
& 0xf) == SCSI_SENSE_MEDIUM_ERROR
) &&
6663 (sense
->AdditionalSenseCode
== 0x2) &&
6664 (sense
->AdditionalSenseCodeQualifier
== 0x0)
6669 } else if ((sense
->AdditionalSenseCode
== 0x57) &&
6670 (sense
->AdditionalSenseCodeQualifier
== 0x00)
6674 // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
6675 // the Matshita CR-585 returns this for all read commands
6676 // on blank CD-R and CD-RW media, and we need to handle
6677 // this for READ_CD detection ability.
6681 *Status
= STATUS_UNRECOGNIZED_MEDIA
;
6688 // tail recursion in both cases takes no stack
6691 if (cddata
->ErrorHandler
) {
6692 cddata
->ErrorHandler(DeviceObject
, Srb
, Status
, Retry
);
6700 Routine Description:
6702 This routine is called for a shutdown and flush IRPs.
6703 These are sent by the system before it actually shuts
6704 down or when the file system does a flush.
6708 DriverObject - Pointer to device object to being shutdown by system.
6719 IN PDEVICE_OBJECT DeviceObject
,
6723 IoMarkIrpPending(Irp
);
6724 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
6725 return STATUS_PENDING
;
6731 Routine Description:
6733 This routine is called for intermediate work a shutdown or
6734 flush IRPs would need to do. We just want to free our resources
6735 and return STATUS_MORE_PROCESSING_REQUIRED.
6739 DeviceObject - NULL?
6751 CdRomShutdownFlushCompletion(
6752 IN PDEVICE_OBJECT Fdo
,
6757 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
6758 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
6759 PIO_STACK_LOCATION originalIrpStack
;
6760 ULONG_PTR iteration
;
6761 NTSTATUS status
= STATUS_SUCCESS
;
6763 ASSERT(OriginalIrp
);
6765 originalIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
6768 // always use a new irp so we can call
6769 // CdRomCompleteIrpAndStartNextPacketSafely() from this routine.
6772 if (NewIrp
!= NULL
) {
6773 status
= NewIrp
->IoStatus
.Status
;
6778 if (!NT_SUCCESS(status
)) {
6779 BAIL_OUT(OriginalIrp
);
6784 // the current irpstack saves the counter which states
6785 // what part of the multi-part shutdown or flush we are in.
6788 iteration
= (ULONG_PTR
)originalIrpStack
->Parameters
.Others
.Argument1
;
6790 originalIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)iteration
;
6792 switch (iteration
) {
6794 if (originalIrpStack
->MajorFunction
!= IRP_MJ_SHUTDOWN
) {
6796 // then we don't want to send the unlock command
6797 // the incrementing of the state was done above.
6798 // return the completion routine's result.
6800 return CdRomShutdownFlushCompletion(Fdo
, NULL
, OriginalIrp
);
6802 // else fall through....
6807 PSCSI_REQUEST_BLOCK newSrb
= NULL
;
6809 PIO_STACK_LOCATION newIrpStack
= NULL
;
6812 newIrp
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1), FALSE
);
6813 if (newIrp
== NULL
) {
6814 BAIL_OUT(OriginalIrp
);
6815 status
= STATUS_INSUFFICIENT_RESOURCES
;
6818 newSrb
= ExAllocatePoolWithTag(NonPagedPool
,
6819 sizeof(SCSI_REQUEST_BLOCK
),
6821 if (newSrb
== NULL
) {
6823 BAIL_OUT(OriginalIrp
);
6824 status
= STATUS_INSUFFICIENT_RESOURCES
;
6829 // ClassIoComplete will free the SRB, but we need a routine
6830 // that will free the irp. then just call ClassSendAsync,
6831 // and don't care about the return value, since the completion
6832 // routine will be called anyways.
6835 IoSetNextIrpStackLocation(newIrp
);
6836 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
6837 newIrpStack
->DeviceObject
= Fdo
;
6838 IoSetCompletionRoutine(newIrp
,
6839 CdRomShutdownFlushCompletion
,
6842 IoSetNextIrpStackLocation(newIrp
);
6843 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
6844 newIrpStack
->DeviceObject
= Fdo
;
6847 // setup the request
6850 RtlZeroMemory(newSrb
, sizeof(SCSI_REQUEST_BLOCK
));
6851 newCdb
= (PCDB
)(newSrb
->Cdb
);
6853 newSrb
->QueueTag
= SP_UNTAGGED
;
6854 newSrb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
6855 newSrb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6858 // tell classpnp not to call StartNextPacket()
6861 newSrb
->SrbFlags
= SRB_FLAGS_DONT_START_NEXT_PACKET
;
6863 if (iteration
== 1) {
6866 // first synchronize the cache
6869 newSrb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 4;
6870 newSrb
->CdbLength
= 10;
6871 newCdb
->SYNCHRONIZE_CACHE10
.OperationCode
= SCSIOP_SYNCHRONIZE_CACHE
;
6873 } else if (iteration
== 2) {
6876 // then unlock the medium
6879 ASSERT( originalIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
);
6881 newSrb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
6882 newSrb
->CdbLength
= 6;
6883 newCdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
6884 newCdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
6889 isRemoved
= ClassAcquireRemoveLock(Fdo
, newIrp
);
6893 ClassReleaseRemoveLock(Fdo
, newIrp
);
6894 BAIL_OUT(OriginalIrp
);
6895 status
= STATUS_DEVICE_DOES_NOT_EXIST
;
6898 ClassSendSrbAsynchronous(Fdo
, newSrb
, newIrp
, NULL
, 0, FALSE
);
6904 PSCSI_REQUEST_BLOCK srb
;
6905 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(OriginalIrp
);
6908 // forward this request to the device appropriately,
6909 // don't use this completion routine anymore...
6912 srb
= ExAllocatePoolWithTag(NonPagedPool
,
6913 sizeof(SCSI_REQUEST_BLOCK
),
6916 BAIL_OUT(OriginalIrp
);
6917 status
= STATUS_INSUFFICIENT_RESOURCES
;
6921 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
6922 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6923 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 4;
6924 srb
->QueueTag
= SP_UNTAGGED
;
6925 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
6926 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
6928 srb
->OriginalRequest
= OriginalIrp
;
6930 if (originalIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
6931 srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
6933 srb
->Function
= SRB_FUNCTION_FLUSH
;
6937 // Set up IoCompletion routine address.
6940 IoSetCompletionRoutine(OriginalIrp
,
6946 // Set the retry count to zero.
6949 originalIrpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
6952 // Get next stack location and set major function code.
6955 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
6958 // Set up SRB for execute scsi request.
6959 // Save SRB address in next stack for port driver.
6962 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
6965 // Call the port driver to process the request.
6968 IoCallDriver(commonExtension
->LowerDeviceObject
, OriginalIrp
);
6980 status
= STATUS_SUCCESS
;
6984 if (!NT_SUCCESS(status
)) {
6985 OriginalIrp
->IoStatus
.Status
= status
;
6986 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
6990 // always return STATUS_MORE_PROCESSING_REQUIRED, so noone else tries
6991 // to access the new irp that we free'd....
6994 return STATUS_MORE_PROCESSING_REQUIRED
;
6996 } // end CdromShutdownFlush()
7000 CdromFakePartitionInfo(
7001 IN PCOMMON_DEVICE_EXTENSION CommonExtension
,
7005 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
7006 ULONG ioctl
= currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
7007 PVOID systemBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
7009 ASSERT(systemBuffer
);
7011 if ((ioctl
!= IOCTL_DISK_GET_DRIVE_LAYOUT
) &&
7012 (ioctl
!= IOCTL_DISK_GET_DRIVE_LAYOUT_EX
) &&
7013 (ioctl
!= IOCTL_DISK_GET_PARTITION_INFO
) &&
7014 (ioctl
!= IOCTL_DISK_GET_PARTITION_INFO_EX
)) {
7015 TraceLog((CdromDebugError
,
7016 "CdromFakePartitionInfo: unhandled ioctl %x\n", ioctl
));
7017 Irp
->IoStatus
.Status
= STATUS_INTERNAL_ERROR
;
7018 Irp
->IoStatus
.Information
= 0;
7019 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension
->DeviceObject
,
7025 // nothing to fail from this point on, so set the size appropriately
7026 // and set irp's status to success.
7029 TraceLog((CdromDebugWarning
,
7030 "CdromFakePartitionInfo: incoming ioctl %x\n", ioctl
));
7033 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
7035 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
7036 Irp
->IoStatus
.Information
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
7038 RtlZeroMemory(systemBuffer
, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
7039 PartitionEntry
[1]));
7041 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
:
7042 Irp
->IoStatus
.Information
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
,
7044 RtlZeroMemory(systemBuffer
, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
,
7045 PartitionEntry
[1]));
7047 case IOCTL_DISK_GET_PARTITION_INFO
:
7048 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
7049 RtlZeroMemory(systemBuffer
, sizeof(PARTITION_INFORMATION
));
7051 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
7052 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
7053 RtlZeroMemory(systemBuffer
, sizeof(PARTITION_INFORMATION_EX
));
7056 ASSERT(!"Invalid ioctl should not have reached this point\n");
7061 // if we are getting the drive layout, then we need to start by
7062 // adding some of the non-partition stuff that says we have
7063 // exactly one partition available.
7067 if (ioctl
== IOCTL_DISK_GET_DRIVE_LAYOUT
) {
7069 PDRIVE_LAYOUT_INFORMATION layout
;
7070 layout
= (PDRIVE_LAYOUT_INFORMATION
)systemBuffer
;
7071 layout
->PartitionCount
= 1;
7072 layout
->Signature
= 1;
7073 systemBuffer
= (PVOID
)(layout
->PartitionEntry
);
7074 ioctl
= IOCTL_DISK_GET_PARTITION_INFO
;
7076 } else if (ioctl
== IOCTL_DISK_GET_DRIVE_LAYOUT_EX
) {
7078 PDRIVE_LAYOUT_INFORMATION_EX layoutEx
;
7079 layoutEx
= (PDRIVE_LAYOUT_INFORMATION_EX
)systemBuffer
;
7080 layoutEx
->PartitionStyle
= PARTITION_STYLE_MBR
;
7081 layoutEx
->PartitionCount
= 1;
7082 layoutEx
->Mbr
.Signature
= 1;
7083 systemBuffer
= (PVOID
)(layoutEx
->PartitionEntry
);
7084 ioctl
= IOCTL_DISK_GET_PARTITION_INFO_EX
;
7089 // NOTE: the local var 'ioctl' is now modified to either EX or
7090 // non-EX version. the local var 'systemBuffer' is now pointing
7091 // to the partition information structure.
7094 if (ioctl
== IOCTL_DISK_GET_PARTITION_INFO
) {
7096 PPARTITION_INFORMATION partitionInfo
;
7097 partitionInfo
= (PPARTITION_INFORMATION
)systemBuffer
;
7098 partitionInfo
->RewritePartition
= FALSE
;
7099 partitionInfo
->RecognizedPartition
= TRUE
;
7100 partitionInfo
->PartitionType
= PARTITION_FAT32
;
7101 partitionInfo
->BootIndicator
= FALSE
;
7102 partitionInfo
->HiddenSectors
= 0;
7103 partitionInfo
->StartingOffset
.QuadPart
= 0;
7104 partitionInfo
->PartitionLength
= CommonExtension
->PartitionLength
;
7105 partitionInfo
->PartitionNumber
= 0;
7109 PPARTITION_INFORMATION_EX partitionInfo
;
7110 partitionInfo
= (PPARTITION_INFORMATION_EX
)systemBuffer
;
7111 partitionInfo
->PartitionStyle
= PARTITION_STYLE_MBR
;
7112 partitionInfo
->RewritePartition
= FALSE
;
7113 partitionInfo
->Mbr
.RecognizedPartition
= TRUE
;
7114 partitionInfo
->Mbr
.PartitionType
= PARTITION_FAT32
;
7115 partitionInfo
->Mbr
.BootIndicator
= FALSE
;
7116 partitionInfo
->Mbr
.HiddenSectors
= 0;
7117 partitionInfo
->StartingOffset
.QuadPart
= 0;
7118 partitionInfo
->PartitionLength
= CommonExtension
->PartitionLength
;
7119 partitionInfo
->PartitionNumber
= 0;
7122 TraceLog((CdromDebugWarning
,
7123 "CdromFakePartitionInfo: finishing ioctl %x\n",
7124 currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
));
7130 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension
->DeviceObject
,