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).
31 #pragma alloc_text(INIT, DriverEntry)
33 #pragma alloc_text(PAGE, CdRomUnload)
34 #pragma alloc_text(PAGE, CdRomAddDevice)
35 #pragma alloc_text(PAGE, CdRomCreateDeviceObject)
36 #pragma alloc_text(PAGE, CdRomStartDevice)
37 #pragma alloc_text(PAGE, ScanForSpecial)
38 #pragma alloc_text(PAGE, ScanForSpecialHandler)
39 #pragma alloc_text(PAGE, CdRomRemoveDevice)
40 #pragma alloc_text(PAGE, CdRomGetDeviceType)
41 #pragma alloc_text(PAGE, CdRomReadWriteVerification)
42 #pragma alloc_text(PAGE, CdRomGetDeviceParameter)
43 #pragma alloc_text(PAGE, CdRomSetDeviceParameter)
44 #pragma alloc_text(PAGE, CdRomPickDvdRegion)
45 #pragma alloc_text(PAGE, CdRomIsPlayActive)
47 #pragma alloc_text(PAGEHITA, HitachiProcessError)
48 #pragma alloc_text(PAGEHIT2, HitachiProcessErrorGD2000)
50 #pragma alloc_text(PAGETOSH, ToshibaProcessErrorCompletion)
51 #pragma alloc_text(PAGETOSH, ToshibaProcessError)
55 #define IS_WRITE_REQUEST(irpStack) \
56 (irpStack->MajorFunction == IRP_MJ_WRITE)
58 #define IS_READ_WRITE_REQUEST(irpStack) \
59 ((irpStack->MajorFunction == IRP_MJ_READ) || \
60 (irpStack->MajorFunction == IRP_MJ_WRITE) || \
61 ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) && \
62 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_RAW_READ)))
68 IN PDRIVER_OBJECT DriverObject
,
69 IN PUNICODE_STRING RegistryPath
76 This routine initializes the cdrom class driver.
80 DriverObject - Pointer to driver object created by system.
82 RegistryPath - Pointer to the name of the services node for this driver.
86 The function value is the final status from the initialization operation.
91 CLASS_INIT_DATA InitializationData
;
92 PCDROM_DRIVER_EXTENSION driverExtension
;
97 WPP_INIT_TRACING(DriverObject
, RegistryPath
);
99 TraceLog((CdromDebugTrace
,
100 "CDROM.SYS DriverObject %p loading\n", DriverObject
));
102 status
= IoAllocateDriverObjectExtension(DriverObject
,
103 CDROM_DRIVER_EXTENSION_ID
,
104 sizeof(CDROM_DRIVER_EXTENSION
),
105 (PVOID
*)&driverExtension
);
107 if (!NT_SUCCESS(status
)) {
108 TraceLog((CdromDebugWarning
,
109 "DriverEntry !! no DriverObjectExtension %x\n", status
));
114 // always zero the memory, since we are now reloading the driver.
117 RtlZeroMemory(driverExtension
, sizeof(CDROM_DRIVER_EXTENSION
));
123 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
129 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
131 InitializationData
.FdoData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
133 InitializationData
.FdoData
.DeviceType
= FILE_DEVICE_CD_ROM
;
134 InitializationData
.FdoData
.DeviceCharacteristics
=
135 FILE_REMOVABLE_MEDIA
| FILE_DEVICE_SECURE_OPEN
;
141 InitializationData
.FdoData
.ClassError
= CdRomErrorHandler
;
142 InitializationData
.FdoData
.ClassInitDevice
= CdRomInitDevice
;
143 InitializationData
.FdoData
.ClassStartDevice
= CdRomStartDevice
;
144 InitializationData
.FdoData
.ClassStopDevice
= CdRomStopDevice
;
145 InitializationData
.FdoData
.ClassRemoveDevice
= CdRomRemoveDevice
;
147 InitializationData
.FdoData
.ClassReadWriteVerification
= CdRomReadWriteVerification
;
148 InitializationData
.FdoData
.ClassDeviceControl
= CdRomDeviceControlDispatch
;
150 InitializationData
.FdoData
.ClassPowerDevice
= ClassSpinDownPowerHandler
;
151 InitializationData
.FdoData
.ClassShutdownFlush
= CdRomShutdownFlush
;
152 InitializationData
.FdoData
.ClassCreateClose
= NULL
;
154 InitializationData
.ClassStartIo
= CdRomStartIo
;
155 InitializationData
.ClassAddDevice
= CdRomAddDevice
;
157 InitializationData
.ClassTick
= CdRomTickHandler
;
158 InitializationData
.ClassUnload
= CdRomUnload
;
161 // Call the class init routine
163 return ClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
165 } // end DriverEntry()
170 IN PDRIVER_OBJECT DriverObject
174 UNREFERENCED_PARAMETER(DriverObject
);
175 TraceLog((CdromDebugTrace
,
176 "CDROM.SYS DriverObject %p unloading\n", DriverObject
));
177 WPP_CLEANUP(DriverObject
);
179 } // end CdRomUnload()
184 IN PDRIVER_OBJECT DriverObject
,
185 IN PDEVICE_OBJECT PhysicalDeviceObject
192 This routine creates and initializes a new FDO for the corresponding
193 PDO. It may perform property queries on the FDO but cannot do any
194 media access operations.
198 DriverObject - CDROM class driver object.
200 Pdo - the physical device object we are being added to
214 // Get the address of the count of the number of cdroms already initialized.
216 DbgPrint("add device\n");
218 status
= CdRomCreateDeviceObject(DriverObject
,
219 PhysicalDeviceObject
);
222 // Note: this always increments driver extension counter
223 // it will eventually wrap, and fail additions
224 // if an existing cdrom has the given number.
225 // so unlikely that we won't even bother considering
226 // this case, since the cure is quite likely worse
227 // than the symptoms.
230 if(NT_SUCCESS(status
)) {
233 // keep track of the total number of active cdroms in IoGet(),
234 // as some programs use this to determine when they have found
235 // all the cdroms in the system.
238 TraceLog((CdromDebugTrace
, "CDROM.SYS Add succeeded\n"));
239 IoGetConfigurationInformation()->CdRomCount
++;
243 TraceLog((CdromDebugWarning
,
244 "CDROM.SYS Add failed! %x\n", status
));
253 CdRomCreateDeviceObject(
254 IN PDRIVER_OBJECT DriverObject
,
255 IN PDEVICE_OBJECT PhysicalDeviceObject
262 This routine creates an object for the device and then calls the
263 SCSI port driver for media capacity and sector size.
267 DriverObject - Pointer to driver object created by system.
268 PortDeviceObject - to connect to SCSI port driver.
269 DeviceCount - Number of previously installed CDROMs.
270 PortCapabilities - Pointer to structure returned by SCSI port
271 driver describing adapter capabilites (and limitations).
272 LunInfo - Pointer to configuration information for this device.
280 UCHAR ntNameBuffer
[64];
281 //STRING ntNameString;
284 PDEVICE_OBJECT lowerDevice
= NULL
;
285 PDEVICE_OBJECT deviceObject
= NULL
;
286 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= NULL
;
287 PCDROM_DATA cdData
= NULL
;
288 PCDROM_DRIVER_EXTENSION driverExtension
= NULL
;
291 //CCHAR dosNameBuffer[64];
292 //CCHAR deviceNameBuffer[64];
293 //STRING deviceNameString;
295 //UNICODE_STRING dosUnicodeString;
296 //UNICODE_STRING unicodeString;
301 // Claim the device. Note that any errors after this
302 // will goto the generic handler, where the device will
306 lowerDevice
= IoGetAttachedDeviceReference(PhysicalDeviceObject
);
308 status
= ClassClaimDevice(lowerDevice
, FALSE
);
310 if(!NT_SUCCESS(status
)) {
313 // Someone already had this device - we're in trouble
316 ObDereferenceObject(lowerDevice
);
321 // Create device object for this device by first getting a unique name
322 // for the device and then creating it.
325 driverExtension
= IoGetDriverObjectExtension(DriverObject
,
326 CDROM_DRIVER_EXTENSION_ID
);
327 ASSERT(driverExtension
!= NULL
);
330 // InterlockedCdRomCounter is biased by 1.
333 deviceNumber
= InterlockedIncrement(&driverExtension
->InterlockedCdRomCounter
) - 1;
334 sprintf(ntNameBuffer
, "\\Device\\CdRom%d", deviceNumber
);
337 status
= ClassCreateDeviceObject(DriverObject
,
339 PhysicalDeviceObject
,
343 if (!NT_SUCCESS(status
)) {
344 TraceLog((CdromDebugWarning
,
345 "CreateCdRomDeviceObjects: Can not create device %s\n",
348 goto CreateCdRomDeviceObjectExit
;
352 // Indicate that IRPs should include MDLs.
355 SET_FLAG(deviceObject
->Flags
, DO_DIRECT_IO
);
357 fdoExtension
= deviceObject
->DeviceExtension
;
360 // Back pointer to device object.
363 fdoExtension
->CommonExtension
.DeviceObject
= deviceObject
;
366 // This is the physical device.
369 fdoExtension
->CommonExtension
.PartitionZeroExtension
= fdoExtension
;
372 // Initialize lock count to zero. The lock count is used to
373 // disable the ejection mechanism when media is mounted.
376 fdoExtension
->LockCount
= 0;
379 // Save system cdrom number
382 fdoExtension
->DeviceNumber
= deviceNumber
;
385 // Set the alignment requirements for the device based on the
386 // host adapter requirements
389 if (lowerDevice
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
390 deviceObject
->AlignmentRequirement
= lowerDevice
->AlignmentRequirement
;
394 // Save the device descriptors
397 fdoExtension
->AdapterDescriptor
= NULL
;
399 fdoExtension
->DeviceDescriptor
= NULL
;
402 // Clear the SrbFlags and disable synchronous transfers
405 fdoExtension
->SrbFlags
= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
408 // Finally, attach to the PDO
411 fdoExtension
->LowerPdo
= PhysicalDeviceObject
;
413 fdoExtension
->CommonExtension
.LowerDeviceObject
=
414 IoAttachDeviceToDeviceStack(deviceObject
, PhysicalDeviceObject
);
416 if(fdoExtension
->CommonExtension
.LowerDeviceObject
== NULL
) {
419 // Uh - oh, we couldn't attach
420 // cleanup and return
423 status
= STATUS_UNSUCCESSFUL
;
424 goto CreateCdRomDeviceObjectExit
;
428 // CdRom uses an extra stack location for synchronizing it's start io
432 deviceObject
->StackSize
++;
435 // cdData is used a few times below
438 cdData
= fdoExtension
->CommonExtension
.DriverData
;
441 // For NTMS to be able to easily determine drives-drv. letter matches.
444 status
= CdRomCreateWellKnownName( deviceObject
);
446 if (!NT_SUCCESS(status
)) {
447 TraceLog((CdromDebugWarning
,
448 "CdromCreateDeviceObjects: unable to create symbolic "
449 "link for device %wZ\n", &fdoExtension
->CommonExtension
.DeviceName
));
450 TraceLog((CdromDebugWarning
,
451 "CdromCreateDeviceObjects: (non-fatal error)\n"));
454 ClassUpdateInformationInRegistry(deviceObject
, "CdRom",
455 fdoExtension
->DeviceNumber
, NULL
, 0);
458 // from above IoGetAttachedDeviceReference
461 ObDereferenceObject(lowerDevice
);
464 // need to init timerlist here in case a remove occurs
465 // without a start, since we check the list is empty on remove.
468 cdData
->DelayedRetryIrp
= NULL
;
469 cdData
->DelayedRetryInterval
= 0;
472 // need this to be initialized for RPC Phase 1 drives (rpc0)
475 KeInitializeMutex(&cdData
->Rpc0RegionMutex
, 0);
478 // The device is initialized properly - mark it as such.
481 CLEAR_FLAG(deviceObject
->Flags
, DO_DEVICE_INITIALIZING
);
483 return(STATUS_SUCCESS
);
485 CreateCdRomDeviceObjectExit
:
488 // Release the device since an error occured.
491 // ClassClaimDevice(PortDeviceObject,
497 // from above IoGetAttachedDeviceReference
500 ObDereferenceObject(lowerDevice
);
502 if (deviceObject
!= NULL
) {
503 IoDeleteDevice(deviceObject
);
508 } // end CreateCdRomDeviceObject()
513 IN PDEVICE_OBJECT Fdo
520 This routine will complete the cd-rom initialization. This includes
521 allocating sense info buffers and srb s-lists, reading drive capacity
522 and setting up Media Change Notification (autorun).
524 This routine will not clean up allocate resources if it fails - that
525 is left for device stop/removal
529 Fdo - a pointer to the functional device object for this device
538 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
539 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
541 PCLASS_DRIVER_EXTENSION driverExtension
= ClassGetDriverExtension(
545 PVOID senseData
= NULL
;
548 PCDROM_DATA cddata
= NULL
;
550 //BOOLEAN changerDevice;
551 BOOLEAN isMmcDevice
= FALSE
;
562 // Build the lookaside list for srb's for the physical disk. Should only
566 ClassInitializeSrbLookasideList(&(fdoExtension
->CommonExtension
),
567 CDROM_SRB_LIST_SIZE
);
570 // Allocate request sense buffer.
573 senseData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
575 CDROM_TAG_SENSE_INFO
);
577 if (senseData
== NULL
) {
580 // The buffer cannot be allocated.
583 status
= STATUS_INSUFFICIENT_RESOURCES
;
584 goto CdRomInitDeviceExit
;
588 // Set the sense data pointer in the device extension.
591 fdoExtension
->SenseData
= senseData
;
594 // CDROMs are not partitionable so starting offset is 0.
597 commonExtension
->StartingOffset
.LowPart
= 0;
598 commonExtension
->StartingOffset
.HighPart
= 0;
601 // Set timeout value in seconds.
604 timeOut
= ClassQueryTimeOutRegistryValue(Fdo
);
606 fdoExtension
->TimeOutValue
= timeOut
;
608 fdoExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
611 cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
614 // Set up media change support defaults.
617 KeInitializeSpinLock(&cddata
->DelayedRetrySpinLock
);
619 cddata
->DelayedRetryIrp
= NULL
;
620 cddata
->DelayedRetryInterval
= 0;
621 cddata
->Mmc
.WriteAllowed
= FALSE
;
624 // Scan for controllers that require special processing.
630 // Determine if the drive is MMC-Capable
633 CdRomIsDeviceMmcDevice(Fdo
, &isMmcDevice
);
637 SET_FLAG(Fdo
->Characteristics
, FILE_READ_ONLY_DEVICE
);
642 // the drive supports at least a subset of MMC commands
643 // (and therefore supports READ_CD, etc...)
646 cddata
->Mmc
.IsMmc
= TRUE
;
649 // allocate a buffer for all the capabilities and such
652 status
= CdRomAllocateMmcResources(Fdo
);
653 if (!NT_SUCCESS(status
)) {
654 goto CdRomInitDeviceExit
;
660 // determine all the various media types from the profiles feature
663 PFEATURE_DATA_PROFILE_LIST profileHeader
;
664 ULONG mediaTypes
= 0;
667 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
668 "Checking all profiles for media types supported.\n"
671 profileHeader
= CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
672 cddata
->Mmc
.CapabilitiesBufferSize
,
674 if (profileHeader
== NULL
) {
677 // if profiles don't exist, there is something seriously
678 // wrong with this command -- it's either not a cdrom or
679 // one that hasn't implemented the spec correctly. exit
680 // now while we have the chance to do so safely.
682 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
683 "CdromDevice supports GET_CONFIGURATION, but "
684 "doesn't provide profiles for PDO %p!\n",
685 fdoExtension
->LowerPdo
));
686 status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
687 goto CdRomInitDeviceExit
;
691 for (i
= 0; i
< MAX_CDROM_MEDIA_TYPES
; i
++) {
693 BOOLEAN profileFound
;
694 CdRomFindProfileInProfiles(profileHeader
,
695 MediaProfileMatch
[i
].Profile
,
699 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
700 "CdromInit -> Found Profile %x => Media %x "
702 MediaProfileMatch
[i
].Profile
,
703 MediaProfileMatch
[i
].Media
,
707 cddata
->Mmc
.MediaProfileMatches
[mediaTypes
] =
708 MediaProfileMatch
[i
];
715 if (mediaTypes
== 0) {
718 // if profiles don't exist, there is something seriously
719 // wrong with this command -- it's either not a cdrom or
720 // one that hasn't implemented the spec correctly. exit
721 // now while we have the chance to do so safely.
723 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
724 "CdromDevice supports GET_CONFIGURATION, but "
725 "doesn't support any of the standard profiles "
726 "for PDO %p!\n", fdoExtension
->LowerPdo
));
727 status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
728 goto CdRomInitDeviceExit
;
732 cddata
->Mmc
.MediaTypes
= mediaTypes
;
736 #endif // media checks, and all failure paths due to bad firmware.
739 // if the drive supports target defect management and sector-addressable
740 // writes, then we should allow writes to the media.
743 if (CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
744 cddata
->Mmc
.CapabilitiesBufferSize
,
745 FeatureDefectManagement
) &&
746 CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
747 cddata
->Mmc
.CapabilitiesBufferSize
,
748 FeatureRandomWritable
)) {
751 // the drive is target defect managed, and supports random writes
752 // on sector-aligment. allow writes to occur by setting the error
753 // handler to point to a private media change detection handler.
756 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
757 "Found a WRITE capable device: %p\n", Fdo
));
760 // the write specific pages have been found --
761 // set the error handler and set it to require an update!
764 cddata
->Mmc
.UpdateState
= CdromMmcUpdateRequired
;
765 cddata
->ErrorHandler
= CdRomMmcErrorHandler
;
770 // ISSUE-2000/4/4-henrygab - mmc-compliant compliant drives should
771 // be initialized based upon reported
772 // capabilities, such as CSS, Analogue Audio,
773 // READ_CD capabilities, and (possibly) even
774 // drive capacity information.
777 TraceLog((CdromDebugWarning
,
778 "Defaulting to READ_CD because device %p is MMC compliant\n",
780 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
781 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
787 // Set the default geometry for the cdrom to match what NT 4 used.
788 // Classpnp will use these values to compute the cylinder count rather
789 // than using it's NT 5.0 defaults.
792 fdoExtension
->DiskGeometry
.TracksPerCylinder
= 0x40;
793 fdoExtension
->DiskGeometry
.SectorsPerTrack
= 0x20;
796 // Do READ CAPACITY. This SCSI command returns the last sector address
797 // on the device and the bytes per sector. These are used to calculate
798 // the drive capacity in bytes.
800 // NOTE: This should be change to send the Srb synchronously, then
801 // call CdRomInterpretReadCapacity() to properly setup the defaults.
804 status
= ClassReadDriveCapacity(Fdo
);
806 bps
= fdoExtension
->DiskGeometry
.BytesPerSector
;
808 if (!NT_SUCCESS(status
) || !bps
) {
810 TraceLog((CdromDebugWarning
,
811 "CdRomStartDevice: Can't read capacity for device %wZ\n",
812 &(fdoExtension
->CommonExtension
.DeviceName
)));
815 // Set disk geometry to default values (per ISO 9660).
819 fdoExtension
->SectorShift
= 11;
820 commonExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
825 // Insure that bytes per sector is a power of 2
826 // This corrects a problem with the HP 4020i CDR where it
827 // returns an incorrect number for bytes per sector.
830 lastBit
= (ULONG
) -1;
838 fdoExtension
->DiskGeometry
.BytesPerSector
= bps
;
839 TraceLog((CdromDebugTrace
, "CdRomInitDevice: Calc'd bps = %x\n", bps
));
842 ClassInitializeMediaChangeDetection(fdoExtension
, "CdRom");
846 // test for audio read capabilities
849 TraceLog((CdromDebugWarning
,
850 "Detecting XA_READ capabilities\n"));
852 if (CdRomGetDeviceType(Fdo
) == FILE_DEVICE_DVD
) {
854 TraceLog((CdromDebugWarning
,
855 "CdRomInitDevice: DVD Devices require START_UNIT\n"));
859 // all DVD devices must support the READ_CD command
862 TraceLog((CdromDebugWarning
,
863 "CdRomDetermineRawReadCapabilities: DVD devices "
864 "support READ_CD command for FDO %p\n", Fdo
));
865 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
866 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
869 status
= STATUS_SUCCESS
;
871 } else if ((fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeScsi
) &&
872 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeAta
) &&
873 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeAtapi
) &&
874 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeUnknown
)
878 // devices on the newer busses must support READ_CD command
881 TraceLog((CdromDebugWarning
,
882 "CdRomDetermineRawReadCapabilities: Devices for newer "
883 "busses must support READ_CD command for FDO %p, Bus %x\n",
884 Fdo
, fdoExtension
->DeviceDescriptor
->BusType
));
885 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
886 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
891 // now clear all our READ_CD flags if the drive should have supported
892 // it, but we are not sure it actually does. we still won't query
893 // the drive more than one time if it supports the command.
896 if (TEST_FLAG(cddata
->HackFlags
, CDROM_HACK_FORCE_READ_CD_DETECTION
)) {
898 TraceLog((CdromDebugWarning
,
899 "Forcing detection of READ_CD for FDO %p because "
900 "testing showed some firmware did not properly support it\n",
902 CLEAR_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
908 // read our READ_CD support in the registry if it was seeded.
911 ULONG readCdSupported
= 0;
913 ClassGetDeviceParameter(fdoExtension
,
919 if (readCdSupported
!= 0) {
921 TraceLog((CdromDebugWarning
,
922 "Defaulting to READ_CD because previously detected "
923 "that the device supports it for Fdo %p.\n",
926 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
934 // backwards-compatible hackish attempt to determine if the drive
935 // supports any method of reading digital audio from the disc.
938 if (!TEST_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
)) {
940 SCSI_REQUEST_BLOCK srb
;
943 PUCHAR buffer
= NULL
;
947 // ISSUE-2000/07/05-henrygab - use the mode page to determine
948 // READ_CD support, then fall back on the below
949 // (unreliable?) hack.
953 // Build the MODE SENSE CDB. The data returned will be kept in the
954 // device extension and used to set block size.
957 length
= max(sizeof(ERROR_RECOVERY_DATA
),sizeof(ERROR_RECOVERY_DATA10
));
959 buffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
961 CDROM_TAG_MODE_DATA
);
964 TraceLog((CdromDebugWarning
,
965 "CdRomDetermineRawReadCapabilities: cannot allocate "
966 "buffer, so leaving for FDO %p\n", Fdo
));
967 status
= STATUS_INSUFFICIENT_RESOURCES
;
968 goto CdRomInitDeviceExit
;
971 for (count
= 0; count
< 2; count
++) {
974 length
= sizeof(ERROR_RECOVERY_DATA
);
976 length
= sizeof(ERROR_RECOVERY_DATA10
);
979 RtlZeroMemory(buffer
, length
);
980 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
983 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
987 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
988 cdb
->MODE_SENSE
.PageCode
= 0x1;
989 // note: not setting DBD in order to get the block descriptor!
990 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
993 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
994 cdb
->MODE_SENSE10
.PageCode
= 0x1;
995 // note: not setting DBD in order to get the block descriptor!
996 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
997 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1000 status
= ClassSendSrbSynchronous(Fdo
,
1007 if (NT_SUCCESS(status
) || (status
== STATUS_DATA_OVERRUN
)) {
1010 // STATUS_DATA_OVERRUN means it's a newer drive with more info
1011 // to tell us, so it's probably able to support READ_CD
1014 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
1017 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1019 status
= ClassSendSrbSynchronous(Fdo
,
1025 if (NT_SUCCESS(status
) ||
1026 (status
== STATUS_NO_MEDIA_IN_DEVICE
) ||
1027 (status
== STATUS_NONEXISTENT_SECTOR
) ||
1028 (status
== STATUS_UNRECOGNIZED_MEDIA
)
1035 TraceLog((CdromDebugWarning
,
1036 "CdRomDetermineRawReadCapabilities: Using "
1037 "READ_CD for FDO %p due to status %x\n",
1040 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
1043 // ignore errors in saving this info
1046 ClassSetDeviceParameter(fdoExtension
,
1053 break; // out of the for loop
1057 TraceLog((CdromDebugWarning
,
1058 "CdRomDetermineRawReadCapabilities: Using "
1059 "%s-byte mode switching for FDO %p due to status "
1060 "%x returned for READ_CD\n",
1061 ((count
== 0) ? "6" : "10"), Fdo
, status
));
1064 SET_FLAG(cddata
->XAFlags
, XA_USE_6_BYTE
);
1065 RtlCopyMemory(&cddata
->Header
,
1067 sizeof(ERROR_RECOVERY_DATA
));
1068 cddata
->Header
.ModeDataLength
= 0;
1070 SET_FLAG(cddata
->XAFlags
, XA_USE_10_BYTE
);
1071 RtlCopyMemory(&cddata
->Header10
,
1073 sizeof(ERROR_RECOVERY_DATA10
));
1074 cddata
->Header10
.ModeDataLength
[0] = 0;
1075 cddata
->Header10
.ModeDataLength
[1] = 0;
1077 break; // out of for loop
1080 TraceLog((CdromDebugWarning
,
1081 "FDO %p failed %x byte mode sense, status %x\n",
1083 ((count
== 0) ? 6 : 10),
1088 // mode sense failed
1091 } // end of for loop to try 6 and 10-byte mode sense
1096 // nothing worked. we probably cannot support digital
1097 // audio extraction from this drive
1100 TraceLog((CdromDebugWarning
,
1101 "CdRomDetermineRawReadCapabilities: FDO %p "
1102 "cannot support READ_CD\n", Fdo
));
1103 CLEAR_FLAG(cddata
->XAFlags
, XA_PLEXTOR_CDDA
);
1104 CLEAR_FLAG(cddata
->XAFlags
, XA_NEC_CDDA
);
1105 SET_FLAG(cddata
->XAFlags
, XA_NOT_SUPPORTED
);
1107 } // end of count == 2
1110 // free our resources
1116 // set a successful status
1117 // (in case someone later checks this)
1120 status
= STATUS_SUCCESS
;
1125 // Register interfaces for this device.
1129 UNICODE_STRING interfaceName
;
1131 RtlInitUnicodeString(&interfaceName
, NULL
);
1133 status
= IoRegisterDeviceInterface(fdoExtension
->LowerPdo
,
1134 (LPGUID
) &CdRomClassGuid
,
1138 if(NT_SUCCESS(status
)) {
1140 cddata
->CdromInterfaceString
= interfaceName
;
1142 status
= IoSetDeviceInterfaceState(
1146 if(!NT_SUCCESS(status
)) {
1148 TraceLog((CdromDebugWarning
,
1149 "CdromInitDevice: Unable to register cdrom "
1150 "DCA for fdo %p [%lx]\n",
1156 return(STATUS_SUCCESS
);
1158 CdRomInitDeviceExit
:
1160 CdRomDeAllocateMmcResources(Fdo
);
1161 RtlZeroMemory(&(cddata
->Mmc
), sizeof(CDROM_MMC_EXTENSION
));
1170 IN PDEVICE_OBJECT Fdo
1174 Routine Description:
1176 This routine starts the timer for the cdrom
1180 Fdo - a pointer to the functional device object for this device
1189 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1190 PCDROM_DATA cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
1191 PDVD_COPY_PROTECT_KEY copyProtectKey
;
1192 PDVD_RPC_KEY rpcKey
;
1193 IO_STATUS_BLOCK ioStatus
;
1196 // CdRomCreateWellKnownName(Fdo);
1199 // if we have a DVD-ROM
1200 // if we have a rpc0 device
1201 // fake a rpc2 device
1202 // if device does not have a dvd region set
1203 // select a dvd region for the user
1206 cddata
->DvdRpc0Device
= FALSE
;
1209 // since StartIo() will call IoStartNextPacket() on error, allowing
1210 // StartIo() to be non-recursive prevents stack overflow bugchecks in
1211 // severe error cases (such as fault-injection in the verifier).
1213 // the only difference is that the thread context may be different
1214 // in StartIo() than in the caller of IoStartNextPacket().
1217 IoSetStartIoAttributes(Fdo
, TRUE
, TRUE
);
1220 // check to see if we have a DVD device
1223 if (CdRomGetDeviceType(Fdo
) != FILE_DEVICE_DVD
) {
1224 return STATUS_SUCCESS
;
1228 // we got a DVD drive.
1229 // now, figure out if we have a RPC0 device
1232 bufferLen
= DVD_RPC_KEY_LENGTH
;
1234 (PDVD_COPY_PROTECT_KEY
)ExAllocatePoolWithTag(PagedPool
,
1236 DVD_TAG_RPC2_CHECK
);
1238 if (copyProtectKey
== NULL
) {
1239 return STATUS_INSUFFICIENT_RESOURCES
;
1243 // get the device region
1245 RtlZeroMemory (copyProtectKey
, bufferLen
);
1246 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
1247 copyProtectKey
->KeyType
= DvdGetRpcKey
;
1250 // Build a request for READ_KEY
1252 ClassSendDeviceIoControlSynchronous(
1262 if (!NT_SUCCESS(ioStatus
.Status
)) {
1265 // we have a rpc0 device
1267 // NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
1270 cddata
->DvdRpc0Device
= TRUE
;
1272 TraceLog((CdromDebugWarning
,
1273 "CdromStartDevice (%p): RPC Phase 1 drive detected\n",
1277 // note: we could force this chosen now, but it's better to reduce
1278 // the number of code paths that could be taken. always delay to
1279 // increase the percentage code coverage.
1282 TraceLog((CdromDebugWarning
,
1283 "CdromStartDevice (%p): Delay DVD Region Selection\n",
1286 cddata
->Rpc0SystemRegion
= 0xff;
1287 cddata
->Rpc0SystemRegionResetCount
= DVD_MAX_REGION_RESET_COUNT
;
1288 cddata
->PickDvdRegion
= 1;
1289 cddata
->Rpc0RetryRegistryCallback
= 1;
1290 ExFreePool(copyProtectKey
);
1291 return STATUS_SUCCESS
;
1295 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
1298 // TypeCode of zero means that no region has been set.
1301 if (rpcKey
->TypeCode
== 0) {
1302 TraceLog((CdromDebugWarning
,
1303 "CdromStartDevice (%p): must choose DVD region\n",
1305 cddata
->PickDvdRegion
= 1;
1306 CdRomPickDvdRegion(Fdo
);
1310 ExFreePool (copyProtectKey
);
1312 return STATUS_SUCCESS
;
1318 IN PDEVICE_OBJECT DeviceObject
,
1322 return STATUS_SUCCESS
;
1328 IN PDEVICE_OBJECT Fdo
,
1333 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
1334 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1336 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1337 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1338 PIO_STACK_LOCATION irpStack
;
1342 ULONG transferPages
;
1343 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1344 //LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
1346 PSCSI_REQUEST_BLOCK srb
= NULL
;
1348 PUCHAR senseBuffer
= NULL
;
1354 // Mark IRP with status pending.
1357 IoMarkIrpPending(Irp
);
1359 cdData
= (PCDROM_DATA
)(fdoExtension
->CommonExtension
.DriverData
);
1360 use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
1363 // if this test is true, then we will exit the routine within this
1364 // code block, queueing the irp for later completion.
1367 if ((cdData
->Mmc
.IsMmc
) &&
1368 (cdData
->Mmc
.UpdateState
!= CdromMmcUpdateComplete
)
1372 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1373 "CdRomStartIo: [%p] Device needs to update capabilities\n",
1375 ASSERT(cdData
->Mmc
.IsMmc
);
1376 ASSERT(cdData
->Mmc
.CapabilitiesIrp
!= NULL
);
1377 ASSERT(cdData
->Mmc
.CapabilitiesIrp
!= Irp
);
1382 // the state was either UpdateRequired (which means we will
1383 // have to start the work item) or UpdateStarted (which means
1384 // we have already started the work item at least once -- may
1385 // transparently change to UpdateComplete).
1387 // if it's update required, we just queue it, change to UpdateStarted,
1388 // start the workitem, and start the next packet.
1390 // else, we must queue the item and check the queue depth. if the
1391 // queue depth is equal to 1, that means the worker item from the
1392 // previous attempt has already de-queued the items, so we should
1393 // call this routine again (retry) as an optimization rather than
1394 // re-add it this irp to the queue. since this is tail recursion,
1395 // it won't take much/any stack to do this.
1397 // NOTE: This presumes the following items are true:
1399 // we only add to the list from CdRomStartIo(), which is serialized.
1400 // we only set to UpdateStarted from CdRomStartIo(), and only if
1401 // the state was UpdateRequired.
1402 // we only set to UpdateRequired from CdRomMmcErrorHandler(), and
1403 // only if the state was UpdateComplete.
1404 // we only set to UpdateComplete from the workitem, and assert the
1405 // state was UpdateStarted.
1406 // we flush the entire queue in one atomic operation in the workitem,
1407 // except in the special case described above when we dequeue
1408 // the request immediately.
1410 // order of operations is vitally important: queue, then test the depth
1411 // this will prevent lost irps.
1414 ExInterlockedPushEntrySList(&(cdData
->Mmc
.DelayedIrps
),
1415 (PSINGLE_LIST_ENTRY
)&(Irp
->Tail
.Overlay
.DriverContext
[0]),
1416 &(cdData
->Mmc
.DelayedLock
));
1418 queueDepth
= ExQueryDepthSList(&(cdData
->Mmc
.DelayedIrps
));
1419 if (queueDepth
== 1) {
1421 if (cdData
->Mmc
.UpdateState
== CdromMmcUpdateRequired
) {
1425 // should free any old partition list info that
1426 // we've previously saved away and then start the WorkItem
1429 oldState
= InterlockedExchange(&cdData
->Mmc
.UpdateState
,
1430 CdromMmcUpdateStarted
);
1431 ASSERT(oldState
== CdromMmcUpdateRequired
);
1433 IoQueueWorkItem(cdData
->Mmc
.CapabilitiesWorkItem
,
1434 CdRomUpdateMmcDriveCapabilities
,
1441 // they *just* finished updating, so we should flush the list
1442 // back onto the StartIo queue and start the next packet.
1445 CdRompFlushDelayedList(Fdo
, &(cdData
->Mmc
), STATUS_SUCCESS
, FALSE
);
1452 // start the next packet so we don't deadlock....
1455 IoStartNextPacket(Fdo
, FALSE
);
1461 // If the flag is set in the device object
1462 // force a verify for READ, WRITE and RAW_READ requests
1463 // Note that ioctls are passed through....
1466 if (TEST_FLAG(Fdo
->Flags
, DO_VERIFY_VOLUME
) &&
1467 IS_READ_WRITE_REQUEST(currentIrpStack
)) {
1469 TraceLog((CdromDebugTrace
,
1470 "CdRomStartIo: [%p] Volume needs verified\n", Irp
));
1472 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1474 if (Irp
->Tail
.Overlay
.Thread
) {
1475 IoSetHardErrorOrVerifyDevice(Irp
, Fdo
);
1478 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1480 TraceLog((CdromDebugTrace
,
1481 "CdRomStartIo: [%p] Calling UpdateCapcity - "
1482 "ioctl event = %p\n",
1484 nextIrpStack
->Parameters
.Others
.Argument1
1488 // our device control dispatch routine stores an event in the next
1489 // stack location to signal when startio has completed. We need to
1490 // pass this in so that the update capacity completion routine can
1491 // set it rather than completing the Irp.
1494 status
= CdRomUpdateCapacity(fdoExtension
,
1496 nextIrpStack
->Parameters
.Others
.Argument1
1499 TraceLog((CdromDebugTrace
,
1500 "CdRomStartIo: [%p] UpdateCapacity returned %lx\n",
1507 // fail writes if they are not allowed...
1510 if ((currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) &&
1511 !(cdData
->Mmc
.WriteAllowed
)) {
1513 TraceLog((CdromDebugError
,
1514 "CdRomStartIo: [%p] Device %p failing write request\n",
1517 Irp
->IoStatus
.Information
= 0;
1518 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1520 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1524 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
1525 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
1527 ULONG maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
1530 // Add partition byte offset to make starting byte relative to
1531 // beginning of disk.
1534 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+=
1535 (fdoExtension
->CommonExtension
.StartingOffset
.QuadPart
);
1538 // Calculate number of pages in this transfer.
1541 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1542 currentIrpStack
->Parameters
.Read
.Length
);
1545 // Check if request length is greater than the maximum number of
1546 // bytes that the hardware can transfer.
1549 if (cdData
->RawAccess
) {
1552 // a writable device must be MMC compliant, which supports
1553 // READ_CD commands.
1556 ASSERT(currentIrpStack
->MajorFunction
!= IRP_MJ_WRITE
);
1558 ASSERT(!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
));
1561 // Fire off a mode select to switch back to cooked sectors.
1564 irp2
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1), FALSE
);
1567 Irp
->IoStatus
.Information
= 0;
1568 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1571 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1575 srb
= ExAllocatePoolWithTag(NonPagedPool
,
1576 sizeof(SCSI_REQUEST_BLOCK
),
1580 Irp
->IoStatus
.Information
= 0;
1581 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1584 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1588 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1590 cdb
= (PCDB
)srb
->Cdb
;
1593 // Allocate sense buffer.
1596 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1598 CDROM_TAG_SENSE_INFO
);
1603 Irp
->IoStatus
.Information
= 0;
1604 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1607 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1615 IoSetNextIrpStackLocation(irp2
);
1616 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1617 irp2
->IoStatus
.Information
= 0;
1619 irp2
->UserBuffer
= NULL
;
1622 // Save the device object and irp in a private stack location.
1625 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1626 irpStack
->DeviceObject
= Fdo
;
1627 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1630 // The retry count will be in the real Irp, as the retry logic will
1631 // recreate our private irp.
1634 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1637 // Only jam this in if it doesn't exist. The completion routines can
1638 // call StartIo directly in the case of retries and resetting it will
1639 // cause infinite loops.
1642 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1646 // Construct the IRP stack for the lower level driver.
1649 irpStack
= IoGetNextIrpStackLocation(irp2
);
1650 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1651 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1652 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1654 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1655 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1656 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1658 srb
->OriginalRequest
= irp2
;
1659 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1660 srb
->SenseInfoBuffer
= senseBuffer
;
1662 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1664 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1669 ExFreePool(senseBuffer
);
1672 Irp
->IoStatus
.Information
= 0;
1673 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1676 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1681 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1687 if (!irp2
->MdlAddress
) {
1688 ExFreePool(senseBuffer
);
1690 ExFreePool(dataBuffer
);
1692 Irp
->IoStatus
.Information
= 0;
1693 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1696 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1704 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1706 srb
->DataBuffer
= dataBuffer
;
1709 // Set the new block size in the descriptor.
1713 cdData
->BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1714 cdData
->BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1715 cdData
->BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1717 cdData
->BlockDescriptor10
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1718 cdData
->BlockDescriptor10
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1719 cdData
->BlockDescriptor10
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1723 // Move error page into dataBuffer.
1726 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, transferByteCount
);
1729 // Build and send a mode select to switch into raw mode.
1732 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
1733 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
1734 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
1735 srb
->DataTransferLength
= transferByteCount
;
1736 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
1740 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1741 cdb
->MODE_SELECT
.PFBit
= 1;
1742 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1744 srb
->CdbLength
= 10;
1745 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1746 cdb
->MODE_SELECT10
.PFBit
= 1;
1747 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1748 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1752 // Update completion routine.
1755 IoSetCompletionRoutine(irp2
,
1756 CdRomSwitchModeCompletion
,
1762 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
1768 // Request needs to be split. Completion of each portion of the
1769 // request will fire off the next portion. The final request will
1770 // signal Io to send a new request.
1774 fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
- 1;
1776 if(maximumTransferLength
> (transferPages
<< PAGE_SHIFT
)) {
1777 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1781 // Check that the maximum transfer size is not zero
1784 if(maximumTransferLength
== 0) {
1785 maximumTransferLength
= PAGE_SIZE
;
1788 ClassSplitRequest(Fdo
, Irp
, maximumTransferLength
);
1791 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1794 // Allocate an irp, srb and associated structures.
1797 irp2
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1),
1801 Irp
->IoStatus
.Information
= 0;
1802 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1805 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1809 srb
= ExAllocatePoolWithTag(NonPagedPool
,
1810 sizeof(SCSI_REQUEST_BLOCK
),
1814 Irp
->IoStatus
.Information
= 0;
1815 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1818 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1822 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1824 cdb
= (PCDB
)srb
->Cdb
;
1827 // Allocate sense buffer.
1830 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1832 CDROM_TAG_SENSE_INFO
);
1837 Irp
->IoStatus
.Information
= 0;
1838 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1841 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1845 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
1851 IoSetNextIrpStackLocation(irp2
);
1852 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1853 irp2
->IoStatus
.Information
= 0;
1855 irp2
->UserBuffer
= NULL
;
1858 // Save the device object and irp in a private stack location.
1861 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1862 irpStack
->DeviceObject
= Fdo
;
1863 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1866 // The retry count will be in the real Irp, as the retry logic will
1867 // recreate our private irp.
1870 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1873 // Only jam this in if it doesn't exist. The completion routines can
1874 // call StartIo directly in the case of retries and resetting it will
1875 // cause infinite loops.
1878 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1882 // keep track of the new irp as Argument3
1885 nextIrpStack
->Parameters
.Others
.Argument3
= irp2
;
1889 // Construct the IRP stack for the lower level driver.
1892 irpStack
= IoGetNextIrpStackLocation(irp2
);
1893 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1894 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1895 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1897 IoSetCompletionRoutine(irp2
,
1898 CdRomDeviceControlCompletion
,
1904 // Setup those fields that are generic to all requests.
1907 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1908 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1909 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1911 srb
->OriginalRequest
= irp2
;
1912 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1913 srb
->SenseInfoBuffer
= senseBuffer
;
1915 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1918 case IOCTL_CDROM_RAW_READ
: {
1921 // Determine whether the drive is currently in raw or cooked mode,
1922 // and which command to use to read the data.
1925 if (!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
)) {
1927 PRAW_READ_INFO rawReadInfo
=
1928 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1929 ULONG maximumTransferLength
;
1930 ULONG transferPages
;
1932 if (cdData
->RawAccess
) {
1934 ULONG startingSector
;
1935 //UCHAR min, sec, frame;
1938 // Free the recently allocated irp, as we don't need it.
1943 cdb
= (PCDB
)srb
->Cdb
;
1944 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
1947 // Calculate starting offset.
1950 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
1951 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1952 maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
1953 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1957 // Determine if request is within limits imposed by miniport.
1959 if (transferByteCount
> maximumTransferLength
||
1960 transferPages
> fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
) {
1963 // The claim is that this won't happen, and is backed up by
1964 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1965 // we get only 4 sector requests.
1968 ExFreePool(senseBuffer
);
1971 Irp
->IoStatus
.Information
= 0;
1972 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1975 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1980 srb
->OriginalRequest
= Irp
;
1981 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
1982 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
1983 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
1984 srb
->DataTransferLength
= transferByteCount
;
1985 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
1986 srb
->CdbLength
= 10;
1987 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1989 if (rawReadInfo
->TrackMode
== CDDA
) {
1990 if (TEST_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
)) {
1992 srb
->CdbLength
= 12;
1994 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
1995 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
1996 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
1997 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
1999 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2000 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2001 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
2002 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
2004 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
2005 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
2007 } else if (TEST_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
)) {
2009 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
2010 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
2011 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
2012 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
2014 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2015 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2017 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
2021 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2022 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2024 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
2025 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
2026 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
2027 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
2029 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
2032 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2034 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2035 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2037 // HACKHACK - REF #0001
2040 // Set up IoCompletion routine address.
2043 IoSetCompletionRoutine(Irp
,
2050 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, Irp
);
2055 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
2056 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2060 ExFreePool(senseBuffer
);
2063 Irp
->IoStatus
.Information
= 0;
2064 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2067 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2072 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2078 if (!irp2
->MdlAddress
) {
2079 ExFreePool(senseBuffer
);
2081 ExFreePool(dataBuffer
);
2083 Irp
->IoStatus
.Information
= 0;
2084 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2087 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2095 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2097 srb
->DataBuffer
= dataBuffer
;
2100 // Set the new block size in the descriptor.
2101 // This will set the block read size to RAW_SECTOR_SIZE
2102 // TODO: Set density code, based on operation
2106 cdData
->BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2107 cdData
->BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2108 cdData
->BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2109 cdData
->BlockDescriptor
.DensityCode
= 0;
2111 cdData
->BlockDescriptor10
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2112 cdData
->BlockDescriptor10
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2113 cdData
->BlockDescriptor10
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2114 cdData
->BlockDescriptor10
.DensityCode
= 0;
2118 // Move error page into dataBuffer.
2121 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, transferByteCount
);
2125 // Build and send a mode select to switch into raw mode.
2128 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2129 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2130 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
2131 srb
->DataTransferLength
= transferByteCount
;
2132 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
2136 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2137 cdb
->MODE_SELECT
.PFBit
= 1;
2138 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2141 srb
->CdbLength
= 10;
2142 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2143 cdb
->MODE_SELECT10
.PFBit
= 1;
2144 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2145 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2149 // Update completion routine.
2152 IoSetCompletionRoutine(irp2
,
2153 CdRomSwitchModeCompletion
,
2163 PRAW_READ_INFO rawReadInfo
=
2164 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2165 ULONG startingSector
;
2168 // Free the recently allocated irp, as we don't need it.
2173 cdb
= (PCDB
)srb
->Cdb
;
2174 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
2178 // Calculate starting offset.
2181 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
2182 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2184 srb
->OriginalRequest
= Irp
;
2185 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2186 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2187 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2188 srb
->DataTransferLength
= transferByteCount
;
2189 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2190 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2191 srb
->CdbLength
= 12;
2192 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2195 // Fill in CDB fields.
2198 cdb
= (PCDB
)srb
->Cdb
;
2201 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2202 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2203 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2206 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2207 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2208 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2209 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2212 // Setup cdb depending upon the sector type we want.
2215 switch (rawReadInfo
->TrackMode
) {
2218 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2219 cdb
->READ_CD
.IncludeUserData
= 1;
2220 cdb
->READ_CD
.HeaderCode
= 3;
2221 cdb
->READ_CD
.IncludeSyncData
= 1;
2226 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2227 cdb
->READ_CD
.IncludeUserData
= 1;
2228 cdb
->READ_CD
.HeaderCode
= 1;
2229 cdb
->READ_CD
.IncludeSyncData
= 1;
2234 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2235 cdb
->READ_CD
.IncludeUserData
= 1;
2236 cdb
->READ_CD
.HeaderCode
= 3;
2237 cdb
->READ_CD
.IncludeSyncData
= 1;
2241 ExFreePool(senseBuffer
);
2243 Irp
->IoStatus
.Information
= 0;
2244 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2247 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2251 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2253 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2254 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2256 // HACKHACK - REF #0001
2259 // Set up IoCompletion routine address.
2262 IoSetCompletionRoutine(Irp
,
2269 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, Irp
);
2274 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2279 // the _EX version does the same thing on the front end
2282 case IOCTL_DISK_GET_LENGTH_INFO
:
2283 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2284 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2285 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
:
2286 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2289 // Issue ReadCapacity to update device extension
2290 // with information for current media.
2293 TraceLog((CdromDebugError
,
2294 "CdRomStartIo: Get drive geometry/length "
2295 "info (%p)\n", Irp
));
2298 // setup remaining srb and cdb parameters.
2301 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2302 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2303 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2304 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2305 srb
->CdbLength
= 10;
2306 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2308 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2309 sizeof(READ_CAPACITY_DATA
),
2310 CDROM_TAG_READ_CAP
);
2312 ExFreePool(senseBuffer
);
2315 Irp
->IoStatus
.Information
= 0;
2316 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2319 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2324 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2325 sizeof(READ_CAPACITY_DATA
),
2330 if (!irp2
->MdlAddress
) {
2331 ExFreePool(senseBuffer
);
2333 ExFreePool(dataBuffer
);
2335 Irp
->IoStatus
.Information
= 0;
2336 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2339 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2347 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2349 srb
->DataBuffer
= dataBuffer
;
2350 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2352 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2356 case IOCTL_CDROM_GET_CONFIGURATION
: {
2358 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer
;
2360 TraceLog((CdromDebugError
,
2361 "CdRomStartIo: Get configuration (%p)\n", Irp
));
2363 if (!cdData
->Mmc
.IsMmc
) {
2364 ExFreePool(senseBuffer
);
2367 Irp
->IoStatus
.Information
= 0;
2368 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
2370 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2374 transferByteCount
= currentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
2376 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2378 CDROM_TAG_GET_CONFIG
);
2380 ExFreePool(senseBuffer
);
2383 Irp
->IoStatus
.Information
= 0;
2384 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2386 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2390 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2395 if (!irp2
->MdlAddress
) {
2396 ExFreePool(dataBuffer
);
2397 ExFreePool(senseBuffer
);
2400 Irp
->IoStatus
.Information
= 0;
2401 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2403 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2407 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2410 // setup remaining srb and cdb parameters
2413 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2414 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2415 srb
->DataTransferLength
= transferByteCount
;
2416 srb
->CdbLength
= 10;
2417 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2418 srb
->DataBuffer
= dataBuffer
;
2420 cdb
->GET_CONFIGURATION
.OperationCode
= SCSIOP_GET_CONFIGURATION
;
2421 cdb
->GET_CONFIGURATION
.AllocationLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2422 cdb
->GET_CONFIGURATION
.AllocationLength
[1] = (UCHAR
)(transferByteCount
& 0xff);
2424 inputBuffer
= (PGET_CONFIGURATION_IOCTL_INPUT
)Irp
->AssociatedIrp
.SystemBuffer
;
2425 cdb
->GET_CONFIGURATION
.StartingFeature
[0] = (UCHAR
)(inputBuffer
->Feature
>> 8);
2426 cdb
->GET_CONFIGURATION
.StartingFeature
[1] = (UCHAR
)(inputBuffer
->Feature
& 0xff);
2427 cdb
->GET_CONFIGURATION
.RequestType
= (UCHAR
)(inputBuffer
->RequestType
);
2429 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2433 case IOCTL_DISK_VERIFY
: {
2435 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2436 LARGE_INTEGER byteOffset
;
2440 if (!cdData
->Mmc
.WriteAllowed
) {
2441 ExFreePool(senseBuffer
);
2444 Irp
->IoStatus
.Information
= 0;
2445 Irp
->IoStatus
.Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2447 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2454 srb
->CdbLength
= 10;
2456 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2459 // Add disk offset to starting sector.
2462 byteOffset
.QuadPart
= commonExtension
->StartingOffset
.QuadPart
+
2463 verifyInfo
->StartingOffset
.QuadPart
;
2466 // Convert byte offset to sector offset.
2469 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> fdoExtension
->SectorShift
);
2472 // Convert ULONG byte count to USHORT sector count.
2475 sectorCount
= (USHORT
)(verifyInfo
->Length
>> fdoExtension
->SectorShift
);
2478 // Move little endian values into CDB in big endian format.
2481 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2482 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2483 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2484 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2486 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2487 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2490 // The verify command is used by the NT FORMAT utility and
2491 // requests are sent down for 5% of the volume size. The
2492 // request timeout value is calculated based on the number of
2493 // sectors verified.
2496 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2497 fdoExtension
->TimeOutValue
;
2499 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2503 case IOCTL_STORAGE_CHECK_VERIFY
:
2504 case IOCTL_DISK_CHECK_VERIFY
:
2505 case IOCTL_CDROM_CHECK_VERIFY
: {
2508 // Since a test unit ready is about to be performed, reset the
2509 // timer value to decrease the opportunities for it to race with
2513 ClassResetMediaChangeTimer(fdoExtension
);
2516 // Set up the SRB/CDB
2520 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2521 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
2522 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2523 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2524 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2527 TraceLog((CdromDebugTrace
,
2528 "CdRomStartIo: [%p] Sending CHECK_VERIFY irp %p\n",
2530 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2534 case IOCTL_DVD_READ_STRUCTURE
: {
2536 CdRomDeviceControlDvdReadStructure(Fdo
, Irp
, irp2
, srb
);
2541 case IOCTL_DVD_END_SESSION
: {
2542 CdRomDeviceControlDvdEndSession(Fdo
, Irp
, irp2
, srb
);
2546 case IOCTL_DVD_START_SESSION
:
2547 case IOCTL_DVD_READ_KEY
: {
2549 CdRomDeviceControlDvdStartSessionReadKey(Fdo
, Irp
, irp2
, srb
);
2555 case IOCTL_DVD_SEND_KEY
:
2556 case IOCTL_DVD_SEND_KEY2
: {
2558 CdRomDeviceControlDvdSendKey (Fdo
, Irp
, irp2
, srb
);
2564 case IOCTL_CDROM_READ_TOC_EX
: {
2566 PCDROM_READ_TOC_EX inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2568 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2570 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2574 ExFreePool(senseBuffer
);
2577 Irp
->IoStatus
.Information
= 0;
2578 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2581 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2586 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2592 if (!irp2
->MdlAddress
) {
2593 ExFreePool(senseBuffer
);
2595 ExFreePool(dataBuffer
);
2597 Irp
->IoStatus
.Information
= 0;
2598 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2601 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2606 // setup the request per user request
2607 // do validity checking in devctl dispatch, not here
2610 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2611 cdb
->READ_TOC
.Msf
= inputBuffer
->Msf
;
2612 cdb
->READ_TOC
.Format2
= inputBuffer
->Format
;
2613 cdb
->READ_TOC
.StartingTrack
= inputBuffer
->SessionTrack
;
2614 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2615 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
)(transferByteCount
& 0xff);
2621 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2624 // do the standard stuff....
2627 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2628 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2629 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2630 srb
->DataTransferLength
= transferByteCount
;
2631 srb
->CdbLength
= 10;
2632 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2633 srb
->DataBuffer
= dataBuffer
;
2635 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2639 case IOCTL_CDROM_GET_LAST_SESSION
:
2640 case IOCTL_CDROM_READ_TOC
: {
2642 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2643 IOCTL_CDROM_GET_LAST_SESSION
) {
2646 // Set format to return first and last session numbers.
2649 cdb
->READ_TOC
.Format
= CDROM_READ_TOC_EX_FORMAT_SESSION
;
2654 // Use MSF addressing
2657 cdb
->READ_TOC
.Msf
= 1;
2663 currentIrpStack
->Parameters
.Read
.Length
>
2664 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2665 currentIrpStack
->Parameters
.Read
.Length
;
2668 // Set size of TOC structure.
2671 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2672 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2675 // setup remaining srb and cdb parameters.
2678 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2679 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2680 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2681 srb
->DataTransferLength
= transferByteCount
;
2682 srb
->CdbLength
= 10;
2683 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2685 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2689 ExFreePool(senseBuffer
);
2692 Irp
->IoStatus
.Information
= 0;
2693 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2696 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2701 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2707 if (!irp2
->MdlAddress
) {
2708 ExFreePool(senseBuffer
);
2710 ExFreePool(dataBuffer
);
2712 Irp
->IoStatus
.Information
= 0;
2713 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2716 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2724 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2726 srb
->DataBuffer
= dataBuffer
;
2727 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2729 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2734 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2736 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2739 // Set up the SRB/CDB
2742 srb
->CdbLength
= 10;
2743 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2745 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2746 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2747 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2749 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2750 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2751 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2753 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2754 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2755 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2756 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2758 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2763 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2766 PSUB_Q_CHANNEL_DATA userChannelData
=
2767 Irp
->AssociatedIrp
.SystemBuffer
;
2769 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2770 Irp
->AssociatedIrp
.SystemBuffer
;
2773 // Allocate buffer for subq channel information.
2776 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2777 sizeof(SUB_Q_CHANNEL_DATA
),
2781 ExFreePool(senseBuffer
);
2784 Irp
->IoStatus
.Information
= 0;
2785 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2788 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2793 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2794 sizeof(SUB_Q_CHANNEL_DATA
),
2799 if (!irp2
->MdlAddress
) {
2800 ExFreePool(senseBuffer
);
2802 ExFreePool(dataBuffer
);
2804 Irp
->IoStatus
.Information
= 0;
2805 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2808 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2816 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2818 srb
->DataBuffer
= dataBuffer
;
2821 // Always logical unit 0, but only use MSF addressing
2822 // for IOCTL_CDROM_CURRENT_POSITION
2825 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2826 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2829 // Return subchannel data
2832 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2835 // Specify format of informatin to return
2838 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2841 // Specify which track to access (only used by Track ISRC reads)
2844 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2845 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2849 // Set size of channel data -- however, this is dependent on
2850 // what information we are requesting (which Format)
2853 switch( inputBuffer
->Format
) {
2855 case IOCTL_CDROM_CURRENT_POSITION
:
2856 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2859 case IOCTL_CDROM_MEDIA_CATALOG
:
2860 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2863 case IOCTL_CDROM_TRACK_ISRC
:
2864 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2868 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2869 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2870 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2871 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2872 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2873 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2874 srb
->DataTransferLength
= transferByteCount
;
2875 srb
->CdbLength
= 10;
2876 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2878 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2883 case IOCTL_CDROM_PAUSE_AUDIO
: {
2885 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2886 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2888 srb
->CdbLength
= 10;
2889 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2890 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2891 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2892 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2894 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2898 case IOCTL_CDROM_RESUME_AUDIO
: {
2900 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2901 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2903 srb
->CdbLength
= 10;
2904 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2905 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2906 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2907 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2909 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2913 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2915 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2916 ULONG logicalBlockAddress
;
2918 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2920 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2921 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2922 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2923 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2924 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2926 srb
->CdbLength
= 10;
2927 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2928 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2929 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2930 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2932 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2937 case IOCTL_CDROM_STOP_AUDIO
: {
2939 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2940 cdb
->START_STOP
.Immediate
= 1;
2941 cdb
->START_STOP
.Start
= 0;
2942 cdb
->START_STOP
.LoadEject
= 0;
2945 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2947 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2948 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2949 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2951 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2955 case IOCTL_CDROM_GET_CONTROL
: {
2957 //PAUDIO_OUTPUT audioOutput;
2958 //PCDROM_AUDIO_CONTROL audioControl = Irp->AssociatedIrp.SystemBuffer;
2961 // Allocate buffer for volume control information.
2964 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2969 ExFreePool(senseBuffer
);
2972 Irp
->IoStatus
.Information
= 0;
2973 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2976 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2981 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2987 if (!irp2
->MdlAddress
) {
2988 ExFreePool(senseBuffer
);
2990 ExFreePool(dataBuffer
);
2992 Irp
->IoStatus
.Information
= 0;
2993 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2996 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3004 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
3005 srb
->DataBuffer
= dataBuffer
;
3007 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
3010 // Setup for either 6 or 10 byte CDBs.
3015 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3016 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3017 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
3020 // Disable block descriptors.
3023 cdb
->MODE_SENSE
.Dbd
= TRUE
;
3028 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
3029 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3030 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
3031 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
3034 // Disable block descriptors.
3037 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
3039 srb
->CdbLength
= 10;
3042 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3043 srb
->DataTransferLength
= MODE_DATA_SIZE
;
3044 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3045 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3046 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3048 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3053 case IOCTL_CDROM_GET_VOLUME
:
3054 case IOCTL_CDROM_SET_VOLUME
: {
3056 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3061 ExFreePool(senseBuffer
);
3064 Irp
->IoStatus
.Information
= 0;
3065 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3068 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3072 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3078 if (!irp2
->MdlAddress
) {
3079 ExFreePool(senseBuffer
);
3081 ExFreePool(dataBuffer
);
3083 Irp
->IoStatus
.Information
= 0;
3084 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3087 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3095 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
3096 srb
->DataBuffer
= dataBuffer
;
3098 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
3103 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3104 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3105 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
3111 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
3112 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3113 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
3114 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
3116 srb
->CdbLength
= 10;
3119 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3120 srb
->DataTransferLength
= MODE_DATA_SIZE
;
3121 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3122 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3123 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3125 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
3128 // Setup a different completion routine as the mode sense data is needed in order
3129 // to send the mode select.
3132 IoSetCompletionRoutine(irp2
,
3133 CdRomSetVolumeIntermediateCompletion
,
3141 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3146 case IOCTL_STORAGE_SET_READ_AHEAD
: {
3148 PSTORAGE_SET_READ_AHEAD readAhead
= Irp
->AssociatedIrp
.SystemBuffer
;
3151 PFOUR_BYTE fourByte
= (PFOUR_BYTE
) &blockAddress
;
3154 // setup the SRB for a set readahead command
3157 cdb
->SET_READ_AHEAD
.OperationCode
= SCSIOP_SET_READ_AHEAD
;
3159 blockAddress
= (ULONG
) (readAhead
->TriggerAddress
.QuadPart
>>
3160 fdoExtension
->SectorShift
);
3162 cdb
->SET_READ_AHEAD
.TriggerLBA
[0] = fourByte
->Byte3
;
3163 cdb
->SET_READ_AHEAD
.TriggerLBA
[1] = fourByte
->Byte2
;
3164 cdb
->SET_READ_AHEAD
.TriggerLBA
[2] = fourByte
->Byte1
;
3165 cdb
->SET_READ_AHEAD
.TriggerLBA
[3] = fourByte
->Byte0
;
3167 blockAddress
= (ULONG
) (readAhead
->TargetAddress
.QuadPart
>>
3168 fdoExtension
->SectorShift
);
3170 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[0] = fourByte
->Byte3
;
3171 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[1] = fourByte
->Byte2
;
3172 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[2] = fourByte
->Byte1
;
3173 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[3] = fourByte
->Byte0
;
3175 srb
->CdbLength
= 12;
3176 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3178 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3179 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3180 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
3182 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3186 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
3187 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
:
3188 case IOCTL_DISK_GET_PARTITION_INFO
:
3189 case IOCTL_DISK_GET_PARTITION_INFO_EX
: {
3192 ASSERT(senseBuffer
);
3196 ExFreePool(senseBuffer
);
3200 // NOTE: should probably update the media's capacity first...
3203 CdromFakePartitionInfo(commonExtension
, Irp
);
3207 case IOCTL_DISK_IS_WRITABLE
: {
3209 TraceLog((CdromDebugWarning
,
3210 "CdRomStartIo: DiskIsWritable (%p) - returning %s\n",
3211 Irp
, (cdData
->Mmc
.WriteAllowed
? "TRUE" : "false")));
3214 ASSERT(senseBuffer
);
3218 ExFreePool(senseBuffer
);
3221 Irp
->IoStatus
.Information
= 0;
3222 if (cdData
->Mmc
.WriteAllowed
) {
3223 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3225 Irp
->IoStatus
.Status
= STATUS_MEDIA_WRITE_PROTECTED
;
3227 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3233 UCHAR uniqueAddress
;
3236 // Just complete the request - CdRomClassIoctlCompletion will take
3237 // care of it for us
3239 // NOTE: THIS IS A SYNCHRONIZATION METHOD!!!
3243 // Acquire a new copy of the lock so that ClassCompleteRequest
3244 // doesn't get confused when we complete the other request while
3245 // holding the lock.
3249 // NOTE: CdRomDeviceControlDispatch/CdRomDeviceControlCompletion
3250 // wait for the event and eventually calls
3251 // IoStartNextPacket()
3255 ASSERT(senseBuffer
);
3259 ExFreePool(senseBuffer
);
3264 ClassAcquireRemoveLock(Fdo
, (PIRP
)&uniqueAddress
);
3265 ClassReleaseRemoveLock(Fdo
, Irp
);
3266 ClassCompleteRequest(Fdo
, Irp
, IO_NO_INCREMENT
);
3267 ClassReleaseRemoveLock(Fdo
, (PIRP
)&uniqueAddress
);
3272 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
||
3273 currentIrpStack
->MajorFunction
== IRP_MJ_FLUSH_BUFFERS
) {
3275 currentIrpStack
->Parameters
.Others
.Argument1
= 0;
3276 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3277 CdRomShutdownFlushCompletion(Fdo
, NULL
, Irp
);
3283 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
3284 // are expected and composed of AutoRun Irps, at present.
3287 IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
3293 CdRomReadWriteVerification(
3294 IN PDEVICE_OBJECT DeviceObject
,
3300 Routine Description:
3302 This is the entry called by the I/O system for read requests.
3303 It builds the SRB and sends it to the port driver.
3307 DeviceObject - the system object for the device.
3317 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
3318 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3320 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3321 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
3322 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3324 //PCDROM_DATA cdData = (PCDROM_DATA)(commonExtension->DriverData);
3326 //SCSI_REQUEST_BLOCK srb;
3327 //PCDB cdb = (PCDB)srb.Cdb;
3333 // note: we are no longer failing write commands immediately
3334 // they are now failed in StartIo based upon media ability
3338 // If the cd is playing music then reject this request.
3341 if (PLAY_ACTIVE(fdoExtension
)) {
3342 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
3343 return STATUS_DEVICE_BUSY
;
3347 // Verify parameters of this request.
3348 // Check that ending sector is on disc and
3349 // that number of bytes to transfer is a multiple of
3353 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
3356 if (!fdoExtension
->DiskGeometry
.BytesPerSector
) {
3357 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
3360 if ((startingOffset
.QuadPart
> commonExtension
->PartitionLength
.QuadPart
) ||
3361 (transferByteCount
& (fdoExtension
->DiskGeometry
.BytesPerSector
- 1))) {
3364 // Fail request with status of invalid parameters.
3367 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3369 return STATUS_INVALID_PARAMETER
;
3373 return STATUS_SUCCESS
;
3375 } // end CdRomReadWriteVerification()
3379 CdRomSwitchModeCompletion(
3380 IN PDEVICE_OBJECT DeviceObject
,
3385 PIO_STACK_LOCATION realIrpStack
;
3386 PIO_STACK_LOCATION realIrpNextStack
;
3387 PIRP realIrp
= NULL
;
3390 PSCSI_REQUEST_BLOCK srb
= Context
;
3391 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
3392 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3393 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3394 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3395 //BOOLEAN use6Byte = TEST_FLAG(cdData->XAFlags, XA_USE_6_BYTE);
3399 // Extract the 'real' irp from the irpstack.
3402 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3403 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3404 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3407 // Check SRB status for success of completing request.
3410 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3412 ULONG retryInterval
;
3414 TraceLog((CdromDebugTrace
,
3415 "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
3421 // Release the queue if it is frozen.
3424 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3425 ClassReleaseQueue(DeviceObject
);
3429 retry
= ClassInterpretSenseInfo(DeviceObject
,
3431 irpStack
->MajorFunction
,
3432 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3433 MAXIMUM_RETRIES
- ((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3438 // If the status is verified required and the this request
3439 // should bypass verify required then retry the request.
3442 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3443 status
== STATUS_VERIFY_REQUIRED
) {
3445 status
= STATUS_IO_DEVICE_ERROR
;
3450 // get current retry count
3452 retryCount
= PtrToUlong(realIrpNextStack
->Parameters
.Others
.Argument1
);
3454 if (retry
&& retryCount
) {
3457 // decrement retryCount and update
3459 realIrpNextStack
->Parameters
.Others
.Argument1
= UlongToPtr(retryCount
-1);
3461 if (((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3467 TraceLog((CdromDebugWarning
,
3468 "Retry request %p - Calling StartIo\n", Irp
));
3471 ExFreePool(srb
->SenseInfoBuffer
);
3472 ExFreePool(srb
->DataBuffer
);
3474 if (Irp
->MdlAddress
) {
3475 IoFreeMdl(Irp
->MdlAddress
);
3481 // Call StartIo directly since IoStartNextPacket hasn't been called,
3482 // the serialisation is still intact.
3485 CdRomRetryRequest(fdoExtension
,
3490 return STATUS_MORE_PROCESSING_REQUIRED
;
3495 // Exhausted retries. Fall through and complete the request with the appropriate status.
3501 // Set status for successful request.
3504 status
= STATUS_SUCCESS
;
3508 if (NT_SUCCESS(status
)) {
3510 ULONG sectorSize
, startingSector
, transferByteCount
;
3514 // Update device ext. to show which mode we are currently using.
3517 sectorSize
= cdData
->BlockDescriptor
.BlockLength
[0] << 16;
3518 sectorSize
|= (cdData
->BlockDescriptor
.BlockLength
[1] << 8);
3519 sectorSize
|= (cdData
->BlockDescriptor
.BlockLength
[2]);
3521 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
3524 // Free the old data buffer, mdl.
3525 // reuse the SenseInfoBuffer and Srb
3528 ExFreePool(srb
->DataBuffer
);
3529 IoFreeMdl(Irp
->MdlAddress
);
3536 cdb
= (PCDB
)srb
->Cdb
;
3537 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3540 if (cdData
->RawAccess
) {
3542 PRAW_READ_INFO rawReadInfo
=
3543 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
3545 ULONG maximumTransferLength
;
3546 ULONG transferPages
;
3547 //UCHAR min, sec, frame;
3550 // Calculate starting offset.
3553 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
3554 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
3555 maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
3556 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3560 // Determine if request is within limits imposed by miniport.
3561 // If the request is larger than the miniport's capabilities, split it.
3564 if (transferByteCount
> maximumTransferLength
||
3565 transferPages
> fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
) {
3568 ExFreePool(srb
->SenseInfoBuffer
);
3570 realIrp
->IoStatus
.Information
= 0;
3571 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3574 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
3575 return STATUS_MORE_PROCESSING_REQUIRED
;
3578 srb
->OriginalRequest
= realIrp
;
3579 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3580 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3581 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3583 srb
->DataTransferLength
= transferByteCount
;
3584 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3585 srb
->CdbLength
= 10;
3586 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
3588 if (rawReadInfo
->TrackMode
== CDDA
) {
3589 if (TEST_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
)) {
3591 srb
->CdbLength
= 12;
3593 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3594 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3595 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3596 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3598 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3599 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3600 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
3601 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
3603 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
3604 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
3606 } else if (TEST_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
)) {
3608 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3609 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3610 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3611 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3613 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3614 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3616 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
3619 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3620 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3622 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3623 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3624 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3625 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3627 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3630 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3633 irpStack
= IoGetNextIrpStackLocation(realIrp
);
3634 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3635 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3637 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
3640 // Only jam this in if it doesn't exist. The completion routines can
3641 // call StartIo directly in the case of retries and resetting it will
3642 // cause infinite loops.
3645 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
3649 // Set up IoCompletion routine address.
3652 IoSetCompletionRoutine(realIrp
,
3660 PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor
;
3661 ULONG maximumTransferLength
;
3662 ULONG transferPages
;
3665 // a writable device must be MMC compliant, which supports
3666 // READ_CD commands, so writes and mode switching should
3667 // never occur on the same device.
3670 ASSERT(realIrpStack
->MajorFunction
!= IRP_MJ_WRITE
);
3673 // free the SRB and SenseInfoBuffer since they aren't used
3674 // by either ClassBuildRequest() nor ClassSplitRequest().
3677 ExFreePool(srb
->SenseInfoBuffer
);
3681 // Back to cooked sectors. Build and send a normal read.
3682 // The real work for setting offsets was done in startio.
3686 commonExtension
->PartitionZeroExtension
->AdapterDescriptor
;
3687 maximumTransferLength
= adapterDescriptor
->MaximumTransferLength
;
3688 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3689 MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3690 realIrpStack
->Parameters
.Read
.Length
);
3692 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
3693 (transferPages
> adapterDescriptor
->MaximumPhysicalPages
)) {
3695 ULONG maxPages
= adapterDescriptor
->MaximumPhysicalPages
;
3697 if (maxPages
!= 0) {
3698 maxPages
--; // to account for page boundaries
3701 TraceLog((CdromDebugTrace
,
3702 "CdromSwitchModeCompletion: Request greater than "
3704 TraceLog((CdromDebugTrace
,
3705 "CdromSwitchModeCompletion: Maximum is %lx\n",
3706 maximumTransferLength
));
3707 TraceLog((CdromDebugTrace
,
3708 "CdromSwitchModeCompletion: Byte count is %lx\n",
3709 realIrpStack
->Parameters
.Read
.Length
));
3712 // Check that the maximum transfer length fits within
3713 // the maximum number of pages the device can handle.
3716 if (maximumTransferLength
> maxPages
<< PAGE_SHIFT
) {
3717 maximumTransferLength
= maxPages
<< PAGE_SHIFT
;
3721 // Check that maximum transfer size is not zero
3724 if (maximumTransferLength
== 0) {
3725 maximumTransferLength
= PAGE_SIZE
;
3729 // Request needs to be split. Completion of each portion
3730 // of the request will fire off the next portion. The final
3731 // request will signal Io to send a new request.
3734 ClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
3735 return STATUS_MORE_PROCESSING_REQUIRED
;
3740 // Build SRB and CDB for this IRP.
3743 ClassBuildRequest(DeviceObject
, realIrp
);
3749 // Call the port driver.
3752 IoCallDriver(commonExtension
->LowerDeviceObject
, realIrp
);
3754 return STATUS_MORE_PROCESSING_REQUIRED
;
3758 // Update device Extension flags to indicate that XA isn't supported.
3761 TraceLog((CdromDebugWarning
,
3762 "Device Cannot Support CDDA (but tested positive) "
3763 "Now Clearing CDDA flags for FDO %p\n", DeviceObject
));
3764 SET_FLAG(cdData
->XAFlags
, XA_NOT_SUPPORTED
);
3765 CLEAR_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
);
3766 CLEAR_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
);
3769 // Deallocate srb and sense buffer.
3773 if (srb
->DataBuffer
) {
3774 ExFreePool(srb
->DataBuffer
);
3776 if (srb
->SenseInfoBuffer
) {
3777 ExFreePool(srb
->SenseInfoBuffer
);
3782 if (Irp
->PendingReturned
) {
3783 IoMarkIrpPending(Irp
);
3786 if (realIrp
->PendingReturned
) {
3787 IoMarkIrpPending(realIrp
);
3790 if (Irp
->MdlAddress
) {
3791 IoFreeMdl(Irp
->MdlAddress
);
3797 // Set status in completing IRP.
3800 realIrp
->IoStatus
.Status
= status
;
3803 // Set the hard error if necessary.
3806 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3809 // Store DeviceObject for filesystem, and clear
3810 // in IoStatus.Information field.
3813 if (realIrp
->Tail
.Overlay
.Thread
) {
3814 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3816 realIrp
->IoStatus
.Information
= 0;
3819 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
3821 return STATUS_MORE_PROCESSING_REQUIRED
;
3826 ScanForSpecialHandler(
3827 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
3831 PCOMMON_DEVICE_EXTENSION commonExtension
;
3836 CLEAR_FLAG(HackFlags
, CDROM_HACK_INVALID_FLAGS
);
3838 commonExtension
= &(FdoExtension
->CommonExtension
);
3839 cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3840 cdData
->HackFlags
= HackFlags
;
3848 PDEVICE_OBJECT DeviceObject
3853 Routine Description:
3855 This function checks to see if an SCSI logical unit requires an special
3856 initialization or error processing.
3860 DeviceObject - Supplies the device object to be tested.
3862 InquiryData - Supplies the inquiry data returned by the device of interest.
3864 PortCapabilities - Supplies the capabilities of the device object.
3873 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
3874 PCOMMON_DEVICE_EXTENSION commonExtension
;
3879 fdoExtension
= DeviceObject
->DeviceExtension
;
3880 commonExtension
= DeviceObject
->DeviceExtension
;
3881 cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3885 // set our hack flags
3888 ClassScanForSpecial(fdoExtension
, CdromHackItems
, ScanForSpecialHandler
);
3891 // All CDRom's can ignore the queue lock failure for power operations
3892 // and do not require handling the SpinUp case (unknown result of sending
3893 // a cdrom a START_UNIT command -- may eject disks?)
3895 // We send the stop command mostly to stop outstanding asynch operations
3896 // (like audio playback) from running when the system is powered off.
3897 // Because of this and the unlikely chance that a PLAY command will be
3898 // sent in the window between the STOP and the time the machine powers down
3899 // we don't require queue locks. This is important because without them
3900 // classpnp's power routines will send the START_STOP_UNIT command to the
3901 // device whether or not it supports locking (atapi does not support locking
3902 // and if we requested them we would end up not stopping audio on atapi
3906 SET_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_SPIN_UP
);
3907 SET_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_NO_QUEUE_LOCK
);
3909 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_1750
)
3910 && ( fdoExtension
->AdapterDescriptor
->AdapterUsesPio
)
3914 // Read-ahead must be disabled in order to get this cdrom drive
3915 // to work on scsi adapters that use PIO.
3919 TraceLog((CdromDebugWarning
,
3920 "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
3923 // Setup an error handler to reinitialize the cd rom after it is reset.
3926 cdData
->ErrorHandler
= HitachiProcessError
;
3929 // Lock down the hitachi error processing code.
3932 MmLockPagableCodeSection(HitachiProcessError
);
3933 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
3936 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_SD_W1101
)) {
3938 TraceLog((CdromDebugError
,
3939 "CdRom ScanForSpecial: Found Toshiba SD-W1101 DVD-RAM "
3940 "-- This drive will *NOT* support DVD-ROM playback.\n"));
3942 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_GD_2000
)) {
3944 TraceLog((CdromDebugWarning
,
3945 "CdRom ScanForSpecial: Found Hitachi GD-2000\n"));
3948 // Setup an error handler to spin up the drive when it idles out
3949 // since it seems to like to fail to spin itself back up on its
3950 // own for a REPORT_KEY command. It may also lose the AGIDs that
3951 // it has given, which will result in DVD playback failures.
3952 // This routine will just do what it can...
3955 cdData
->ErrorHandler
= HitachiProcessErrorGD2000
;
3958 // this drive may require START_UNIT commands to spin
3959 // the drive up when it's spun itself down.
3962 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
3965 // Lock down the hitachi error processing code.
3968 MmLockPagableCodeSection(HitachiProcessErrorGD2000
);
3969 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
3971 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_FUJITSU_FMCD_10x
)) {
3974 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
3975 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
3979 fdoExtension
->TimeOutValue
= 20;
3981 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_DEC_RRD
)) {
3983 PMODE_PARM_READ_WRITE_DATA modeParameters
;
3984 SCSI_REQUEST_BLOCK srb
;
3989 TraceLog((CdromDebugWarning
,
3990 "CdRom ScanForSpecial: Found DEC RRD.\n"));
3992 cdData
->IsDecRrd
= TRUE
;
3995 // Setup an error handler to reinitialize the cd rom after it is reset?
3997 //commonExtension->DevInfo->ClassError = DecRrdProcessError;
4000 // Found a DEC RRD cd-rom. These devices do not pass MS HCT
4001 // multi-media tests because the DEC firmware modifieds the block
4002 // from the PC-standard 2K to 512. Change the block transfer size
4003 // back to the PC-standard 2K by using a mode select command.
4006 modeParameters
= ExAllocatePoolWithTag(NonPagedPool
,
4007 sizeof(MODE_PARM_READ_WRITE_DATA
),
4010 if (modeParameters
== NULL
) {
4014 RtlZeroMemory(modeParameters
, sizeof(MODE_PARM_READ_WRITE_DATA
));
4015 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4018 // Set the block length to 2K.
4021 modeParameters
->ParameterListHeader
.BlockDescriptorLength
=
4022 sizeof(MODE_PARAMETER_BLOCK
);
4025 // Set block length to 2K (0x0800) in Parameter Block.
4028 modeParameters
->ParameterListBlock
.BlockLength
[0] = 0x00; //MSB
4029 modeParameters
->ParameterListBlock
.BlockLength
[1] = 0x08;
4030 modeParameters
->ParameterListBlock
.BlockLength
[2] = 0x00; //LSB
4033 // Build the mode select CDB.
4037 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4039 cdb
= (PCDB
)srb
.Cdb
;
4040 cdb
->MODE_SELECT
.PFBit
= 1;
4041 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4042 cdb
->MODE_SELECT
.ParameterListLength
= HITACHI_MODE_DATA_SIZE
;
4045 // Send the request to the device.
4048 status
= ClassSendSrbSynchronous(DeviceObject
,
4051 sizeof(MODE_PARM_READ_WRITE_DATA
),
4054 if (!NT_SUCCESS(status
)) {
4055 TraceLog((CdromDebugWarning
,
4056 "CdRom ScanForSpecial: Setting DEC RRD to 2K block"
4057 "size failed [%x]\n", status
));
4059 ExFreePool(modeParameters
);
4061 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_XM_3xx
)) {
4063 SCSI_REQUEST_BLOCK srb
;
4070 // Set the density code and the error handler.
4073 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
4075 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4078 // Build the MODE SENSE CDB.
4082 cdb
= (PCDB
)srb
.Cdb
;
4085 // Set timeout value from device extension.
4088 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4090 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
4091 cdb
->MODE_SENSE
.PageCode
= 0x1;
4092 // NOTE: purposely not setting DBD because it is what is needed.
4093 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
4095 buffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4096 (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
),
4097 CDROM_TAG_MODE_DATA
);
4102 status
= ClassSendSrbSynchronous(DeviceObject
,
4108 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
4109 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
4111 RtlCopyMemory(&cdData
->Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
4113 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4116 // Build the MODE SENSE CDB.
4120 cdb
= (PCDB
)srb
.Cdb
;
4123 // Set timeout value from device extension.
4126 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4128 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4129 cdb
->MODE_SELECT
.PFBit
= 1;
4130 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4132 status
= ClassSendSrbSynchronous(DeviceObject
,
4138 if (!NT_SUCCESS(status
)) {
4139 TraceLog((CdromDebugWarning
,
4140 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4144 cdData
->ErrorHandler
= ToshibaProcessError
;
4147 // Lock down the toshiba error section.
4150 MmLockPagableCodeSection(ToshibaProcessError
);
4151 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
4158 // Determine special CD-DA requirements.
4161 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_READ_CD_SUPPORTED
)) {
4163 SET_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
);
4165 } else if (!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
)) {
4167 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_PLEXTOR_CDDA
)) {
4168 SET_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
);
4169 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_NEC_CDDA
)) {
4170 SET_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
);
4175 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
)) {
4176 KdPrintEx((DPFLTR_SYSTEM_ID
, DPFLTR_ERROR_LEVEL
,
4177 "Locking pages for error handler\n"));
4186 HitachiProcessErrorGD2000(
4188 PSCSI_REQUEST_BLOCK OriginalSrb
,
4194 Routine Description:
4196 This routine checks the type of error. If the error suggests that the
4197 drive has spun down and cannot reinitialize itself, send a
4198 START_UNIT or READ to the device. This will force the drive to spin
4199 up. This drive also loses the AGIDs it has granted when it spins down,
4200 which may result in playback failure the first time around.
4204 DeviceObject - Supplies a pointer to the device object.
4206 Srb - Supplies a pointer to the failing Srb.
4208 Status - return the final status for this command?
4210 Retry - return if the command should be retried.
4218 PSENSE_DATA senseBuffer
= OriginalSrb
->SenseInfoBuffer
;
4220 UNREFERENCED_PARAMETER(Status
);
4221 UNREFERENCED_PARAMETER(Retry
);
4223 if (!TEST_FLAG(OriginalSrb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
4227 if (((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_HARDWARE_ERROR
) &&
4228 (senseBuffer
->AdditionalSenseCode
== 0x44)) {
4230 //PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
4232 //PIO_STACK_LOCATION irpStack;
4233 //PCOMPLETION_CONTEXT context;
4234 //PSCSI_REQUEST_BLOCK newSrb;
4237 TraceLog((CdromDebugWarning
,
4238 "HitachiProcessErrorGD2000 (%p) => Internal Target "
4239 "Failure Detected -- spinning up drive\n", Fdo
));
4242 // the request should be retried because the device isn't ready
4246 *Status
= STATUS_DEVICE_NOT_READY
;
4249 // send a START_STOP unit to spin up the drive
4250 // NOTE: this temporarily violates the StartIo serialization
4251 // mechanism, but the completion routine on this will NOT
4252 // call StartNextPacket(), so it's a temporary disruption
4253 // of the serialization only.
4256 ClassSendStartUnit(Fdo
);
4265 HitachiProcessError(
4266 PDEVICE_OBJECT DeviceObject
,
4267 PSCSI_REQUEST_BLOCK Srb
,
4273 Routine Description:
4275 This routine checks the type of error. If the error indicates CD-ROM the
4276 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
4277 device. This command disables read-ahead for the device.
4281 DeviceObject - Supplies a pointer to the device object.
4283 Srb - Supplies a pointer to the failing Srb.
4296 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4297 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
4298 LARGE_INTEGER largeInt
;
4300 PIO_STACK_LOCATION irpStack
;
4302 PSCSI_REQUEST_BLOCK srb
;
4303 PCOMPLETION_CONTEXT context
;
4305 ULONG_PTR alignment
;
4307 UNREFERENCED_PARAMETER(Status
);
4308 UNREFERENCED_PARAMETER(Retry
);
4310 largeInt
.QuadPart
= (LONGLONG
) 1;
4313 // Check the status. The initialization command only needs to be sent
4314 // if UNIT ATTENTION is returned.
4317 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
4320 // The drive does not require reinitialization.
4327 // Found an HITACHI cd-rom that does not work with PIO
4328 // adapters when read-ahead is enabled. Read-ahead is disabled by
4329 // a mode select command. The mode select page code is zero and the
4330 // length is 6 bytes. All of the other bytes should be zero.
4333 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
4335 TraceLog((CdromDebugWarning
,
4336 "HitachiProcessError: Reinitializing the CD-ROM.\n"));
4339 // Send the special mode select command to disable read-ahead
4340 // on the CD-ROM reader.
4343 alignment
= DeviceObject
->AlignmentRequirement
?
4344 DeviceObject
->AlignmentRequirement
: 1;
4346 context
= ExAllocatePoolWithTag(
4348 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ (ULONG
)alignment
,
4349 CDROM_TAG_HITACHI_ERROR
4352 if (context
== NULL
) {
4355 // If there is not enough memory to fulfill this request,
4356 // simply return. A subsequent retry will fail and another
4357 // chance to start the unit.
4363 context
->DeviceObject
= DeviceObject
;
4364 srb
= &context
->Srb
;
4366 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4369 // Write length to SRB.
4372 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4375 // Set up SCSI bus address.
4378 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4379 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
4382 // Set the transfer length.
4385 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
4386 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
4387 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
4388 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_AUTOSENSE
);
4389 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
4392 // The data buffer must be aligned.
4395 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
4400 // Build the HITACHI read-ahead mode select CDB.
4404 cdb
= (PCDB
)srb
->Cdb
;
4405 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
4406 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
4407 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
4410 // Initialize the mode sense data.
4413 modePage
= srb
->DataBuffer
;
4415 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
4418 // Set the page length field to 6.
4424 // Build the asynchronous request to be sent to the port driver.
4427 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
4430 srb
->DataTransferLength
,
4437 // If there is not enough memory to fulfill this request,
4438 // simply return. A subsequent retry will fail and another
4439 // chance to start the unit.
4442 ExFreePool(context
);
4446 ClassAcquireRemoveLock(DeviceObject
, irp
);
4448 IoSetCompletionRoutine(irp
,
4449 (PIO_COMPLETION_ROUTINE
)ClassAsynchronousCompletion
,
4455 irpStack
= IoGetNextIrpStackLocation(irp
);
4457 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4459 srb
->OriginalRequest
= irp
;
4462 // Save SRB address in next stack for port driver.
4465 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
4468 // Set up IRP Address.
4471 (VOID
)IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp
);
4478 ToshibaProcessErrorCompletion(
4479 PDEVICE_OBJECT DeviceObject
,
4486 Routine Description:
4488 Completion routine for the ClassError routine to handle older Toshiba units
4489 that require setting the density code.
4493 DeviceObject - Supplies a pointer to the device object.
4495 Irp - Pointer to irp created to set the density code.
4497 Context - Supplies a pointer to the Mode Select Srb.
4502 STATUS_MORE_PROCESSING_REQUIRED
4508 PSCSI_REQUEST_BLOCK srb
= Context
;
4511 // Free all of the allocations.
4514 ClassReleaseRemoveLock(DeviceObject
, Irp
);
4516 ExFreePool(srb
->DataBuffer
);
4518 IoFreeMdl(Irp
->MdlAddress
);
4522 // Indicate the I/O system should stop processing the Irp completion.
4525 return STATUS_MORE_PROCESSING_REQUIRED
;
4530 ToshibaProcessError(
4531 PDEVICE_OBJECT DeviceObject
,
4532 PSCSI_REQUEST_BLOCK Srb
,
4539 Routine Description:
4541 This routine checks the type of error. If the error indicates a unit attention,
4542 the density code needs to be set via a Mode select command.
4546 DeviceObject - Supplies a pointer to the device object.
4548 Srb - Supplies a pointer to the failing Srb.
4561 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4562 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
4564 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
4565 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
4566 PIO_STACK_LOCATION irpStack
;
4568 PSCSI_REQUEST_BLOCK srb
;
4574 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
4579 // The Toshiba's require the density code to be set on power up and media changes.
4582 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
4585 irp
= IoAllocateIrp((CCHAR
)(DeviceObject
->StackSize
+1),
4592 srb
= ExAllocatePoolWithTag(NonPagedPool
,
4593 sizeof(SCSI_REQUEST_BLOCK
),
4594 CDROM_TAG_TOSHIBA_ERROR
);
4601 length
= sizeof(ERROR_RECOVERY_DATA
);
4602 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4604 CDROM_TAG_TOSHIBA_ERROR
);
4611 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
4617 if (!irp
->MdlAddress
) {
4619 ExFreePool(dataBuffer
);
4628 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
4630 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
4632 srb
->DataBuffer
= dataBuffer
;
4633 cdb
= (PCDB
)srb
->Cdb
;
4639 IoSetNextIrpStackLocation(irp
);
4640 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4641 irp
->IoStatus
.Information
= 0;
4643 irp
->UserBuffer
= NULL
;
4646 // Save the device object and irp in a private stack location.
4649 irpStack
= IoGetCurrentIrpStackLocation(irp
);
4650 irpStack
->DeviceObject
= DeviceObject
;
4653 // Construct the IRP stack for the lower level driver.
4656 irpStack
= IoGetNextIrpStackLocation(irp
);
4657 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
4658 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
4659 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4661 IoSetCompletionRoutine(irp
,
4662 ToshibaProcessErrorCompletion
,
4668 ClassAcquireRemoveLock(DeviceObject
, irp
);
4670 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4671 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4672 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
4674 srb
->OriginalRequest
= irp
;
4675 srb
->SenseInfoBufferLength
= 0;
4678 // Set the transfer length.
4681 srb
->DataTransferLength
= length
;
4682 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
4683 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
4684 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_AUTOSENSE
);
4685 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
4686 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
4690 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4691 cdb
->MODE_SELECT
.PFBit
= 1;
4692 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4695 // Copy the Mode page into the databuffer.
4698 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, length
);
4701 // Set the density code.
4704 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
4706 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp
);
4713 IN PDEVICE_OBJECT DeviceObject
4718 Routine Description:
4720 This routine determines if the cd is currently playing music.
4724 DeviceObject - Device object to test.
4728 TRUE if the device is playing music.
4732 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4733 IO_STATUS_BLOCK ioStatus
;
4734 PSUB_Q_CURRENT_POSITION currentBuffer
;
4739 // if we don't think it is playing audio, don't bother checking.
4742 if (!PLAY_ACTIVE(fdoExtension
)) {
4746 currentBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4747 sizeof(SUB_Q_CURRENT_POSITION
),
4748 CDROM_TAG_PLAY_ACTIVE
);
4750 if (currentBuffer
== NULL
) {
4754 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
4755 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
4758 // Build the synchronous request to be sent to ourself
4759 // to perform the request.
4762 ClassSendDeviceIoControlSynchronous(
4763 IOCTL_CDROM_READ_Q_CHANNEL
,
4766 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
4767 sizeof(SUB_Q_CURRENT_POSITION
),
4771 if (!NT_SUCCESS(ioStatus
.Status
)) {
4772 ExFreePool(currentBuffer
);
4777 // should update the playactive flag here.
4780 if (currentBuffer
->Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
4781 PLAY_ACTIVE(fdoExtension
) = TRUE
;
4783 PLAY_ACTIVE(fdoExtension
) = FALSE
;
4786 ExFreePool(currentBuffer
);
4788 return(PLAY_ACTIVE(fdoExtension
));
4795 IN PDEVICE_OBJECT DeviceObject
4800 Routine Description:
4802 This routine handles the once per second timer provided by the
4803 Io subsystem. It is used to do delayed retries for cdroms.
4807 DeviceObject - what to check.
4816 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4817 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
4826 //PLIST_ENTRY listEntry;
4828 //PIO_STACK_LOCATION irpStack;
4829 UCHAR uniqueAddress
;
4831 isRemoved
= ClassAcquireRemoveLock(DeviceObject
, (PIRP
) &uniqueAddress
);
4834 // We stop the timer before deleting the device. It's safe to keep going
4835 // if the flag value is REMOVE_PENDING because the removal thread will be
4836 // blocked trying to stop the timer.
4839 ASSERT(isRemoved
!= REMOVE_COMPLETE
);
4842 // This routine is reasonably safe even if the device object has a pending
4845 cddata
= commonExtension
->DriverData
;
4848 // Since cdrom is completely synchronized there can never be more than one
4849 // irp delayed for retry at any time.
4852 KeAcquireSpinLock(&(cddata
->DelayedRetrySpinLock
), &oldIrql
);
4854 if(cddata
->DelayedRetryIrp
!= NULL
) {
4856 PIRP irp
= cddata
->DelayedRetryIrp
;
4859 // If we've got a delayed retry at this point then there had beter
4860 // be an interval for it.
4863 ASSERT(cddata
->DelayedRetryInterval
!= 0);
4864 cddata
->DelayedRetryInterval
--;
4869 // This device is removed - flush the timer queue
4872 cddata
->DelayedRetryIrp
= NULL
;
4873 cddata
->DelayedRetryInterval
= 0;
4875 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4877 ClassReleaseRemoveLock(DeviceObject
, irp
);
4878 ClassCompleteRequest(DeviceObject
, irp
, IO_CD_ROM_INCREMENT
);
4880 } else if (cddata
->DelayedRetryInterval
== 0) {
4883 // Submit this IRP to the lower driver. This IRP does not
4884 // need to be remembered here. It will be handled again when
4888 cddata
->DelayedRetryIrp
= NULL
;
4890 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4892 TraceLog((CdromDebugWarning
,
4893 "CdRomTickHandler: Reissuing request %p (thread = %p)\n",
4895 irp
->Tail
.Overlay
.Thread
));
4898 // feed this to the appropriate port driver
4901 CdRomRerunRequest(fdoExtension
, irp
, cddata
->DelayedRetryResend
);
4903 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4906 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4909 ClassReleaseRemoveLock(DeviceObject
, (PIRP
) &uniqueAddress
);
4914 CdRomUpdateGeometryCompletion(
4915 PDEVICE_OBJECT DeviceObject
,
4922 Routine Description:
4924 This routine andles the completion of the test unit ready irps
4925 used to determine if the media has changed. If the media has
4926 changed, this code signals the named event to wake up other
4927 system services that react to media change (aka AutoPlay).
4931 DeviceObject - the object for the completion
4932 Irp - the IRP being completed
4933 Context - the SRB from the IRP
4942 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
4943 PCOMMON_DEVICE_EXTENSION commonExtension
;
4945 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
4946 PREAD_CAPACITY_DATA readCapacityBuffer
;
4947 PIO_STACK_LOCATION irpStack
;
4953 //PCDROM_DATA cddata;
4954 //UCHAR uniqueAddress;
4957 // Get items saved in the private IRP stack location.
4960 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4961 retryCount
= (ULONG
)(ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
4962 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
4964 if (!DeviceObject
) {
4965 DeviceObject
= irpStack
->DeviceObject
;
4967 ASSERT(DeviceObject
);
4969 fdoExtension
= DeviceObject
->DeviceExtension
;
4970 commonExtension
= DeviceObject
->DeviceExtension
;
4971 //cddata = commonExtension->DriverData;
4972 readCapacityBuffer
= srb
->DataBuffer
;
4974 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
4976 CdRomInterpretReadCapacity(DeviceObject
, readCapacityBuffer
);
4980 ULONG retryInterval
;
4982 TraceLog((CdromDebugWarning
,
4983 "CdRomUpdateGeometryCompletion: [%p] unsuccessful "
4984 "completion of buddy-irp %p (status - %lx)\n",
4985 originalIrp
, Irp
, Irp
->IoStatus
.Status
));
4987 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4988 ClassReleaseQueue(DeviceObject
);
4991 retry
= ClassInterpretSenseInfo(DeviceObject
,
5000 if ((retryCount
) && (commonExtension
->IsRemoved
== NO_REMOVE
)) {
5003 TraceLog((CdromDebugWarning
,
5004 "CdRomUpdateGeometryCompletion: [%p] Retrying "
5005 "request %p .. thread is %p\n",
5006 originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
5009 // set up a one shot timer to get this process started over
5012 irpStack
->Parameters
.Others
.Argument1
= ULongToPtr( retryCount
);
5013 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
5014 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
5017 // Setup the IRP to be submitted again in the timer routine.
5020 irpStack
= IoGetNextIrpStackLocation(Irp
);
5021 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5022 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
5023 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5024 IoSetCompletionRoutine(Irp
,
5025 CdRomUpdateGeometryCompletion
,
5032 // Set up the SRB for read capacity.
5035 srb
->CdbLength
= 10;
5036 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
5037 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5039 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5040 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5041 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
5042 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
5043 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
5044 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
5050 cdb
= (PCDB
) &srb
->Cdb
[0];
5051 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
5054 // Requests queued onto this list will be sent to the
5055 // lower level driver during CdRomTickHandler
5058 CdRomRetryRequest(fdoExtension
, Irp
, retryInterval
, TRUE
);
5060 return STATUS_MORE_PROCESSING_REQUIRED
;
5063 if (commonExtension
->IsRemoved
!= NO_REMOVE
) {
5066 // We cannot retry the request. Fail it.
5069 originalIrp
->IoStatus
.Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
5074 // This has been bounced for a number of times. Error the
5075 // original request.
5078 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
5079 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5080 sizeof(DISK_GEOMETRY
));
5081 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5082 fdoExtension
->SectorShift
= 11;
5083 commonExtension
->PartitionLength
.QuadPart
=
5084 (LONGLONG
)(0x7fffffff);
5085 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5090 // Set up reasonable defaults
5093 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5094 sizeof(DISK_GEOMETRY
));
5095 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5096 fdoExtension
->SectorShift
= 11;
5097 commonExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
5098 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5103 // Free resources held.
5106 ExFreePool(srb
->SenseInfoBuffer
);
5107 ExFreePool(srb
->DataBuffer
);
5109 if (Irp
->MdlAddress
) {
5110 IoFreeMdl(Irp
->MdlAddress
);
5115 if (originalIrp
->Tail
.Overlay
.Thread
) {
5117 TraceLog((CdromDebugTrace
,
5118 "CdRomUpdateGeometryCompletion: [%p] completing "
5119 "original IRP\n", originalIrp
));
5123 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
5124 "CdRomUpdateGeometryCompletion: completing irp %p which has "
5125 "no thread\n", originalIrp
));
5130 // NOTE: should the original irp be sent down to the device object?
5131 // it probably should if the SL_OVERRIDER_VERIFY_VOLUME flag
5134 PIO_STACK_LOCATION realIrpStack
;
5136 realIrpStack
= IoGetCurrentIrpStackLocation(originalIrp
);
5137 oldIrql
= KeRaiseIrqlToDpcLevel();
5139 if (TEST_FLAG(realIrpStack
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
)) {
5140 CdRomStartIo(DeviceObject
, originalIrp
);
5142 originalIrp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
5143 originalIrp
->IoStatus
.Information
= 0;
5144 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, originalIrp
);
5146 KeLowerIrql(oldIrql
);
5149 return STATUS_MORE_PROCESSING_REQUIRED
;
5154 CdRomUpdateCapacity(
5155 IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension
,
5156 IN PIRP IrpToComplete
,
5157 IN OPTIONAL PKEVENT IoctlEvent
5162 Routine Description:
5164 This routine updates the capacity of the disk as recorded in the device extension.
5165 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
5166 when a media change has occurred and it is necessary to determine the capacity of the
5167 new media prior to the next access.
5171 DeviceExtension - the device to update
5172 IrpToComplete - the request that needs to be completed when done.
5181 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
) DeviceExtension
;
5182 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
) DeviceExtension
;
5186 PSCSI_REQUEST_BLOCK srb
;
5187 PREAD_CAPACITY_DATA capacityBuffer
;
5188 PIO_STACK_LOCATION irpStack
;
5192 irp
= IoAllocateIrp((CCHAR
)(commonExtension
->DeviceObject
->StackSize
+1),
5197 srb
= ExAllocatePoolWithTag(NonPagedPool
,
5198 sizeof(SCSI_REQUEST_BLOCK
),
5199 CDROM_TAG_UPDATE_CAP
);
5201 capacityBuffer
= ExAllocatePoolWithTag(
5202 NonPagedPoolCacheAligned
,
5203 sizeof(READ_CAPACITY_DATA
),
5204 CDROM_TAG_UPDATE_CAP
);
5206 if (capacityBuffer
) {
5209 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
5211 CDROM_TAG_UPDATE_CAP
);
5215 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
5216 sizeof(READ_CAPACITY_DATA
),
5221 if (irp
->MdlAddress
) {
5224 // Have all resources. Set up the IRP to send for the capacity.
5227 IoSetNextIrpStackLocation(irp
);
5228 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5229 irp
->IoStatus
.Information
= 0;
5231 irp
->UserBuffer
= NULL
;
5234 // Save the device object and retry count in a private stack location.
5237 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5238 irpStack
->DeviceObject
= commonExtension
->DeviceObject
;
5239 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
5240 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
5243 // Construct the IRP stack for the lower level driver.
5246 irpStack
= IoGetNextIrpStackLocation(irp
);
5247 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5248 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
5249 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5250 IoSetCompletionRoutine(irp
,
5251 CdRomUpdateGeometryCompletion
,
5260 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5264 // Set up the SRB for read capacity.
5267 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5268 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
5269 srb
->CdbLength
= 10;
5270 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
5271 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5273 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5274 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5275 srb
->SrbFlags
= DeviceExtension
->SrbFlags
;
5276 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
5277 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
5278 srb
->DataBuffer
= capacityBuffer
;
5279 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
5280 srb
->OriginalRequest
= irp
;
5281 srb
->SenseInfoBuffer
= senseBuffer
;
5282 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
5288 cdb
= (PCDB
) &srb
->Cdb
[0];
5289 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
5292 // Set the return value in the IRP that will be completed
5293 // upon completion of the read capacity.
5296 IrpToComplete
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
5297 IoMarkIrpPending(IrpToComplete
);
5299 IoCallDriver(commonExtension
->LowerDeviceObject
, irp
);
5302 // status is not checked because the completion routine for this
5303 // IRP will always get called and it will free the resources.
5306 return STATUS_PENDING
;
5309 ExFreePool(senseBuffer
);
5310 ExFreePool(capacityBuffer
);
5315 ExFreePool(capacityBuffer
);
5329 // complete the original irp with a failure.
5330 // ISSUE-2000/07/05-henrygab - find a way to avoid failure.
5333 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5334 sizeof(DISK_GEOMETRY
));
5335 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5336 fdoExtension
->SectorShift
= 11;
5337 commonExtension
->PartitionLength
.QuadPart
=
5338 (LONGLONG
)(0x7fffffff);
5339 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5341 IrpToComplete
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
5342 IrpToComplete
->IoStatus
.Information
= 0;
5344 BAIL_OUT(IrpToComplete
);
5345 CdRomCompleteIrpAndStartNextPacketSafely(commonExtension
->DeviceObject
,
5347 return STATUS_INSUFFICIENT_RESOURCES
;
5353 IN PDEVICE_OBJECT DeviceObject
,
5359 Routine Description:
5361 This routine is responsible for releasing any resources in use by the
5362 cdrom driver and shutting down it's timer routine. This routine is called
5363 when all outstanding requests have been completed and the device has
5364 disappeared - no requests may be issued to the lower drivers.
5368 DeviceObject - the device object being removed
5372 none - this routine may not fail
5377 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension
=
5378 DeviceObject
->DeviceExtension
;
5380 PCDROM_DATA cdData
= deviceExtension
->CommonExtension
.DriverData
;
5384 if((Type
== IRP_MN_QUERY_REMOVE_DEVICE
) ||
5385 (Type
== IRP_MN_CANCEL_REMOVE_DEVICE
)) {
5386 return STATUS_SUCCESS
;
5389 if(cdData
->DelayedRetryIrp
!= NULL
) {
5390 cdData
->DelayedRetryInterval
= 1;
5391 CdRomTickHandler(DeviceObject
);
5394 CdRomDeAllocateMmcResources(DeviceObject
);
5396 if (deviceExtension
->DeviceDescriptor
) {
5397 ExFreePool(deviceExtension
->DeviceDescriptor
);
5398 deviceExtension
->DeviceDescriptor
= NULL
;
5401 if (deviceExtension
->AdapterDescriptor
) {
5402 ExFreePool(deviceExtension
->AdapterDescriptor
);
5403 deviceExtension
->AdapterDescriptor
= NULL
;
5406 if (deviceExtension
->SenseData
) {
5407 ExFreePool(deviceExtension
->SenseData
);
5408 deviceExtension
->SenseData
= NULL
;
5411 ClassDeleteSrbLookasideList(&deviceExtension
->CommonExtension
);
5413 if(cdData
->CdromInterfaceString
.Buffer
!= NULL
) {
5414 IoSetDeviceInterfaceState(
5415 &(cdData
->CdromInterfaceString
),
5417 RtlFreeUnicodeString(&(cdData
->CdromInterfaceString
));
5418 RtlInitUnicodeString(&(cdData
->CdromInterfaceString
), NULL
);
5421 if(cdData
->VolumeInterfaceString
.Buffer
!= NULL
) {
5422 IoSetDeviceInterfaceState(
5423 &(cdData
->VolumeInterfaceString
),
5425 RtlFreeUnicodeString(&(cdData
->VolumeInterfaceString
));
5426 RtlInitUnicodeString(&(cdData
->VolumeInterfaceString
), NULL
);
5429 CdRomDeleteWellKnownName(DeviceObject
);
5431 ASSERT(cdData
->DelayedRetryIrp
== NULL
);
5433 if(Type
== IRP_MN_REMOVE_DEVICE
) {
5435 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
)) {
5438 // unlock locked pages by locking (to get Mm pointer)
5439 // and then unlocking twice.
5444 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_1750
)) {
5446 locked
= MmLockPagableCodeSection(HitachiProcessError
);
5448 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_GD_2000
)) {
5450 locked
= MmLockPagableCodeSection(HitachiProcessErrorGD2000
);
5452 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_XM_3xx
)) {
5454 locked
= MmLockPagableCodeSection(ToshibaProcessError
);
5458 // this is a problem!
5459 // workaround by locking this twice, once for us and
5460 // once for the non-existant locker from ScanForSpecial
5461 ASSERT(!"hack flags show locked section, but none exists?");
5462 locked
= MmLockPagableCodeSection(CdRomRemoveDevice
);
5463 locked
= MmLockPagableCodeSection(CdRomRemoveDevice
);
5468 MmUnlockPagableImageSection(locked
);
5469 MmUnlockPagableImageSection(locked
);
5474 // keep the system-wide count accurate, as
5475 // programs use this info to know when they
5476 // have found all the cdroms in a system.
5479 TraceLog((CdromDebugTrace
,
5480 "CDROM.SYS Remove device\n"));
5481 IoGetConfigurationInformation()->CdRomCount
--;
5485 // so long, and thanks for all the fish!
5488 return STATUS_SUCCESS
;
5494 IN PDEVICE_OBJECT DeviceObject
5498 Routine Description:
5500 This routine figures out the real device type
5501 by checking CDVD_CAPABILITIES_PAGE
5509 FILE_DEVICE_CD_ROM or FILE_DEVICE_DVD
5514 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
5515 PCDROM_DATA cdromExtension
;
5517 SCSI_REQUEST_BLOCK srb
;
5519 PMODE_PARAMETER_HEADER10 modePageHeader
;
5520 PCDVD_CAPABILITIES_PAGE capPage
;
5521 ULONG capPageOffset
;
5522 DEVICE_TYPE deviceType
;
5529 // NOTE: don't cache this until understand how it affects GetMediaTypes()
5533 // default device type
5536 deviceType
= FILE_DEVICE_CD_ROM
;
5538 fdoExtension
= DeviceObject
->DeviceExtension
;
5540 cdromExtension
= fdoExtension
->CommonExtension
.DriverData
;
5542 use6Byte
= TEST_FLAG(cdromExtension
->XAFlags
, XA_USE_6_BYTE
);
5544 RtlZeroMemory(&srb
, sizeof(srb
));
5545 cdb
= (PCDB
)srb
.Cdb
;
5548 // Build the MODE SENSE CDB. The data returned will be kept in the
5549 // device extension and used to set block size.
5553 bufLength
= sizeof(CDVD_CAPABILITIES_PAGE
) +
5554 sizeof(MODE_PARAMETER_HEADER
);
5556 capPageOffset
= sizeof(MODE_PARAMETER_HEADER
);
5558 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
5559 cdb
->MODE_SENSE
.Dbd
= 1;
5560 cdb
->MODE_SENSE
.PageCode
= MODE_PAGE_CAPABILITIES
;
5561 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)bufLength
;
5565 bufLength
= sizeof(CDVD_CAPABILITIES_PAGE
) +
5566 sizeof(MODE_PARAMETER_HEADER10
);
5568 capPageOffset
= sizeof(MODE_PARAMETER_HEADER10
);
5570 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
5571 cdb
->MODE_SENSE10
.Dbd
= 1;
5572 cdb
->MODE_SENSE10
.PageCode
= MODE_PAGE_CAPABILITIES
;
5573 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(bufLength
>> 8);
5574 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(bufLength
>> 0);
5579 // Set timeout value from device extension.
5581 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
5583 modePageHeader
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
5585 CDROM_TAG_MODE_DATA
);
5586 if (modePageHeader
) {
5588 RtlZeroMemory(modePageHeader
, bufLength
);
5590 status
= ClassSendSrbSynchronous(
5597 if (NT_SUCCESS(status
) ||
5598 (status
== STATUS_DATA_OVERRUN
) ||
5599 (status
== STATUS_BUFFER_OVERFLOW
)
5602 capPage
= (PCDVD_CAPABILITIES_PAGE
) (((PUCHAR
) modePageHeader
) + capPageOffset
);
5604 if ((capPage
->PageCode
== MODE_PAGE_CAPABILITIES
) &&
5605 (capPage
->DVDROMRead
|| capPage
->DVDRRead
||
5606 capPage
->DVDRAMRead
|| capPage
->DVDRWrite
||
5607 capPage
->DVDRAMWrite
)) {
5609 deviceType
= FILE_DEVICE_DVD
;
5612 ExFreePool (modePageHeader
);
5620 CdRomCreateWellKnownName(
5621 IN PDEVICE_OBJECT DeviceObject
5625 Routine Description:
5627 This routine creates a symbolic link to the cdrom device object
5628 under \dosdevices. The number of the cdrom device does not neccessarily
5629 match between \dosdevices and \device, but usually will be the same.
5643 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
5644 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
5645 PCDROM_DATA cdromData
= commonExtension
->DriverData
;
5647 UNICODE_STRING unicodeLinkName
;
5648 WCHAR wideLinkName
[64];
5651 LONG cdromNumber
= fdoExtension
->DeviceNumber
;
5656 // if already linked, assert then return
5659 if (cdromData
->WellKnownName
.Buffer
!= NULL
) {
5661 TraceLog((CdromDebugError
,
5662 "CdRomCreateWellKnownName: link already exists %p\n",
5663 cdromData
->WellKnownName
.Buffer
));
5665 return STATUS_UNSUCCESSFUL
;
5670 // find an unused CdRomNN to link to
5675 swprintf(wideLinkName
, L
"\\DosDevices\\CdRom%d", cdromNumber
);
5676 RtlInitUnicodeString(&unicodeLinkName
, wideLinkName
);
5677 status
= IoCreateSymbolicLink(&unicodeLinkName
,
5678 &(commonExtension
->DeviceName
));
5682 } while((status
== STATUS_OBJECT_NAME_COLLISION
) ||
5683 (status
== STATUS_OBJECT_NAME_EXISTS
));
5685 if (!NT_SUCCESS(status
)) {
5687 TraceLog((CdromDebugWarning
,
5688 "CdRomCreateWellKnownName: Error %lx linking %wZ to "
5692 &(commonExtension
->DeviceName
)));
5697 TraceLog((CdromDebugWarning
,
5698 "CdRomCreateWellKnownName: successfully linked %wZ "
5701 &(commonExtension
->DeviceName
)));
5704 // Save away the symbolic link name in the driver data block. We need
5705 // it so we can delete the link when the device is removed.
5708 savedName
= ExAllocatePoolWithTag(PagedPool
,
5709 unicodeLinkName
.MaximumLength
,
5712 if (savedName
== NULL
) {
5713 IoDeleteSymbolicLink(&unicodeLinkName
);
5714 return STATUS_INSUFFICIENT_RESOURCES
;
5717 RtlCopyMemory(savedName
,
5718 unicodeLinkName
.Buffer
,
5719 unicodeLinkName
.MaximumLength
);
5721 RtlInitUnicodeString(&(cdromData
->WellKnownName
), savedName
);
5724 // the name was saved and the link created
5727 return STATUS_SUCCESS
;
5732 CdRomDeleteWellKnownName(
5733 IN PDEVICE_OBJECT DeviceObject
5736 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
5737 PCDROM_DATA cdromData
= commonExtension
->DriverData
;
5739 if(cdromData
->WellKnownName
.Buffer
!= NULL
) {
5741 IoDeleteSymbolicLink(&(cdromData
->WellKnownName
));
5742 ExFreePool(cdromData
->WellKnownName
.Buffer
);
5743 cdromData
->WellKnownName
.Buffer
= NULL
;
5744 cdromData
->WellKnownName
.Length
= 0;
5745 cdromData
->WellKnownName
.MaximumLength
= 0;
5753 CdRomGetDeviceParameter (
5754 IN PDEVICE_OBJECT Fdo
,
5755 IN PWSTR ParameterName
,
5756 IN OUT PULONG ParameterValue
5760 Routine Description:
5762 retrieve a devnode registry parameter
5766 DeviceObject - Cdrom Device Object
5768 ParameterName - parameter name to look up
5770 ParameterValuse - default parameter value
5778 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
5780 HANDLE deviceParameterHandle
;
5781 RTL_QUERY_REGISTRY_TABLE queryTable
[2];
5782 ULONG defaultParameterValue
;
5787 // open the given parameter
5789 status
= IoOpenDeviceRegistryKey(fdoExtension
->LowerPdo
,
5790 PLUGPLAY_REGKEY_DRIVER
,
5792 &deviceParameterHandle
);
5794 if(NT_SUCCESS(status
)) {
5796 RtlZeroMemory(queryTable
, sizeof(queryTable
));
5798 defaultParameterValue
= *ParameterValue
;
5800 queryTable
->Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
5801 queryTable
->Name
= ParameterName
;
5802 queryTable
->EntryContext
= ParameterValue
;
5803 queryTable
->DefaultType
= REG_NONE
;
5804 queryTable
->DefaultData
= NULL
;
5805 queryTable
->DefaultLength
= 0;
5807 status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
5808 (PWSTR
) deviceParameterHandle
,
5812 if (!NT_SUCCESS(status
)) {
5814 *ParameterValue
= defaultParameterValue
;
5818 // close what we open
5820 ZwClose(deviceParameterHandle
);
5825 } // CdRomGetDeviceParameter
5829 CdRomSetDeviceParameter (
5830 IN PDEVICE_OBJECT Fdo
,
5831 IN PWSTR ParameterName
,
5832 IN ULONG ParameterValue
5836 Routine Description:
5838 save a devnode registry parameter
5842 DeviceObject - Cdrom Device Object
5844 ParameterName - parameter name
5846 ParameterValuse - parameter value
5854 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
5856 HANDLE deviceParameterHandle
;
5861 // open the given parameter
5863 status
= IoOpenDeviceRegistryKey(fdoExtension
->LowerPdo
,
5864 PLUGPLAY_REGKEY_DRIVER
,
5865 KEY_READ
| KEY_WRITE
,
5866 &deviceParameterHandle
);
5868 if(NT_SUCCESS(status
)) {
5870 status
= RtlWriteRegistryValue(
5871 RTL_REGISTRY_HANDLE
,
5872 (PWSTR
) deviceParameterHandle
,
5876 sizeof (ParameterValue
));
5879 // close what we open
5881 ZwClose(deviceParameterHandle
);
5886 } // CdromSetDeviceParameter
5891 IN PDEVICE_OBJECT Fdo
5895 Routine Description:
5897 pick a default dvd region
5901 DeviceObject - Cdrom Device Object
5909 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
5910 PCDROM_DATA cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
5913 // these five pointers all point to dvdReadStructure or part of
5914 // its data, so don't deallocate them more than once!
5917 PDVD_READ_STRUCTURE dvdReadStructure
;
5918 PDVD_COPY_PROTECT_KEY copyProtectKey
;
5919 PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight
;
5920 PDVD_RPC_KEY rpcKey
;
5921 PDVD_SET_RPC_KEY dvdRpcKey
;
5923 IO_STATUS_BLOCK ioStatus
;
5926 ULONG pickDvdRegion
;
5927 ULONG defaultDvdRegion
;
5934 if ((pickDvdRegion
= InterlockedExchange(&cddata
->PickDvdRegion
, 0)) == 0) {
5937 // it was non-zero, so either another thread will do this, or
5938 // we no longer need to pick a region
5945 // short-circuit if license agreement violated
5948 if (cddata
->DvdRpc0LicenseFailure
) {
5949 TraceLog((CdromDebugWarning
,
5950 "DVD License failure. Refusing to pick a region\n"));
5951 InterlockedExchange(&cddata
->PickDvdRegion
, 0);
5957 a
= max(sizeof(DVD_DESCRIPTOR_HEADER
) +
5958 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
5959 sizeof(DVD_READ_STRUCTURE
)
5961 b
= max(DVD_RPC_KEY_LENGTH
,
5962 DVD_SET_RPC_KEY_LENGTH
5964 bufferLen
= max(a
, b
);
5966 dvdReadStructure
= (PDVD_READ_STRUCTURE
)
5967 ExAllocatePoolWithTag(PagedPool
, bufferLen
, DVD_TAG_DVD_REGION
);
5969 if (dvdReadStructure
== NULL
) {
5970 InterlockedExchange(&cddata
->PickDvdRegion
, pickDvdRegion
);
5974 if (cddata
->DvdRpc0Device
&& cddata
->Rpc0RetryRegistryCallback
) {
5976 TraceLog((CdromDebugWarning
,
5977 "CdRomPickDvdRegion (%p): now retrying RPC0 callback\n",
5981 // get the registry settings again
5984 ioStatus
.Status
= CdRomGetRpc0Settings(Fdo
);
5986 if (ioStatus
.Status
== STATUS_LICENSE_VIOLATION
) {
5989 // if this is the returned error, then
5990 // the routine should have set this!
5993 ASSERT(cddata
->DvdRpc0LicenseFailure
);
5994 cddata
->DvdRpc0LicenseFailure
= 1;
5995 TraceLog((CdromDebugWarning
,
5996 "CdRomPickDvdRegion (%p): "
5997 "setting to fail all dvd ioctls due to CSS licensing "
5998 "failure.\n", Fdo
));
6006 // get the device region, again
6009 copyProtectKey
= (PDVD_COPY_PROTECT_KEY
)dvdReadStructure
;
6010 RtlZeroMemory(copyProtectKey
, bufferLen
);
6011 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
6012 copyProtectKey
->KeyType
= DvdGetRpcKey
;
6015 // Build a request for READ_KEY
6018 ClassSendDeviceIoControlSynchronous(
6027 if (!NT_SUCCESS(ioStatus
.Status
)) {
6028 TraceLog((CdromDebugWarning
,
6029 "CdRomPickDvdRegion: Unable to get "
6030 "device RPC data (%x)\n", ioStatus
.Status
));
6036 // now that we have gotten the device's RPC data,
6037 // we have set the device extension to usable data.
6038 // no need to call back into this section of code again
6041 cddata
->Rpc0RetryRegistryCallback
= 0;
6044 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
6047 // TypeCode of zero means that no region has been set.
6050 if (rpcKey
->TypeCode
!= 0) {
6051 TraceLog((CdromDebugWarning
,
6052 "CdRomPickDvdRegion (%p): DVD Region already "
6058 TraceLog((CdromDebugWarning
,
6059 "CdRomPickDvdRegion (%p): must choose initial DVD "
6065 copyProtectKey
= (PDVD_COPY_PROTECT_KEY
) dvdReadStructure
;
6067 dvdCopyRight
= (PDVD_COPYRIGHT_DESCRIPTOR
)
6068 ((PDVD_DESCRIPTOR_HEADER
) dvdReadStructure
)->Data
;
6071 // get the media region
6074 RtlZeroMemory (dvdReadStructure
, bufferLen
);
6075 dvdReadStructure
->Format
= DvdCopyrightDescriptor
;
6078 // Build and send a request for READ_KEY
6081 TraceLog((CdromDebugTrace
,
6082 "CdRomPickDvdRegion (%p): Getting Copyright Descriptor\n",
6085 ClassSendDeviceIoControlSynchronous(
6086 IOCTL_DVD_READ_STRUCTURE
,
6089 sizeof(DVD_READ_STRUCTURE
),
6090 sizeof (DVD_DESCRIPTOR_HEADER
) +
6091 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
6095 TraceLog((CdromDebugTrace
,
6096 "CdRomPickDvdRegion (%p): Got Copyright Descriptor %x\n",
6097 Fdo
, ioStatus
.Status
));
6099 if ((NT_SUCCESS(ioStatus
.Status
)) &&
6100 (dvdCopyRight
->CopyrightProtectionType
== 0x01)
6104 // keep the media region bitmap around
6105 // a 1 means ok to play
6108 if (dvdCopyRight
->RegionManagementInformation
== 0xff) {
6109 TraceLog((CdromDebugError
,
6110 "CdRomPickDvdRegion (%p): RegionManagementInformation "
6111 "is set to dis-allow playback for all regions. This is "
6112 "most likely a poorly authored disc. defaulting to all "
6113 "region disc for purpose of choosing initial region\n",
6115 dvdCopyRight
->RegionManagementInformation
= 0;
6119 mediaRegion
= ~dvdCopyRight
->RegionManagementInformation
;
6124 // could be media, can't set the device region
6127 if (!cddata
->DvdRpc0Device
) {
6130 // can't automatically pick a default region on a rpc2 drive
6131 // without media, so just exit
6133 TraceLog((CdromDebugWarning
,
6134 "CdRomPickDvdRegion (%p): failed to auto-choose "
6135 "a region due to status %x getting copyright "
6136 "descriptor\n", Fdo
, ioStatus
.Status
));
6142 // for an RPC0 drive, we can try to pick a region for
6152 // get the device region
6155 RtlZeroMemory (copyProtectKey
, bufferLen
);
6156 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
6157 copyProtectKey
->KeyType
= DvdGetRpcKey
;
6160 // Build and send a request for READ_KEY for RPC key
6163 TraceLog((CdromDebugTrace
,
6164 "CdRomPickDvdRegion (%p): Getting RpcKey\n",
6166 ClassSendDeviceIoControlSynchronous(
6175 TraceLog((CdromDebugTrace
,
6176 "CdRomPickDvdRegion (%p): Got RpcKey %x\n",
6177 Fdo
, ioStatus
.Status
));
6179 if (!NT_SUCCESS(ioStatus
.Status
)) {
6181 TraceLog((CdromDebugWarning
,
6182 "CdRomPickDvdRegion (%p): failed to get RpcKey from "
6183 "a DVD Device\n", Fdo
));
6189 // so we now have what we can get for the media region and the
6190 // drive region. we will not set a region if the drive has one
6191 // set already (mask is not all 1's), nor will we set a region
6192 // if there are no more user resets available.
6195 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
6198 if (rpcKey
->RegionMask
!= 0xff) {
6199 TraceLog((CdromDebugWarning
,
6200 "CdRomPickDvdRegion (%p): not picking a region since "
6201 "it is already chosen\n", Fdo
));
6205 if (rpcKey
->UserResetsAvailable
<= 1) {
6206 TraceLog((CdromDebugWarning
,
6207 "CdRomPickDvdRegion (%p): not picking a region since "
6208 "only one change remains\n", Fdo
));
6212 defaultDvdRegion
= 0;
6215 // the proppage dvd class installer sets
6216 // this key based upon the system locale
6219 CdRomGetDeviceParameter (
6225 if (defaultDvdRegion
> DVD_MAX_REGION
) {
6228 // the registry has a bogus default
6231 TraceLog((CdromDebugWarning
,
6232 "CdRomPickDvdRegion (%p): registry has a bogus default "
6233 "region value of %x\n", Fdo
, defaultDvdRegion
));
6234 defaultDvdRegion
= 0;
6239 // if defaultDvdRegion == 0, it means no default.
6243 // we will select the initial dvd region for the user
6246 if ((defaultDvdRegion
!= 0) &&
6248 (1 << (defaultDvdRegion
- 1))
6254 // the media has region that matches
6255 // the default dvd region.
6258 dvdRegion
= (1 << (defaultDvdRegion
- 1));
6260 TraceLog((CdromDebugWarning
,
6261 "CdRomPickDvdRegion (%p): Choice #1: media matches "
6262 "drive's default, chose region %x\n", Fdo
, dvdRegion
));
6265 } else if (mediaRegion
) {
6269 // pick the lowest region number
6277 while (mediaRegion
&& !dvdRegion
) {
6280 // pick the lowest bit
6282 dvdRegion
= mediaRegion
& mask
;
6286 TraceLog((CdromDebugWarning
,
6287 "CdRomPickDvdRegion (%p): Choice #2: choosing lowest "
6288 "media region %x\n", Fdo
, dvdRegion
));
6290 } else if (defaultDvdRegion
) {
6294 // default dvd region from the dvd class installer
6297 dvdRegion
= (1 << (defaultDvdRegion
- 1));
6298 TraceLog((CdromDebugWarning
,
6299 "CdRomPickDvdRegion (%p): Choice #3: using default "
6300 "region for this install %x\n", Fdo
, dvdRegion
));
6305 // unable to pick one for the user -- this should rarely
6306 // happen, since the proppage dvd class installer sets
6307 // the key based upon the system locale
6309 TraceLog((CdromDebugWarning
,
6310 "CdRomPickDvdRegion (%p): Choice #4: failed to choose "
6311 "a media region\n", Fdo
));
6317 // now that we've chosen a region, set the region by sending the
6318 // appropriate request to the drive
6321 RtlZeroMemory (copyProtectKey
, bufferLen
);
6322 copyProtectKey
->KeyLength
= DVD_SET_RPC_KEY_LENGTH
;
6323 copyProtectKey
->KeyType
= DvdSetRpcKey
;
6324 dvdRpcKey
= (PDVD_SET_RPC_KEY
) copyProtectKey
->KeyData
;
6325 dvdRpcKey
->PreferredDriveRegionCode
= (UCHAR
) ~dvdRegion
;
6328 // Build and send request for SEND_KEY
6330 TraceLog((CdromDebugTrace
,
6331 "CdRomPickDvdRegion (%p): Sending new Rpc Key to region %x\n",
6334 ClassSendDeviceIoControlSynchronous(
6335 IOCTL_DVD_SEND_KEY2
,
6338 DVD_SET_RPC_KEY_LENGTH
,
6342 TraceLog((CdromDebugTrace
,
6343 "CdRomPickDvdRegion (%p): Sent new Rpc Key %x\n",
6344 Fdo
, ioStatus
.Status
));
6346 if (!NT_SUCCESS(ioStatus
.Status
)) {
6347 DebugPrint ((1, "CdRomPickDvdRegion (%p): unable to set dvd initial "
6348 " region code (%p)\n", Fdo
, ioStatus
.Status
));
6350 DebugPrint ((1, "CdRomPickDvdRegion (%p): Successfully set dvd "
6351 "initial region\n", Fdo
));
6356 if (dvdReadStructure
) {
6357 ExFreePool (dvdReadStructure
);
6361 // update the new PickDvdRegion value
6364 InterlockedExchange(&cddata
->PickDvdRegion
, pickDvdRegion
);
6372 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
6375 IN BOOLEAN ResendIrp
6382 return CdRomRerunRequest(FdoExtension
, Irp
, ResendIrp
);
6385 cdData
= FdoExtension
->CommonExtension
.DriverData
;
6387 KeAcquireSpinLock(&(cdData
->DelayedRetrySpinLock
), &oldIrql
);
6389 ASSERT(cdData
->DelayedRetryIrp
== NULL
);
6390 ASSERT(cdData
->DelayedRetryInterval
== 0);
6392 cdData
->DelayedRetryIrp
= Irp
;
6393 cdData
->DelayedRetryInterval
= Delay
;
6394 cdData
->DelayedRetryResend
= ResendIrp
;
6396 KeReleaseSpinLock(&(cdData
->DelayedRetrySpinLock
), oldIrql
);
6398 return STATUS_PENDING
;
6404 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
6405 IN OPTIONAL PIRP Irp
,
6406 IN BOOLEAN ResendIrp
6410 return IoCallDriver(FdoExtension
->CommonExtension
.LowerDeviceObject
,
6415 oldIrql
= KeRaiseIrqlToDpcLevel();
6416 CdRomStartIo(FdoExtension
->DeviceObject
, Irp
);
6417 KeLowerIrql(oldIrql
);
6418 return STATUS_MORE_PROCESSING_REQUIRED
;
6424 Routine Description:
6426 This routine just checks for media change sense/asc/ascq and
6427 also for other events, such as bus resets. this is used to
6428 determine if the device behaviour has changed, to allow for
6429 read and write operations to be allowed and/or disallowed.
6433 ISSUE-2000/3/30-henrygab - not fully doc'd
6443 CdRomMmcErrorHandler(
6444 IN PDEVICE_OBJECT Fdo
,
6445 IN PSCSI_REQUEST_BLOCK Srb
,
6446 OUT PNTSTATUS Status
,
6450 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
6451 //BOOLEAN queryCapabilities = FALSE;
6453 if (TEST_FLAG(Srb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
6455 PCDROM_DATA cddata
= (PCDROM_DATA
)commonExtension
->DriverData
;
6456 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
6459 // the following sense keys could indicate a change in
6464 // we used to expect this to be serialized, and only hit from our
6465 // own routine. we now allow some requests to continue during our
6466 // processing of the capabilities update in order to allow
6467 // IoReadPartitionTable() to succeed.
6470 switch (senseBuffer
->SenseKey
& 0xf) {
6472 case SCSI_SENSE_NOT_READY
: {
6473 if (senseBuffer
->AdditionalSenseCode
==
6474 SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
) {
6476 if (cddata
->Mmc
.WriteAllowed
) {
6477 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6478 "CdromErrorHandler: media removed, writes will be "
6479 "failed until new media detected\n"));
6483 cddata
->Mmc
.WriteAllowed
= FALSE
;
6485 if ((senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
6486 (senseBuffer
->AdditionalSenseCodeQualifier
==
6487 SCSI_SENSEQ_BECOMING_READY
)) {
6488 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6489 "CdromErrorHandler: media becoming ready, "
6490 "SHOULD notify shell of change time by sending "
6491 "GESN request immediately!\n"));
6494 } // end SCSI_SENSE_NOT_READY
6496 case SCSI_SENSE_UNIT_ATTENTION
: {
6497 switch (senseBuffer
->AdditionalSenseCode
) {
6498 case SCSI_ADSENSE_MEDIUM_CHANGED
: {
6501 // always update if the medium may have changed
6505 cddata
->Mmc
.WriteAllowed
= FALSE
;
6506 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6507 CdromMmcUpdateRequired
,
6508 CdromMmcUpdateComplete
);
6510 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6511 "CdromErrorHandler: media change detected, need to "
6512 "update drive capabilities\n"));
6515 } // end SCSI_ADSENSE_MEDIUM_CHANGED
6517 case SCSI_ADSENSE_BUS_RESET
: {
6520 cddata
->Mmc
.WriteAllowed
= FALSE
;
6521 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6522 CdromMmcUpdateRequired
,
6523 CdromMmcUpdateComplete
);
6525 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6526 "CdromErrorHandler: bus reset detected, need to "
6527 "update drive capabilities\n"));
6530 } // end SCSI_ADSENSE_BUS_RESET
6532 case SCSI_ADSENSE_OPERATOR_REQUEST
: {
6536 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
6537 case SCSI_SENSEQ_MEDIUM_REMOVAL
: {
6540 // eject notification currently handled by classpnp
6543 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6544 "CdromErrorHandler: Eject requested by user\n"));
6546 *Status
= STATUS_DEVICE_BUSY
;
6550 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE
:
6552 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE
: {
6554 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6555 "CdromErrorHandler: Write protect %s requested "
6557 (b
? "disable" : "enable")));
6559 *Status
= STATUS_DEVICE_BUSY
;
6561 cddata
->Mmc
.WriteAllowed
= FALSE
;
6562 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6563 CdromMmcUpdateRequired
,
6564 CdromMmcUpdateComplete
);
6568 } // end of AdditionalSenseCodeQualifier switch
6573 } // end SCSI_ADSENSE_OPERATOR_REQUEST
6576 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6577 "CdromErrorHandler: Unit attention %02x/%02x\n",
6578 senseBuffer
->AdditionalSenseCode
,
6579 senseBuffer
->AdditionalSenseCodeQualifier
));
6583 } // end of AdditionSenseCode switch
6586 } // end SCSI_SENSE_UNIT_ATTENTION
6588 case SCSI_SENSE_ILLEGAL_REQUEST
: {
6589 if (senseBuffer
->AdditionalSenseCode
==
6590 SCSI_ADSENSE_WRITE_PROTECT
) {
6592 if (cddata
->Mmc
.WriteAllowed
) {
6593 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6594 "CdromErrorHandler: media was writable, but "
6595 "failed request with WRITE_PROTECT error...\n"));
6598 // do not update all the capabilities just because
6599 // we can't write to the disc.
6600 cddata
->Mmc
.WriteAllowed
= FALSE
;
6603 } // end SCSI_SENSE_ILLEGAL_REQUEST
6605 } // end of SenseKey switch
6607 } // end of SRB_STATUS_AUTOSENSE_VALID
6612 Routine Description:
6614 This routine checks for a device-specific error handler
6615 and calls it if it exists. This allows multiple drives
6616 that require their own error handler to co-exist.
6622 PDEVICE_OBJECT DeviceObject
,
6623 PSCSI_REQUEST_BLOCK Srb
,
6628 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
6629 PCDROM_DATA cddata
= (PCDROM_DATA
)commonExtension
->DriverData
;
6630 PSENSE_DATA sense
= Srb
->SenseInfoBuffer
;
6632 if ((Srb
->SenseInfoBufferLength
>=
6633 RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA
,AdditionalSenseCodeQualifier
)) &&
6634 TEST_FLAG(Srb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
6637 // Many non-WHQL certified drives (mostly CD-RW) return
6638 // 2/4/0 when they have no media instead of the obvious
6641 // SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
6643 // These drives should not pass WHQL certification due
6644 // to this discrepency.
6646 // However, we have to retry on 2/4/0 (Not ready, LUN not ready,
6647 // no info) and also 3/2/0 (no seek complete).
6649 // These conditions occur when the shell tries to examine an
6650 // injected CD (e.g. for autoplay) before the CD is spun up.
6652 // The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
6653 // (0x01) in order to comply with WHQL standards.
6655 // The default retry timeout of one second is acceptable to balance
6656 // these discrepencies. don't modify the status, though....
6659 if (((sense
->SenseKey
& 0xf) == SCSI_SENSE_NOT_READY
) &&
6660 (sense
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
6661 (sense
->AdditionalSenseCodeQualifier
== SCSI_SENSEQ_CAUSE_NOT_REPORTABLE
)
6666 } else if (((sense
->SenseKey
& 0xf) == SCSI_SENSE_MEDIUM_ERROR
) &&
6667 (sense
->AdditionalSenseCode
== 0x2) &&
6668 (sense
->AdditionalSenseCodeQualifier
== 0x0)
6673 } else if ((sense
->AdditionalSenseCode
== 0x57) &&
6674 (sense
->AdditionalSenseCodeQualifier
== 0x00)
6678 // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
6679 // the Matshita CR-585 returns this for all read commands
6680 // on blank CD-R and CD-RW media, and we need to handle
6681 // this for READ_CD detection ability.
6685 *Status
= STATUS_UNRECOGNIZED_MEDIA
;
6692 // tail recursion in both cases takes no stack
6695 if (cddata
->ErrorHandler
) {
6696 cddata
->ErrorHandler(DeviceObject
, Srb
, Status
, Retry
);
6703 Routine Description:
6705 This routine is called for a shutdown and flush IRPs.
6706 These are sent by the system before it actually shuts
6707 down or when the file system does a flush.
6711 DriverObject - Pointer to device object to being shutdown by system.
6723 IN PDEVICE_OBJECT DeviceObject
,
6727 IoMarkIrpPending(Irp
);
6728 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
6729 return STATUS_PENDING
;
6735 Routine Description:
6737 This routine is called for intermediate work a shutdown or
6738 flush IRPs would need to do. We just want to free our resources
6739 and return STATUS_MORE_PROCESSING_REQUIRED.
6743 DeviceObject - NULL?
6756 CdRomShutdownFlushCompletion(
6757 IN PDEVICE_OBJECT Fdo
,
6762 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
6763 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
6764 PIO_STACK_LOCATION originalIrpStack
;
6765 ULONG_PTR iteration
;
6766 NTSTATUS status
= STATUS_SUCCESS
;
6768 ASSERT(OriginalIrp
);
6770 originalIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
6773 // always use a new irp so we can call
6774 // CdRomCompleteIrpAndStartNextPacketSafely() from this routine.
6777 if (NewIrp
!= NULL
) {
6778 status
= NewIrp
->IoStatus
.Status
;
6783 if (!NT_SUCCESS(status
)) {
6784 BAIL_OUT(OriginalIrp
);
6789 // the current irpstack saves the counter which states
6790 // what part of the multi-part shutdown or flush we are in.
6793 iteration
= (ULONG_PTR
)originalIrpStack
->Parameters
.Others
.Argument1
;
6795 originalIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)iteration
;
6797 switch (iteration
) {
6799 if (originalIrpStack
->MajorFunction
!= IRP_MJ_SHUTDOWN
) {
6801 // then we don't want to send the unlock command
6802 // the incrementing of the state was done above.
6803 // return the completion routine's result.
6805 return CdRomShutdownFlushCompletion(Fdo
, NULL
, OriginalIrp
);
6807 // else fall through....
6812 PSCSI_REQUEST_BLOCK newSrb
= NULL
;
6814 PIO_STACK_LOCATION newIrpStack
= NULL
;
6817 newIrp
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1), FALSE
);
6818 if (newIrp
== NULL
) {
6819 BAIL_OUT(OriginalIrp
);
6820 status
= STATUS_INSUFFICIENT_RESOURCES
;
6823 newSrb
= ExAllocatePoolWithTag(NonPagedPool
,
6824 sizeof(SCSI_REQUEST_BLOCK
),
6826 if (newSrb
== NULL
) {
6828 BAIL_OUT(OriginalIrp
);
6829 status
= STATUS_INSUFFICIENT_RESOURCES
;
6834 // ClassIoComplete will free the SRB, but we need a routine
6835 // that will free the irp. then just call ClassSendAsync,
6836 // and don't care about the return value, since the completion
6837 // routine will be called anyways.
6840 IoSetNextIrpStackLocation(newIrp
);
6841 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
6842 newIrpStack
->DeviceObject
= Fdo
;
6843 IoSetCompletionRoutine(newIrp
,
6844 (PIO_COMPLETION_ROUTINE
)CdRomShutdownFlushCompletion
,
6847 IoSetNextIrpStackLocation(newIrp
);
6848 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
6849 newIrpStack
->DeviceObject
= Fdo
;
6852 // setup the request
6855 RtlZeroMemory(newSrb
, sizeof(SCSI_REQUEST_BLOCK
));
6856 newCdb
= (PCDB
)(newSrb
->Cdb
);
6858 newSrb
->QueueTag
= SP_UNTAGGED
;
6859 newSrb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
6860 newSrb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6863 // tell classpnp not to call StartNextPacket()
6866 newSrb
->SrbFlags
= SRB_FLAGS_DONT_START_NEXT_PACKET
;
6868 if (iteration
== 1) {
6871 // first synchronize the cache
6874 newSrb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 4;
6875 newSrb
->CdbLength
= 10;
6876 newCdb
->SYNCHRONIZE_CACHE10
.OperationCode
= SCSIOP_SYNCHRONIZE_CACHE
;
6878 } else if (iteration
== 2) {
6881 // then unlock the medium
6884 ASSERT( originalIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
);
6886 newSrb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
6887 newSrb
->CdbLength
= 6;
6888 newCdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
6889 newCdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
6894 isRemoved
= ClassAcquireRemoveLock(Fdo
, newIrp
);
6898 ClassReleaseRemoveLock(Fdo
, newIrp
);
6899 BAIL_OUT(OriginalIrp
);
6900 status
= STATUS_DEVICE_DOES_NOT_EXIST
;
6903 ClassSendSrbAsynchronous(Fdo
, newSrb
, newIrp
, NULL
, 0, FALSE
);
6909 PSCSI_REQUEST_BLOCK srb
;
6910 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(OriginalIrp
);
6913 // forward this request to the device appropriately,
6914 // don't use this completion routine anymore...
6917 srb
= ExAllocatePoolWithTag(NonPagedPool
,
6918 sizeof(SCSI_REQUEST_BLOCK
),
6921 BAIL_OUT(OriginalIrp
);
6922 status
= STATUS_INSUFFICIENT_RESOURCES
;
6926 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
6927 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6928 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 4;
6929 srb
->QueueTag
= SP_UNTAGGED
;
6930 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
6931 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
6933 srb
->OriginalRequest
= OriginalIrp
;
6935 if (originalIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
6936 srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
6938 srb
->Function
= SRB_FUNCTION_FLUSH
;
6942 // Set up IoCompletion routine address.
6945 IoSetCompletionRoutine(OriginalIrp
,
6951 // Set the retry count to zero.
6954 originalIrpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
6957 // Get next stack location and set major function code.
6960 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
6963 // Set up SRB for execute scsi request.
6964 // Save SRB address in next stack for port driver.
6967 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
6970 // Call the port driver to process the request.
6973 IoCallDriver(commonExtension
->LowerDeviceObject
, OriginalIrp
);
6985 status
= STATUS_SUCCESS
;
6989 if (!NT_SUCCESS(status
)) {
6990 OriginalIrp
->IoStatus
.Status
= status
;
6991 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
6995 // always return STATUS_MORE_PROCESSING_REQUIRED, so noone else tries
6996 // to access the new irp that we free'd....
6999 return STATUS_MORE_PROCESSING_REQUIRED
;
7001 } // end CdromShutdownFlush()
7005 CdromFakePartitionInfo(
7006 IN PCOMMON_DEVICE_EXTENSION CommonExtension
,
7010 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
7011 ULONG ioctl
= currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
7012 PVOID systemBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
7014 ASSERT(systemBuffer
);
7016 if ((ioctl
!= IOCTL_DISK_GET_DRIVE_LAYOUT
) &&
7017 (ioctl
!= IOCTL_DISK_GET_DRIVE_LAYOUT_EX
) &&
7018 (ioctl
!= IOCTL_DISK_GET_PARTITION_INFO
) &&
7019 (ioctl
!= IOCTL_DISK_GET_PARTITION_INFO_EX
)) {
7020 TraceLog((CdromDebugError
,
7021 "CdromFakePartitionInfo: unhandled ioctl %x\n", ioctl
));
7022 Irp
->IoStatus
.Status
= STATUS_INTERNAL_ERROR
;
7023 Irp
->IoStatus
.Information
= 0;
7024 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension
->DeviceObject
,
7030 // nothing to fail from this point on, so set the size appropriately
7031 // and set irp's status to success.
7034 TraceLog((CdromDebugWarning
,
7035 "CdromFakePartitionInfo: incoming ioctl %x\n", ioctl
));
7038 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
7040 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
7041 Irp
->IoStatus
.Information
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
7043 RtlZeroMemory(systemBuffer
, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
7044 PartitionEntry
[1]));
7046 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
:
7047 Irp
->IoStatus
.Information
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
,
7049 RtlZeroMemory(systemBuffer
, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
,
7050 PartitionEntry
[1]));
7052 case IOCTL_DISK_GET_PARTITION_INFO
:
7053 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
7054 RtlZeroMemory(systemBuffer
, sizeof(PARTITION_INFORMATION
));
7056 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
7057 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
7058 RtlZeroMemory(systemBuffer
, sizeof(PARTITION_INFORMATION_EX
));
7061 ASSERT(!"Invalid ioctl should not have reached this point\n");
7066 // if we are getting the drive layout, then we need to start by
7067 // adding some of the non-partition stuff that says we have
7068 // exactly one partition available.
7072 if (ioctl
== IOCTL_DISK_GET_DRIVE_LAYOUT
) {
7074 PDRIVE_LAYOUT_INFORMATION layout
;
7075 layout
= (PDRIVE_LAYOUT_INFORMATION
)systemBuffer
;
7076 layout
->PartitionCount
= 1;
7077 layout
->Signature
= 1;
7078 systemBuffer
= (PVOID
)(layout
->PartitionEntry
);
7079 ioctl
= IOCTL_DISK_GET_PARTITION_INFO
;
7081 } else if (ioctl
== IOCTL_DISK_GET_DRIVE_LAYOUT_EX
) {
7083 PDRIVE_LAYOUT_INFORMATION_EX layoutEx
;
7084 layoutEx
= (PDRIVE_LAYOUT_INFORMATION_EX
)systemBuffer
;
7085 layoutEx
->PartitionStyle
= PARTITION_STYLE_MBR
;
7086 layoutEx
->PartitionCount
= 1;
7087 layoutEx
->Mbr
.Signature
= 1;
7088 systemBuffer
= (PVOID
)(layoutEx
->PartitionEntry
);
7089 ioctl
= IOCTL_DISK_GET_PARTITION_INFO_EX
;
7094 // NOTE: the local var 'ioctl' is now modified to either EX or
7095 // non-EX version. the local var 'systemBuffer' is now pointing
7096 // to the partition information structure.
7099 if (ioctl
== IOCTL_DISK_GET_PARTITION_INFO
) {
7101 PPARTITION_INFORMATION partitionInfo
;
7102 partitionInfo
= (PPARTITION_INFORMATION
)systemBuffer
;
7103 partitionInfo
->RewritePartition
= FALSE
;
7104 partitionInfo
->RecognizedPartition
= TRUE
;
7105 partitionInfo
->PartitionType
= PARTITION_FAT32
;
7106 partitionInfo
->BootIndicator
= FALSE
;
7107 partitionInfo
->HiddenSectors
= 0;
7108 partitionInfo
->StartingOffset
.QuadPart
= 0;
7109 partitionInfo
->PartitionLength
= CommonExtension
->PartitionLength
;
7110 partitionInfo
->PartitionNumber
= 0;
7114 PPARTITION_INFORMATION_EX partitionInfo
;
7115 partitionInfo
= (PPARTITION_INFORMATION_EX
)systemBuffer
;
7116 partitionInfo
->PartitionStyle
= PARTITION_STYLE_MBR
;
7117 partitionInfo
->RewritePartition
= FALSE
;
7118 partitionInfo
->Mbr
.RecognizedPartition
= TRUE
;
7119 partitionInfo
->Mbr
.PartitionType
= PARTITION_FAT32
;
7120 partitionInfo
->Mbr
.BootIndicator
= FALSE
;
7121 partitionInfo
->Mbr
.HiddenSectors
= 0;
7122 partitionInfo
->StartingOffset
.QuadPart
= 0;
7123 partitionInfo
->PartitionLength
= CommonExtension
->PartitionLength
;
7124 partitionInfo
->PartitionNumber
= 0;
7127 TraceLog((CdromDebugWarning
,
7128 "CdromFakePartitionInfo: finishing ioctl %x\n",
7129 currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
));
7135 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension
->DeviceObject
,