3 Copyright (C) Microsoft Corporation, 1991 - 1999
11 The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
12 and sends them to its devices through the port driver.
20 SCSI Tape, CDRom and Disk class drivers share common routines
21 that can be found in the CLASS directory (..\ntos\dd\class).
41 #pragma alloc_text(INIT, DriverEntry)
43 #pragma alloc_text(PAGE, CdRomUnload)
44 #pragma alloc_text(PAGE, CdRomAddDevice)
45 #pragma alloc_text(PAGE, CdRomCreateDeviceObject)
46 #pragma alloc_text(PAGE, CdRomStartDevice)
47 #pragma alloc_text(PAGE, ScanForSpecial)
48 #pragma alloc_text(PAGE, ScanForSpecialHandler)
49 #pragma alloc_text(PAGE, CdRomRemoveDevice)
50 #pragma alloc_text(PAGE, CdRomGetDeviceType)
51 #pragma alloc_text(PAGE, CdRomReadWriteVerification)
52 #pragma alloc_text(PAGE, CdRomGetDeviceParameter)
53 #pragma alloc_text(PAGE, CdRomSetDeviceParameter)
54 #pragma alloc_text(PAGE, CdRomPickDvdRegion)
55 #pragma alloc_text(PAGE, CdRomIsPlayActive)
57 #pragma alloc_text(PAGEHITA, HitachiProcessError)
58 #pragma alloc_text(PAGEHIT2, HitachiProcessErrorGD2000)
60 #pragma alloc_text(PAGETOSH, ToshibaProcessErrorCompletion)
61 #pragma alloc_text(PAGETOSH, ToshibaProcessError)
65 #define IS_WRITE_REQUEST(irpStack) \
66 (irpStack->MajorFunction == IRP_MJ_WRITE)
68 #define IS_READ_WRITE_REQUEST(irpStack) \
69 ((irpStack->MajorFunction == IRP_MJ_READ) || \
70 (irpStack->MajorFunction == IRP_MJ_WRITE) || \
71 ((irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) && \
72 (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_CDROM_RAW_READ)))
80 IN PDRIVER_OBJECT DriverObject
,
81 IN PUNICODE_STRING RegistryPath
88 This routine initializes the cdrom class driver.
92 DriverObject - Pointer to driver object created by system.
94 RegistryPath - Pointer to the name of the services node for this driver.
98 The function value is the final status from the initialization operation.
103 CLASS_INIT_DATA InitializationData
;
104 PCDROM_DRIVER_EXTENSION driverExtension
;
109 WPP_INIT_TRACING(DriverObject
, RegistryPath
);
111 TraceLog((CdromDebugTrace
,
112 "CDROM.SYS DriverObject %p loading\n", DriverObject
));
114 status
= IoAllocateDriverObjectExtension(DriverObject
,
115 CDROM_DRIVER_EXTENSION_ID
,
116 sizeof(CDROM_DRIVER_EXTENSION
),
117 (PVOID
*)&driverExtension
);
119 if (!NT_SUCCESS(status
)) {
120 TraceLog((CdromDebugWarning
,
121 "DriverEntry !! no DriverObjectExtension %x\n", status
));
126 // always zero the memory, since we are now reloading the driver.
129 RtlZeroMemory(driverExtension
, sizeof(CDROM_DRIVER_EXTENSION
));
135 RtlZeroMemory (&InitializationData
, sizeof(CLASS_INIT_DATA
));
141 InitializationData
.InitializationDataSize
= sizeof(CLASS_INIT_DATA
);
143 InitializationData
.FdoData
.DeviceExtensionSize
= DEVICE_EXTENSION_SIZE
;
145 InitializationData
.FdoData
.DeviceType
= FILE_DEVICE_CD_ROM
;
146 InitializationData
.FdoData
.DeviceCharacteristics
=
147 FILE_REMOVABLE_MEDIA
| FILE_DEVICE_SECURE_OPEN
;
153 InitializationData
.FdoData
.ClassError
= CdRomErrorHandler
;
154 InitializationData
.FdoData
.ClassInitDevice
= CdRomInitDevice
;
155 InitializationData
.FdoData
.ClassStartDevice
= CdRomStartDevice
;
156 InitializationData
.FdoData
.ClassStopDevice
= CdRomStopDevice
;
157 InitializationData
.FdoData
.ClassRemoveDevice
= CdRomRemoveDevice
;
159 InitializationData
.FdoData
.ClassReadWriteVerification
= CdRomReadWriteVerification
;
160 InitializationData
.FdoData
.ClassDeviceControl
= CdRomDeviceControlDispatch
;
162 InitializationData
.FdoData
.ClassPowerDevice
= ClassSpinDownPowerHandler
;
163 InitializationData
.FdoData
.ClassShutdownFlush
= CdRomShutdownFlush
;
164 InitializationData
.FdoData
.ClassCreateClose
= NULL
;
166 InitializationData
.ClassStartIo
= CdRomStartIo
;
167 InitializationData
.ClassAddDevice
= CdRomAddDevice
;
169 InitializationData
.ClassTick
= CdRomTickHandler
;
170 InitializationData
.ClassUnload
= CdRomUnload
;
173 // Call the class init routine
175 return ClassInitialize( DriverObject
, RegistryPath
, &InitializationData
);
177 } // end DriverEntry()
182 IN PDRIVER_OBJECT DriverObject
186 UNREFERENCED_PARAMETER(DriverObject
);
187 TraceLog((CdromDebugTrace
,
188 "CDROM.SYS DriverObject %p unloading\n", DriverObject
));
189 WPP_CLEANUP(DriverObject
);
191 } // end CdRomUnload()
196 IN PDRIVER_OBJECT DriverObject
,
197 IN PDEVICE_OBJECT PhysicalDeviceObject
204 This routine creates and initializes a new FDO for the corresponding
205 PDO. It may perform property queries on the FDO but cannot do any
206 media access operations.
210 DriverObject - CDROM class driver object.
212 Pdo - the physical device object we are being added to
226 // Get the address of the count of the number of cdroms already initialized.
228 DbgPrint("add device\n");
230 status
= CdRomCreateDeviceObject(DriverObject
,
231 PhysicalDeviceObject
);
234 // Note: this always increments driver extension counter
235 // it will eventually wrap, and fail additions
236 // if an existing cdrom has the given number.
237 // so unlikely that we won't even bother considering
238 // this case, since the cure is quite likely worse
239 // than the symptoms.
242 if(NT_SUCCESS(status
)) {
245 // keep track of the total number of active cdroms in IoGet(),
246 // as some programs use this to determine when they have found
247 // all the cdroms in the system.
250 TraceLog((CdromDebugTrace
, "CDROM.SYS Add succeeded\n"));
251 IoGetConfigurationInformation()->CdRomCount
++;
255 TraceLog((CdromDebugWarning
,
256 "CDROM.SYS Add failed! %x\n", status
));
265 CdRomCreateDeviceObject(
266 IN PDRIVER_OBJECT DriverObject
,
267 IN PDEVICE_OBJECT PhysicalDeviceObject
274 This routine creates an object for the device and then calls the
275 SCSI port driver for media capacity and sector size.
279 DriverObject - Pointer to driver object created by system.
280 PortDeviceObject - to connect to SCSI port driver.
281 DeviceCount - Number of previously installed CDROMs.
282 PortCapabilities - Pointer to structure returned by SCSI port
283 driver describing adapter capabilites (and limitations).
284 LunInfo - Pointer to configuration information for this device.
292 UCHAR ntNameBuffer
[64];
296 PDEVICE_OBJECT lowerDevice
= NULL
;
297 PDEVICE_OBJECT deviceObject
= NULL
;
298 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= NULL
;
299 PCDROM_DATA cdData
= NULL
;
300 PCDROM_DRIVER_EXTENSION driverExtension
= NULL
;
303 CCHAR dosNameBuffer
[64];
304 CCHAR deviceNameBuffer
[64];
305 STRING deviceNameString
;
307 UNICODE_STRING dosUnicodeString
;
308 UNICODE_STRING unicodeString
;
313 // Claim the device. Note that any errors after this
314 // will goto the generic handler, where the device will
318 lowerDevice
= IoGetAttachedDeviceReference(PhysicalDeviceObject
);
320 status
= ClassClaimDevice(lowerDevice
, FALSE
);
322 if(!NT_SUCCESS(status
)) {
325 // Someone already had this device - we're in trouble
328 ObDereferenceObject(lowerDevice
);
333 // Create device object for this device by first getting a unique name
334 // for the device and then creating it.
337 driverExtension
= IoGetDriverObjectExtension(DriverObject
,
338 CDROM_DRIVER_EXTENSION_ID
);
339 ASSERT(driverExtension
!= NULL
);
342 // InterlockedCdRomCounter is biased by 1.
345 deviceNumber
= InterlockedIncrement(&driverExtension
->InterlockedCdRomCounter
) - 1;
346 sprintf(ntNameBuffer
, "\\Device\\CdRom%d", deviceNumber
);
349 status
= ClassCreateDeviceObject(DriverObject
,
351 PhysicalDeviceObject
,
355 if (!NT_SUCCESS(status
)) {
356 TraceLog((CdromDebugWarning
,
357 "CreateCdRomDeviceObjects: Can not create device %s\n",
360 goto CreateCdRomDeviceObjectExit
;
364 // Indicate that IRPs should include MDLs.
367 SET_FLAG(deviceObject
->Flags
, DO_DIRECT_IO
);
369 fdoExtension
= deviceObject
->DeviceExtension
;
372 // Back pointer to device object.
375 fdoExtension
->CommonExtension
.DeviceObject
= deviceObject
;
378 // This is the physical device.
381 fdoExtension
->CommonExtension
.PartitionZeroExtension
= fdoExtension
;
384 // Initialize lock count to zero. The lock count is used to
385 // disable the ejection mechanism when media is mounted.
388 fdoExtension
->LockCount
= 0;
391 // Save system cdrom number
394 fdoExtension
->DeviceNumber
= deviceNumber
;
397 // Set the alignment requirements for the device based on the
398 // host adapter requirements
401 if (lowerDevice
->AlignmentRequirement
> deviceObject
->AlignmentRequirement
) {
402 deviceObject
->AlignmentRequirement
= lowerDevice
->AlignmentRequirement
;
406 // Save the device descriptors
409 fdoExtension
->AdapterDescriptor
= NULL
;
411 fdoExtension
->DeviceDescriptor
= NULL
;
414 // Clear the SrbFlags and disable synchronous transfers
417 fdoExtension
->SrbFlags
= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
420 // Finally, attach to the PDO
423 fdoExtension
->LowerPdo
= PhysicalDeviceObject
;
425 fdoExtension
->CommonExtension
.LowerDeviceObject
=
426 IoAttachDeviceToDeviceStack(deviceObject
, PhysicalDeviceObject
);
428 if(fdoExtension
->CommonExtension
.LowerDeviceObject
== NULL
) {
431 // Uh - oh, we couldn't attach
432 // cleanup and return
435 status
= STATUS_UNSUCCESSFUL
;
436 goto CreateCdRomDeviceObjectExit
;
440 // CdRom uses an extra stack location for synchronizing it's start io
444 deviceObject
->StackSize
++;
447 // cdData is used a few times below
450 cdData
= fdoExtension
->CommonExtension
.DriverData
;
453 // For NTMS to be able to easily determine drives-drv. letter matches.
456 status
= CdRomCreateWellKnownName( deviceObject
);
458 if (!NT_SUCCESS(status
)) {
459 TraceLog((CdromDebugWarning
,
460 "CdromCreateDeviceObjects: unable to create symbolic "
461 "link for device %wZ\n", &fdoExtension
->CommonExtension
.DeviceName
));
462 TraceLog((CdromDebugWarning
,
463 "CdromCreateDeviceObjects: (non-fatal error)\n"));
466 ClassUpdateInformationInRegistry(deviceObject
, "CdRom",
467 fdoExtension
->DeviceNumber
, NULL
, 0);
470 // from above IoGetAttachedDeviceReference
473 ObDereferenceObject(lowerDevice
);
476 // need to init timerlist here in case a remove occurs
477 // without a start, since we check the list is empty on remove.
480 cdData
->DelayedRetryIrp
= NULL
;
481 cdData
->DelayedRetryInterval
= 0;
484 // need this to be initialized for RPC Phase 1 drives (rpc0)
487 KeInitializeMutex(&cdData
->Rpc0RegionMutex
, 0);
490 // The device is initialized properly - mark it as such.
493 CLEAR_FLAG(deviceObject
->Flags
, DO_DEVICE_INITIALIZING
);
495 return(STATUS_SUCCESS
);
497 CreateCdRomDeviceObjectExit
:
500 // Release the device since an error occured.
503 // ClassClaimDevice(PortDeviceObject,
509 // from above IoGetAttachedDeviceReference
512 ObDereferenceObject(lowerDevice
);
514 if (deviceObject
!= NULL
) {
515 IoDeleteDevice(deviceObject
);
520 } // end CreateCdRomDeviceObject()
525 IN PDEVICE_OBJECT Fdo
532 This routine will complete the cd-rom initialization. This includes
533 allocating sense info buffers and srb s-lists, reading drive capacity
534 and setting up Media Change Notification (autorun).
536 This routine will not clean up allocate resources if it fails - that
537 is left for device stop/removal
541 Fdo - a pointer to the functional device object for this device
550 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
551 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
552 PCLASS_DRIVER_EXTENSION driverExtension
= ClassGetDriverExtension(
555 PVOID senseData
= NULL
;
558 PCDROM_DATA cddata
= NULL
;
560 BOOLEAN changerDevice
;
561 BOOLEAN isMmcDevice
= FALSE
;
572 // Build the lookaside list for srb's for the physical disk. Should only
576 ClassInitializeSrbLookasideList(&(fdoExtension
->CommonExtension
),
577 CDROM_SRB_LIST_SIZE
);
580 // Allocate request sense buffer.
583 senseData
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
585 CDROM_TAG_SENSE_INFO
);
587 if (senseData
== NULL
) {
590 // The buffer cannot be allocated.
593 status
= STATUS_INSUFFICIENT_RESOURCES
;
594 goto CdRomInitDeviceExit
;
598 // Set the sense data pointer in the device extension.
601 fdoExtension
->SenseData
= senseData
;
604 // CDROMs are not partitionable so starting offset is 0.
607 commonExtension
->StartingOffset
.LowPart
= 0;
608 commonExtension
->StartingOffset
.HighPart
= 0;
611 // Set timeout value in seconds.
614 timeOut
= ClassQueryTimeOutRegistryValue(Fdo
);
616 fdoExtension
->TimeOutValue
= timeOut
;
618 fdoExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
621 cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
624 // Set up media change support defaults.
627 KeInitializeSpinLock(&cddata
->DelayedRetrySpinLock
);
629 cddata
->DelayedRetryIrp
= NULL
;
630 cddata
->DelayedRetryInterval
= 0;
631 cddata
->Mmc
.WriteAllowed
= FALSE
;
634 // Scan for controllers that require special processing.
640 // Determine if the drive is MMC-Capable
643 CdRomIsDeviceMmcDevice(Fdo
, &isMmcDevice
);
647 SET_FLAG(Fdo
->Characteristics
, FILE_READ_ONLY_DEVICE
);
652 // the drive supports at least a subset of MMC commands
653 // (and therefore supports READ_CD, etc...)
656 cddata
->Mmc
.IsMmc
= TRUE
;
659 // allocate a buffer for all the capabilities and such
662 status
= CdRomAllocateMmcResources(Fdo
);
663 if (!NT_SUCCESS(status
)) {
664 goto CdRomInitDeviceExit
;
670 // determine all the various media types from the profiles feature
673 PFEATURE_DATA_PROFILE_LIST profileHeader
;
674 ULONG mediaTypes
= 0;
677 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
678 "Checking all profiles for media types supported.\n"
681 profileHeader
= CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
682 cddata
->Mmc
.CapabilitiesBufferSize
,
684 if (profileHeader
== NULL
) {
687 // if profiles don't exist, there is something seriously
688 // wrong with this command -- it's either not a cdrom or
689 // one that hasn't implemented the spec correctly. exit
690 // now while we have the chance to do so safely.
692 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
693 "CdromDevice supports GET_CONFIGURATION, but "
694 "doesn't provide profiles for PDO %p!\n",
695 fdoExtension
->LowerPdo
));
696 status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
697 goto CdRomInitDeviceExit
;
701 for (i
= 0; i
< MAX_CDROM_MEDIA_TYPES
; i
++) {
703 BOOLEAN profileFound
;
704 CdRomFindProfileInProfiles(profileHeader
,
705 MediaProfileMatch
[i
].Profile
,
709 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
710 "CdromInit -> Found Profile %x => Media %x "
712 MediaProfileMatch
[i
].Profile
,
713 MediaProfileMatch
[i
].Media
,
717 cddata
->Mmc
.MediaProfileMatches
[mediaTypes
] =
718 MediaProfileMatch
[i
];
725 if (mediaTypes
== 0) {
728 // if profiles don't exist, there is something seriously
729 // wrong with this command -- it's either not a cdrom or
730 // one that hasn't implemented the spec correctly. exit
731 // now while we have the chance to do so safely.
733 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
734 "CdromDevice supports GET_CONFIGURATION, but "
735 "doesn't support any of the standard profiles "
736 "for PDO %p!\n", fdoExtension
->LowerPdo
));
737 status
= STATUS_DEVICE_CONFIGURATION_ERROR
;
738 goto CdRomInitDeviceExit
;
742 cddata
->Mmc
.MediaTypes
= mediaTypes
;
746 #endif // media checks, and all failure paths due to bad firmware.
749 // if the drive supports target defect management and sector-addressable
750 // writes, then we should allow writes to the media.
753 if (CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
754 cddata
->Mmc
.CapabilitiesBufferSize
,
755 FeatureDefectManagement
) &&
756 CdRomFindFeaturePage(cddata
->Mmc
.CapabilitiesBuffer
,
757 cddata
->Mmc
.CapabilitiesBufferSize
,
758 FeatureRandomWritable
)) {
761 // the drive is target defect managed, and supports random writes
762 // on sector-aligment. allow writes to occur by setting the error
763 // handler to point to a private media change detection handler.
766 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
767 "Found a WRITE capable device: %p\n", Fdo
));
770 // the write specific pages have been found --
771 // set the error handler and set it to require an update!
774 cddata
->Mmc
.UpdateState
= CdromMmcUpdateRequired
;
775 cddata
->ErrorHandler
= CdRomMmcErrorHandler
;
780 // ISSUE-2000/4/4-henrygab - mmc-compliant compliant drives should
781 // be initialized based upon reported
782 // capabilities, such as CSS, Analogue Audio,
783 // READ_CD capabilities, and (possibly) even
784 // drive capacity information.
787 TraceLog((CdromDebugWarning
,
788 "Defaulting to READ_CD because device %p is MMC compliant\n",
790 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
791 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
797 // Set the default geometry for the cdrom to match what NT 4 used.
798 // Classpnp will use these values to compute the cylinder count rather
799 // than using it's NT 5.0 defaults.
802 fdoExtension
->DiskGeometry
.TracksPerCylinder
= 0x40;
803 fdoExtension
->DiskGeometry
.SectorsPerTrack
= 0x20;
806 // Do READ CAPACITY. This SCSI command returns the last sector address
807 // on the device and the bytes per sector. These are used to calculate
808 // the drive capacity in bytes.
810 // NOTE: This should be change to send the Srb synchronously, then
811 // call CdRomInterpretReadCapacity() to properly setup the defaults.
814 status
= ClassReadDriveCapacity(Fdo
);
816 bps
= fdoExtension
->DiskGeometry
.BytesPerSector
;
818 if (!NT_SUCCESS(status
) || !bps
) {
820 TraceLog((CdromDebugWarning
,
821 "CdRomStartDevice: Can't read capacity for device %wZ\n",
822 &(fdoExtension
->CommonExtension
.DeviceName
)));
825 // Set disk geometry to default values (per ISO 9660).
829 fdoExtension
->SectorShift
= 11;
830 commonExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
835 // Insure that bytes per sector is a power of 2
836 // This corrects a problem with the HP 4020i CDR where it
837 // returns an incorrect number for bytes per sector.
840 lastBit
= (ULONG
) -1;
848 fdoExtension
->DiskGeometry
.BytesPerSector
= bps
;
849 TraceLog((CdromDebugTrace
, "CdRomInitDevice: Calc'd bps = %x\n", bps
));
852 ClassInitializeMediaChangeDetection(fdoExtension
, "CdRom");
856 // test for audio read capabilities
859 TraceLog((CdromDebugWarning
,
860 "Detecting XA_READ capabilities\n"));
862 if (CdRomGetDeviceType(Fdo
) == FILE_DEVICE_DVD
) {
864 TraceLog((CdromDebugWarning
,
865 "CdRomInitDevice: DVD Devices require START_UNIT\n"));
869 // all DVD devices must support the READ_CD command
872 TraceLog((CdromDebugWarning
,
873 "CdRomDetermineRawReadCapabilities: DVD devices "
874 "support READ_CD command for FDO %p\n", Fdo
));
875 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
876 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
879 status
= STATUS_SUCCESS
;
881 } else if ((fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeScsi
) &&
882 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeAta
) &&
883 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeAtapi
) &&
884 (fdoExtension
->DeviceDescriptor
->BusType
!= BusTypeUnknown
)
888 // devices on the newer busses must support READ_CD command
891 TraceLog((CdromDebugWarning
,
892 "CdRomDetermineRawReadCapabilities: Devices for newer "
893 "busses must support READ_CD command for FDO %p, Bus %x\n",
894 Fdo
, fdoExtension
->DeviceDescriptor
->BusType
));
895 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
896 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
901 // now clear all our READ_CD flags if the drive should have supported
902 // it, but we are not sure it actually does. we still won't query
903 // the drive more than one time if it supports the command.
906 if (TEST_FLAG(cddata
->HackFlags
, CDROM_HACK_FORCE_READ_CD_DETECTION
)) {
908 TraceLog((CdromDebugWarning
,
909 "Forcing detection of READ_CD for FDO %p because "
910 "testing showed some firmware did not properly support it\n",
912 CLEAR_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
918 // read our READ_CD support in the registry if it was seeded.
921 ULONG readCdSupported
= 0;
923 ClassGetDeviceParameter(fdoExtension
,
929 if (readCdSupported
!= 0) {
931 TraceLog((CdromDebugWarning
,
932 "Defaulting to READ_CD because previously detected "
933 "that the device supports it for Fdo %p.\n",
936 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
944 // backwards-compatible hackish attempt to determine if the drive
945 // supports any method of reading digital audio from the disc.
948 if (!TEST_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
)) {
950 SCSI_REQUEST_BLOCK srb
;
953 PUCHAR buffer
= NULL
;
957 // ISSUE-2000/07/05-henrygab - use the mode page to determine
958 // READ_CD support, then fall back on the below
959 // (unreliable?) hack.
963 // Build the MODE SENSE CDB. The data returned will be kept in the
964 // device extension and used to set block size.
967 length
= max(sizeof(ERROR_RECOVERY_DATA
),sizeof(ERROR_RECOVERY_DATA10
));
969 buffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
971 CDROM_TAG_MODE_DATA
);
974 TraceLog((CdromDebugWarning
,
975 "CdRomDetermineRawReadCapabilities: cannot allocate "
976 "buffer, so leaving for FDO %p\n", Fdo
));
977 status
= STATUS_INSUFFICIENT_RESOURCES
;
978 goto CdRomInitDeviceExit
;
981 for (count
= 0; count
< 2; count
++) {
984 length
= sizeof(ERROR_RECOVERY_DATA
);
986 length
= sizeof(ERROR_RECOVERY_DATA10
);
989 RtlZeroMemory(buffer
, length
);
990 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
993 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
997 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
998 cdb
->MODE_SENSE
.PageCode
= 0x1;
999 // note: not setting DBD in order to get the block descriptor!
1000 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
1003 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
1004 cdb
->MODE_SENSE10
.PageCode
= 0x1;
1005 // note: not setting DBD in order to get the block descriptor!
1006 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(length
>> 8);
1007 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(length
& 0xFF);
1010 status
= ClassSendSrbSynchronous(Fdo
,
1017 if (NT_SUCCESS(status
) || (status
== STATUS_DATA_OVERRUN
)) {
1020 // STATUS_DATA_OVERRUN means it's a newer drive with more info
1021 // to tell us, so it's probably able to support READ_CD
1024 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
1027 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
1029 status
= ClassSendSrbSynchronous(Fdo
,
1035 if (NT_SUCCESS(status
) ||
1036 (status
== STATUS_NO_MEDIA_IN_DEVICE
) ||
1037 (status
== STATUS_NONEXISTENT_SECTOR
) ||
1038 (status
== STATUS_UNRECOGNIZED_MEDIA
)
1045 TraceLog((CdromDebugWarning
,
1046 "CdRomDetermineRawReadCapabilities: Using "
1047 "READ_CD for FDO %p due to status %x\n",
1050 SET_FLAG(cddata
->XAFlags
, XA_USE_READ_CD
);
1053 // ignore errors in saving this info
1056 ClassSetDeviceParameter(fdoExtension
,
1063 break; // out of the for loop
1067 TraceLog((CdromDebugWarning
,
1068 "CdRomDetermineRawReadCapabilities: Using "
1069 "%s-byte mode switching for FDO %p due to status "
1070 "%x returned for READ_CD\n",
1071 ((count
== 0) ? "6" : "10"), Fdo
, status
));
1074 SET_FLAG(cddata
->XAFlags
, XA_USE_6_BYTE
);
1075 RtlCopyMemory(&cddata
->Header
,
1077 sizeof(ERROR_RECOVERY_DATA
));
1078 cddata
->Header
.ModeDataLength
= 0;
1080 SET_FLAG(cddata
->XAFlags
, XA_USE_10_BYTE
);
1081 RtlCopyMemory(&cddata
->Header10
,
1083 sizeof(ERROR_RECOVERY_DATA10
));
1084 cddata
->Header10
.ModeDataLength
[0] = 0;
1085 cddata
->Header10
.ModeDataLength
[1] = 0;
1087 break; // out of for loop
1090 TraceLog((CdromDebugWarning
,
1091 "FDO %p failed %x byte mode sense, status %x\n",
1093 ((count
== 0) ? 6 : 10),
1098 // mode sense failed
1101 } // end of for loop to try 6 and 10-byte mode sense
1106 // nothing worked. we probably cannot support digital
1107 // audio extraction from this drive
1110 TraceLog((CdromDebugWarning
,
1111 "CdRomDetermineRawReadCapabilities: FDO %p "
1112 "cannot support READ_CD\n", Fdo
));
1113 CLEAR_FLAG(cddata
->XAFlags
, XA_PLEXTOR_CDDA
);
1114 CLEAR_FLAG(cddata
->XAFlags
, XA_NEC_CDDA
);
1115 SET_FLAG(cddata
->XAFlags
, XA_NOT_SUPPORTED
);
1117 } // end of count == 2
1120 // free our resources
1126 // set a successful status
1127 // (in case someone later checks this)
1130 status
= STATUS_SUCCESS
;
1135 // Register interfaces for this device.
1139 UNICODE_STRING interfaceName
;
1141 RtlInitUnicodeString(&interfaceName
, NULL
);
1143 status
= IoRegisterDeviceInterface(fdoExtension
->LowerPdo
,
1144 (LPGUID
) &CdRomClassGuid
,
1148 if(NT_SUCCESS(status
)) {
1150 cddata
->CdromInterfaceString
= interfaceName
;
1152 status
= IoSetDeviceInterfaceState(
1156 if(!NT_SUCCESS(status
)) {
1158 TraceLog((CdromDebugWarning
,
1159 "CdromInitDevice: Unable to register cdrom "
1160 "DCA for fdo %p [%lx]\n",
1166 return(STATUS_SUCCESS
);
1168 CdRomInitDeviceExit
:
1170 CdRomDeAllocateMmcResources(Fdo
);
1171 RtlZeroMemory(&(cddata
->Mmc
), sizeof(CDROM_MMC_EXTENSION
));
1180 IN PDEVICE_OBJECT Fdo
1184 Routine Description:
1186 This routine starts the timer for the cdrom
1190 Fdo - a pointer to the functional device object for this device
1199 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1200 PCDROM_DATA cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
1201 PDVD_COPY_PROTECT_KEY copyProtectKey
;
1202 PDVD_RPC_KEY rpcKey
;
1203 IO_STATUS_BLOCK ioStatus
;
1206 // CdRomCreateWellKnownName(Fdo);
1209 // if we have a DVD-ROM
1210 // if we have a rpc0 device
1211 // fake a rpc2 device
1212 // if device does not have a dvd region set
1213 // select a dvd region for the user
1216 cddata
->DvdRpc0Device
= FALSE
;
1219 // since StartIo() will call IoStartNextPacket() on error, allowing
1220 // StartIo() to be non-recursive prevents stack overflow bugchecks in
1221 // severe error cases (such as fault-injection in the verifier).
1223 // the only difference is that the thread context may be different
1224 // in StartIo() than in the caller of IoStartNextPacket().
1227 IoSetStartIoAttributes(Fdo
, TRUE
, TRUE
);
1230 // check to see if we have a DVD device
1233 if (CdRomGetDeviceType(Fdo
) != FILE_DEVICE_DVD
) {
1234 return STATUS_SUCCESS
;
1238 // we got a DVD drive.
1239 // now, figure out if we have a RPC0 device
1242 bufferLen
= DVD_RPC_KEY_LENGTH
;
1244 (PDVD_COPY_PROTECT_KEY
)ExAllocatePoolWithTag(PagedPool
,
1246 DVD_TAG_RPC2_CHECK
);
1248 if (copyProtectKey
== NULL
) {
1249 return STATUS_INSUFFICIENT_RESOURCES
;
1253 // get the device region
1255 RtlZeroMemory (copyProtectKey
, bufferLen
);
1256 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
1257 copyProtectKey
->KeyType
= DvdGetRpcKey
;
1260 // Build a request for READ_KEY
1262 ClassSendDeviceIoControlSynchronous(
1272 if (!NT_SUCCESS(ioStatus
.Status
)) {
1275 // we have a rpc0 device
1277 // NOTE: THIS MODIFIES THE BEHAVIOR OF THE IOCTL
1280 cddata
->DvdRpc0Device
= TRUE
;
1282 TraceLog((CdromDebugWarning
,
1283 "CdromStartDevice (%p): RPC Phase 1 drive detected\n",
1287 // note: we could force this chosen now, but it's better to reduce
1288 // the number of code paths that could be taken. always delay to
1289 // increase the percentage code coverage.
1292 TraceLog((CdromDebugWarning
,
1293 "CdromStartDevice (%p): Delay DVD Region Selection\n",
1296 cddata
->Rpc0SystemRegion
= 0xff;
1297 cddata
->Rpc0SystemRegionResetCount
= DVD_MAX_REGION_RESET_COUNT
;
1298 cddata
->PickDvdRegion
= 1;
1299 cddata
->Rpc0RetryRegistryCallback
= 1;
1300 ExFreePool(copyProtectKey
);
1301 return STATUS_SUCCESS
;
1305 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
1308 // TypeCode of zero means that no region has been set.
1311 if (rpcKey
->TypeCode
== 0) {
1312 TraceLog((CdromDebugWarning
,
1313 "CdromStartDevice (%p): must choose DVD region\n",
1315 cddata
->PickDvdRegion
= 1;
1316 CdRomPickDvdRegion(Fdo
);
1320 ExFreePool (copyProtectKey
);
1322 return STATUS_SUCCESS
;
1328 IN PDEVICE_OBJECT DeviceObject
,
1332 return STATUS_SUCCESS
;
1338 IN PDEVICE_OBJECT Fdo
,
1343 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
1344 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
1346 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1347 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(Irp
);
1348 PIO_STACK_LOCATION irpStack
;
1352 ULONG transferPages
;
1353 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
1354 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
1356 PSCSI_REQUEST_BLOCK srb
= NULL
;
1358 PUCHAR senseBuffer
= NULL
;
1364 // Mark IRP with status pending.
1367 IoMarkIrpPending(Irp
);
1369 cdData
= (PCDROM_DATA
)(fdoExtension
->CommonExtension
.DriverData
);
1370 use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
1373 // if this test is true, then we will exit the routine within this
1374 // code block, queueing the irp for later completion.
1377 if ((cdData
->Mmc
.IsMmc
) &&
1378 (cdData
->Mmc
.UpdateState
!= CdromMmcUpdateComplete
)
1382 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
1383 "CdRomStartIo: [%p] Device needs to update capabilities\n",
1385 ASSERT(cdData
->Mmc
.IsMmc
);
1386 ASSERT(cdData
->Mmc
.CapabilitiesIrp
!= NULL
);
1387 ASSERT(cdData
->Mmc
.CapabilitiesIrp
!= Irp
);
1392 // the state was either UpdateRequired (which means we will
1393 // have to start the work item) or UpdateStarted (which means
1394 // we have already started the work item at least once -- may
1395 // transparently change to UpdateComplete).
1397 // if it's update required, we just queue it, change to UpdateStarted,
1398 // start the workitem, and start the next packet.
1400 // else, we must queue the item and check the queue depth. if the
1401 // queue depth is equal to 1, that means the worker item from the
1402 // previous attempt has already de-queued the items, so we should
1403 // call this routine again (retry) as an optimization rather than
1404 // re-add it this irp to the queue. since this is tail recursion,
1405 // it won't take much/any stack to do this.
1407 // NOTE: This presumes the following items are true:
1409 // we only add to the list from CdRomStartIo(), which is serialized.
1410 // we only set to UpdateStarted from CdRomStartIo(), and only if
1411 // the state was UpdateRequired.
1412 // we only set to UpdateRequired from CdRomMmcErrorHandler(), and
1413 // only if the state was UpdateComplete.
1414 // we only set to UpdateComplete from the workitem, and assert the
1415 // state was UpdateStarted.
1416 // we flush the entire queue in one atomic operation in the workitem,
1417 // except in the special case described above when we dequeue
1418 // the request immediately.
1420 // order of operations is vitally important: queue, then test the depth
1421 // this will prevent lost irps.
1424 ExInterlockedPushEntrySList(&(cdData
->Mmc
.DelayedIrps
),
1425 (PSINGLE_LIST_ENTRY
)&(Irp
->Tail
.Overlay
.DriverContext
[0]),
1426 &(cdData
->Mmc
.DelayedLock
));
1428 queueDepth
= ExQueryDepthSList(&(cdData
->Mmc
.DelayedIrps
));
1429 if (queueDepth
== 1) {
1431 if (cdData
->Mmc
.UpdateState
== CdromMmcUpdateRequired
) {
1435 // should free any old partition list info that
1436 // we've previously saved away and then start the WorkItem
1439 oldState
= InterlockedExchange(&cdData
->Mmc
.UpdateState
,
1440 CdromMmcUpdateStarted
);
1441 ASSERT(oldState
== CdromMmcUpdateRequired
);
1443 IoQueueWorkItem(cdData
->Mmc
.CapabilitiesWorkItem
,
1444 CdRomUpdateMmcDriveCapabilities
,
1451 // they *just* finished updating, so we should flush the list
1452 // back onto the StartIo queue and start the next packet.
1455 CdRompFlushDelayedList(Fdo
, &(cdData
->Mmc
), STATUS_SUCCESS
, FALSE
);
1462 // start the next packet so we don't deadlock....
1465 IoStartNextPacket(Fdo
, FALSE
);
1471 // If the flag is set in the device object
1472 // force a verify for READ, WRITE and RAW_READ requests
1473 // Note that ioctls are passed through....
1476 if (TEST_FLAG(Fdo
->Flags
, DO_VERIFY_VOLUME
) &&
1477 IS_READ_WRITE_REQUEST(currentIrpStack
)) {
1479 TraceLog((CdromDebugTrace
,
1480 "CdRomStartIo: [%p] Volume needs verified\n", Irp
));
1482 if (!(currentIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
)) {
1484 if (Irp
->Tail
.Overlay
.Thread
) {
1485 IoSetHardErrorOrVerifyDevice(Irp
, Fdo
);
1488 Irp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
1490 TraceLog((CdromDebugTrace
,
1491 "CdRomStartIo: [%p] Calling UpdateCapcity - "
1492 "ioctl event = %p\n",
1494 nextIrpStack
->Parameters
.Others
.Argument1
1498 // our device control dispatch routine stores an event in the next
1499 // stack location to signal when startio has completed. We need to
1500 // pass this in so that the update capacity completion routine can
1501 // set it rather than completing the Irp.
1504 status
= CdRomUpdateCapacity(fdoExtension
,
1506 nextIrpStack
->Parameters
.Others
.Argument1
1509 TraceLog((CdromDebugTrace
,
1510 "CdRomStartIo: [%p] UpdateCapacity returned %lx\n",
1517 // fail writes if they are not allowed...
1520 if ((currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) &&
1521 !(cdData
->Mmc
.WriteAllowed
)) {
1523 TraceLog((CdromDebugError
,
1524 "CdRomStartIo: [%p] Device %p failing write request\n",
1527 Irp
->IoStatus
.Information
= 0;
1528 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1530 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1534 if (currentIrpStack
->MajorFunction
== IRP_MJ_READ
||
1535 currentIrpStack
->MajorFunction
== IRP_MJ_WRITE
) {
1537 ULONG maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
1540 // Add partition byte offset to make starting byte relative to
1541 // beginning of disk.
1544 currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+=
1545 (fdoExtension
->CommonExtension
.StartingOffset
.QuadPart
);
1548 // Calculate number of pages in this transfer.
1551 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1552 currentIrpStack
->Parameters
.Read
.Length
);
1555 // Check if request length is greater than the maximum number of
1556 // bytes that the hardware can transfer.
1559 if (cdData
->RawAccess
) {
1562 // a writable device must be MMC compliant, which supports
1563 // READ_CD commands.
1566 ASSERT(currentIrpStack
->MajorFunction
!= IRP_MJ_WRITE
);
1568 ASSERT(!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
));
1571 // Fire off a mode select to switch back to cooked sectors.
1574 irp2
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1), FALSE
);
1577 Irp
->IoStatus
.Information
= 0;
1578 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1581 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1585 srb
= ExAllocatePoolWithTag(NonPagedPool
,
1586 sizeof(SCSI_REQUEST_BLOCK
),
1590 Irp
->IoStatus
.Information
= 0;
1591 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1594 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1598 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1600 cdb
= (PCDB
)srb
->Cdb
;
1603 // Allocate sense buffer.
1606 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1608 CDROM_TAG_SENSE_INFO
);
1613 Irp
->IoStatus
.Information
= 0;
1614 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1617 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1625 IoSetNextIrpStackLocation(irp2
);
1626 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1627 irp2
->IoStatus
.Information
= 0;
1629 irp2
->UserBuffer
= NULL
;
1632 // Save the device object and irp in a private stack location.
1635 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1636 irpStack
->DeviceObject
= Fdo
;
1637 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1640 // The retry count will be in the real Irp, as the retry logic will
1641 // recreate our private irp.
1644 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1647 // Only jam this in if it doesn't exist. The completion routines can
1648 // call StartIo directly in the case of retries and resetting it will
1649 // cause infinite loops.
1652 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1656 // Construct the IRP stack for the lower level driver.
1659 irpStack
= IoGetNextIrpStackLocation(irp2
);
1660 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1661 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1662 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1664 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1665 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1666 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1668 srb
->OriginalRequest
= irp2
;
1669 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1670 srb
->SenseInfoBuffer
= senseBuffer
;
1672 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
1674 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1679 ExFreePool(senseBuffer
);
1682 Irp
->IoStatus
.Information
= 0;
1683 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1686 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1691 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
1697 if (!irp2
->MdlAddress
) {
1698 ExFreePool(senseBuffer
);
1700 ExFreePool(dataBuffer
);
1702 Irp
->IoStatus
.Information
= 0;
1703 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1706 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1714 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
1716 srb
->DataBuffer
= dataBuffer
;
1719 // Set the new block size in the descriptor.
1723 cdData
->BlockDescriptor
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1724 cdData
->BlockDescriptor
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1725 cdData
->BlockDescriptor
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1727 cdData
->BlockDescriptor10
.BlockLength
[0] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 16) & 0xFF;
1728 cdData
->BlockDescriptor10
.BlockLength
[1] = (UCHAR
)(COOKED_SECTOR_SIZE
>> 8) & 0xFF;
1729 cdData
->BlockDescriptor10
.BlockLength
[2] = (UCHAR
)(COOKED_SECTOR_SIZE
& 0xFF);
1733 // Move error page into dataBuffer.
1736 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, transferByteCount
);
1739 // Build and send a mode select to switch into raw mode.
1742 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
1743 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
1744 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
1745 srb
->DataTransferLength
= transferByteCount
;
1746 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
1750 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
1751 cdb
->MODE_SELECT
.PFBit
= 1;
1752 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
1754 srb
->CdbLength
= 10;
1755 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
1756 cdb
->MODE_SELECT10
.PFBit
= 1;
1757 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
1758 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
1762 // Update completion routine.
1765 IoSetCompletionRoutine(irp2
,
1766 CdRomSwitchModeCompletion
,
1772 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
1778 // Request needs to be split. Completion of each portion of the
1779 // request will fire off the next portion. The final request will
1780 // signal Io to send a new request.
1784 fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
- 1;
1786 if(maximumTransferLength
> (transferPages
<< PAGE_SHIFT
)) {
1787 maximumTransferLength
= transferPages
<< PAGE_SHIFT
;
1791 // Check that the maximum transfer size is not zero
1794 if(maximumTransferLength
== 0) {
1795 maximumTransferLength
= PAGE_SIZE
;
1798 ClassSplitRequest(Fdo
, Irp
, maximumTransferLength
);
1801 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_DEVICE_CONTROL
) {
1804 // Allocate an irp, srb and associated structures.
1807 irp2
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1),
1811 Irp
->IoStatus
.Information
= 0;
1812 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1815 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1819 srb
= ExAllocatePoolWithTag(NonPagedPool
,
1820 sizeof(SCSI_REQUEST_BLOCK
),
1824 Irp
->IoStatus
.Information
= 0;
1825 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1828 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1832 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
1834 cdb
= (PCDB
)srb
->Cdb
;
1837 // Allocate sense buffer.
1840 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
1842 CDROM_TAG_SENSE_INFO
);
1847 Irp
->IoStatus
.Information
= 0;
1848 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
1851 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1855 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
1861 IoSetNextIrpStackLocation(irp2
);
1862 irp2
->IoStatus
.Status
= STATUS_SUCCESS
;
1863 irp2
->IoStatus
.Information
= 0;
1865 irp2
->UserBuffer
= NULL
;
1868 // Save the device object and irp in a private stack location.
1871 irpStack
= IoGetCurrentIrpStackLocation(irp2
);
1872 irpStack
->DeviceObject
= Fdo
;
1873 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) Irp
;
1876 // The retry count will be in the real Irp, as the retry logic will
1877 // recreate our private irp.
1880 if (!(nextIrpStack
->Parameters
.Others
.Argument1
)) {
1883 // Only jam this in if it doesn't exist. The completion routines can
1884 // call StartIo directly in the case of retries and resetting it will
1885 // cause infinite loops.
1888 nextIrpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
1892 // keep track of the new irp as Argument3
1895 nextIrpStack
->Parameters
.Others
.Argument3
= irp2
;
1899 // Construct the IRP stack for the lower level driver.
1902 irpStack
= IoGetNextIrpStackLocation(irp2
);
1903 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
1904 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
1905 irpStack
->Parameters
.Scsi
.Srb
= srb
;
1907 IoSetCompletionRoutine(irp2
,
1908 CdRomDeviceControlCompletion
,
1914 // Setup those fields that are generic to all requests.
1917 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
1918 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1919 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
1921 srb
->OriginalRequest
= irp2
;
1922 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
1923 srb
->SenseInfoBuffer
= senseBuffer
;
1925 switch (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
) {
1928 case IOCTL_CDROM_RAW_READ
: {
1931 // Determine whether the drive is currently in raw or cooked mode,
1932 // and which command to use to read the data.
1935 if (!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
)) {
1937 PRAW_READ_INFO rawReadInfo
=
1938 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1939 ULONG maximumTransferLength
;
1940 ULONG transferPages
;
1942 if (cdData
->RawAccess
) {
1944 ULONG startingSector
;
1945 UCHAR min
, sec
, frame
;
1948 // Free the recently allocated irp, as we don't need it.
1953 cdb
= (PCDB
)srb
->Cdb
;
1954 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
1957 // Calculate starting offset.
1960 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
1961 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
1962 maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
1963 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp
->MdlAddress
),
1967 // Determine if request is within limits imposed by miniport.
1969 if (transferByteCount
> maximumTransferLength
||
1970 transferPages
> fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
) {
1973 // The claim is that this won't happen, and is backed up by
1974 // ActiveMovie usage, which does unbuffered XA reads of 0x18000, yet
1975 // we get only 4 sector requests.
1978 ExFreePool(senseBuffer
);
1981 Irp
->IoStatus
.Information
= 0;
1982 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
1985 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
1990 srb
->OriginalRequest
= Irp
;
1991 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
1992 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
1993 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
1994 srb
->DataTransferLength
= transferByteCount
;
1995 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
1996 srb
->CdbLength
= 10;
1997 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
1999 if (rawReadInfo
->TrackMode
== CDDA
) {
2000 if (TEST_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
)) {
2002 srb
->CdbLength
= 12;
2004 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
2005 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
2006 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
2007 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
2009 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2010 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2011 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
2012 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
2014 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
2015 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
2017 } else if (TEST_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
)) {
2019 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
2020 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
2021 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
2022 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
2024 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2025 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2027 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
2031 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
2032 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2034 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
2035 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
2036 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
2037 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
2039 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
2042 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2044 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2045 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2047 // HACKHACK - REF #0001
2050 // Set up IoCompletion routine address.
2053 IoSetCompletionRoutine(Irp
,
2060 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, Irp
);
2065 transferByteCount
= (use6Byte
) ? sizeof(ERROR_RECOVERY_DATA
) : sizeof(ERROR_RECOVERY_DATA10
);
2066 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2070 ExFreePool(senseBuffer
);
2073 Irp
->IoStatus
.Information
= 0;
2074 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2077 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2082 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2088 if (!irp2
->MdlAddress
) {
2089 ExFreePool(senseBuffer
);
2091 ExFreePool(dataBuffer
);
2093 Irp
->IoStatus
.Information
= 0;
2094 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2097 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2105 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2107 srb
->DataBuffer
= dataBuffer
;
2110 // Set the new block size in the descriptor.
2111 // This will set the block read size to RAW_SECTOR_SIZE
2112 // TODO: Set density code, based on operation
2116 cdData
->BlockDescriptor
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2117 cdData
->BlockDescriptor
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2118 cdData
->BlockDescriptor
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2119 cdData
->BlockDescriptor
.DensityCode
= 0;
2121 cdData
->BlockDescriptor10
.BlockLength
[0] = (UCHAR
)(RAW_SECTOR_SIZE
>> 16) & 0xFF;
2122 cdData
->BlockDescriptor10
.BlockLength
[1] = (UCHAR
)(RAW_SECTOR_SIZE
>> 8) & 0xFF;
2123 cdData
->BlockDescriptor10
.BlockLength
[2] = (UCHAR
)(RAW_SECTOR_SIZE
& 0xFF);
2124 cdData
->BlockDescriptor10
.DensityCode
= 0;
2128 // Move error page into dataBuffer.
2131 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, transferByteCount
);
2135 // Build and send a mode select to switch into raw mode.
2138 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2139 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2140 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
2141 srb
->DataTransferLength
= transferByteCount
;
2142 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
2146 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
2147 cdb
->MODE_SELECT
.PFBit
= 1;
2148 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)transferByteCount
;
2151 srb
->CdbLength
= 10;
2152 cdb
->MODE_SELECT10
.OperationCode
= SCSIOP_MODE_SELECT10
;
2153 cdb
->MODE_SELECT10
.PFBit
= 1;
2154 cdb
->MODE_SELECT10
.ParameterListLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2155 cdb
->MODE_SELECT10
.ParameterListLength
[1] = (UCHAR
)(transferByteCount
& 0xFF);
2159 // Update completion routine.
2162 IoSetCompletionRoutine(irp2
,
2163 CdRomSwitchModeCompletion
,
2173 PRAW_READ_INFO rawReadInfo
=
2174 (PRAW_READ_INFO
)currentIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
2175 ULONG startingSector
;
2178 // Free the recently allocated irp, as we don't need it.
2183 cdb
= (PCDB
)srb
->Cdb
;
2184 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
2188 // Calculate starting offset.
2191 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
2192 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
2194 srb
->OriginalRequest
= Irp
;
2195 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2196 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2197 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2198 srb
->DataTransferLength
= transferByteCount
;
2199 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2200 srb
->DataBuffer
= MmGetMdlVirtualAddress(Irp
->MdlAddress
);
2201 srb
->CdbLength
= 12;
2202 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
2205 // Fill in CDB fields.
2208 cdb
= (PCDB
)srb
->Cdb
;
2211 cdb
->READ_CD
.TransferBlocks
[2] = (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
2212 cdb
->READ_CD
.TransferBlocks
[1] = (UCHAR
) (rawReadInfo
->SectorCount
>> 8 );
2213 cdb
->READ_CD
.TransferBlocks
[0] = (UCHAR
) (rawReadInfo
->SectorCount
>> 16);
2216 cdb
->READ_CD
.StartingLBA
[3] = (UCHAR
) (startingSector
& 0xFF);
2217 cdb
->READ_CD
.StartingLBA
[2] = (UCHAR
) ((startingSector
>> 8));
2218 cdb
->READ_CD
.StartingLBA
[1] = (UCHAR
) ((startingSector
>> 16));
2219 cdb
->READ_CD
.StartingLBA
[0] = (UCHAR
) ((startingSector
>> 24));
2222 // Setup cdb depending upon the sector type we want.
2225 switch (rawReadInfo
->TrackMode
) {
2228 cdb
->READ_CD
.ExpectedSectorType
= CD_DA_SECTOR
;
2229 cdb
->READ_CD
.IncludeUserData
= 1;
2230 cdb
->READ_CD
.HeaderCode
= 3;
2231 cdb
->READ_CD
.IncludeSyncData
= 1;
2236 cdb
->READ_CD
.ExpectedSectorType
= YELLOW_MODE2_SECTOR
;
2237 cdb
->READ_CD
.IncludeUserData
= 1;
2238 cdb
->READ_CD
.HeaderCode
= 1;
2239 cdb
->READ_CD
.IncludeSyncData
= 1;
2244 cdb
->READ_CD
.ExpectedSectorType
= FORM2_MODE2_SECTOR
;
2245 cdb
->READ_CD
.IncludeUserData
= 1;
2246 cdb
->READ_CD
.HeaderCode
= 3;
2247 cdb
->READ_CD
.IncludeSyncData
= 1;
2251 ExFreePool(senseBuffer
);
2253 Irp
->IoStatus
.Information
= 0;
2254 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
2257 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2261 cdb
->READ_CD
.OperationCode
= SCSIOP_READ_CD
;
2263 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
2264 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
2266 // HACKHACK - REF #0001
2269 // Set up IoCompletion routine address.
2272 IoSetCompletionRoutine(Irp
,
2279 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, Irp
);
2284 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2289 // the _EX version does the same thing on the front end
2292 case IOCTL_DISK_GET_LENGTH_INFO
:
2293 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
2294 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
2295 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
:
2296 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
: {
2299 // Issue ReadCapacity to update device extension
2300 // with information for current media.
2303 TraceLog((CdromDebugError
,
2304 "CdRomStartIo: Get drive geometry/length "
2305 "info (%p)\n", Irp
));
2308 // setup remaining srb and cdb parameters.
2311 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2312 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2313 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2314 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
2315 srb
->CdbLength
= 10;
2316 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2318 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2319 sizeof(READ_CAPACITY_DATA
),
2320 CDROM_TAG_READ_CAP
);
2322 ExFreePool(senseBuffer
);
2325 Irp
->IoStatus
.Information
= 0;
2326 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2329 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2334 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2335 sizeof(READ_CAPACITY_DATA
),
2340 if (!irp2
->MdlAddress
) {
2341 ExFreePool(senseBuffer
);
2343 ExFreePool(dataBuffer
);
2345 Irp
->IoStatus
.Information
= 0;
2346 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2349 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2357 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2359 srb
->DataBuffer
= dataBuffer
;
2360 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
2362 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2366 case IOCTL_CDROM_GET_CONFIGURATION
: {
2368 PGET_CONFIGURATION_IOCTL_INPUT inputBuffer
;
2370 TraceLog((CdromDebugError
,
2371 "CdRomStartIo: Get configuration (%p)\n", Irp
));
2373 if (!cdData
->Mmc
.IsMmc
) {
2374 ExFreePool(senseBuffer
);
2377 Irp
->IoStatus
.Information
= 0;
2378 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
2380 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2384 transferByteCount
= currentIrpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
2386 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2388 CDROM_TAG_GET_CONFIG
);
2390 ExFreePool(senseBuffer
);
2393 Irp
->IoStatus
.Information
= 0;
2394 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2396 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2400 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2405 if (!irp2
->MdlAddress
) {
2406 ExFreePool(dataBuffer
);
2407 ExFreePool(senseBuffer
);
2410 Irp
->IoStatus
.Information
= 0;
2411 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2413 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2417 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2420 // setup remaining srb and cdb parameters
2423 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2424 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2425 srb
->DataTransferLength
= transferByteCount
;
2426 srb
->CdbLength
= 10;
2427 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2428 srb
->DataBuffer
= dataBuffer
;
2430 cdb
->GET_CONFIGURATION
.OperationCode
= SCSIOP_GET_CONFIGURATION
;
2431 cdb
->GET_CONFIGURATION
.AllocationLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2432 cdb
->GET_CONFIGURATION
.AllocationLength
[1] = (UCHAR
)(transferByteCount
& 0xff);
2434 inputBuffer
= (PGET_CONFIGURATION_IOCTL_INPUT
)Irp
->AssociatedIrp
.SystemBuffer
;
2435 cdb
->GET_CONFIGURATION
.StartingFeature
[0] = (UCHAR
)(inputBuffer
->Feature
>> 8);
2436 cdb
->GET_CONFIGURATION
.StartingFeature
[1] = (UCHAR
)(inputBuffer
->Feature
& 0xff);
2437 cdb
->GET_CONFIGURATION
.RequestType
= (UCHAR
)(inputBuffer
->RequestType
);
2439 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2443 case IOCTL_DISK_VERIFY
: {
2445 PVERIFY_INFORMATION verifyInfo
= Irp
->AssociatedIrp
.SystemBuffer
;
2446 LARGE_INTEGER byteOffset
;
2450 if (!cdData
->Mmc
.WriteAllowed
) {
2451 ExFreePool(senseBuffer
);
2454 Irp
->IoStatus
.Information
= 0;
2455 Irp
->IoStatus
.Status
= STATUS_MEDIA_WRITE_PROTECTED
;
2457 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2464 srb
->CdbLength
= 10;
2466 cdb
->CDB10
.OperationCode
= SCSIOP_VERIFY
;
2469 // Add disk offset to starting sector.
2472 byteOffset
.QuadPart
= commonExtension
->StartingOffset
.QuadPart
+
2473 verifyInfo
->StartingOffset
.QuadPart
;
2476 // Convert byte offset to sector offset.
2479 sectorOffset
= (ULONG
)(byteOffset
.QuadPart
>> fdoExtension
->SectorShift
);
2482 // Convert ULONG byte count to USHORT sector count.
2485 sectorCount
= (USHORT
)(verifyInfo
->Length
>> fdoExtension
->SectorShift
);
2488 // Move little endian values into CDB in big endian format.
2491 cdb
->CDB10
.LogicalBlockByte0
= ((PFOUR_BYTE
)§orOffset
)->Byte3
;
2492 cdb
->CDB10
.LogicalBlockByte1
= ((PFOUR_BYTE
)§orOffset
)->Byte2
;
2493 cdb
->CDB10
.LogicalBlockByte2
= ((PFOUR_BYTE
)§orOffset
)->Byte1
;
2494 cdb
->CDB10
.LogicalBlockByte3
= ((PFOUR_BYTE
)§orOffset
)->Byte0
;
2496 cdb
->CDB10
.TransferBlocksMsb
= ((PFOUR_BYTE
)§orCount
)->Byte1
;
2497 cdb
->CDB10
.TransferBlocksLsb
= ((PFOUR_BYTE
)§orCount
)->Byte0
;
2500 // The verify command is used by the NT FORMAT utility and
2501 // requests are sent down for 5% of the volume size. The
2502 // request timeout value is calculated based on the number of
2503 // sectors verified.
2506 srb
->TimeOutValue
= ((sectorCount
+ 0x7F) >> 7) *
2507 fdoExtension
->TimeOutValue
;
2509 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2513 case IOCTL_STORAGE_CHECK_VERIFY
:
2514 case IOCTL_DISK_CHECK_VERIFY
:
2515 case IOCTL_CDROM_CHECK_VERIFY
: {
2518 // Since a test unit ready is about to be performed, reset the
2519 // timer value to decrease the opportunities for it to race with
2523 ClassResetMediaChangeTimer(fdoExtension
);
2526 // Set up the SRB/CDB
2530 cdb
->CDB6GENERIC
.OperationCode
= SCSIOP_TEST_UNIT_READY
;
2531 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 2;
2532 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2533 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2534 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2537 TraceLog((CdromDebugTrace
,
2538 "CdRomStartIo: [%p] Sending CHECK_VERIFY irp %p\n",
2540 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2544 case IOCTL_DVD_READ_STRUCTURE
: {
2546 CdRomDeviceControlDvdReadStructure(Fdo
, Irp
, irp2
, srb
);
2551 case IOCTL_DVD_END_SESSION
: {
2552 CdRomDeviceControlDvdEndSession(Fdo
, Irp
, irp2
, srb
);
2556 case IOCTL_DVD_START_SESSION
:
2557 case IOCTL_DVD_READ_KEY
: {
2559 CdRomDeviceControlDvdStartSessionReadKey(Fdo
, Irp
, irp2
, srb
);
2565 case IOCTL_DVD_SEND_KEY
:
2566 case IOCTL_DVD_SEND_KEY2
: {
2568 CdRomDeviceControlDvdSendKey (Fdo
, Irp
, irp2
, srb
);
2574 case IOCTL_CDROM_READ_TOC_EX
: {
2576 PCDROM_READ_TOC_EX inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2578 transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
2580 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2584 ExFreePool(senseBuffer
);
2587 Irp
->IoStatus
.Information
= 0;
2588 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2591 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2596 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2602 if (!irp2
->MdlAddress
) {
2603 ExFreePool(senseBuffer
);
2605 ExFreePool(dataBuffer
);
2607 Irp
->IoStatus
.Information
= 0;
2608 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2611 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2616 // setup the request per user request
2617 // do validity checking in devctl dispatch, not here
2620 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2621 cdb
->READ_TOC
.Msf
= inputBuffer
->Msf
;
2622 cdb
->READ_TOC
.Format2
= inputBuffer
->Format
;
2623 cdb
->READ_TOC
.StartingTrack
= inputBuffer
->SessionTrack
;
2624 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
)(transferByteCount
>> 8);
2625 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
)(transferByteCount
& 0xff);
2631 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2634 // do the standard stuff....
2637 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2638 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2639 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2640 srb
->DataTransferLength
= transferByteCount
;
2641 srb
->CdbLength
= 10;
2642 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2643 srb
->DataBuffer
= dataBuffer
;
2645 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2649 case IOCTL_CDROM_GET_LAST_SESSION
:
2650 case IOCTL_CDROM_READ_TOC
: {
2652 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
==
2653 IOCTL_CDROM_GET_LAST_SESSION
) {
2656 // Set format to return first and last session numbers.
2659 cdb
->READ_TOC
.Format
= CDROM_READ_TOC_EX_FORMAT_SESSION
;
2664 // Use MSF addressing
2667 cdb
->READ_TOC
.Msf
= 1;
2673 currentIrpStack
->Parameters
.Read
.Length
>
2674 sizeof(CDROM_TOC
) ? sizeof(CDROM_TOC
):
2675 currentIrpStack
->Parameters
.Read
.Length
;
2678 // Set size of TOC structure.
2681 cdb
->READ_TOC
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2682 cdb
->READ_TOC
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2685 // setup remaining srb and cdb parameters.
2688 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2689 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2690 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2691 srb
->DataTransferLength
= transferByteCount
;
2692 srb
->CdbLength
= 10;
2693 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2695 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2699 ExFreePool(senseBuffer
);
2702 Irp
->IoStatus
.Information
= 0;
2703 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2706 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2711 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2717 if (!irp2
->MdlAddress
) {
2718 ExFreePool(senseBuffer
);
2720 ExFreePool(dataBuffer
);
2722 Irp
->IoStatus
.Information
= 0;
2723 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2726 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2734 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2736 srb
->DataBuffer
= dataBuffer
;
2737 cdb
->READ_TOC
.OperationCode
= SCSIOP_READ_TOC
;
2739 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2744 case IOCTL_CDROM_PLAY_AUDIO_MSF
: {
2746 PCDROM_PLAY_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2749 // Set up the SRB/CDB
2752 srb
->CdbLength
= 10;
2753 cdb
->PLAY_AUDIO_MSF
.OperationCode
= SCSIOP_PLAY_AUDIO_MSF
;
2755 cdb
->PLAY_AUDIO_MSF
.StartingM
= inputBuffer
->StartingM
;
2756 cdb
->PLAY_AUDIO_MSF
.StartingS
= inputBuffer
->StartingS
;
2757 cdb
->PLAY_AUDIO_MSF
.StartingF
= inputBuffer
->StartingF
;
2759 cdb
->PLAY_AUDIO_MSF
.EndingM
= inputBuffer
->EndingM
;
2760 cdb
->PLAY_AUDIO_MSF
.EndingS
= inputBuffer
->EndingS
;
2761 cdb
->PLAY_AUDIO_MSF
.EndingF
= inputBuffer
->EndingF
;
2763 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2764 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2765 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2766 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2768 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2773 case IOCTL_CDROM_READ_Q_CHANNEL
: {
2775 PSUB_Q_CHANNEL_DATA userChannelData
=
2776 Irp
->AssociatedIrp
.SystemBuffer
;
2777 PCDROM_SUB_Q_DATA_FORMAT inputBuffer
=
2778 Irp
->AssociatedIrp
.SystemBuffer
;
2781 // Allocate buffer for subq channel information.
2784 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2785 sizeof(SUB_Q_CHANNEL_DATA
),
2789 ExFreePool(senseBuffer
);
2792 Irp
->IoStatus
.Information
= 0;
2793 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2796 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2801 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2802 sizeof(SUB_Q_CHANNEL_DATA
),
2807 if (!irp2
->MdlAddress
) {
2808 ExFreePool(senseBuffer
);
2810 ExFreePool(dataBuffer
);
2812 Irp
->IoStatus
.Information
= 0;
2813 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2816 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2824 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
2826 srb
->DataBuffer
= dataBuffer
;
2829 // Always logical unit 0, but only use MSF addressing
2830 // for IOCTL_CDROM_CURRENT_POSITION
2833 if (inputBuffer
->Format
==IOCTL_CDROM_CURRENT_POSITION
)
2834 cdb
->SUBCHANNEL
.Msf
= CDB_USE_MSF
;
2837 // Return subchannel data
2840 cdb
->SUBCHANNEL
.SubQ
= CDB_SUBCHANNEL_BLOCK
;
2843 // Specify format of informatin to return
2846 cdb
->SUBCHANNEL
.Format
= inputBuffer
->Format
;
2849 // Specify which track to access (only used by Track ISRC reads)
2852 if (inputBuffer
->Format
==IOCTL_CDROM_TRACK_ISRC
) {
2853 cdb
->SUBCHANNEL
.TrackNumber
= inputBuffer
->Track
;
2857 // Set size of channel data -- however, this is dependent on
2858 // what information we are requesting (which Format)
2861 switch( inputBuffer
->Format
) {
2863 case IOCTL_CDROM_CURRENT_POSITION
:
2864 transferByteCount
= sizeof(SUB_Q_CURRENT_POSITION
);
2867 case IOCTL_CDROM_MEDIA_CATALOG
:
2868 transferByteCount
= sizeof(SUB_Q_MEDIA_CATALOG_NUMBER
);
2871 case IOCTL_CDROM_TRACK_ISRC
:
2872 transferByteCount
= sizeof(SUB_Q_TRACK_ISRC
);
2876 cdb
->SUBCHANNEL
.AllocationLength
[0] = (UCHAR
) (transferByteCount
>> 8);
2877 cdb
->SUBCHANNEL
.AllocationLength
[1] = (UCHAR
) (transferByteCount
& 0xFF);
2878 cdb
->SUBCHANNEL
.OperationCode
= SCSIOP_READ_SUB_CHANNEL
;
2879 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2880 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2881 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
2882 srb
->DataTransferLength
= transferByteCount
;
2883 srb
->CdbLength
= 10;
2884 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2886 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2891 case IOCTL_CDROM_PAUSE_AUDIO
: {
2893 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2894 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_PAUSE
;
2896 srb
->CdbLength
= 10;
2897 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2898 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2899 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2900 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2902 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2906 case IOCTL_CDROM_RESUME_AUDIO
: {
2908 cdb
->PAUSE_RESUME
.OperationCode
= SCSIOP_PAUSE_RESUME
;
2909 cdb
->PAUSE_RESUME
.Action
= CDB_AUDIO_RESUME
;
2911 srb
->CdbLength
= 10;
2912 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2913 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2914 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2915 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2917 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2921 case IOCTL_CDROM_SEEK_AUDIO_MSF
: {
2923 PCDROM_SEEK_AUDIO_MSF inputBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
2924 ULONG logicalBlockAddress
;
2926 logicalBlockAddress
= MSF_TO_LBA(inputBuffer
->M
, inputBuffer
->S
, inputBuffer
->F
);
2928 cdb
->SEEK
.OperationCode
= SCSIOP_SEEK
;
2929 cdb
->SEEK
.LogicalBlockAddress
[0] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte3
;
2930 cdb
->SEEK
.LogicalBlockAddress
[1] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte2
;
2931 cdb
->SEEK
.LogicalBlockAddress
[2] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte1
;
2932 cdb
->SEEK
.LogicalBlockAddress
[3] = ((PFOUR_BYTE
)&logicalBlockAddress
)->Byte0
;
2934 srb
->CdbLength
= 10;
2935 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2936 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2937 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2938 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2940 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2945 case IOCTL_CDROM_STOP_AUDIO
: {
2947 cdb
->START_STOP
.OperationCode
= SCSIOP_START_STOP_UNIT
;
2948 cdb
->START_STOP
.Immediate
= 1;
2949 cdb
->START_STOP
.Start
= 0;
2950 cdb
->START_STOP
.LoadEject
= 0;
2953 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
2955 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
2956 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
2957 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
2959 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
2963 case IOCTL_CDROM_GET_CONTROL
: {
2965 PAUDIO_OUTPUT audioOutput
;
2966 PCDROM_AUDIO_CONTROL audioControl
= Irp
->AssociatedIrp
.SystemBuffer
;
2969 // Allocate buffer for volume control information.
2972 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
2977 ExFreePool(senseBuffer
);
2980 Irp
->IoStatus
.Information
= 0;
2981 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2984 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
2989 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
2995 if (!irp2
->MdlAddress
) {
2996 ExFreePool(senseBuffer
);
2998 ExFreePool(dataBuffer
);
3000 Irp
->IoStatus
.Information
= 0;
3001 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3004 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3012 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
3013 srb
->DataBuffer
= dataBuffer
;
3015 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
3018 // Setup for either 6 or 10 byte CDBs.
3023 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3024 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3025 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
3028 // Disable block descriptors.
3031 cdb
->MODE_SENSE
.Dbd
= TRUE
;
3036 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
3037 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3038 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
3039 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
3042 // Disable block descriptors.
3045 cdb
->MODE_SENSE10
.Dbd
= TRUE
;
3047 srb
->CdbLength
= 10;
3050 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3051 srb
->DataTransferLength
= MODE_DATA_SIZE
;
3052 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3053 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3054 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3056 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3061 case IOCTL_CDROM_GET_VOLUME
:
3062 case IOCTL_CDROM_SET_VOLUME
: {
3064 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
3069 ExFreePool(senseBuffer
);
3072 Irp
->IoStatus
.Information
= 0;
3073 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3076 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3080 irp2
->MdlAddress
= IoAllocateMdl(dataBuffer
,
3086 if (!irp2
->MdlAddress
) {
3087 ExFreePool(senseBuffer
);
3089 ExFreePool(dataBuffer
);
3091 Irp
->IoStatus
.Information
= 0;
3092 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
3095 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3103 MmBuildMdlForNonPagedPool(irp2
->MdlAddress
);
3104 srb
->DataBuffer
= dataBuffer
;
3106 RtlZeroMemory(dataBuffer
, MODE_DATA_SIZE
);
3111 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
3112 cdb
->MODE_SENSE
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3113 cdb
->MODE_SENSE
.AllocationLength
= MODE_DATA_SIZE
;
3119 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
3120 cdb
->MODE_SENSE10
.PageCode
= CDROM_AUDIO_CONTROL_PAGE
;
3121 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(MODE_DATA_SIZE
>> 8);
3122 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(MODE_DATA_SIZE
& 0xFF);
3124 srb
->CdbLength
= 10;
3127 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3128 srb
->DataTransferLength
= MODE_DATA_SIZE
;
3129 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3130 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3131 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3133 if (currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_CDROM_SET_VOLUME
) {
3136 // Setup a different completion routine as the mode sense data is needed in order
3137 // to send the mode select.
3140 IoSetCompletionRoutine(irp2
,
3141 CdRomSetVolumeIntermediateCompletion
,
3149 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3154 case IOCTL_STORAGE_SET_READ_AHEAD
: {
3156 PSTORAGE_SET_READ_AHEAD readAhead
= Irp
->AssociatedIrp
.SystemBuffer
;
3159 PFOUR_BYTE fourByte
= (PFOUR_BYTE
) &blockAddress
;
3162 // setup the SRB for a set readahead command
3165 cdb
->SET_READ_AHEAD
.OperationCode
= SCSIOP_SET_READ_AHEAD
;
3167 blockAddress
= (ULONG
) (readAhead
->TriggerAddress
.QuadPart
>>
3168 fdoExtension
->SectorShift
);
3170 cdb
->SET_READ_AHEAD
.TriggerLBA
[0] = fourByte
->Byte3
;
3171 cdb
->SET_READ_AHEAD
.TriggerLBA
[1] = fourByte
->Byte2
;
3172 cdb
->SET_READ_AHEAD
.TriggerLBA
[2] = fourByte
->Byte1
;
3173 cdb
->SET_READ_AHEAD
.TriggerLBA
[3] = fourByte
->Byte0
;
3175 blockAddress
= (ULONG
) (readAhead
->TargetAddress
.QuadPart
>>
3176 fdoExtension
->SectorShift
);
3178 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[0] = fourByte
->Byte3
;
3179 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[1] = fourByte
->Byte2
;
3180 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[2] = fourByte
->Byte1
;
3181 cdb
->SET_READ_AHEAD
.ReadAheadLBA
[3] = fourByte
->Byte0
;
3183 srb
->CdbLength
= 12;
3184 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3186 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3187 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3188 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_DATA_TRANSFER
);
3190 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp2
);
3194 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
3195 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
:
3196 case IOCTL_DISK_GET_PARTITION_INFO
:
3197 case IOCTL_DISK_GET_PARTITION_INFO_EX
: {
3200 ASSERT(senseBuffer
);
3204 ExFreePool(senseBuffer
);
3208 // NOTE: should probably update the media's capacity first...
3211 CdromFakePartitionInfo(commonExtension
, Irp
);
3215 case IOCTL_DISK_IS_WRITABLE
: {
3217 TraceLog((CdromDebugWarning
,
3218 "CdRomStartIo: DiskIsWritable (%p) - returning %s\n",
3219 Irp
, (cdData
->Mmc
.WriteAllowed
? "TRUE" : "false")));
3222 ASSERT(senseBuffer
);
3226 ExFreePool(senseBuffer
);
3229 Irp
->IoStatus
.Information
= 0;
3230 if (cdData
->Mmc
.WriteAllowed
) {
3231 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3233 Irp
->IoStatus
.Status
= STATUS_MEDIA_WRITE_PROTECTED
;
3235 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, Irp
);
3241 UCHAR uniqueAddress
;
3244 // Just complete the request - CdRomClassIoctlCompletion will take
3245 // care of it for us
3247 // NOTE: THIS IS A SYNCHRONIZATION METHOD!!!
3251 // Acquire a new copy of the lock so that ClassCompleteRequest
3252 // doesn't get confused when we complete the other request while
3253 // holding the lock.
3257 // NOTE: CdRomDeviceControlDispatch/CdRomDeviceControlCompletion
3258 // wait for the event and eventually calls
3259 // IoStartNextPacket()
3263 ASSERT(senseBuffer
);
3267 ExFreePool(senseBuffer
);
3272 ClassAcquireRemoveLock(Fdo
, (PIRP
)&uniqueAddress
);
3273 ClassReleaseRemoveLock(Fdo
, Irp
);
3274 ClassCompleteRequest(Fdo
, Irp
, IO_NO_INCREMENT
);
3275 ClassReleaseRemoveLock(Fdo
, (PIRP
)&uniqueAddress
);
3280 } else if (currentIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
||
3281 currentIrpStack
->MajorFunction
== IRP_MJ_FLUSH_BUFFERS
) {
3283 currentIrpStack
->Parameters
.Others
.Argument1
= 0;
3284 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
3285 CdRomShutdownFlushCompletion(Fdo
, NULL
, Irp
);
3291 // If a read or an unhandled IRP_MJ_XX, end up here. The unhandled IRP_MJ's
3292 // are expected and composed of AutoRun Irps, at present.
3295 IoCallDriver(commonExtension
->LowerDeviceObject
, Irp
);
3301 CdRomReadWriteVerification(
3302 IN PDEVICE_OBJECT DeviceObject
,
3308 Routine Description:
3310 This is the entry called by the I/O system for read requests.
3311 It builds the SRB and sends it to the port driver.
3315 DeviceObject - the system object for the device.
3325 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
3326 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3328 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
3329 ULONG transferByteCount
= currentIrpStack
->Parameters
.Read
.Length
;
3330 LARGE_INTEGER startingOffset
= currentIrpStack
->Parameters
.Read
.ByteOffset
;
3332 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3334 SCSI_REQUEST_BLOCK srb
;
3335 PCDB cdb
= (PCDB
)srb
.Cdb
;
3341 // note: we are no longer failing write commands immediately
3342 // they are now failed in StartIo based upon media ability
3346 // If the cd is playing music then reject this request.
3349 if (PLAY_ACTIVE(fdoExtension
)) {
3350 Irp
->IoStatus
.Status
= STATUS_DEVICE_BUSY
;
3351 return STATUS_DEVICE_BUSY
;
3355 // Verify parameters of this request.
3356 // Check that ending sector is on disc and
3357 // that number of bytes to transfer is a multiple of
3361 startingOffset
.QuadPart
= currentIrpStack
->Parameters
.Read
.ByteOffset
.QuadPart
+
3364 if (!fdoExtension
->DiskGeometry
.BytesPerSector
) {
3365 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
3368 if ((startingOffset
.QuadPart
> commonExtension
->PartitionLength
.QuadPart
) ||
3369 (transferByteCount
& (fdoExtension
->DiskGeometry
.BytesPerSector
- 1))) {
3372 // Fail request with status of invalid parameters.
3375 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3377 return STATUS_INVALID_PARAMETER
;
3381 return STATUS_SUCCESS
;
3383 } // end CdRomReadWriteVerification()
3387 CdRomSwitchModeCompletion(
3388 IN PDEVICE_OBJECT DeviceObject
,
3393 PIO_STACK_LOCATION realIrpStack
;
3394 PIO_STACK_LOCATION realIrpNextStack
;
3395 PIRP realIrp
= NULL
;
3398 PSCSI_REQUEST_BLOCK srb
= Context
;
3399 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
3400 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
3401 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3402 PIO_STACK_LOCATION irpStack
= IoGetCurrentIrpStackLocation(Irp
);
3403 BOOLEAN use6Byte
= TEST_FLAG(cdData
->XAFlags
, XA_USE_6_BYTE
);
3407 // Extract the 'real' irp from the irpstack.
3410 realIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
3411 realIrpStack
= IoGetCurrentIrpStackLocation(realIrp
);
3412 realIrpNextStack
= IoGetNextIrpStackLocation(realIrp
);
3415 // Check SRB status for success of completing request.
3418 if (SRB_STATUS(srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) {
3420 ULONG retryInterval
;
3422 TraceLog((CdromDebugTrace
,
3423 "CdRomSetVolumeIntermediateCompletion: Irp %p, Srb %p, Real Irp %p\n",
3429 // Release the queue if it is frozen.
3432 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
3433 ClassReleaseQueue(DeviceObject
);
3437 retry
= ClassInterpretSenseInfo(DeviceObject
,
3439 irpStack
->MajorFunction
,
3440 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
,
3441 MAXIMUM_RETRIES
- ((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
),
3446 // If the status is verified required and the this request
3447 // should bypass verify required then retry the request.
3450 if (realIrpStack
->Flags
& SL_OVERRIDE_VERIFY_VOLUME
&&
3451 status
== STATUS_VERIFY_REQUIRED
) {
3453 status
= STATUS_IO_DEVICE_ERROR
;
3458 // get current retry count
3460 retryCount
= PtrToUlong(realIrpNextStack
->Parameters
.Others
.Argument1
);
3462 if (retry
&& retryCount
) {
3465 // decrement retryCount and update
3467 realIrpNextStack
->Parameters
.Others
.Argument1
= UlongToPtr(retryCount
-1);
3469 if (((ULONG
)(ULONG_PTR
)realIrpNextStack
->Parameters
.Others
.Argument1
)) {
3475 TraceLog((CdromDebugWarning
,
3476 "Retry request %p - Calling StartIo\n", Irp
));
3479 ExFreePool(srb
->SenseInfoBuffer
);
3480 ExFreePool(srb
->DataBuffer
);
3482 if (Irp
->MdlAddress
) {
3483 IoFreeMdl(Irp
->MdlAddress
);
3489 // Call StartIo directly since IoStartNextPacket hasn't been called,
3490 // the serialisation is still intact.
3493 CdRomRetryRequest(fdoExtension
,
3498 return STATUS_MORE_PROCESSING_REQUIRED
;
3503 // Exhausted retries. Fall through and complete the request with the appropriate status.
3509 // Set status for successful request.
3512 status
= STATUS_SUCCESS
;
3516 if (NT_SUCCESS(status
)) {
3518 ULONG sectorSize
, startingSector
, transferByteCount
;
3522 // Update device ext. to show which mode we are currently using.
3525 sectorSize
= cdData
->BlockDescriptor
.BlockLength
[0] << 16;
3526 sectorSize
|= (cdData
->BlockDescriptor
.BlockLength
[1] << 8);
3527 sectorSize
|= (cdData
->BlockDescriptor
.BlockLength
[2]);
3529 cdData
->RawAccess
= (sectorSize
== RAW_SECTOR_SIZE
) ? TRUE
: FALSE
;
3532 // Free the old data buffer, mdl.
3533 // reuse the SenseInfoBuffer and Srb
3536 ExFreePool(srb
->DataBuffer
);
3537 IoFreeMdl(Irp
->MdlAddress
);
3544 cdb
= (PCDB
)srb
->Cdb
;
3545 RtlZeroMemory(cdb
, CDB12GENERIC_LENGTH
);
3548 if (cdData
->RawAccess
) {
3550 PRAW_READ_INFO rawReadInfo
=
3551 (PRAW_READ_INFO
)realIrpStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
3553 ULONG maximumTransferLength
;
3554 ULONG transferPages
;
3555 UCHAR min
, sec
, frame
;
3558 // Calculate starting offset.
3561 startingSector
= (ULONG
)(rawReadInfo
->DiskOffset
.QuadPart
>> fdoExtension
->SectorShift
);
3562 transferByteCount
= rawReadInfo
->SectorCount
* RAW_SECTOR_SIZE
;
3563 maximumTransferLength
= fdoExtension
->AdapterDescriptor
->MaximumTransferLength
;
3564 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3568 // Determine if request is within limits imposed by miniport.
3569 // If the request is larger than the miniport's capabilities, split it.
3572 if (transferByteCount
> maximumTransferLength
||
3573 transferPages
> fdoExtension
->AdapterDescriptor
->MaximumPhysicalPages
) {
3576 ExFreePool(srb
->SenseInfoBuffer
);
3578 realIrp
->IoStatus
.Information
= 0;
3579 realIrp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
3582 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
3583 return STATUS_MORE_PROCESSING_REQUIRED
;
3586 srb
->OriginalRequest
= realIrp
;
3587 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
3588 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
3589 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
3591 srb
->DataTransferLength
= transferByteCount
;
3592 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
3593 srb
->CdbLength
= 10;
3594 srb
->DataBuffer
= MmGetMdlVirtualAddress(realIrp
->MdlAddress
);
3596 if (rawReadInfo
->TrackMode
== CDDA
) {
3597 if (TEST_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
)) {
3599 srb
->CdbLength
= 12;
3601 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3602 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3603 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3604 cdb
->PLXTR_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3606 cdb
->PLXTR_READ_CDDA
.TransferBlockByte3
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3607 cdb
->PLXTR_READ_CDDA
.TransferBlockByte2
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3608 cdb
->PLXTR_READ_CDDA
.TransferBlockByte1
= 0;
3609 cdb
->PLXTR_READ_CDDA
.TransferBlockByte0
= 0;
3611 cdb
->PLXTR_READ_CDDA
.SubCode
= 0;
3612 cdb
->PLXTR_READ_CDDA
.OperationCode
= 0xD8;
3614 } else if (TEST_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
)) {
3616 cdb
->NEC_READ_CDDA
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3617 cdb
->NEC_READ_CDDA
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3618 cdb
->NEC_READ_CDDA
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3619 cdb
->NEC_READ_CDDA
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3621 cdb
->NEC_READ_CDDA
.TransferBlockByte1
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3622 cdb
->NEC_READ_CDDA
.TransferBlockByte0
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3624 cdb
->NEC_READ_CDDA
.OperationCode
= 0xD4;
3627 cdb
->CDB10
.TransferBlocksMsb
= (UCHAR
) (rawReadInfo
->SectorCount
>> 8);
3628 cdb
->CDB10
.TransferBlocksLsb
= (UCHAR
) (rawReadInfo
->SectorCount
& 0xFF);
3630 cdb
->CDB10
.LogicalBlockByte3
= (UCHAR
) (startingSector
& 0xFF);
3631 cdb
->CDB10
.LogicalBlockByte2
= (UCHAR
) ((startingSector
>> 8) & 0xFF);
3632 cdb
->CDB10
.LogicalBlockByte1
= (UCHAR
) ((startingSector
>> 16) & 0xFF);
3633 cdb
->CDB10
.LogicalBlockByte0
= (UCHAR
) ((startingSector
>> 24) & 0xFF);
3635 cdb
->CDB10
.OperationCode
= SCSIOP_READ
;
3638 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
3641 irpStack
= IoGetNextIrpStackLocation(realIrp
);
3642 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
3643 irpStack
->Parameters
.Scsi
.Srb
= srb
;
3645 if (!(irpStack
->Parameters
.Others
.Argument1
)) {
3648 // Only jam this in if it doesn't exist. The completion routines can
3649 // call StartIo directly in the case of retries and resetting it will
3650 // cause infinite loops.
3653 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
3657 // Set up IoCompletion routine address.
3660 IoSetCompletionRoutine(realIrp
,
3668 PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor
;
3669 ULONG maximumTransferLength
;
3670 ULONG transferPages
;
3673 // a writable device must be MMC compliant, which supports
3674 // READ_CD commands, so writes and mode switching should
3675 // never occur on the same device.
3678 ASSERT(realIrpStack
->MajorFunction
!= IRP_MJ_WRITE
);
3681 // free the SRB and SenseInfoBuffer since they aren't used
3682 // by either ClassBuildRequest() nor ClassSplitRequest().
3685 ExFreePool(srb
->SenseInfoBuffer
);
3689 // Back to cooked sectors. Build and send a normal read.
3690 // The real work for setting offsets was done in startio.
3694 commonExtension
->PartitionZeroExtension
->AdapterDescriptor
;
3695 maximumTransferLength
= adapterDescriptor
->MaximumTransferLength
;
3696 transferPages
= ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3697 MmGetMdlVirtualAddress(realIrp
->MdlAddress
),
3698 realIrpStack
->Parameters
.Read
.Length
);
3700 if ((realIrpStack
->Parameters
.Read
.Length
> maximumTransferLength
) ||
3701 (transferPages
> adapterDescriptor
->MaximumPhysicalPages
)) {
3703 ULONG maxPages
= adapterDescriptor
->MaximumPhysicalPages
;
3705 if (maxPages
!= 0) {
3706 maxPages
--; // to account for page boundaries
3709 TraceLog((CdromDebugTrace
,
3710 "CdromSwitchModeCompletion: Request greater than "
3712 TraceLog((CdromDebugTrace
,
3713 "CdromSwitchModeCompletion: Maximum is %lx\n",
3714 maximumTransferLength
));
3715 TraceLog((CdromDebugTrace
,
3716 "CdromSwitchModeCompletion: Byte count is %lx\n",
3717 realIrpStack
->Parameters
.Read
.Length
));
3720 // Check that the maximum transfer length fits within
3721 // the maximum number of pages the device can handle.
3724 if (maximumTransferLength
> maxPages
<< PAGE_SHIFT
) {
3725 maximumTransferLength
= maxPages
<< PAGE_SHIFT
;
3729 // Check that maximum transfer size is not zero
3732 if (maximumTransferLength
== 0) {
3733 maximumTransferLength
= PAGE_SIZE
;
3737 // Request needs to be split. Completion of each portion
3738 // of the request will fire off the next portion. The final
3739 // request will signal Io to send a new request.
3742 ClassSplitRequest(DeviceObject
, realIrp
, maximumTransferLength
);
3743 return STATUS_MORE_PROCESSING_REQUIRED
;
3748 // Build SRB and CDB for this IRP.
3751 ClassBuildRequest(DeviceObject
, realIrp
);
3757 // Call the port driver.
3760 IoCallDriver(commonExtension
->LowerDeviceObject
, realIrp
);
3762 return STATUS_MORE_PROCESSING_REQUIRED
;
3766 // Update device Extension flags to indicate that XA isn't supported.
3769 TraceLog((CdromDebugWarning
,
3770 "Device Cannot Support CDDA (but tested positive) "
3771 "Now Clearing CDDA flags for FDO %p\n", DeviceObject
));
3772 SET_FLAG(cdData
->XAFlags
, XA_NOT_SUPPORTED
);
3773 CLEAR_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
);
3774 CLEAR_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
);
3777 // Deallocate srb and sense buffer.
3781 if (srb
->DataBuffer
) {
3782 ExFreePool(srb
->DataBuffer
);
3784 if (srb
->SenseInfoBuffer
) {
3785 ExFreePool(srb
->SenseInfoBuffer
);
3790 if (Irp
->PendingReturned
) {
3791 IoMarkIrpPending(Irp
);
3794 if (realIrp
->PendingReturned
) {
3795 IoMarkIrpPending(realIrp
);
3798 if (Irp
->MdlAddress
) {
3799 IoFreeMdl(Irp
->MdlAddress
);
3805 // Set status in completing IRP.
3808 realIrp
->IoStatus
.Status
= status
;
3811 // Set the hard error if necessary.
3814 if (!NT_SUCCESS(status
) && IoIsErrorUserInduced(status
)) {
3817 // Store DeviceObject for filesystem, and clear
3818 // in IoStatus.Information field.
3821 if (realIrp
->Tail
.Overlay
.Thread
) {
3822 IoSetHardErrorOrVerifyDevice(realIrp
, DeviceObject
);
3824 realIrp
->IoStatus
.Information
= 0;
3827 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, realIrp
);
3829 return STATUS_MORE_PROCESSING_REQUIRED
;
3834 ScanForSpecialHandler(
3835 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
3839 PCOMMON_DEVICE_EXTENSION commonExtension
;
3844 CLEAR_FLAG(HackFlags
, CDROM_HACK_INVALID_FLAGS
);
3846 commonExtension
= &(FdoExtension
->CommonExtension
);
3847 cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3848 cdData
->HackFlags
= HackFlags
;
3855 PDEVICE_OBJECT DeviceObject
3860 Routine Description:
3862 This function checks to see if an SCSI logical unit requires an special
3863 initialization or error processing.
3867 DeviceObject - Supplies the device object to be tested.
3869 InquiryData - Supplies the inquiry data returned by the device of interest.
3871 PortCapabilities - Supplies the capabilities of the device object.
3880 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
3881 PCOMMON_DEVICE_EXTENSION commonExtension
;
3886 fdoExtension
= DeviceObject
->DeviceExtension
;
3887 commonExtension
= DeviceObject
->DeviceExtension
;
3888 cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
3892 // set our hack flags
3895 ClassScanForSpecial(fdoExtension
, CdromHackItems
, ScanForSpecialHandler
);
3898 // All CDRom's can ignore the queue lock failure for power operations
3899 // and do not require handling the SpinUp case (unknown result of sending
3900 // a cdrom a START_UNIT command -- may eject disks?)
3902 // We send the stop command mostly to stop outstanding asynch operations
3903 // (like audio playback) from running when the system is powered off.
3904 // Because of this and the unlikely chance that a PLAY command will be
3905 // sent in the window between the STOP and the time the machine powers down
3906 // we don't require queue locks. This is important because without them
3907 // classpnp's power routines will send the START_STOP_UNIT command to the
3908 // device whether or not it supports locking (atapi does not support locking
3909 // and if we requested them we would end up not stopping audio on atapi
3913 SET_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_DISABLE_SPIN_UP
);
3914 SET_FLAG(fdoExtension
->ScanForSpecialFlags
, CLASS_SPECIAL_NO_QUEUE_LOCK
);
3916 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_1750
)
3917 && ( fdoExtension
->AdapterDescriptor
->AdapterUsesPio
)
3921 // Read-ahead must be disabled in order to get this cdrom drive
3922 // to work on scsi adapters that use PIO.
3926 TraceLog((CdromDebugWarning
,
3927 "CdRom ScanForSpecial: Found Hitachi CDR-1750S.\n"));
3930 // Setup an error handler to reinitialize the cd rom after it is reset.
3933 cdData
->ErrorHandler
= HitachiProcessError
;
3936 // Lock down the hitachi error processing code.
3939 MmLockPagableCodeSection(HitachiProcessError
);
3940 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
3943 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_SD_W1101
)) {
3945 TraceLog((CdromDebugError
,
3946 "CdRom ScanForSpecial: Found Toshiba SD-W1101 DVD-RAM "
3947 "-- This drive will *NOT* support DVD-ROM playback.\n"));
3949 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_GD_2000
)) {
3951 TraceLog((CdromDebugWarning
,
3952 "CdRom ScanForSpecial: Found Hitachi GD-2000\n"));
3955 // Setup an error handler to spin up the drive when it idles out
3956 // since it seems to like to fail to spin itself back up on its
3957 // own for a REPORT_KEY command. It may also lose the AGIDs that
3958 // it has given, which will result in DVD playback failures.
3959 // This routine will just do what it can...
3962 cdData
->ErrorHandler
= HitachiProcessErrorGD2000
;
3965 // this drive may require START_UNIT commands to spin
3966 // the drive up when it's spun itself down.
3969 SET_FLAG(fdoExtension
->DeviceFlags
, DEV_SAFE_START_UNIT
);
3972 // Lock down the hitachi error processing code.
3975 MmLockPagableCodeSection(HitachiProcessErrorGD2000
);
3976 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
3978 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_FUJITSU_FMCD_10x
)) {
3981 // When Read command is issued to FMCD-101 or FMCD-102 and there is a music
3982 // cd in it. It takes longer time than SCSI_CDROM_TIMEOUT before returning
3986 fdoExtension
->TimeOutValue
= 20;
3988 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_DEC_RRD
)) {
3990 PMODE_PARM_READ_WRITE_DATA modeParameters
;
3991 SCSI_REQUEST_BLOCK srb
;
3996 TraceLog((CdromDebugWarning
,
3997 "CdRom ScanForSpecial: Found DEC RRD.\n"));
3999 cdData
->IsDecRrd
= TRUE
;
4002 // Setup an error handler to reinitialize the cd rom after it is reset?
4004 //commonExtension->DevInfo->ClassError = DecRrdProcessError;
4007 // Found a DEC RRD cd-rom. These devices do not pass MS HCT
4008 // multi-media tests because the DEC firmware modifieds the block
4009 // from the PC-standard 2K to 512. Change the block transfer size
4010 // back to the PC-standard 2K by using a mode select command.
4013 modeParameters
= ExAllocatePoolWithTag(NonPagedPool
,
4014 sizeof(MODE_PARM_READ_WRITE_DATA
),
4017 if (modeParameters
== NULL
) {
4021 RtlZeroMemory(modeParameters
, sizeof(MODE_PARM_READ_WRITE_DATA
));
4022 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4025 // Set the block length to 2K.
4028 modeParameters
->ParameterListHeader
.BlockDescriptorLength
=
4029 sizeof(MODE_PARAMETER_BLOCK
);
4032 // Set block length to 2K (0x0800) in Parameter Block.
4035 modeParameters
->ParameterListBlock
.BlockLength
[0] = 0x00; //MSB
4036 modeParameters
->ParameterListBlock
.BlockLength
[1] = 0x08;
4037 modeParameters
->ParameterListBlock
.BlockLength
[2] = 0x00; //LSB
4040 // Build the mode select CDB.
4044 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4046 cdb
= (PCDB
)srb
.Cdb
;
4047 cdb
->MODE_SELECT
.PFBit
= 1;
4048 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4049 cdb
->MODE_SELECT
.ParameterListLength
= HITACHI_MODE_DATA_SIZE
;
4052 // Send the request to the device.
4055 status
= ClassSendSrbSynchronous(DeviceObject
,
4058 sizeof(MODE_PARM_READ_WRITE_DATA
),
4061 if (!NT_SUCCESS(status
)) {
4062 TraceLog((CdromDebugWarning
,
4063 "CdRom ScanForSpecial: Setting DEC RRD to 2K block"
4064 "size failed [%x]\n", status
));
4066 ExFreePool(modeParameters
);
4068 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_XM_3xx
)) {
4070 SCSI_REQUEST_BLOCK srb
;
4077 // Set the density code and the error handler.
4080 length
= (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
);
4082 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4085 // Build the MODE SENSE CDB.
4089 cdb
= (PCDB
)srb
.Cdb
;
4092 // Set timeout value from device extension.
4095 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4097 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
4098 cdb
->MODE_SENSE
.PageCode
= 0x1;
4099 // NOTE: purposely not setting DBD because it is what is needed.
4100 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)length
;
4102 buffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4103 (sizeof(MODE_READ_RECOVERY_PAGE
) + MODE_BLOCK_DESC_LENGTH
+ MODE_HEADER_LENGTH
),
4104 CDROM_TAG_MODE_DATA
);
4109 status
= ClassSendSrbSynchronous(DeviceObject
,
4115 ((PERROR_RECOVERY_DATA
)buffer
)->BlockDescriptor
.DensityCode
= 0x83;
4116 ((PERROR_RECOVERY_DATA
)buffer
)->Header
.ModeDataLength
= 0x0;
4118 RtlCopyMemory(&cdData
->Header
, buffer
, sizeof(ERROR_RECOVERY_DATA
));
4120 RtlZeroMemory(&srb
, sizeof(SCSI_REQUEST_BLOCK
));
4123 // Build the MODE SENSE CDB.
4127 cdb
= (PCDB
)srb
.Cdb
;
4130 // Set timeout value from device extension.
4133 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
4135 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4136 cdb
->MODE_SELECT
.PFBit
= 1;
4137 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4139 status
= ClassSendSrbSynchronous(DeviceObject
,
4145 if (!NT_SUCCESS(status
)) {
4146 TraceLog((CdromDebugWarning
,
4147 "Cdrom.ScanForSpecial: Setting density code on Toshiba failed [%x]\n",
4151 cdData
->ErrorHandler
= ToshibaProcessError
;
4154 // Lock down the toshiba error section.
4157 MmLockPagableCodeSection(ToshibaProcessError
);
4158 SET_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
);
4165 // Determine special CD-DA requirements.
4168 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_READ_CD_SUPPORTED
)) {
4170 SET_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
);
4172 } else if (!TEST_FLAG(cdData
->XAFlags
, XA_USE_READ_CD
)) {
4174 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_PLEXTOR_CDDA
)) {
4175 SET_FLAG(cdData
->XAFlags
, XA_PLEXTOR_CDDA
);
4176 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_NEC_CDDA
)) {
4177 SET_FLAG(cdData
->XAFlags
, XA_NEC_CDDA
);
4182 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
)) {
4183 KdPrintEx((DPFLTR_SYSTEM_ID
, DPFLTR_ERROR_LEVEL
,
4184 "Locking pages for error handler\n"));
4193 HitachiProcessErrorGD2000(
4195 PSCSI_REQUEST_BLOCK OriginalSrb
,
4201 Routine Description:
4203 This routine checks the type of error. If the error suggests that the
4204 drive has spun down and cannot reinitialize itself, send a
4205 START_UNIT or READ to the device. This will force the drive to spin
4206 up. This drive also loses the AGIDs it has granted when it spins down,
4207 which may result in playback failure the first time around.
4211 DeviceObject - Supplies a pointer to the device object.
4213 Srb - Supplies a pointer to the failing Srb.
4215 Status - return the final status for this command?
4217 Retry - return if the command should be retried.
4225 PSENSE_DATA senseBuffer
= OriginalSrb
->SenseInfoBuffer
;
4227 UNREFERENCED_PARAMETER(Status
);
4228 UNREFERENCED_PARAMETER(Retry
);
4230 if (!TEST_FLAG(OriginalSrb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
4234 if (((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_HARDWARE_ERROR
) &&
4235 (senseBuffer
->AdditionalSenseCode
== 0x44)) {
4237 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
4239 PIO_STACK_LOCATION irpStack
;
4240 PCOMPLETION_CONTEXT context
;
4241 PSCSI_REQUEST_BLOCK newSrb
;
4244 TraceLog((CdromDebugWarning
,
4245 "HitachiProcessErrorGD2000 (%p) => Internal Target "
4246 "Failure Detected -- spinning up drive\n", Fdo
));
4249 // the request should be retried because the device isn't ready
4253 *Status
= STATUS_DEVICE_NOT_READY
;
4256 // send a START_STOP unit to spin up the drive
4257 // NOTE: this temporarily violates the StartIo serialization
4258 // mechanism, but the completion routine on this will NOT
4259 // call StartNextPacket(), so it's a temporary disruption
4260 // of the serialization only.
4263 ClassSendStartUnit(Fdo
);
4272 HitachiProcessError(
4273 PDEVICE_OBJECT DeviceObject
,
4274 PSCSI_REQUEST_BLOCK Srb
,
4280 Routine Description:
4282 This routine checks the type of error. If the error indicates CD-ROM the
4283 CD-ROM needs to be reinitialized then a Mode sense command is sent to the
4284 device. This command disables read-ahead for the device.
4288 DeviceObject - Supplies a pointer to the device object.
4290 Srb - Supplies a pointer to the failing Srb.
4303 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4304 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
4305 LARGE_INTEGER largeInt
;
4307 PIO_STACK_LOCATION irpStack
;
4309 PSCSI_REQUEST_BLOCK srb
;
4310 PCOMPLETION_CONTEXT context
;
4312 ULONG_PTR alignment
;
4314 UNREFERENCED_PARAMETER(Status
);
4315 UNREFERENCED_PARAMETER(Retry
);
4317 largeInt
.QuadPart
= (LONGLONG
) 1;
4320 // Check the status. The initialization command only needs to be sent
4321 // if UNIT ATTENTION is returned.
4324 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
4327 // The drive does not require reinitialization.
4334 // Found an HITACHI cd-rom that does not work with PIO
4335 // adapters when read-ahead is enabled. Read-ahead is disabled by
4336 // a mode select command. The mode select page code is zero and the
4337 // length is 6 bytes. All of the other bytes should be zero.
4340 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
4342 TraceLog((CdromDebugWarning
,
4343 "HitachiProcessError: Reinitializing the CD-ROM.\n"));
4346 // Send the special mode select command to disable read-ahead
4347 // on the CD-ROM reader.
4350 alignment
= DeviceObject
->AlignmentRequirement
?
4351 DeviceObject
->AlignmentRequirement
: 1;
4353 context
= ExAllocatePoolWithTag(
4355 sizeof(COMPLETION_CONTEXT
) + HITACHI_MODE_DATA_SIZE
+ (ULONG
)alignment
,
4356 CDROM_TAG_HITACHI_ERROR
4359 if (context
== NULL
) {
4362 // If there is not enough memory to fulfill this request,
4363 // simply return. A subsequent retry will fail and another
4364 // chance to start the unit.
4370 context
->DeviceObject
= DeviceObject
;
4371 srb
= &context
->Srb
;
4373 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
4376 // Write length to SRB.
4379 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4382 // Set up SCSI bus address.
4385 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4386 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
4389 // Set the transfer length.
4392 srb
->DataTransferLength
= HITACHI_MODE_DATA_SIZE
;
4393 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
4394 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
4395 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_AUTOSENSE
);
4396 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
4399 // The data buffer must be aligned.
4402 srb
->DataBuffer
= (PVOID
) (((ULONG_PTR
) (context
+ 1) + (alignment
- 1)) &
4407 // Build the HITACHI read-ahead mode select CDB.
4411 cdb
= (PCDB
)srb
->Cdb
;
4412 cdb
->MODE_SENSE
.LogicalUnitNumber
= srb
->Lun
;
4413 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SELECT
;
4414 cdb
->MODE_SENSE
.AllocationLength
= HITACHI_MODE_DATA_SIZE
;
4417 // Initialize the mode sense data.
4420 modePage
= srb
->DataBuffer
;
4422 RtlZeroMemory(modePage
, HITACHI_MODE_DATA_SIZE
);
4425 // Set the page length field to 6.
4431 // Build the asynchronous request to be sent to the port driver.
4434 irp
= IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE
,
4437 srb
->DataTransferLength
,
4444 // If there is not enough memory to fulfill this request,
4445 // simply return. A subsequent retry will fail and another
4446 // chance to start the unit.
4449 ExFreePool(context
);
4453 ClassAcquireRemoveLock(DeviceObject
, irp
);
4455 IoSetCompletionRoutine(irp
,
4456 (PIO_COMPLETION_ROUTINE
)ClassAsynchronousCompletion
,
4462 irpStack
= IoGetNextIrpStackLocation(irp
);
4464 irpStack
->MajorFunction
= IRP_MJ_SCSI
;
4466 srb
->OriginalRequest
= irp
;
4469 // Save SRB address in next stack for port driver.
4472 irpStack
->Parameters
.Scsi
.Srb
= (PVOID
)srb
;
4475 // Set up IRP Address.
4478 (VOID
)IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp
);
4485 ToshibaProcessErrorCompletion(
4486 PDEVICE_OBJECT DeviceObject
,
4493 Routine Description:
4495 Completion routine for the ClassError routine to handle older Toshiba units
4496 that require setting the density code.
4500 DeviceObject - Supplies a pointer to the device object.
4502 Irp - Pointer to irp created to set the density code.
4504 Context - Supplies a pointer to the Mode Select Srb.
4509 STATUS_MORE_PROCESSING_REQUIRED
4515 PSCSI_REQUEST_BLOCK srb
= Context
;
4518 // Free all of the allocations.
4521 ClassReleaseRemoveLock(DeviceObject
, Irp
);
4523 ExFreePool(srb
->DataBuffer
);
4525 IoFreeMdl(Irp
->MdlAddress
);
4529 // Indicate the I/O system should stop processing the Irp completion.
4532 return STATUS_MORE_PROCESSING_REQUIRED
;
4537 ToshibaProcessError(
4538 PDEVICE_OBJECT DeviceObject
,
4539 PSCSI_REQUEST_BLOCK Srb
,
4546 Routine Description:
4548 This routine checks the type of error. If the error indicates a unit attention,
4549 the density code needs to be set via a Mode select command.
4553 DeviceObject - Supplies a pointer to the device object.
4555 Srb - Supplies a pointer to the failing Srb.
4568 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4569 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
4571 PCDROM_DATA cdData
= (PCDROM_DATA
)(commonExtension
->DriverData
);
4572 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
4573 PIO_STACK_LOCATION irpStack
;
4575 PSCSI_REQUEST_BLOCK srb
;
4581 if (!(Srb
->SrbStatus
& SRB_STATUS_AUTOSENSE_VALID
)) {
4586 // The Toshiba's require the density code to be set on power up and media changes.
4589 if ((senseBuffer
->SenseKey
& 0xf) == SCSI_SENSE_UNIT_ATTENTION
) {
4592 irp
= IoAllocateIrp((CCHAR
)(DeviceObject
->StackSize
+1),
4599 srb
= ExAllocatePoolWithTag(NonPagedPool
,
4600 sizeof(SCSI_REQUEST_BLOCK
),
4601 CDROM_TAG_TOSHIBA_ERROR
);
4608 length
= sizeof(ERROR_RECOVERY_DATA
);
4609 dataBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4611 CDROM_TAG_TOSHIBA_ERROR
);
4618 irp
->MdlAddress
= IoAllocateMdl(dataBuffer
,
4624 if (!irp
->MdlAddress
) {
4626 ExFreePool(dataBuffer
);
4635 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
4637 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
4639 srb
->DataBuffer
= dataBuffer
;
4640 cdb
= (PCDB
)srb
->Cdb
;
4646 IoSetNextIrpStackLocation(irp
);
4647 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
4648 irp
->IoStatus
.Information
= 0;
4650 irp
->UserBuffer
= NULL
;
4653 // Save the device object and irp in a private stack location.
4656 irpStack
= IoGetCurrentIrpStackLocation(irp
);
4657 irpStack
->DeviceObject
= DeviceObject
;
4660 // Construct the IRP stack for the lower level driver.
4663 irpStack
= IoGetNextIrpStackLocation(irp
);
4664 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
4665 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_OUT
;
4666 irpStack
->Parameters
.Scsi
.Srb
= srb
;
4668 IoSetCompletionRoutine(irp
,
4669 ToshibaProcessErrorCompletion
,
4675 ClassAcquireRemoveLock(DeviceObject
, irp
);
4677 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
4678 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
4679 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
4681 srb
->OriginalRequest
= irp
;
4682 srb
->SenseInfoBufferLength
= 0;
4685 // Set the transfer length.
4688 srb
->DataTransferLength
= length
;
4689 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
4690 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_OUT
);
4691 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_AUTOSENSE
);
4692 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
4693 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_NO_QUEUE_FREEZE
);
4697 cdb
->MODE_SELECT
.OperationCode
= SCSIOP_MODE_SELECT
;
4698 cdb
->MODE_SELECT
.PFBit
= 1;
4699 cdb
->MODE_SELECT
.ParameterListLength
= (UCHAR
)length
;
4702 // Copy the Mode page into the databuffer.
4705 RtlCopyMemory(srb
->DataBuffer
, &cdData
->Header
, length
);
4708 // Set the density code.
4711 ((PERROR_RECOVERY_DATA
)srb
->DataBuffer
)->BlockDescriptor
.DensityCode
= 0x83;
4713 IoCallDriver(fdoExtension
->CommonExtension
.LowerDeviceObject
, irp
);
4720 IN PDEVICE_OBJECT DeviceObject
4725 Routine Description:
4727 This routine determines if the cd is currently playing music.
4731 DeviceObject - Device object to test.
4735 TRUE if the device is playing music.
4739 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4740 IO_STATUS_BLOCK ioStatus
;
4741 PSUB_Q_CURRENT_POSITION currentBuffer
;
4746 // if we don't think it is playing audio, don't bother checking.
4749 if (!PLAY_ACTIVE(fdoExtension
)) {
4753 currentBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
4754 sizeof(SUB_Q_CURRENT_POSITION
),
4755 CDROM_TAG_PLAY_ACTIVE
);
4757 if (currentBuffer
== NULL
) {
4761 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Format
= IOCTL_CDROM_CURRENT_POSITION
;
4762 ((PCDROM_SUB_Q_DATA_FORMAT
) currentBuffer
)->Track
= 0;
4765 // Build the synchronous request to be sent to ourself
4766 // to perform the request.
4769 ClassSendDeviceIoControlSynchronous(
4770 IOCTL_CDROM_READ_Q_CHANNEL
,
4773 sizeof(CDROM_SUB_Q_DATA_FORMAT
),
4774 sizeof(SUB_Q_CURRENT_POSITION
),
4778 if (!NT_SUCCESS(ioStatus
.Status
)) {
4779 ExFreePool(currentBuffer
);
4784 // should update the playactive flag here.
4787 if (currentBuffer
->Header
.AudioStatus
== AUDIO_STATUS_IN_PROGRESS
) {
4788 PLAY_ACTIVE(fdoExtension
) = TRUE
;
4790 PLAY_ACTIVE(fdoExtension
) = FALSE
;
4793 ExFreePool(currentBuffer
);
4795 return(PLAY_ACTIVE(fdoExtension
));
4802 IN PDEVICE_OBJECT DeviceObject
4807 Routine Description:
4809 This routine handles the once per second timer provided by the
4810 Io subsystem. It is used to do delayed retries for cdroms.
4814 DeviceObject - what to check.
4823 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
4824 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
4833 PLIST_ENTRY listEntry
;
4835 PIO_STACK_LOCATION irpStack
;
4836 UCHAR uniqueAddress
;
4838 isRemoved
= ClassAcquireRemoveLock(DeviceObject
, (PIRP
) &uniqueAddress
);
4841 // We stop the timer before deleting the device. It's safe to keep going
4842 // if the flag value is REMOVE_PENDING because the removal thread will be
4843 // blocked trying to stop the timer.
4846 ASSERT(isRemoved
!= REMOVE_COMPLETE
);
4849 // This routine is reasonably safe even if the device object has a pending
4852 cddata
= commonExtension
->DriverData
;
4855 // Since cdrom is completely synchronized there can never be more than one
4856 // irp delayed for retry at any time.
4859 KeAcquireSpinLock(&(cddata
->DelayedRetrySpinLock
), &oldIrql
);
4861 if(cddata
->DelayedRetryIrp
!= NULL
) {
4863 PIRP irp
= cddata
->DelayedRetryIrp
;
4866 // If we've got a delayed retry at this point then there had beter
4867 // be an interval for it.
4870 ASSERT(cddata
->DelayedRetryInterval
!= 0);
4871 cddata
->DelayedRetryInterval
--;
4876 // This device is removed - flush the timer queue
4879 cddata
->DelayedRetryIrp
= NULL
;
4880 cddata
->DelayedRetryInterval
= 0;
4882 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4884 ClassReleaseRemoveLock(DeviceObject
, irp
);
4885 ClassCompleteRequest(DeviceObject
, irp
, IO_CD_ROM_INCREMENT
);
4887 } else if (cddata
->DelayedRetryInterval
== 0) {
4890 // Submit this IRP to the lower driver. This IRP does not
4891 // need to be remembered here. It will be handled again when
4895 cddata
->DelayedRetryIrp
= NULL
;
4897 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4899 TraceLog((CdromDebugWarning
,
4900 "CdRomTickHandler: Reissuing request %p (thread = %p)\n",
4902 irp
->Tail
.Overlay
.Thread
));
4905 // feed this to the appropriate port driver
4908 CdRomRerunRequest(fdoExtension
, irp
, cddata
->DelayedRetryResend
);
4910 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4913 KeReleaseSpinLock(&(cddata
->DelayedRetrySpinLock
), oldIrql
);
4916 ClassReleaseRemoveLock(DeviceObject
, (PIRP
) &uniqueAddress
);
4921 CdRomUpdateGeometryCompletion(
4922 PDEVICE_OBJECT DeviceObject
,
4929 Routine Description:
4931 This routine andles the completion of the test unit ready irps
4932 used to determine if the media has changed. If the media has
4933 changed, this code signals the named event to wake up other
4934 system services that react to media change (aka AutoPlay).
4938 DeviceObject - the object for the completion
4939 Irp - the IRP being completed
4940 Context - the SRB from the IRP
4949 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
4950 PCOMMON_DEVICE_EXTENSION commonExtension
;
4952 PSCSI_REQUEST_BLOCK srb
= (PSCSI_REQUEST_BLOCK
) Context
;
4953 PREAD_CAPACITY_DATA readCapacityBuffer
;
4954 PIO_STACK_LOCATION irpStack
;
4961 UCHAR uniqueAddress
;
4964 // Get items saved in the private IRP stack location.
4967 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
4968 retryCount
= (ULONG
)(ULONG_PTR
) irpStack
->Parameters
.Others
.Argument1
;
4969 originalIrp
= (PIRP
) irpStack
->Parameters
.Others
.Argument2
;
4971 if (!DeviceObject
) {
4972 DeviceObject
= irpStack
->DeviceObject
;
4974 ASSERT(DeviceObject
);
4976 fdoExtension
= DeviceObject
->DeviceExtension
;
4977 commonExtension
= DeviceObject
->DeviceExtension
;
4978 cddata
= commonExtension
->DriverData
;
4979 readCapacityBuffer
= srb
->DataBuffer
;
4981 if ((NT_SUCCESS(Irp
->IoStatus
.Status
)) && (SRB_STATUS(srb
->SrbStatus
) == SRB_STATUS_SUCCESS
)) {
4983 CdRomInterpretReadCapacity(DeviceObject
, readCapacityBuffer
);
4987 ULONG retryInterval
;
4989 TraceLog((CdromDebugWarning
,
4990 "CdRomUpdateGeometryCompletion: [%p] unsuccessful "
4991 "completion of buddy-irp %p (status - %lx)\n",
4992 originalIrp
, Irp
, Irp
->IoStatus
.Status
));
4994 if (srb
->SrbStatus
& SRB_STATUS_QUEUE_FROZEN
) {
4995 ClassReleaseQueue(DeviceObject
);
4998 retry
= ClassInterpretSenseInfo(DeviceObject
,
5007 if ((retryCount
) && (commonExtension
->IsRemoved
== NO_REMOVE
)) {
5010 TraceLog((CdromDebugWarning
,
5011 "CdRomUpdateGeometryCompletion: [%p] Retrying "
5012 "request %p .. thread is %p\n",
5013 originalIrp
, Irp
, Irp
->Tail
.Overlay
.Thread
));
5016 // set up a one shot timer to get this process started over
5019 irpStack
->Parameters
.Others
.Argument1
= ULongToPtr( retryCount
);
5020 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) originalIrp
;
5021 irpStack
->Parameters
.Others
.Argument3
= (PVOID
) 2;
5024 // Setup the IRP to be submitted again in the timer routine.
5027 irpStack
= IoGetNextIrpStackLocation(Irp
);
5028 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5029 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
5030 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5031 IoSetCompletionRoutine(Irp
,
5032 CdRomUpdateGeometryCompletion
,
5039 // Set up the SRB for read capacity.
5042 srb
->CdbLength
= 10;
5043 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
5044 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5046 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5047 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5048 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
5049 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
5050 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
5051 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
5057 cdb
= (PCDB
) &srb
->Cdb
[0];
5058 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
5061 // Requests queued onto this list will be sent to the
5062 // lower level driver during CdRomTickHandler
5065 CdRomRetryRequest(fdoExtension
, Irp
, retryInterval
, TRUE
);
5067 return STATUS_MORE_PROCESSING_REQUIRED
;
5070 if (commonExtension
->IsRemoved
!= NO_REMOVE
) {
5073 // We cannot retry the request. Fail it.
5076 originalIrp
->IoStatus
.Status
= STATUS_DEVICE_DOES_NOT_EXIST
;
5081 // This has been bounced for a number of times. Error the
5082 // original request.
5085 originalIrp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
5086 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5087 sizeof(DISK_GEOMETRY
));
5088 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5089 fdoExtension
->SectorShift
= 11;
5090 commonExtension
->PartitionLength
.QuadPart
=
5091 (LONGLONG
)(0x7fffffff);
5092 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5097 // Set up reasonable defaults
5100 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5101 sizeof(DISK_GEOMETRY
));
5102 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5103 fdoExtension
->SectorShift
= 11;
5104 commonExtension
->PartitionLength
.QuadPart
= (LONGLONG
)(0x7fffffff);
5105 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5110 // Free resources held.
5113 ExFreePool(srb
->SenseInfoBuffer
);
5114 ExFreePool(srb
->DataBuffer
);
5116 if (Irp
->MdlAddress
) {
5117 IoFreeMdl(Irp
->MdlAddress
);
5122 if (originalIrp
->Tail
.Overlay
.Thread
) {
5124 TraceLog((CdromDebugTrace
,
5125 "CdRomUpdateGeometryCompletion: [%p] completing "
5126 "original IRP\n", originalIrp
));
5130 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugError
,
5131 "CdRomUpdateGeometryCompletion: completing irp %p which has "
5132 "no thread\n", originalIrp
));
5137 // NOTE: should the original irp be sent down to the device object?
5138 // it probably should if the SL_OVERRIDER_VERIFY_VOLUME flag
5141 PIO_STACK_LOCATION realIrpStack
;
5143 realIrpStack
= IoGetCurrentIrpStackLocation(originalIrp
);
5144 oldIrql
= KeRaiseIrqlToDpcLevel();
5146 if (TEST_FLAG(realIrpStack
->Flags
, SL_OVERRIDE_VERIFY_VOLUME
)) {
5147 CdRomStartIo(DeviceObject
, originalIrp
);
5149 originalIrp
->IoStatus
.Status
= STATUS_VERIFY_REQUIRED
;
5150 originalIrp
->IoStatus
.Information
= 0;
5151 CdRomCompleteIrpAndStartNextPacketSafely(DeviceObject
, originalIrp
);
5153 KeLowerIrql(oldIrql
);
5156 return STATUS_MORE_PROCESSING_REQUIRED
;
5161 CdRomUpdateCapacity(
5162 IN PFUNCTIONAL_DEVICE_EXTENSION DeviceExtension
,
5163 IN PIRP IrpToComplete
,
5164 IN OPTIONAL PKEVENT IoctlEvent
5169 Routine Description:
5171 This routine updates the capacity of the disk as recorded in the device extension.
5172 It also completes the IRP given with STATUS_VERIFY_REQUIRED. This routine is called
5173 when a media change has occurred and it is necessary to determine the capacity of the
5174 new media prior to the next access.
5178 DeviceExtension - the device to update
5179 IrpToComplete - the request that needs to be completed when done.
5188 PCOMMON_DEVICE_EXTENSION commonExtension
= (PCOMMON_DEVICE_EXTENSION
) DeviceExtension
;
5189 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= (PFUNCTIONAL_DEVICE_EXTENSION
) DeviceExtension
;
5193 PSCSI_REQUEST_BLOCK srb
;
5194 PREAD_CAPACITY_DATA capacityBuffer
;
5195 PIO_STACK_LOCATION irpStack
;
5199 irp
= IoAllocateIrp((CCHAR
)(commonExtension
->DeviceObject
->StackSize
+1),
5204 srb
= ExAllocatePoolWithTag(NonPagedPool
,
5205 sizeof(SCSI_REQUEST_BLOCK
),
5206 CDROM_TAG_UPDATE_CAP
);
5208 capacityBuffer
= ExAllocatePoolWithTag(
5209 NonPagedPoolCacheAligned
,
5210 sizeof(READ_CAPACITY_DATA
),
5211 CDROM_TAG_UPDATE_CAP
);
5213 if (capacityBuffer
) {
5216 senseBuffer
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
5218 CDROM_TAG_UPDATE_CAP
);
5222 irp
->MdlAddress
= IoAllocateMdl(capacityBuffer
,
5223 sizeof(READ_CAPACITY_DATA
),
5228 if (irp
->MdlAddress
) {
5231 // Have all resources. Set up the IRP to send for the capacity.
5234 IoSetNextIrpStackLocation(irp
);
5235 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
5236 irp
->IoStatus
.Information
= 0;
5238 irp
->UserBuffer
= NULL
;
5241 // Save the device object and retry count in a private stack location.
5244 irpStack
= IoGetCurrentIrpStackLocation(irp
);
5245 irpStack
->DeviceObject
= commonExtension
->DeviceObject
;
5246 irpStack
->Parameters
.Others
.Argument1
= (PVOID
) MAXIMUM_RETRIES
;
5247 irpStack
->Parameters
.Others
.Argument2
= (PVOID
) IrpToComplete
;
5250 // Construct the IRP stack for the lower level driver.
5253 irpStack
= IoGetNextIrpStackLocation(irp
);
5254 irpStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
5255 irpStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_SCSI_EXECUTE_IN
;
5256 irpStack
->Parameters
.Scsi
.Srb
= srb
;
5257 IoSetCompletionRoutine(irp
,
5258 CdRomUpdateGeometryCompletion
,
5267 MmBuildMdlForNonPagedPool(irp
->MdlAddress
);
5271 // Set up the SRB for read capacity.
5274 RtlZeroMemory(srb
, sizeof(SCSI_REQUEST_BLOCK
));
5275 RtlZeroMemory(senseBuffer
, SENSE_BUFFER_SIZE
);
5276 srb
->CdbLength
= 10;
5277 srb
->TimeOutValue
= DeviceExtension
->TimeOutValue
;
5278 srb
->SrbStatus
= srb
->ScsiStatus
= 0;
5280 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
5281 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
5282 srb
->SrbFlags
= DeviceExtension
->SrbFlags
;
5283 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DISABLE_SYNCH_TRANSFER
);
5284 SET_FLAG(srb
->SrbFlags
, SRB_FLAGS_DATA_IN
);
5285 srb
->DataBuffer
= capacityBuffer
;
5286 srb
->DataTransferLength
= sizeof(READ_CAPACITY_DATA
);
5287 srb
->OriginalRequest
= irp
;
5288 srb
->SenseInfoBuffer
= senseBuffer
;
5289 srb
->SenseInfoBufferLength
= SENSE_BUFFER_SIZE
;
5295 cdb
= (PCDB
) &srb
->Cdb
[0];
5296 cdb
->CDB10
.OperationCode
= SCSIOP_READ_CAPACITY
;
5299 // Set the return value in the IRP that will be completed
5300 // upon completion of the read capacity.
5303 IrpToComplete
->IoStatus
.Status
= STATUS_IO_DEVICE_ERROR
;
5304 IoMarkIrpPending(IrpToComplete
);
5306 IoCallDriver(commonExtension
->LowerDeviceObject
, irp
);
5309 // status is not checked because the completion routine for this
5310 // IRP will always get called and it will free the resources.
5313 return STATUS_PENDING
;
5316 ExFreePool(senseBuffer
);
5317 ExFreePool(capacityBuffer
);
5322 ExFreePool(capacityBuffer
);
5336 // complete the original irp with a failure.
5337 // ISSUE-2000/07/05-henrygab - find a way to avoid failure.
5340 RtlZeroMemory(&(fdoExtension
->DiskGeometry
),
5341 sizeof(DISK_GEOMETRY
));
5342 fdoExtension
->DiskGeometry
.BytesPerSector
= 2048;
5343 fdoExtension
->SectorShift
= 11;
5344 commonExtension
->PartitionLength
.QuadPart
=
5345 (LONGLONG
)(0x7fffffff);
5346 fdoExtension
->DiskGeometry
.MediaType
= RemovableMedia
;
5348 IrpToComplete
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
5349 IrpToComplete
->IoStatus
.Information
= 0;
5351 BAIL_OUT(IrpToComplete
);
5352 CdRomCompleteIrpAndStartNextPacketSafely(commonExtension
->DeviceObject
,
5354 return STATUS_INSUFFICIENT_RESOURCES
;
5360 IN PDEVICE_OBJECT DeviceObject
,
5366 Routine Description:
5368 This routine is responsible for releasing any resources in use by the
5369 cdrom driver and shutting down it's timer routine. This routine is called
5370 when all outstanding requests have been completed and the device has
5371 disappeared - no requests may be issued to the lower drivers.
5375 DeviceObject - the device object being removed
5379 none - this routine may not fail
5384 PFUNCTIONAL_DEVICE_EXTENSION deviceExtension
=
5385 DeviceObject
->DeviceExtension
;
5387 PCDROM_DATA cdData
= deviceExtension
->CommonExtension
.DriverData
;
5391 if((Type
== IRP_MN_QUERY_REMOVE_DEVICE
) ||
5392 (Type
== IRP_MN_CANCEL_REMOVE_DEVICE
)) {
5393 return STATUS_SUCCESS
;
5396 if(cdData
->DelayedRetryIrp
!= NULL
) {
5397 cdData
->DelayedRetryInterval
= 1;
5398 CdRomTickHandler(DeviceObject
);
5401 CdRomDeAllocateMmcResources(DeviceObject
);
5403 if (deviceExtension
->DeviceDescriptor
) {
5404 ExFreePool(deviceExtension
->DeviceDescriptor
);
5405 deviceExtension
->DeviceDescriptor
= NULL
;
5408 if (deviceExtension
->AdapterDescriptor
) {
5409 ExFreePool(deviceExtension
->AdapterDescriptor
);
5410 deviceExtension
->AdapterDescriptor
= NULL
;
5413 if (deviceExtension
->SenseData
) {
5414 ExFreePool(deviceExtension
->SenseData
);
5415 deviceExtension
->SenseData
= NULL
;
5418 ClassDeleteSrbLookasideList(&deviceExtension
->CommonExtension
);
5420 if(cdData
->CdromInterfaceString
.Buffer
!= NULL
) {
5421 IoSetDeviceInterfaceState(
5422 &(cdData
->CdromInterfaceString
),
5424 RtlFreeUnicodeString(&(cdData
->CdromInterfaceString
));
5425 RtlInitUnicodeString(&(cdData
->CdromInterfaceString
), NULL
);
5428 if(cdData
->VolumeInterfaceString
.Buffer
!= NULL
) {
5429 IoSetDeviceInterfaceState(
5430 &(cdData
->VolumeInterfaceString
),
5432 RtlFreeUnicodeString(&(cdData
->VolumeInterfaceString
));
5433 RtlInitUnicodeString(&(cdData
->VolumeInterfaceString
), NULL
);
5436 CdRomDeleteWellKnownName(DeviceObject
);
5438 ASSERT(cdData
->DelayedRetryIrp
== NULL
);
5440 if(Type
== IRP_MN_REMOVE_DEVICE
) {
5442 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_LOCKED_PAGES
)) {
5445 // unlock locked pages by locking (to get Mm pointer)
5446 // and then unlocking twice.
5451 if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_1750
)) {
5453 locked
= MmLockPagableCodeSection(HitachiProcessError
);
5455 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_HITACHI_GD_2000
)) {
5457 locked
= MmLockPagableCodeSection(HitachiProcessErrorGD2000
);
5459 } else if (TEST_FLAG(cdData
->HackFlags
, CDROM_HACK_TOSHIBA_XM_3xx
)) {
5461 locked
= MmLockPagableCodeSection(ToshibaProcessError
);
5465 // this is a problem!
5466 // workaround by locking this twice, once for us and
5467 // once for the non-existant locker from ScanForSpecial
5468 ASSERT(!"hack flags show locked section, but none exists?");
5469 locked
= MmLockPagableCodeSection(CdRomRemoveDevice
);
5470 locked
= MmLockPagableCodeSection(CdRomRemoveDevice
);
5475 MmUnlockPagableImageSection(locked
);
5476 MmUnlockPagableImageSection(locked
);
5481 // keep the system-wide count accurate, as
5482 // programs use this info to know when they
5483 // have found all the cdroms in a system.
5486 TraceLog((CdromDebugTrace
,
5487 "CDROM.SYS Remove device\n"));
5488 IoGetConfigurationInformation()->CdRomCount
--;
5492 // so long, and thanks for all the fish!
5495 return STATUS_SUCCESS
;
5501 IN PDEVICE_OBJECT DeviceObject
5505 Routine Description:
5507 This routine figures out the real device type
5508 by checking CDVD_CAPABILITIES_PAGE
5516 FILE_DEVICE_CD_ROM or FILE_DEVICE_DVD
5521 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
;
5522 PCDROM_DATA cdromExtension
;
5524 SCSI_REQUEST_BLOCK srb
;
5526 PMODE_PARAMETER_HEADER10 modePageHeader
;
5527 PCDVD_CAPABILITIES_PAGE capPage
;
5528 ULONG capPageOffset
;
5529 DEVICE_TYPE deviceType
;
5536 // NOTE: don't cache this until understand how it affects GetMediaTypes()
5540 // default device type
5543 deviceType
= FILE_DEVICE_CD_ROM
;
5545 fdoExtension
= DeviceObject
->DeviceExtension
;
5547 cdromExtension
= fdoExtension
->CommonExtension
.DriverData
;
5549 use6Byte
= TEST_FLAG(cdromExtension
->XAFlags
, XA_USE_6_BYTE
);
5551 RtlZeroMemory(&srb
, sizeof(srb
));
5552 cdb
= (PCDB
)srb
.Cdb
;
5555 // Build the MODE SENSE CDB. The data returned will be kept in the
5556 // device extension and used to set block size.
5560 bufLength
= sizeof(CDVD_CAPABILITIES_PAGE
) +
5561 sizeof(MODE_PARAMETER_HEADER
);
5563 capPageOffset
= sizeof(MODE_PARAMETER_HEADER
);
5565 cdb
->MODE_SENSE
.OperationCode
= SCSIOP_MODE_SENSE
;
5566 cdb
->MODE_SENSE
.Dbd
= 1;
5567 cdb
->MODE_SENSE
.PageCode
= MODE_PAGE_CAPABILITIES
;
5568 cdb
->MODE_SENSE
.AllocationLength
= (UCHAR
)bufLength
;
5572 bufLength
= sizeof(CDVD_CAPABILITIES_PAGE
) +
5573 sizeof(MODE_PARAMETER_HEADER10
);
5575 capPageOffset
= sizeof(MODE_PARAMETER_HEADER10
);
5577 cdb
->MODE_SENSE10
.OperationCode
= SCSIOP_MODE_SENSE10
;
5578 cdb
->MODE_SENSE10
.Dbd
= 1;
5579 cdb
->MODE_SENSE10
.PageCode
= MODE_PAGE_CAPABILITIES
;
5580 cdb
->MODE_SENSE10
.AllocationLength
[0] = (UCHAR
)(bufLength
>> 8);
5581 cdb
->MODE_SENSE10
.AllocationLength
[1] = (UCHAR
)(bufLength
>> 0);
5586 // Set timeout value from device extension.
5588 srb
.TimeOutValue
= fdoExtension
->TimeOutValue
;
5590 modePageHeader
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
5592 CDROM_TAG_MODE_DATA
);
5593 if (modePageHeader
) {
5595 RtlZeroMemory(modePageHeader
, bufLength
);
5597 status
= ClassSendSrbSynchronous(
5604 if (NT_SUCCESS(status
) ||
5605 (status
== STATUS_DATA_OVERRUN
) ||
5606 (status
== STATUS_BUFFER_OVERFLOW
)
5609 capPage
= (PCDVD_CAPABILITIES_PAGE
) (((PUCHAR
) modePageHeader
) + capPageOffset
);
5611 if ((capPage
->PageCode
== MODE_PAGE_CAPABILITIES
) &&
5612 (capPage
->DVDROMRead
|| capPage
->DVDRRead
||
5613 capPage
->DVDRAMRead
|| capPage
->DVDRWrite
||
5614 capPage
->DVDRAMWrite
)) {
5616 deviceType
= FILE_DEVICE_DVD
;
5619 ExFreePool (modePageHeader
);
5627 CdRomCreateWellKnownName(
5628 IN PDEVICE_OBJECT DeviceObject
5632 Routine Description:
5634 This routine creates a symbolic link to the cdrom device object
5635 under \dosdevices. The number of the cdrom device does not neccessarily
5636 match between \dosdevices and \device, but usually will be the same.
5650 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= DeviceObject
->DeviceExtension
;
5651 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
5652 PCDROM_DATA cdromData
= commonExtension
->DriverData
;
5654 UNICODE_STRING unicodeLinkName
;
5655 WCHAR wideLinkName
[64];
5658 LONG cdromNumber
= fdoExtension
->DeviceNumber
;
5663 // if already linked, assert then return
5666 if (cdromData
->WellKnownName
.Buffer
!= NULL
) {
5668 TraceLog((CdromDebugError
,
5669 "CdRomCreateWellKnownName: link already exists %p\n",
5670 cdromData
->WellKnownName
.Buffer
));
5672 return STATUS_UNSUCCESSFUL
;
5677 // find an unused CdRomNN to link to
5682 swprintf(wideLinkName
, L
"\\DosDevices\\CdRom%d", cdromNumber
);
5683 RtlInitUnicodeString(&unicodeLinkName
, wideLinkName
);
5684 status
= IoCreateSymbolicLink(&unicodeLinkName
,
5685 &(commonExtension
->DeviceName
));
5689 } while((status
== STATUS_OBJECT_NAME_COLLISION
) ||
5690 (status
== STATUS_OBJECT_NAME_EXISTS
));
5692 if (!NT_SUCCESS(status
)) {
5694 TraceLog((CdromDebugWarning
,
5695 "CdRomCreateWellKnownName: Error %lx linking %wZ to "
5699 &(commonExtension
->DeviceName
)));
5704 TraceLog((CdromDebugWarning
,
5705 "CdRomCreateWellKnownName: successfully linked %wZ "
5708 &(commonExtension
->DeviceName
)));
5711 // Save away the symbolic link name in the driver data block. We need
5712 // it so we can delete the link when the device is removed.
5715 savedName
= ExAllocatePoolWithTag(PagedPool
,
5716 unicodeLinkName
.MaximumLength
,
5719 if (savedName
== NULL
) {
5720 IoDeleteSymbolicLink(&unicodeLinkName
);
5721 return STATUS_INSUFFICIENT_RESOURCES
;
5724 RtlCopyMemory(savedName
,
5725 unicodeLinkName
.Buffer
,
5726 unicodeLinkName
.MaximumLength
);
5728 RtlInitUnicodeString(&(cdromData
->WellKnownName
), savedName
);
5731 // the name was saved and the link created
5734 return STATUS_SUCCESS
;
5739 CdRomDeleteWellKnownName(
5740 IN PDEVICE_OBJECT DeviceObject
5743 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
5744 PCDROM_DATA cdromData
= commonExtension
->DriverData
;
5746 if(cdromData
->WellKnownName
.Buffer
!= NULL
) {
5748 IoDeleteSymbolicLink(&(cdromData
->WellKnownName
));
5749 ExFreePool(cdromData
->WellKnownName
.Buffer
);
5750 cdromData
->WellKnownName
.Buffer
= NULL
;
5751 cdromData
->WellKnownName
.Length
= 0;
5752 cdromData
->WellKnownName
.MaximumLength
= 0;
5760 CdRomGetDeviceParameter (
5761 IN PDEVICE_OBJECT Fdo
,
5762 IN PWSTR ParameterName
,
5763 IN OUT PULONG ParameterValue
5767 Routine Description:
5769 retrieve a devnode registry parameter
5773 DeviceObject - Cdrom Device Object
5775 ParameterName - parameter name to look up
5777 ParameterValuse - default parameter value
5785 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
5787 HANDLE deviceParameterHandle
;
5788 RTL_QUERY_REGISTRY_TABLE queryTable
[2];
5789 ULONG defaultParameterValue
;
5794 // open the given parameter
5796 status
= IoOpenDeviceRegistryKey(fdoExtension
->LowerPdo
,
5797 PLUGPLAY_REGKEY_DRIVER
,
5799 &deviceParameterHandle
);
5801 if(NT_SUCCESS(status
)) {
5803 RtlZeroMemory(queryTable
, sizeof(queryTable
));
5805 defaultParameterValue
= *ParameterValue
;
5807 queryTable
->Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
5808 queryTable
->Name
= ParameterName
;
5809 queryTable
->EntryContext
= ParameterValue
;
5810 queryTable
->DefaultType
= REG_NONE
;
5811 queryTable
->DefaultData
= NULL
;
5812 queryTable
->DefaultLength
= 0;
5814 status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
5815 (PWSTR
) deviceParameterHandle
,
5819 if (!NT_SUCCESS(status
)) {
5821 *ParameterValue
= defaultParameterValue
;
5825 // close what we open
5827 ZwClose(deviceParameterHandle
);
5832 } // CdRomGetDeviceParameter
5836 CdRomSetDeviceParameter (
5837 IN PDEVICE_OBJECT Fdo
,
5838 IN PWSTR ParameterName
,
5839 IN ULONG ParameterValue
5843 Routine Description:
5845 save a devnode registry parameter
5849 DeviceObject - Cdrom Device Object
5851 ParameterName - parameter name
5853 ParameterValuse - parameter value
5861 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
5863 HANDLE deviceParameterHandle
;
5868 // open the given parameter
5870 status
= IoOpenDeviceRegistryKey(fdoExtension
->LowerPdo
,
5871 PLUGPLAY_REGKEY_DRIVER
,
5872 KEY_READ
| KEY_WRITE
,
5873 &deviceParameterHandle
);
5875 if(NT_SUCCESS(status
)) {
5877 status
= RtlWriteRegistryValue(
5878 RTL_REGISTRY_HANDLE
,
5879 (PWSTR
) deviceParameterHandle
,
5883 sizeof (ParameterValue
));
5886 // close what we open
5888 ZwClose(deviceParameterHandle
);
5893 } // CdromSetDeviceParameter
5898 IN PDEVICE_OBJECT Fdo
5902 Routine Description:
5904 pick a default dvd region
5908 DeviceObject - Cdrom Device Object
5916 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
5917 PCDROM_DATA cddata
= (PCDROM_DATA
)(commonExtension
->DriverData
);
5920 // these five pointers all point to dvdReadStructure or part of
5921 // its data, so don't deallocate them more than once!
5924 PDVD_READ_STRUCTURE dvdReadStructure
;
5925 PDVD_COPY_PROTECT_KEY copyProtectKey
;
5926 PDVD_COPYRIGHT_DESCRIPTOR dvdCopyRight
;
5927 PDVD_RPC_KEY rpcKey
;
5928 PDVD_SET_RPC_KEY dvdRpcKey
;
5930 IO_STATUS_BLOCK ioStatus
;
5933 ULONG pickDvdRegion
;
5934 ULONG defaultDvdRegion
;
5941 if ((pickDvdRegion
= InterlockedExchange(&cddata
->PickDvdRegion
, 0)) == 0) {
5944 // it was non-zero, so either another thread will do this, or
5945 // we no longer need to pick a region
5952 // short-circuit if license agreement violated
5955 if (cddata
->DvdRpc0LicenseFailure
) {
5956 TraceLog((CdromDebugWarning
,
5957 "DVD License failure. Refusing to pick a region\n"));
5958 InterlockedExchange(&cddata
->PickDvdRegion
, 0);
5964 a
= max(sizeof(DVD_DESCRIPTOR_HEADER
) +
5965 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
5966 sizeof(DVD_READ_STRUCTURE
)
5968 b
= max(DVD_RPC_KEY_LENGTH
,
5969 DVD_SET_RPC_KEY_LENGTH
5971 bufferLen
= max(a
, b
);
5973 dvdReadStructure
= (PDVD_READ_STRUCTURE
)
5974 ExAllocatePoolWithTag(PagedPool
, bufferLen
, DVD_TAG_DVD_REGION
);
5976 if (dvdReadStructure
== NULL
) {
5977 InterlockedExchange(&cddata
->PickDvdRegion
, pickDvdRegion
);
5981 if (cddata
->DvdRpc0Device
&& cddata
->Rpc0RetryRegistryCallback
) {
5983 TraceLog((CdromDebugWarning
,
5984 "CdRomPickDvdRegion (%p): now retrying RPC0 callback\n",
5988 // get the registry settings again
5991 ioStatus
.Status
= CdRomGetRpc0Settings(Fdo
);
5993 if (ioStatus
.Status
== STATUS_LICENSE_VIOLATION
) {
5996 // if this is the returned error, then
5997 // the routine should have set this!
6000 ASSERT(cddata
->DvdRpc0LicenseFailure
);
6001 cddata
->DvdRpc0LicenseFailure
= 1;
6002 TraceLog((CdromDebugWarning
,
6003 "CdRomPickDvdRegion (%p): "
6004 "setting to fail all dvd ioctls due to CSS licensing "
6005 "failure.\n", Fdo
));
6013 // get the device region, again
6016 copyProtectKey
= (PDVD_COPY_PROTECT_KEY
)dvdReadStructure
;
6017 RtlZeroMemory(copyProtectKey
, bufferLen
);
6018 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
6019 copyProtectKey
->KeyType
= DvdGetRpcKey
;
6022 // Build a request for READ_KEY
6025 ClassSendDeviceIoControlSynchronous(
6034 if (!NT_SUCCESS(ioStatus
.Status
)) {
6035 TraceLog((CdromDebugWarning
,
6036 "CdRomPickDvdRegion: Unable to get "
6037 "device RPC data (%x)\n", ioStatus
.Status
));
6043 // now that we have gotten the device's RPC data,
6044 // we have set the device extension to usable data.
6045 // no need to call back into this section of code again
6048 cddata
->Rpc0RetryRegistryCallback
= 0;
6051 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
6054 // TypeCode of zero means that no region has been set.
6057 if (rpcKey
->TypeCode
!= 0) {
6058 TraceLog((CdromDebugWarning
,
6059 "CdRomPickDvdRegion (%p): DVD Region already "
6065 TraceLog((CdromDebugWarning
,
6066 "CdRomPickDvdRegion (%p): must choose initial DVD "
6072 copyProtectKey
= (PDVD_COPY_PROTECT_KEY
) dvdReadStructure
;
6074 dvdCopyRight
= (PDVD_COPYRIGHT_DESCRIPTOR
)
6075 ((PDVD_DESCRIPTOR_HEADER
) dvdReadStructure
)->Data
;
6078 // get the media region
6081 RtlZeroMemory (dvdReadStructure
, bufferLen
);
6082 dvdReadStructure
->Format
= DvdCopyrightDescriptor
;
6085 // Build and send a request for READ_KEY
6088 TraceLog((CdromDebugTrace
,
6089 "CdRomPickDvdRegion (%p): Getting Copyright Descriptor\n",
6092 ClassSendDeviceIoControlSynchronous(
6093 IOCTL_DVD_READ_STRUCTURE
,
6096 sizeof(DVD_READ_STRUCTURE
),
6097 sizeof (DVD_DESCRIPTOR_HEADER
) +
6098 sizeof(DVD_COPYRIGHT_DESCRIPTOR
),
6102 TraceLog((CdromDebugTrace
,
6103 "CdRomPickDvdRegion (%p): Got Copyright Descriptor %x\n",
6104 Fdo
, ioStatus
.Status
));
6106 if ((NT_SUCCESS(ioStatus
.Status
)) &&
6107 (dvdCopyRight
->CopyrightProtectionType
== 0x01)
6111 // keep the media region bitmap around
6112 // a 1 means ok to play
6115 if (dvdCopyRight
->RegionManagementInformation
== 0xff) {
6116 TraceLog((CdromDebugError
,
6117 "CdRomPickDvdRegion (%p): RegionManagementInformation "
6118 "is set to dis-allow playback for all regions. This is "
6119 "most likely a poorly authored disc. defaulting to all "
6120 "region disc for purpose of choosing initial region\n",
6122 dvdCopyRight
->RegionManagementInformation
= 0;
6126 mediaRegion
= ~dvdCopyRight
->RegionManagementInformation
;
6131 // could be media, can't set the device region
6134 if (!cddata
->DvdRpc0Device
) {
6137 // can't automatically pick a default region on a rpc2 drive
6138 // without media, so just exit
6140 TraceLog((CdromDebugWarning
,
6141 "CdRomPickDvdRegion (%p): failed to auto-choose "
6142 "a region due to status %x getting copyright "
6143 "descriptor\n", Fdo
, ioStatus
.Status
));
6149 // for an RPC0 drive, we can try to pick a region for
6159 // get the device region
6162 RtlZeroMemory (copyProtectKey
, bufferLen
);
6163 copyProtectKey
->KeyLength
= DVD_RPC_KEY_LENGTH
;
6164 copyProtectKey
->KeyType
= DvdGetRpcKey
;
6167 // Build and send a request for READ_KEY for RPC key
6170 TraceLog((CdromDebugTrace
,
6171 "CdRomPickDvdRegion (%p): Getting RpcKey\n",
6173 ClassSendDeviceIoControlSynchronous(
6182 TraceLog((CdromDebugTrace
,
6183 "CdRomPickDvdRegion (%p): Got RpcKey %x\n",
6184 Fdo
, ioStatus
.Status
));
6186 if (!NT_SUCCESS(ioStatus
.Status
)) {
6188 TraceLog((CdromDebugWarning
,
6189 "CdRomPickDvdRegion (%p): failed to get RpcKey from "
6190 "a DVD Device\n", Fdo
));
6196 // so we now have what we can get for the media region and the
6197 // drive region. we will not set a region if the drive has one
6198 // set already (mask is not all 1's), nor will we set a region
6199 // if there are no more user resets available.
6202 rpcKey
= (PDVD_RPC_KEY
) copyProtectKey
->KeyData
;
6205 if (rpcKey
->RegionMask
!= 0xff) {
6206 TraceLog((CdromDebugWarning
,
6207 "CdRomPickDvdRegion (%p): not picking a region since "
6208 "it is already chosen\n", Fdo
));
6212 if (rpcKey
->UserResetsAvailable
<= 1) {
6213 TraceLog((CdromDebugWarning
,
6214 "CdRomPickDvdRegion (%p): not picking a region since "
6215 "only one change remains\n", Fdo
));
6219 defaultDvdRegion
= 0;
6222 // the proppage dvd class installer sets
6223 // this key based upon the system locale
6226 CdRomGetDeviceParameter (
6232 if (defaultDvdRegion
> DVD_MAX_REGION
) {
6235 // the registry has a bogus default
6238 TraceLog((CdromDebugWarning
,
6239 "CdRomPickDvdRegion (%p): registry has a bogus default "
6240 "region value of %x\n", Fdo
, defaultDvdRegion
));
6241 defaultDvdRegion
= 0;
6246 // if defaultDvdRegion == 0, it means no default.
6250 // we will select the initial dvd region for the user
6253 if ((defaultDvdRegion
!= 0) &&
6255 (1 << (defaultDvdRegion
- 1))
6261 // the media has region that matches
6262 // the default dvd region.
6265 dvdRegion
= (1 << (defaultDvdRegion
- 1));
6267 TraceLog((CdromDebugWarning
,
6268 "CdRomPickDvdRegion (%p): Choice #1: media matches "
6269 "drive's default, chose region %x\n", Fdo
, dvdRegion
));
6272 } else if (mediaRegion
) {
6276 // pick the lowest region number
6284 while (mediaRegion
&& !dvdRegion
) {
6287 // pick the lowest bit
6289 dvdRegion
= mediaRegion
& mask
;
6293 TraceLog((CdromDebugWarning
,
6294 "CdRomPickDvdRegion (%p): Choice #2: choosing lowest "
6295 "media region %x\n", Fdo
, dvdRegion
));
6297 } else if (defaultDvdRegion
) {
6301 // default dvd region from the dvd class installer
6304 dvdRegion
= (1 << (defaultDvdRegion
- 1));
6305 TraceLog((CdromDebugWarning
,
6306 "CdRomPickDvdRegion (%p): Choice #3: using default "
6307 "region for this install %x\n", Fdo
, dvdRegion
));
6312 // unable to pick one for the user -- this should rarely
6313 // happen, since the proppage dvd class installer sets
6314 // the key based upon the system locale
6316 TraceLog((CdromDebugWarning
,
6317 "CdRomPickDvdRegion (%p): Choice #4: failed to choose "
6318 "a media region\n", Fdo
));
6324 // now that we've chosen a region, set the region by sending the
6325 // appropriate request to the drive
6328 RtlZeroMemory (copyProtectKey
, bufferLen
);
6329 copyProtectKey
->KeyLength
= DVD_SET_RPC_KEY_LENGTH
;
6330 copyProtectKey
->KeyType
= DvdSetRpcKey
;
6331 dvdRpcKey
= (PDVD_SET_RPC_KEY
) copyProtectKey
->KeyData
;
6332 dvdRpcKey
->PreferredDriveRegionCode
= (UCHAR
) ~dvdRegion
;
6335 // Build and send request for SEND_KEY
6337 TraceLog((CdromDebugTrace
,
6338 "CdRomPickDvdRegion (%p): Sending new Rpc Key to region %x\n",
6341 ClassSendDeviceIoControlSynchronous(
6342 IOCTL_DVD_SEND_KEY2
,
6345 DVD_SET_RPC_KEY_LENGTH
,
6349 TraceLog((CdromDebugTrace
,
6350 "CdRomPickDvdRegion (%p): Sent new Rpc Key %x\n",
6351 Fdo
, ioStatus
.Status
));
6353 if (!NT_SUCCESS(ioStatus
.Status
)) {
6354 DebugPrint ((1, "CdRomPickDvdRegion (%p): unable to set dvd initial "
6355 " region code (%p)\n", Fdo
, ioStatus
.Status
));
6357 DebugPrint ((1, "CdRomPickDvdRegion (%p): Successfully set dvd "
6358 "initial region\n", Fdo
));
6363 if (dvdReadStructure
) {
6364 ExFreePool (dvdReadStructure
);
6368 // update the new PickDvdRegion value
6371 InterlockedExchange(&cddata
->PickDvdRegion
, pickDvdRegion
);
6379 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
6382 IN BOOLEAN ResendIrp
6389 return CdRomRerunRequest(FdoExtension
, Irp
, ResendIrp
);
6392 cdData
= FdoExtension
->CommonExtension
.DriverData
;
6394 KeAcquireSpinLock(&(cdData
->DelayedRetrySpinLock
), &oldIrql
);
6396 ASSERT(cdData
->DelayedRetryIrp
== NULL
);
6397 ASSERT(cdData
->DelayedRetryInterval
== 0);
6399 cdData
->DelayedRetryIrp
= Irp
;
6400 cdData
->DelayedRetryInterval
= Delay
;
6401 cdData
->DelayedRetryResend
= ResendIrp
;
6403 KeReleaseSpinLock(&(cdData
->DelayedRetrySpinLock
), oldIrql
);
6405 return STATUS_PENDING
;
6411 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
,
6412 IN OPTIONAL PIRP Irp
,
6413 IN BOOLEAN ResendIrp
6417 return IoCallDriver(FdoExtension
->CommonExtension
.LowerDeviceObject
,
6422 oldIrql
= KeRaiseIrqlToDpcLevel();
6423 CdRomStartIo(FdoExtension
->DeviceObject
, Irp
);
6424 KeLowerIrql(oldIrql
);
6425 return STATUS_MORE_PROCESSING_REQUIRED
;
6432 Routine Description:
6434 This routine just checks for media change sense/asc/ascq and
6435 also for other events, such as bus resets. this is used to
6436 determine if the device behaviour has changed, to allow for
6437 read and write operations to be allowed and/or disallowed.
6441 ISSUE-2000/3/30-henrygab - not fully doc'd
6451 CdRomMmcErrorHandler(
6452 IN PDEVICE_OBJECT Fdo
,
6453 IN PSCSI_REQUEST_BLOCK Srb
,
6454 OUT PNTSTATUS Status
,
6458 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
6459 BOOLEAN queryCapabilities
= FALSE
;
6461 if (TEST_FLAG(Srb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
6463 PCDROM_DATA cddata
= (PCDROM_DATA
)commonExtension
->DriverData
;
6464 PSENSE_DATA senseBuffer
= Srb
->SenseInfoBuffer
;
6467 // the following sense keys could indicate a change in
6472 // we used to expect this to be serialized, and only hit from our
6473 // own routine. we now allow some requests to continue during our
6474 // processing of the capabilities update in order to allow
6475 // IoReadPartitionTable() to succeed.
6478 switch (senseBuffer
->SenseKey
& 0xf) {
6480 case SCSI_SENSE_NOT_READY
: {
6481 if (senseBuffer
->AdditionalSenseCode
==
6482 SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
) {
6484 if (cddata
->Mmc
.WriteAllowed
) {
6485 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6486 "CdromErrorHandler: media removed, writes will be "
6487 "failed until new media detected\n"));
6491 cddata
->Mmc
.WriteAllowed
= FALSE
;
6493 if ((senseBuffer
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
6494 (senseBuffer
->AdditionalSenseCodeQualifier
==
6495 SCSI_SENSEQ_BECOMING_READY
)) {
6496 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6497 "CdromErrorHandler: media becoming ready, "
6498 "SHOULD notify shell of change time by sending "
6499 "GESN request immediately!\n"));
6502 } // end SCSI_SENSE_NOT_READY
6504 case SCSI_SENSE_UNIT_ATTENTION
: {
6505 switch (senseBuffer
->AdditionalSenseCode
) {
6506 case SCSI_ADSENSE_MEDIUM_CHANGED
: {
6509 // always update if the medium may have changed
6513 cddata
->Mmc
.WriteAllowed
= FALSE
;
6514 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6515 CdromMmcUpdateRequired
,
6516 CdromMmcUpdateComplete
);
6518 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6519 "CdromErrorHandler: media change detected, need to "
6520 "update drive capabilities\n"));
6523 } // end SCSI_ADSENSE_MEDIUM_CHANGED
6525 case SCSI_ADSENSE_BUS_RESET
: {
6528 cddata
->Mmc
.WriteAllowed
= FALSE
;
6529 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6530 CdromMmcUpdateRequired
,
6531 CdromMmcUpdateComplete
);
6533 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6534 "CdromErrorHandler: bus reset detected, need to "
6535 "update drive capabilities\n"));
6538 } // end SCSI_ADSENSE_BUS_RESET
6540 case SCSI_ADSENSE_OPERATOR_REQUEST
: {
6544 switch (senseBuffer
->AdditionalSenseCodeQualifier
) {
6545 case SCSI_SENSEQ_MEDIUM_REMOVAL
: {
6548 // eject notification currently handled by classpnp
6551 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6552 "CdromErrorHandler: Eject requested by user\n"));
6554 *Status
= STATUS_DEVICE_BUSY
;
6558 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE
:
6560 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE
: {
6562 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6563 "CdromErrorHandler: Write protect %s requested "
6565 (b
? "disable" : "enable")));
6567 *Status
= STATUS_DEVICE_BUSY
;
6569 cddata
->Mmc
.WriteAllowed
= FALSE
;
6570 InterlockedCompareExchange(&(cddata
->Mmc
.UpdateState
),
6571 CdromMmcUpdateRequired
,
6572 CdromMmcUpdateComplete
);
6576 } // end of AdditionalSenseCodeQualifier switch
6581 } // end SCSI_ADSENSE_OPERATOR_REQUEST
6584 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6585 "CdromErrorHandler: Unit attention %02x/%02x\n",
6586 senseBuffer
->AdditionalSenseCode
,
6587 senseBuffer
->AdditionalSenseCodeQualifier
));
6591 } // end of AdditionSenseCode switch
6594 } // end SCSI_SENSE_UNIT_ATTENTION
6596 case SCSI_SENSE_ILLEGAL_REQUEST
: {
6597 if (senseBuffer
->AdditionalSenseCode
==
6598 SCSI_ADSENSE_WRITE_PROTECT
) {
6600 if (cddata
->Mmc
.WriteAllowed
) {
6601 KdPrintEx((DPFLTR_CDROM_ID
, CdromDebugFeatures
,
6602 "CdromErrorHandler: media was writable, but "
6603 "failed request with WRITE_PROTECT error...\n"));
6606 // do not update all the capabilities just because
6607 // we can't write to the disc.
6608 cddata
->Mmc
.WriteAllowed
= FALSE
;
6611 } // end SCSI_SENSE_ILLEGAL_REQUEST
6613 } // end of SenseKey switch
6615 } // end of SRB_STATUS_AUTOSENSE_VALID
6620 Routine Description:
6622 This routine checks for a device-specific error handler
6623 and calls it if it exists. This allows multiple drives
6624 that require their own error handler to co-exist.
6629 PDEVICE_OBJECT DeviceObject
,
6630 PSCSI_REQUEST_BLOCK Srb
,
6635 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
6636 PCDROM_DATA cddata
= (PCDROM_DATA
)commonExtension
->DriverData
;
6637 PSENSE_DATA sense
= Srb
->SenseInfoBuffer
;
6639 if ((Srb
->SenseInfoBufferLength
>=
6640 RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA
,AdditionalSenseCodeQualifier
)) &&
6641 TEST_FLAG(Srb
->SrbStatus
, SRB_STATUS_AUTOSENSE_VALID
)) {
6644 // Many non-WHQL certified drives (mostly CD-RW) return
6645 // 2/4/0 when they have no media instead of the obvious
6648 // SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
6650 // These drives should not pass WHQL certification due
6651 // to this discrepency.
6653 // However, we have to retry on 2/4/0 (Not ready, LUN not ready,
6654 // no info) and also 3/2/0 (no seek complete).
6656 // These conditions occur when the shell tries to examine an
6657 // injected CD (e.g. for autoplay) before the CD is spun up.
6659 // The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
6660 // (0x01) in order to comply with WHQL standards.
6662 // The default retry timeout of one second is acceptable to balance
6663 // these discrepencies. don't modify the status, though....
6666 if (((sense
->SenseKey
& 0xf) == SCSI_SENSE_NOT_READY
) &&
6667 (sense
->AdditionalSenseCode
== SCSI_ADSENSE_LUN_NOT_READY
) &&
6668 (sense
->AdditionalSenseCodeQualifier
== SCSI_SENSEQ_CAUSE_NOT_REPORTABLE
)
6673 } else if (((sense
->SenseKey
& 0xf) == SCSI_SENSE_MEDIUM_ERROR
) &&
6674 (sense
->AdditionalSenseCode
== 0x2) &&
6675 (sense
->AdditionalSenseCodeQualifier
== 0x0)
6680 } else if ((sense
->AdditionalSenseCode
== 0x57) &&
6681 (sense
->AdditionalSenseCodeQualifier
== 0x00)
6685 // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
6686 // the Matshita CR-585 returns this for all read commands
6687 // on blank CD-R and CD-RW media, and we need to handle
6688 // this for READ_CD detection ability.
6692 *Status
= STATUS_UNRECOGNIZED_MEDIA
;
6699 // tail recursion in both cases takes no stack
6702 if (cddata
->ErrorHandler
) {
6703 cddata
->ErrorHandler(DeviceObject
, Srb
, Status
, Retry
);
6711 Routine Description:
6713 This routine is called for a shutdown and flush IRPs.
6714 These are sent by the system before it actually shuts
6715 down or when the file system does a flush.
6719 DriverObject - Pointer to device object to being shutdown by system.
6730 IN PDEVICE_OBJECT DeviceObject
,
6734 IoMarkIrpPending(Irp
);
6735 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
6736 return STATUS_PENDING
;
6742 Routine Description:
6744 This routine is called for intermediate work a shutdown or
6745 flush IRPs would need to do. We just want to free our resources
6746 and return STATUS_MORE_PROCESSING_REQUIRED.
6750 DeviceObject - NULL?
6763 CdRomShutdownFlushCompletion(
6764 IN PDEVICE_OBJECT Fdo
,
6769 PCOMMON_DEVICE_EXTENSION commonExtension
= Fdo
->DeviceExtension
;
6770 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension
= Fdo
->DeviceExtension
;
6771 PIO_STACK_LOCATION originalIrpStack
;
6772 ULONG_PTR iteration
;
6773 NTSTATUS status
= STATUS_SUCCESS
;
6775 ASSERT(OriginalIrp
);
6777 originalIrpStack
= IoGetCurrentIrpStackLocation(OriginalIrp
);
6780 // always use a new irp so we can call
6781 // CdRomCompleteIrpAndStartNextPacketSafely() from this routine.
6784 if (NewIrp
!= NULL
) {
6785 status
= NewIrp
->IoStatus
.Status
;
6790 if (!NT_SUCCESS(status
)) {
6791 BAIL_OUT(OriginalIrp
);
6796 // the current irpstack saves the counter which states
6797 // what part of the multi-part shutdown or flush we are in.
6800 iteration
= (ULONG_PTR
)originalIrpStack
->Parameters
.Others
.Argument1
;
6802 originalIrpStack
->Parameters
.Others
.Argument1
= (PVOID
)iteration
;
6804 switch (iteration
) {
6806 if (originalIrpStack
->MajorFunction
!= IRP_MJ_SHUTDOWN
) {
6808 // then we don't want to send the unlock command
6809 // the incrementing of the state was done above.
6810 // return the completion routine's result.
6812 return CdRomShutdownFlushCompletion(Fdo
, NULL
, OriginalIrp
);
6814 // else fall through....
6819 PSCSI_REQUEST_BLOCK newSrb
= NULL
;
6821 PIO_STACK_LOCATION newIrpStack
= NULL
;
6824 newIrp
= IoAllocateIrp((CCHAR
)(Fdo
->StackSize
+1), FALSE
);
6825 if (newIrp
== NULL
) {
6826 BAIL_OUT(OriginalIrp
);
6827 status
= STATUS_INSUFFICIENT_RESOURCES
;
6830 newSrb
= ExAllocatePoolWithTag(NonPagedPool
,
6831 sizeof(SCSI_REQUEST_BLOCK
),
6833 if (newSrb
== NULL
) {
6835 BAIL_OUT(OriginalIrp
);
6836 status
= STATUS_INSUFFICIENT_RESOURCES
;
6841 // ClassIoComplete will free the SRB, but we need a routine
6842 // that will free the irp. then just call ClassSendAsync,
6843 // and don't care about the return value, since the completion
6844 // routine will be called anyways.
6847 IoSetNextIrpStackLocation(newIrp
);
6848 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
6849 newIrpStack
->DeviceObject
= Fdo
;
6850 IoSetCompletionRoutine(newIrp
,
6851 (PIO_COMPLETION_ROUTINE
)CdRomShutdownFlushCompletion
,
6854 IoSetNextIrpStackLocation(newIrp
);
6855 newIrpStack
= IoGetCurrentIrpStackLocation(newIrp
);
6856 newIrpStack
->DeviceObject
= Fdo
;
6859 // setup the request
6862 RtlZeroMemory(newSrb
, sizeof(SCSI_REQUEST_BLOCK
));
6863 newCdb
= (PCDB
)(newSrb
->Cdb
);
6865 newSrb
->QueueTag
= SP_UNTAGGED
;
6866 newSrb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
6867 newSrb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6870 // tell classpnp not to call StartNextPacket()
6873 newSrb
->SrbFlags
= SRB_FLAGS_DONT_START_NEXT_PACKET
;
6875 if (iteration
== 1) {
6878 // first synchronize the cache
6881 newSrb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 4;
6882 newSrb
->CdbLength
= 10;
6883 newCdb
->SYNCHRONIZE_CACHE10
.OperationCode
= SCSIOP_SYNCHRONIZE_CACHE
;
6885 } else if (iteration
== 2) {
6888 // then unlock the medium
6891 ASSERT( originalIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
);
6893 newSrb
->TimeOutValue
= fdoExtension
->TimeOutValue
;
6894 newSrb
->CdbLength
= 6;
6895 newCdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
6896 newCdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
6901 isRemoved
= ClassAcquireRemoveLock(Fdo
, newIrp
);
6905 ClassReleaseRemoveLock(Fdo
, newIrp
);
6906 BAIL_OUT(OriginalIrp
);
6907 status
= STATUS_DEVICE_DOES_NOT_EXIST
;
6910 ClassSendSrbAsynchronous(Fdo
, newSrb
, newIrp
, NULL
, 0, FALSE
);
6916 PSCSI_REQUEST_BLOCK srb
;
6917 PIO_STACK_LOCATION nextIrpStack
= IoGetNextIrpStackLocation(OriginalIrp
);
6920 // forward this request to the device appropriately,
6921 // don't use this completion routine anymore...
6924 srb
= ExAllocatePoolWithTag(NonPagedPool
,
6925 sizeof(SCSI_REQUEST_BLOCK
),
6928 BAIL_OUT(OriginalIrp
);
6929 status
= STATUS_INSUFFICIENT_RESOURCES
;
6933 RtlZeroMemory(srb
, SCSI_REQUEST_BLOCK_SIZE
);
6934 srb
->Length
= SCSI_REQUEST_BLOCK_SIZE
;
6935 srb
->TimeOutValue
= fdoExtension
->TimeOutValue
* 4;
6936 srb
->QueueTag
= SP_UNTAGGED
;
6937 srb
->QueueAction
= SRB_SIMPLE_TAG_REQUEST
;
6938 srb
->SrbFlags
= fdoExtension
->SrbFlags
;
6940 srb
->OriginalRequest
= OriginalIrp
;
6942 if (originalIrpStack
->MajorFunction
== IRP_MJ_SHUTDOWN
) {
6943 srb
->Function
= SRB_FUNCTION_SHUTDOWN
;
6945 srb
->Function
= SRB_FUNCTION_FLUSH
;
6949 // Set up IoCompletion routine address.
6952 IoSetCompletionRoutine(OriginalIrp
,
6958 // Set the retry count to zero.
6961 originalIrpStack
->Parameters
.Others
.Argument4
= (PVOID
) 0;
6964 // Get next stack location and set major function code.
6967 nextIrpStack
->MajorFunction
= IRP_MJ_SCSI
;
6970 // Set up SRB for execute scsi request.
6971 // Save SRB address in next stack for port driver.
6974 nextIrpStack
->Parameters
.Scsi
.Srb
= srb
;
6977 // Call the port driver to process the request.
6980 IoCallDriver(commonExtension
->LowerDeviceObject
, OriginalIrp
);
6992 status
= STATUS_SUCCESS
;
6996 if (!NT_SUCCESS(status
)) {
6997 OriginalIrp
->IoStatus
.Status
= status
;
6998 CdRomCompleteIrpAndStartNextPacketSafely(Fdo
, OriginalIrp
);
7002 // always return STATUS_MORE_PROCESSING_REQUIRED, so noone else tries
7003 // to access the new irp that we free'd....
7006 return STATUS_MORE_PROCESSING_REQUIRED
;
7008 } // end CdromShutdownFlush()
7012 CdromFakePartitionInfo(
7013 IN PCOMMON_DEVICE_EXTENSION CommonExtension
,
7017 PIO_STACK_LOCATION currentIrpStack
= IoGetCurrentIrpStackLocation(Irp
);
7018 ULONG ioctl
= currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
;
7019 PVOID systemBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
7021 ASSERT(systemBuffer
);
7023 if ((ioctl
!= IOCTL_DISK_GET_DRIVE_LAYOUT
) &&
7024 (ioctl
!= IOCTL_DISK_GET_DRIVE_LAYOUT_EX
) &&
7025 (ioctl
!= IOCTL_DISK_GET_PARTITION_INFO
) &&
7026 (ioctl
!= IOCTL_DISK_GET_PARTITION_INFO_EX
)) {
7027 TraceLog((CdromDebugError
,
7028 "CdromFakePartitionInfo: unhandled ioctl %x\n", ioctl
));
7029 Irp
->IoStatus
.Status
= STATUS_INTERNAL_ERROR
;
7030 Irp
->IoStatus
.Information
= 0;
7031 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension
->DeviceObject
,
7037 // nothing to fail from this point on, so set the size appropriately
7038 // and set irp's status to success.
7041 TraceLog((CdromDebugWarning
,
7042 "CdromFakePartitionInfo: incoming ioctl %x\n", ioctl
));
7045 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
7047 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
7048 Irp
->IoStatus
.Information
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
7050 RtlZeroMemory(systemBuffer
, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
,
7051 PartitionEntry
[1]));
7053 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
:
7054 Irp
->IoStatus
.Information
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
,
7056 RtlZeroMemory(systemBuffer
, FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
,
7057 PartitionEntry
[1]));
7059 case IOCTL_DISK_GET_PARTITION_INFO
:
7060 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION
);
7061 RtlZeroMemory(systemBuffer
, sizeof(PARTITION_INFORMATION
));
7063 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
7064 Irp
->IoStatus
.Information
= sizeof(PARTITION_INFORMATION_EX
);
7065 RtlZeroMemory(systemBuffer
, sizeof(PARTITION_INFORMATION_EX
));
7068 ASSERT(!"Invalid ioctl should not have reached this point\n");
7073 // if we are getting the drive layout, then we need to start by
7074 // adding some of the non-partition stuff that says we have
7075 // exactly one partition available.
7079 if (ioctl
== IOCTL_DISK_GET_DRIVE_LAYOUT
) {
7081 PDRIVE_LAYOUT_INFORMATION layout
;
7082 layout
= (PDRIVE_LAYOUT_INFORMATION
)systemBuffer
;
7083 layout
->PartitionCount
= 1;
7084 layout
->Signature
= 1;
7085 systemBuffer
= (PVOID
)(layout
->PartitionEntry
);
7086 ioctl
= IOCTL_DISK_GET_PARTITION_INFO
;
7088 } else if (ioctl
== IOCTL_DISK_GET_DRIVE_LAYOUT_EX
) {
7090 PDRIVE_LAYOUT_INFORMATION_EX layoutEx
;
7091 layoutEx
= (PDRIVE_LAYOUT_INFORMATION_EX
)systemBuffer
;
7092 layoutEx
->PartitionStyle
= PARTITION_STYLE_MBR
;
7093 layoutEx
->PartitionCount
= 1;
7094 layoutEx
->Mbr
.Signature
= 1;
7095 systemBuffer
= (PVOID
)(layoutEx
->PartitionEntry
);
7096 ioctl
= IOCTL_DISK_GET_PARTITION_INFO_EX
;
7101 // NOTE: the local var 'ioctl' is now modified to either EX or
7102 // non-EX version. the local var 'systemBuffer' is now pointing
7103 // to the partition information structure.
7106 if (ioctl
== IOCTL_DISK_GET_PARTITION_INFO
) {
7108 PPARTITION_INFORMATION partitionInfo
;
7109 partitionInfo
= (PPARTITION_INFORMATION
)systemBuffer
;
7110 partitionInfo
->RewritePartition
= FALSE
;
7111 partitionInfo
->RecognizedPartition
= TRUE
;
7112 partitionInfo
->PartitionType
= PARTITION_FAT32
;
7113 partitionInfo
->BootIndicator
= FALSE
;
7114 partitionInfo
->HiddenSectors
= 0;
7115 partitionInfo
->StartingOffset
.QuadPart
= 0;
7116 partitionInfo
->PartitionLength
= CommonExtension
->PartitionLength
;
7117 partitionInfo
->PartitionNumber
= 0;
7121 PPARTITION_INFORMATION_EX partitionInfo
;
7122 partitionInfo
= (PPARTITION_INFORMATION_EX
)systemBuffer
;
7123 partitionInfo
->PartitionStyle
= PARTITION_STYLE_MBR
;
7124 partitionInfo
->RewritePartition
= FALSE
;
7125 partitionInfo
->Mbr
.RecognizedPartition
= TRUE
;
7126 partitionInfo
->Mbr
.PartitionType
= PARTITION_FAT32
;
7127 partitionInfo
->Mbr
.BootIndicator
= FALSE
;
7128 partitionInfo
->Mbr
.HiddenSectors
= 0;
7129 partitionInfo
->StartingOffset
.QuadPart
= 0;
7130 partitionInfo
->PartitionLength
= CommonExtension
->PartitionLength
;
7131 partitionInfo
->PartitionNumber
= 0;
7134 TraceLog((CdromDebugWarning
,
7135 "CdromFakePartitionInfo: finishing ioctl %x\n",
7136 currentIrpStack
->Parameters
.DeviceIoControl
.IoControlCode
));
7142 CdRomCompleteIrpAndStartNextPacketSafely(CommonExtension
->DeviceObject
,